From a023b710ea918b966987f1081fa68369fc1596c9 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 30 May 2014 23:49:56 +0300 Subject: ath10k: remove unused len variables from wmi process rx functions These len variables are not used anywhere. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 4b7782a529ac..6f83cae57655 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2106,7 +2106,6 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; enum wmi_event_id id; - u16 len; cmd_hdr = (struct wmi_cmd_hdr *)skb->data; id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); @@ -2114,8 +2113,6 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb) if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) return; - len = skb->len; - trace_ath10k_wmi_event(id, skb->data, skb->len); switch (id) { @@ -2225,7 +2222,6 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; enum wmi_10x_event_id id; - u16 len; cmd_hdr = (struct wmi_cmd_hdr *)skb->data; id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); @@ -2233,8 +2229,6 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb) if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) return; - len = skb->len; - trace_ath10k_wmi_event(id, skb->data, skb->len); switch (id) { -- cgit v1.2.3 From 4e0561e775e0f76a2032a2c4ed9fde20deda29bb Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Fri, 30 May 2014 23:49:58 +0300 Subject: ath10k: print Kconfig options Print Kconfig options enabled/disabled in the build. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 82017f56e661..68bed4e5c9f4 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -798,7 +798,7 @@ int ath10k_core_start(struct ath10k *ar) ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; INIT_LIST_HEAD(&ar->arvifs); - if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) + if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) { ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", ar->hw_params.name, ar->target_version, @@ -807,6 +807,12 @@ int ath10k_core_start(struct ath10k *ar) ar->fw_api, ar->htt.target_version_major, ar->htt.target_version_minor); + ath10k_info("debug %d debugfs %d tracing %d dfs %d\n", + config_enabled(CONFIG_ATH10K_DEBUG), + config_enabled(CONFIG_ATH10K_DEBUGFS), + config_enabled(CONFIG_ATH10K_TRACING), + config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)); + } __set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags); -- cgit v1.2.3 From 3dac9a79e1425069e7950bd46bd932e0b1c1d795 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 16 Jun 2014 09:12:31 +0530 Subject: mrf24j40: separate h/w init and add checkings separate the mrf24j40 hardware initialisation from probe() and adds the sanity checkings. These checkings are required if somebody hasn't a right spi configuration the probe function should fail. So we have to return from there. Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ieee802154/mrf24j40.c | 115 +++++++++++++++++++++++++++++--------- 1 file changed, 89 insertions(+), 26 deletions(-) diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index 4048062011ba..9e6a124b13f2 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -610,10 +610,95 @@ out: return IRQ_HANDLED; } +static int mrf24j40_hw_init(struct mrf24j40 *devrec) +{ + int ret; + u8 val; + + /* Initialize the device. + From datasheet section 3.2: Initialization. */ + ret = write_short_reg(devrec, REG_SOFTRST, 0x07); + if (ret) + goto err_ret; + + ret = write_short_reg(devrec, REG_PACON2, 0x98); + if (ret) + goto err_ret; + + ret = write_short_reg(devrec, REG_TXSTBL, 0x95); + if (ret) + goto err_ret; + + ret = write_long_reg(devrec, REG_RFCON0, 0x03); + if (ret) + goto err_ret; + + ret = write_long_reg(devrec, REG_RFCON1, 0x01); + if (ret) + goto err_ret; + + ret = write_long_reg(devrec, REG_RFCON2, 0x80); + if (ret) + goto err_ret; + + ret = write_long_reg(devrec, REG_RFCON6, 0x90); + if (ret) + goto err_ret; + + ret = write_long_reg(devrec, REG_RFCON7, 0x80); + if (ret) + goto err_ret; + + ret = write_long_reg(devrec, REG_RFCON8, 0x10); + if (ret) + goto err_ret; + + ret = write_long_reg(devrec, REG_SLPCON1, 0x21); + if (ret) + goto err_ret; + + ret = write_short_reg(devrec, REG_BBREG2, 0x80); + if (ret) + goto err_ret; + + ret = write_short_reg(devrec, REG_CCAEDTH, 0x60); + if (ret) + goto err_ret; + + ret = write_short_reg(devrec, REG_BBREG6, 0x40); + if (ret) + goto err_ret; + + ret = write_short_reg(devrec, REG_RFCTL, 0x04); + if (ret) + goto err_ret; + + ret = write_short_reg(devrec, REG_RFCTL, 0x0); + if (ret) + goto err_ret; + + udelay(192); + + /* Set RX Mode. RXMCR<1:0>: 0x0 normal, 0x1 promisc, 0x2 error */ + ret = read_short_reg(devrec, REG_RXMCR, &val); + if (ret) + goto err_ret; + + val &= ~0x3; /* Clear RX mode (normal) */ + + ret = write_short_reg(devrec, REG_RXMCR, val); + if (ret) + goto err_ret; + + return 0; + +err_ret: + return ret; +} + static int mrf24j40_probe(struct spi_device *spi) { int ret = -ENOMEM; - u8 val; struct mrf24j40 *devrec; printk(KERN_INFO "mrf24j40: probe(). IRQ: %d\n", spi->irq); @@ -650,31 +735,9 @@ static int mrf24j40_probe(struct spi_device *spi) if (ret) goto err_register_device; - /* Initialize the device. - From datasheet section 3.2: Initialization. */ - write_short_reg(devrec, REG_SOFTRST, 0x07); - write_short_reg(devrec, REG_PACON2, 0x98); - write_short_reg(devrec, REG_TXSTBL, 0x95); - write_long_reg(devrec, REG_RFCON0, 0x03); - write_long_reg(devrec, REG_RFCON1, 0x01); - write_long_reg(devrec, REG_RFCON2, 0x80); - write_long_reg(devrec, REG_RFCON6, 0x90); - write_long_reg(devrec, REG_RFCON7, 0x80); - write_long_reg(devrec, REG_RFCON8, 0x10); - write_long_reg(devrec, REG_SLPCON1, 0x21); - write_short_reg(devrec, REG_BBREG2, 0x80); - write_short_reg(devrec, REG_CCAEDTH, 0x60); - write_short_reg(devrec, REG_BBREG6, 0x40); - write_short_reg(devrec, REG_RFCTL, 0x04); - write_short_reg(devrec, REG_RFCTL, 0x0); - udelay(192); - - /* Set RX Mode. RXMCR<1:0>: 0x0 normal, 0x1 promisc, 0x2 error */ - ret = read_short_reg(devrec, REG_RXMCR, &val); + ret = mrf24j40_hw_init(devrec); if (ret) - goto err_read_reg; - val &= ~0x3; /* Clear RX mode (normal) */ - write_short_reg(devrec, REG_RXMCR, val); + goto err_hw_init; ret = devm_request_threaded_irq(&spi->dev, spi->irq, @@ -692,7 +755,7 @@ static int mrf24j40_probe(struct spi_device *spi) return 0; err_irq: -err_read_reg: +err_hw_init: ieee802154_unregister_device(devrec->dev); err_register_device: ieee802154_free_device(devrec->dev); -- cgit v1.2.3 From d215d10f2d6bd41ce9d11a2707568bbb50d2c32e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Mon, 16 Jun 2014 21:57:22 +0800 Subject: net: delete duplicate dev_set_rx_mode() call In __dev_open(), it already calls dev_set_rx_mode(). and dev_set_rx_mode() has no effect for a net device which does not have IFF_UP flag set. So the call of dev_set_rx_mode() is duplicate in __dev_change_flags(). Signed-off-by: Weiping Pan Signed-off-by: David S. Miller --- net/core/dev.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 30eedf677913..a04b12f31e18 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5432,13 +5432,9 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags) */ ret = 0; - if ((old_flags ^ flags) & IFF_UP) { /* Bit is different ? */ + if ((old_flags ^ flags) & IFF_UP) ret = ((old_flags & IFF_UP) ? __dev_close : __dev_open)(dev); - if (!ret) - dev_set_rx_mode(dev); - } - if ((flags ^ dev->gflags) & IFF_PROMISC) { int inc = (flags & IFF_PROMISC) ? 1 : -1; unsigned int old_flags = dev->flags; -- cgit v1.2.3 From e0f802fbcaa3bffe4728e37a8fa1279b5d554173 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Tue, 17 Jun 2014 11:25:37 +0300 Subject: tcp: move ir_mark initialization to tcp_openreq_init ir_mark initialization is done for both TCP v4 and v6, move it in the common tcp_openreq_init function. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/tcp.h | 3 ++- net/ipv4/tcp_ipv4.c | 3 +-- net/ipv6/tcp_ipv6.c | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 7286db80e8b8..06a3023080c0 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1098,7 +1098,7 @@ static inline int tcp_full_space(const struct sock *sk) static inline void tcp_openreq_init(struct request_sock *req, struct tcp_options_received *rx_opt, - struct sk_buff *skb) + struct sk_buff *skb, struct sock *sk) { struct inet_request_sock *ireq = inet_rsk(req); @@ -1117,6 +1117,7 @@ static inline void tcp_openreq_init(struct request_sock *req, ireq->ecn_ok = 0; ireq->ir_rmt_port = tcp_hdr(skb)->source; ireq->ir_num = ntohs(tcp_hdr(skb)->dest); + ireq->ir_mark = inet_request_mark(sk, skb); } extern void tcp_openreq_init_rwin(struct request_sock *req, diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 77cccda1ad0c..180336d47df6 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1311,14 +1311,13 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) tcp_clear_options(&tmp_opt); tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; - tcp_openreq_init(req, &tmp_opt, skb); + tcp_openreq_init(req, &tmp_opt, skb, sk); ireq = inet_rsk(req); ireq->ir_loc_addr = daddr; ireq->ir_rmt_addr = saddr; ireq->no_srccheck = inet_sk(sk)->transparent; ireq->opt = tcp_v4_save_options(skb); - ireq->ir_mark = inet_request_mark(sk, skb); if (security_inet_conn_request(sk, skb, req)) goto drop_and_free; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 229239ad96b1..08ae3da0db4a 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1025,7 +1025,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) tcp_clear_options(&tmp_opt); tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; - tcp_openreq_init(req, &tmp_opt, skb); + tcp_openreq_init(req, &tmp_opt, skb, sk); ireq = inet_rsk(req); ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; @@ -1034,7 +1034,6 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) TCP_ECN_create_request(req, skb, sock_net(sk)); ireq->ir_iif = sk->sk_bound_dev_if; - ireq->ir_mark = inet_request_mark(sk, skb); /* So that link locals have meaning */ if (!sk->sk_bound_dev_if && -- cgit v1.2.3 From 12f32370068d539bdc2fc9cf22c37dbdc2bae158 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Sat, 31 May 2014 10:14:06 -0300 Subject: net: wireless: Remove useless return variables This patch remove variables that are initialized with a constant, are never updated, and are only used as parameter of return. Return the constant instead of using a variable. wl_cfg80211.c verified by compilation only. phy/phy_cmn.c unverified. The coccinelle script that find and fixes this issue is: // @@ type T; constant C; identifier ret; @@ - T ret = C; ... when != ret when strict return - ret + C ; // Signed-off-by: Peter Senna Tschudin Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 18 ++++++------------ drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c | 6 +----- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index d8fa276e368b..db3d8487dc42 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -1331,7 +1331,6 @@ static s32 brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); - s32 err = 0; brcmf_dbg(TRACE, "Enter\n"); if (!check_vif_up(ifp->vif)) @@ -1341,7 +1340,7 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) brcmf_dbg(TRACE, "Exit\n"); - return err; + return 0; } static s32 brcmf_set_wpa_version(struct net_device *ndev, @@ -2388,7 +2387,6 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, struct cfg80211_bss *bss; struct ieee80211_supported_band *band; struct brcmu_chan ch; - s32 err = 0; u16 channel; u32 freq; u16 notify_capability; @@ -2438,7 +2436,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, cfg80211_put_bss(wiphy, bss); - return err; + return 0; } static struct brcmf_bss_info_le * @@ -2690,7 +2688,6 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, { struct brcmf_cfg80211_info *cfg = ifp->drvr->config; s32 status; - s32 err = 0; struct brcmf_escan_result_le *escan_result_le; struct brcmf_bss_info_le *bss_info_le; struct brcmf_bss_info_le *bss = NULL; @@ -2781,7 +2778,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, status); } exit: - return err; + return 0; } static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg) @@ -3507,7 +3504,6 @@ static s32 brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len, struct parsed_vndr_ies *vndr_ies) { - s32 err = 0; struct brcmf_vs_tlv *vndrie; struct brcmf_tlv *ie; struct parsed_vndr_ie_info *parsed_info; @@ -3560,7 +3556,7 @@ next: ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len + TLV_HDR_LEN); } - return err; + return 0; } static u32 @@ -4650,7 +4646,6 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); - s32 err = 0; brcmf_dbg(TRACE, "Enter\n"); @@ -4676,7 +4671,7 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, completed ? "succeeded" : "failed"); } brcmf_dbg(TRACE, "Exit\n"); - return err; + return 0; } static s32 @@ -4768,7 +4763,6 @@ brcmf_notify_roaming_status(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { struct brcmf_cfg80211_info *cfg = ifp->drvr->config; - s32 err = 0; u32 event = e->event_code; u32 status = e->status; @@ -4779,7 +4773,7 @@ brcmf_notify_roaming_status(struct brcmf_if *ifp, brcmf_bss_connect_done(cfg, ifp->ndev, e, true); } - return err; + return 0; } static s32 diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c index b0fd807f2b2b..57ecc05802e9 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c @@ -1538,11 +1538,7 @@ static s8 wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band, u8 rate) { - s8 offset = 0; - - if (!pi->user_txpwr_at_rfport) - return offset; - return offset; + return 0; } void wlc_phy_txpower_recalc_target(struct brcms_phy *pi) -- cgit v1.2.3 From 69253b6108102834c7cac826d4c34a0414b83a3e Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Sat, 31 May 2014 13:12:26 -0300 Subject: cw1200: Remove useless return variables This patch remove variables that are initialized with a constant, are never updated, and are only used as parameter of return. Return the constant instead of using a variable. Verified by compilation only. The coccinelle script that find and fixes this issue is: // @@ type T; constant C; identifier ret; @@ - T ret = C; ... when != ret when strict return - ret + C ; // Signed-off-by: Peter Senna Tschudin Signed-off-by: John W. Linville --- drivers/net/wireless/cw1200/sta.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c index cd0cad7f7759..5b84664db13b 100644 --- a/drivers/net/wireless/cw1200/sta.c +++ b/drivers/net/wireless/cw1200/sta.c @@ -2289,7 +2289,6 @@ static int cw1200_upload_null(struct cw1200_common *priv) static int cw1200_upload_qosnull(struct cw1200_common *priv) { - int ret = 0; /* TODO: This needs to be implemented struct wsm_template_frame frame = { @@ -2306,7 +2305,7 @@ static int cw1200_upload_qosnull(struct cw1200_common *priv) dev_kfree_skb(frame.skb); */ - return ret; + return 0; } static int cw1200_enable_beaconing(struct cw1200_common *priv, -- cgit v1.2.3 From afbedbf7dfc0ebff0ea3280530fe0609fd307486 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Sat, 31 May 2014 18:29:46 +0200 Subject: rtl818x_pci: make RSSI code more readable remove the if-else chains and use switch-case to make code more readable and avoiding long lines that broke in several lines Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 2c1c02bafa10..c2dd5e636d28 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -209,7 +209,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) struct rtl8180_priv *priv = dev->priv; struct rtl818x_rx_cmd_desc *cmd_desc; unsigned int count = 32; - u8 signal, agc, sq; + u8 agc, sq, signal = 1; dma_addr_t mapping; while (count--) { @@ -266,18 +266,21 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) rx_status.rate_idx = (flags >> 20) & 0xF; agc = (flags2 >> 17) & 0x7F; - if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) { + switch (priv->chip_family) { + case RTL818X_CHIP_FAMILY_RTL8185: if (rx_status.rate_idx > 3) signal = 90 - clamp_t(u8, agc, 25, 90); else signal = 95 - clamp_t(u8, agc, 30, 95); - } else if (priv->chip_family == - RTL818X_CHIP_FAMILY_RTL8180) { + break; + case RTL818X_CHIP_FAMILY_RTL8180: sq = flags2 & 0xff; signal = priv->rf->calc_rssi(agc, sq); - } else { + break; + case RTL818X_CHIP_FAMILY_RTL8187SE: /* TODO: rtl8187se rssi */ signal = 10; + break; } rx_status.signal = signal; rx_status.freq = dev->conf.chandef.chan->center_freq; -- cgit v1.2.3 From 7049327a686d2ba888b28a0456eddd3c71fb4b55 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Sat, 31 May 2014 18:30:13 +0200 Subject: rtl818x_pci: provide dBm signal information for rtl8185 This patch makes the driver report signal information for rtl8185 boards using dBm instead of unspecified unit. Rtl8180 remains untouched. I did some tests to confirm the correctness of the measure performed by the board and it seems reasonably correct. The test setup has been made by connecting an AP with coax and RF attenuators to the card antenna port. In order to get a reference measure I tried with several cards with different chipset I own. I found that many gave different results, and I finally selected two cards that gave me consistent results to use as reference: AR9271 and Prism54-usb (isl3887 with Frisbee radio). Using this references I compared the RSSI information with my rtl8185 and I repeated tests with three different attenuation values, increasing attenuation by 10dB each step. I made only relative measures, making NO assumption about source power. CCK measures seem very close to my references, OFDM are a little bit less precise but, considering that these cards are not measuring instrumentation, IMHO this is still fairly good. CCK measures (1Mbps beacons) ATTENUATOR 1 p54usb: -58dBm ath9k_htc: -59dBm rtl8185: -59dBm ATTENUATOR 2 p54usb: -67dBm ath9k_htc: -68dBm rtl8185: -70dBm ATTENUATOR 3 p54usb: -78dBm ath9k_htc: -79dBm rtl8185: -79dBm OFDM measures (54Mbps ping) ATTENUATOR 1 p54usb: -58dBm ath9k_htc: -57dBm rtl8185: -62dBm ATTENUATOR 2 p54usb: -68dBm rtl8185: -71dBm Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index c2dd5e636d28..cd8c09076b52 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -269,9 +269,9 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) switch (priv->chip_family) { case RTL818X_CHIP_FAMILY_RTL8185: if (rx_status.rate_idx > 3) - signal = 90 - clamp_t(u8, agc, 25, 90); + signal = -clamp_t(u8, agc, 25, 90) - 9; else - signal = 95 - clamp_t(u8, agc, 30, 95); + signal = -clamp_t(u8, agc, 30, 95); break; case RTL818X_CHIP_FAMILY_RTL8180: sq = flags2 & 0xff; @@ -1754,8 +1754,7 @@ static int rtl8180_probe(struct pci_dev *pdev, dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SIGNAL_UNSPEC; + IEEE80211_HW_RX_INCLUDES_FCS; dev->vif_data_size = sizeof(struct rtl8180_vif); dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); @@ -1812,6 +1811,11 @@ static int rtl8180_probe(struct pci_dev *pdev, pci_try_set_mwi(pdev); } + if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185) + dev->flags |= IEEE80211_HW_SIGNAL_DBM; + else + dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; + rtl8180_eeprom_read(priv); switch (priv->rf_type) { -- cgit v1.2.3 From 325ed9ff14d2c726725324280ce3a56d6258b0ea Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Sat, 31 May 2014 18:30:26 +0200 Subject: rtl818x_pci: fix possible RX descriptor invalid data read RX descriptor data must be read only if the descriptor has been fully updated by HW. There is a "ownership" flag in the descriptor itself to test this. The driver code contains a read for the "ownership" flag and, after it, other read access for descriptor data. This is in DMA coherent memory, that is _not_ guaranteed to be immune to instruction reordering, thus it is possible that the descriptor data is read _before_ the "ownership" flag. This can theoretically lead to a DMA/CPU race that may end up with the driver reading the data when it is still not valid, and the "ownership" bit just after enough time that the HW make the whole descriptor valid. The driver will in this case believe the data is valid, but it will use the invalid data read earlier. In order to avoid this, this patch adds a rmb() to force the "ownership" bit read to be issued before other descriptor data reads are attempted. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index cd8c09076b52..1e2592918fc6 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -222,12 +222,20 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) struct rtl8187se_rx_desc *desc = entry; flags = le32_to_cpu(desc->flags); + /* if ownership flag is set, then we can trust the + * HW has written other fields. We must not trust + * other descriptor data read before we checked (read) + * the ownership flag + */ + rmb(); flags2 = le32_to_cpu(desc->flags2); tsft = le64_to_cpu(desc->tsft); } else { struct rtl8180_rx_desc *desc = entry; flags = le32_to_cpu(desc->flags); + /* same as above */ + rmb(); flags2 = le32_to_cpu(desc->flags2); tsft = le64_to_cpu(desc->tsft); } -- cgit v1.2.3 From c5ce4874d1f303dc851849d05191d79c3f798acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 31 May 2014 20:49:33 +0200 Subject: b43: drop B43_DEFAULT_CHANNEL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was never used, b43_switch_channel is always called with hw_value (from mac80211) or whatever get_default_chan returns. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_common.c | 3 --- drivers/net/wireless/b43/phy_common.h | 4 ---- 2 files changed, 7 deletions(-) diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 08244b3b327e..ac4cf2b8aca8 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -408,9 +408,6 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel) u16 channelcookie, savedcookie; int err; - if (new_channel == B43_DEFAULT_CHANNEL) - new_channel = phy->ops->get_default_chan(dev); - /* First we set the channel radio code to prevent the * firmware from sending ghost packets. */ diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 4ad6240d9ff4..9a92df46ae84 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -400,10 +400,6 @@ void b43_phy_take_out_of_reset(struct b43_wldev *dev); * b43_switch_channel - Switch to another channel */ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); -/** - * B43_DEFAULT_CHANNEL - Switch to the default channel. - */ -#define B43_DEFAULT_CHANNEL UINT_MAX /** * b43_software_rfkill - Turn the radio ON or OFF in software. -- cgit v1.2.3 From 53256511010b2ee226ded9155728862d90ac2b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 31 May 2014 20:49:34 +0200 Subject: b43: b43_op_config: drop check for core change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There aren't devices with multiple 802.11 cores supported by b43. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 32538ac5f7e4..a9e50ee125fa 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3798,17 +3798,13 @@ static void b43_set_retry_limits(struct b43_wldev *dev, static int b43_op_config(struct ieee80211_hw *hw, u32 changed) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev; - struct b43_phy *phy; + struct b43_wldev *dev = wl->current_dev; + struct b43_phy *phy = &dev->phy; struct ieee80211_conf *conf = &hw->conf; int antenna; int err = 0; - bool reload_bss = false; mutex_lock(&wl->mutex); - - dev = wl->current_dev; - b43_mac_suspend(dev); /* Switch the band (if necessary). This might change the active core. */ @@ -3816,15 +3812,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) if (err) goto out_unlock_mutex; - /* Need to reload all settings if the core changed */ - if (dev != wl->current_dev) { - dev = wl->current_dev; - changed = ~0; - reload_bss = true; - } - - phy = &dev->phy; - if (conf_is_ht(conf)) phy->is_40mhz = (conf_is_ht40_minus(conf) || conf_is_ht40_plus(conf)); @@ -3881,9 +3868,6 @@ out_mac_enable: out_unlock_mutex: mutex_unlock(&wl->mutex); - if (wl->vif && reload_bss) - b43_op_bss_info_changed(hw, wl->vif, &wl->vif->bss_conf, ~0); - return err; } -- cgit v1.2.3 From 8c79e5ee033798bc1147ec29f222c2ace6e9e897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 31 May 2014 20:49:35 +0200 Subject: b43: b43_op_config: use IEEE80211_CONF_CHANGE_CHANNEL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is tiny optimization and grouping band/channel ops. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index a9e50ee125fa..59aa4fdb2aeb 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3807,16 +3807,23 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); b43_mac_suspend(dev); - /* Switch the band (if necessary). This might change the active core. */ - err = b43_switch_band(dev, conf->chandef.chan); - if (err) - goto out_unlock_mutex; + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + if (conf_is_ht(conf)) + phy->is_40mhz = conf_is_ht40_minus(conf) || + conf_is_ht40_plus(conf); + else + phy->is_40mhz = false; - if (conf_is_ht(conf)) - phy->is_40mhz = - (conf_is_ht40_minus(conf) || conf_is_ht40_plus(conf)); - else - phy->is_40mhz = false; + /* Switch the band (if necessary). */ + err = b43_switch_band(dev, conf->chandef.chan); + if (err) + goto out_mac_enable; + + /* Switch to the requested channel. + * The firmware takes care of races with the TX handler. + */ + b43_switch_channel(dev, conf->chandef.chan->hw_value); + } if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) b43_set_retry_limits(dev, conf->short_frame_max_tx_count, @@ -3825,11 +3832,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) if (!changed) goto out_mac_enable; - /* Switch to the requested channel. - * The firmware takes care of races with the TX handler. */ - if (conf->chandef.chan->hw_value != phy->channel) - b43_switch_channel(dev, conf->chandef.chan->hw_value); - dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR); /* Adjust the desired TX power level. */ @@ -3865,7 +3867,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) out_mac_enable: b43_mac_enable(dev); -out_unlock_mutex: mutex_unlock(&wl->mutex); return err; -- cgit v1.2.3 From eb530b0fed7ec8ca435ec421cbff773b318a6a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 31 May 2014 20:49:36 +0200 Subject: b43: PHY: don't force default channel during init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PHY may need to be re-initialized during runtime (e.g. on band switch). Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_common.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index ac4cf2b8aca8..3bfb795f6a6d 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -94,7 +94,8 @@ int b43_phy_init(struct b43_wldev *dev) const struct b43_phy_operations *ops = phy->ops; int err; - phy->channel = ops->get_default_chan(dev); + if (!phy->channel) + phy->channel = ops->get_default_chan(dev); phy->ops->switch_analog(dev, true); b43_software_rfkill(dev, false); @@ -106,9 +107,7 @@ int b43_phy_init(struct b43_wldev *dev) } phy->do_full_init = false; - /* Make sure to switch hardware and firmware (SHM) to - * the default channel. */ - err = b43_switch_channel(dev, ops->get_default_chan(dev)); + err = b43_switch_channel(dev, phy->channel); if (err) { b43err(dev->wl, "PHY init: Channel switch to default failed\n"); goto err_phy_exit; -- cgit v1.2.3 From f9471e9973fd887b8af888b98860182b6c534ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 31 May 2014 20:49:37 +0200 Subject: b43: b43_op_config: set channel info before switching band MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Band switching code needs to know what channel we switch to. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 3 ++- drivers/net/wireless/b43/phy_common.c | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 59aa4fdb2aeb..5e4eed37e3ce 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3808,6 +3808,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) b43_mac_suspend(dev); if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + phy->channel = conf->chandef.chan->hw_value; if (conf_is_ht(conf)) phy->is_40mhz = conf_is_ht40_minus(conf) || conf_is_ht40_plus(conf); @@ -3822,7 +3823,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ - b43_switch_channel(dev, conf->chandef.chan->hw_value); + b43_switch_channel(dev, phy->channel); } if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 3bfb795f6a6d..b465011c14ea 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -424,7 +424,6 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel) if (err) goto err_restore_cookie; - dev->phy.channel = new_channel; /* Wait for the radio to tune to the channel and stabilize. */ msleep(8); -- cgit v1.2.3 From ea42e71c79068daa8bfd04f5e3c4a19b5e62f7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 31 May 2014 20:49:38 +0200 Subject: b43: store current channel using struct cfg80211_chan_def MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 1 + drivers/net/wireless/b43/phy_common.c | 9 +++++++-- drivers/net/wireless/b43/phy_common.h | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 5e4eed37e3ce..2b99ed31ab08 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3808,6 +3808,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) b43_mac_suspend(dev); if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + phy->chandef = &conf->chandef; phy->channel = conf->chandef.chan->hw_value; if (conf_is_ht(conf)) phy->is_40mhz = conf_is_ht40_minus(conf) || diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index b465011c14ea..9aa6c9c57393 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -94,8 +94,13 @@ int b43_phy_init(struct b43_wldev *dev) const struct b43_phy_operations *ops = phy->ops; int err; - if (!phy->channel) - phy->channel = ops->get_default_chan(dev); + /* During PHY init we need to use some channel. On the first init this + * function is called *before* b43_op_config, so our pointer is NULL. + */ + if (!phy->chandef) { + phy->chandef = &dev->wl->hw->conf.chandef; + phy->channel = phy->chandef->chan->hw_value; + } phy->ops->switch_analog(dev, true); b43_software_rfkill(dev, false); diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 9a92df46ae84..56dfe7aa50a7 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -267,6 +267,7 @@ struct b43_phy { unsigned long next_txpwr_check_time; /* Current channel */ + struct cfg80211_chan_def *chandef; unsigned int channel; u16 channel_freq; enum nl80211_channel_type channel_type; -- cgit v1.2.3 From 39e971ef1b0ced72b6504429296551bbf14ac965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 31 May 2014 20:49:39 +0200 Subject: b43: PHY: drop own channel_freq (get it from chandef when needed) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_common.h | 1 - drivers/net/wireless/b43/phy_ht.c | 2 +- drivers/net/wireless/b43/phy_n.c | 24 ++++++++++++++---------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 56dfe7aa50a7..399082026b03 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -269,7 +269,6 @@ struct b43_phy { /* Current channel */ struct cfg80211_chan_def *chandef; unsigned int channel; - u16 channel_freq; enum nl80211_channel_type channel_type; /* PHY TX errors counter. */ diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index 5d6833f18498..f2974c6b1c01 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -596,7 +596,7 @@ static void b43_phy_ht_tx_power_ctl_setup(struct b43_wldev *dev) u8 target[3]; s16 a1[3], b0[3], b1[3]; - u16 freq = dev->phy.channel_freq; + u16 freq = dev->phy.chandef->chan->center_freq; int i, c; if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 86569f6a8705..dc62f024f776 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -798,6 +798,7 @@ static void b43_chantab_radio_2056_upload(struct b43_wldev *dev, static void b43_radio_2056_setup(struct b43_wldev *dev, const struct b43_nphy_channeltab_entry_rev3 *e) { + struct b43_phy *phy = &dev->phy; struct ssb_sprom *sprom = dev->dev->bus_sprom; enum ieee80211_band band = b43_current_band(dev->wl); u16 offset; @@ -909,7 +910,7 @@ static void b43_radio_2056_setup(struct b43_wldev *dev, b43_radio_write(dev, offset | B2056_TX_PA_SPARE1, 0xee); } } else if (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ) { - u16 freq = dev->phy.channel_freq; + u16 freq = phy->chandef->chan->center_freq; if (freq < 5100) { paa_boost = 0xA; pada_boost = 0x77; @@ -1675,6 +1676,7 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, enum n_rssi_type rssi_type, /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) { + struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; u16 saved_regs_phy_rfctl[2]; @@ -1897,9 +1899,9 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) /* Remember for which channel we store configuration */ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - nphy->rssical_chanspec_2G.center_freq = dev->phy.channel_freq; + nphy->rssical_chanspec_2G.center_freq = phy->chandef->chan->center_freq; else - nphy->rssical_chanspec_5G.center_freq = dev->phy.channel_freq; + nphy->rssical_chanspec_5G.center_freq = phy->chandef->chan->center_freq; /* End of calibration, restore configuration */ b43_nphy_classifier(dev, 7, class); @@ -2528,7 +2530,7 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) } } } else { - u16 freq = phy->channel_freq; + u16 freq = phy->chandef->chan->center_freq; if ((freq >= 5180 && freq <= 5230) || (freq >= 5745 && freq <= 5805)) { b43_radio_write(dev, 0x7D, 0xFF); @@ -3184,12 +3186,13 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrFix */ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) { + struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; struct ssb_sprom *sprom = dev->dev->bus_sprom; u8 txpi[2], bbmult, i; u16 tmp, radio_gain, dac_gain; - u16 freq = dev->phy.channel_freq; + u16 freq = phy->chandef->chan->center_freq; u32 txgain; /* u32 gaintbl; rev3+ */ @@ -3474,6 +3477,7 @@ static void b43_nphy_tx_prepare_adjusted_power_table(struct b43_wldev *dev) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlSetup */ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev) { + struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; struct ssb_sprom *sprom = dev->dev->bus_sprom; @@ -3483,7 +3487,7 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev) s32 num, den, pwr; u32 regval[64]; - u16 freq = dev->phy.channel_freq; + u16 freq = phy->chandef->chan->center_freq; u16 tmp; u16 r; /* routing */ u8 i, c; @@ -4500,7 +4504,7 @@ static void b43_nphy_save_cal(struct b43_wldev *dev) txcal_radio_regs[2] = b43_radio_read(dev, 0x8D); txcal_radio_regs[3] = b43_radio_read(dev, 0xBC); } - iqcal_chanspec->center_freq = dev->phy.channel_freq; + iqcal_chanspec->center_freq = dev->phy.chandef->chan->center_freq; iqcal_chanspec->channel_type = dev->phy.channel_type; b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 8, table); @@ -4581,6 +4585,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, struct nphy_txgains target, bool full, bool mphase) { + struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; int i; int error = 0; @@ -4773,7 +4778,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, nphy->txiqlocal_bestc); nphy->txiqlocal_coeffsvalid = true; nphy->txiqlocal_chanspec.center_freq = - dev->phy.channel_freq; + phy->chandef->chan->center_freq; nphy->txiqlocal_chanspec.channel_type = dev->phy.channel_type; } else { @@ -4811,7 +4816,7 @@ static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev) bool equal = true; if (!nphy->txiqlocal_coeffsvalid || - nphy->txiqlocal_chanspec.center_freq != dev->phy.channel_freq || + nphy->txiqlocal_chanspec.center_freq != dev->phy.chandef->chan->center_freq || nphy->txiqlocal_chanspec.channel_type != dev->phy.channel_type) return; @@ -5502,7 +5507,6 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, /* Channel is set later in common code, but we need to set it on our own to let this function's subcalls work properly. */ phy->channel = channel->hw_value; - phy->channel_freq = channel->center_freq; if (b43_channel_type_is_40mhz(phy->channel_type) != b43_channel_type_is_40mhz(channel_type)) -- cgit v1.2.3 From bee6d4b272ba6e668f0c12d8bb66d76e1826f406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 31 May 2014 20:49:40 +0200 Subject: b43: PHY: drop is_40mhz (get width info from chandef) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 5 ---- drivers/net/wireless/b43/phy_common.c | 5 ++++ drivers/net/wireless/b43/phy_common.h | 5 ++-- drivers/net/wireless/b43/phy_n.c | 53 +++++++++++++++++------------------ 4 files changed, 33 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2b99ed31ab08..4b662d0abdd2 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3810,11 +3810,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { phy->chandef = &conf->chandef; phy->channel = conf->chandef.chan->hw_value; - if (conf_is_ht(conf)) - phy->is_40mhz = conf_is_ht40_minus(conf) || - conf_is_ht40_plus(conf); - else - phy->is_40mhz = false; /* Switch the band (if necessary). */ err = b43_switch_band(dev, conf->chandef.chan); diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 9aa6c9c57393..e7e83835f725 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -553,6 +553,11 @@ bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type) channel_type == NL80211_CHAN_HT40PLUS); } +bool b43_is_40mhz(struct b43_wldev *dev) +{ + return dev->phy.chandef->width == NL80211_CHAN_WIDTH_40; +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ void b43_phy_force_clock(struct b43_wldev *dev, bool force) { diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 399082026b03..674422fd22e6 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -228,9 +228,6 @@ struct b43_phy { bool supports_2ghz; bool supports_5ghz; - /* HT info */ - bool is_40mhz; - /* Is GMODE (2 GHz mode) bit enabled? */ bool gmode; @@ -452,6 +449,8 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on); bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type); +bool b43_is_40mhz(struct b43_wldev *dev); + void b43_phy_force_clock(struct b43_wldev *dev, bool force); struct b43_c32 b43_cordic(int theta); diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index dc62f024f776..dc1249381275 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -896,7 +896,7 @@ static void b43_radio_2056_setup(struct b43_wldev *dev, offset | B2056_TX_MIXG_BOOST_TUNE, mixg_boost); } else { - bias = dev->phy.is_40mhz ? 0x40 : 0x20; + bias = b43_is_40mhz(dev) ? 0x40 : 0x20; b43_radio_write(dev, offset | B2056_TX_INTPAG_IMAIN_STAT, bias); @@ -1211,8 +1211,7 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, u16 bw, len, rot, angle; struct b43_c32 *samples; - - bw = (dev->phy.is_40mhz) ? 40 : 20; + bw = b43_is_40mhz(dev) ? 40 : 20; len = bw << 3; if (test) { @@ -1221,7 +1220,7 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, else bw = 80; - if (dev->phy.is_40mhz) + if (b43_is_40mhz(dev)) bw <<= 1; len = bw << 1; @@ -1264,7 +1263,7 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, } /* TODO: add modify_bbmult argument */ - if (!dev->phy.is_40mhz) + if (!b43_is_40mhz(dev)) tmp = 0x6464; else tmp = 0x4747; @@ -2194,7 +2193,7 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84); b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84); - if (!dev->phy.is_40mhz) { + if (!b43_is_40mhz(dev)) { /* Set dwell lengths */ b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B); b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B); @@ -2208,7 +2207,7 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev) b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES, ~B43_NPHY_C2_CLIPWBTHRES_CLIP2, 21); - if (!dev->phy.is_40mhz) { + if (!b43_is_40mhz(dev)) { b43_phy_maskset(dev, B43_NPHY_C1_CGAINI, ~B43_NPHY_C1_CGAINI_GAINBKOFF, 0x1); b43_phy_maskset(dev, B43_NPHY_C2_CGAINI, @@ -2223,12 +2222,12 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev) if (nphy->gain_boost) { if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ && - dev->phy.is_40mhz) + b43_is_40mhz(dev)) code = 4; else code = 5; } else { - code = dev->phy.is_40mhz ? 6 : 7; + code = b43_is_40mhz(dev) ? 6 : 7; } /* Set HPVGA2 index */ @@ -2300,7 +2299,7 @@ static void b43_nphy_gain_ctl_workarounds(struct b43_wldev *dev) static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset) { if (!offset) - offset = (dev->phy.is_40mhz) ? 0x159 : 0x154; + offset = b43_is_40mhz(dev) ? 0x159 : 0x154; return b43_ntab_read(dev, B43_NTAB16(7, offset)) & 0x7; } @@ -2373,13 +2372,13 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) lpf_40 = b43_nphy_read_lpf_ctl(dev, 0x159); lpf_11b = b43_nphy_read_lpf_ctl(dev, 0x152); if (b43_nphy_ipa(dev)) { - if ((phy->radio_rev == 5 && phy->is_40mhz) || + if ((phy->radio_rev == 5 && b43_is_40mhz(dev)) || phy->radio_rev == 7 || phy->radio_rev == 8) { bcap_val = b43_radio_read(dev, 0x16b); scap_val = b43_radio_read(dev, 0x16a); scap_val_11b = scap_val; bcap_val_11b = bcap_val; - if (phy->radio_rev == 5 && phy->is_40mhz) { + if (phy->radio_rev == 5 && b43_is_40mhz(dev)) { scap_val_11n_20 = scap_val; bcap_val_11n_20 = bcap_val; scap_val_11n_40 = bcap_val_11n_40 = 0xc; @@ -2521,7 +2520,7 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) } } } else if (phy->radio_rev == 7 || phy->radio_rev == 8) { - if (!phy->is_40mhz) { + if (!b43_is_40mhz(dev)) { b43_radio_write(dev, 0x5F, 0x14); b43_radio_write(dev, 0xE8, 0x12); } else { @@ -2594,7 +2593,7 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) b43_ntab_write(dev, B43_NTAB16(7, 0x123), 0x77); b43_ntab_write(dev, B43_NTAB16(7, 0x12A), 0x77); - if (!phy->is_40mhz) { + if (!b43_is_40mhz(dev)) { b43_ntab_write(dev, B43_NTAB32(16, 0x03), 0x18D); b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x18D); } else { @@ -2693,7 +2692,7 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) b43_phy_maskset(dev, B43_NPHY_SGILTRNOFFSET, 0xF0FF, 0x0700); - if (!dev->phy.is_40mhz) { + if (!b43_is_40mhz(dev)) { b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D); b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D); } else { @@ -3116,7 +3115,7 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~B43_NPHY_BPHY_CTL3_SCALE, 0x5A); - if (dev->phy.rev < 2 && dev->phy.is_40mhz) + if (dev->phy.rev < 2 && b43_is_40mhz(dev)) b43_hf_write(dev, b43_hf_read(dev) | B43_HF_TSSIRPSMW); } else { b43_ntab_write_bulk(dev, B43_NTAB16(26, 64), 84, @@ -3170,7 +3169,7 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) else if (dev->phy.rev < 2) b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~0xFF, 0x40); - if (dev->phy.rev < 2 && dev->phy.is_40mhz) + if (dev->phy.rev < 2 && b43_is_40mhz(dev)) b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_TSSIRPSMW); if (b43_nphy_ipa(dev)) { @@ -3442,21 +3441,21 @@ static void b43_nphy_tx_prepare_adjusted_power_table(struct b43_wldev *dev) delta = 0; switch (stf_mode) { case 0: - if (dev->phy.is_40mhz && dev->phy.rev >= 5) { + if (b43_is_40mhz(dev) && dev->phy.rev >= 5) { idx = 68; } else { delta = 1; - idx = dev->phy.is_40mhz ? 52 : 4; + idx = b43_is_40mhz(dev) ? 52 : 4; } break; case 1: - idx = dev->phy.is_40mhz ? 76 : 28; + idx = b43_is_40mhz(dev) ? 76 : 28; break; case 2: - idx = dev->phy.is_40mhz ? 84 : 36; + idx = b43_is_40mhz(dev) ? 84 : 36; break; case 3: - idx = dev->phy.is_40mhz ? 92 : 44; + idx = b43_is_40mhz(dev) ? 92 : 44; break; } @@ -3996,7 +3995,7 @@ static void b43_nphy_spur_workaround(struct b43_wldev *dev) if (nphy->gband_spurwar_en) { /* TODO: N PHY Adjust Analog Pfbw (7) */ - if (channel == 11 && dev->phy.is_40mhz) + if (channel == 11 && b43_is_40mhz(dev)) ; /* TODO: N PHY Adjust Min Noise Var(2, tone, noise)*/ else ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/ @@ -4290,7 +4289,7 @@ static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_N(offset[i] + j), tbl_tx_filter_coef_rev4[i][j]); - if (dev->phy.is_40mhz) { + if (b43_is_40mhz(dev)) { for (j = 0; j < 15; j++) b43_phy_write(dev, B43_PHY_N(offset[0] + j), tbl_tx_filter_coef_rev4[3][j]); @@ -4626,7 +4625,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, (dev->phy.rev == 5 && nphy->ipa2g_on && b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ); if (phy6or5x) { - if (dev->phy.is_40mhz) { + if (b43_is_40mhz(dev)) { b43_ntab_write_bulk(dev, B43_NTAB16(15, 0), 18, tbl_tx_iqlo_cal_loft_ladder_40); b43_ntab_write_bulk(dev, B43_NTAB16(15, 32), 18, @@ -4641,13 +4640,13 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9); - if (!dev->phy.is_40mhz) + if (!b43_is_40mhz(dev)) freq = 2500; else freq = 5000; if (nphy->mphase_cal_phase_id > 2) - b43_nphy_run_samples(dev, (dev->phy.is_40mhz ? 40 : 20) * 8, + b43_nphy_run_samples(dev, (b43_is_40mhz(dev) ? 40 : 20) * 8, 0xFFFF, 0, true, false); else error = b43_nphy_tx_tone(dev, freq, 250, true, false); -- cgit v1.2.3 From 427fa00b8953b4cc428737af2b062e8ab4de3e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 31 May 2014 20:49:41 +0200 Subject: b43: PHY: drop channel_type (we can get this info from chandef) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_common.c | 6 ------ drivers/net/wireless/b43/phy_common.h | 3 --- drivers/net/wireless/b43/phy_n.c | 11 +++++++---- drivers/net/wireless/b43/tables_nphy.c | 2 +- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index e7e83835f725..2d05b5987168 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -547,12 +547,6 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on) } -bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type) -{ - return (channel_type == NL80211_CHAN_HT40MINUS || - channel_type == NL80211_CHAN_HT40PLUS); -} - bool b43_is_40mhz(struct b43_wldev *dev) { return dev->phy.chandef->width == NL80211_CHAN_WIDTH_40; diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 674422fd22e6..3912274f71e3 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -266,7 +266,6 @@ struct b43_phy { /* Current channel */ struct cfg80211_chan_def *chandef; unsigned int channel; - enum nl80211_channel_type channel_type; /* PHY TX errors counter. */ atomic_t txerr_cnt; @@ -447,8 +446,6 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset); */ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on); -bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type); - bool b43_is_40mhz(struct b43_wldev *dev); void b43_phy_force_clock(struct b43_wldev *dev, bool force); diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index dc1249381275..6398c7e45ab7 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -4504,7 +4504,8 @@ static void b43_nphy_save_cal(struct b43_wldev *dev) txcal_radio_regs[3] = b43_radio_read(dev, 0xBC); } iqcal_chanspec->center_freq = dev->phy.chandef->chan->center_freq; - iqcal_chanspec->channel_type = dev->phy.channel_type; + iqcal_chanspec->channel_type = + cfg80211_get_chandef_type(dev->phy.chandef); b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 8, table); if (nphy->hang_avoid) @@ -4779,7 +4780,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, nphy->txiqlocal_chanspec.center_freq = phy->chandef->chan->center_freq; nphy->txiqlocal_chanspec.channel_type = - dev->phy.channel_type; + cfg80211_get_chandef_type(phy->chandef); } else { length = 11; if (dev->phy.rev < 3) @@ -4816,7 +4817,7 @@ static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev) if (!nphy->txiqlocal_coeffsvalid || nphy->txiqlocal_chanspec.center_freq != dev->phy.chandef->chan->center_freq || - nphy->txiqlocal_chanspec.channel_type != dev->phy.channel_type) + nphy->txiqlocal_chanspec.channel_type != cfg80211_get_chandef_type(dev->phy.chandef)) return; b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer); @@ -5441,7 +5442,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, bool avoid = false; if (dev->phy.n->spur_avoid == B43_SPUR_AVOID_FORCE) { avoid = true; - } else if (!b43_channel_type_is_40mhz(phy->channel_type)) { + } else if (!b43_is_40mhz(dev)) { if ((ch >= 5 && ch <= 8) || ch == 13 || ch == 14) avoid = true; } else { /* 40MHz */ @@ -5507,9 +5508,11 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, own to let this function's subcalls work properly. */ phy->channel = channel->hw_value; +#if 0 if (b43_channel_type_is_40mhz(phy->channel_type) != b43_channel_type_is_40mhz(channel_type)) ; /* TODO: BMAC BW Set (channel_type) */ +#endif if (channel_type == NL80211_CHAN_HT40PLUS) b43_phy_set(dev, B43_NPHY_RXCTL, diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 4047c05e3807..b22171592926 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -3191,7 +3191,7 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent( /* Some workarounds to the workarounds... */ if (ghz5 && dev->phy.rev >= 6) { if (dev->phy.radio_rev == 11 && - !b43_channel_type_is_40mhz(dev->phy.channel_type)) + !b43_is_40mhz(dev)) e->cliplo_gain = 0x2d; } else if (!ghz5 && dev->phy.rev >= 5) { static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a, -- cgit v1.2.3 From c0f36ebf9f5e92d38a5859e88527109388fc398b Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 1 Jun 2014 14:39:20 +0200 Subject: net: wireless: libertas: cmd.c: Cleaning up uninitialized variables There is a risk that the variable will be used without being initialized. This was largely found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index aaa297315c47..0387a5b380c8 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1111,6 +1111,7 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on) cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.control = 0; /* Only v8 and below support setting the preamble */ if (priv->fwrelease < 0x09000000) { -- cgit v1.2.3 From 57eaeb6efa1f732ecf61130d7e0bb67c3ad9e4af Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 1 Jun 2014 14:44:13 +0200 Subject: net: wireless: rt2x00: rt2x00mac.c: Cleaning up uninitialized variables There is a risk that the variable will be used without being initialized. This was largely found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 212ac4842c16..671836210744 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -799,6 +799,8 @@ int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) setup.tx = tx_ant; setup.rx = rx_ant; + setup.rx_chain_num = 0; + setup.tx_chain_num = 0; rt2x00lib_config_antenna(rt2x00dev, setup); -- cgit v1.2.3 From 7949513b315ac70abcd292170ba1099a9a56dbfe Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 1 Jun 2014 22:14:38 +0200 Subject: net: wireless: rtlwifi: rtl8192de: phy.c: Cleaning up uninitialized variable There is a risk that the variables will be used without being initialized. Have also moved variable to the part of the code where it is used. This was largely found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192de/phy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 3d1f0dd4e52d..592125a5f19c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -203,11 +203,12 @@ u32 rtl92d_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u32 returnvalue, originalvalue, bitshift; - u8 dbi_direct; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask); if (rtlhal->during_mac1init_radioa || rtlhal->during_mac0init_radiob) { + u8 dbi_direct = 0; + /* mac1 use phy0 read radio_b. */ /* mac0 use phy1 read radio_b. */ if (rtlhal->during_mac1init_radioa) -- cgit v1.2.3 From 7d8831bb1bfbf8db896bfc1de9d0b3bc7a8e60f0 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Wed, 4 Jun 2014 15:32:32 +0200 Subject: mwifiex: Remove custom world regulatory domain A custom regulatory domain was introduced in this commit: cc0ba0d mwifiex: support custom world regulatory domain The commit description says that it was introduced because the world regulatory domain does not include channels 52-64 and 100-140. These channels are described in the world regulatory domain now, so we can drop this custom regulatory domain. Signed-off-by: Markus Pargmann Acked-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 36 --------------------------------- 1 file changed, 36 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index e95dec91a561..201edbf76c81 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -42,36 +42,6 @@ static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = { .beacon_int_infra_match = true, }; -static const struct ieee80211_regdomain mwifiex_world_regdom_custom = { - .n_reg_rules = 7, - .alpha2 = "99", - .reg_rules = { - /* Channel 1 - 11 */ - REG_RULE(2412-10, 2462+10, 40, 3, 20, 0), - /* Channel 12 - 13 */ - REG_RULE(2467-10, 2472+10, 20, 3, 20, - NL80211_RRF_NO_IR), - /* Channel 14 */ - REG_RULE(2484-10, 2484+10, 20, 3, 20, - NL80211_RRF_NO_IR | - NL80211_RRF_NO_OFDM), - /* Channel 36 - 48 */ - REG_RULE(5180-10, 5240+10, 40, 3, 20, - NL80211_RRF_NO_IR), - /* Channel 149 - 165 */ - REG_RULE(5745-10, 5825+10, 40, 3, 20, - NL80211_RRF_NO_IR), - /* Channel 52 - 64 */ - REG_RULE(5260-10, 5320+10, 40, 3, 30, - NL80211_RRF_NO_IR | - NL80211_RRF_DFS), - /* Channel 100 - 140 */ - REG_RULE(5500-10, 5700+10, 40, 3, 30, - NL80211_RRF_NO_IR | - NL80211_RRF_DFS), - } -}; - /* * This function maps the nl802.11 channel type into driver channel type. * @@ -2916,12 +2886,6 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_TDLS_EXTERNAL_SETUP; - wiphy->regulatory_flags |= - REGULATORY_CUSTOM_REG | - REGULATORY_STRICT_REG; - - wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom); - #ifdef CONFIG_PM wiphy->wowlan = &mwifiex_wowlan_support; #endif -- cgit v1.2.3 From 283dafa1c69475596701da7767df471c0a71d8fb Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 5 Jun 2014 13:52:23 +0200 Subject: rt2x00: change beaconing locking This patch is needed for further changes to keep global variables consistent when changing beaconing on diffrent vif's. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 7 +++++-- drivers/net/wireless/rt2x00/rt2x00mac.c | 6 ++---- drivers/net/wireless/rt2x00/rt2x00queue.c | 21 ++------------------- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 2bde6729f5e6..72e3e8138111 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -141,8 +141,11 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; - if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) + if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) { + mutex_lock(&intf->beacon_skb_mutex); rt2x00queue_update_beacon(rt2x00dev, vif); + mutex_unlock(&intf->beacon_skb_mutex); + } } static void rt2x00lib_intf_scheduled(struct work_struct *work) @@ -216,7 +219,7 @@ static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac, * never be called for USB devices. */ WARN_ON(rt2x00_is_usb(rt2x00dev)); - rt2x00queue_update_beacon_locked(rt2x00dev, vif); + rt2x00queue_update_beacon(rt2x00dev, vif); } void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 671836210744..d63636bbb9d7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -624,6 +624,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, * Start/stop beaconing. */ if (changes & BSS_CHANGED_BEACON_ENABLED) { + mutex_lock(&intf->beacon_skb_mutex); if (!bss_conf->enable_beacon && intf->enable_beacon) { rt2x00dev->intf_beaconing--; intf->enable_beacon = false; @@ -639,9 +640,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, * Last beaconing interface disabled * -> stop beacon queue. */ - mutex_lock(&intf->beacon_skb_mutex); rt2x00queue_stop_queue(rt2x00dev->bcn); - mutex_unlock(&intf->beacon_skb_mutex); } } else if (bss_conf->enable_beacon && !intf->enable_beacon) { rt2x00dev->intf_beaconing++; @@ -658,11 +657,10 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, * First beaconing interface enabled * -> start beacon queue. */ - mutex_lock(&intf->beacon_skb_mutex); rt2x00queue_start_queue(rt2x00dev->bcn); - mutex_unlock(&intf->beacon_skb_mutex); } } + mutex_unlock(&intf->beacon_skb_mutex); } /* diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 5642ccceca7c..8e68f87ab13c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -754,8 +754,6 @@ int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev, if (unlikely(!intf->beacon)) return -ENOBUFS; - mutex_lock(&intf->beacon_skb_mutex); - /* * Clean up the beacon skb. */ @@ -768,13 +766,11 @@ int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev, if (rt2x00dev->ops->lib->clear_beacon) rt2x00dev->ops->lib->clear_beacon(intf->beacon); - mutex_unlock(&intf->beacon_skb_mutex); - return 0; } -int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev, - struct ieee80211_vif *vif) +int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, + struct ieee80211_vif *vif) { struct rt2x00_intf *intf = vif_to_intf(vif); struct skb_frame_desc *skbdesc; @@ -815,19 +811,6 @@ int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev, } -int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, - struct ieee80211_vif *vif) -{ - struct rt2x00_intf *intf = vif_to_intf(vif); - int ret; - - mutex_lock(&intf->beacon_skb_mutex); - ret = rt2x00queue_update_beacon_locked(rt2x00dev, vif); - mutex_unlock(&intf->beacon_skb_mutex); - - return ret; -} - bool rt2x00queue_for_each_entry(struct data_queue *queue, enum queue_index start, enum queue_index end, -- cgit v1.2.3 From ba08910e04e09088cac42ab6d5ceedd1239a3208 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 5 Jun 2014 13:52:24 +0200 Subject: rt2x00: change beaconing setup on RT2800 As reported by Matthias, on 5572 chip, even if we clear up TXWI of corresponding beacon, hardware still try to send it or do other action that increase power consumption peak up to 1A. To avoid the issue, setup beaconing dynamically by configuring offsets of currently active beacons and MAC_BSSID_DW1_BSS_BCN_NUM variable, which limit number of beacons that hardware will try to send. Reported-by: Matthias Fend Signed-off-by: Stanislaw Gruszka Acked-by: Helmut Schaa Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 45 +++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00queue.h | 1 + 2 files changed, 46 insertions(+) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index c17fcf272728..c45b2d31ea65 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -947,6 +947,40 @@ static inline u8 rt2800_get_beacon_offset(struct rt2x00_dev *rt2x00dev, return BEACON_BASE_TO_OFFSET(rt2800_hw_beacon_base(rt2x00dev, index)); } +static void rt2800_update_beacons_setup(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue = rt2x00dev->bcn; + struct queue_entry *entry; + int i, bcn_num = 0; + u64 off, reg = 0; + u32 bssid_dw1; + + /* + * Setup offsets of all active beacons in BCN_OFFSET{0,1} registers. + */ + for (i = 0; i < queue->limit; i++) { + entry = &queue->entries[i]; + if (!test_bit(ENTRY_BCN_ENABLED, &entry->flags)) + continue; + off = rt2800_get_beacon_offset(rt2x00dev, entry->entry_idx); + reg |= off << (8 * bcn_num); + bcn_num++; + } + + WARN_ON_ONCE(bcn_num != rt2x00dev->intf_beaconing); + + rt2800_register_write(rt2x00dev, BCN_OFFSET0, (u32) reg); + rt2800_register_write(rt2x00dev, BCN_OFFSET1, (u32) (reg >> 32)); + + /* + * H/W sends up to MAC_BSSID_DW1_BSS_BCN_NUM + 1 consecutive beacons. + */ + rt2800_register_read(rt2x00dev, MAC_BSSID_DW1, &bssid_dw1); + rt2x00_set_field32(&bssid_dw1, MAC_BSSID_DW1_BSS_BCN_NUM, + bcn_num > 0 ? bcn_num - 1 : 0); + rt2800_register_write(rt2x00dev, MAC_BSSID_DW1, bssid_dw1); +} + void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; @@ -1003,6 +1037,12 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data, entry->skb->len + padding_len); + __set_bit(ENTRY_BCN_ENABLED, &entry->flags); + + /* + * Change global beacons settings. + */ + rt2800_update_beacons_setup(rt2x00dev); /* * Restore beaconing state. @@ -1053,7 +1093,12 @@ void rt2800_clear_beacon(struct queue_entry *entry) * Clear beacon. */ rt2800_clear_beacon_register(rt2x00dev, entry->entry_idx); + __clear_bit(ENTRY_BCN_ENABLED, &entry->flags); + /* + * Change global beacons settings. + */ + rt2800_update_beacons_setup(rt2x00dev); /* * Restore beaconing state. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index c48125be0e34..2233b911a1d7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -353,6 +353,7 @@ struct txentry_desc { */ enum queue_entry_flags { ENTRY_BCN_ASSIGNED, + ENTRY_BCN_ENABLED, ENTRY_OWNER_DEVICE_DATA, ENTRY_DATA_PENDING, ENTRY_DATA_IO_FAILED, -- cgit v1.2.3 From 88ff2f45f23eb0f0e262251b34edb4582ce8e188 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 5 Jun 2014 13:52:25 +0200 Subject: rt2x00: change default MAC_BSSID_DW1_BSS_BCN_NUM We setup MAC_BSSID_DW1_BSS_BCN_NUM dynamically when numbers of active beacons increase. Change default to 0 to tell hardware that we want to send only one beacon as default. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index c45b2d31ea65..a9cdddd2ab1a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1601,7 +1601,7 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, if (!is_zero_ether_addr((const u8 *)conf->bssid)) { reg = le32_to_cpu(conf->bssid[1]); rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 3); - rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 7); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); conf->bssid[1] = cpu_to_le32(reg); } -- cgit v1.2.3 From ddb405506cc2273e2a367383831b50053464929b Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 5 Jun 2014 13:52:26 +0200 Subject: rt2x00: change order when stop beaconing When no beaconing is needed, first stop beacon queue (disable beaconing globally) to avoid possible sending of not prepared beacon on short period after clearing beacon and before stop of BCN queue. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index d63636bbb9d7..e5935ea3719f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -628,12 +628,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, if (!bss_conf->enable_beacon && intf->enable_beacon) { rt2x00dev->intf_beaconing--; intf->enable_beacon = false; - /* - * Clear beacon in the H/W for this vif. This is needed - * to disable beaconing on this particular interface - * and keep it running on other interfaces. - */ - rt2x00queue_clear_beacon(rt2x00dev, vif); if (rt2x00dev->intf_beaconing == 0) { /* @@ -642,6 +636,12 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, */ rt2x00queue_stop_queue(rt2x00dev->bcn); } + /* + * Clear beacon in the H/W for this vif. This is needed + * to disable beaconing on this particular interface + * and keep it running on other interfaces. + */ + rt2x00queue_clear_beacon(rt2x00dev, vif); } else if (bss_conf->enable_beacon && !intf->enable_beacon) { rt2x00dev->intf_beaconing++; intf->enable_beacon = true; -- cgit v1.2.3 From 19dcb76842d6d51690188c49c5c3142077f8ec5a Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 5 Jun 2014 13:52:27 +0200 Subject: rt2x00: do not initialize BCN_OFFSET registers We setup BCN_OFFSET{0,1} registers dynamically, don't have to initialize them. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index a9cdddd2ab1a..893c9d5f3d6f 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -4562,28 +4562,6 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) if (ret) return ret; - rt2800_register_read(rt2x00dev, BCN_OFFSET0, ®); - rt2x00_set_field32(®, BCN_OFFSET0_BCN0, - rt2800_get_beacon_offset(rt2x00dev, 0)); - rt2x00_set_field32(®, BCN_OFFSET0_BCN1, - rt2800_get_beacon_offset(rt2x00dev, 1)); - rt2x00_set_field32(®, BCN_OFFSET0_BCN2, - rt2800_get_beacon_offset(rt2x00dev, 2)); - rt2x00_set_field32(®, BCN_OFFSET0_BCN3, - rt2800_get_beacon_offset(rt2x00dev, 3)); - rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg); - - rt2800_register_read(rt2x00dev, BCN_OFFSET1, ®); - rt2x00_set_field32(®, BCN_OFFSET1_BCN4, - rt2800_get_beacon_offset(rt2x00dev, 4)); - rt2x00_set_field32(®, BCN_OFFSET1_BCN5, - rt2800_get_beacon_offset(rt2x00dev, 5)); - rt2x00_set_field32(®, BCN_OFFSET1_BCN6, - rt2800_get_beacon_offset(rt2x00dev, 6)); - rt2x00_set_field32(®, BCN_OFFSET1_BCN7, - rt2800_get_beacon_offset(rt2x00dev, 7)); - rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg); - rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); -- cgit v1.2.3 From f0db59e1c491e921e412148ce05558bfcf9aaa64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 5 Jun 2014 20:20:44 +0200 Subject: bcma: gpio: register all 32 GPIOs on BCM53572 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've here a device detected as: bcma: bus0: Found chip with id 0xD144, rev 0x01 and package 0x08 I couldn't find GPIO handling hw button until trying GPIO 20. It seems BCM53572 also has 32 GPIOs. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/bcma/driver_gpio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c index d7f81ad56b8a..aec9f850b4a8 100644 --- a/drivers/bcma/driver_gpio.c +++ b/drivers/bcma/driver_gpio.c @@ -220,6 +220,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) #endif switch (cc->core->bus->chipinfo.id) { case BCMA_CHIP_ID_BCM5357: + case BCMA_CHIP_ID_BCM53572: chip->ngpio = 32; break; default: -- cgit v1.2.3 From 4dbc13fae485c2519e995b2e0d8580641f14cad0 Mon Sep 17 00:00:00 2001 From: Zhiyuan Yang Date: Fri, 6 Jun 2014 19:47:42 -0700 Subject: mwifiex: support wowlan magic-packet encapsulated as UDP packet When magic-packet is generated as a UDP packet the offset should be 20+8 more bytes to cover IPv4 header and UDP header. So the total offset become 56. Add a new MEF entry to support both magic-packet patterns generated by different tools. Cc: Andreas Fenkart Signed-off-by: Zhiyuan Yang Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 201edbf76c81..e8981afb208b 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2453,6 +2453,16 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, mef_entry->filter[filt_num].filt_type = TYPE_EQ; if (filt_num) mef_entry->filter[filt_num].filt_action = TYPE_OR; + + filt_num++; + mef_entry->filter[filt_num].repeat = 16; + memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, + ETH_ALEN); + mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = + ETH_ALEN; + mef_entry->filter[filt_num].offset = 56; + mef_entry->filter[filt_num].filt_type = TYPE_EQ; + mef_entry->filter[filt_num].filt_action = TYPE_OR; } if (!mef_cfg.criteria) -- cgit v1.2.3 From ef0a68a832cccfc8400aa32b2a3d65e16d29ae9d Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 6 Jun 2014 19:47:44 -0700 Subject: mwifiex: wowlan: do not disconnect on suspend For users who do not need wowlan, load mwifiex.ko with disconnect_on_suspend = 1; or iw phy0 wowlan disable. Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sta_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 536c14aa71f3..229526356d9b 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -26,7 +26,7 @@ #include "11n.h" #include "cfg80211.h" -static int disconnect_on_suspend = 1; +static int disconnect_on_suspend; module_param(disconnect_on_suspend, int, 0644); /* -- cgit v1.2.3 From b101426aae371b91ad10c7553e54725cc5844e4a Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 7 Jun 2014 07:18:30 +0400 Subject: rsi: Use module_usb_driver module_usb_driver eliminates the boilerplate and makes the code simpler, in addition to the fact currently rsi_module_init() ignores usb_deregister() error. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_usb.c | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 4c46e5631e2f..3226f19989e7 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -550,33 +550,7 @@ static struct usb_driver rsi_driver = { #endif }; -/** - * rsi_module_init() - This function registers the client driver. - * @void: Void. - * - * Return: 0 on success. - */ -static int rsi_module_init(void) -{ - usb_register(&rsi_driver); - rsi_dbg(INIT_ZONE, "%s: Registering driver\n", __func__); - return 0; -} - -/** - * rsi_module_exit() - This function unregisters the client driver. - * @void: Void. - * - * Return: None. - */ -static void rsi_module_exit(void) -{ - usb_deregister(&rsi_driver); - rsi_dbg(INFO_ZONE, "%s: Unregistering driver\n", __func__); -} - -module_init(rsi_module_init); -module_exit(rsi_module_exit); +module_usb_driver(rsi_driver); MODULE_AUTHOR("Redpine Signals Inc"); MODULE_DESCRIPTION("Common USB layer for RSI drivers"); -- cgit v1.2.3 From e860c33f7d05907bb21ea6f0c2b085b75b028e3d Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 7 Jun 2014 07:18:31 +0400 Subject: rsi_91x_sdio: add error handling into rsi_module_init() Fix rsi_module_init() to propagate sdio_register_driver() errors. Signed-off-by: Alexey Khoroshilov Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 46e7af446f01..8428858204a6 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -820,9 +820,11 @@ static struct sdio_driver rsi_driver = { */ static int rsi_module_init(void) { - sdio_register_driver(&rsi_driver); + int ret; + + ret = sdio_register_driver(&rsi_driver); rsi_dbg(INIT_ZONE, "%s: Registering driver\n", __func__); - return 0; + return ret; } /** -- cgit v1.2.3 From 6437f51ec36af8ef1e3e2659439b35c37e5498e2 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 10 Jun 2014 10:37:24 -0700 Subject: rtlwifi: btcoexist: avoid format string in printk Since CL_PRINTF only ever takes a single argument, make sure a format string cannot leak into printk. Signed-off-by: Kees Cook Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h index 871fc3c6d559..049f4c8d98a8 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h @@ -114,7 +114,7 @@ extern u32 btc_dbg_type[]; #define CL_SPRINTF snprintf -#define CL_PRINTF printk +#define CL_PRINTF(buf) printk("%s", buf) #define BTC_PRINT(dbgtype, dbgflag, printstr, ...) \ do { \ -- cgit v1.2.3 From fbbcd14690d3c42b664740d58a22af50a77d5689 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:17:49 +0530 Subject: ath9k: Add channel context structure The channel context structure is defined to enable multi-channel concurrency support. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Makefile | 3 +- drivers/net/wireless/ath/ath9k/ath9k.h | 18 +++++ drivers/net/wireless/ath/ath9k/channel.c | 133 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/link.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 111 +++----------------------- drivers/net/wireless/ath/ath9k/recv.c | 4 +- 7 files changed, 169 insertions(+), 103 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/channel.c diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 8fcd586d1c39..6b4020a57984 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -5,7 +5,8 @@ ath9k-y += beacon.o \ recv.o \ xmit.o \ link.o \ - antenna.o + antenna.o \ + channel.o ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o ath9k-$(CONFIG_ATH9K_PCI) += pci.o diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 2ca8f7e06174..8c87eb7fb6de 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -325,6 +325,16 @@ struct ath_rx { u32 ampdu_ref; }; +struct ath_chanctx { + struct cfg80211_chan_def chandef; + struct list_head vifs; + bool offchannel; +}; + +void ath_chanctx_init(struct ath_softc *sc); +int ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, + struct cfg80211_chan_def *chandef); +int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); int ath_startrecv(struct ath_softc *sc); bool ath_stoprecv(struct ath_softc *sc); u32 ath_calcrxfilter(struct ath_softc *sc); @@ -370,12 +380,15 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, /********/ struct ath_vif { + struct list_head list; + struct ieee80211_vif *vif; struct ath_node mcast_node; int av_bslot; bool primary_sta_vif; __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ struct ath_buf *av_bcbuf; + struct ath_chanctx *chanctx; /* P2P Client */ struct ieee80211_noa_data noa; @@ -702,6 +715,8 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); #define PS_BEACON_SYNC BIT(4) #define PS_WAIT_FOR_ANI BIT(5) +#define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */ + struct ath_softc { struct ieee80211_hw *hw; struct device *dev; @@ -743,6 +758,9 @@ struct ath_softc { struct ath_tx tx; struct ath_beacon beacon; + struct ath_chanctx chanctx[ATH9K_NUM_CHANCTX]; + struct ath_chanctx *cur_chan; + #ifdef CONFIG_MAC80211_LEDS bool led_registered; char led_name[32]; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c new file mode 100644 index 000000000000..aee6cdb4975b --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +/* Set/change channels. If the channel is really being changed, it's done + * by reseting the chip. To accomplish this we must first cleanup any pending + * DMA, then restart stuff. + */ +static int ath_set_channel(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_hw *hw = sc->hw; + struct ath9k_channel *hchan; + struct cfg80211_chan_def *chandef = &sc->cur_chan->chandef; + struct ieee80211_channel *chan = chandef->chan; + int pos = chan->hw_value; + int old_pos = -1; + int r; + + if (test_bit(ATH_OP_INVALID, &common->op_flags)) + return -EIO; + + if (ah->curchan) + old_pos = ah->curchan - &ah->channels[0]; + + ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", + chan->center_freq, chandef->width); + + /* update survey stats for the old channel before switching */ + spin_lock_bh(&common->cc_lock); + ath_update_survey_stats(sc); + spin_unlock_bh(&common->cc_lock); + + ath9k_cmn_get_channel(hw, ah, chandef); + + /* If the operating channel changes, change the survey in-use flags + * along with it. + * Reset the survey data for the new channel, unless we're switching + * back to the operating channel from an off-channel operation. + */ + if (!sc->cur_chan->offchannel && sc->cur_survey != &sc->survey[pos]) { + if (sc->cur_survey) + sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; + + sc->cur_survey = &sc->survey[pos]; + + memset(sc->cur_survey, 0, sizeof(struct survey_info)); + sc->cur_survey->filled |= SURVEY_INFO_IN_USE; + } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { + memset(&sc->survey[pos], 0, sizeof(struct survey_info)); + } + + hchan = &sc->sc_ah->channels[pos]; + r = ath_reset_internal(sc, hchan); + if (r) + return r; + + /* The most recent snapshot of channel->noisefloor for the old + * channel is only available after the hardware reset. Copy it to + * the survey stats now. + */ + if (old_pos >= 0) + ath_update_survey_nf(sc, old_pos); + + /* Enable radar pulse detection if on a DFS channel. Spectral + * scanning and radar detection can not be used concurrently. + */ + if (hw->conf.radar_enabled) { + u32 rxfilter; + + /* set HW specific DFS configuration */ + ath9k_hw_set_radar_params(ah); + rxfilter = ath9k_hw_getrxfilter(ah); + rxfilter |= ATH9K_RX_FILTER_PHYRADAR | + ATH9K_RX_FILTER_PHYERR; + ath9k_hw_setrxfilter(ah, rxfilter); + ath_dbg(common, DFS, "DFS enabled at freq %d\n", + chan->center_freq); + } else { + /* perform spectral scan if requested. */ + if (test_bit(ATH_OP_SCANNING, &common->op_flags) && + sc->spectral_mode == SPECTRAL_CHANSCAN) + ath9k_spectral_scan_trigger(hw); + } + + return 0; +} + +void ath_chanctx_init(struct ath_softc *sc) +{ + struct ath_chanctx *ctx; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + int i; + + sband = &common->sbands[IEEE80211_BAND_2GHZ]; + if (!sband->n_channels) + sband = &common->sbands[IEEE80211_BAND_5GHZ]; + + chan = &sband->channels[0]; + for (i = 0; i < ATH9K_NUM_CHANCTX; i++) { + ctx = &sc->chanctx[i]; + cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20); + INIT_LIST_HEAD(&ctx->vifs); + } + sc->cur_chan = &sc->chanctx[0]; +} + +int ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, + struct cfg80211_chan_def *chandef) +{ + memcpy(&ctx->chandef, chandef, sizeof(ctx->chandef)); + if (ctx != sc->cur_chan) + return 0; + + return ath_set_channel(sc); +} diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 0246b990fe87..32d954275d47 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -599,6 +599,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ath9k_cmn_init_crypto(sc->sc_ah); ath9k_init_misc(sc); ath_fill_led_pin(sc); + ath_chanctx_init(sc); if (common->bus_ops->aspm_init) common->bus_ops->aspm_init(common); diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 72a715fe8f24..6f91974c7b08 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -416,7 +416,7 @@ void ath_start_ani(struct ath_softc *sc) if (common->disable_ani || !test_bit(ATH_OP_ANI_RUN, &common->op_flags) || - (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) + sc->cur_chan->offchannel) return; common->ani.longcal_timer = timestamp; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 62ac95d6bb9d..2e7cce7b1238 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -233,7 +233,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); - if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) { + if (!sc->cur_chan->offchannel && start) { if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) goto work; @@ -266,7 +266,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) return true; } -static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) +int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -279,7 +279,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) tasklet_disable(&sc->intr_tq); spin_lock_bh(&sc->sc_pcu_lock); - if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { + if (!sc->cur_chan->offchannel) { fastcc = false; caldata = &sc->caldata; } @@ -307,7 +307,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) } if (ath9k_hw_mci_is_enabled(sc->sc_ah) && - (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) + sc->cur_chan->offchannel) ath9k_mci_set_txpower(sc, true, false); if (!ath_complete_reset(sc, true)) @@ -320,98 +320,6 @@ out: return r; } - -/* - * Set/change channels. If the channel is really being changed, it's done - * by reseting the chip. To accomplish this we must first cleanup any pending - * DMA, then restart stuff. -*/ -static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chandef) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_hw *hw = sc->hw; - struct ath9k_channel *hchan; - struct ieee80211_channel *chan = chandef->chan; - bool offchannel; - int pos = chan->hw_value; - int old_pos = -1; - int r; - - if (test_bit(ATH_OP_INVALID, &common->op_flags)) - return -EIO; - - offchannel = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); - - if (ah->curchan) - old_pos = ah->curchan - &ah->channels[0]; - - ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", - chan->center_freq, chandef->width); - - /* update survey stats for the old channel before switching */ - spin_lock_bh(&common->cc_lock); - ath_update_survey_stats(sc); - spin_unlock_bh(&common->cc_lock); - - ath9k_cmn_get_channel(hw, ah, chandef); - - /* - * If the operating channel changes, change the survey in-use flags - * along with it. - * Reset the survey data for the new channel, unless we're switching - * back to the operating channel from an off-channel operation. - */ - if (!offchannel && sc->cur_survey != &sc->survey[pos]) { - if (sc->cur_survey) - sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; - - sc->cur_survey = &sc->survey[pos]; - - memset(sc->cur_survey, 0, sizeof(struct survey_info)); - sc->cur_survey->filled |= SURVEY_INFO_IN_USE; - } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { - memset(&sc->survey[pos], 0, sizeof(struct survey_info)); - } - - hchan = &sc->sc_ah->channels[pos]; - r = ath_reset_internal(sc, hchan); - if (r) - return r; - - /* - * The most recent snapshot of channel->noisefloor for the old - * channel is only available after the hardware reset. Copy it to - * the survey stats now. - */ - if (old_pos >= 0) - ath_update_survey_nf(sc, old_pos); - - /* - * Enable radar pulse detection if on a DFS channel. Spectral - * scanning and radar detection can not be used concurrently. - */ - if (hw->conf.radar_enabled) { - u32 rxfilter; - - /* set HW specific DFS configuration */ - ath9k_hw_set_radar_params(ah); - rxfilter = ath9k_hw_getrxfilter(ah); - rxfilter |= ATH9K_RX_FILTER_PHYRADAR | - ATH9K_RX_FILTER_PHYERR; - ath9k_hw_setrxfilter(ah, rxfilter); - ath_dbg(common, DFS, "DFS enabled at freq %d\n", - chan->center_freq); - } else { - /* perform spectral scan if requested. */ - if (test_bit(ATH_OP_SCANNING, &common->op_flags) && - sc->spectral_mode == SPECTRAL_CHANSCAN) - ath9k_spectral_scan_trigger(hw); - } - - return 0; -} - static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, struct ieee80211_vif *vif) { @@ -713,6 +621,7 @@ static int ath9k_start(struct ieee80211_hw *hw) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *curchan = hw->conf.chandef.chan; + struct ath_chanctx *ctx = sc->cur_chan; struct ath9k_channel *init_channel; int r; @@ -723,7 +632,8 @@ static int ath9k_start(struct ieee80211_hw *hw) ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); - init_channel = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef); + memcpy(&ctx->chandef, &hw->conf.chandef, sizeof(ctx->chandef)); + init_channel = ath9k_cmn_get_channel(hw, ah, &ctx->chandef); /* Reset SERDES registers */ ath9k_hw_configpcipowersave(ah, false); @@ -934,7 +844,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) } if (!ah->curchan) - ah->curchan = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef); + ah->curchan = ath9k_cmn_get_channel(hw, ah, + &sc->cur_chan->chandef); ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); ath9k_hw_phy_disable(ah); @@ -1345,6 +1256,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &hw->conf; + struct ath_chanctx *ctx = sc->cur_chan; bool reset_channel = false; ath9k_ps_wakeup(sc); @@ -1392,7 +1304,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) { - if (ath_set_channel(sc, &hw->conf.chandef) < 0) { + ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL); + if (ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef) < 0) { ath_err(common, "Unable to set channel\n"); mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 9105a92364f7..de5684a33dd7 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -259,7 +259,7 @@ static void ath_edma_start_recv(struct ath_softc *sc) ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP); ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP); ath_opmode_init(sc); - ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); + ath9k_hw_startpcureceive(sc->sc_ah, sc->cur_chan->offchannel); } static void ath_edma_stop_recv(struct ath_softc *sc) @@ -457,7 +457,7 @@ int ath_startrecv(struct ath_softc *sc) start_recv: ath_opmode_init(sc); - ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); + ath9k_hw_startpcureceive(ah, sc->cur_chan->offchannel); return 0; } -- cgit v1.2.3 From bc7e1be70c9f1c6de622aa14baa62003342034bb Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:17:50 +0530 Subject: ath9k: Move txpower limit to channel context Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 6 +----- drivers/net/wireless/ath/ath9k/channel.c | 1 + drivers/net/wireless/ath/ath9k/init.c | 5 ++--- drivers/net/wireless/ath/ath9k/main.c | 6 +++--- drivers/net/wireless/ath/ath9k/mci.c | 2 +- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8c87eb7fb6de..b6f6444d109e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -36,10 +36,6 @@ extern int ath9k_modparam_nohwcrypt; extern int led_blink; extern bool is_ath9k_unloaded; -struct ath_config { - u16 txpowlimit; -}; - /*************************/ /* Descriptor Management */ /*************************/ @@ -328,6 +324,7 @@ struct ath_rx { struct ath_chanctx { struct cfg80211_chan_def chandef; struct list_head vifs; + u16 txpower; bool offchannel; }; @@ -753,7 +750,6 @@ struct ath_softc { short nvifs; unsigned long ps_usecount; - struct ath_config config; struct ath_rx rx; struct ath_tx tx; struct ath_beacon beacon; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index aee6cdb4975b..1b40cf5aa955 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -118,6 +118,7 @@ void ath_chanctx_init(struct ath_softc *sc) ctx = &sc->chanctx[i]; cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20); INIT_LIST_HEAD(&ctx->vifs); + ctx->txpower = ATH_TXPOWER_MAX; } sc->cur_chan = &sc->chanctx[0]; } diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 32d954275d47..ffd42bfb74b4 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -169,9 +169,9 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, /* Set tx power */ if (ah->curchan) { - sc->config.txpowlimit = 2 * ah->curchan->chan->max_power; + sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power; ath9k_ps_wakeup(sc); - ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); + ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; /* synchronize DFS detector if regulatory domain changed */ if (sc->dfs_detector != NULL) @@ -335,7 +335,6 @@ static void ath9k_init_misc(struct ath_softc *sc) setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); common->last_rssi = ATH_RSSI_DUMMY_MARKER; - sc->config.txpowlimit = ATH_TXPOWER_MAX; memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); sc->beacon.slottime = ATH9K_SLOT_TIME_9; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2e7cce7b1238..5a9cee4a8935 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -227,7 +227,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) } ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); + sc->cur_chan->txpower, &sc->curtxpow); clear_bit(ATH_OP_HW_RESET, &common->op_flags); ath9k_hw_set_interrupts(ah); @@ -1315,9 +1315,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_POWER) { ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level); - sc->config.txpowlimit = 2 * conf->power_level; + sc->cur_chan->txpower = 2 * conf->power_level; ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); + sc->cur_chan->txpower, &sc->curtxpow); } mutex_unlock(&sc->mutex); diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index a0dbcc412384..313ed995585a 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -720,7 +720,7 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, mci_hw->concur_tx = concur_tx; if (old_concur_tx != mci_hw->concur_tx) - ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); + ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); } static void ath9k_mci_stomp_audio(struct ath_softc *sc) -- cgit v1.2.3 From 0453531e2eae61c5c0a2af7b67cdafd19c0dce68 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:17:51 +0530 Subject: ath9k: Move acq to channel context Add support to maintain per-channel ACs list. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++- drivers/net/wireless/ath/ath9k/channel.c | 4 ++- drivers/net/wireless/ath/ath9k/main.c | 25 ++++++++------ drivers/net/wireless/ath/ath9k/xmit.c | 58 +++++++++++++++++++++++--------- 4 files changed, 63 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b6f6444d109e..198cca38c24b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -163,7 +163,6 @@ struct ath_txq { u32 axq_ampdu_depth; bool stopped; bool axq_tx_inprogress; - struct list_head axq_acq; struct list_head txq_fifo[ATH_TXFIFO_DEPTH]; u8 txq_headidx; u8 txq_tailidx; @@ -324,6 +323,8 @@ struct ath_rx { struct ath_chanctx { struct cfg80211_chan_def chandef; struct list_head vifs; + struct list_head acq[IEEE80211_NUM_ACS]; + u16 txpower; bool offchannel; }; @@ -348,6 +349,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq); void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); +void ath_txq_schedule_all(struct ath_softc *sc); int ath_tx_init(struct ath_softc *sc, int nbufs); int ath_txq_update(struct ath_softc *sc, int qnum, struct ath9k_tx_queue_info *q); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 1b40cf5aa955..c8d91dfcb3b9 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -107,7 +107,7 @@ void ath_chanctx_init(struct ath_softc *sc) struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; - int i; + int i, j; sband = &common->sbands[IEEE80211_BAND_2GHZ]; if (!sband->n_channels) @@ -119,6 +119,8 @@ void ath_chanctx_init(struct ath_softc *sc) cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20); INIT_LIST_HEAD(&ctx->vifs); ctx->txpower = ATH_TXPOWER_MAX; + for (j = 0; j < ARRAY_SIZE(ctx->acq); j++) + INIT_LIST_HEAD(&ctx->acq[j]); } sc->cur_chan = &sc->chanctx[0]; } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5a9cee4a8935..5f7e0bf4c986 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -63,9 +63,16 @@ static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq) spin_lock_bh(&txq->axq_lock); - if (txq->axq_depth || !list_empty(&txq->axq_acq)) + if (txq->axq_depth) pending = true; + if (txq->mac80211_qnum >= 0) { + struct list_head *list; + + list = &sc->cur_chan->acq[txq->mac80211_qnum]; + if (!list_empty(list)) + pending = true; + } spin_unlock_bh(&txq->axq_lock); return pending; } @@ -219,7 +226,6 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); unsigned long flags; - int i; if (ath_startrecv(sc) != 0) { ath_err(common, "Unable to restart recv logic\n"); @@ -247,15 +253,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) } work: ath_restart_work(sc); - - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (!ATH_TXQ_SETUP(sc, i)) - continue; - - spin_lock_bh(&sc->tx.txq[i].axq_lock); - ath_txq_schedule(sc, &sc->tx.txq[i]); - spin_unlock_bh(&sc->tx.txq[i].axq_lock); - } + ath_txq_schedule_all(sc); } sc->gtt_cnt = 0; @@ -1035,6 +1033,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, avp->vif = vif; + /* XXX - will be removed once chanctx ops are added */ + avp->chanctx = sc->cur_chan; + list_add_tail(&avp->list, &sc->cur_chan->vifs); + an->sc = sc; an->sta = NULL; an->vif = vif; @@ -1120,6 +1122,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, } spin_unlock_bh(&sc->sc_pcu_lock); + list_del(&avp->list); sc->nvifs--; sc->tx99_vif = NULL; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 66acb2cbd9df..b2e66d21af1c 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -103,9 +103,16 @@ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) ieee80211_tx_status(sc->hw, skb); } -static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) +static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid) { struct ath_atx_ac *ac = tid->ac; + struct list_head *list; + struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv; + struct ath_chanctx *ctx = avp->chanctx; + + if (!ctx) + return; if (tid->sched) return; @@ -117,7 +124,9 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) return; ac->sched = true; - list_add_tail(&ac->list, &txq->axq_acq); + + list = &ctx->acq[TID_TO_WME_AC(tid->tidno)]; + list_add_tail(&ac->list, list); } static struct ath_frame_info *get_frame_info(struct sk_buff *skb) @@ -626,7 +635,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, skb_queue_splice_tail(&bf_pending, &tid->retry_q); if (!an->sleeping) { - ath_tx_queue_tid(txq, tid); + ath_tx_queue_tid(sc, txq, tid); if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) tid->ac->clear_ps_filter = true; @@ -1483,7 +1492,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) ac->clear_ps_filter = true; if (ath_tid_has_buffered(tid)) { - ath_tx_queue_tid(txq, tid); + ath_tx_queue_tid(sc, txq, tid); ath_txq_schedule(sc, txq); } @@ -1507,7 +1516,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; if (ath_tid_has_buffered(tid)) { - ath_tx_queue_tid(txq, tid); + ath_tx_queue_tid(sc, txq, tid); ath_txq_schedule(sc, txq); } @@ -1642,7 +1651,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->axq_link = NULL; __skb_queue_head_init(&txq->complete_q); INIT_LIST_HEAD(&txq->axq_q); - INIT_LIST_HEAD(&txq->axq_acq); spin_lock_init(&txq->axq_lock); txq->axq_depth = 0; txq->axq_ampdu_depth = 0; @@ -1804,7 +1812,7 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) sc->tx.txqsetup &= ~(1<axq_qnum); } -/* For each axq_acq entry, for each tid, try to schedule packets +/* For each acq entry, for each tid, try to schedule packets * for transmit until ampdu_depth has reached min Q depth. */ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) @@ -1812,19 +1820,25 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_atx_ac *ac, *last_ac; struct ath_atx_tid *tid, *last_tid; + struct list_head *ac_list; bool sent = false; + if (txq->mac80211_qnum < 0) + return; + + ac_list = &sc->cur_chan->acq[txq->mac80211_qnum]; + if (test_bit(ATH_OP_HW_RESET, &common->op_flags) || - list_empty(&txq->axq_acq)) + list_empty(ac_list)) return; rcu_read_lock(); - last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list); - while (!list_empty(&txq->axq_acq)) { + last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list); + while (!list_empty(ac_list)) { bool stop = false; - ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); + ac = list_first_entry(ac_list, struct ath_atx_ac, list); last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); list_del(&ac->list); ac->sched = false; @@ -1844,7 +1858,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) * are pending for the tid */ if (ath_tid_has_buffered(tid)) - ath_tx_queue_tid(txq, tid); + ath_tx_queue_tid(sc, txq, tid); if (stop || tid == last_tid) break; @@ -1852,7 +1866,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) if (!list_empty(&ac->tid_q) && !ac->sched) { ac->sched = true; - list_add_tail(&ac->list, &txq->axq_acq); + list_add_tail(&ac->list, ac_list); } if (stop) @@ -1863,7 +1877,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) break; sent = false; - last_ac = list_entry(txq->axq_acq.prev, + last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list); } } @@ -1871,6 +1885,20 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) rcu_read_unlock(); } +void ath_txq_schedule_all(struct ath_softc *sc) +{ + struct ath_txq *txq; + int i; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + txq = sc->tx.txq_map[i]; + + spin_lock_bh(&txq->axq_lock); + ath_txq_schedule(sc, txq); + spin_unlock_bh(&txq->axq_lock); + } +} + /***********/ /* TX, DMA */ /***********/ @@ -2198,7 +2226,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, TX_STAT_INC(txq->axq_qnum, a_queued_sw); __skb_queue_tail(&tid->buf_q, skb); if (!txctl->an->sleeping) - ath_tx_queue_tid(txq, tid); + ath_tx_queue_tid(sc, txq, tid); ath_txq_schedule(sc, txq); goto out; -- cgit v1.2.3 From bff117669841c04d08bd1d23617818e0030b3299 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:17:52 +0530 Subject: ath9k: Add channel context worker thread The channel context worker is used to switch to next requested channel context. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 13 ++++++- drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/channel.c | 64 +++++++++++++++++++++++++++++--- drivers/net/wireless/ath/ath9k/init.c | 2 + drivers/net/wireless/ath/ath9k/link.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 29 +++++++++------ drivers/net/wireless/ath/ath9k/wow.c | 1 + drivers/net/wireless/ath/ath9k/xmit.c | 7 ++++ 8 files changed, 99 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 198cca38c24b..8f59cea33fd6 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -327,11 +327,14 @@ struct ath_chanctx { u16 txpower; bool offchannel; + bool stopped; }; void ath_chanctx_init(struct ath_softc *sc); -int ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, - struct cfg80211_chan_def *chandef); +void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, + struct cfg80211_chan_def *chandef); +void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, + struct cfg80211_chan_def *chandef); int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); int ath_startrecv(struct ath_softc *sc); bool ath_stoprecv(struct ath_softc *sc); @@ -470,6 +473,7 @@ void ath9k_csa_update(struct ath_softc *sc); #define ATH_PAPRD_TIMEOUT 100 /* msecs */ #define ATH_PLL_WORK_INTERVAL 100 +void ath_chanctx_work(struct work_struct *work); void ath_tx_complete_poll_work(struct work_struct *work); void ath_reset_work(struct work_struct *work); bool ath_hw_check(struct ath_softc *sc); @@ -485,6 +489,7 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); void ath_ps_full_sleep(unsigned long data); void ath9k_p2p_ps_timer(void *priv); void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif); +void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop); /**********/ /* BTCOEX */ @@ -734,6 +739,7 @@ struct ath_softc { struct mutex mutex; struct work_struct paprd_work; struct work_struct hw_reset_work; + struct work_struct chanctx_work; struct completion paprd_complete; wait_queue_head_t tx_wait; @@ -756,8 +762,11 @@ struct ath_softc { struct ath_tx tx; struct ath_beacon beacon; + struct cfg80211_chan_def cur_chandef; struct ath_chanctx chanctx[ATH9K_NUM_CHANCTX]; struct ath_chanctx *cur_chan; + struct ath_chanctx *next_chan; + spinlock_t chan_lock; #ifdef CONFIG_MAC80211_LEDS bool led_registered; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index e387f0b2954a..eae8f686f125 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -80,7 +80,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, u8 chainmask = ah->txchainmask; u8 rate = 0; - sband = &common->sbands[common->hw->conf.chandef.chan->band]; + sband = &common->sbands[sc->cur_chandef.chan->band]; rate = sband->bitrates[rateidx].hw_value; if (vif->bss_conf.use_short_preamble) rate |= sband->bitrates[rateidx].hw_value_short; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index c8d91dfcb3b9..86404d38901e 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -101,6 +101,39 @@ static int ath_set_channel(struct ath_softc *sc) return 0; } +void ath_chanctx_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + chanctx_work); + + mutex_lock(&sc->mutex); + spin_lock_bh(&sc->chan_lock); + if (!sc->next_chan) { + spin_unlock_bh(&sc->chan_lock); + mutex_unlock(&sc->mutex); + return; + } + + if (sc->cur_chan != sc->next_chan) { + sc->cur_chan->stopped = true; + spin_unlock_bh(&sc->chan_lock); + + __ath9k_flush(sc->hw, ~0, true); + + spin_lock_bh(&sc->chan_lock); + } + sc->cur_chan = sc->next_chan; + sc->cur_chan->stopped = false; + sc->next_chan = NULL; + spin_unlock_bh(&sc->chan_lock); + + if (sc->sc_ah->chip_fullsleep || + memcmp(&sc->cur_chandef, &sc->cur_chan->chandef, + sizeof(sc->cur_chandef))) + ath_set_channel(sc); + mutex_unlock(&sc->mutex); +} + void ath_chanctx_init(struct ath_softc *sc) { struct ath_chanctx *ctx; @@ -125,12 +158,31 @@ void ath_chanctx_init(struct ath_softc *sc) sc->cur_chan = &sc->chanctx[0]; } -int ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, - struct cfg80211_chan_def *chandef) +void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, + struct cfg80211_chan_def *chandef) { - memcpy(&ctx->chandef, chandef, sizeof(ctx->chandef)); - if (ctx != sc->cur_chan) - return 0; - return ath_set_channel(sc); + spin_lock_bh(&sc->chan_lock); + sc->next_chan = ctx; + if (chandef) + ctx->chandef = *chandef; + spin_unlock_bh(&sc->chan_lock); + ieee80211_queue_work(sc->hw, &sc->chanctx_work); +} + +void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, + struct cfg80211_chan_def *chandef) +{ + bool cur_chan; + + spin_lock_bh(&sc->chan_lock); + if (chandef) + memcpy(&ctx->chandef, chandef, sizeof(*chandef)); + cur_chan = sc->cur_chan == ctx; + spin_unlock_bh(&sc->chan_lock); + + if (!cur_chan) + return; + + ath_set_channel(sc); } diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index ffd42bfb74b4..8bd3e422b82b 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -555,6 +555,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, spin_lock_init(&common->cc_lock); spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_pm_lock); + spin_lock_init(&sc->chan_lock); mutex_init(&sc->mutex); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, @@ -563,6 +564,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc); INIT_WORK(&sc->hw_reset_work, ath_reset_work); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); + INIT_WORK(&sc->chanctx_work, ath_chanctx_work); INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); /* diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 6f91974c7b08..d9c01d563cc2 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -178,7 +178,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE]; memset(tx_info, 0, sizeof(*tx_info)); - tx_info->band = hw->conf.chandef.chan->band; + tx_info->band = sc->cur_chandef.chan->band; tx_info->flags |= IEEE80211_TX_CTL_NO_ACK; tx_info->control.rates[0].idx = 0; tx_info->control.rates[0].count = 1; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5f7e0bf4c986..bb73a23f19f8 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -290,6 +290,12 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) if (!ath_prepare_reset(sc)) fastcc = false; + if (hchan) { + spin_lock_bh(&sc->chan_lock); + sc->cur_chandef = sc->cur_chan->chandef; + spin_unlock_bh(&sc->chan_lock); + } + ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", hchan->channel, IS_CHAN_HT40(hchan), fastcc); @@ -630,8 +636,8 @@ static int ath9k_start(struct ieee80211_hw *hw) ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); - memcpy(&ctx->chandef, &hw->conf.chandef, sizeof(ctx->chandef)); init_channel = ath9k_cmn_get_channel(hw, ah, &ctx->chandef); + sc->cur_chandef = hw->conf.chandef; /* Reset SERDES registers */ ath9k_hw_configpcipowersave(ah, false); @@ -794,6 +800,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) struct ath_common *common = ath9k_hw_common(ah); bool prev_idle; + cancel_work_sync(&sc->chanctx_work); mutex_lock(&sc->mutex); ath_cancel_work(sc); @@ -1308,12 +1315,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) { ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL); - if (ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef) < 0) { - ath_err(common, "Unable to set channel\n"); - mutex_unlock(&sc->mutex); - ath9k_ps_restore(sc); - return -EINVAL; - } + ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef); } if (changed & IEEE80211_CONF_CHANGE_POWER) { @@ -1946,6 +1948,15 @@ static bool ath9k_has_tx_pending(struct ath_softc *sc) static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) +{ + struct ath_softc *sc = hw->priv; + + mutex_lock(&sc->mutex); + __ath9k_flush(hw, queues, drop); + mutex_unlock(&sc->mutex); +} + +void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; @@ -1953,18 +1964,15 @@ static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int timeout = HZ / 5; /* 200 ms */ bool drain_txq; - mutex_lock(&sc->mutex); cancel_delayed_work_sync(&sc->tx_complete_work); if (ah->ah_flags & AH_UNPLUGGED) { ath_dbg(common, ANY, "Device has been unplugged!\n"); - mutex_unlock(&sc->mutex); return; } if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); - mutex_unlock(&sc->mutex); return; } @@ -1986,7 +1994,6 @@ static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); - mutex_unlock(&sc->mutex); } static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 2879887f5691..a4f4f0da81f6 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -193,6 +193,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, u32 wow_triggers_enabled = 0; int ret = 0; + cancel_work_sync(&sc->chanctx_work); mutex_lock(&sc->mutex); ath_cancel_work(sc); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index b2e66d21af1c..5aaed39459d2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1826,18 +1826,24 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) if (txq->mac80211_qnum < 0) return; + spin_lock_bh(&sc->chan_lock); ac_list = &sc->cur_chan->acq[txq->mac80211_qnum]; + spin_unlock_bh(&sc->chan_lock); if (test_bit(ATH_OP_HW_RESET, &common->op_flags) || list_empty(ac_list)) return; + spin_lock_bh(&sc->chan_lock); rcu_read_lock(); last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list); while (!list_empty(ac_list)) { bool stop = false; + if (sc->cur_chan->stopped) + break; + ac = list_first_entry(ac_list, struct ath_atx_ac, list); last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); list_del(&ac->list); @@ -1883,6 +1889,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) } rcu_read_unlock(); + spin_unlock_bh(&sc->chan_lock); } void ath_txq_schedule_all(struct ath_softc *sc) -- cgit v1.2.3 From befcf7e70e899db62307408259c51e0435bd9b3f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:17:53 +0530 Subject: ath9k: channel context based transmission Force queueing of all frames that belong to a virtual interface on a different channel context, to ensure that they are sent on the correct channel. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 ++- drivers/net/wireless/ath/ath9k/xmit.c | 24 +++++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8f59cea33fd6..ddd2e81ccd58 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -275,8 +275,9 @@ struct ath_node { struct ath_tx_control { struct ath_txq *txq; struct ath_node *an; - u8 paprd; struct ieee80211_sta *sta; + u8 paprd; + bool force_channel; }; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 5aaed39459d2..7972e1e24dd2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2185,13 +2185,18 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = txctl->sta; struct ieee80211_vif *vif = info->control.vif; + struct ath_vif *avp = NULL; struct ath_softc *sc = hw->priv; struct ath_txq *txq = txctl->txq; struct ath_atx_tid *tid = NULL; struct ath_buf *bf; + bool queue; int q; int ret; + if (vif) + avp = (void *)vif->drv_priv; + ret = ath_tx_prepare(hw, skb, txctl); if (ret) return ret; @@ -2212,15 +2217,28 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, txq->stopped = true; } - if (txctl->an && ieee80211_is_data_present(hdr->frame_control)) + queue = ieee80211_is_data_present(hdr->frame_control); + + /* Force queueing of all frames that belong to a virtual interface on + * a different channel context, to ensure that they are sent on the + * correct channel. + */ + if (((avp && avp->chanctx != sc->cur_chan) || + sc->cur_chan->stopped) && !txctl->force_channel) { + if (!txctl->an) + txctl->an = &avp->mcast_node; + info->flags &= ~IEEE80211_TX_CTL_PS_RESPONSE; + queue = true; + } + + if (txctl->an && queue) tid = ath_get_skb_tid(sc, txctl->an, skb); if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) { ath_txq_unlock(sc, txq); txq = sc->tx.uapsdq; ath_txq_lock(sc, txq); - } else if (txctl->an && - ieee80211_is_data_present(hdr->frame_control)) { + } else if (txctl->an && queue) { WARN_ON(tid->ac->txq != txctl->txq); if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) -- cgit v1.2.3 From c083ce9980109065297aa2171d18980a0ac92bb9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:17:54 +0530 Subject: ath9k: send powersave frame on channel switch While leaving from or entering to active channel context, send out nullfunc frame to inform to the AP about the presence of station. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 + drivers/net/wireless/ath/ath9k/channel.c | 97 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/main.c | 6 ++ 3 files changed, 106 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index ddd2e81ccd58..d5a586bbab7c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -329,6 +329,7 @@ struct ath_chanctx { u16 txpower; bool offchannel; bool stopped; + bool active; }; void ath_chanctx_init(struct ath_softc *sc); @@ -336,6 +337,8 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); +void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); + int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); int ath_startrecv(struct ath_softc *sc); bool ath_stoprecv(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 86404d38901e..26fc98b3495b 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -101,10 +101,99 @@ static int ath_set_channel(struct ath_softc *sc) return 0; } +static bool +ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp, + bool powersave) +{ + struct ieee80211_vif *vif = avp->vif; + struct ieee80211_sta *sta = NULL; + struct ieee80211_hdr_3addr *nullfunc; + struct ath_tx_control txctl; + struct sk_buff *skb; + int band = sc->cur_chan->chandef.chan->band; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + if (!vif->bss_conf.assoc) + return false; + + skb = ieee80211_nullfunc_get(sc->hw, vif); + if (!skb) + return false; + + nullfunc = (struct ieee80211_hdr_3addr *) skb->data; + if (powersave) + nullfunc->frame_control |= + cpu_to_le16(IEEE80211_FCTL_PM); + + skb_set_queue_mapping(skb, IEEE80211_AC_VO); + if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) { + dev_kfree_skb_any(skb); + return false; + } + break; + default: + return false; + } + + memset(&txctl, 0, sizeof(txctl)); + txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; + txctl.sta = sta; + txctl.force_channel = true; + if (ath_tx_start(sc->hw, skb, &txctl)) { + ieee80211_free_txskb(sc->hw, skb); + return false; + } + + return true; +} + +void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) +{ + struct ath_vif *avp; + bool active = false; + + if (!ctx) + return; + + list_for_each_entry(avp, &ctx->vifs, list) { + struct ieee80211_vif *vif = avp->vif; + + switch (vif->type) { + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_STATION: + if (vif->bss_conf.assoc) + active = true; + break; + default: + active = true; + break; + } + } + ctx->active = active; +} + +static bool +ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave) +{ + struct ath_vif *avp; + bool sent = false; + + rcu_read_lock(); + list_for_each_entry(avp, &sc->cur_chan->vifs, list) { + if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave)) + sent = true; + } + rcu_read_unlock(); + + return sent; +} + void ath_chanctx_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, chanctx_work); + bool send_ps = false; mutex_lock(&sc->mutex); spin_lock_bh(&sc->chan_lock); @@ -120,6 +209,10 @@ void ath_chanctx_work(struct work_struct *work) __ath9k_flush(sc->hw, ~0, true); + if (ath_chanctx_send_ps_frame(sc, true)) + __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false); + + send_ps = true; spin_lock_bh(&sc->chan_lock); } sc->cur_chan = sc->next_chan; @@ -131,6 +224,10 @@ void ath_chanctx_work(struct work_struct *work) memcmp(&sc->cur_chandef, &sc->cur_chan->chandef, sizeof(sc->cur_chandef))) ath_set_channel(sc); + + if (send_ps) + ath_chanctx_send_ps_frame(sc, false); + mutex_unlock(&sc->mutex); } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index bb73a23f19f8..d8a4510f963a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1043,6 +1043,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, /* XXX - will be removed once chanctx ops are added */ avp->chanctx = sc->cur_chan; list_add_tail(&avp->list, &sc->cur_chan->vifs); + ath_chanctx_check_active(sc, avp->chanctx); an->sc = sc; an->sta = NULL; @@ -1061,6 +1062,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp = (void *)vif->drv_priv; mutex_lock(&sc->mutex); @@ -1083,6 +1085,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); + ath_chanctx_check_active(sc, avp->chanctx); mutex_unlock(&sc->mutex); return 0; @@ -1141,6 +1144,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath9k_ps_restore(sc); ath_tx_node_cleanup(sc, &avp->mcast_node); + ath_chanctx_check_active(sc, avp->chanctx); mutex_unlock(&sc->mutex); } @@ -1733,6 +1737,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (ath9k_hw_mci_is_enabled(sc->sc_ah)) ath9k_mci_update_wlan_channels(sc, true); } + + ath_chanctx_check_active(sc, avp->chanctx); } if (changed & BSS_CHANGED_IBSS) { -- cgit v1.2.3 From 78b21949711ee3c877f1aab5b51abe1981e1161d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:17:55 +0530 Subject: ath9k: Implement hw_scan support Implement hw_scan support for enabling multi-channel cuncurrency. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 24 ++++ drivers/net/wireless/ath/ath9k/channel.c | 31 +++++ drivers/net/wireless/ath/ath9k/init.c | 9 +- drivers/net/wireless/ath/ath9k/main.c | 187 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/pci.c | 1 + drivers/net/wireless/ath/ath9k/recv.c | 5 + 6 files changed, 255 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index d5a586bbab7c..d6b0c4e55c95 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -35,6 +35,7 @@ extern struct ieee80211_ops ath9k_ops; extern int ath9k_modparam_nohwcrypt; extern int led_blink; extern bool is_ath9k_unloaded; +extern int ath9k_use_chanctx; /*************************/ /* Descriptor Management */ @@ -332,12 +333,34 @@ struct ath_chanctx { bool active; }; +enum ath_offchannel_state { + ATH_OFFCHANNEL_IDLE, + ATH_OFFCHANNEL_PROBE_SEND, + ATH_OFFCHANNEL_PROBE_WAIT, + ATH_OFFCHANNEL_SUSPEND, +}; + +struct ath_offchannel { + struct ath_chanctx chan; + struct timer_list timer; + struct cfg80211_scan_request *scan_req; + struct ieee80211_vif *scan_vif; + int scan_idx; + enum ath_offchannel_state state; +}; + +void ath9k_fill_chanctx_ops(void); void ath_chanctx_init(struct ath_softc *sc); void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); +void ath_offchannel_timer(unsigned long data); +void ath_offchannel_channel_change(struct ath_softc *sc); +void ath_chanctx_offchan_switch(struct ath_softc *sc, + struct ieee80211_channel *chan); +struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc); int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); int ath_startrecv(struct ath_softc *sc); @@ -771,6 +794,7 @@ struct ath_softc { struct ath_chanctx *cur_chan; struct ath_chanctx *next_chan; spinlock_t chan_lock; + struct ath_offchannel offchannel; #ifdef CONFIG_MAC80211_LEDS bool led_registered; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 26fc98b3495b..c679a26045ac 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -228,6 +228,7 @@ void ath_chanctx_work(struct work_struct *work) if (send_ps) ath_chanctx_send_ps_frame(sc, false); + ath_offchannel_channel_change(sc); mutex_unlock(&sc->mutex); } @@ -253,6 +254,14 @@ void ath_chanctx_init(struct ath_softc *sc) INIT_LIST_HEAD(&ctx->acq[j]); } sc->cur_chan = &sc->chanctx[0]; + ctx = &sc->offchannel.chan; + cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20); + INIT_LIST_HEAD(&ctx->vifs); + ctx->txpower = ATH_TXPOWER_MAX; + for (j = 0; j < ARRAY_SIZE(ctx->acq); j++) + INIT_LIST_HEAD(&ctx->acq[j]); + sc->offchannel.chan.offchannel = true; + } void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, @@ -283,3 +292,25 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, ath_set_channel(sc); } + +struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc) +{ + u8 i; + + for (i = 0; i < ARRAY_SIZE(sc->chanctx); i++) { + if (!list_empty(&sc->chanctx[i].vifs)) + return &sc->chanctx[i]; + } + + return &sc->chanctx[0]; +} + +void ath_chanctx_offchan_switch(struct ath_softc *sc, + struct ieee80211_channel *chan) +{ + struct cfg80211_chan_def chandef; + + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); + + ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef); +} diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 8bd3e422b82b..9f5e1e4931af 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -61,7 +61,7 @@ static int ath9k_ps_enable; module_param_named(ps_enable, ath9k_ps_enable, int, 0444); MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); -static int ath9k_use_chanctx; +int ath9k_use_chanctx; module_param_named(use_chanctx, ath9k_use_chanctx, int, 0444); MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency"); @@ -566,6 +566,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); INIT_WORK(&sc->chanctx_work, ath_chanctx_work); INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); + setup_timer(&sc->offchannel.timer, ath_offchannel_timer, + (unsigned long)sc); /* * Cache line size is used to size and align various @@ -745,8 +747,11 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) if (!ath9k_use_chanctx) { hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS); - } else + } else { hw->wiphy->n_iface_combinations = 1; + hw->wiphy->max_scan_ssids = 255; + hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + } } hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d8a4510f963a..5da62ef1fc26 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2159,6 +2159,193 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) clear_bit(ATH_OP_SCANNING, &common->op_flags); } +static void +ath_scan_next_channel(struct ath_softc *sc) +{ + struct cfg80211_scan_request *req = sc->offchannel.scan_req; + struct ieee80211_channel *chan; + + if (sc->offchannel.scan_idx >= req->n_channels) { + sc->offchannel.state = ATH_OFFCHANNEL_IDLE; + ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc), NULL); + return; + } + + chan = req->channels[sc->offchannel.scan_idx++]; + sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND; + ath_chanctx_offchan_switch(sc, chan); +} + +static void ath_scan_complete(struct ath_softc *sc, bool abort) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc), NULL); + sc->offchannel.scan_req = NULL; + sc->offchannel.scan_vif = NULL; + sc->offchannel.state = ATH_OFFCHANNEL_IDLE; + ieee80211_scan_completed(sc->hw, abort); + clear_bit(ATH_OP_SCANNING, &common->op_flags); + ath9k_ps_restore(sc); + + if (!sc->ps_idle) + return; + + ath_cancel_work(sc); +} + +static void ath_scan_send_probe(struct ath_softc *sc, + struct cfg80211_ssid *ssid) +{ + struct cfg80211_scan_request *req = sc->offchannel.scan_req; + struct ieee80211_vif *vif = sc->offchannel.scan_vif; + struct ath_tx_control txctl = {}; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + int band = sc->offchannel.chan.chandef.chan->band; + + skb = ieee80211_probereq_get(sc->hw, vif, + ssid->ssid, ssid->ssid_len, req->ie_len); + if (!skb) + return; + + info = IEEE80211_SKB_CB(skb); + if (req->no_cck) + info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE; + + if (req->ie_len) + memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len); + + skb_set_queue_mapping(skb, IEEE80211_AC_VO); + + if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL)) + goto error; + + txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; + txctl.force_channel = true; + if (ath_tx_start(sc->hw, skb, &txctl)) + goto error; + + return; + +error: + ieee80211_free_txskb(sc->hw, skb); +} + +static void ath_scan_channel_start(struct ath_softc *sc) +{ + struct cfg80211_scan_request *req = sc->offchannel.scan_req; + int i, dwell; + + if ((sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) || + !req->n_ssids) { + dwell = HZ / 9; /* ~110 ms */ + } else { + dwell = HZ / 16; /* ~60 ms */ + + for (i = 0; i < req->n_ssids; i++) + ath_scan_send_probe(sc, &req->ssids[i]); + } + + sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT; + mod_timer(&sc->offchannel.timer, jiffies + dwell); +} + +void ath_offchannel_channel_change(struct ath_softc *sc) +{ + if (!sc->offchannel.scan_req) + return; + + switch (sc->offchannel.state) { + case ATH_OFFCHANNEL_PROBE_SEND: + if (sc->cur_chan->chandef.chan != + sc->offchannel.chan.chandef.chan) + return; + + ath_scan_channel_start(sc); + break; + case ATH_OFFCHANNEL_IDLE: + ath_scan_complete(sc, false); + break; + default: + break; + } +} + +void ath_offchannel_timer(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *)data; + struct ath_chanctx *ctx = ath_chanctx_get_oper_chan(sc); + + if (!sc->offchannel.scan_req) + return; + + switch (sc->offchannel.state) { + case ATH_OFFCHANNEL_PROBE_WAIT: + if (ctx->active) { + sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND; + ath_chanctx_switch(sc, ctx, NULL); + mod_timer(&sc->offchannel.timer, jiffies + HZ / 10); + break; + } + /* fall through */ + case ATH_OFFCHANNEL_SUSPEND: + ath_scan_next_channel(sc); + break; + default: + break; + } +} + +static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_scan_request *req) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + int ret = 0; + + mutex_lock(&sc->mutex); + + if (WARN_ON(sc->offchannel.scan_req)) { + ret = -EBUSY; + goto out; + } + + ath9k_ps_wakeup(sc); + set_bit(ATH_OP_SCANNING, &common->op_flags); + sc->offchannel.scan_vif = vif; + sc->offchannel.scan_req = req; + sc->offchannel.scan_idx = 0; + sc->offchannel.chan.txpower = vif->bss_conf.txpower; + + ath_scan_next_channel(sc); + +out: + mutex_unlock(&sc->mutex); + + return ret; +} + +static void ath9k_cancel_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath_softc *sc = hw->priv; + + mutex_lock(&sc->mutex); + del_timer_sync(&sc->offchannel.timer); + ath_scan_complete(sc, true); + mutex_unlock(&sc->mutex); +} + +void ath9k_fill_chanctx_ops(void) +{ + if (!ath9k_use_chanctx) + return; + + ath9k_ops.hw_scan = ath9k_hw_scan; + ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan; +} + struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 4dec09e565ed..7a2b2c5caced 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -843,6 +843,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENODEV; } + ath9k_fill_chanctx_ops(); hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); if (!hw) { dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index de5684a33dd7..fec9e0b42f5d 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -374,6 +374,7 @@ void ath_rx_cleanup(struct ath_softc *sc) u32 ath_calcrxfilter(struct ath_softc *sc) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); u32 rfilt; if (config_enabled(CONFIG_ATH9K_TX99)) @@ -424,6 +425,10 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah)) rfilt |= ATH9K_RX_FILTER_4ADDRESS; + if (ath9k_use_chanctx && + test_bit(ATH_OP_SCANNING, &common->op_flags)) + rfilt |= ATH9K_RX_FILTER_BEACON; + return rfilt; } -- cgit v1.2.3 From 405393cfde07781c21cdee28b145919d6dfe382e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:17:56 +0530 Subject: ath9k: Implement remain-on-channal support Add remain on channel support in order to enable multi-channel concurrency. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 6 ++ drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/main.c | 126 +++++++++++++++++++++++++++++---- drivers/net/wireless/ath/ath9k/xmit.c | 6 +- 4 files changed, 124 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index d6b0c4e55c95..a8ae3e9b49fa 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -338,6 +338,9 @@ enum ath_offchannel_state { ATH_OFFCHANNEL_PROBE_SEND, ATH_OFFCHANNEL_PROBE_WAIT, ATH_OFFCHANNEL_SUSPEND, + ATH_OFFCHANNEL_ROC_START, + ATH_OFFCHANNEL_ROC_WAIT, + ATH_OFFCHANNEL_ROC_DONE, }; struct ath_offchannel { @@ -347,6 +350,9 @@ struct ath_offchannel { struct ieee80211_vif *scan_vif; int scan_idx; enum ath_offchannel_state state; + struct ieee80211_channel *roc_chan; + struct ieee80211_vif *roc_vif; + int roc_duration; }; void ath9k_fill_chanctx_ops(void); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 9f5e1e4931af..001b7d02345c 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -751,6 +751,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->n_iface_combinations = 1; hw->wiphy->max_scan_ssids = 255; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + hw->wiphy->max_remain_on_channel_duration = 10000; } } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5da62ef1fc26..9e10434dbfa5 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2176,22 +2176,48 @@ ath_scan_next_channel(struct ath_softc *sc) ath_chanctx_offchan_switch(sc, chan); } +static void ath_offchannel_next(struct ath_softc *sc) +{ + struct ieee80211_vif *vif; + + if (sc->offchannel.scan_req) { + vif = sc->offchannel.scan_vif; + sc->offchannel.chan.txpower = vif->bss_conf.txpower; + ath_scan_next_channel(sc); + } else if (sc->offchannel.roc_vif) { + vif = sc->offchannel.roc_vif; + sc->offchannel.chan.txpower = vif->bss_conf.txpower; + sc->offchannel.state = ATH_OFFCHANNEL_ROC_START; + ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan); + } else { + ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc), NULL); + sc->offchannel.state = ATH_OFFCHANNEL_IDLE; + if (sc->ps_idle) + ath_cancel_work(sc); + } +} + +static void ath_roc_complete(struct ath_softc *sc, bool abort) +{ + sc->offchannel.roc_vif = NULL; + sc->offchannel.roc_chan = NULL; + if (!abort) + ieee80211_remain_on_channel_expired(sc->hw); + ath_offchannel_next(sc); + ath9k_ps_restore(sc); +} + static void ath_scan_complete(struct ath_softc *sc, bool abort) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc), NULL); sc->offchannel.scan_req = NULL; sc->offchannel.scan_vif = NULL; sc->offchannel.state = ATH_OFFCHANNEL_IDLE; ieee80211_scan_completed(sc->hw, abort); clear_bit(ATH_OP_SCANNING, &common->op_flags); + ath_offchannel_next(sc); ath9k_ps_restore(sc); - - if (!sc->ps_idle) - return; - - ath_cancel_work(sc); } static void ath_scan_send_probe(struct ath_softc *sc, @@ -2253,11 +2279,11 @@ static void ath_scan_channel_start(struct ath_softc *sc) void ath_offchannel_channel_change(struct ath_softc *sc) { - if (!sc->offchannel.scan_req) - return; - switch (sc->offchannel.state) { case ATH_OFFCHANNEL_PROBE_SEND: + if (!sc->offchannel.scan_req) + return; + if (sc->cur_chan->chandef.chan != sc->offchannel.chan.chandef.chan) return; @@ -2265,8 +2291,23 @@ void ath_offchannel_channel_change(struct ath_softc *sc) ath_scan_channel_start(sc); break; case ATH_OFFCHANNEL_IDLE: + if (!sc->offchannel.scan_req) + return; + ath_scan_complete(sc, false); break; + case ATH_OFFCHANNEL_ROC_START: + if (sc->cur_chan != &sc->offchannel.chan) + break; + + sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT; + mod_timer(&sc->offchannel.timer, jiffies + + msecs_to_jiffies(sc->offchannel.roc_duration)); + ieee80211_ready_on_channel(sc->hw); + break; + case ATH_OFFCHANNEL_ROC_DONE: + ath_roc_complete(sc, false); + break; default: break; } @@ -2277,11 +2318,11 @@ void ath_offchannel_timer(unsigned long data) struct ath_softc *sc = (struct ath_softc *)data; struct ath_chanctx *ctx = ath_chanctx_get_oper_chan(sc); - if (!sc->offchannel.scan_req) - return; - switch (sc->offchannel.state) { case ATH_OFFCHANNEL_PROBE_WAIT: + if (!sc->offchannel.scan_req) + return; + if (ctx->active) { sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND; ath_chanctx_switch(sc, ctx, NULL); @@ -2290,8 +2331,16 @@ void ath_offchannel_timer(unsigned long data) } /* fall through */ case ATH_OFFCHANNEL_SUSPEND: + if (!sc->offchannel.scan_req) + return; + ath_scan_next_channel(sc); break; + case ATH_OFFCHANNEL_ROC_START: + case ATH_OFFCHANNEL_ROC_WAIT: + sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE; + ath_chanctx_switch(sc, ctx, NULL); + break; default: break; } @@ -2316,9 +2365,9 @@ static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, sc->offchannel.scan_vif = vif; sc->offchannel.scan_req = req; sc->offchannel.scan_idx = 0; - sc->offchannel.chan.txpower = vif->bss_conf.txpower; - ath_scan_next_channel(sc); + if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) + ath_offchannel_next(sc); out: mutex_unlock(&sc->mutex); @@ -2337,6 +2386,53 @@ static void ath9k_cancel_hw_scan(struct ieee80211_hw *hw, mutex_unlock(&sc->mutex); } +static int ath9k_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel *chan, int duration, + enum ieee80211_roc_type type) +{ + struct ath_softc *sc = hw->priv; + int ret = 0; + + mutex_lock(&sc->mutex); + + if (WARN_ON(sc->offchannel.roc_vif)) { + ret = -EBUSY; + goto out; + } + + ath9k_ps_wakeup(sc); + sc->offchannel.roc_vif = vif; + sc->offchannel.roc_chan = chan; + sc->offchannel.roc_duration = duration; + + if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) + ath_offchannel_next(sc); + +out: + mutex_unlock(&sc->mutex); + + return ret; +} + +static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + + mutex_lock(&sc->mutex); + + del_timer_sync(&sc->offchannel.timer); + + if (sc->offchannel.roc_vif) { + if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) + ath_roc_complete(sc, true); + } + + mutex_unlock(&sc->mutex); + + return 0; +} + void ath9k_fill_chanctx_ops(void) { if (!ath9k_use_chanctx) @@ -2344,6 +2440,8 @@ void ath9k_fill_chanctx_ops(void) ath9k_ops.hw_scan = ath9k_hw_scan; ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan; + ath9k_ops.remain_on_channel = ath9k_remain_on_channel; + ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel; } struct ieee80211_ops ath9k_ops = { diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 7972e1e24dd2..22460a1e033c 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2197,6 +2197,9 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, if (vif) avp = (void *)vif->drv_priv; + if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) + txctl->force_channel = true; + ret = ath_tx_prepare(hw, skb, txctl); if (ret) return ret; @@ -2234,7 +2237,8 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, if (txctl->an && queue) tid = ath_get_skb_tid(sc, txctl->an, skb); - if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) { + if (info->flags & (IEEE80211_TX_CTL_PS_RESPONSE | + IEEE80211_TX_CTL_TX_OFFCHAN)) { ath_txq_unlock(sc, txq); txq = sc->tx.uapsdq; ath_txq_lock(sc, txq); -- cgit v1.2.3 From 3930563570d3714420a2ebe0324a917ff64e0422 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:17:57 +0530 Subject: ath9k: Implement channel context ops Add channel context operations (add, remove, change, assign and unassign) to enable support for multiple channels. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 7 +++ drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/main.c | 104 +++++++++++++++++++++++++++++---- drivers/net/wireless/ath/ath9k/tx99.c | 2 +- 4 files changed, 102 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a8ae3e9b49fa..eae1830ad33f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -331,6 +331,7 @@ struct ath_chanctx { bool offchannel; bool stopped; bool active; + bool assigned; }; enum ath_offchannel_state { @@ -356,6 +357,12 @@ struct ath_offchannel { }; void ath9k_fill_chanctx_ops(void); +static inline struct ath_chanctx * +ath_chanctx_get(struct ieee80211_chanctx_conf *ctx) +{ + struct ath_chanctx **ptr = (void *) ctx->drv_priv; + return *ptr; +} void ath_chanctx_init(struct ath_softc *sc); void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 001b7d02345c..45f198ff6e0e 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -752,6 +752,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->max_scan_ssids = 255; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; hw->wiphy->max_remain_on_channel_duration = 10000; + hw->chanctx_data_size = sizeof(void *); } } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9e10434dbfa5..e0cb2af51767 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -624,7 +624,7 @@ static int ath9k_start(struct ieee80211_hw *hw) struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_channel *curchan = hw->conf.chandef.chan; + struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan; struct ath_chanctx *ctx = sc->cur_chan; struct ath9k_channel *init_channel; int r; @@ -1039,11 +1039,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath9k_beacon_assign_slot(sc, vif); avp->vif = vif; - - /* XXX - will be removed once chanctx ops are added */ - avp->chanctx = sc->cur_chan; - list_add_tail(&avp->list, &sc->cur_chan->vifs); - ath_chanctx_check_active(sc, avp->chanctx); + if (!ath9k_use_chanctx) + avp->chanctx = sc->cur_chan; an->sc = sc; an->sta = NULL; @@ -1132,7 +1129,6 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, } spin_unlock_bh(&sc->sc_pcu_lock); - list_del(&avp->list); sc->nvifs--; sc->tx99_vif = NULL; @@ -1144,7 +1140,6 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath9k_ps_restore(sc); ath_tx_node_cleanup(sc, &avp->mcast_node); - ath_chanctx_check_active(sc, avp->chanctx); mutex_unlock(&sc->mutex); } @@ -1271,7 +1266,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &hw->conf; struct ath_chanctx *ctx = sc->cur_chan; - bool reset_channel = false; ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); @@ -1287,7 +1281,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) * The chip needs a reset to properly wake up from * full sleep */ - reset_channel = ah->chip_fullsleep; + ath_chanctx_set_channel(sc, ctx, &ctx->chandef); } } @@ -1317,7 +1311,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } } - if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) { + if (!ath9k_use_chanctx && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL); ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef); } @@ -2433,6 +2427,89 @@ static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw) return 0; } +static int ath9k_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf) +{ + struct ath_softc *sc = hw->priv; + struct ath_chanctx *ctx, **ptr; + int i; + + mutex_lock(&sc->mutex); + for (i = 0; i < ATH9K_NUM_CHANCTX; i++) { + if (!sc->chanctx[i].assigned) + break; + } + if (i == ATH9K_NUM_CHANCTX) { + mutex_unlock(&sc->mutex); + return -ENOSPC; + } + + ctx = &sc->chanctx[i]; + ptr = (void *) conf->drv_priv; + *ptr = ctx; + ctx->assigned = true; + ath_chanctx_set_channel(sc, ctx, &conf->def); + mutex_unlock(&sc->mutex); + + return 0; +} + + +static void ath9k_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf) +{ + struct ath_softc *sc = hw->priv; + struct ath_chanctx *ctx = ath_chanctx_get(conf); + + mutex_lock(&sc->mutex); + ctx->assigned = false; + mutex_unlock(&sc->mutex); +} + +static void ath9k_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, + u32 changed) +{ + struct ath_softc *sc = hw->priv; + struct ath_chanctx *ctx = ath_chanctx_get(conf); + + mutex_lock(&sc->mutex); + ath_chanctx_set_channel(sc, ctx, &conf->def); + mutex_unlock(&sc->mutex); +} + +static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf) +{ + struct ath_softc *sc = hw->priv; + struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_chanctx *ctx = ath_chanctx_get(conf); + + mutex_lock(&sc->mutex); + avp->chanctx = ctx; + list_add_tail(&avp->list, &ctx->vifs); + ath_chanctx_check_active(sc, ctx); + mutex_unlock(&sc->mutex); + + return 0; +} + +static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf) +{ + struct ath_softc *sc = hw->priv; + struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_chanctx *ctx = ath_chanctx_get(conf); + + mutex_lock(&sc->mutex); + avp->chanctx = NULL; + list_del(&avp->list); + ath_chanctx_check_active(sc, ctx); + mutex_unlock(&sc->mutex); +} + void ath9k_fill_chanctx_ops(void) { if (!ath9k_use_chanctx) @@ -2442,6 +2519,11 @@ void ath9k_fill_chanctx_ops(void) ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan; ath9k_ops.remain_on_channel = ath9k_remain_on_channel; ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel; + ath9k_ops.add_chanctx = ath9k_add_chanctx; + ath9k_ops.remove_chanctx = ath9k_remove_chanctx; + ath9k_ops.change_chanctx = ath9k_change_chanctx; + ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx; + ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx; } struct ieee80211_ops ath9k_ops = { diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index a65cfb91adca..23972924c774 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -76,7 +76,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) tx_info = IEEE80211_SKB_CB(skb); memset(tx_info, 0, sizeof(*tx_info)); rate = &tx_info->control.rates[0]; - tx_info->band = hw->conf.chandef.chan->band; + tx_info->band = sc->cur_chan->chandef.chan->band; tx_info->flags = IEEE80211_TX_CTL_NO_ACK; tx_info->control.vif = sc->tx99_vif; rate->count = 1; -- cgit v1.2.3 From c4dc0d040e356efc0263e0b27181b05f9ef33e5f Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 11 Jun 2014 16:17:58 +0530 Subject: ath9k: Fetch appropriate operating channel context Retrieve appropriate operating channel context while switching between operating and off channels. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 7 +++++- drivers/net/wireless/ath/ath9k/channel.c | 14 +++++++----- drivers/net/wireless/ath/ath9k/main.c | 37 ++++++++++++++++---------------- 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index eae1830ad33f..3db489824261 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -355,6 +355,10 @@ struct ath_offchannel { struct ieee80211_vif *roc_vif; int roc_duration; }; +#define ath_for_each_chanctx(_sc, _ctx) \ + for (ctx = &sc->chanctx[0]; \ + ctx <= &sc->chanctx[ARRAY_SIZE(sc->chanctx) - 1]; \ + ctx++) void ath9k_fill_chanctx_ops(void); static inline struct ath_chanctx * @@ -373,7 +377,8 @@ void ath_offchannel_timer(unsigned long data); void ath_offchannel_channel_change(struct ath_softc *sc); void ath_chanctx_offchan_switch(struct ath_softc *sc, struct ieee80211_channel *chan); -struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc); +struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, + bool active); int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); int ath_startrecv(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index c679a26045ac..097207073cd4 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -293,13 +293,17 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, ath_set_channel(sc); } -struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc) +struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active) { - u8 i; + struct ath_chanctx *ctx; + + ath_for_each_chanctx(sc, ctx) { + if (!ctx->assigned || list_empty(&ctx->vifs)) + continue; + if (active && !ctx->active) + continue; - for (i = 0; i < ARRAY_SIZE(sc->chanctx); i++) { - if (!list_empty(&sc->chanctx[i].vifs)) - return &sc->chanctx[i]; + return ctx; } return &sc->chanctx[0]; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e0cb2af51767..92bf9079184f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2161,7 +2161,8 @@ ath_scan_next_channel(struct ath_softc *sc) if (sc->offchannel.scan_idx >= req->n_channels) { sc->offchannel.state = ATH_OFFCHANNEL_IDLE; - ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc), NULL); + ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), + NULL); return; } @@ -2184,7 +2185,8 @@ static void ath_offchannel_next(struct ath_softc *sc) sc->offchannel.state = ATH_OFFCHANNEL_ROC_START; ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan); } else { - ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc), NULL); + ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), + NULL); sc->offchannel.state = ATH_OFFCHANNEL_IDLE; if (sc->ps_idle) ath_cancel_work(sc); @@ -2310,13 +2312,15 @@ void ath_offchannel_channel_change(struct ath_softc *sc) void ath_offchannel_timer(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; - struct ath_chanctx *ctx = ath_chanctx_get_oper_chan(sc); + struct ath_chanctx *ctx; switch (sc->offchannel.state) { case ATH_OFFCHANNEL_PROBE_WAIT: if (!sc->offchannel.scan_req) return; + /* get first active channel context */ + ctx = ath_chanctx_get_oper_chan(sc, true); if (ctx->active) { sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND; ath_chanctx_switch(sc, ctx, NULL); @@ -2332,6 +2336,7 @@ void ath_offchannel_timer(unsigned long data) break; case ATH_OFFCHANNEL_ROC_START: case ATH_OFFCHANNEL_ROC_WAIT: + ctx = ath_chanctx_get_oper_chan(sc, false); sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE; ath_chanctx_switch(sc, ctx, NULL); break; @@ -2432,26 +2437,22 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_chanctx *ctx, **ptr; - int i; mutex_lock(&sc->mutex); - for (i = 0; i < ATH9K_NUM_CHANCTX; i++) { - if (!sc->chanctx[i].assigned) - break; - } - if (i == ATH9K_NUM_CHANCTX) { + + ath_for_each_chanctx(sc, ctx) { + if (ctx->assigned) + continue; + + ptr = (void *) conf->drv_priv; + *ptr = ctx; + ctx->assigned = true; + ath_chanctx_set_channel(sc, ctx, &conf->def); mutex_unlock(&sc->mutex); - return -ENOSPC; + return 0; } - - ctx = &sc->chanctx[i]; - ptr = (void *) conf->drv_priv; - *ptr = ctx; - ctx->assigned = true; - ath_chanctx_set_channel(sc, ctx, &conf->def); mutex_unlock(&sc->mutex); - - return 0; + return -ENOSPC; } -- cgit v1.2.3 From b01459e856cbe9ccf64dde251aec02eae60094ce Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:17:59 +0530 Subject: ath9k: Move caldata into channel context Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++-- drivers/net/wireless/ath/ath9k/debug.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 2 +- drivers/net/wireless/ath/ath9k/mci.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3db489824261..ffacbf6e9f52 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -327,6 +327,8 @@ struct ath_chanctx { struct list_head vifs; struct list_head acq[IEEE80211_NUM_ACS]; + struct ath9k_hw_cal_data caldata; + u16 txpower; bool offchannel; bool stopped; @@ -820,8 +822,6 @@ struct ath_softc { struct led_classdev led_cdev; #endif - struct ath9k_hw_cal_data caldata; - #ifdef CONFIG_ATH9K_DEBUGFS struct ath9k_debug debug; #endif diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 6cc42be48d4e..f230e2e9824e 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1080,7 +1080,7 @@ static ssize_t read_file_dump_nfcal(struct file *file, char __user *user_buf, { struct ath_softc *sc = file->private_data; struct ath_hw *ah = sc->sc_ah; - struct ath9k_nfcal_hist *h = sc->caldata.nfCalHist; + struct ath9k_nfcal_hist *h = sc->cur_chan->caldata.nfCalHist; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &common->hw->conf; u32 len = 0, size = 1500; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 92bf9079184f..85db24be8eec 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -279,7 +279,7 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) if (!sc->cur_chan->offchannel) { fastcc = false; - caldata = &sc->caldata; + caldata = &sc->cur_chan->caldata; } if (!hchan) { diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 313ed995585a..3f7a11edb82a 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -706,7 +706,7 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, return; if (setchannel) { - struct ath9k_hw_cal_data *caldata = &sc->caldata; + struct ath9k_hw_cal_data *caldata = &sc->cur_chan->caldata; if (IS_CHAN_HT40PLUS(ah->curchan) && (ah->curchan->channel > caldata->channel) && (ah->curchan->channel <= caldata->channel + 20)) -- cgit v1.2.3 From 26f16c246cea41f30ab2f63214a5529678677d0d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:18:00 +0530 Subject: ath9k: Add ATH_OP_MULTI_CHANNEL Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 1 + drivers/net/wireless/ath/ath9k/channel.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index a889fd66fc63..fd9e5305e77f 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -63,6 +63,7 @@ enum ath_op_flags { ATH_OP_PRIM_STA_VIF, ATH_OP_HW_RESET, ATH_OP_SCANNING, + ATH_OP_MULTI_CHANNEL, }; enum ath_bus_type { diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 097207073cd4..e3127b52e1ee 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -150,8 +150,10 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp, void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp; bool active = false; + u8 n_active = 0; if (!ctx) return; @@ -171,6 +173,17 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) } } ctx->active = active; + + ath_for_each_chanctx(sc, ctx) { + if (!ctx->assigned || list_empty(&ctx->vifs)) + continue; + n_active++; + } + + if (n_active > 1) + set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags); + else + clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags); } static bool -- cgit v1.2.3 From 8d7e09dda8214e4154f45238b4c85ab1ecb5d89a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:18:01 +0530 Subject: ath9k: save tsf in channel context Save TSF in channel context for multiple operating channels. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 +++ drivers/net/wireless/ath/ath9k/channel.c | 5 +++++ drivers/net/wireless/ath/ath9k/hw.c | 23 ++++++++++++++++++----- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 10 ++++++++++ 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index ffacbf6e9f52..4df412b71680 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "common.h" #include "debug.h" @@ -328,6 +329,8 @@ struct ath_chanctx { struct list_head acq[IEEE80211_NUM_ACS]; struct ath9k_hw_cal_data caldata; + struct timespec tsf_ts; + u64 tsf_val; u16 txpower; bool offchannel; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index e3127b52e1ee..4a7691eecdb4 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -227,6 +227,11 @@ void ath_chanctx_work(struct work_struct *work) send_ps = true; spin_lock_bh(&sc->chan_lock); + + if (sc->cur_chan != &sc->offchannel.chan) { + getrawmonotonic(&sc->cur_chan->tsf_ts); + sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah); + } } sc->cur_chan = sc->next_chan; sc->cur_chan->stopped = false; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2a8ed8375ec0..ace4fe2740d4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1730,6 +1730,23 @@ fail: return -EINVAL; } +u32 ath9k_hw_get_tsf_offset(struct timespec *last, struct timespec *cur) +{ + struct timespec ts; + s64 usec; + + if (!cur) { + getrawmonotonic(&ts); + cur = &ts; + } + + usec = cur->tv_sec * 1000000ULL + cur->tv_nsec / 1000; + usec -= last->tv_sec * 1000000ULL + last->tv_nsec / 1000; + + return (u32) usec; +} +EXPORT_SYMBOL(ath9k_hw_get_tsf_offset); + int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, struct ath9k_hw_cal_data *caldata, bool fastcc) { @@ -1739,7 +1756,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, u32 saveDefAntenna; u32 macStaId1; u64 tsf = 0; - s64 usec = 0; int r; bool start_mci_reset = false; bool save_fullsleep = ah->chip_fullsleep; @@ -1785,7 +1801,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, /* Save TSF before chip reset, a cold reset clears it */ tsf = ath9k_hw_gettsf64(ah); getrawmonotonic(&ts); - usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000; saveLedState = REG_READ(ah, AR_CFG_LED) & (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | @@ -1818,9 +1833,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, } /* Restore TSF */ - getrawmonotonic(&ts); - usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000 - usec; - ath9k_hw_settsf64(ah, tsf + usec); + ath9k_hw_settsf64(ah, tsf + ath9k_hw_get_tsf_offset(&ts, NULL)); if (AR_SREV_9280_20_OR_LATER(ah)) REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 0acd4b5a4892..51b4ebe04c04 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1000,6 +1000,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah); u64 ath9k_hw_gettsf64(struct ath_hw *ah); void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); +u32 ath9k_hw_get_tsf_offset(struct timespec *last, struct timespec *cur); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set); void ath9k_hw_init_global_settings(struct ath_hw *ah); u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 85db24be8eec..6abdf99ffae4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -240,6 +240,16 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath9k_hw_enable_interrupts(ah); if (!sc->cur_chan->offchannel && start) { + /* restore per chanctx TSF timer */ + if (sc->cur_chan->tsf_val) { + u32 offset; + + offset = ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, + NULL); + ath9k_hw_settsf64(ah, sc->cur_chan->tsf_val + offset); + } + + if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) goto work; -- cgit v1.2.3 From ca900ac9d9f0e38782f5a24e64b05f607fd6eb4c Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 11 Jun 2014 16:18:02 +0530 Subject: ath9k: Move beacon config to channel context Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/beacon.c | 10 +++++----- drivers/net/wireless/ath/ath9k/channel.c | 1 - drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/link.c | 2 +- drivers/net/wireless/ath/ath9k/recv.c | 2 +- drivers/net/wireless/ath/ath9k/xmit.c | 6 +++--- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 4df412b71680..d632f8f2a72c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -328,6 +328,7 @@ struct ath_chanctx { struct list_head vifs; struct list_head acq[IEEE80211_NUM_ACS]; + struct ath_beacon_config beacon; struct ath9k_hw_cal_data caldata; struct timespec tsf_ts; u64 tsf_val; @@ -828,7 +829,6 @@ struct ath_softc { #ifdef CONFIG_ATH9K_DEBUGFS struct ath9k_debug debug; #endif - struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; struct delayed_work hw_pll_work; struct timer_list sleep_timer; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index eae8f686f125..c0ff01599ed3 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -249,7 +249,7 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif) static int ath9k_beacon_choose_slot(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; u16 intval; u32 tsftu; u64 tsf; @@ -277,7 +277,7 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc) static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; struct ath_vif *avp = (void *)vif->drv_priv; u32 tsfadjust; @@ -528,7 +528,7 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, struct ieee80211_bss_conf *bss_conf) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; ath_dbg(common, BEACON, "Caching beacon data for BSS: %pM\n", bss_conf->bssid); @@ -564,7 +564,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, u32 changed) { struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); unsigned long flags; @@ -631,7 +631,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, void ath9k_set_beacon(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; switch (sc->sc_ah->opmode) { case NL80211_IFTYPE_AP: diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 4a7691eecdb4..156625318d04 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -271,7 +271,6 @@ void ath_chanctx_init(struct ath_softc *sc) for (j = 0; j < ARRAY_SIZE(ctx->acq); j++) INIT_LIST_HEAD(&ctx->acq[j]); } - sc->cur_chan = &sc->chanctx[0]; ctx = &sc->offchannel.chan; cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20); INIT_LIST_HEAD(&ctx->vifs); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 45f198ff6e0e..1ff1a75f4fed 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -510,6 +510,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET); sc->tx99_power = MAX_RATE_POWER + 1; init_waitqueue_head(&sc->tx_wait); + sc->cur_chan = &sc->chanctx[0]; if (!pdata || pdata->use_eeprom) { ah->ah_flags |= AH_USE_EEPROM; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index d9c01d563cc2..2343f56e6498 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -440,7 +440,7 @@ void ath_check_ani(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; /* * Check for the various conditions in which ANI has to diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index fec9e0b42f5d..7b9c7e53caaa 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -545,7 +545,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, PS, "Reconfigure beacon timers based on synchronized timestamp\n"); - if (!(WARN_ON_ONCE(sc->cur_beacon_conf.beacon_interval == 0))) + if (!(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0))) ath9k_set_beacon(sc); if (sc->p2p_ps_vif) ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 22460a1e033c..7dd6187761c1 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1694,7 +1694,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum, int ath_cabq_update(struct ath_softc *sc) { struct ath9k_tx_queue_info qi; - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; int qnum = sc->beacon.cabq->axq_qnum; ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); @@ -2301,8 +2301,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int max_duration; max_duration = - sc->cur_beacon_conf.beacon_interval * 1000 * - sc->cur_beacon_conf.dtim_period / ATH_BCBUF; + sc->cur_chan->beacon.beacon_interval * 1000 * + sc->cur_chan->beacon.dtim_period / ATH_BCBUF; do { struct ath_frame_info *fi = get_frame_info(skb); -- cgit v1.2.3 From 9a9c4fbc3fcabc0d510600743204f890ebdbb141 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 11 Jun 2014 16:18:03 +0530 Subject: ath9k: Summarize hw state per channel context Group and set hw state (opmode, primary_sta, beacon conf) per channel context instead of whole list of vifs. This would allow each channel context to run in different mode (STA/AP). Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 13 +- drivers/net/wireless/ath/ath9k/beacon.c | 28 +++- drivers/net/wireless/ath/ath9k/debug.c | 26 +-- drivers/net/wireless/ath/ath9k/main.c | 275 ++++++++++++++++---------------- 4 files changed, 184 insertions(+), 158 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index d632f8f2a72c..a0c7279e4364 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -328,6 +328,9 @@ struct ath_chanctx { struct list_head vifs; struct list_head acq[IEEE80211_NUM_ACS]; + /* do not dereference, use for comparison only */ + struct ieee80211_vif *primary_sta; + struct ath_beacon_config beacon; struct ath9k_hw_cal_data caldata; struct timespec tsf_ts; @@ -438,7 +441,6 @@ struct ath_vif { struct ieee80211_vif *vif; struct ath_node mcast_node; int av_bslot; - bool primary_sta_vif; __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ struct ath_buf *av_bcbuf; struct ath_chanctx *chanctx; @@ -451,17 +453,22 @@ struct ath9k_vif_iter_data { u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */ u8 mask[ETH_ALEN]; /* bssid mask */ bool has_hw_macaddr; + u8 slottime; + bool beacons; int naps; /* number of AP vifs */ int nmeshes; /* number of mesh vifs */ int nstations; /* number of station vifs */ int nwds; /* number of WDS vifs */ int nadhocs; /* number of adhoc vifs */ + struct ieee80211_vif *primary_sta; }; -void ath9k_calculate_iter_data(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, +void ath9k_calculate_iter_data(struct ath_softc *sc, + struct ath_chanctx *ctx, struct ath9k_vif_iter_data *iter_data); +void ath9k_calculate_summary_state(struct ath_softc *sc, + struct ath_chanctx *ctx); /*******************/ /* Beacon Handling */ diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index c0ff01599ed3..d3553927c6dd 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -277,8 +277,8 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc) static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_beacon_config *cur_conf = &avp->chanctx->beacon; u32 tsfadjust; if (avp->av_bslot == 0) @@ -500,7 +500,6 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp = (void *)vif->drv_priv; if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { if ((vif->type != NL80211_IFTYPE_AP) || @@ -514,7 +513,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { if ((vif->type == NL80211_IFTYPE_STATION) && test_bit(ATH_OP_BEACONS, &common->op_flags) && - !avp->primary_sta_vif) { + vif != sc->cur_chan->primary_sta) { ath_dbg(common, CONFIG, "Beacon already configured for a station interface\n"); return false; @@ -525,10 +524,11 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, } static void ath9k_cache_beacon_config(struct ath_softc *sc, + struct ath_chanctx *ctx, struct ieee80211_bss_conf *bss_conf) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; + struct ath_beacon_config *cur_conf = &ctx->beacon; ath_dbg(common, BEACON, "Caching beacon data for BSS: %pM\n", bss_conf->bssid); @@ -564,20 +564,29 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, u32 changed) { struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_chanctx *ctx = avp->chanctx; + struct ath_beacon_config *cur_conf; unsigned long flags; bool skip_beacon = false; + if (!ctx) + return; + + cur_conf = &avp->chanctx->beacon; if (vif->type == NL80211_IFTYPE_AP) ath9k_set_tsfadjust(sc, vif); if (!ath9k_allow_beacon_config(sc, vif)) return; - if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { - ath9k_cache_beacon_config(sc, bss_conf); + if (vif->type == NL80211_IFTYPE_STATION) { + ath9k_cache_beacon_config(sc, ctx, bss_conf); + if (ctx != sc->cur_chan) + return; + ath9k_set_beacon(sc); set_bit(ATH_OP_BEACONS, &common->op_flags); return; @@ -593,10 +602,13 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, cur_conf->enable_beacon = false; } else if (bss_conf->enable_beacon) { cur_conf->enable_beacon = true; - ath9k_cache_beacon_config(sc, bss_conf); + ath9k_cache_beacon_config(sc, ctx, bss_conf); } } + if (ctx != sc->cur_chan) + return; + /* * Configure the HW beacon registers only when we have a valid * beacon interval. diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index f230e2e9824e..ce073e995dfe 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -750,13 +750,13 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, { struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ieee80211_hw *hw = sc->hw; struct ath9k_vif_iter_data iter_data; + struct ath_chanctx *ctx; char buf[512]; unsigned int len = 0; ssize_t retval = 0; unsigned int reg; - u32 rxfilter; + u32 rxfilter, i; len += scnprintf(buf + len, sizeof(buf) - len, "BSSID: %pM\n", common->curbssid); @@ -826,14 +826,20 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, len += scnprintf(buf + len, sizeof(buf) - len, "\n"); - ath9k_calculate_iter_data(hw, NULL, &iter_data); - - len += scnprintf(buf + len, sizeof(buf) - len, - "VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i" - " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", - iter_data.naps, iter_data.nstations, iter_data.nmeshes, - iter_data.nwds, iter_data.nadhocs, - sc->nvifs, sc->nbcnvifs); + i = 0; + ath_for_each_chanctx(sc, ctx) { + if (!ctx->assigned || list_empty(&ctx->vifs)) + continue; + ath9k_calculate_iter_data(sc, ctx, &iter_data); + + len += scnprintf(buf + len, sizeof(buf) - len, + "VIF-COUNTS: CTX %i AP: %i STA: %i MESH: %i WDS: %i", + i++, iter_data.naps, iter_data.nstations, + iter_data.nmeshes, iter_data.nwds); + len += scnprintf(buf + len, sizeof(buf) - len, + " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", + iter_data.nadhocs, sc->nvifs, sc->nbcnvifs); + } if (len > sizeof(buf)) len = sizeof(buf); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6abdf99ffae4..9dfb82077016 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -19,9 +19,6 @@ #include "ath9k.h" #include "btcoex.h" -static void ath9k_set_assoc_state(struct ath_softc *sc, - struct ieee80211_vif *vif); - u8 ath9k_parse_mpdudensity(u8 mpdudensity) { /* @@ -236,8 +233,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) sc->cur_chan->txpower, &sc->curtxpow); clear_bit(ATH_OP_HW_RESET, &common->op_flags); - ath9k_hw_set_interrupts(ah); - ath9k_hw_enable_interrupts(ah); + ath9k_calculate_summary_state(sc, sc->cur_chan); if (!sc->cur_chan->offchannel && start) { /* restore per chanctx TSF timer */ @@ -267,6 +263,10 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) } sc->gtt_cnt = 0; + + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); + ieee80211_wake_queues(sc->hw); ath9k_p2p_ps_timer(sc); @@ -905,18 +905,29 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) iter_data->has_hw_macaddr = true; } + if (!vif->bss_conf.use_short_slot) + iter_data->slottime = ATH9K_SLOT_TIME_20; + switch (vif->type) { case NL80211_IFTYPE_AP: iter_data->naps++; + if (vif->bss_conf.enable_beacon) + iter_data->beacons = true; break; case NL80211_IFTYPE_STATION: iter_data->nstations++; + if (vif->bss_conf.assoc && !iter_data->primary_sta) + iter_data->primary_sta = vif; break; case NL80211_IFTYPE_ADHOC: iter_data->nadhocs++; + if (vif->bss_conf.enable_beacon) + iter_data->beacons = true; break; case NL80211_IFTYPE_MESH_POINT: iter_data->nmeshes++; + if (vif->bss_conf.enable_beacon) + iter_data->beacons = true; break; case NL80211_IFTYPE_WDS: iter_data->nwds++; @@ -926,26 +937,12 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) } } -static void ath9k_sta_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct ath_softc *sc = data; - struct ath_vif *avp = (void *)vif->drv_priv; - - if (vif->type != NL80211_IFTYPE_STATION) - return; - - if (avp->primary_sta_vif) - ath9k_set_assoc_state(sc, vif); -} - /* Called with sc->mutex held. */ -void ath9k_calculate_iter_data(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, +void ath9k_calculate_iter_data(struct ath_softc *sc, + struct ath_chanctx *ctx, struct ath9k_vif_iter_data *iter_data) { - struct ath_softc *sc = hw->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); + struct ath_vif *avp; /* * Pick the MAC address of the first interface as the new hardware @@ -954,29 +951,80 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, */ memset(iter_data, 0, sizeof(*iter_data)); memset(&iter_data->mask, 0xff, ETH_ALEN); + iter_data->slottime = ATH9K_SLOT_TIME_9; + + list_for_each_entry(avp, &ctx->vifs, list) + ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif); + + if (ctx == &sc->offchannel.chan) { + struct ieee80211_vif *vif; + + if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START) + vif = sc->offchannel.scan_vif; + else + vif = sc->offchannel.roc_vif; + + if (vif) + ath9k_vif_iter(iter_data, vif->addr, vif); + iter_data->beacons = false; + } +} + +static void ath9k_set_assoc_state(struct ath_softc *sc, + struct ieee80211_vif *vif, bool changed) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + unsigned long flags; + + set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); + /* Set the AID, BSSID and do beacon-sync only when + * the HW opmode is STATION. + * + * But the primary bit is set above in any case. + */ + if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) + return; + + ether_addr_copy(common->curbssid, bss_conf->bssid); + common->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah); + + if (changed) { + common->last_rssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - if (vif) - ath9k_vif_iter(iter_data, vif->addr, vif); + spin_lock_irqsave(&sc->sc_pm_lock, flags); + sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + } - /* Get list of all active MAC addresses */ - ieee80211_iterate_active_interfaces_atomic( - sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - ath9k_vif_iter, iter_data); + if (ath9k_hw_mci_is_enabled(sc->sc_ah)) + ath9k_mci_update_wlan_channels(sc, false); - memcpy(common->macaddr, iter_data->hw_macaddr, ETH_ALEN); + ath_dbg(common, CONFIG, + "Primary Station interface: %pM, BSSID: %pM\n", + vif->addr, common->curbssid); } /* Called with sc->mutex held. */ -static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +void ath9k_calculate_summary_state(struct ath_softc *sc, + struct ath_chanctx *ctx) { - struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_vif_iter_data iter_data; - enum nl80211_iftype old_opmode = ah->opmode; - ath9k_calculate_iter_data(hw, vif, &iter_data); + ath_chanctx_check_active(sc, ctx); + + if (ctx != sc->cur_chan) + return; + + ath9k_ps_wakeup(sc); + ath9k_calculate_iter_data(sc, ctx, &iter_data); + + if (iter_data.has_hw_macaddr) + ether_addr_copy(common->macaddr, iter_data.hw_macaddr); memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); ath_hw_setbssidmask(common); @@ -1004,19 +1052,48 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, else ah->imask &= ~ATH9K_INT_TSFOOR; + ah->imask &= ~ATH9K_INT_SWBA; + if (ah->opmode == NL80211_IFTYPE_STATION) { + bool changed = (iter_data.primary_sta != ctx->primary_sta); + + iter_data.beacons = true; + if (iter_data.primary_sta) { + ath9k_set_assoc_state(sc, iter_data.primary_sta, + changed); + if (!ctx->primary_sta || + !ctx->primary_sta->bss_conf.assoc) + ctx->primary_sta = iter_data.primary_sta; + } else { + ctx->primary_sta = NULL; + memset(common->curbssid, 0, ETH_ALEN); + common->curaid = 0; + ath9k_hw_write_associd(sc->sc_ah); + if (ath9k_hw_mci_is_enabled(sc->sc_ah)) + ath9k_mci_update_wlan_channels(sc, true); + } + } else if (iter_data.beacons) { + ah->imask |= ATH9K_INT_SWBA; + } ath9k_hw_set_interrupts(ah); - /* - * If we are changing the opmode to STATION, - * a beacon sync needs to be done. - */ - if (ah->opmode == NL80211_IFTYPE_STATION && - old_opmode == NL80211_IFTYPE_AP && - test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { - ieee80211_iterate_active_interfaces_atomic( - sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - ath9k_sta_vif_iter, sc); + if (iter_data.beacons) + set_bit(ATH_OP_BEACONS, &common->op_flags); + else + clear_bit(ATH_OP_BEACONS, &common->op_flags); + + if (ah->slottime != iter_data.slottime) { + ah->slottime = iter_data.slottime; + ath9k_hw_init_global_settings(ah); } + + if (iter_data.primary_sta) + set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); + else + clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); + + ctx->primary_sta = iter_data.primary_sta; + + ath9k_ps_restore(sc); } static int ath9k_add_interface(struct ieee80211_hw *hw, @@ -1041,16 +1118,14 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type); sc->nvifs++; - ath9k_ps_wakeup(sc); - ath9k_calculate_summary_state(hw, vif); - ath9k_ps_restore(sc); - if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); avp->vif = vif; - if (!ath9k_use_chanctx) + if (!ath9k_use_chanctx) { avp->chanctx = sc->cur_chan; + list_add_tail(&avp->list, &avp->chanctx->vifs); + } an->sc = sc; an->sta = NULL; @@ -1086,13 +1161,10 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, vif->type = new_type; vif->p2p = p2p; - ath9k_ps_wakeup(sc); - ath9k_calculate_summary_state(hw, vif); - ath9k_ps_restore(sc); - if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); - ath_chanctx_check_active(sc, avp->chanctx); + + ath9k_calculate_summary_state(sc, avp->chanctx); mutex_unlock(&sc->mutex); return 0; @@ -1141,14 +1213,12 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, sc->nvifs--; sc->tx99_vif = NULL; + if (!ath9k_use_chanctx) + list_del(&avp->list); if (ath9k_uses_beacons(vif->type)) ath9k_beacon_remove_slot(sc, vif); - ath9k_ps_wakeup(sc); - ath9k_calculate_summary_state(hw, NULL); - ath9k_ps_restore(sc); - ath_tx_node_cleanup(sc, &avp->mcast_node); mutex_unlock(&sc->mutex); @@ -1585,58 +1655,6 @@ static int ath9k_set_key(struct ieee80211_hw *hw, return ret; } -static void ath9k_set_assoc_state(struct ath_softc *sc, - struct ieee80211_vif *vif) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp = (void *)vif->drv_priv; - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - unsigned long flags; - - set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); - avp->primary_sta_vif = true; - - /* - * Set the AID, BSSID and do beacon-sync only when - * the HW opmode is STATION. - * - * But the primary bit is set above in any case. - */ - if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) - return; - - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - common->curaid = bss_conf->aid; - ath9k_hw_write_associd(sc->sc_ah); - - common->last_rssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - - spin_lock_irqsave(&sc->sc_pm_lock, flags); - sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; - spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - - if (ath9k_hw_mci_is_enabled(sc->sc_ah)) - ath9k_mci_update_wlan_channels(sc, false); - - ath_dbg(common, CONFIG, - "Primary Station interface: %pM, BSSID: %pM\n", - vif->addr, common->curbssid); -} - -static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct ath_softc *sc = data; - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - - if (test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) - return; - - if (bss_conf->assoc) - ath9k_set_assoc_state(sc, vif); -} - void ath9k_p2p_ps_timer(void *priv) { struct ath_softc *sc = priv; @@ -1646,7 +1664,7 @@ void ath9k_p2p_ps_timer(void *priv) struct ath_node *an; u32 tsf; - if (!avp) + if (!avp || avp->chanctx != sc->cur_chan) return; tsf = ath9k_hw_gettsf32(sc->sc_ah); @@ -1721,28 +1739,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n", bss_conf->bssid, bss_conf->assoc); - if (avp->primary_sta_vif && !bss_conf->assoc) { - clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); - avp->primary_sta_vif = false; - - if (ah->opmode == NL80211_IFTYPE_STATION) - clear_bit(ATH_OP_BEACONS, &common->op_flags); - } - - ieee80211_iterate_active_interfaces_atomic( - sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - ath9k_bss_assoc_iter, sc); - - if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags) && - ah->opmode == NL80211_IFTYPE_STATION) { - memset(common->curbssid, 0, ETH_ALEN); - common->curaid = 0; - ath9k_hw_write_associd(sc->sc_ah); - if (ath9k_hw_mci_is_enabled(sc->sc_ah)) - ath9k_mci_update_wlan_channels(sc, true); - } - - ath_chanctx_check_active(sc, avp->chanctx); + ath9k_calculate_summary_state(sc, avp->chanctx); } if (changed & BSS_CHANGED_IBSS) { @@ -1752,10 +1749,14 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if ((changed & BSS_CHANGED_BEACON_ENABLED) || - (changed & BSS_CHANGED_BEACON_INT)) + (changed & BSS_CHANGED_BEACON_INT)) { + if (changed & BSS_CHANGED_BEACON_ENABLED) + ath9k_calculate_summary_state(sc, avp->chanctx); ath9k_beacon_config(sc, vif, changed); + } - if (changed & BSS_CHANGED_ERP_SLOT) { + if ((avp->chanctx == sc->cur_chan) && + (changed & BSS_CHANGED_ERP_SLOT)) { if (bss_conf->use_short_slot) slottime = 9; else @@ -2500,7 +2501,7 @@ static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); avp->chanctx = ctx; list_add_tail(&avp->list, &ctx->vifs); - ath_chanctx_check_active(sc, ctx); + ath9k_calculate_summary_state(sc, ctx); mutex_unlock(&sc->mutex); return 0; @@ -2517,7 +2518,7 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); avp->chanctx = NULL; list_del(&avp->list); - ath_chanctx_check_active(sc, ctx); + ath9k_calculate_summary_state(sc, ctx); mutex_unlock(&sc->mutex); } -- cgit v1.2.3 From 748299f27b21c23ba963df4768abb2344fe6e9a7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:18:04 +0530 Subject: ath9k: switch channel context for beaconing Add a basic state machine for switch channel context for beacon transmission. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 25 ++++++++++ drivers/net/wireless/ath/ath9k/beacon.c | 11 ++++- drivers/net/wireless/ath/ath9k/channel.c | 84 +++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath9k/main.c | 9 +++- drivers/net/wireless/ath/ath9k/xmit.c | 2 + 5 files changed, 126 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a0c7279e4364..b657115d1eb7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -341,6 +341,28 @@ struct ath_chanctx { bool stopped; bool active; bool assigned; + bool switch_after_beacon; +}; + +enum ath_chanctx_event { + ATH_CHANCTX_EVENT_BEACON_PREPARE, + ATH_CHANCTX_EVENT_BEACON_SENT, + ATH_CHANCTX_EVENT_TSF_TIMER, +}; + +enum ath_chanctx_state { + ATH_CHANCTX_STATE_IDLE, + ATH_CHANCTX_STATE_WAIT_FOR_BEACON, + ATH_CHANCTX_STATE_WAIT_FOR_TIMER, + ATH_CHANCTX_STATE_SWITCH, +}; + +struct ath_chanctx_sched { + bool beacon_pending; + enum ath_chanctx_state state; + + u32 next_tbtt; + unsigned int channel_switch_time; }; enum ath_offchannel_state { @@ -388,6 +410,8 @@ void ath_chanctx_offchan_switch(struct ath_softc *sc, struct ieee80211_channel *chan); struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active); +void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, + enum ath_chanctx_event ev); int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); int ath_startrecv(struct ath_softc *sc); @@ -826,6 +850,7 @@ struct ath_softc { struct ath_chanctx *next_chan; spinlock_t chan_lock; struct ath_offchannel offchannel; + struct ath_chanctx_sched sched; #ifdef CONFIG_MAC80211_LEDS bool led_registered; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index d3553927c6dd..5b1689cf029a 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -374,12 +374,19 @@ void ath9k_beacon_tasklet(unsigned long data) vif = sc->beacon.bslot[slot]; /* EDMA devices check that in the tx completion function. */ - if (!edma && ath9k_csa_is_finished(sc, vif)) - return; + if (!edma) { + if (sc->sched.beacon_pending) + ath_chanctx_event(sc, NULL, + ATH_CHANCTX_EVENT_BEACON_SENT); + + if (ath9k_csa_is_finished(sc, vif)) + return; + } if (!vif || !vif->bss_conf.enable_beacon) return; + ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE); bf = ath9k_beacon_generate(sc->hw, vif); if (sc->beacon.bmisscnt != 0) { diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 156625318d04..503b7766e12e 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -202,10 +202,33 @@ ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave) return sent; } +static bool ath_chanctx_defer_switch(struct ath_softc *sc) +{ + if (sc->cur_chan == &sc->offchannel.chan) + return false; + + switch (sc->sched.state) { + case ATH_CHANCTX_STATE_SWITCH: + return false; + case ATH_CHANCTX_STATE_IDLE: + if (!sc->cur_chan->switch_after_beacon) + return false; + + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + break; + default: + break; + } + + return true; +} + void ath_chanctx_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, chanctx_work); + struct timespec ts; + bool measure_time = false; bool send_ps = false; mutex_lock(&sc->mutex); @@ -216,10 +239,20 @@ void ath_chanctx_work(struct work_struct *work) return; } + if (ath_chanctx_defer_switch(sc)) { + spin_unlock_bh(&sc->chan_lock); + mutex_unlock(&sc->mutex); + return; + } + if (sc->cur_chan != sc->next_chan) { sc->cur_chan->stopped = true; spin_unlock_bh(&sc->chan_lock); + if (sc->next_chan == &sc->offchannel.chan) { + getrawmonotonic(&ts); + measure_time = true; + } __ath9k_flush(sc->hw, ~0, true); if (ath_chanctx_send_ps_frame(sc, true)) @@ -236,13 +269,17 @@ void ath_chanctx_work(struct work_struct *work) sc->cur_chan = sc->next_chan; sc->cur_chan->stopped = false; sc->next_chan = NULL; + sc->sched.state = ATH_CHANCTX_STATE_IDLE; spin_unlock_bh(&sc->chan_lock); if (sc->sc_ah->chip_fullsleep || memcmp(&sc->cur_chandef, &sc->cur_chan->chandef, - sizeof(sc->cur_chandef))) + sizeof(sc->cur_chandef))) { ath_set_channel(sc); - + if (measure_time) + sc->sched.channel_switch_time = + ath9k_hw_get_tsf_offset(&ts, NULL); + } if (send_ps) ath_chanctx_send_ps_frame(sc, false); @@ -335,3 +372,46 @@ void ath_chanctx_offchan_switch(struct ath_softc *sc, ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef); } + +void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, + enum ath_chanctx_event ev) +{ + struct ath_hw *ah = sc->sc_ah; + u32 tsf_time; + + spin_lock_bh(&sc->chan_lock); + + switch (ev) { + case ATH_CHANCTX_EVENT_BEACON_PREPARE: + if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) + break; + + sc->sched.beacon_pending = true; + sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER); + break; + case ATH_CHANCTX_EVENT_BEACON_SENT: + if (!sc->sched.beacon_pending) + break; + + sc->sched.beacon_pending = false; + if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) + break; + + /* defer channel switch by a quarter beacon interval */ + tsf_time = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); + tsf_time = sc->sched.next_tbtt + tsf_time / 4; + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; + ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, + 1000000); + break; + case ATH_CHANCTX_EVENT_TSF_TIMER: + if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_TIMER) + break; + + sc->sched.state = ATH_CHANCTX_STATE_SWITCH; + ieee80211_queue_work(sc->hw, &sc->chanctx_work); + break; + } + + spin_unlock_bh(&sc->chan_lock); +} diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9dfb82077016..2393af058afe 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1047,10 +1047,14 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, ath9k_hw_setopmode(ah); + ctx->switch_after_beacon = false; if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) ah->imask |= ATH9K_INT_TSFOOR; - else + else { ah->imask &= ~ATH9K_INT_TSFOOR; + if (iter_data.naps == 1 && iter_data.beacons) + ctx->switch_after_beacon = true; + } ah->imask &= ~ATH9K_INT_SWBA; if (ah->opmode == NL80211_IFTYPE_STATION) { @@ -1664,6 +1668,9 @@ void ath9k_p2p_ps_timer(void *priv) struct ath_node *an; u32 tsf; + ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer); + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER); + if (!avp || avp->chanctx != sc->cur_chan) return; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 7dd6187761c1..a422c20fe065 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2617,6 +2617,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) sc->beacon.tx_processed = true; sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); + ath_chanctx_event(sc, NULL, + ATH_CHANCTX_EVENT_BEACON_SENT); ath9k_csa_update(sc); continue; } -- cgit v1.2.3 From ea6ff2de5c56f6b0c08717f6cc47281b52504e81 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 11 Jun 2014 16:18:05 +0530 Subject: ath9k: Store current offchannel duration Update current offchannel duration during scan or roc request. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 28 +++++++++++++++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b657115d1eb7..6487c4769af4 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -385,6 +385,7 @@ struct ath_offchannel { struct ieee80211_channel *roc_chan; struct ieee80211_vif *roc_vif; int roc_duration; + int duration; }; #define ath_for_each_chanctx(_sc, _ctx) \ for (ctx = &sc->chanctx[0]; \ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2393af058afe..0ba496d400d0 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2171,6 +2171,17 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) clear_bit(ATH_OP_SCANNING, &common->op_flags); } +static int ath_scan_channel_duration(struct ath_softc *sc, + struct ieee80211_channel *chan) +{ + struct cfg80211_scan_request *req = sc->offchannel.scan_req; + + if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR)) + return (HZ / 9); /* ~110 ms */ + + return (HZ / 16); /* ~60 ms */ +} + static void ath_scan_next_channel(struct ath_softc *sc) { @@ -2185,6 +2196,7 @@ ath_scan_next_channel(struct ath_softc *sc) } chan = req->channels[sc->offchannel.scan_idx++]; + sc->offchannel.duration = ath_scan_channel_duration(sc, chan); sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND; ath_chanctx_offchan_switch(sc, chan); } @@ -2200,6 +2212,7 @@ static void ath_offchannel_next(struct ath_softc *sc) } else if (sc->offchannel.roc_vif) { vif = sc->offchannel.roc_vif; sc->offchannel.chan.txpower = vif->bss_conf.txpower; + sc->offchannel.duration = sc->offchannel.roc_duration; sc->offchannel.state = ATH_OFFCHANNEL_ROC_START; ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan); } else { @@ -2275,20 +2288,17 @@ error: static void ath_scan_channel_start(struct ath_softc *sc) { struct cfg80211_scan_request *req = sc->offchannel.scan_req; - int i, dwell; - - if ((sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) || - !req->n_ssids) { - dwell = HZ / 9; /* ~110 ms */ - } else { - dwell = HZ / 16; /* ~60 ms */ + int i; + if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) && + req->n_ssids) { for (i = 0; i < req->n_ssids; i++) ath_scan_send_probe(sc, &req->ssids[i]); + } sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT; - mod_timer(&sc->offchannel.timer, jiffies + dwell); + mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration); } void ath_offchannel_channel_change(struct ath_softc *sc) @@ -2316,7 +2326,7 @@ void ath_offchannel_channel_change(struct ath_softc *sc) sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT; mod_timer(&sc->offchannel.timer, jiffies + - msecs_to_jiffies(sc->offchannel.roc_duration)); + msecs_to_jiffies(sc->offchannel.duration)); ieee80211_ready_on_channel(sc->hw); break; case ATH_OFFCHANNEL_ROC_DONE: -- cgit v1.2.3 From 3ae07d39ea81440768427e7786c5422f3af38a94 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:18:06 +0530 Subject: ath9k: Add p2p go NoA attribute Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 7 ++++++ drivers/net/wireless/ath/ath9k/beacon.c | 37 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/channel.c | 39 ++++++++++++++++++++++++++++---- drivers/net/wireless/ath/ath9k/init.c | 2 ++ 4 files changed, 80 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 6487c4769af4..02f30980c31a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -362,6 +362,8 @@ struct ath_chanctx_sched { enum ath_chanctx_state state; u32 next_tbtt; + u32 switch_start_time; + unsigned int offchannel_duration; unsigned int channel_switch_time; }; @@ -472,6 +474,11 @@ struct ath_vif { /* P2P Client */ struct ieee80211_noa_data noa; + + /* P2P GO */ + u8 noa_index; + u32 offchannel_start; + u32 offchannel_duration; }; struct ath9k_vif_iter_data { diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 5b1689cf029a..85a40d749e20 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -108,6 +108,40 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, ath9k_hw_set_txdesc(ah, bf->bf_desc, &info); } +static void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, + struct sk_buff *skb) +{ + static const u8 noa_ie_hdr[] = { + WLAN_EID_VENDOR_SPECIFIC, /* type */ + 0, /* length */ + 0x50, 0x6f, 0x9a, /* WFA OUI */ + 0x09, /* P2P subtype */ + 0x0c, /* Notice of Absence */ + 0x00, /* LSB of little-endian len */ + 0x00, /* MSB of little-endian len */ + }; + + struct ieee80211_p2p_noa_attr *noa; + int noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc); + u8 *hdr; + + if (!avp->offchannel_duration) + return; + + hdr = skb_put(skb, sizeof(noa_ie_hdr)); + memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr)); + hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2; + hdr[7] = noa_len; + + noa = (void *) skb_put(skb, noa_len); + memset(noa, 0, noa_len); + + noa->index = avp->noa_index; + noa->desc[0].count = 1; + noa->desc[0].duration = cpu_to_le32(avp->offchannel_duration); + noa->desc[0].start_time = cpu_to_le32(avp->offchannel_start); +} + static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -155,6 +189,9 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); } + if (vif->p2p) + ath9k_beacon_add_noa(sc, avp, skb); + bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, skb->len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 503b7766e12e..364a55502b7d 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -270,6 +270,8 @@ void ath_chanctx_work(struct work_struct *work) sc->cur_chan->stopped = false; sc->next_chan = NULL; sc->sched.state = ATH_CHANCTX_STATE_IDLE; + sc->sched.offchannel_duration = 0; + spin_unlock_bh(&sc->chan_lock); if (sc->sc_ah->chip_fullsleep || @@ -326,6 +328,12 @@ void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, sc->next_chan = ctx; if (chandef) ctx->chandef = *chandef; + + if (sc->next_chan == &sc->offchannel.chan) { + sc->sched.offchannel_duration = + TU_TO_USEC(sc->offchannel.duration) + + sc->sched.channel_switch_time; + } spin_unlock_bh(&sc->chan_lock); ieee80211_queue_work(sc->hw, &sc->chanctx_work); } @@ -377,17 +385,40 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, enum ath_chanctx_event ev) { struct ath_hw *ah = sc->sc_ah; + struct ath_vif *avp = NULL; u32 tsf_time; + bool noa_changed = false; + + if (vif) + avp = (struct ath_vif *) vif->drv_priv; spin_lock_bh(&sc->chan_lock); switch (ev) { case ATH_CHANCTX_EVENT_BEACON_PREPARE: + if (avp->offchannel_duration) + avp->offchannel_duration = 0; + if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) break; sc->sched.beacon_pending = true; sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER); + + /* defer channel switch by a quarter beacon interval */ + tsf_time = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); + tsf_time = sc->sched.next_tbtt + tsf_time / 4; + sc->sched.switch_start_time = tsf_time; + + if (sc->sched.offchannel_duration) { + noa_changed = true; + avp->offchannel_start = tsf_time; + avp->offchannel_duration = + sc->sched.offchannel_duration; + } + + if (noa_changed) + avp->noa_index++; break; case ATH_CHANCTX_EVENT_BEACON_SENT: if (!sc->sched.beacon_pending) @@ -397,12 +428,10 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) break; - /* defer channel switch by a quarter beacon interval */ - tsf_time = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); - tsf_time = sc->sched.next_tbtt + tsf_time / 4; sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; - ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, - 1000000); + ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, + sc->sched.switch_start_time, + 1000000); break; case ATH_CHANCTX_EVENT_TSF_TIMER: if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_TIMER) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 1ff1a75f4fed..66a9dc3a5369 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -754,6 +754,8 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; hw->wiphy->max_remain_on_channel_duration = 10000; hw->chanctx_data_size = sizeof(void *); + hw->extra_beacon_tailroom = + sizeof(struct ieee80211_p2p_noa_attr) + 9; } } -- cgit v1.2.3 From 8eab25108e374403f759dd7de01084a1f3ba6d68 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:18:07 +0530 Subject: ath9k: switch channel after sending beacon Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/channel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 364a55502b7d..4793de079f77 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -365,7 +365,8 @@ struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active) if (active && !ctx->active) continue; - return ctx; + if (ctx->switch_after_beacon) + return ctx; } return &sc->chanctx[0]; -- cgit v1.2.3 From 58b57375285223badddebdf8d905a864c271b87d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:18:08 +0530 Subject: ath9k: Adjust AP beacon tsf based on station context In multi channel context (AP + STA case), adjust the TSF time of the AP chanctx to keep its beacons at half beacon interval offset relative to the STA chanctx. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 ++ drivers/net/wireless/ath/ath9k/channel.c | 48 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/recv.c | 5 ++++ 3 files changed, 55 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 02f30980c31a..a4646a076099 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -335,6 +335,7 @@ struct ath_chanctx { struct ath9k_hw_cal_data caldata; struct timespec tsf_ts; u64 tsf_val; + u32 last_beacon; u16 txpower; bool offchannel; @@ -348,6 +349,7 @@ enum ath_chanctx_event { ATH_CHANCTX_EVENT_BEACON_PREPARE, ATH_CHANCTX_EVENT_BEACON_SENT, ATH_CHANCTX_EVENT_TSF_TIMER, + ATH_CHANCTX_EVENT_BEACON_RECEIVED, }; enum ath_chanctx_state { diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 4793de079f77..6ea806cc68fe 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -382,10 +382,51 @@ void ath_chanctx_offchan_switch(struct ath_softc *sc, ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef); } +static struct ath_chanctx * +ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx) +{ + int idx = ctx - &sc->chanctx[0]; + + return &sc->chanctx[!idx]; +} + +static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc) +{ + struct ath_chanctx *prev, *cur; + struct timespec ts; + u32 cur_tsf, prev_tsf, beacon_int; + s32 offset; + + beacon_int = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); + + cur = sc->cur_chan; + prev = ath_chanctx_get_next(sc, cur); + + getrawmonotonic(&ts); + cur_tsf = (u32) cur->tsf_val + + ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts); + + prev_tsf = prev->last_beacon - (u32) prev->tsf_val + cur_tsf; + prev_tsf -= ath9k_hw_get_tsf_offset(&prev->tsf_ts, &ts); + + /* Adjust the TSF time of the AP chanctx to keep its beacons + * at half beacon interval offset relative to the STA chanctx. + */ + offset = cur_tsf - prev_tsf; + + /* Ignore stale data or spurious timestamps */ + if (offset < 0 || offset > 3 * beacon_int) + return; + + offset = beacon_int / 2 - (offset % beacon_int); + prev->tsf_val += offset; +} + void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, enum ath_chanctx_event ev) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = NULL; u32 tsf_time; bool noa_changed = false; @@ -410,6 +451,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, tsf_time = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); tsf_time = sc->sched.next_tbtt + tsf_time / 4; sc->sched.switch_start_time = tsf_time; + sc->cur_chan->last_beacon = sc->sched.next_tbtt; if (sc->sched.offchannel_duration) { noa_changed = true; @@ -441,6 +483,12 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, sc->sched.state = ATH_CHANCTX_STATE_SWITCH; ieee80211_queue_work(sc->hw, &sc->chanctx_work); break; + case ATH_CHANCTX_EVENT_BEACON_RECEIVED: + if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) + break; + + ath_chanctx_adjust_tbtt_delta(sc); + break; } spin_unlock_bh(&sc->chan_lock); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 7b9c7e53caaa..74ab1d02013b 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -892,6 +892,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, return -EINVAL; } + if (rx_stats->is_mybeacon) { + sc->sched.next_tbtt = rx_stats->rs_tstamp; + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_BEACON_RECEIVED); + } + ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); rx_status->band = ah->curchan->chan->band; -- cgit v1.2.3 From 6036c2845650d26a15b44498f8fb8f8f4518847a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:18:09 +0530 Subject: ath9k: Implement mgd_prepare_tx Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 ++ drivers/net/wireless/ath/ath9k/channel.c | 50 +++++++++++++++++++++++++++----- drivers/net/wireless/ath/ath9k/main.c | 1 + 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a4646a076099..7947909918bd 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -357,6 +357,7 @@ enum ath_chanctx_state { ATH_CHANCTX_STATE_WAIT_FOR_BEACON, ATH_CHANCTX_STATE_WAIT_FOR_TIMER, ATH_CHANCTX_STATE_SWITCH, + ATH_CHANCTX_STATE_FORCE_ACTIVE, }; struct ath_chanctx_sched { @@ -397,6 +398,8 @@ struct ath_offchannel { ctx++) void ath9k_fill_chanctx_ops(void); +void ath9k_chanctx_force_active(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); static inline struct ath_chanctx * ath_chanctx_get(struct ieee80211_chanctx_conf *ctx) { diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 6ea806cc68fe..8d56b7961d7b 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -223,25 +223,20 @@ static bool ath_chanctx_defer_switch(struct ath_softc *sc) return true; } -void ath_chanctx_work(struct work_struct *work) +static void ath_chanctx_set_next(struct ath_softc *sc, bool force) { - struct ath_softc *sc = container_of(work, struct ath_softc, - chanctx_work); struct timespec ts; bool measure_time = false; bool send_ps = false; - mutex_lock(&sc->mutex); spin_lock_bh(&sc->chan_lock); if (!sc->next_chan) { spin_unlock_bh(&sc->chan_lock); - mutex_unlock(&sc->mutex); return; } - if (ath_chanctx_defer_switch(sc)) { + if (!force && ath_chanctx_defer_switch(sc)) { spin_unlock_bh(&sc->chan_lock); - mutex_unlock(&sc->mutex); return; } @@ -269,8 +264,9 @@ void ath_chanctx_work(struct work_struct *work) sc->cur_chan = sc->next_chan; sc->cur_chan->stopped = false; sc->next_chan = NULL; - sc->sched.state = ATH_CHANCTX_STATE_IDLE; sc->sched.offchannel_duration = 0; + if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE) + sc->sched.state = ATH_CHANCTX_STATE_IDLE; spin_unlock_bh(&sc->chan_lock); @@ -286,6 +282,14 @@ void ath_chanctx_work(struct work_struct *work) ath_chanctx_send_ps_frame(sc, false); ath_offchannel_channel_change(sc); +} + +void ath_chanctx_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + chanctx_work); + mutex_lock(&sc->mutex); + ath_chanctx_set_next(sc, false); mutex_unlock(&sc->mutex); } @@ -320,6 +324,36 @@ void ath_chanctx_init(struct ath_softc *sc) } +void ath9k_chanctx_force_active(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp = (struct ath_vif *) vif->drv_priv; + bool changed = false; + + if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) + return; + + if (!avp->chanctx) + return; + + mutex_lock(&sc->mutex); + + spin_lock_bh(&sc->chan_lock); + if (sc->next_chan || (sc->cur_chan != avp->chanctx)) { + sc->next_chan = avp->chanctx; + changed = true; + } + sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE; + spin_unlock_bh(&sc->chan_lock); + + if (changed) + ath_chanctx_set_next(sc, true); + + mutex_unlock(&sc->mutex); +} + void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef) { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 0ba496d400d0..b8975f0700bf 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2553,6 +2553,7 @@ void ath9k_fill_chanctx_ops(void) ath9k_ops.change_chanctx = ath9k_change_chanctx; ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx; ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx; + ath9k_ops.mgd_prepare_tx = ath9k_chanctx_force_active; } struct ieee80211_ops ath9k_ops = { -- cgit v1.2.3 From 73fa2f26d35a37034fdff9fd702887909e138926 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:18:10 +0530 Subject: ath9k: Add multi-channel scheduling support Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 5 ++ drivers/net/wireless/ath/ath9k/channel.c | 95 ++++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath9k/main.c | 3 + 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7947909918bd..0bc63bd4ec26 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -350,6 +350,10 @@ enum ath_chanctx_event { ATH_CHANCTX_EVENT_BEACON_SENT, ATH_CHANCTX_EVENT_TSF_TIMER, ATH_CHANCTX_EVENT_BEACON_RECEIVED, + ATH_CHANCTX_EVENT_ASSOC, + ATH_CHANCTX_EVENT_SWITCH, + ATH_CHANCTX_EVENT_UNASSIGN, + ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL, }; enum ath_chanctx_state { @@ -362,6 +366,7 @@ enum ath_chanctx_state { struct ath_chanctx_sched { bool beacon_pending; + bool offchannel_pending; enum ath_chanctx_state state; u32 next_tbtt; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 8d56b7961d7b..1cb2909a114c 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -180,10 +180,13 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) n_active++; } - if (n_active > 1) - set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags); - else + if (n_active <= 1) { clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags); + return; + } + if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) + return; + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL); } static bool @@ -282,6 +285,7 @@ static void ath_chanctx_set_next(struct ath_softc *sc, bool force) ath_chanctx_send_ps_frame(sc, false); ath_offchannel_channel_change(sc); + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH); } void ath_chanctx_work(struct work_struct *work) @@ -357,8 +361,17 @@ void ath9k_chanctx_force_active(struct ieee80211_hw *hw, void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, struct cfg80211_chan_def *chandef) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); spin_lock_bh(&sc->chan_lock); + + if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) && + (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) { + sc->sched.offchannel_pending = true; + spin_unlock_bh(&sc->chan_lock); + return; + } + sc->next_chan = ctx; if (chandef) ctx->chandef = *chandef; @@ -462,6 +475,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = NULL; + struct ath_chanctx *ctx; u32 tsf_time; bool noa_changed = false; @@ -475,6 +489,25 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, if (avp->offchannel_duration) avp->offchannel_duration = 0; + if (avp->chanctx != sc->cur_chan) + break; + + if (sc->sched.offchannel_pending) { + sc->sched.offchannel_pending = false; + sc->next_chan = &sc->offchannel.chan; + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + } + + ctx = ath_chanctx_get_next(sc, sc->cur_chan); + if (ctx->active && sc->sched.state == ATH_CHANCTX_STATE_IDLE) { + sc->next_chan = ctx; + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + } + + /* if the timer missed its window, use the next interval */ + if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER) + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) break; @@ -518,11 +551,65 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ieee80211_queue_work(sc->hw, &sc->chanctx_work); break; case ATH_CHANCTX_EVENT_BEACON_RECEIVED: - if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) + if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) || + sc->cur_chan == &sc->offchannel.chan) break; ath_chanctx_adjust_tbtt_delta(sc); break; + case ATH_CHANCTX_EVENT_ASSOC: + if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE || + avp->chanctx != sc->cur_chan) + break; + + sc->sched.state = ATH_CHANCTX_STATE_IDLE; + /* fall through */ + case ATH_CHANCTX_EVENT_SWITCH: + if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) || + sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE || + sc->cur_chan->switch_after_beacon || + sc->cur_chan == &sc->offchannel.chan) + break; + + /* If this is a station chanctx, stay active for a half + * beacon period (minus channel switch time) + */ + sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan); + + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; + tsf_time = ath9k_hw_gettsf32(sc->sc_ah); + tsf_time += + TU_TO_USEC(sc->cur_chan->beacon.beacon_interval) / 2; + tsf_time -= sc->sched.channel_switch_time; + sc->sched.switch_start_time = tsf_time; + + ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, + tsf_time, 1000000); + break; + case ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL: + if (sc->cur_chan == &sc->offchannel.chan || + sc->cur_chan->switch_after_beacon) + break; + + sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan); + ieee80211_queue_work(sc->hw, &sc->chanctx_work); + break; + case ATH_CHANCTX_EVENT_UNASSIGN: + if (sc->cur_chan->assigned) { + if (sc->next_chan && !sc->next_chan->assigned && + sc->next_chan != &sc->offchannel.chan) + sc->sched.state = ATH_CHANCTX_STATE_IDLE; + break; + } + + ctx = ath_chanctx_get_next(sc, sc->cur_chan); + sc->sched.state = ATH_CHANCTX_STATE_IDLE; + if (!ctx->assigned) + break; + + sc->next_chan = ctx; + ieee80211_queue_work(sc->hw, &sc->chanctx_work); + break; } spin_unlock_bh(&sc->chan_lock); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b8975f0700bf..f7d8ddae216e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1747,6 +1747,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, bss_conf->bssid, bss_conf->assoc); ath9k_calculate_summary_state(sc, avp->chanctx); + if (bss_conf->assoc) + ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_ASSOC); } if (changed & BSS_CHANGED_IBSS) { @@ -2492,6 +2494,7 @@ static void ath9k_remove_chanctx(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); ctx->assigned = false; + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN); mutex_unlock(&sc->mutex); } -- cgit v1.2.3 From 7414863ed3dfa407006c92616c1e0efda481738c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:18:11 +0530 Subject: ath9k: Add periodic NoA support Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 +++ drivers/net/wireless/ath/ath9k/beacon.c | 25 ++++++++++++++++++++----- drivers/net/wireless/ath/ath9k/channel.c | 24 +++++++++++++++++++++--- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0bc63bd4ec26..a5afd4a7df9f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -489,6 +489,9 @@ struct ath_vif { u8 noa_index; u32 offchannel_start; u32 offchannel_duration; + + u32 periodic_noa_start; + u32 periodic_noa_duration; }; struct ath9k_vif_iter_data { diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 85a40d749e20..eaf8f058c151 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -122,12 +122,15 @@ static void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, }; struct ieee80211_p2p_noa_attr *noa; - int noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc); + int noa_len, noa_desc, i = 0; u8 *hdr; - if (!avp->offchannel_duration) + if (!avp->offchannel_duration && !avp->periodic_noa_duration) return; + noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration; + noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc; + hdr = skb_put(skb, sizeof(noa_ie_hdr)); memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr)); hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2; @@ -137,9 +140,21 @@ static void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, memset(noa, 0, noa_len); noa->index = avp->noa_index; - noa->desc[0].count = 1; - noa->desc[0].duration = cpu_to_le32(avp->offchannel_duration); - noa->desc[0].start_time = cpu_to_le32(avp->offchannel_start); + if (avp->periodic_noa_duration) { + u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); + + noa->desc[i].count = 255; + noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start); + noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration); + noa->desc[i].interval = cpu_to_le32(interval); + i++; + } + + if (avp->offchannel_duration) { + noa->desc[i].count = 1; + noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start); + noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration); + } } static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 1cb2909a114c..3d9776c4c909 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -474,6 +474,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + struct ath_beacon_config *cur_conf; struct ath_vif *avp = NULL; struct ath_chanctx *ctx; u32 tsf_time; @@ -514,12 +515,29 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, sc->sched.beacon_pending = true; sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER); + cur_conf = &sc->cur_chan->beacon; /* defer channel switch by a quarter beacon interval */ - tsf_time = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); + tsf_time = TU_TO_USEC(cur_conf->beacon_interval); tsf_time = sc->sched.next_tbtt + tsf_time / 4; sc->sched.switch_start_time = tsf_time; sc->cur_chan->last_beacon = sc->sched.next_tbtt; + /* Prevent wrap-around issues */ + if (avp->periodic_noa_duration && + tsf_time - avp->periodic_noa_start > BIT(30)) + avp->periodic_noa_duration = 0; + + if (ctx->active && !avp->periodic_noa_duration) { + avp->periodic_noa_start = tsf_time; + avp->periodic_noa_duration = + TU_TO_USEC(cur_conf->beacon_interval) / 2 - + sc->sched.channel_switch_time; + noa_changed = true; + } else if (!ctx->active && avp->periodic_noa_duration) { + avp->periodic_noa_duration = 0; + noa_changed = true; + } + if (sc->sched.offchannel_duration) { noa_changed = true; avp->offchannel_start = tsf_time; @@ -575,11 +593,11 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, * beacon period (minus channel switch time) */ sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan); + cur_conf = &sc->cur_chan->beacon; sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; tsf_time = ath9k_hw_gettsf32(sc->sc_ah); - tsf_time += - TU_TO_USEC(sc->cur_chan->beacon.beacon_interval) / 2; + tsf_time += TU_TO_USEC(cur_conf->beacon_interval) / 2; tsf_time -= sc->sched.channel_switch_time; sc->sched.switch_start_time = tsf_time; -- cgit v1.2.3 From ec70abe1f62099f8cdd5453e20098e15435706bd Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:18:12 +0530 Subject: ath9k: Handle beacon miss on multi channel context Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/channel.c | 30 ++++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a5afd4a7df9f..ee00ddb8885d 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -368,6 +368,7 @@ struct ath_chanctx_sched { bool beacon_pending; bool offchannel_pending; enum ath_chanctx_state state; + u8 beacon_miss; u32 next_tbtt; u32 switch_start_time; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 3d9776c4c909..55165d5a7ed1 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -478,6 +478,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, struct ath_vif *avp = NULL; struct ath_chanctx *ctx; u32 tsf_time; + u32 beacon_int; bool noa_changed = false; if (vif) @@ -516,9 +517,10 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER); cur_conf = &sc->cur_chan->beacon; + beacon_int = TU_TO_USEC(cur_conf->beacon_interval); + /* defer channel switch by a quarter beacon interval */ - tsf_time = TU_TO_USEC(cur_conf->beacon_interval); - tsf_time = sc->sched.next_tbtt + tsf_time / 4; + tsf_time = sc->sched.next_tbtt + beacon_int / 4; sc->sched.switch_start_time = tsf_time; sc->cur_chan->last_beacon = sc->sched.next_tbtt; @@ -538,6 +540,13 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, noa_changed = true; } + /* If at least two consecutive beacons were missed on the STA + * chanctx, stay on the STA channel for one extra beacon period, + * to resync the timer properly. + */ + if (ctx->active && sc->sched.beacon_miss >= 2) + sc->sched.offchannel_duration = 3 * beacon_int / 2; + if (sc->sched.offchannel_duration) { noa_changed = true; avp->offchannel_start = tsf_time; @@ -565,6 +574,10 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_TIMER) break; + if (!sc->cur_chan->switch_after_beacon && + sc->sched.beacon_pending) + sc->sched.beacon_miss++; + sc->sched.state = ATH_CHANCTX_STATE_SWITCH; ieee80211_queue_work(sc->hw, &sc->chanctx_work); break; @@ -574,6 +587,8 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, break; ath_chanctx_adjust_tbtt_delta(sc); + sc->sched.beacon_pending = false; + sc->sched.beacon_miss = 0; break; case ATH_CHANCTX_EVENT_ASSOC: if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE || @@ -596,13 +611,20 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, cur_conf = &sc->cur_chan->beacon; sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; - tsf_time = ath9k_hw_gettsf32(sc->sc_ah); - tsf_time += TU_TO_USEC(cur_conf->beacon_interval) / 2; + + tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2; + if (sc->sched.beacon_miss >= 2) { + sc->sched.beacon_miss = 0; + tsf_time *= 3; + } + tsf_time -= sc->sched.channel_switch_time; + tsf_time += ath9k_hw_gettsf32(sc->sc_ah); sc->sched.switch_start_time = tsf_time; ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000); + sc->sched.beacon_pending = true; break; case ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL: if (sc->cur_chan == &sc->offchannel.chan || -- cgit v1.2.3 From a899b678d92fcd25215192dae26913cdb8a9b96d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:18:13 +0530 Subject: ath9k: Update channel switch timer TSF time might have been updated by the incoming beacon, need update the channel switch timer to reflect the change. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/channel.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 55165d5a7ed1..0a38eea27870 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -589,6 +589,17 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ath_chanctx_adjust_tbtt_delta(sc); sc->sched.beacon_pending = false; sc->sched.beacon_miss = 0; + + /* TSF time might have been updated by the incoming beacon, + * need update the channel switch timer to reflect the change. + */ + tsf_time = sc->sched.switch_start_time; + tsf_time -= (u32) sc->cur_chan->tsf_val + + ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL); + tsf_time += ath9k_hw_gettsf32(ah); + + ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, + tsf_time, 1000000); break; case ATH_CHANCTX_EVENT_ASSOC: if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE || -- cgit v1.2.3 From 42eda11558559104c09f0d0924bbb210edfcf487 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 11 Jun 2014 16:18:14 +0530 Subject: ath9k: Add recovery mechanism for hw TSF timer Configure the TSF based hardware timer for a channel switch. Also set up backup software timer, in case the gen timer fails. This could be caused by a hardware reset. Signed-off-by: Felix Fietkau Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++++ drivers/net/wireless/ath/ath9k/channel.c | 32 +++++++++++++++++++++++++------- drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/main.c | 1 + 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index ee00ddb8885d..757dd602daaa 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -374,6 +374,9 @@ struct ath_chanctx_sched { u32 switch_start_time; unsigned int offchannel_duration; unsigned int channel_switch_time; + + /* backup, in case the hardware timer fails */ + struct timer_list timer; }; enum ath_offchannel_state { @@ -426,6 +429,7 @@ struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active); void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, enum ath_chanctx_event ev); +void ath_chanctx_timer(unsigned long data); int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); int ath_startrecv(struct ath_softc *sc); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 0a38eea27870..ba214ebdcd16 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -469,6 +469,27 @@ static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc) prev->tsf_val += offset; } +void ath_chanctx_timer(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *) data; + + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER); +} + +/* Configure the TSF based hardware timer for a channel switch. + * Also set up backup software timer, in case the gen timer fails. + * This could be caused by a hardware reset. + */ +static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time) +{ + struct ath_hw *ah = sc->sc_ah; + + ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000); + tsf_time -= ath9k_hw_gettsf32(ah); + tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1; + mod_timer(&sc->sched.timer, tsf_time); +} + void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, enum ath_chanctx_event ev) { @@ -566,9 +587,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, break; sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; - ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, - sc->sched.switch_start_time, - 1000000); + ath_chanctx_setup_timer(sc, sc->sched.switch_start_time); break; case ATH_CHANCTX_EVENT_TSF_TIMER: if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_TIMER) @@ -598,8 +617,8 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL); tsf_time += ath9k_hw_gettsf32(ah); - ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, - tsf_time, 1000000); + + ath_chanctx_setup_timer(sc, tsf_time); break; case ATH_CHANCTX_EVENT_ASSOC: if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE || @@ -633,8 +652,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, tsf_time += ath9k_hw_gettsf32(sc->sc_ah); sc->sched.switch_start_time = tsf_time; - ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, - tsf_time, 1000000); + ath_chanctx_setup_timer(sc, tsf_time); sc->sched.beacon_pending = true; break; case ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL: diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 66a9dc3a5369..a4afcb19af2a 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -569,6 +569,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); setup_timer(&sc->offchannel.timer, ath_offchannel_timer, (unsigned long)sc); + setup_timer(&sc->sched.timer, ath_chanctx_timer, (unsigned long)sc); /* * Cache line size is used to size and align various diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index f7d8ddae216e..b307e6e2c0be 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1668,6 +1668,7 @@ void ath9k_p2p_ps_timer(void *priv) struct ath_node *an; u32 tsf; + del_timer_sync(&sc->sched.timer); ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer); ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER); -- cgit v1.2.3 From 3ad9c3861acef2343b232d733aa288e71cc07d44 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 11 Jun 2014 16:18:15 +0530 Subject: ath9k: use separate HW queue for each channel context Use seperate tx queue for each AC in each channel context and expose these information to mac80211 to avoid stopping one channel context leads to stopping the entire traffic for that AC even on other contexts. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 10 ++++++- drivers/net/wireless/ath/ath9k/main.c | 48 ++++++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath9k/xmit.c | 11 +++++--- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 757dd602daaa..11b5e4dd6294 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -327,6 +327,7 @@ struct ath_chanctx { struct cfg80211_chan_def chandef; struct list_head vifs; struct list_head acq[IEEE80211_NUM_ACS]; + int hw_queue_base; /* do not dereference, use for comparison only */ struct ieee80211_vif *primary_sta; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index a4afcb19af2a..7afb40572ed0 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -511,6 +511,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, sc->tx99_power = MAX_RATE_POWER + 1; init_waitqueue_head(&sc->tx_wait); sc->cur_chan = &sc->chanctx[0]; + if (!ath9k_use_chanctx) + sc->cur_chan->hw_queue_base = 0; if (!pdata || pdata->use_eeprom) { ah->ah_flags |= AH_USE_EEPROM; @@ -718,6 +720,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_RC_TABLE | + IEEE80211_HW_QUEUE_CONTROL | IEEE80211_HW_SUPPORTS_HT_CCK_RATES; if (ath9k_ps_enable) @@ -769,7 +772,12 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; - hw->queues = 4; + /* allow 4 queues per channel context + + * 1 cab queue + 1 offchannel tx queue + */ + hw->queues = 10; + /* last queue for offchannel */ + hw->offchannel_tx_hw_queue = hw->queues - 1; hw->max_rates = 4; hw->max_listen_interval = 1; hw->max_rate_tries = 10; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b307e6e2c0be..cf21652835c1 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -223,6 +223,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); unsigned long flags; + int i; if (ath_startrecv(sc) != 0) { ath_err(common, "Unable to restart recv logic\n"); @@ -267,7 +268,20 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); - ieee80211_wake_queues(sc->hw); + if (!ath9k_use_chanctx) + ieee80211_wake_queues(sc->hw); + else { + if (sc->cur_chan == &sc->offchannel.chan) + ieee80211_wake_queue(sc->hw, + sc->hw->offchannel_tx_hw_queue); + else { + for (i = 0; i < IEEE80211_NUM_ACS; i++) + ieee80211_wake_queue(sc->hw, + sc->cur_chan->hw_queue_base + i); + } + if (ah->opmode == NL80211_IFTYPE_AP) + ieee80211_wake_queue(sc->hw, sc->hw->queues - 2); + } ath9k_p2p_ps_timer(sc); @@ -1108,6 +1122,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; struct ath_node *an = &avp->mcast_node; + int i; mutex_lock(&sc->mutex); @@ -1130,6 +1145,12 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, avp->chanctx = sc->cur_chan; list_add_tail(&avp->list, &avp->chanctx->vifs); } + for (i = 0; i < IEEE80211_NUM_ACS; i++) + vif->hw_queue[i] = i; + if (vif->type == NL80211_IFTYPE_AP) + vif->cab_queue = hw->queues - 2; + else + vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; an->sc = sc; an->sta = NULL; @@ -1149,6 +1170,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp = (void *)vif->drv_priv; + int i; mutex_lock(&sc->mutex); @@ -1168,6 +1190,14 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); + for (i = 0; i < IEEE80211_NUM_ACS; i++) + vif->hw_queue[i] = i; + + if (vif->type == NL80211_IFTYPE_AP) + vif->cab_queue = hw->queues - 2; + else + vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; + ath9k_calculate_summary_state(sc, avp->chanctx); mutex_unlock(&sc->mutex); @@ -1984,6 +2014,7 @@ void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) struct ath_common *common = ath9k_hw_common(ah); int timeout = HZ / 5; /* 200 ms */ bool drain_txq; + int i; cancel_delayed_work_sync(&sc->tx_complete_work); @@ -2011,7 +2042,10 @@ void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) ath_reset(sc); ath9k_ps_restore(sc); - ieee80211_wake_queues(hw); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + ieee80211_wake_queue(sc->hw, + sc->cur_chan->hw_queue_base + i); + } } ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); @@ -2468,6 +2502,7 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_chanctx *ctx, **ptr; + int pos; mutex_lock(&sc->mutex); @@ -2478,6 +2513,8 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw, ptr = (void *) conf->drv_priv; *ptr = ctx; ctx->assigned = true; + pos = ctx - &sc->chanctx[0]; + ctx->hw_queue_base = pos * IEEE80211_NUM_ACS; ath_chanctx_set_channel(sc, ctx, &conf->def); mutex_unlock(&sc->mutex); return 0; @@ -2495,6 +2532,7 @@ static void ath9k_remove_chanctx(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); ctx->assigned = false; + ctx->hw_queue_base = -1; ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN); mutex_unlock(&sc->mutex); } @@ -2518,11 +2556,14 @@ static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_vif *avp = (void *)vif->drv_priv; struct ath_chanctx *ctx = ath_chanctx_get(conf); + int i; mutex_lock(&sc->mutex); avp->chanctx = ctx; list_add_tail(&avp->list, &ctx->vifs); ath9k_calculate_summary_state(sc, ctx); + for (i = 0; i < IEEE80211_NUM_ACS; i++) + vif->hw_queue[i] = ctx->hw_queue_base + i; mutex_unlock(&sc->mutex); return 0; @@ -2535,11 +2576,14 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_vif *avp = (void *)vif->drv_priv; struct ath_chanctx *ctx = ath_chanctx_get(conf); + int ac; mutex_lock(&sc->mutex); avp->chanctx = NULL; list_del(&avp->list); ath9k_calculate_summary_state(sc, ctx); + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) + vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE; mutex_unlock(&sc->mutex); } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a422c20fe065..d4927c9a6bae 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -156,7 +156,8 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, struct sk_buff *skb) { - int q; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int q, hw_queue; q = skb_get_queue_mapping(skb); if (txq == sc->tx.uapsdq) @@ -168,9 +169,10 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, if (WARN_ON(--txq->pending_frames < 0)) txq->pending_frames = 0; + hw_queue = (info->hw_queue >= sc->hw->queues - 2) ? q : info->hw_queue; if (txq->stopped && txq->pending_frames < sc->tx.txq_max_pending[q]) { - ieee80211_wake_queue(sc->hw, q); + ieee80211_wake_queue(sc->hw, hw_queue); txq->stopped = false; } } @@ -2191,7 +2193,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_atx_tid *tid = NULL; struct ath_buf *bf; bool queue; - int q; + int q, hw_queue; int ret; if (vif) @@ -2211,12 +2213,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, */ q = skb_get_queue_mapping(skb); + hw_queue = (info->hw_queue >= sc->hw->queues - 2) ? q : info->hw_queue; ath_txq_lock(sc, txq); if (txq == sc->tx.txq_map[q] && ++txq->pending_frames > sc->tx.txq_max_pending[q] && !txq->stopped) { - ieee80211_stop_queue(sc->hw, q); + ieee80211_stop_queue(sc->hw, hw_queue); txq->stopped = true; } -- cgit v1.2.3 From a4068323d5775877e89d87fc2fdaebd6e9e6a33c Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 11 Jun 2014 16:18:16 +0530 Subject: ath9k: Advertise multichannel support Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 7afb40572ed0..79fdab6a4003 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -672,6 +672,12 @@ static const struct ieee80211_iface_limit wds_limits[] = { { .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) }, }; +static const struct ieee80211_iface_limit if_limits_multi[] = { + { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) }, +}; + static const struct ieee80211_iface_limit if_dfs_limits[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_AP) | #ifdef CONFIG_MAC80211_MESH @@ -680,6 +686,16 @@ static const struct ieee80211_iface_limit if_dfs_limits[] = { BIT(NL80211_IFTYPE_ADHOC) }, }; +static const struct ieee80211_iface_combination if_comb_multi[] = { + { + .limits = if_limits_multi, + .n_limits = ARRAY_SIZE(if_limits_multi), + .max_interfaces = 2, + .num_different_channels = 2, + .beacon_int_infra_match = true, + }, +}; + static const struct ieee80211_iface_combination if_comb[] = { { .limits = if_limits, @@ -748,12 +764,14 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); - hw->wiphy->iface_combinations = if_comb; if (!ath9k_use_chanctx) { + hw->wiphy->iface_combinations = if_comb; hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS); } else { - hw->wiphy->n_iface_combinations = 1; + hw->wiphy->iface_combinations = if_comb_multi; + hw->wiphy->n_iface_combinations = + ARRAY_SIZE(if_comb_multi); hw->wiphy->max_scan_ssids = 255; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; hw->wiphy->max_remain_on_channel_duration = 10000; -- cgit v1.2.3 From df6e6333237dd1e55571e1e8c61354ae51b26d82 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 15 Jun 2014 13:37:43 -0700 Subject: rt2x00: Use dma_zalloc_coherent Use the zeroing function instead of dma_alloc_coherent & memset(,0,) Signed-off-by: Joe Perches Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mmio.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00mmio.c b/drivers/net/wireless/rt2x00/rt2x00mmio.c index 6f236ea180aa..f0178fd4fe5f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mmio.c +++ b/drivers/net/wireless/rt2x00/rt2x00mmio.c @@ -119,14 +119,12 @@ static int rt2x00mmio_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, /* * Allocate DMA memory for descriptor and buffer. */ - addr = dma_alloc_coherent(rt2x00dev->dev, - queue->limit * queue->desc_size, - &dma, GFP_KERNEL); + addr = dma_zalloc_coherent(rt2x00dev->dev, + queue->limit * queue->desc_size, &dma, + GFP_KERNEL); if (!addr) return -ENOMEM; - memset(addr, 0, queue->limit * queue->desc_size); - /* * Initialize all queue entries to contain valid addresses. */ -- cgit v1.2.3 From 51b4a86abd088431e09a01fd335ad385a3ddfe21 Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:39:40 +0530 Subject: rsi: Mapping the debugfs stats to the correct s/w queues. Changed the queue numbers to macros, and corrected the mappings. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_debugfs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_debugfs.c b/drivers/net/wireless/rsi/rsi_91x_debugfs.c index c466246a323f..828a042f903f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_debugfs.c +++ b/drivers/net/wireless/rsi/rsi_91x_debugfs.c @@ -145,7 +145,7 @@ static int rsi_stats_read(struct seq_file *seq, void *data) seq_printf(seq, "total_mgmt_pkt_send : %d\n", common->tx_stats.total_tx_pkt_send[MGMT_SOFT_Q]); seq_printf(seq, "total_mgmt_pkt_queued : %d\n", - skb_queue_len(&common->tx_queue[4])); + skb_queue_len(&common->tx_queue[MGMT_SOFT_Q])); seq_printf(seq, "total_mgmt_pkt_freed : %d\n", common->tx_stats.total_tx_pkt_freed[MGMT_SOFT_Q]); @@ -153,25 +153,25 @@ static int rsi_stats_read(struct seq_file *seq, void *data) seq_printf(seq, "total_data_vo_pkt_send: %8d\t", common->tx_stats.total_tx_pkt_send[VO_Q]); seq_printf(seq, "total_data_vo_pkt_queued: %8d\t", - skb_queue_len(&common->tx_queue[0])); + skb_queue_len(&common->tx_queue[VO_Q])); seq_printf(seq, "total_vo_pkt_freed: %8d\n", common->tx_stats.total_tx_pkt_freed[VO_Q]); seq_printf(seq, "total_data_vi_pkt_send: %8d\t", common->tx_stats.total_tx_pkt_send[VI_Q]); seq_printf(seq, "total_data_vi_pkt_queued: %8d\t", - skb_queue_len(&common->tx_queue[1])); + skb_queue_len(&common->tx_queue[VI_Q])); seq_printf(seq, "total_vi_pkt_freed: %8d\n", common->tx_stats.total_tx_pkt_freed[VI_Q]); seq_printf(seq, "total_data_be_pkt_send: %8d\t", common->tx_stats.total_tx_pkt_send[BE_Q]); seq_printf(seq, "total_data_be_pkt_queued: %8d\t", - skb_queue_len(&common->tx_queue[2])); + skb_queue_len(&common->tx_queue[BE_Q])); seq_printf(seq, "total_be_pkt_freed: %8d\n", common->tx_stats.total_tx_pkt_freed[BE_Q]); seq_printf(seq, "total_data_bk_pkt_send: %8d\t", common->tx_stats.total_tx_pkt_send[BK_Q]); seq_printf(seq, "total_data_bk_pkt_queued: %8d\t", - skb_queue_len(&common->tx_queue[3])); + skb_queue_len(&common->tx_queue[BK_Q])); seq_printf(seq, "total_bk_pkt_freed: %8d\n", common->tx_stats.total_tx_pkt_freed[BK_Q]); -- cgit v1.2.3 From 19d2e619e75459291ad053ab3e1a97619ae0704e Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:40:02 +0530 Subject: rsi: Fixed the kernel doc Changed the function header to match the function name. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 54aaeb09debf..a1bdea126151 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -185,7 +185,7 @@ static void rsi_register_rates_channels(struct rsi_hw *adapter, int band) } /** - * rsi_mac80211_attach() - This function is used to de-initialize the + * rsi_mac80211_detach() - This function is used to de-initialize the * Mac80211 stack. * @adapter: Pointer to the adapter structure. * -- cgit v1.2.3 From aabd3ad41a00651fa7c81c3bcb9a7138cf1bb224 Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:40:55 +0530 Subject: rsi: Using band from rsi_common to fill in ieee80211_rx_status Filling in band from common->band. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index a1bdea126151..45bdb9953755 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -770,10 +770,7 @@ static void rsi_fill_rx_status(struct ieee80211_hw *hw, rxs->signal = -(rssi); - if (channel <= 14) - rxs->band = IEEE80211_BAND_2GHZ; - else - rxs->band = IEEE80211_BAND_5GHZ; + rxs->band = common->band; freq = ieee80211_channel_to_frequency(channel, rxs->band); -- cgit v1.2.3 From f870a340f12ea7889fff40dbd05c0910ef3ecbd4 Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:41:22 +0530 Subject: rsi: Add macros for endpoints and set default value of endpoint. Added macros for the endpoints and set the default value of endpoint to 2.4GHz and 20MHz. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 1 + drivers/net/wireless/rsi/rsi_mgmt.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 2eefbf159bc0..2cdb36a4239e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -217,6 +217,7 @@ static void rsi_set_default_parameters(struct rsi_common *common) common->min_rate = 0xffff; common->fsm_state = FSM_CARD_NOT_READY; common->iface_down = true; + common->endpoint = EP_2GHZ_20MHZ; } /** diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 225215a3b8bb..0641068d7fec 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -123,6 +123,11 @@ #define BW_20MHZ 0 #define BW_40MHZ 1 +#define EP_2GHZ_20MHZ 0 +#define EP_2GHZ_40MHZ 1 +#define EP_5GHZ_20MHZ 2 +#define EP_5GHZ_40MHZ 3 + #define RSI_SUPP_FILTERS (FIF_ALLMULTI | FIF_PROBE_REQ |\ FIF_BCN_PRBRESP_PROMISC) enum opmode { -- cgit v1.2.3 From 4550faac36f532b5600eea8a13f655f4fe39484a Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:41:41 +0530 Subject: rsi: Changed the radio caps frame. Changed the radio caps frame and added the required fields. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 7 +++++++ drivers/net/wireless/rsi/rsi_mgmt.h | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 2cdb36a4239e..c3d8da9b544a 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -331,6 +331,13 @@ static int rsi_load_radio_caps(struct rsi_common *common) } } + radio_caps->sifs_tx_11n = cpu_to_le16(SIFS_TX_11N_VALUE); + radio_caps->sifs_tx_11b = cpu_to_le16(SIFS_TX_11B_VALUE); + radio_caps->slot_rx_11n = cpu_to_le16(SHORT_SLOT_VALUE); + radio_caps->ofdm_ack_tout = cpu_to_le16(OFDM_ACK_TOUT_VALUE); + radio_caps->cck_ack_tout = cpu_to_le16(CCK_ACK_TOUT_VALUE); + radio_caps->preamble_type = cpu_to_le16(LONG_PREAMBLE); + radio_caps->desc_word[7] |= cpu_to_le16(radio_id << 8); for (ii = 0; ii < MAX_HW_QUEUES; ii++) { diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 0641068d7fec..6ccf9d935e4b 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -128,6 +128,15 @@ #define EP_5GHZ_20MHZ 2 #define EP_5GHZ_40MHZ 3 +#define SIFS_TX_11N_VALUE 580 +#define SIFS_TX_11B_VALUE 346 +#define SHORT_SLOT_VALUE 360 +#define LONG_SLOT_VALUE 640 +#define OFDM_ACK_TOUT_VALUE 2720 +#define CCK_ACK_TOUT_VALUE 9440 +#define LONG_PREAMBLE 0x0000 +#define SHORT_PREAMBLE 0x0001 + #define RSI_SUPP_FILTERS (FIF_ALLMULTI | FIF_PROBE_REQ |\ FIF_BCN_PRBRESP_PROMISC) enum opmode { @@ -243,6 +252,12 @@ struct rsi_radio_caps { u8 num_11n_rates; u8 num_11ac_rates; __le16 gcpd_per_rate[20]; + __le16 sifs_tx_11n; + __le16 sifs_tx_11b; + __le16 slot_rx_11n; + __le16 ofdm_ack_tout; + __le16 cck_ack_tout; + __le16 preamble_type; } __packed; static inline u32 rsi_get_queueno(u8 *addr, u16 offset) -- cgit v1.2.3 From 8701d0312880fcddff757d153c7591d8caad4217 Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:41:58 +0530 Subject: rsi: Changed the rsi_set_channel() and rsi_program_bb_rf(). Made required changes to rsi_set_channel() and rsi_program_bb_rf() functions. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index c3d8da9b544a..5c122e8cd526 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -596,7 +596,7 @@ static int rsi_program_bb_rf(struct rsi_common *common) mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); mgmt_frame->desc_word[1] = cpu_to_le16(BBP_PROG_IN_TA); - mgmt_frame->desc_word[4] = cpu_to_le16(common->endpoint << 8); + mgmt_frame->desc_word[4] = cpu_to_le16(common->endpoint); if (common->rf_reset) { mgmt_frame->desc_word[7] = cpu_to_le16(RF_RESET_ENABLE); @@ -849,23 +849,6 @@ int rsi_set_channel(struct rsi_common *common, u16 channel) rsi_dbg(MGMT_TX_ZONE, "%s: Sending scan req frame\n", __func__); - if (common->band == IEEE80211_BAND_5GHZ) { - if ((channel >= 36) && (channel <= 64)) - channel = ((channel - 32) / 4); - else if ((channel > 64) && (channel <= 140)) - channel = ((channel - 102) / 4) + 8; - else if (channel >= 149) - channel = ((channel - 151) / 4) + 18; - else - return -EINVAL; - } else { - if (channel > 14) { - rsi_dbg(ERR_ZONE, "%s: Invalid chno %d, band = %d\n", - __func__, channel, common->band); - return -EINVAL; - } - } - skb = dev_alloc_skb(FRAME_DESC_SZ); if (!skb) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", @@ -885,6 +868,7 @@ int rsi_set_channel(struct rsi_common *common, u16 channel) (RSI_RF_TYPE << 4)); mgmt_frame->desc_word[5] = cpu_to_le16(0x01); + mgmt_frame->desc_word[6] = cpu_to_le16(0x12); if (common->channel_width == BW_40MHZ) mgmt_frame->desc_word[5] |= cpu_to_le16(0x1 << 8); -- cgit v1.2.3 From 0d59f5267d93f71b3d0c3c80f4948065e77ee75c Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:43:09 +0530 Subject: rsi: Changed rate handling. Changed rate handling. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 35 +++++++++++++++------------------ 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 5c122e8cd526..f5182cd67f53 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -942,7 +942,7 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) struct ieee80211_hw *hw = common->priv->hw; u8 band = hw->conf.chandef.chan->band; u8 num_supported_rates = 0; - u8 rate_offset = 0; + u8 rate_table_offset, rate_offset = 0; u32 rate_bitmap = common->bitrate_mask[band]; u16 *selected_rates, min_rate; @@ -978,14 +978,18 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) if (common->channel_width == BW_40MHZ) auto_rate->desc_word[7] |= cpu_to_le16(1); - if (band == IEEE80211_BAND_2GHZ) - min_rate = STD_RATE_01; - else - min_rate = STD_RATE_06; + if (band == IEEE80211_BAND_2GHZ) { + min_rate = RSI_RATE_1; + rate_table_offset = 0; + } else { + min_rate = RSI_RATE_6; + rate_table_offset = 4; + } for (ii = 0, jj = 0; ii < ARRAY_SIZE(rsi_rates); ii++) { if (rate_bitmap & BIT(ii)) { - selected_rates[jj++] = (rsi_rates[ii].bitrate / 5); + selected_rates[jj++] = + (rsi_rates[ii + rate_table_offset].bitrate / 5); rate_offset++; } } @@ -998,13 +1002,6 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) rate_offset += ARRAY_SIZE(mcs); } - if (rate_offset < (RSI_TBL_SZ / 2) - 1) { - for (ii = jj; ii < (RSI_TBL_SZ / 2); ii++) { - selected_rates[jj++] = min_rate; - rate_offset++; - } - } - sort(selected_rates, jj, sizeof(u16), &rsi_compare, NULL); /* mapping the rates to RSI rates */ @@ -1020,25 +1017,25 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) /* loading HT rates in the bottom half of the auto rate table */ if (common->vif_info[0].is_ht) { - if (common->vif_info[0].sgi) - auto_rate->supported_rates[rate_offset++] = - cpu_to_le16(RSI_RATE_MCS7_SG); - for (ii = rate_offset, kk = ARRAY_SIZE(rsi_mcsrates) - 1; ii < rate_offset + 2 * ARRAY_SIZE(rsi_mcsrates); ii++) { - if (common->vif_info[0].sgi) + if (common->vif_info[0].sgi || + conf_is_ht40(&common->priv->hw->conf)) auto_rate->supported_rates[ii++] = cpu_to_le16(rsi_mcsrates[kk] | BIT(9)); auto_rate->supported_rates[ii] = cpu_to_le16(rsi_mcsrates[kk--]); } - for (; ii < RSI_TBL_SZ; ii++) { + for (; ii < (RSI_TBL_SZ - 1); ii++) { auto_rate->supported_rates[ii] = cpu_to_le16(rsi_mcsrates[0]); } } + for (; ii < RSI_TBL_SZ; ii++) + auto_rate->supported_rates[ii] = min_rate; + auto_rate->num_supported_rates = cpu_to_le16(num_supported_rates * 2); auto_rate->moderate_rate_inx = cpu_to_le16(num_supported_rates / 2); auto_rate->desc_word[7] |= cpu_to_le16(0 << 8); -- cgit v1.2.3 From be876b299e12bae2b38cba3f48324fe5913a250b Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:43:35 +0530 Subject: rsi: Lower level debug messages and changed handling of confirm received for rsi_program_bb_rf(). Lower level debug messages for some frames and changed confirm received for rsi_program_bb_rf() to a valid case. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index f5182cd67f53..92f584e636d4 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1153,7 +1153,7 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common, common->fsm_state = FSM_EEPROM_READ_MAC_ADDR; } } else { - rsi_dbg(ERR_ZONE, + rsi_dbg(INFO_ZONE, "%s: Received bootup params cfm in %d state\n", __func__, common->fsm_state); return 0; @@ -1216,7 +1216,7 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common, __func__); } } else { - rsi_dbg(ERR_ZONE, + rsi_dbg(INFO_ZONE, "%s: Received radio caps cfm in %d state\n", __func__, common->fsm_state); return 0; @@ -1234,7 +1234,10 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common, return rsi_mac80211_attach(common); } } else { - goto out; + rsi_dbg(INFO_ZONE, + "%s: Received bbb_rf cfm in %d state\n", + __func__, common->fsm_state); + return 0; } break; -- cgit v1.2.3 From 2bfa6969d9b332ce43d03d679bf178ecb19b23c0 Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:43:54 +0530 Subject: rsi: Use SGI if configured for fixed rate transmission. Use SGI if configured while sending data packets at a fixed rate. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_pkt.c | 6 ++++++ drivers/net/wireless/rsi/rsi_mgmt.h | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/net/wireless/rsi/rsi_91x_pkt.c b/drivers/net/wireless/rsi/rsi_91x_pkt.c index 8e48e72bae20..229ef3aeaaaf 100644 --- a/drivers/net/wireless/rsi/rsi_91x_pkt.c +++ b/drivers/net/wireless/rsi/rsi_91x_pkt.c @@ -81,6 +81,12 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) /* Send fixed rate */ frame_desc[3] = cpu_to_le16(RATE_INFO_ENABLE); frame_desc[4] = cpu_to_le16(common->min_rate); + if (common->vif_info[0].sgi) { + if (common->min_rate & 0x100) /* Only MCS rates */ + frame_desc[4] |= + cpu_to_le16(ENABLE_SHORTGI_RATE); + } + } frame_desc[6] |= cpu_to_le16(seq_num & 0xfff); diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 6ccf9d935e4b..8bff6640dd10 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -69,6 +69,7 @@ #define RSI_LMAC_CLOCK_80MHZ 0x1 #define RSI_ENABLE_40MHZ (0x1 << 3) +#define ENABLE_SHORTGI_RATE BIT(9) #define RX_BA_INDICATION 1 #define RSI_TBL_SZ 40 -- cgit v1.2.3 From f75d3419ec2579929a29c4b3b0a7b790c6f6ae24 Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:44:12 +0530 Subject: rsi: Changed the SDIO interrupt variables and some clean up. Changed the SDIO interrupt variables and some clean ups. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 8 +++++--- drivers/net/wireless/rsi/rsi_sdio.h | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index 20d11ccfffe3..4834a9abc171 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -401,14 +401,16 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) case BUFFER_AVAILABLE: dev->rx_info.watch_bufferfull_count = 0; dev->rx_info.buffer_full = false; + dev->rx_info.semi_buffer_full = false; dev->rx_info.mgmt_buffer_full = false; rsi_sdio_ack_intr(common->priv, (1 << PKT_BUFF_AVAILABLE)); - rsi_set_event((&common->tx_thread.event)); + rsi_set_event(&common->tx_thread.event); + rsi_dbg(ISR_ZONE, - "%s: ==> BUFFER_AVILABLE <==\n", + "%s: ==> BUFFER_AVAILABLE <==\n", __func__); - dev->rx_info.buf_avilable_counter++; + dev->rx_info.buf_available_counter++; break; case FIRMWARE_ASSERT_IND: diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index df4b5e20e05f..c7e8f2be7901 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -30,7 +30,7 @@ enum sdio_interrupt_type { BUFFER_FULL = 0x0, - BUFFER_AVAILABLE = 0x1, + BUFFER_AVAILABLE = 0x2, FIRMWARE_ASSERT_IND = 0x3, MSDU_PACKET_PENDING = 0x4, UNKNOWN_INT = 0XE @@ -42,7 +42,7 @@ enum sdio_interrupt_type { #define PKT_MGMT_BUFF_FULL 2 #define MSDU_PKT_PENDING 3 /* Interrupt Bit Related Macros */ -#define PKT_BUFF_AVAILABLE 0 +#define PKT_BUFF_AVAILABLE 1 #define FW_ASSERT_IND 2 #define RSI_DEVICE_BUFFER_STATUS_REGISTER 0xf3 @@ -84,7 +84,7 @@ enum sdio_interrupt_type { #define TA_HOLD_THREAD_VALUE cpu_to_le32(0xF) #define TA_RELEASE_THREAD_VALUE cpu_to_le32(0xF) #define TA_BASE_ADDR 0x2200 -#define MISC_CFG_BASE_ADDR 0x4150 +#define MISC_CFG_BASE_ADDR 0x4105 struct receive_info { bool buffer_full; @@ -98,7 +98,7 @@ struct receive_info { u32 total_sdio_msdu_pending_intr; u32 total_sdio_unknown_intr; u32 buf_full_counter; - u32 buf_avilable_counter; + u32 buf_available_counter; }; struct rsi_91x_sdiodev { -- cgit v1.2.3 From 360accb0dba1777a4ea85a637c816b7987fa947b Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:45:03 +0530 Subject: rsi: Changed the logic of dequeuing packets from hal queues. The number of packets being dequeued from s/w queues was fixed - changed it to a dynamic calculation based on txop. There are also some fixes to the dequeuing algorithm. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_core.c | 80 +++++++++++++++++++++++---------- drivers/net/wireless/rsi/rsi_main.h | 3 ++ 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index cf61d6e3eaa7..264e8fac83ff 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -76,6 +76,50 @@ static bool rsi_recalculate_weights(struct rsi_common *common) return recontend_queue; } +/** + * rsi_get_num_pkts_dequeue() - This function determines the number of + * packets to be dequeued based on the number + * of bytes calculated using txop. + * + * @common: Pointer to the driver private structure. + * @q_num: the queue from which pkts have to be dequeued + * + * Return: pkt_num: Number of pkts to be dequeued. + */ +static u32 rsi_get_num_pkts_dequeue(struct rsi_common *common, u8 q_num) +{ + struct rsi_hw *adapter = common->priv; + struct sk_buff *skb; + u32 pkt_cnt = 0; + s16 txop = common->tx_qinfo[q_num].txop * 32; + struct ieee80211_rate rate; + + rate.bitrate = RSI_RATE_MCS0 * 5 * 10; /* Convert to Kbps */ + if (q_num == VI_Q) + txop = ((txop << 5) / 80); + + if (skb_queue_len(&common->tx_queue[q_num])) + skb = skb_peek(&common->tx_queue[q_num]); + else + return 0; + + do { + txop -= ieee80211_generic_frame_duration(adapter->hw, + adapter->vifs[0], + common->band, + skb->len, &rate); + pkt_cnt += 1; + /*checking if pkts are still there*/ + if (skb_queue_len(&common->tx_queue[q_num]) - pkt_cnt) + skb = skb->next; + else + break; + + } while (txop > 0); + + return pkt_cnt; +} + /** * rsi_core_determine_hal_queue() - This function determines the queue from * which packet has to be dequeued. @@ -88,7 +132,7 @@ static u8 rsi_core_determine_hal_queue(struct rsi_common *common) bool recontend_queue = false; u32 q_len = 0; u8 q_num = INVALID_QUEUE; - u8 ii = 0, min = 0; + u8 ii = 0; if (skb_queue_len(&common->tx_queue[MGMT_SOFT_Q])) { if (!common->mgmt_q_block) @@ -96,6 +140,9 @@ static u8 rsi_core_determine_hal_queue(struct rsi_common *common) return q_num; } + if (common->hw_data_qs_blocked) + return q_num; + if (common->pkt_cnt != 0) { --common->pkt_cnt; return common->selected_qnum; @@ -106,14 +153,15 @@ get_queue_num: q_num = rsi_determine_min_weight_queue(common); - q_len = skb_queue_len(&common->tx_queue[ii]); ii = q_num; /* Selecting the queue with least back off */ for (; ii < NUM_EDCA_QUEUES; ii++) { + q_len = skb_queue_len(&common->tx_queue[ii]); if (((common->tx_qinfo[ii].pkt_contended) && - (common->tx_qinfo[ii].weight < min)) && q_len) { - min = common->tx_qinfo[ii].weight; + (common->tx_qinfo[ii].weight < common->min_weight)) && + q_len) { + common->min_weight = common->tx_qinfo[ii].weight; q_num = ii; } } @@ -140,26 +188,10 @@ get_queue_num: common->selected_qnum = q_num; q_len = skb_queue_len(&common->tx_queue[q_num]); - switch (common->selected_qnum) { - case VO_Q: - if (q_len > MAX_CONTINUOUS_VO_PKTS) - common->pkt_cnt = (MAX_CONTINUOUS_VO_PKTS - 1); - else - common->pkt_cnt = --q_len; - break; - - case VI_Q: - if (q_len > MAX_CONTINUOUS_VI_PKTS) - common->pkt_cnt = (MAX_CONTINUOUS_VI_PKTS - 1); - else - common->pkt_cnt = --q_len; - - break; - - default: - common->pkt_cnt = 0; - break; - } + if (q_num == VO_Q || q_num == VI_Q) { + common->pkt_cnt = rsi_get_num_pkts_dequeue(common, q_num); + common->pkt_cnt -= 1; + }; return q_num; } diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 2cb73e7edb98..86291310e293 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -115,6 +115,7 @@ struct wmm_qinfo { s32 weight; s32 wme_params; s32 pkt_contended; + s32 txop; }; struct transmit_q_stats { @@ -192,6 +193,8 @@ struct rsi_common { u8 selected_qnum; u32 pkt_cnt; u8 min_weight; + + bool hw_data_qs_blocked; }; struct rsi_hw { -- cgit v1.2.3 From 258587f913f48f45b7e810d700ce1300afdb97da Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:45:45 +0530 Subject: rsi: Added debug messages. Added some debug messages. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 264e8fac83ff..6f6a4d0b5b1f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -284,6 +284,7 @@ void rsi_core_qos_processor(struct rsi_common *common) skb = rsi_core_dequeue_pkt(common, q_num); if (skb == NULL) { + rsi_dbg(ERR_ZONE, "skb null\n"); mutex_unlock(&common->tx_rxlock); break; } @@ -357,6 +358,7 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) if ((q_num != MGMT_SOFT_Q) && ((skb_queue_len(&common->tx_queue[q_num]) + 1) >= DATA_QUEUE_WATER_MARK)) { + rsi_dbg(ERR_ZONE, "%s: sw queue full\n", __func__); if (!ieee80211_queue_stopped(adapter->hw, WME_AC(q_num))) ieee80211_stop_queue(adapter->hw, WME_AC(q_num)); rsi_set_event(&common->tx_thread.event); -- cgit v1.2.3 From 7b748dc0ed95cfee7962c5359299e4f305989769 Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:46:13 +0530 Subject: rsi: Sending QoS null packet via the mgmt queue. Send the QoS null packet via mgmt queue. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 6f6a4d0b5b1f..1cd0914db270 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -339,7 +339,8 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) } if ((ieee80211_is_mgmt(tmp_hdr->frame_control)) || - (ieee80211_is_ctl(tmp_hdr->frame_control))) { + (ieee80211_is_ctl(tmp_hdr->frame_control)) || + (ieee80211_is_qos_nullfunc(tmp_hdr->frame_control))) { q_num = MGMT_SOFT_Q; skb->priority = q_num; } else { -- cgit v1.2.3 From 85af5bf829813df5571779e795b73ee498173945 Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:46:31 +0530 Subject: rsi: Adding support for 5GHz Adding support for 5GHz. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 17 +++--- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 81 +++++++++++++++++++++++++++-- drivers/net/wireless/rsi/rsi_mgmt.h | 1 + 3 files changed, 87 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 45bdb9953755..4700714e600f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -723,17 +723,17 @@ static int rsi_mac80211_set_rate_mask(struct ieee80211_hw *hw, { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; + enum ieee80211_band band = hw->conf.chandef.chan->band; mutex_lock(&common->mutex); + common->fixedrate_mask[band] = 0; - common->fixedrate_mask[IEEE80211_BAND_2GHZ] = 0; - - if (mask->control[IEEE80211_BAND_2GHZ].legacy == 0xfff) { - common->fixedrate_mask[IEEE80211_BAND_2GHZ] = - (mask->control[IEEE80211_BAND_2GHZ].ht_mcs[0] << 12); + if (mask->control[band].legacy == 0xfff) { + common->fixedrate_mask[band] = + (mask->control[band].ht_mcs[0] << 12); } else { - common->fixedrate_mask[IEEE80211_BAND_2GHZ] = - mask->control[IEEE80211_BAND_2GHZ].legacy; + common->fixedrate_mask[band] = + mask->control[band].legacy; } mutex_unlock(&common->mutex); @@ -980,6 +980,7 @@ int rsi_mac80211_attach(struct rsi_common *common) hw->max_tx_aggregation_subframes = 6; rsi_register_rates_channels(adapter, IEEE80211_BAND_2GHZ); + rsi_register_rates_channels(adapter, IEEE80211_BAND_5GHZ); hw->rate_control_algorithm = "AARF"; SET_IEEE80211_PERM_ADDR(hw, common->mac_addr); @@ -997,6 +998,8 @@ int rsi_mac80211_attach(struct rsi_common *common) wiphy->available_antennas_tx = 1; wiphy->bands[IEEE80211_BAND_2GHZ] = &adapter->sbands[IEEE80211_BAND_2GHZ]; + wiphy->bands[IEEE80211_BAND_5GHZ] = + &adapter->sbands[IEEE80211_BAND_5GHZ]; status = ieee80211_register_hw(hw); if (status) diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 92f584e636d4..cbd5a7e7c73c 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -623,6 +623,9 @@ int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode) { struct sk_buff *skb = NULL; struct rsi_vap_caps *vap_caps; + struct rsi_hw *adapter = common->priv; + struct ieee80211_hw *hw = adapter->hw; + struct ieee80211_conf *conf = &hw->conf; u16 vap_id = 0; rsi_dbg(MGMT_TX_ZONE, "%s: Sending VAP capabilities frame\n", __func__); @@ -652,13 +655,24 @@ int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode) vap_caps->frag_threshold = cpu_to_le16(IEEE80211_MAX_FRAG_THRESHOLD); vap_caps->rts_threshold = cpu_to_le16(common->rts_threshold); - vap_caps->default_mgmt_rate = 0; - if (conf_is_ht40(&common->priv->hw->conf)) { - vap_caps->default_ctrl_rate = - cpu_to_le32(RSI_RATE_6 | FULL40M_ENABLE << 16); - } else { + vap_caps->default_mgmt_rate = cpu_to_le32(RSI_RATE_6); + + if (common->band == IEEE80211_BAND_5GHZ) { vap_caps->default_ctrl_rate = cpu_to_le32(RSI_RATE_6); + if (conf_is_ht40(&common->priv->hw->conf)) { + vap_caps->default_ctrl_rate |= + cpu_to_le32(FULL40M_ENABLE << 16); + } + } else { + vap_caps->default_ctrl_rate = cpu_to_le32(RSI_RATE_1); + if (conf_is_ht40_minus(conf)) + vap_caps->default_ctrl_rate |= + cpu_to_le32(UPPER_20_ENABLE << 16); + else if (conf_is_ht40_plus(conf)) + vap_caps->default_ctrl_rate |= + cpu_to_le32(LOWER_20_ENABLE << 16); } + vap_caps->default_data_rate = 0; vap_caps->beacon_interval = cpu_to_le16(200); vap_caps->dtim_period = cpu_to_le16(4); @@ -834,6 +848,63 @@ static int rsi_send_reset_mac(struct rsi_common *common) return rsi_send_internal_mgmt_frame(common, skb); } +/** + * rsi_band_check() - This function programs the band + * @common: Pointer to the driver private structure. + * + * Return: 0 on success, corresponding error code on failure. + */ +int rsi_band_check(struct rsi_common *common) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_hw *hw = adapter->hw; + u8 prev_bw = common->channel_width; + u8 prev_ep = common->endpoint; + struct ieee80211_channel *curchan = hw->conf.chandef.chan; + int status = 0; + + if (common->band != curchan->band) { + common->rf_reset = 1; + common->band = curchan->band; + } + + if ((hw->conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) || + (hw->conf.chandef.width == NL80211_CHAN_WIDTH_20)) + common->channel_width = BW_20MHZ; + else + common->channel_width = BW_40MHZ; + + if (common->band == IEEE80211_BAND_2GHZ) { + if (common->channel_width) + common->endpoint = EP_2GHZ_40MHZ; + else + common->endpoint = EP_2GHZ_20MHZ; + } else { + if (common->channel_width) + common->endpoint = EP_5GHZ_40MHZ; + else + common->endpoint = EP_5GHZ_20MHZ; + } + + if (common->endpoint != prev_ep) { + status = rsi_program_bb_rf(common); + if (status) + return status; + } + + if (common->channel_width != prev_bw) { + status = rsi_load_bootup_params(common); + if (status) + return status; + + status = rsi_load_radio_caps(common); + if (status) + return status; + } + + return status; +} + /** * rsi_set_channel() - This function programs the channel. * @common: Pointer to the driver private structure. diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index 8bff6640dd10..f10d6c67e82f 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -304,4 +304,5 @@ void rsi_core_qos_processor(struct rsi_common *common); void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb); int rsi_send_mgmt_pkt(struct rsi_common *common, struct sk_buff *skb); int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb); +int rsi_band_check(struct rsi_common *common); #endif -- cgit v1.2.3 From 686a254177929cf82bc34af0944906e6866e393a Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:46:48 +0530 Subject: rsi: Adding support for host based bgscan. Added support for host based bgscan. The h/w queues are blocked while bgscan is being performed and after coming to the connected channel, the queues are unblocked. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 117 +++++++++++++++++++++++++--- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 43 ++++++++++ drivers/net/wireless/rsi/rsi_main.h | 9 +++ drivers/net/wireless/rsi/rsi_mgmt.h | 3 +- 4 files changed, 160 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 4700714e600f..1cb316417887 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -340,6 +340,59 @@ static void rsi_mac80211_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&common->mutex); } +/** + * rsi_channel_change() - This function is a performs the checks + * required for changing a channel and sets + * the channel accordingly. + * @hw: Pointer to the ieee80211_hw structure. + * + * Return: 0 on success, negative error code on failure. + */ +static int rsi_channel_change(struct ieee80211_hw *hw) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + int status = -EOPNOTSUPP; + struct ieee80211_channel *curchan = hw->conf.chandef.chan; + u16 channel = curchan->hw_value; + struct ieee80211_bss_conf *bss = &adapter->vifs[0]->bss_conf; + + rsi_dbg(INFO_ZONE, + "%s: Set channel: %d MHz type: %d channel_no %d\n", + __func__, curchan->center_freq, + curchan->flags, channel); + + if (bss->assoc) { + if (!common->hw_data_qs_blocked && + (rsi_get_connected_channel(adapter) != channel)) { + rsi_dbg(INFO_ZONE, "blk data q %d\n", channel); + if (!rsi_send_block_unblock_frame(common, true)) + common->hw_data_qs_blocked = true; + } + } + + status = rsi_band_check(common); + if (!status) + status = rsi_set_channel(adapter->priv, channel); + + if (bss->assoc) { + if (common->hw_data_qs_blocked && + (rsi_get_connected_channel(adapter) == channel)) { + rsi_dbg(INFO_ZONE, "unblk data q %d\n", channel); + if (!rsi_send_block_unblock_frame(common, false)) + common->hw_data_qs_blocked = false; + } + } else { + if (common->hw_data_qs_blocked) { + rsi_dbg(INFO_ZONE, "unblk data q %d\n", channel); + if (!rsi_send_block_unblock_frame(common, false)) + common->hw_data_qs_blocked = false; + } + } + + return status; +} + /** * rsi_mac80211_config() - This function is a handler for configuration * requests. The stack calls this function to @@ -357,17 +410,10 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw, int status = -EOPNOTSUPP; mutex_lock(&common->mutex); - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - struct ieee80211_channel *curchan = hw->conf.chandef.chan; - u16 channel = curchan->hw_value; - - rsi_dbg(INFO_ZONE, - "%s: Set channel: %d MHz type: %d channel_no %d\n", - __func__, curchan->center_freq, - curchan->flags, channel); - common->band = curchan->band; - status = rsi_set_channel(adapter->priv, channel); - } + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) + status = rsi_channel_change(hw); + mutex_unlock(&common->mutex); return status; @@ -421,6 +467,15 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, bss_conf->qos, bss_conf->aid); } + + if (changed & BSS_CHANGED_CQM) { + common->cqm_info.last_cqm_event_rssi = 0; + common->cqm_info.rssi_thold = bss_conf->cqm_rssi_thold; + common->cqm_info.rssi_hyst = bss_conf->cqm_rssi_hyst; + rsi_dbg(INFO_ZONE, "RSSI throld & hysteresis are: %d %d\n", + common->cqm_info.rssi_thold, + common->cqm_info.rssi_hyst); + } mutex_unlock(&common->mutex); } @@ -740,6 +795,37 @@ static int rsi_mac80211_set_rate_mask(struct ieee80211_hw *hw, return 0; } +/** + * rsi_perform_cqm() - This function performs cqm. + * @common: Pointer to the driver private structure. + * @bssid: pointer to the bssid. + * @rssi: RSSI value. + */ +static void rsi_perform_cqm(struct rsi_common *common, + u8 *bssid, + s8 rssi) +{ + struct rsi_hw *adapter = common->priv; + s8 last_event = common->cqm_info.last_cqm_event_rssi; + int thold = common->cqm_info.rssi_thold; + u32 hyst = common->cqm_info.rssi_hyst; + enum nl80211_cqm_rssi_threshold_event event; + + if (rssi < thold && (last_event == 0 || rssi < (last_event - hyst))) + event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; + else if (rssi > thold && + (last_event == 0 || rssi > (last_event + hyst))) + event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; + else + return; + + common->cqm_info.last_cqm_event_rssi = rssi; + rsi_dbg(INFO_ZONE, "CQM: Notifying event: %d\n", event); + ieee80211_cqm_rssi_notify(adapter->vifs[0], event, GFP_KERNEL); + + return; +} + /** * rsi_fill_rx_status() - This function fills rx status in * ieee80211_rx_status structure. @@ -755,6 +841,7 @@ static void rsi_fill_rx_status(struct ieee80211_hw *hw, struct rsi_common *common, struct ieee80211_rx_status *rxs) { + struct ieee80211_bss_conf *bss = &common->priv->vifs[0]->bss_conf; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct skb_info *rx_params = (struct skb_info *)info->driver_data; struct ieee80211_hdr *hdr; @@ -789,6 +876,14 @@ static void rsi_fill_rx_status(struct ieee80211_hw *hw, rxs->flag |= RX_FLAG_DECRYPTED; rxs->flag |= RX_FLAG_IV_STRIPPED; } + + /* CQM only for connected AP beacons, the RSSI is a weighted avg */ + if (bss->assoc && !(memcmp(bss->bssid, hdr->addr2, ETH_ALEN))) { + if (ieee80211_is_beacon(hdr->frame_control)) + rsi_perform_cqm(common, hdr->addr2, rxs->signal); + } + + return; } /** diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index cbd5a7e7c73c..3ef343469c4e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1200,6 +1200,49 @@ static int rsi_eeprom_read(struct rsi_common *common) return rsi_send_internal_mgmt_frame(common, skb); } +/** + * This function sends a frame to block/unblock + * data queues in the firmware + * + * @param common Pointer to the driver private structure. + * @param block event - block if true, unblock if false + * @return 0 on success, -1 on failure. + */ +int rsi_send_block_unblock_frame(struct rsi_common *common, bool block_event) +{ + struct rsi_mac_frame *mgmt_frame; + struct sk_buff *skb; + + rsi_dbg(MGMT_TX_ZONE, "%s: Sending block/unblock frame\n", __func__); + + skb = dev_alloc_skb(FRAME_DESC_SZ); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, FRAME_DESC_SZ); + mgmt_frame = (struct rsi_mac_frame *)skb->data; + + mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); + mgmt_frame->desc_word[1] = cpu_to_le16(BLOCK_HW_QUEUE); + + if (block_event == true) { + rsi_dbg(INFO_ZONE, "blocking the data qs\n"); + mgmt_frame->desc_word[4] = cpu_to_le16(0xf); + } else { + rsi_dbg(INFO_ZONE, "unblocking the data qs\n"); + mgmt_frame->desc_word[5] = cpu_to_le16(0xf); + } + + skb_put(skb, FRAME_DESC_SZ); + + return rsi_send_internal_mgmt_frame(common, skb); + +} + + /** * rsi_handle_ta_confirm_type() - This function handles the confirm frames. * @common: Pointer to the driver private structure. diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 86291310e293..5baed945f60e 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -142,6 +142,12 @@ struct rsi_thread { atomic_t thread_done; }; +struct cqm_info { + s8 last_cqm_event_rssi; + int rssi_thold; + u32 rssi_hyst; +}; + struct rsi_hw; struct rsi_common { @@ -194,6 +200,9 @@ struct rsi_common { u32 pkt_cnt; u8 min_weight; + /* bgscan related */ + struct cqm_info cqm_info; + bool hw_data_qs_blocked; }; diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index f10d6c67e82f..3741173fd3ac 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -168,7 +168,7 @@ enum cmd_frame_type { SCAN_REQUEST, TSF_UPDATE, PEER_NOTIFY, - BLOCK_UNBLOCK, + BLOCK_HW_QUEUE, SET_KEY_REQ, AUTO_RATE_IND, BOOTUP_PARAMS_REQUEST, @@ -293,6 +293,7 @@ int rsi_send_aggregation_params_frame(struct rsi_common *common, u16 tid, int rsi_hal_load_key(struct rsi_common *common, u8 *data, u16 key_len, u8 key_type, u8 key_id, u32 cipher); int rsi_set_channel(struct rsi_common *common, u16 chno); +int rsi_send_block_unblock_frame(struct rsi_common *common, bool event); void rsi_inform_bss_status(struct rsi_common *common, u8 status, const u8 *bssid, u8 qos_enable, u16 aid); void rsi_indicate_pkt_to_os(struct rsi_common *common, struct sk_buff *skb); -- cgit v1.2.3 From e8c58e7a5a106c3d557fccd01cd4d1128f9bab38 Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Mon, 16 Jun 2014 19:47:03 +0530 Subject: rsi: Changes for 40MHz Added code required for 40MHz. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 2 +- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 40 ++++++++++++++--------------- drivers/net/wireless/rsi/rsi_91x_pkt.c | 11 ++++++++ 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 1cb316417887..aeaf87bb5518 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -177,7 +177,7 @@ static void rsi_register_rates_channels(struct rsi_hw *adapter, int band) sbands->ht_cap.cap = (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40); - sbands->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K; + sbands->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K; sbands->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; sbands->ht_cap.mcs.rx_mask[0] = 0xff; sbands->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 3ef343469c4e..83abe580cf5f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -277,7 +277,6 @@ static int rsi_load_radio_caps(struct rsi_common *common) { struct rsi_radio_caps *radio_caps; struct rsi_hw *adapter = common->priv; - struct ieee80211_hw *hw = adapter->hw; u16 inx = 0; u8 ii; u8 radio_id = 0; @@ -286,7 +285,6 @@ static int rsi_load_radio_caps(struct rsi_common *common) 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}; - struct ieee80211_conf *conf = &hw->conf; struct sk_buff *skb; rsi_dbg(INFO_ZONE, "%s: Sending rate symbol req frame\n", __func__); @@ -308,26 +306,26 @@ static int rsi_load_radio_caps(struct rsi_common *common) if (common->channel_width == BW_40MHZ) { radio_caps->desc_word[7] |= cpu_to_le16(RSI_LMAC_CLOCK_80MHZ); radio_caps->desc_word[7] |= cpu_to_le16(RSI_ENABLE_40MHZ); - if (common->channel_width) { - radio_caps->desc_word[5] = - cpu_to_le16(common->channel_width << 12); - radio_caps->desc_word[5] |= cpu_to_le16(FULL40M_ENABLE); - } - if (conf_is_ht40_minus(conf)) { - radio_caps->desc_word[5] = 0; - radio_caps->desc_word[5] |= - cpu_to_le16(LOWER_20_ENABLE); - radio_caps->desc_word[5] |= - cpu_to_le16(LOWER_20_ENABLE >> 12); - } - - if (conf_is_ht40_plus(conf)) { - radio_caps->desc_word[5] = 0; - radio_caps->desc_word[5] |= - cpu_to_le16(UPPER_20_ENABLE); - radio_caps->desc_word[5] |= - cpu_to_le16(UPPER_20_ENABLE >> 12); + if (common->fsm_state == FSM_MAC_INIT_DONE) { + struct ieee80211_hw *hw = adapter->hw; + struct ieee80211_conf *conf = &hw->conf; + if (conf_is_ht40_plus(conf)) { + radio_caps->desc_word[5] = + cpu_to_le16(LOWER_20_ENABLE); + radio_caps->desc_word[5] |= + cpu_to_le16(LOWER_20_ENABLE >> 12); + } else if (conf_is_ht40_minus(conf)) { + radio_caps->desc_word[5] = + cpu_to_le16(UPPER_20_ENABLE); + radio_caps->desc_word[5] |= + cpu_to_le16(UPPER_20_ENABLE >> 12); + } else { + radio_caps->desc_word[5] = + cpu_to_le16(BW_40MHZ << 12); + radio_caps->desc_word[5] |= + cpu_to_le16(FULL40M_ENABLE); + } } } diff --git a/drivers/net/wireless/rsi/rsi_91x_pkt.c b/drivers/net/wireless/rsi/rsi_91x_pkt.c index 229ef3aeaaaf..702593f19997 100644 --- a/drivers/net/wireless/rsi/rsi_91x_pkt.c +++ b/drivers/net/wireless/rsi/rsi_91x_pkt.c @@ -81,6 +81,10 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) /* Send fixed rate */ frame_desc[3] = cpu_to_le16(RATE_INFO_ENABLE); frame_desc[4] = cpu_to_le16(common->min_rate); + + if (conf_is_ht40(&common->priv->hw->conf)) + frame_desc[5] = cpu_to_le16(FULL40M_ENABLE); + if (common->vif_info[0].sgi) { if (common->min_rate & 0x100) /* Only MCS rates */ frame_desc[4] |= @@ -122,6 +126,8 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, struct ieee80211_hdr *wh = NULL; struct ieee80211_tx_info *info; struct ieee80211_bss_conf *bss = NULL; + struct ieee80211_hw *hw = adapter->hw; + struct ieee80211_conf *conf = &hw->conf; struct skb_info *tx_params; int status = -E2BIG; __le16 *msg = NULL; @@ -181,6 +187,11 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, else msg[4] = cpu_to_le16((RSI_RATE_6 & 0x0f) | RSI_11G_MODE); + if (conf_is_ht40(conf)) { + msg[4] = cpu_to_le16(0xB | RSI_11G_MODE); + msg[5] = cpu_to_le16(0x6); + } + /* Indicate to firmware to give cfm */ if ((skb->data[16] == IEEE80211_STYPE_PROBE_REQ) && (!bss->assoc)) { msg[1] |= cpu_to_le16(BIT(10)); -- cgit v1.2.3 From 0b39aaf2f2035b1c42b805a786a8b42f7501b82f Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:36:59 +0300 Subject: wil6210: Tx mgmt frame from debugfs Provide 2 files on the debugfs: - "rxon": write channel (1..4) to open Rx on it, 0 to rxoff - "tx_mgmt": write binary frame, starting from MAC header one need to care about turning receiver on/off before/after tx_mgmt Correct sequence is: echo $channel > rxon cat mfmt_frame > tx_mgmt echo 0 > rxon Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 7 ++- drivers/net/wireless/ath/wil6210/debugfs.c | 80 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 3 ++ 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 820d4ebd9322..1725dfca1d8c 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -443,10 +443,9 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, return rc; } -static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, - struct wireless_dev *wdev, - struct cfg80211_mgmt_tx_params *params, - u64 *cookie) +int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie) { const u8 *buf = params->buf; size_t len = params->len; diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 8d4bc4bfb664..9d5db0472f4b 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -397,6 +397,84 @@ static const struct file_operations fops_reset = { .write = wil_write_file_reset, .open = simple_open, }; +/*---write channel 1..4 to rxon for it, 0 to rxoff---*/ +static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + int rc; + long channel; + bool on; + + char *kbuf = kmalloc(len + 1, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + if (copy_from_user(kbuf, buf, len)) + return -EIO; + + kbuf[len] = '\0'; + rc = kstrtol(kbuf, 0, &channel); + kfree(kbuf); + if (rc) + return rc; + + if ((channel < 0) || (channel > 4)) { + wil_err(wil, "Invalid channel %ld\n", channel); + return -EINVAL; + } + on = !!channel; + + if (on) { + rc = wmi_set_channel(wil, (int)channel); + if (rc) + return rc; + } + + rc = wmi_rxon(wil, on); + if (rc) + return rc; + + return len; +} + +static const struct file_operations fops_rxon = { + .write = wil_write_file_rxon, + .open = simple_open, +}; +/*---tx_mgmt---*/ +/* Write mgmt frame to this file to send it */ +static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + struct wiphy *wiphy = wil_to_wiphy(wil); + struct wireless_dev *wdev = wil_to_wdev(wil); + struct cfg80211_mgmt_tx_params params; + int rc; + + void *frame = kmalloc(len, GFP_KERNEL); + if (!frame) + return -ENOMEM; + + if (copy_from_user(frame, buf, len)) + return -EIO; + + params.buf = frame; + params.len = len; + params.chan = wdev->preset_chandef.chan; + + rc = wil_cfg80211_mgmt_tx(wiphy, wdev, ¶ms, NULL); + + kfree(frame); + wil_info(wil, "%s() -> %d\n", __func__, rc); + + return len; +} + +static const struct file_operations fops_txmgmt = { + .write = wil_write_file_txmgmt, + .open = simple_open, +}; static void wil_seq_hexdump(struct seq_file *s, void *p, int len, const char *prefix) @@ -719,6 +797,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread); debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset); + debugfs_create_file("rxon", S_IWUSR, dbg, wil, &fops_rxon); + debugfs_create_file("tx_mgmt", S_IWUSR, dbg, wil, &fops_txmgmt); debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp); wil->rgf_blob.data = (void * __force)wil->csr + 0; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index e25edc52398f..793675ee69a9 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -504,6 +504,9 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); void wil6210_disable_irq(struct wil6210_priv *wil); void wil6210_enable_irq(struct wil6210_priv *wil); +int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie); int wil6210_debugfs_init(struct wil6210_priv *wil); void wil6210_debugfs_remove(struct wil6210_priv *wil); -- cgit v1.2.3 From 304464f482272d761bf4c479738d3183fc36857b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:00 +0300 Subject: wil6210: indicate mgmt_tx status Inform cfg80211 about Tx result Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 1725dfca1d8c..cfdf1a273e8f 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -451,6 +451,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, size_t len = params->len; struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; + bool tx_status = false; struct ieee80211_mgmt *mgmt_frame = (void *)buf; struct wmi_sw_tx_req_cmd *cmd; struct { @@ -459,8 +460,10 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, } __packed evt; cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); - if (!cmd) - return -ENOMEM; + if (!cmd) { + rc = -ENOMEM; + goto out; + } memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); cmd->len = cpu_to_le16(len); @@ -469,10 +472,12 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); if (rc == 0) - rc = evt.evt.status; + tx_status = !evt.evt.status; kfree(cmd); - + out: + cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len, + tx_status, GFP_KERNEL); return rc; } -- cgit v1.2.3 From ca959773f00128defd7b87815b7d38ca318e21d9 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:01 +0300 Subject: wil6210: print debug info when starting AP In the wil_cfg80211_start_ap(), debug print selected data: - beacon (before and after fix-up) - crypto parameters - mark start/stop AP invocation Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 43 ++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index cfdf1a273e8f..a3042cd3d308 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -566,6 +566,34 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy, return rc; } +static void wil_print_bcon_data(struct cfg80211_beacon_data *b) +{ + print_hex_dump_bytes("head ", DUMP_PREFIX_OFFSET, + b->head, b->head_len); + print_hex_dump_bytes("tail ", DUMP_PREFIX_OFFSET, + b->tail, b->tail_len); + print_hex_dump_bytes("BCON IE ", DUMP_PREFIX_OFFSET, + b->beacon_ies, b->beacon_ies_len); + print_hex_dump_bytes("PROBE ", DUMP_PREFIX_OFFSET, + b->probe_resp, b->probe_resp_len); + print_hex_dump_bytes("PROBE IE ", DUMP_PREFIX_OFFSET, + b->proberesp_ies, b->proberesp_ies_len); + print_hex_dump_bytes("ASSOC IE ", DUMP_PREFIX_OFFSET, + b->assocresp_ies, b->assocresp_ies_len); +} + +static void wil_print_crypto(struct wil6210_priv *wil, + struct cfg80211_crypto_settings *c) +{ + wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n", + c->wpa_versions, c->cipher_group); + wil_dbg_misc(wil, "Pairwise ciphers [%d]\n", c->n_ciphers_pairwise); + wil_dbg_misc(wil, "AKM suites [%d]\n", c->n_akm_suites); + wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n", + c->control_port, be16_to_cpu(c->control_port_ethertype), + c->control_port_no_encrypt); +} + static int wil_fix_bcon(struct wil6210_priv *wil, struct cfg80211_beacon_data *bcon) { @@ -599,8 +627,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct wireless_dev *wdev = ndev->ieee80211_ptr; struct ieee80211_channel *channel = info->chandef.chan; struct cfg80211_beacon_data *bcon = &info->beacon; + struct cfg80211_crypto_settings *crypto = &info->crypto; u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); + wil_dbg_misc(wil, "%s()\n", __func__); + if (!channel) { wil_err(wil, "AP: No channel???\n"); return -EINVAL; @@ -608,11 +639,19 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, channel->center_freq, info->privacy ? "secure" : "open"); + wil_dbg_misc(wil, "Privacy: %d auth_type %d\n", + info->privacy, info->auth_type); + wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval, + info->dtim_period); print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, info->ssid, info->ssid_len); + wil_print_bcon_data(bcon); + wil_print_crypto(wil, crypto); - if (wil_fix_bcon(wil, bcon)) + if (wil_fix_bcon(wil, bcon)) { wil_dbg_misc(wil, "Fixed bcon\n"); + wil_print_bcon_data(bcon); + } mutex_lock(&wil->mutex); @@ -667,6 +706,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, int rc = 0; struct wil6210_priv *wil = wiphy_to_wil(wiphy); + wil_dbg_misc(wil, "%s()\n", __func__); + mutex_lock(&wil->mutex); rc = wmi_pcp_stop(wil); -- cgit v1.2.3 From 3de6cf204d540d9cf52ad6669d49425579562d2a Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:02 +0300 Subject: wil6210: trace wil->status on debugfs For debug purposes Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 9d5db0472f4b..4fb33750505c 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -231,6 +231,26 @@ static struct dentry *wil_debugfs_create_iomem_x32(const char *name, &fops_iomem_x32); } +static int wil_debugfs_ulong_set(void *data, u64 val) +{ + *(ulong *)data = val; + return 0; +} +static int wil_debugfs_ulong_get(void *data, u64 *val) +{ + *val = *(ulong *)data; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, + wil_debugfs_ulong_set, "%llu\n"); + +static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode, + struct dentry *parent, + ulong *value) +{ + return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong); +} + static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, const char *name, struct dentry *parent, u32 off) @@ -781,6 +801,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, &wil->secure_pcp); + wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg, + &wil->status); wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg, HOSTADDR(RGF_USER_USER_ICR)); -- cgit v1.2.3 From 8eea944af0efcdba09dac1ad220c9bfa68293279 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:03 +0300 Subject: wil6210: print more info about BSS found print essential info to dmesg Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/wmi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 6cc0e182cc70..1c5e6e995437 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -327,6 +327,17 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) { struct cfg80211_bss *bss; + u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp); + u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info); + u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int); + const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable; + size_t ie_len = d_len - offsetof(struct ieee80211_mgmt, + u.beacon.variable); + wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap); + wil_dbg_wmi(wil, "TSF : 0x%016llx\n", tsf); + wil_dbg_wmi(wil, "Beacon interval : %d\n", bi); + wil_hex_dump_wmi("IE ", DUMP_PREFIX_OFFSET, 16, 1, ie_buf, + ie_len, true); bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame, d_len, signal, GFP_KERNEL); -- cgit v1.2.3 From 67c3e1b41efe4dd400f444c6dccc4538b627758c Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:04 +0300 Subject: wil6210: more debug info for vring print used/available counters on debugfs; print to dmesg when Tx vring becomes empty This aids with performance investigation Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 9 +++++++-- drivers/net/wireless/ath/wil6210/txrx.c | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 4fb33750505c..d90aa28ec7bd 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -72,11 +72,16 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) if (vring->va) { int cid = wil->vring2cid_tid[i][0]; int tid = wil->vring2cid_tid[i][1]; + u32 swhead = vring->swhead; + u32 swtail = vring->swtail; + int used = (vring->size + swhead - swtail) + % vring->size; + int avail = vring->size - used - 1; char name[10]; snprintf(name, sizeof(name), "tx_%2d", i); - seq_printf(s, "\n%pM CID %d TID %d\n", - wil->sta[cid].addr, cid, tid); + seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d]\n", + wil->sta[cid].addr, cid, tid, used, avail); wil_print_vring(s, wil, name, vring, '_', 'H'); } } diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 0784ef3d4ce2..c08d041fbe74 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1132,6 +1132,10 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) done++; } } + + if (wil_vring_is_empty(vring)) + wil_dbg_txrx(wil, "Ring[%2d] empty\n", ringid); + if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring)) netif_tx_wake_all_queues(wil_to_ndev(wil)); -- cgit v1.2.3 From 7c0acf868d2e470c9d6a40091acf8d6444c01b57 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:05 +0300 Subject: wil6210: Tx performance monitoring For performance monitoring, trace time intervals when Tx vring is idle/not idle. Use CPU cycle counter for this, because jiffies is too rough, and other precise time measurement methods involve overhead while get_cycles() should be fast. This used to provide some estimation for percentage when Tx vring was idle, i.e. when hardware is under-utilized. Estimation is not precise because of many reasons - CPU frequency scaling, grt_cycles() may be per core etc. But still, it is good estimation Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 16 ++++++++++++++-- drivers/net/wireless/ath/wil6210/txrx.c | 8 +++++++- drivers/net/wireless/ath/wil6210/wil6210.h | 3 ++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index d90aa28ec7bd..9c1102304b93 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -69,6 +69,8 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { struct vring *vring = &(wil->vring_tx[i]); + struct vring_tx_data *txdata = &wil->vring_tx_data[i]; + if (vring->va) { int cid = wil->vring2cid_tid[i][0]; int tid = wil->vring2cid_tid[i][1]; @@ -78,10 +80,20 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) % vring->size; int avail = vring->size - used - 1; char name[10]; + /* performance monitoring */ + cycles_t now = get_cycles(); + cycles_t idle = txdata->idle; + cycles_t total = now - txdata->begin; + + txdata->begin = now; + txdata->idle = 0ULL; + snprintf(name, sizeof(name), "tx_%2d", i); - seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d]\n", - wil->sta[cid].addr, cid, tid, used, avail); + seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d] idle %3d%%\n", + wil->sta[cid].addr, cid, tid, used, avail, + (int)((idle*100)/total)); + wil_print_vring(s, wil, name, vring, '_', 'H'); } } diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index c08d041fbe74..0318cd2650ce 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -881,6 +881,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, int nr_frags = skb_shinfo(skb)->nr_frags; uint f = 0; int vring_index = vring - wil->vring_tx; + struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; uint i = swhead; dma_addr_t pa; @@ -953,6 +954,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); + if (wil_vring_is_empty(vring)) /* performance monitoring */ + txdata->idle += get_cycles() - txdata->last_idle; + /* advance swhead */ wil_vring_advance_head(vring, nr_frags + 1); wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); @@ -1133,8 +1137,10 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) } } - if (wil_vring_is_empty(vring)) + if (wil_vring_is_empty(vring)) { /* performance monitoring */ wil_dbg_txrx(wil, "Ring[%2d] empty\n", ringid); + txdata->last_idle = get_cycles(); + } if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring)) netif_tx_wake_all_queues(wil_to_ndev(wil)); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 793675ee69a9..ede4c9f5f5c2 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -20,6 +20,7 @@ #include #include #include +#include #define WIL_NAME "wil6210" @@ -251,7 +252,7 @@ struct vring { */ struct vring_tx_data { int enabled; - + cycles_t idle, last_idle, begin; }; enum { /* for wil6210_priv.status */ -- cgit v1.2.3 From 94b7b64c73515bc7689bd9d80e6d2fea536a3cef Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:06 +0300 Subject: wil6210: Allow driver load if FW not ready Usable for debugging, to be able to obtain FW traces Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/pcie_bus.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 1e2e07b9d13d..e5d7ffe7d4e6 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -27,6 +27,10 @@ MODULE_PARM_DESC(use_msi, " Use MSI interrupt: " "0 - don't, 1 - (default) - single, or 3"); +static bool debug_fw; /* = false; */ +module_param(debug_fw, bool, S_IRUGO); +MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug"); + /* Bus ops */ static int wil_if_pcie_enable(struct wil6210_priv *wil) { @@ -71,6 +75,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) mutex_lock(&wil->mutex); rc = wil_reset(wil); mutex_unlock(&wil->mutex); + if (debug_fw) + rc = 0; if (rc) goto release_irq; -- cgit v1.2.3 From d5b1c32f51fc27f4fff77878e83949d665124f7d Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:07 +0300 Subject: wil6210: BACK: track last dropped SSN Track and print on debugfs Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 2 +- drivers/net/wireless/ath/wil6210/rx_reorder.c | 1 + drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 9c1102304b93..3c3abb6f30fe 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -745,7 +745,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) else seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); } - seq_puts(s, "]\n"); + seq_printf(s, "] last drop 0x%03x\n", r->ssn_last_drop); } static int wil_sta_debugfs_show(struct seq_file *s, void *data) diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 747ae1275877..180ca4793904 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -116,6 +116,7 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) /* frame with out of date sequence number */ if (seq_less(seq, r->head_seq_num)) { + r->ssn_last_drop = seq; dev_kfree_skb(skb); goto out; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index ede4c9f5f5c2..4cbb8cec29c6 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -304,6 +304,7 @@ struct wil_tid_ampdu_rx { u16 ssn; u16 buf_size; u16 timeout; + u16 ssn_last_drop; u8 dialog_token; bool first_time; /* is it 1-st time this buffer used? */ }; -- cgit v1.2.3 From ff974e4083341383d3dd4079e52ed30f57f376f0 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:08 +0300 Subject: wil6210: debugfs interface to send raw WMI command Debug aid Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 3c3abb6f30fe..8767f4ce33f4 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -513,6 +513,46 @@ static const struct file_operations fops_txmgmt = { .open = simple_open, }; +/* Write WMI command (w/o mbox header) to this file to send it + * WMI starts from wil6210_mbox_hdr_wmi header + */ +static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + struct wil6210_mbox_hdr_wmi *wmi; + void *cmd; + int cmdlen = len - sizeof(struct wil6210_mbox_hdr_wmi); + u16 cmdid; + int rc, rc1; + + if (cmdlen <= 0) + return -EINVAL; + + wmi = kmalloc(len, GFP_KERNEL); + if (!wmi) + return -ENOMEM; + + rc = simple_write_to_buffer(wmi, len, ppos, buf, len); + if (rc < 0) + return rc; + + cmd = &wmi[1]; + cmdid = le16_to_cpu(wmi->id); + + rc1 = wmi_send(wil, cmdid, cmd, cmdlen); + kfree(wmi); + + wil_info(wil, "%s(0x%04x[%d]) -> %d\n", __func__, cmdid, cmdlen, rc1); + + return rc; +} + +static const struct file_operations fops_wmi = { + .write = wil_write_file_wmi, + .open = simple_open, +}; + static void wil_seq_hexdump(struct seq_file *s, void *p, int len, const char *prefix) { @@ -838,6 +878,7 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset); debugfs_create_file("rxon", S_IWUSR, dbg, wil, &fops_rxon); debugfs_create_file("tx_mgmt", S_IWUSR, dbg, wil, &fops_txmgmt); + debugfs_create_file("wmi_send", S_IWUSR, dbg, wil, &fops_wmi); debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp); wil->rgf_blob.data = (void * __force)wil->csr + 0; -- cgit v1.2.3 From 4b63261c7d203472a1670d4199ee7754d52150e9 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:09 +0300 Subject: wil6210: writeable ITR registers Interrupt threshold registers may be written to. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 8767f4ce33f4..4cb54eb6c8fa 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -321,11 +321,11 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, if (IS_ERR_OR_NULL(d)) return -ENODEV; - wil_debugfs_create_iomem_x32("TRSH", S_IRUGO, d, wil->csr + + wil_debugfs_create_iomem_x32("TRSH", S_IRUGO | S_IWUSR, d, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); - wil_debugfs_create_iomem_x32("DATA", S_IRUGO, d, wil->csr + + wil_debugfs_create_iomem_x32("DATA", S_IRUGO | S_IWUSR, d, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_DATA)); - wil_debugfs_create_iomem_x32("CTL", S_IRUGO, d, wil->csr + + wil_debugfs_create_iomem_x32("CTL", S_IRUGO | S_IWUSR, d, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); return 0; -- cgit v1.2.3 From 92b6747eedc300680de5063c642789d239dcbfbc Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:10 +0300 Subject: wil6210: print error when notifying about FW error Print to dmesg when FW error notification is about to be sent Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/interrupt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 73593aa3cd98..e4aba53c20e4 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -257,6 +257,7 @@ static void wil_notify_fw_error(struct wil6210_priv *wil) [1] = "EVENT=FW_ERROR", [2] = NULL, }; + wil_err(wil, "Notify about firmware error\n"); kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); } -- cgit v1.2.3 From 2a91d7d06bae371c13ce09e7976cb1470ed67be7 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:11 +0300 Subject: wil6210: debug print when scan request state changes Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 1 + drivers/net/wireless/ath/wil6210/main.c | 2 ++ drivers/net/wireless/ath/wil6210/wmi.c | 3 +++ 3 files changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index a3042cd3d308..850a2f11e0f9 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -287,6 +287,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, return -EBUSY; } + wil_dbg_misc(wil, "Start scan_request 0x%p\n", request); wil->scan_request = request; mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 11e6d9d22eae..33b89d1e4570 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -552,6 +552,8 @@ static int __wil_down(struct wil6210_priv *wil) napi_disable(&wil->napi_tx); if (wil->scan_request) { + wil_dbg_misc(wil, "Abort scan_request 0x%p\n", + wil->scan_request); del_timer_sync(&wil->scan_timer); cfg80211_scan_done(wil->scan_request, true); wil->scan_request = NULL; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 1c5e6e995437..281a28f24be6 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -362,6 +362,9 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, bool aborted = (data->status != WMI_SCAN_SUCCESS); wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); + wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n", + wil->scan_request, aborted); + del_timer_sync(&wil->scan_timer); cfg80211_scan_done(wil->scan_request, aborted); wil->scan_request = NULL; -- cgit v1.2.3 From d45cff9f6151bf40006a97804a83e55abccbc21b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:12 +0300 Subject: wil6210: Use "name = value" format in the debugfs Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 4cb54eb6c8fa..89f0d094c5a2 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -755,8 +755,8 @@ static int wil_temp_debugfs_show(struct seq_file *s, void *data) return 0; } - print_temp(s, "MAC temperature :", t_m); - print_temp(s, "Radio temperature :", t_r); + print_temp(s, "T_mac =", t_m); + print_temp(s, "T_radio =", t_r); return 0; } -- cgit v1.2.3 From 9eb82d43da0618f6bab78de0f18e7405085dd955 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:13 +0300 Subject: wil6210: add 'freq' and 'link' debugfs entries Expose operational frequency and link info Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/cfg80211.c | 4 +- drivers/net/wireless/ath/wil6210/debugfs.c | 76 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 2 + 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 850a2f11e0f9..4ac2c208c9ba 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -104,8 +104,8 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type) return -EOPNOTSUPP; } -static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, - struct station_info *sinfo) +int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, + struct station_info *sinfo) { struct wmi_notify_req_cmd cmd = { .cid = cid, diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 89f0d094c5a2..d6acb309dd16 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -773,6 +773,80 @@ static const struct file_operations fops_temp = { .llseek = seq_lseek, }; +/*---------freq------------*/ +static int wil_freq_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + struct wireless_dev *wdev = wil_to_wdev(wil); + u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0; + + seq_printf(s, "Freq = %d\n", freq); + + return 0; +} + +static int wil_freq_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_freq_debugfs_show, inode->i_private); +} + +static const struct file_operations fops_freq = { + .open = wil_freq_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + +/*---------link------------*/ +static int wil_link_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + struct station_info sinfo; + int i, rc; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + struct wil_sta_info *p = &wil->sta[i]; + char *status = "unknown"; + switch (p->status) { + case wil_sta_unused: + status = "unused "; + break; + case wil_sta_conn_pending: + status = "pending "; + break; + case wil_sta_connected: + status = "connected"; + break; + } + seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, + (p->data_port_open ? " data_port_open" : "")); + + if (p->status == wil_sta_connected) { + rc = wil_cid_fill_sinfo(wil, i, &sinfo); + if (rc) + return rc; + + seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs); + seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs); + seq_printf(s, " SQ = %d\n", sinfo.signal); + } + } + + return 0; +} + +static int wil_link_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_link_debugfs_show, inode->i_private); +} + +static const struct file_operations fops_link = { + .open = wil_link_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + /*---------Station matrix------------*/ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) { @@ -880,6 +954,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("tx_mgmt", S_IWUSR, dbg, wil, &fops_txmgmt); debugfs_create_file("wmi_send", S_IWUSR, dbg, wil, &fops_wmi); debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp); + debugfs_create_file("freq", S_IRUGO, dbg, wil, &fops_freq); + debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link); wil->rgf_blob.data = (void * __force)wil->csr + 0; wil->rgf_blob.size = 0xa000; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 4cbb8cec29c6..fd6ff0926f3b 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -512,6 +512,8 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, int wil6210_debugfs_init(struct wil6210_priv *wil); void wil6210_debugfs_remove(struct wil6210_priv *wil); +int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, + struct station_info *sinfo); struct wireless_dev *wil_cfg80211_init(struct device *dev); void wil_wdev_free(struct wil6210_priv *wil); -- cgit v1.2.3 From 194b482b5055d50b481e0c5651bab90623deb611 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:14 +0300 Subject: wil6210: Debug print GRO Rx result Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 0318cd2650ce..a89a5c68e006 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -525,6 +525,17 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) ndev->stats.rx_bytes += len; stats->rx_bytes += len; } + { + static const char * const gro_res_str[] = { + [GRO_MERGED] = "GRO_MERGED", + [GRO_MERGED_FREE] = "GRO_MERGED_FREE", + [GRO_HELD] = "GRO_HELD", + [GRO_NORMAL] = "GRO_NORMAL", + [GRO_DROP] = "GRO_DROP", + }; + wil_dbg_txrx(wil, "Rx complete %d bytes => %s,\n", + len, gro_res_str[rc]); + } } /** -- cgit v1.2.3 From 5aed13932a36a4c12aad4d84b98d439f5b7af34e Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:15 +0300 Subject: wil6210: avoid dmesg pollution by Tx errors On Tx path, when vring for the destination not found, it was considered as error and message was printed unconditionally. However, this situation is normal after disconnect. If disconnect was while heavy traffic load, lots of Tx packets will be dropped and this would cause significant amount of prints in dmesg. Demote messages priority from 'error' to 'debug'. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index a89a5c68e006..c06d74adb3fc 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -771,7 +771,7 @@ static struct vring *wil_tx_bcast(struct wil6210_priv *wil, goto found; } - wil_err(wil, "Tx while no vrings active?\n"); + wil_dbg_txrx(wil, "Tx while no vrings active?\n"); return NULL; @@ -1031,7 +1031,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) vring = wil_tx_bcast(wil, skb); } if (!vring) { - wil_err(wil, "No Tx VRING found for %pM\n", eth->h_dest); + wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); goto drop; } /* set up vring entry */ -- cgit v1.2.3 From fc58f6811a9edae55f64538bd361945572c366f6 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:16 +0300 Subject: wil6210: fix disconnect handling for AP For the AP-like interface, if "disconnect all" requested, every station should be deleted with cfg80211_del_sta(). Implement this behavior. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 33b89d1e4570..6cc4791d6022 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -61,11 +61,24 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) { uint i; + struct net_device *ndev = wil_to_ndev(wil); + struct wireless_dev *wdev = wil->wdev; struct wil_sta_info *sta = &wil->sta[cid]; + wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid, + sta->status); sta->data_port_open = false; if (sta->status != wil_sta_unused) { wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING); + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + /* AP-like interface */ + cfg80211_del_sta(ndev, sta->addr, GFP_KERNEL); + break; + default: + break; + } sta->status = wil_sta_unused; } @@ -119,11 +132,6 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid) clear_bit(wil_status_fwconnecting, &wil->status); break; default: - /* AP-like interface and monitor: - * never scan, always connected - */ - if (bssid) - cfg80211_del_sta(ndev, bssid, GFP_KERNEL); break; } } -- cgit v1.2.3 From 84d94d520495d443a6e8202d7f1e190106edbef6 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:17 +0300 Subject: wil6210: remove unused #include In the pcie_bus.c, knowledge about debugfs is not necessary Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/pcie_bus.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index e5d7ffe7d4e6..05c1c9d6f9c2 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -15,7 +15,6 @@ */ #include -#include #include #include -- cgit v1.2.3 From f8cd9f8b327aaf74ab15b8e8146e8102fe90dbb6 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:18 +0300 Subject: wil6210: map additional registers on target New registers area introduced, mark corresponded address range as valid Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 281a28f24be6..b92a042af2c3 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -75,6 +75,7 @@ static const struct { {0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */ {0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */ {0x880000, 0x88a000, 0x880000}, /* various RGF */ + {0x88b000, 0x88c000, 0x88b000}, /* Pcie_ext_rgf */ {0x8c0000, 0x949000, 0x8c0000}, /* trivial mapping for upper area */ /* * 920000..930000 ucode code RAM -- cgit v1.2.3 From 95266dc07d52b28d7cedb755e2ff4254bb2d7eec Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:19 +0300 Subject: wil6210: fix for unreachable code in wmi_recv_cmd As reported by Dan Carpenter : The patch a715c7ddd65a: "wil6210: improve debug for WMI receive" from May 29, 2014, leads to the following static checker warning: drivers/net/wireless/ath/wil6210/wmi.c:746 wmi_recv_cmd() info: ignoring unreachable code. drivers/net/wireless/ath/wil6210/wmi.c 739 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); 740 { 741 int q = queue_work(wil->wmi_wq, 742 &wil->wmi_event_worker); 743 wil_dbg_wmi(wil, "queue_work -> %d\n", q); 744 } 745 } 746 if (n > 1) ^^^^^^^^^^ We never reach this if statemtent. 747 wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n); 748 } Exit loop with "break", not "return". Reported-by: Dan Carpenter Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/wmi.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index b92a042af2c3..a136dab560e2 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -683,14 +683,12 @@ void wmi_recv_cmd(struct wil6210_priv *wil) for (n = 0;; n++) { u16 len; + bool q; r->head = ioread32(wil->csr + HOST_MBOX + offsetof(struct wil6210_mbox_ctl, rx.head)); - if (r->tail == r->head) { - if (n == 0) - wil_dbg_wmi(wil, "No events?\n"); - return; - } + if (r->tail == r->head) + break; wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n", r->head, r->tail); @@ -699,14 +697,14 @@ void wmi_recv_cmd(struct wil6210_priv *wil) sizeof(struct wil6210_mbox_ring_desc)); if (d_tail.sync == 0) { wil_err(wil, "Mbox evt not owned by FW?\n"); - return; + break; } /* read cmd header from descriptor */ if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) { wil_err(wil, "Mbox evt at 0x%08x?\n", le32_to_cpu(d_tail.addr)); - return; + break; } len = le16_to_cpu(hdr.len); wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n", @@ -720,7 +718,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) event.wmi) + len, 4), GFP_KERNEL); if (!evt) - return; + break; evt->event.hdr = hdr; cmd = (void *)&evt->event.wmi; @@ -752,14 +750,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil) spin_lock_irqsave(&wil->wmi_ev_lock, flags); list_add_tail(&evt->list, &wil->pending_wmi_ev); spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); - { - int q = queue_work(wil->wmi_wq, - &wil->wmi_event_worker); - wil_dbg_wmi(wil, "queue_work -> %d\n", q); - } + q = queue_work(wil->wmi_wq, &wil->wmi_event_worker); + wil_dbg_wmi(wil, "queue_work -> %d\n", q); } - if (n > 1) - wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n); + /* normally, 1 event per IRQ should be processed */ + wil_dbg_wmi(wil, "%s -> %d events queued\n", __func__, n); } int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, -- cgit v1.2.3 From 2bdc0700263ff2c557fa566881721394abfc2ea4 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:20 +0300 Subject: wil6210: work around for platforms with broken INTx There are platforms where INTx can't be routed by ACPI, this leads to pci_enable_device failure. Re-try pretending we have MSI already configured; in this case pci_enable_device do not try to configure INTx. However, MSI could still work. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/pcie_bus.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 05c1c9d6f9c2..77b6272d93fb 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -35,6 +35,13 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) { struct pci_dev *pdev = wil->pdev; int rc; + /* on platforms with buggy ACPI, pdev->msi_enabled may be set to + * allow pci_enable_device to work. This indicates INTx was not routed + * and only MSI should be used + */ + int msi_only = pdev->msi_enabled; + + pdev->msi_enabled = 0; pci_set_master(pdev); @@ -66,6 +73,12 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) wil->n_msi = use_msi; + if ((wil->n_msi == 0) && msi_only) { + wil_err(wil, "Interrupt pin not routed, unable to use INTx\n"); + rc = -ENODEV; + goto stop_master; + } + rc = wil6210_init_irq(wil, pdev->irq); if (rc) goto stop_master; @@ -124,9 +137,16 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) rc = pci_enable_device(pdev); if (rc) { - dev_err(&pdev->dev, "pci_enable_device failed\n"); - return -ENODEV; + dev_err(&pdev->dev, + "pci_enable_device failed, retry with MSI only\n"); + /* Work around for platforms that can't allocate IRQ: + * retry with MSI only + */ + pdev->msi_enabled = 1; + rc = pci_enable_device(pdev); } + if (rc) + return -ENODEV; /* rollback to err_disable_pdev */ rc = pci_request_region(pdev, 0, WIL_NAME); -- cgit v1.2.3 From 84bb29b7ab71daed9318073dd33632274373a1ea Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:21 +0300 Subject: wil6210: add 'info' debugfs entry Use 'info' debugfs entry for misc. assorted information. Start with indication whether platform is AC-powered; will use it later for power related decisions Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index d6acb309dd16..8bf00aca321b 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "wil6210.h" #include "txrx.h" @@ -847,6 +848,29 @@ static const struct file_operations fops_link = { .llseek = seq_lseek, }; +/*---------info------------*/ +static int wil_info_debugfs_show(struct seq_file *s, void *data) +{ + int is_ac = power_supply_is_system_supplied(); + + /* >0 : AC; 0 : battery; <0 : error */ + seq_printf(s, "AC powered : %d\n", is_ac); + + return 0; +} + +static int wil_info_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_info_debugfs_show, inode->i_private); +} + +static const struct file_operations fops_info = { + .open = wil_info_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + /*---------Station matrix------------*/ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) { @@ -956,6 +980,7 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp); debugfs_create_file("freq", S_IRUGO, dbg, wil, &fops_freq); debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link); + debugfs_create_file("info", S_IRUGO, dbg, wil, &fops_info); wil->rgf_blob.data = (void * __force)wil->csr + 0; wil->rgf_blob.size = 0xa000; -- cgit v1.2.3 From be299858d0611ee9f43fab7fa6dbea8671748267 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:22 +0300 Subject: wil6210: interrupt statistics Track number of interrupts and Tx/Rx packets; expose through debugfs 'info'. Reset upon read. Used to analyse effectivness of interrupt coalescing and NAPI. Read twice with some interval like cat info > /dev/null; sleep 1; cat info Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 11 +++++++++++ drivers/net/wireless/ath/wil6210/interrupt.c | 2 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 3 files changed, 14 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 8bf00aca321b..94ac69a380b8 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -851,10 +851,21 @@ static const struct file_operations fops_link = { /*---------info------------*/ static int wil_info_debugfs_show(struct seq_file *s, void *data) { + struct wil6210_priv *wil = s->private; + struct net_device *ndev = wil_to_ndev(wil); int is_ac = power_supply_is_system_supplied(); + int rx = atomic_xchg(&wil->isr_count_rx, 0); + int tx = atomic_xchg(&wil->isr_count_tx, 0); + static ulong rxf_old, txf_old; + ulong rxf = ndev->stats.rx_packets; + ulong txf = ndev->stats.tx_packets; /* >0 : AC; 0 : battery; <0 : error */ seq_printf(s, "AC powered : %d\n", is_ac); + seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old); + seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old); + rxf_old = rxf; + txf_old = txf; return 0; } diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index e4aba53c20e4..67f1002a03a1 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -208,6 +208,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) /* Rx IRQ will be enabled when NAPI processing finished */ + atomic_inc(&wil->isr_count_rx); return IRQ_HANDLED; } @@ -246,6 +247,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) /* Tx IRQ will be enabled when NAPI processing finished */ + atomic_inc(&wil->isr_count_tx); return IRQ_HANDLED; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index fd6ff0926f3b..424906635f05 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -412,6 +412,7 @@ struct wil6210_priv { struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */ /* statistics */ struct wil6210_stats stats; + atomic_t isr_count_rx, isr_count_tx; /* debugfs */ struct dentry *debug; struct debugfs_blob_wrapper fw_code_blob; -- cgit v1.2.3 From 55f8f68017a2d1f4836d50ac5c6473f10c22e557 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 16 Jun 2014 19:37:23 +0300 Subject: wil6210: track Tx queue state Provide both event (netif_tx_[stop|wake]) tracking via printk; and state via debugfs 'info' Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 16 ++++++++++++++++ drivers/net/wireless/ath/wil6210/main.c | 2 ++ drivers/net/wireless/ath/wil6210/txrx.c | 8 ++++++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 94ac69a380b8..7d1ef4eea0d8 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -859,6 +859,7 @@ static int wil_info_debugfs_show(struct seq_file *s, void *data) static ulong rxf_old, txf_old; ulong rxf = ndev->stats.rx_packets; ulong txf = ndev->stats.tx_packets; + unsigned int i; /* >0 : AC; 0 : battery; <0 : error */ seq_printf(s, "AC powered : %d\n", is_ac); @@ -867,6 +868,21 @@ static int wil_info_debugfs_show(struct seq_file *s, void *data) rxf_old = rxf; txf_old = txf; + +#define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \ + " " __stringify(x) : "" + + for (i = 0; i < ndev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(ndev, i); + unsigned long state = txq->state; + + seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state, + CHECK_QSTATE(DRV_XOFF), + CHECK_QSTATE(STACK_XOFF), + CHECK_QSTATE(FROZEN) + ); + } +#undef CHECK_QSTATE return 0; } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 6cc4791d6022..53a689ed7c7d 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -473,6 +473,7 @@ void wil_link_on(struct wil6210_priv *wil) wil_dbg_misc(wil, "%s()\n", __func__); netif_carrier_on(ndev); + wil_dbg_misc(wil, "netif_tx_wake : link on\n"); netif_tx_wake_all_queues(ndev); } @@ -483,6 +484,7 @@ void wil_link_off(struct wil6210_priv *wil) wil_dbg_misc(wil, "%s()\n", __func__); netif_tx_stop_all_queues(ndev); + wil_dbg_misc(wil, "netif_tx_stop : link off\n"); netif_carrier_off(ndev); } diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index c06d74adb3fc..af4b93e4beb5 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1038,8 +1038,10 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) rc = wil_tx_vring(wil, vring, skb); /* do we still have enough room in the vring? */ - if (wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring)) + if (wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring)) { netif_tx_stop_all_queues(wil_to_ndev(wil)); + wil_dbg_txrx(wil, "netif_tx_stop : ring full\n"); + } switch (rc) { case 0: @@ -1153,8 +1155,10 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) txdata->last_idle = get_cycles(); } - if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring)) + if (wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring)) { + wil_dbg_txrx(wil, "netif_tx_wake : ring not full\n"); netif_tx_wake_all_queues(wil_to_ndev(wil)); + } return done; } -- cgit v1.2.3 From d4150246eb403eee756516c98e7ebc5792cb34f7 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 18 Jun 2014 16:51:29 +0200 Subject: drivers/net/wireless/rt2x00/rt2x00dev.c: remove null test before kfree Fix checkpatch warning: WARNING: kfree(NULL) is safe this check is probably not required Cc: Ivo van Doorn Cc: Helmut Schaa Signed-off-by: Fabian Frederick Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 72e3e8138111..c6ae9a495b77 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1455,8 +1455,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) /* * Free the driver data. */ - if (rt2x00dev->drv_data) - kfree(rt2x00dev->drv_data); + kfree(rt2x00dev->drv_data); } EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev); -- cgit v1.2.3 From dff6277658fc3609ccd6bf0a6dc487e7bf1ac6d6 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 18 Jun 2014 19:43:31 +0200 Subject: SPECTRUM_CS: ioport_map/unmap relies on HAS_IOPORT_MAP Fixing following sh-allmodconfig errors reported on kisskb " drivers/net/wireless/orinoco/spectrum_cs.c:216:2: error: implicit declaration of function 'ioport_map' [-Werror=implicit-function-declaration] drivers/net/wireless/orinoco/spectrum_cs.c:273:3: error: implicit declaration of function 'ioport_unmap' [-Werror=implicit-function-declaration] " Cc: "John W. Linville" Cc: Paul Gortmaker Cc: linux-wireless@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig index 60819bcf4377..a8aab9f99d79 100644 --- a/drivers/net/wireless/orinoco/Kconfig +++ b/drivers/net/wireless/orinoco/Kconfig @@ -122,7 +122,7 @@ config PCMCIA_HERMES config PCMCIA_SPECTRUM tristate "Symbol Spectrum24 Trilogy PCMCIA card support" - depends on PCMCIA && HERMES + depends on PCMCIA && HERMES && HAS_IOPORT_MAP ---help--- This is a driver for 802.11b cards using RAM-loadable Symbol -- cgit v1.2.3 From 11c761c4816c2b2d7704a94e5ab3f010d816e601 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 18 Jun 2014 19:48:02 +0200 Subject: LIBERTAS_CS: ioport_map/unmap relies on HAS_IOPORT_MAP Fixing following sh-allmodconfig errors reported on kisskb " drivers/net/wireless/libertas/if_cs.c:826:3: error: implicit declaration of function 'ioport_unmap' [-Werror=implicit-function-declaration] drivers/net/wireless/libertas/if_cs.c:878:2: error: implicit declaration of function 'ioport_map' [-Werror=implicit-function-declaration] " Cc: "John W. Linville" Cc: Dan Williams Cc: linux-wireless@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig index 0485c9957575..e6268ceacbf1 100644 --- a/drivers/net/wireless/libertas/Kconfig +++ b/drivers/net/wireless/libertas/Kconfig @@ -16,7 +16,7 @@ config LIBERTAS_USB config LIBERTAS_CS tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" - depends on LIBERTAS && PCMCIA + depends on LIBERTAS && PCMCIA && HAS_IOPORT_MAP ---help--- A driver for Marvell Libertas 8385 CompactFlash devices. -- cgit v1.2.3 From 2e91606f5e1ec7329557dfc0e298c4c021acbb80 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 18 Jun 2014 19:55:38 +0200 Subject: PCMCIA_HERMES: ioport_map/unmap relies on HAS_IOPORT_MAP Fixing following sh-allmodconfig errors reported on kisskb " drivers/net/wireless/orinoco/orinoco_cs.c:153:2: error: implicit declaration of function 'ioport_map' [-Werror=implicit-function-declaration] drivers/net/wireless/orinoco/orinoco_cs.c:205:3: error: implicit declaration of function 'ioport_unmap' [-Werror=implicit-function-declaration] " Cc: "John W. Linville" Cc: Paul Gortmaker Cc: linux-wireless@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig index a8aab9f99d79..60698b020851 100644 --- a/drivers/net/wireless/orinoco/Kconfig +++ b/drivers/net/wireless/orinoco/Kconfig @@ -107,7 +107,7 @@ config PCI_HERMES config PCMCIA_HERMES tristate "Hermes PCMCIA card support" - depends on PCMCIA && HERMES + depends on PCMCIA && HERMES && HAS_IOPORT_MAP ---help--- A driver for "Hermes" chipset based PCMCIA wireless adaptors, such as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ -- cgit v1.2.3 From 4c33f83a02a065a3c3751a862c2231e38b3da99e Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Thu, 5 Jun 2014 00:18:21 +0000 Subject: i40e/i40evf: i40e_register.h update This updates the register file for new hardware. The format of the file has changed requiring drivers to declare I40E_MASK. I40E_MASK is to be used with 32 bit registers. This patch also updates the drivers to accommodate the register changes. Change-ID: If9bc8d736391024cbf99054efe50f9acc12ee4f1 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 30 +- drivers/net/ethernet/intel/i40e/i40e_register.h | 5011 ++++++++------------- drivers/net/ethernet/intel/i40e/i40e_type.h | 3 + drivers/net/ethernet/intel/i40evf/i40e_register.h | 5011 ++++++++------------- drivers/net/ethernet/intel/i40evf/i40e_type.h | 3 + 5 files changed, 3728 insertions(+), 6330 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 275ca9a1719e..374f36b84513 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5744,26 +5744,28 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf) /* find what triggered the MDD event */ reg = rd32(hw, I40E_GL_MDET_TX); if (reg & I40E_GL_MDET_TX_VALID_MASK) { - u8 func = (reg & I40E_GL_MDET_TX_FUNCTION_MASK) - >> I40E_GL_MDET_TX_FUNCTION_SHIFT; - u8 event = (reg & I40E_GL_MDET_TX_EVENT_SHIFT) - >> I40E_GL_MDET_TX_EVENT_SHIFT; - u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) - >> I40E_GL_MDET_TX_QUEUE_SHIFT; + u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >> + I40E_GL_MDET_TX_PF_NUM_SHIFT; + u8 vf_num = (reg & I40E_GL_MDET_TX_VF_NUM_MASK) >> + I40E_GL_MDET_TX_VF_NUM_SHIFT; + u8 event = (reg & I40E_GL_MDET_TX_EVENT_SHIFT) >> + I40E_GL_MDET_TX_EVENT_SHIFT; + u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >> + I40E_GL_MDET_TX_QUEUE_SHIFT; dev_info(&pf->pdev->dev, - "Malicious Driver Detection event 0x%02x on TX queue %d of function 0x%02x\n", - event, queue, func); + "Malicious Driver Detection event 0x%02x on TX queue %d pf number 0x%02x vf number 0x%02x\n", + event, queue, pf_num, vf_num); wr32(hw, I40E_GL_MDET_TX, 0xffffffff); mdd_detected = true; } reg = rd32(hw, I40E_GL_MDET_RX); if (reg & I40E_GL_MDET_RX_VALID_MASK) { - u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) - >> I40E_GL_MDET_RX_FUNCTION_SHIFT; - u8 event = (reg & I40E_GL_MDET_RX_EVENT_SHIFT) - >> I40E_GL_MDET_RX_EVENT_SHIFT; - u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) - >> I40E_GL_MDET_RX_QUEUE_SHIFT; + u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >> + I40E_GL_MDET_RX_FUNCTION_SHIFT; + u8 event = (reg & I40E_GL_MDET_RX_EVENT_SHIFT) >> + I40E_GL_MDET_RX_EVENT_SHIFT; + u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >> + I40E_GL_MDET_RX_QUEUE_SHIFT; dev_info(&pf->pdev->dev, "Malicious Driver Detection event 0x%02x on RX queue %d of function 0x%02x\n", event, queue, func); diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h index 947de98500f3..65d3c8bb2d5b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_register.h +++ b/drivers/net/ethernet/intel/i40e/i40e_register.h @@ -27,4648 +27,3343 @@ #ifndef _I40E_REGISTER_H_ #define _I40E_REGISTER_H_ -#define I40E_GL_GP_FUSE(_i) (0x0009400C + ((_i) * 4)) /* _i=0...28 */ -#define I40E_GL_GP_FUSE_MAX_INDEX 28 -#define I40E_GL_GP_FUSE_GL_GP_FUSE_SHIFT 0 -#define I40E_GL_GP_FUSE_GL_GP_FUSE_MASK (0xFFFFFFFF << I40E_GL_GP_FUSE_GL_GP_FUSE_SHIFT) -#define I40E_GLPCI_PM_MUX_NPQ 0x0009C4F4 -#define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT 0 -#define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_MASK (0x7 << I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT) -#define I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_SHIFT 16 -#define I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_MASK (0x1F << I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_SHIFT) -#define I40E_GLPCI_PM_MUX_PFB 0x0009C4F0 -#define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT 0 -#define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_MASK (0x1F << I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT) -#define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT 16 -#define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_MASK (0x7 << I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT) -#define I40E_GLPCI_PQ_MAX_USED_SPC 0x0009C4EC -#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_SHIFT 0 -#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_MASK (0xFF << I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_SHIFT) -#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_SHIFT 8 -#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_MASK (0xFF << I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_SHIFT) -#define I40E_GLPCI_SPARE_BITS_0 0x0009C4F8 -#define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT 0 -#define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_MASK (0xFFFFFFFF << I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT) -#define I40E_GLPCI_SPARE_BITS_1 0x0009C4FC -#define I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_SHIFT 0 -#define I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_MASK (0xFFFFFFFF << I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_SHIFT) -#define I40E_PFPCI_PF_FLUSH_DONE 0x0009C800 -#define I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_SHIFT 0 -#define I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_SHIFT) -#define I40E_PFPCI_VF_FLUSH_DONE 0x0009C600 -#define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT 0 -#define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT) -#define I40E_PFPCI_VF_FLUSH_DONE1(_VF) (0x0009C600 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_PFPCI_VF_FLUSH_DONE1_MAX_INDEX 127 -#define I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_SHIFT 0 -#define I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_SHIFT) -#define I40E_PFPCI_VM_FLUSH_DONE 0x0009C880 -#define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT 0 -#define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT) - -#define I40E_PF_ARQBAH 0x00080180 +#define I40E_GL_ARQBAH 0x000801C0 /* Reset: EMPR */ +#define I40E_GL_ARQBAH_ARQBAH_SHIFT 0 +#define I40E_GL_ARQBAH_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ARQBAH_ARQBAH_SHIFT) +#define I40E_GL_ARQBAL 0x000800C0 /* Reset: EMPR */ +#define I40E_GL_ARQBAL_ARQBAL_SHIFT 0 +#define I40E_GL_ARQBAL_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ARQBAL_ARQBAL_SHIFT) +#define I40E_GL_ARQH 0x000803C0 /* Reset: EMPR */ +#define I40E_GL_ARQH_ARQH_SHIFT 0 +#define I40E_GL_ARQH_ARQH_MASK I40E_MASK(0x3FF, I40E_GL_ARQH_ARQH_SHIFT) +#define I40E_GL_ARQT 0x000804C0 /* Reset: EMPR */ +#define I40E_GL_ARQT_ARQT_SHIFT 0 +#define I40E_GL_ARQT_ARQT_MASK I40E_MASK(0x3FF, I40E_GL_ARQT_ARQT_SHIFT) +#define I40E_GL_ATQBAH 0x00080140 /* Reset: EMPR */ +#define I40E_GL_ATQBAH_ATQBAH_SHIFT 0 +#define I40E_GL_ATQBAH_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ATQBAH_ATQBAH_SHIFT) +#define I40E_GL_ATQBAL 0x00080040 /* Reset: EMPR */ +#define I40E_GL_ATQBAL_ATQBAL_SHIFT 0 +#define I40E_GL_ATQBAL_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ATQBAL_ATQBAL_SHIFT) +#define I40E_GL_ATQH 0x00080340 /* Reset: EMPR */ +#define I40E_GL_ATQH_ATQH_SHIFT 0 +#define I40E_GL_ATQH_ATQH_MASK I40E_MASK(0x3FF, I40E_GL_ATQH_ATQH_SHIFT) +#define I40E_GL_ATQLEN 0x00080240 /* Reset: EMPR */ +#define I40E_GL_ATQLEN_ATQLEN_SHIFT 0 +#define I40E_GL_ATQLEN_ATQLEN_MASK I40E_MASK(0x3FF, I40E_GL_ATQLEN_ATQLEN_SHIFT) +#define I40E_GL_ATQLEN_ATQVFE_SHIFT 28 +#define I40E_GL_ATQLEN_ATQVFE_MASK I40E_MASK(0x1, I40E_GL_ATQLEN_ATQVFE_SHIFT) +#define I40E_GL_ATQLEN_ATQOVFL_SHIFT 29 +#define I40E_GL_ATQLEN_ATQOVFL_MASK I40E_MASK(0x1, I40E_GL_ATQLEN_ATQOVFL_SHIFT) +#define I40E_GL_ATQLEN_ATQCRIT_SHIFT 30 +#define I40E_GL_ATQLEN_ATQCRIT_MASK I40E_MASK(0x1, I40E_GL_ATQLEN_ATQCRIT_SHIFT) +#define I40E_GL_ATQLEN_ATQENABLE_SHIFT 31 +#define I40E_GL_ATQLEN_ATQENABLE_MASK I40E_MASK(0x1, I40E_GL_ATQLEN_ATQENABLE_SHIFT) +#define I40E_GL_ATQT 0x00080440 /* Reset: EMPR */ +#define I40E_GL_ATQT_ATQT_SHIFT 0 +#define I40E_GL_ATQT_ATQT_MASK I40E_MASK(0x3FF, I40E_GL_ATQT_ATQT_SHIFT) +#define I40E_PF_ARQBAH 0x00080180 /* Reset: EMPR */ #define I40E_PF_ARQBAH_ARQBAH_SHIFT 0 -#define I40E_PF_ARQBAH_ARQBAH_MASK (0xFFFFFFFF << I40E_PF_ARQBAH_ARQBAH_SHIFT) -#define I40E_PF_ARQBAL 0x00080080 +#define I40E_PF_ARQBAH_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_ARQBAH_ARQBAH_SHIFT) +#define I40E_PF_ARQBAL 0x00080080 /* Reset: EMPR */ #define I40E_PF_ARQBAL_ARQBAL_SHIFT 0 -#define I40E_PF_ARQBAL_ARQBAL_MASK (0xFFFFFFFF << I40E_PF_ARQBAL_ARQBAL_SHIFT) -#define I40E_PF_ARQH 0x00080380 +#define I40E_PF_ARQBAL_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_ARQBAL_ARQBAL_SHIFT) +#define I40E_PF_ARQH 0x00080380 /* Reset: EMPR */ #define I40E_PF_ARQH_ARQH_SHIFT 0 -#define I40E_PF_ARQH_ARQH_MASK (0x3FF << I40E_PF_ARQH_ARQH_SHIFT) -#define I40E_PF_ARQLEN 0x00080280 +#define I40E_PF_ARQH_ARQH_MASK I40E_MASK(0x3FF, I40E_PF_ARQH_ARQH_SHIFT) +#define I40E_PF_ARQLEN 0x00080280 /* Reset: EMPR */ #define I40E_PF_ARQLEN_ARQLEN_SHIFT 0 -#define I40E_PF_ARQLEN_ARQLEN_MASK (0x3FF << I40E_PF_ARQLEN_ARQLEN_SHIFT) +#define I40E_PF_ARQLEN_ARQLEN_MASK I40E_MASK(0x3FF, I40E_PF_ARQLEN_ARQLEN_SHIFT) #define I40E_PF_ARQLEN_ARQVFE_SHIFT 28 -#define I40E_PF_ARQLEN_ARQVFE_MASK (0x1 << I40E_PF_ARQLEN_ARQVFE_SHIFT) +#define I40E_PF_ARQLEN_ARQVFE_MASK I40E_MASK(0x1, I40E_PF_ARQLEN_ARQVFE_SHIFT) #define I40E_PF_ARQLEN_ARQOVFL_SHIFT 29 -#define I40E_PF_ARQLEN_ARQOVFL_MASK (0x1 << I40E_PF_ARQLEN_ARQOVFL_SHIFT) +#define I40E_PF_ARQLEN_ARQOVFL_MASK I40E_MASK(0x1, I40E_PF_ARQLEN_ARQOVFL_SHIFT) #define I40E_PF_ARQLEN_ARQCRIT_SHIFT 30 -#define I40E_PF_ARQLEN_ARQCRIT_MASK (0x1 << I40E_PF_ARQLEN_ARQCRIT_SHIFT) +#define I40E_PF_ARQLEN_ARQCRIT_MASK I40E_MASK(0x1, I40E_PF_ARQLEN_ARQCRIT_SHIFT) #define I40E_PF_ARQLEN_ARQENABLE_SHIFT 31 -#define I40E_PF_ARQLEN_ARQENABLE_MASK (0x1 << I40E_PF_ARQLEN_ARQENABLE_SHIFT) -#define I40E_PF_ARQT 0x00080480 +#define I40E_PF_ARQLEN_ARQENABLE_MASK I40E_MASK(0x1, I40E_PF_ARQLEN_ARQENABLE_SHIFT) +#define I40E_PF_ARQT 0x00080480 /* Reset: EMPR */ #define I40E_PF_ARQT_ARQT_SHIFT 0 -#define I40E_PF_ARQT_ARQT_MASK (0x3FF << I40E_PF_ARQT_ARQT_SHIFT) -#define I40E_PF_ATQBAH 0x00080100 +#define I40E_PF_ARQT_ARQT_MASK I40E_MASK(0x3FF, I40E_PF_ARQT_ARQT_SHIFT) +#define I40E_PF_ATQBAH 0x00080100 /* Reset: EMPR */ #define I40E_PF_ATQBAH_ATQBAH_SHIFT 0 -#define I40E_PF_ATQBAH_ATQBAH_MASK (0xFFFFFFFF << I40E_PF_ATQBAH_ATQBAH_SHIFT) -#define I40E_PF_ATQBAL 0x00080000 +#define I40E_PF_ATQBAH_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_ATQBAH_ATQBAH_SHIFT) +#define I40E_PF_ATQBAL 0x00080000 /* Reset: EMPR */ #define I40E_PF_ATQBAL_ATQBAL_SHIFT 0 -#define I40E_PF_ATQBAL_ATQBAL_MASK (0xFFFFFFFF << I40E_PF_ATQBAL_ATQBAL_SHIFT) -#define I40E_PF_ATQH 0x00080300 +#define I40E_PF_ATQBAL_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_ATQBAL_ATQBAL_SHIFT) +#define I40E_PF_ATQH 0x00080300 /* Reset: EMPR */ #define I40E_PF_ATQH_ATQH_SHIFT 0 -#define I40E_PF_ATQH_ATQH_MASK (0x3FF << I40E_PF_ATQH_ATQH_SHIFT) -#define I40E_PF_ATQLEN 0x00080200 +#define I40E_PF_ATQH_ATQH_MASK I40E_MASK(0x3FF, I40E_PF_ATQH_ATQH_SHIFT) +#define I40E_PF_ATQLEN 0x00080200 /* Reset: EMPR */ #define I40E_PF_ATQLEN_ATQLEN_SHIFT 0 -#define I40E_PF_ATQLEN_ATQLEN_MASK (0x3FF << I40E_PF_ATQLEN_ATQLEN_SHIFT) +#define I40E_PF_ATQLEN_ATQLEN_MASK I40E_MASK(0x3FF, I40E_PF_ATQLEN_ATQLEN_SHIFT) #define I40E_PF_ATQLEN_ATQVFE_SHIFT 28 -#define I40E_PF_ATQLEN_ATQVFE_MASK (0x1 << I40E_PF_ATQLEN_ATQVFE_SHIFT) +#define I40E_PF_ATQLEN_ATQVFE_MASK I40E_MASK(0x1, I40E_PF_ATQLEN_ATQVFE_SHIFT) #define I40E_PF_ATQLEN_ATQOVFL_SHIFT 29 -#define I40E_PF_ATQLEN_ATQOVFL_MASK (0x1 << I40E_PF_ATQLEN_ATQOVFL_SHIFT) +#define I40E_PF_ATQLEN_ATQOVFL_MASK I40E_MASK(0x1, I40E_PF_ATQLEN_ATQOVFL_SHIFT) #define I40E_PF_ATQLEN_ATQCRIT_SHIFT 30 -#define I40E_PF_ATQLEN_ATQCRIT_MASK (0x1 << I40E_PF_ATQLEN_ATQCRIT_SHIFT) +#define I40E_PF_ATQLEN_ATQCRIT_MASK I40E_MASK(0x1, I40E_PF_ATQLEN_ATQCRIT_SHIFT) #define I40E_PF_ATQLEN_ATQENABLE_SHIFT 31 -#define I40E_PF_ATQLEN_ATQENABLE_MASK (0x1 << I40E_PF_ATQLEN_ATQENABLE_SHIFT) -#define I40E_PF_ATQT 0x00080400 +#define I40E_PF_ATQLEN_ATQENABLE_MASK I40E_MASK(0x1, I40E_PF_ATQLEN_ATQENABLE_SHIFT) +#define I40E_PF_ATQT 0x00080400 /* Reset: EMPR */ #define I40E_PF_ATQT_ATQT_SHIFT 0 -#define I40E_PF_ATQT_ATQT_MASK (0x3FF << I40E_PF_ATQT_ATQT_SHIFT) -#define I40E_VF_ARQBAH(_VF) (0x00081400 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_PF_ATQT_ATQT_MASK I40E_MASK(0x3FF, I40E_PF_ATQT_ATQT_SHIFT) +#define I40E_VF_ARQBAH(_VF) (0x00081400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ARQBAH_MAX_INDEX 127 #define I40E_VF_ARQBAH_ARQBAH_SHIFT 0 -#define I40E_VF_ARQBAH_ARQBAH_MASK (0xFFFFFFFF << I40E_VF_ARQBAH_ARQBAH_SHIFT) -#define I40E_VF_ARQBAL(_VF) (0x00080C00 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ARQBAH_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAH_ARQBAH_SHIFT) +#define I40E_VF_ARQBAL(_VF) (0x00080C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ARQBAL_MAX_INDEX 127 #define I40E_VF_ARQBAL_ARQBAL_SHIFT 0 -#define I40E_VF_ARQBAL_ARQBAL_MASK (0xFFFFFFFF << I40E_VF_ARQBAL_ARQBAL_SHIFT) -#define I40E_VF_ARQH(_VF) (0x00082400 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ARQBAL_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAL_ARQBAL_SHIFT) +#define I40E_VF_ARQH(_VF) (0x00082400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ARQH_MAX_INDEX 127 #define I40E_VF_ARQH_ARQH_SHIFT 0 -#define I40E_VF_ARQH_ARQH_MASK (0x3FF << I40E_VF_ARQH_ARQH_SHIFT) -#define I40E_VF_ARQLEN(_VF) (0x00081C00 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ARQH_ARQH_MASK I40E_MASK(0x3FF, I40E_VF_ARQH_ARQH_SHIFT) +#define I40E_VF_ARQLEN(_VF) (0x00081C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ARQLEN_MAX_INDEX 127 #define I40E_VF_ARQLEN_ARQLEN_SHIFT 0 -#define I40E_VF_ARQLEN_ARQLEN_MASK (0x3FF << I40E_VF_ARQLEN_ARQLEN_SHIFT) +#define I40E_VF_ARQLEN_ARQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ARQLEN_ARQLEN_SHIFT) #define I40E_VF_ARQLEN_ARQVFE_SHIFT 28 -#define I40E_VF_ARQLEN_ARQVFE_MASK (0x1 << I40E_VF_ARQLEN_ARQVFE_SHIFT) +#define I40E_VF_ARQLEN_ARQVFE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN_ARQVFE_SHIFT) #define I40E_VF_ARQLEN_ARQOVFL_SHIFT 29 -#define I40E_VF_ARQLEN_ARQOVFL_MASK (0x1 << I40E_VF_ARQLEN_ARQOVFL_SHIFT) +#define I40E_VF_ARQLEN_ARQOVFL_MASK I40E_MASK(0x1, I40E_VF_ARQLEN_ARQOVFL_SHIFT) #define I40E_VF_ARQLEN_ARQCRIT_SHIFT 30 -#define I40E_VF_ARQLEN_ARQCRIT_MASK (0x1 << I40E_VF_ARQLEN_ARQCRIT_SHIFT) +#define I40E_VF_ARQLEN_ARQCRIT_MASK I40E_MASK(0x1, I40E_VF_ARQLEN_ARQCRIT_SHIFT) #define I40E_VF_ARQLEN_ARQENABLE_SHIFT 31 -#define I40E_VF_ARQLEN_ARQENABLE_MASK (0x1 << I40E_VF_ARQLEN_ARQENABLE_SHIFT) -#define I40E_VF_ARQT(_VF) (0x00082C00 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ARQLEN_ARQENABLE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN_ARQENABLE_SHIFT) +#define I40E_VF_ARQT(_VF) (0x00082C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ARQT_MAX_INDEX 127 #define I40E_VF_ARQT_ARQT_SHIFT 0 -#define I40E_VF_ARQT_ARQT_MASK (0x3FF << I40E_VF_ARQT_ARQT_SHIFT) -#define I40E_VF_ATQBAH(_VF) (0x00081000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ARQT_ARQT_MASK I40E_MASK(0x3FF, I40E_VF_ARQT_ARQT_SHIFT) +#define I40E_VF_ATQBAH(_VF) (0x00081000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ATQBAH_MAX_INDEX 127 #define I40E_VF_ATQBAH_ATQBAH_SHIFT 0 -#define I40E_VF_ATQBAH_ATQBAH_MASK (0xFFFFFFFF << I40E_VF_ATQBAH_ATQBAH_SHIFT) -#define I40E_VF_ATQBAL(_VF) (0x00080800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ATQBAH_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAH_ATQBAH_SHIFT) +#define I40E_VF_ATQBAL(_VF) (0x00080800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ATQBAL_MAX_INDEX 127 #define I40E_VF_ATQBAL_ATQBAL_SHIFT 0 -#define I40E_VF_ATQBAL_ATQBAL_MASK (0xFFFFFFFF << I40E_VF_ATQBAL_ATQBAL_SHIFT) -#define I40E_VF_ATQH(_VF) (0x00082000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ATQBAL_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAL_ATQBAL_SHIFT) +#define I40E_VF_ATQH(_VF) (0x00082000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ATQH_MAX_INDEX 127 #define I40E_VF_ATQH_ATQH_SHIFT 0 -#define I40E_VF_ATQH_ATQH_MASK (0x3FF << I40E_VF_ATQH_ATQH_SHIFT) -#define I40E_VF_ATQLEN(_VF) (0x00081800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ATQH_ATQH_MASK I40E_MASK(0x3FF, I40E_VF_ATQH_ATQH_SHIFT) +#define I40E_VF_ATQLEN(_VF) (0x00081800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ATQLEN_MAX_INDEX 127 #define I40E_VF_ATQLEN_ATQLEN_SHIFT 0 -#define I40E_VF_ATQLEN_ATQLEN_MASK (0x3FF << I40E_VF_ATQLEN_ATQLEN_SHIFT) +#define I40E_VF_ATQLEN_ATQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ATQLEN_ATQLEN_SHIFT) #define I40E_VF_ATQLEN_ATQVFE_SHIFT 28 -#define I40E_VF_ATQLEN_ATQVFE_MASK (0x1 << I40E_VF_ATQLEN_ATQVFE_SHIFT) +#define I40E_VF_ATQLEN_ATQVFE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN_ATQVFE_SHIFT) #define I40E_VF_ATQLEN_ATQOVFL_SHIFT 29 -#define I40E_VF_ATQLEN_ATQOVFL_MASK (0x1 << I40E_VF_ATQLEN_ATQOVFL_SHIFT) +#define I40E_VF_ATQLEN_ATQOVFL_MASK I40E_MASK(0x1, I40E_VF_ATQLEN_ATQOVFL_SHIFT) #define I40E_VF_ATQLEN_ATQCRIT_SHIFT 30 -#define I40E_VF_ATQLEN_ATQCRIT_MASK (0x1 << I40E_VF_ATQLEN_ATQCRIT_SHIFT) +#define I40E_VF_ATQLEN_ATQCRIT_MASK I40E_MASK(0x1, I40E_VF_ATQLEN_ATQCRIT_SHIFT) #define I40E_VF_ATQLEN_ATQENABLE_SHIFT 31 -#define I40E_VF_ATQLEN_ATQENABLE_MASK (0x1 << I40E_VF_ATQLEN_ATQENABLE_SHIFT) -#define I40E_VF_ATQT(_VF) (0x00082800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ATQLEN_ATQENABLE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN_ATQENABLE_SHIFT) +#define I40E_VF_ATQT(_VF) (0x00082800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ATQT_MAX_INDEX 127 #define I40E_VF_ATQT_ATQT_SHIFT 0 -#define I40E_VF_ATQT_ATQT_MASK (0x3FF << I40E_VF_ATQT_ATQT_SHIFT) -#define I40E_PRT_L2TAGSEN 0x001C0B20 +#define I40E_VF_ATQT_ATQT_MASK I40E_MASK(0x3FF, I40E_VF_ATQT_ATQT_SHIFT) +#define I40E_PRT_L2TAGSEN 0x001C0B20 /* Reset: CORER */ #define I40E_PRT_L2TAGSEN_ENABLE_SHIFT 0 -#define I40E_PRT_L2TAGSEN_ENABLE_MASK (0xFF << I40E_PRT_L2TAGSEN_ENABLE_SHIFT) -#define I40E_PFCM_LAN_ERRDATA 0x0010C080 +#define I40E_PRT_L2TAGSEN_ENABLE_MASK I40E_MASK(0xFF, I40E_PRT_L2TAGSEN_ENABLE_SHIFT) +#define I40E_PFCM_LAN_ERRDATA 0x0010C080 /* Reset: PFR */ #define I40E_PFCM_LAN_ERRDATA_ERROR_CODE_SHIFT 0 -#define I40E_PFCM_LAN_ERRDATA_ERROR_CODE_MASK (0xF << I40E_PFCM_LAN_ERRDATA_ERROR_CODE_SHIFT) +#define I40E_PFCM_LAN_ERRDATA_ERROR_CODE_MASK I40E_MASK(0xF, I40E_PFCM_LAN_ERRDATA_ERROR_CODE_SHIFT) #define I40E_PFCM_LAN_ERRDATA_Q_TYPE_SHIFT 4 -#define I40E_PFCM_LAN_ERRDATA_Q_TYPE_MASK (0x7 << I40E_PFCM_LAN_ERRDATA_Q_TYPE_SHIFT) +#define I40E_PFCM_LAN_ERRDATA_Q_TYPE_MASK I40E_MASK(0x7, I40E_PFCM_LAN_ERRDATA_Q_TYPE_SHIFT) #define I40E_PFCM_LAN_ERRDATA_Q_NUM_SHIFT 8 -#define I40E_PFCM_LAN_ERRDATA_Q_NUM_MASK (0xFFF << I40E_PFCM_LAN_ERRDATA_Q_NUM_SHIFT) -#define I40E_PFCM_LAN_ERRINFO 0x0010C000 +#define I40E_PFCM_LAN_ERRDATA_Q_NUM_MASK I40E_MASK(0xFFF, I40E_PFCM_LAN_ERRDATA_Q_NUM_SHIFT) +#define I40E_PFCM_LAN_ERRINFO 0x0010C000 /* Reset: PFR */ #define I40E_PFCM_LAN_ERRINFO_ERROR_VALID_SHIFT 0 -#define I40E_PFCM_LAN_ERRINFO_ERROR_VALID_MASK (0x1 << I40E_PFCM_LAN_ERRINFO_ERROR_VALID_SHIFT) +#define I40E_PFCM_LAN_ERRINFO_ERROR_VALID_MASK I40E_MASK(0x1, I40E_PFCM_LAN_ERRINFO_ERROR_VALID_SHIFT) #define I40E_PFCM_LAN_ERRINFO_ERROR_INST_SHIFT 4 -#define I40E_PFCM_LAN_ERRINFO_ERROR_INST_MASK (0x7 << I40E_PFCM_LAN_ERRINFO_ERROR_INST_SHIFT) +#define I40E_PFCM_LAN_ERRINFO_ERROR_INST_MASK I40E_MASK(0x7, I40E_PFCM_LAN_ERRINFO_ERROR_INST_SHIFT) #define I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_SHIFT 8 -#define I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_MASK (0xFF << I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_SHIFT) +#define I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_SHIFT) #define I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_SHIFT 16 -#define I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_MASK (0xFF << I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_SHIFT) +#define I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_SHIFT) #define I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_SHIFT 24 -#define I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_MASK (0xFF << I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_SHIFT) -#define I40E_PFCM_LANCTXCTL 0x0010C300 +#define I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_SHIFT) +#define I40E_PFCM_LANCTXCTL 0x0010C300 /* Reset: CORER */ #define I40E_PFCM_LANCTXCTL_QUEUE_NUM_SHIFT 0 -#define I40E_PFCM_LANCTXCTL_QUEUE_NUM_MASK (0xFFF << I40E_PFCM_LANCTXCTL_QUEUE_NUM_SHIFT) +#define I40E_PFCM_LANCTXCTL_QUEUE_NUM_MASK I40E_MASK(0xFFF, I40E_PFCM_LANCTXCTL_QUEUE_NUM_SHIFT) #define I40E_PFCM_LANCTXCTL_SUB_LINE_SHIFT 12 -#define I40E_PFCM_LANCTXCTL_SUB_LINE_MASK (0x7 << I40E_PFCM_LANCTXCTL_SUB_LINE_SHIFT) +#define I40E_PFCM_LANCTXCTL_SUB_LINE_MASK I40E_MASK(0x7, I40E_PFCM_LANCTXCTL_SUB_LINE_SHIFT) #define I40E_PFCM_LANCTXCTL_QUEUE_TYPE_SHIFT 15 -#define I40E_PFCM_LANCTXCTL_QUEUE_TYPE_MASK (0x3 << I40E_PFCM_LANCTXCTL_QUEUE_TYPE_SHIFT) +#define I40E_PFCM_LANCTXCTL_QUEUE_TYPE_MASK I40E_MASK(0x3, I40E_PFCM_LANCTXCTL_QUEUE_TYPE_SHIFT) #define I40E_PFCM_LANCTXCTL_OP_CODE_SHIFT 17 -#define I40E_PFCM_LANCTXCTL_OP_CODE_MASK (0x3 << I40E_PFCM_LANCTXCTL_OP_CODE_SHIFT) -#define I40E_PFCM_LANCTXDATA(_i) (0x0010C100 + ((_i) * 128)) /* _i=0...3 */ +#define I40E_PFCM_LANCTXCTL_OP_CODE_MASK I40E_MASK(0x3, I40E_PFCM_LANCTXCTL_OP_CODE_SHIFT) +#define I40E_PFCM_LANCTXDATA(_i) (0x0010C100 + ((_i) * 128)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_PFCM_LANCTXDATA_MAX_INDEX 3 #define I40E_PFCM_LANCTXDATA_DATA_SHIFT 0 -#define I40E_PFCM_LANCTXDATA_DATA_MASK (0xFFFFFFFF << I40E_PFCM_LANCTXDATA_DATA_SHIFT) -#define I40E_PFCM_LANCTXSTAT 0x0010C380 +#define I40E_PFCM_LANCTXDATA_DATA_MASK I40E_MASK(0xFFFFFFFF, I40E_PFCM_LANCTXDATA_DATA_SHIFT) +#define I40E_PFCM_LANCTXSTAT 0x0010C380 /* Reset: CORER */ #define I40E_PFCM_LANCTXSTAT_CTX_DONE_SHIFT 0 -#define I40E_PFCM_LANCTXSTAT_CTX_DONE_MASK (0x1 << I40E_PFCM_LANCTXSTAT_CTX_DONE_SHIFT) +#define I40E_PFCM_LANCTXSTAT_CTX_DONE_MASK I40E_MASK(0x1, I40E_PFCM_LANCTXSTAT_CTX_DONE_SHIFT) #define I40E_PFCM_LANCTXSTAT_CTX_MISS_SHIFT 1 -#define I40E_PFCM_LANCTXSTAT_CTX_MISS_MASK (0x1 << I40E_PFCM_LANCTXSTAT_CTX_MISS_SHIFT) -#define I40E_PFCM_PE_ERRDATA 0x00138D00 -#define I40E_PFCM_PE_ERRDATA_ERROR_CODE_SHIFT 0 -#define I40E_PFCM_PE_ERRDATA_ERROR_CODE_MASK (0xF << I40E_PFCM_PE_ERRDATA_ERROR_CODE_SHIFT) -#define I40E_PFCM_PE_ERRDATA_Q_TYPE_SHIFT 4 -#define I40E_PFCM_PE_ERRDATA_Q_TYPE_MASK (0x7 << I40E_PFCM_PE_ERRDATA_Q_TYPE_SHIFT) -#define I40E_PFCM_PE_ERRDATA_Q_NUM_SHIFT 8 -#define I40E_PFCM_PE_ERRDATA_Q_NUM_MASK (0x3FFFF << I40E_PFCM_PE_ERRDATA_Q_NUM_SHIFT) -#define I40E_PFCM_PE_ERRINFO 0x00138C80 -#define I40E_PFCM_PE_ERRINFO_ERROR_VALID_SHIFT 0 -#define I40E_PFCM_PE_ERRINFO_ERROR_VALID_MASK (0x1 << I40E_PFCM_PE_ERRINFO_ERROR_VALID_SHIFT) -#define I40E_PFCM_PE_ERRINFO_ERROR_INST_SHIFT 4 -#define I40E_PFCM_PE_ERRINFO_ERROR_INST_MASK (0x7 << I40E_PFCM_PE_ERRINFO_ERROR_INST_SHIFT) -#define I40E_PFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT 8 -#define I40E_PFCM_PE_ERRINFO_DBL_ERROR_CNT_MASK (0xFF << I40E_PFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT) -#define I40E_PFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT 16 -#define I40E_PFCM_PE_ERRINFO_RLU_ERROR_CNT_MASK (0xFF << I40E_PFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT) -#define I40E_PFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT 24 -#define I40E_PFCM_PE_ERRINFO_RLS_ERROR_CNT_MASK (0xFF << I40E_PFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT) -#define I40E_VFCM_PE_ERRDATA1(_VF) (0x00138800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_PFCM_LANCTXSTAT_CTX_MISS_MASK I40E_MASK(0x1, I40E_PFCM_LANCTXSTAT_CTX_MISS_SHIFT) +#define I40E_VFCM_PE_ERRDATA1(_VF) (0x00138800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VFCM_PE_ERRDATA1_MAX_INDEX 127 #define I40E_VFCM_PE_ERRDATA1_ERROR_CODE_SHIFT 0 -#define I40E_VFCM_PE_ERRDATA1_ERROR_CODE_MASK (0xF << I40E_VFCM_PE_ERRDATA1_ERROR_CODE_SHIFT) +#define I40E_VFCM_PE_ERRDATA1_ERROR_CODE_MASK I40E_MASK(0xF, I40E_VFCM_PE_ERRDATA1_ERROR_CODE_SHIFT) #define I40E_VFCM_PE_ERRDATA1_Q_TYPE_SHIFT 4 -#define I40E_VFCM_PE_ERRDATA1_Q_TYPE_MASK (0x7 << I40E_VFCM_PE_ERRDATA1_Q_TYPE_SHIFT) +#define I40E_VFCM_PE_ERRDATA1_Q_TYPE_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRDATA1_Q_TYPE_SHIFT) #define I40E_VFCM_PE_ERRDATA1_Q_NUM_SHIFT 8 -#define I40E_VFCM_PE_ERRDATA1_Q_NUM_MASK (0x3FFFF << I40E_VFCM_PE_ERRDATA1_Q_NUM_SHIFT) -#define I40E_VFCM_PE_ERRINFO1(_VF) (0x00138400 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFCM_PE_ERRDATA1_Q_NUM_MASK I40E_MASK(0x3FFFF, I40E_VFCM_PE_ERRDATA1_Q_NUM_SHIFT) +#define I40E_VFCM_PE_ERRINFO1(_VF) (0x00138400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VFCM_PE_ERRINFO1_MAX_INDEX 127 #define I40E_VFCM_PE_ERRINFO1_ERROR_VALID_SHIFT 0 -#define I40E_VFCM_PE_ERRINFO1_ERROR_VALID_MASK (0x1 << I40E_VFCM_PE_ERRINFO1_ERROR_VALID_SHIFT) +#define I40E_VFCM_PE_ERRINFO1_ERROR_VALID_MASK I40E_MASK(0x1, I40E_VFCM_PE_ERRINFO1_ERROR_VALID_SHIFT) #define I40E_VFCM_PE_ERRINFO1_ERROR_INST_SHIFT 4 -#define I40E_VFCM_PE_ERRINFO1_ERROR_INST_MASK (0x7 << I40E_VFCM_PE_ERRINFO1_ERROR_INST_SHIFT) +#define I40E_VFCM_PE_ERRINFO1_ERROR_INST_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRINFO1_ERROR_INST_SHIFT) #define I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_SHIFT 8 -#define I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_SHIFT) +#define I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_SHIFT) #define I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_SHIFT 16 -#define I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_SHIFT) +#define I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_SHIFT) #define I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_SHIFT 24 -#define I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_SHIFT) -#define I40E_GLDCB_GENC 0x00083044 +#define I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_SHIFT) +#define I40E_GLDCB_GENC 0x00083044 /* Reset: CORER */ #define I40E_GLDCB_GENC_PCIRTT_SHIFT 0 -#define I40E_GLDCB_GENC_PCIRTT_MASK (0xFFFF << I40E_GLDCB_GENC_PCIRTT_SHIFT) -#define I40E_GLDCB_RUPTI 0x00122618 +#define I40E_GLDCB_GENC_PCIRTT_MASK I40E_MASK(0xFFFF, I40E_GLDCB_GENC_PCIRTT_SHIFT) +#define I40E_GLDCB_RUPTI 0x00122618 /* Reset: CORER */ #define I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_SHIFT 0 -#define I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_MASK (0xFFFFFFFF << I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_SHIFT) -#define I40E_PRTDCB_FCCFG 0x001E4640 +#define I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_SHIFT) +#define I40E_PRTDCB_FCCFG 0x001E4640 /* Reset: GLOBR */ #define I40E_PRTDCB_FCCFG_TFCE_SHIFT 3 -#define I40E_PRTDCB_FCCFG_TFCE_MASK (0x3 << I40E_PRTDCB_FCCFG_TFCE_SHIFT) -#define I40E_PRTDCB_FCRTV 0x001E4600 +#define I40E_PRTDCB_FCCFG_TFCE_MASK I40E_MASK(0x3, I40E_PRTDCB_FCCFG_TFCE_SHIFT) +#define I40E_PRTDCB_FCRTV 0x001E4600 /* Reset: GLOBR */ #define I40E_PRTDCB_FCRTV_FC_REFRESH_TH_SHIFT 0 -#define I40E_PRTDCB_FCRTV_FC_REFRESH_TH_MASK (0xFFFF << I40E_PRTDCB_FCRTV_FC_REFRESH_TH_SHIFT) -#define I40E_PRTDCB_FCTTVN(_i) (0x001E4580 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRTDCB_FCRTV_FC_REFRESH_TH_MASK I40E_MASK(0xFFFF, I40E_PRTDCB_FCRTV_FC_REFRESH_TH_SHIFT) +#define I40E_PRTDCB_FCTTVN(_i) (0x001E4580 + ((_i) * 32)) /* _i=0...3 */ /* Reset: GLOBR */ #define I40E_PRTDCB_FCTTVN_MAX_INDEX 3 #define I40E_PRTDCB_FCTTVN_TTV_2N_SHIFT 0 -#define I40E_PRTDCB_FCTTVN_TTV_2N_MASK (0xFFFF << I40E_PRTDCB_FCTTVN_TTV_2N_SHIFT) +#define I40E_PRTDCB_FCTTVN_TTV_2N_MASK I40E_MASK(0xFFFF, I40E_PRTDCB_FCTTVN_TTV_2N_SHIFT) #define I40E_PRTDCB_FCTTVN_TTV_2N_P1_SHIFT 16 -#define I40E_PRTDCB_FCTTVN_TTV_2N_P1_MASK (0xFFFF << I40E_PRTDCB_FCTTVN_TTV_2N_P1_SHIFT) -#define I40E_PRTDCB_GENC 0x00083000 +#define I40E_PRTDCB_FCTTVN_TTV_2N_P1_MASK I40E_MASK(0xFFFF, I40E_PRTDCB_FCTTVN_TTV_2N_P1_SHIFT) +#define I40E_PRTDCB_GENC 0x00083000 /* Reset: CORER */ #define I40E_PRTDCB_GENC_RESERVED_1_SHIFT 0 -#define I40E_PRTDCB_GENC_RESERVED_1_MASK (0x3 << I40E_PRTDCB_GENC_RESERVED_1_SHIFT) +#define I40E_PRTDCB_GENC_RESERVED_1_MASK I40E_MASK(0x3, I40E_PRTDCB_GENC_RESERVED_1_SHIFT) #define I40E_PRTDCB_GENC_NUMTC_SHIFT 2 -#define I40E_PRTDCB_GENC_NUMTC_MASK (0xF << I40E_PRTDCB_GENC_NUMTC_SHIFT) +#define I40E_PRTDCB_GENC_NUMTC_MASK I40E_MASK(0xF, I40E_PRTDCB_GENC_NUMTC_SHIFT) #define I40E_PRTDCB_GENC_FCOEUP_SHIFT 6 -#define I40E_PRTDCB_GENC_FCOEUP_MASK (0x7 << I40E_PRTDCB_GENC_FCOEUP_SHIFT) +#define I40E_PRTDCB_GENC_FCOEUP_MASK I40E_MASK(0x7, I40E_PRTDCB_GENC_FCOEUP_SHIFT) #define I40E_PRTDCB_GENC_FCOEUP_VALID_SHIFT 9 -#define I40E_PRTDCB_GENC_FCOEUP_VALID_MASK (0x1 << I40E_PRTDCB_GENC_FCOEUP_VALID_SHIFT) +#define I40E_PRTDCB_GENC_FCOEUP_VALID_MASK I40E_MASK(0x1, I40E_PRTDCB_GENC_FCOEUP_VALID_SHIFT) #define I40E_PRTDCB_GENC_PFCLDA_SHIFT 16 -#define I40E_PRTDCB_GENC_PFCLDA_MASK (0xFFFF << I40E_PRTDCB_GENC_PFCLDA_SHIFT) -#define I40E_PRTDCB_GENS 0x00083020 +#define I40E_PRTDCB_GENC_PFCLDA_MASK I40E_MASK(0xFFFF, I40E_PRTDCB_GENC_PFCLDA_SHIFT) +#define I40E_PRTDCB_GENS 0x00083020 /* Reset: CORER */ #define I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT 0 -#define I40E_PRTDCB_GENS_DCBX_STATUS_MASK (0x7 << I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT) -#define I40E_PRTDCB_MFLCN 0x001E2400 +#define I40E_PRTDCB_GENS_DCBX_STATUS_MASK I40E_MASK(0x7, I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT) +#define I40E_PRTDCB_MFLCN 0x001E2400 /* Reset: GLOBR */ #define I40E_PRTDCB_MFLCN_PMCF_SHIFT 0 -#define I40E_PRTDCB_MFLCN_PMCF_MASK (0x1 << I40E_PRTDCB_MFLCN_PMCF_SHIFT) +#define I40E_PRTDCB_MFLCN_PMCF_MASK I40E_MASK(0x1, I40E_PRTDCB_MFLCN_PMCF_SHIFT) #define I40E_PRTDCB_MFLCN_DPF_SHIFT 1 -#define I40E_PRTDCB_MFLCN_DPF_MASK (0x1 << I40E_PRTDCB_MFLCN_DPF_SHIFT) +#define I40E_PRTDCB_MFLCN_DPF_MASK I40E_MASK(0x1, I40E_PRTDCB_MFLCN_DPF_SHIFT) #define I40E_PRTDCB_MFLCN_RPFCM_SHIFT 2 -#define I40E_PRTDCB_MFLCN_RPFCM_MASK (0x1 << I40E_PRTDCB_MFLCN_RPFCM_SHIFT) +#define I40E_PRTDCB_MFLCN_RPFCM_MASK I40E_MASK(0x1, I40E_PRTDCB_MFLCN_RPFCM_SHIFT) #define I40E_PRTDCB_MFLCN_RFCE_SHIFT 3 -#define I40E_PRTDCB_MFLCN_RFCE_MASK (0x1 << I40E_PRTDCB_MFLCN_RFCE_SHIFT) +#define I40E_PRTDCB_MFLCN_RFCE_MASK I40E_MASK(0x1, I40E_PRTDCB_MFLCN_RFCE_SHIFT) #define I40E_PRTDCB_MFLCN_RPFCE_SHIFT 4 -#define I40E_PRTDCB_MFLCN_RPFCE_MASK (0xFF << I40E_PRTDCB_MFLCN_RPFCE_SHIFT) -#define I40E_PRTDCB_RETSC 0x001223E0 +#define I40E_PRTDCB_MFLCN_RPFCE_MASK I40E_MASK(0xFF, I40E_PRTDCB_MFLCN_RPFCE_SHIFT) +#define I40E_PRTDCB_RETSC 0x001223E0 /* Reset: CORER */ #define I40E_PRTDCB_RETSC_ETS_MODE_SHIFT 0 -#define I40E_PRTDCB_RETSC_ETS_MODE_MASK (0x1 << I40E_PRTDCB_RETSC_ETS_MODE_SHIFT) +#define I40E_PRTDCB_RETSC_ETS_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_RETSC_ETS_MODE_SHIFT) #define I40E_PRTDCB_RETSC_NON_ETS_MODE_SHIFT 1 -#define I40E_PRTDCB_RETSC_NON_ETS_MODE_MASK (0x1 << I40E_PRTDCB_RETSC_NON_ETS_MODE_SHIFT) +#define I40E_PRTDCB_RETSC_NON_ETS_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_RETSC_NON_ETS_MODE_SHIFT) #define I40E_PRTDCB_RETSC_ETS_MAX_EXP_SHIFT 2 -#define I40E_PRTDCB_RETSC_ETS_MAX_EXP_MASK (0xF << I40E_PRTDCB_RETSC_ETS_MAX_EXP_SHIFT) +#define I40E_PRTDCB_RETSC_ETS_MAX_EXP_MASK I40E_MASK(0xF, I40E_PRTDCB_RETSC_ETS_MAX_EXP_SHIFT) #define I40E_PRTDCB_RETSC_LLTC_SHIFT 8 -#define I40E_PRTDCB_RETSC_LLTC_MASK (0xFF << I40E_PRTDCB_RETSC_LLTC_SHIFT) -#define I40E_PRTDCB_RETSTCC(_i) (0x00122180 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTDCB_RETSC_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_RETSC_LLTC_SHIFT) +#define I40E_PRTDCB_RETSTCC(_i) (0x00122180 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTDCB_RETSTCC_MAX_INDEX 7 #define I40E_PRTDCB_RETSTCC_BWSHARE_SHIFT 0 -#define I40E_PRTDCB_RETSTCC_BWSHARE_MASK (0x7F << I40E_PRTDCB_RETSTCC_BWSHARE_SHIFT) +#define I40E_PRTDCB_RETSTCC_BWSHARE_MASK I40E_MASK(0x7F, I40E_PRTDCB_RETSTCC_BWSHARE_SHIFT) #define I40E_PRTDCB_RETSTCC_UPINTC_MODE_SHIFT 30 -#define I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK (0x1 << I40E_PRTDCB_RETSTCC_UPINTC_MODE_SHIFT) +#define I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_RETSTCC_UPINTC_MODE_SHIFT) #define I40E_PRTDCB_RETSTCC_ETSTC_SHIFT 31 -#define I40E_PRTDCB_RETSTCC_ETSTC_MASK (0x1 << I40E_PRTDCB_RETSTCC_ETSTC_SHIFT) -#define I40E_PRTDCB_RPPMC 0x001223A0 +#define I40E_PRTDCB_RETSTCC_ETSTC_MASK I40E_MASK(0x1, I40E_PRTDCB_RETSTCC_ETSTC_SHIFT) +#define I40E_PRTDCB_RPPMC 0x001223A0 /* Reset: CORER */ #define I40E_PRTDCB_RPPMC_LANRPPM_SHIFT 0 -#define I40E_PRTDCB_RPPMC_LANRPPM_MASK (0xFF << I40E_PRTDCB_RPPMC_LANRPPM_SHIFT) +#define I40E_PRTDCB_RPPMC_LANRPPM_MASK I40E_MASK(0xFF, I40E_PRTDCB_RPPMC_LANRPPM_SHIFT) #define I40E_PRTDCB_RPPMC_RDMARPPM_SHIFT 8 -#define I40E_PRTDCB_RPPMC_RDMARPPM_MASK (0xFF << I40E_PRTDCB_RPPMC_RDMARPPM_SHIFT) +#define I40E_PRTDCB_RPPMC_RDMARPPM_MASK I40E_MASK(0xFF, I40E_PRTDCB_RPPMC_RDMARPPM_SHIFT) #define I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_SHIFT 16 -#define I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_MASK (0xFF << I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_SHIFT) -#define I40E_PRTDCB_RUP 0x001C0B00 +#define I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_MASK I40E_MASK(0xFF, I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_SHIFT) +#define I40E_PRTDCB_RUP 0x001C0B00 /* Reset: CORER */ #define I40E_PRTDCB_RUP_NOVLANUP_SHIFT 0 -#define I40E_PRTDCB_RUP_NOVLANUP_MASK (0x7 << I40E_PRTDCB_RUP_NOVLANUP_SHIFT) -#define I40E_PRTDCB_RUP2TC 0x001C09A0 +#define I40E_PRTDCB_RUP_NOVLANUP_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP_NOVLANUP_SHIFT) +#define I40E_PRTDCB_RUP2TC 0x001C09A0 /* Reset: CORER */ #define I40E_PRTDCB_RUP2TC_UP0TC_SHIFT 0 -#define I40E_PRTDCB_RUP2TC_UP0TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP0TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP0TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP0TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP1TC_SHIFT 3 -#define I40E_PRTDCB_RUP2TC_UP1TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP1TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP1TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP1TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP2TC_SHIFT 6 -#define I40E_PRTDCB_RUP2TC_UP2TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP2TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP2TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP2TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP3TC_SHIFT 9 -#define I40E_PRTDCB_RUP2TC_UP3TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP3TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP3TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP3TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP4TC_SHIFT 12 -#define I40E_PRTDCB_RUP2TC_UP4TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP4TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP4TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP4TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP5TC_SHIFT 15 -#define I40E_PRTDCB_RUP2TC_UP5TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP5TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP5TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP5TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP6TC_SHIFT 18 -#define I40E_PRTDCB_RUP2TC_UP6TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP6TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP6TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP6TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP7TC_SHIFT 21 -#define I40E_PRTDCB_RUP2TC_UP7TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP7TC_SHIFT) -#define I40E_PRTDCB_TC2PFC 0x001C0980 +#define I40E_PRTDCB_RUP2TC_UP7TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP7TC_SHIFT) +#define I40E_PRTDCB_TC2PFC 0x001C0980 /* Reset: CORER */ #define I40E_PRTDCB_TC2PFC_TC2PFC_SHIFT 0 -#define I40E_PRTDCB_TC2PFC_TC2PFC_MASK (0xFF << I40E_PRTDCB_TC2PFC_TC2PFC_SHIFT) -#define I40E_PRTDCB_TCPMC 0x000A21A0 +#define I40E_PRTDCB_TC2PFC_TC2PFC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TC2PFC_TC2PFC_SHIFT) +#define I40E_PRTDCB_TCMSTC(_i) (0x000A0040 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ +#define I40E_PRTDCB_TCMSTC_MAX_INDEX 7 +#define I40E_PRTDCB_TCMSTC_MSTC_SHIFT 0 +#define I40E_PRTDCB_TCMSTC_MSTC_MASK I40E_MASK(0xFFFFF, I40E_PRTDCB_TCMSTC_MSTC_SHIFT) +#define I40E_PRTDCB_TCPMC 0x000A21A0 /* Reset: CORER */ #define I40E_PRTDCB_TCPMC_CPM_SHIFT 0 -#define I40E_PRTDCB_TCPMC_CPM_MASK (0x1FFF << I40E_PRTDCB_TCPMC_CPM_SHIFT) +#define I40E_PRTDCB_TCPMC_CPM_MASK I40E_MASK(0x1FFF, I40E_PRTDCB_TCPMC_CPM_SHIFT) #define I40E_PRTDCB_TCPMC_LLTC_SHIFT 13 -#define I40E_PRTDCB_TCPMC_LLTC_MASK (0xFF << I40E_PRTDCB_TCPMC_LLTC_SHIFT) +#define I40E_PRTDCB_TCPMC_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TCPMC_LLTC_SHIFT) #define I40E_PRTDCB_TCPMC_TCPM_MODE_SHIFT 30 -#define I40E_PRTDCB_TCPMC_TCPM_MODE_MASK (0x1 << I40E_PRTDCB_TCPMC_TCPM_MODE_SHIFT) -#define I40E_PRTDCB_TCWSTC(_i) (0x000A2040 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTDCB_TCPMC_TCPM_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_TCPMC_TCPM_MODE_SHIFT) +#define I40E_PRTDCB_TCWSTC(_i) (0x000A2040 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTDCB_TCWSTC_MAX_INDEX 7 #define I40E_PRTDCB_TCWSTC_MSTC_SHIFT 0 -#define I40E_PRTDCB_TCWSTC_MSTC_MASK (0xFFFFF << I40E_PRTDCB_TCWSTC_MSTC_SHIFT) -#define I40E_PRTDCB_TDPMC 0x000A0180 +#define I40E_PRTDCB_TCWSTC_MSTC_MASK I40E_MASK(0xFFFFF, I40E_PRTDCB_TCWSTC_MSTC_SHIFT) +#define I40E_PRTDCB_TDPMC 0x000A0180 /* Reset: CORER */ #define I40E_PRTDCB_TDPMC_DPM_SHIFT 0 -#define I40E_PRTDCB_TDPMC_DPM_MASK (0xFF << I40E_PRTDCB_TDPMC_DPM_SHIFT) +#define I40E_PRTDCB_TDPMC_DPM_MASK I40E_MASK(0xFF, I40E_PRTDCB_TDPMC_DPM_SHIFT) #define I40E_PRTDCB_TDPMC_TCPM_MODE_SHIFT 30 -#define I40E_PRTDCB_TDPMC_TCPM_MODE_MASK (0x1 << I40E_PRTDCB_TDPMC_TCPM_MODE_SHIFT) -#define I40E_PRTDCB_TDPUC 0x00044100 -#define I40E_PRTDCB_TDPUC_MAX_TXFRAME_SHIFT 0 -#define I40E_PRTDCB_TDPUC_MAX_TXFRAME_MASK (0xFFFF << I40E_PRTDCB_TDPUC_MAX_TXFRAME_SHIFT) -#define I40E_PRTDCB_TETSC_TCB 0x000AE060 +#define I40E_PRTDCB_TDPMC_TCPM_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_TDPMC_TCPM_MODE_SHIFT) +#define I40E_PRTDCB_TETSC_TCB 0x000AE060 /* Reset: CORER */ #define I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_SHIFT 0 -#define I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_MASK (0x1 << I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_SHIFT) +#define I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_MASK I40E_MASK(0x1, I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_SHIFT) #define I40E_PRTDCB_TETSC_TCB_LLTC_SHIFT 8 -#define I40E_PRTDCB_TETSC_TCB_LLTC_MASK (0xFF << I40E_PRTDCB_TETSC_TCB_LLTC_SHIFT) -#define I40E_PRTDCB_TETSC_TPB 0x00098060 +#define I40E_PRTDCB_TETSC_TCB_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TETSC_TCB_LLTC_SHIFT) +#define I40E_PRTDCB_TETSC_TPB 0x00098060 /* Reset: CORER */ #define I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_SHIFT 0 -#define I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_MASK (0x1 << I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_SHIFT) +#define I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_MASK I40E_MASK(0x1, I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_SHIFT) #define I40E_PRTDCB_TETSC_TPB_LLTC_SHIFT 8 -#define I40E_PRTDCB_TETSC_TPB_LLTC_MASK (0xFF << I40E_PRTDCB_TETSC_TPB_LLTC_SHIFT) -#define I40E_PRTDCB_TFCS 0x001E4560 +#define I40E_PRTDCB_TETSC_TPB_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TETSC_TPB_LLTC_SHIFT) +#define I40E_PRTDCB_TFCS 0x001E4560 /* Reset: GLOBR */ #define I40E_PRTDCB_TFCS_TXOFF_SHIFT 0 -#define I40E_PRTDCB_TFCS_TXOFF_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF0_SHIFT 8 -#define I40E_PRTDCB_TFCS_TXOFF0_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF0_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF0_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF0_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF1_SHIFT 9 -#define I40E_PRTDCB_TFCS_TXOFF1_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF1_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF1_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF1_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF2_SHIFT 10 -#define I40E_PRTDCB_TFCS_TXOFF2_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF2_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF2_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF2_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF3_SHIFT 11 -#define I40E_PRTDCB_TFCS_TXOFF3_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF3_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF3_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF3_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF4_SHIFT 12 -#define I40E_PRTDCB_TFCS_TXOFF4_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF4_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF4_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF4_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF5_SHIFT 13 -#define I40E_PRTDCB_TFCS_TXOFF5_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF5_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF5_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF5_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF6_SHIFT 14 -#define I40E_PRTDCB_TFCS_TXOFF6_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF6_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF6_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF6_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF7_SHIFT 15 -#define I40E_PRTDCB_TFCS_TXOFF7_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF7_SHIFT) -#define I40E_PRTDCB_TFWSTC(_i) (0x000A0040 + ((_i) * 32)) /* _i=0...7 */ -#define I40E_PRTDCB_TFWSTC_MAX_INDEX 7 -#define I40E_PRTDCB_TFWSTC_MSTC_SHIFT 0 -#define I40E_PRTDCB_TFWSTC_MSTC_MASK (0xFFFFF << I40E_PRTDCB_TFWSTC_MSTC_SHIFT) -#define I40E_PRTDCB_TPFCTS(_i) (0x001E4660 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTDCB_TFCS_TXOFF7_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF7_SHIFT) +#define I40E_PRTDCB_TPFCTS(_i) (0x001E4660 + ((_i) * 32)) /* _i=0...7 */ /* Reset: GLOBR */ #define I40E_PRTDCB_TPFCTS_MAX_INDEX 7 #define I40E_PRTDCB_TPFCTS_PFCTIMER_SHIFT 0 -#define I40E_PRTDCB_TPFCTS_PFCTIMER_MASK (0x3FFF << I40E_PRTDCB_TPFCTS_PFCTIMER_SHIFT) -#define I40E_GLFCOE_RCTL 0x00269B94 +#define I40E_PRTDCB_TPFCTS_PFCTIMER_MASK I40E_MASK(0x3FFF, I40E_PRTDCB_TPFCTS_PFCTIMER_SHIFT) +#define I40E_GLFCOE_RCTL 0x00269B94 /* Reset: CORER */ #define I40E_GLFCOE_RCTL_FCOEVER_SHIFT 0 -#define I40E_GLFCOE_RCTL_FCOEVER_MASK (0xF << I40E_GLFCOE_RCTL_FCOEVER_SHIFT) +#define I40E_GLFCOE_RCTL_FCOEVER_MASK I40E_MASK(0xF, I40E_GLFCOE_RCTL_FCOEVER_SHIFT) #define I40E_GLFCOE_RCTL_SAVBAD_SHIFT 4 -#define I40E_GLFCOE_RCTL_SAVBAD_MASK (0x1 << I40E_GLFCOE_RCTL_SAVBAD_SHIFT) +#define I40E_GLFCOE_RCTL_SAVBAD_MASK I40E_MASK(0x1, I40E_GLFCOE_RCTL_SAVBAD_SHIFT) #define I40E_GLFCOE_RCTL_ICRC_SHIFT 5 -#define I40E_GLFCOE_RCTL_ICRC_MASK (0x1 << I40E_GLFCOE_RCTL_ICRC_SHIFT) +#define I40E_GLFCOE_RCTL_ICRC_MASK I40E_MASK(0x1, I40E_GLFCOE_RCTL_ICRC_SHIFT) #define I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT 16 -#define I40E_GLFCOE_RCTL_MAX_SIZE_MASK (0x3FFF << I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT) -#define I40E_GL_FWSTS 0x00083048 +#define I40E_GLFCOE_RCTL_MAX_SIZE_MASK I40E_MASK(0x3FFF, I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT) +#define I40E_GL_FWSTS 0x00083048 /* Reset: POR */ #define I40E_GL_FWSTS_FWS0B_SHIFT 0 -#define I40E_GL_FWSTS_FWS0B_MASK (0xFF << I40E_GL_FWSTS_FWS0B_SHIFT) +#define I40E_GL_FWSTS_FWS0B_MASK I40E_MASK(0xFF, I40E_GL_FWSTS_FWS0B_SHIFT) #define I40E_GL_FWSTS_FWRI_SHIFT 9 -#define I40E_GL_FWSTS_FWRI_MASK (0x1 << I40E_GL_FWSTS_FWRI_SHIFT) +#define I40E_GL_FWSTS_FWRI_MASK I40E_MASK(0x1, I40E_GL_FWSTS_FWRI_SHIFT) #define I40E_GL_FWSTS_FWS1B_SHIFT 16 -#define I40E_GL_FWSTS_FWS1B_MASK (0xFF << I40E_GL_FWSTS_FWS1B_SHIFT) -#define I40E_GLGEN_CLKSTAT 0x000B8184 +#define I40E_GL_FWSTS_FWS1B_MASK I40E_MASK(0xFF, I40E_GL_FWSTS_FWS1B_SHIFT) +#define I40E_GLGEN_CLKSTAT 0x000B8184 /* Reset: POR */ #define I40E_GLGEN_CLKSTAT_CLKMODE_SHIFT 0 -#define I40E_GLGEN_CLKSTAT_CLKMODE_MASK (0x1 << I40E_GLGEN_CLKSTAT_CLKMODE_SHIFT) +#define I40E_GLGEN_CLKSTAT_CLKMODE_MASK I40E_MASK(0x1, I40E_GLGEN_CLKSTAT_CLKMODE_SHIFT) #define I40E_GLGEN_CLKSTAT_U_CLK_SPEED_SHIFT 4 -#define I40E_GLGEN_CLKSTAT_U_CLK_SPEED_MASK (0x3 << I40E_GLGEN_CLKSTAT_U_CLK_SPEED_SHIFT) +#define I40E_GLGEN_CLKSTAT_U_CLK_SPEED_MASK I40E_MASK(0x3, I40E_GLGEN_CLKSTAT_U_CLK_SPEED_SHIFT) #define I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_SHIFT 8 -#define I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_MASK (0x7 << I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_SHIFT) +#define I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_MASK I40E_MASK(0x7, I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_SHIFT) #define I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_SHIFT 12 -#define I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_MASK (0x7 << I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_SHIFT) +#define I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_MASK I40E_MASK(0x7, I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_SHIFT) #define I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_SHIFT 16 -#define I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_MASK (0x7 << I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_SHIFT) +#define I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_MASK I40E_MASK(0x7, I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_SHIFT) #define I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_SHIFT 20 -#define I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_MASK (0x7 << I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_SHIFT) -#define I40E_GLGEN_GPIO_CTL(_i) (0x00088100 + ((_i) * 4)) /* _i=0...29 */ +#define I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_MASK I40E_MASK(0x7, I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_SHIFT) +#define I40E_GLGEN_GPIO_CTL(_i) (0x00088100 + ((_i) * 4)) /* _i=0...29 */ /* Reset: POR */ #define I40E_GLGEN_GPIO_CTL_MAX_INDEX 29 #define I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT 0 -#define I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK (0x3 << I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT) +#define I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK I40E_MASK(0x3, I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT) #define I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_SHIFT 3 -#define I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_MASK (0x1 << I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_SHIFT) +#define I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_SHIFT) #define I40E_GLGEN_GPIO_CTL_PIN_DIR_SHIFT 4 -#define I40E_GLGEN_GPIO_CTL_PIN_DIR_MASK (0x1 << I40E_GLGEN_GPIO_CTL_PIN_DIR_SHIFT) +#define I40E_GLGEN_GPIO_CTL_PIN_DIR_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_PIN_DIR_SHIFT) #define I40E_GLGEN_GPIO_CTL_TRI_CTL_SHIFT 5 -#define I40E_GLGEN_GPIO_CTL_TRI_CTL_MASK (0x1 << I40E_GLGEN_GPIO_CTL_TRI_CTL_SHIFT) +#define I40E_GLGEN_GPIO_CTL_TRI_CTL_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_TRI_CTL_SHIFT) #define I40E_GLGEN_GPIO_CTL_OUT_CTL_SHIFT 6 -#define I40E_GLGEN_GPIO_CTL_OUT_CTL_MASK (0x1 << I40E_GLGEN_GPIO_CTL_OUT_CTL_SHIFT) +#define I40E_GLGEN_GPIO_CTL_OUT_CTL_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_OUT_CTL_SHIFT) #define I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT 7 -#define I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK (0x7 << I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT) +#define I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK I40E_MASK(0x7, I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT) #define I40E_GLGEN_GPIO_CTL_LED_INVRT_SHIFT 10 -#define I40E_GLGEN_GPIO_CTL_LED_INVRT_MASK (0x1 << I40E_GLGEN_GPIO_CTL_LED_INVRT_SHIFT) +#define I40E_GLGEN_GPIO_CTL_LED_INVRT_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_LED_INVRT_SHIFT) #define I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT 11 -#define I40E_GLGEN_GPIO_CTL_LED_BLINK_MASK (0x1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT) +#define I40E_GLGEN_GPIO_CTL_LED_BLINK_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT) #define I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT 12 -#define I40E_GLGEN_GPIO_CTL_LED_MODE_MASK (0xF << I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT) +#define I40E_GLGEN_GPIO_CTL_LED_MODE_MASK I40E_MASK(0x1F, I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT) #define I40E_GLGEN_GPIO_CTL_INT_MODE_SHIFT 17 -#define I40E_GLGEN_GPIO_CTL_INT_MODE_MASK (0x3 << I40E_GLGEN_GPIO_CTL_INT_MODE_SHIFT) +#define I40E_GLGEN_GPIO_CTL_INT_MODE_MASK I40E_MASK(0x3, I40E_GLGEN_GPIO_CTL_INT_MODE_SHIFT) #define I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_SHIFT 19 -#define I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_MASK (0x1 << I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_SHIFT) +#define I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_SHIFT) #define I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_SHIFT 20 -#define I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_MASK (0x3F << I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_SHIFT) -#define I40E_GLGEN_GPIO_SET 0x00088184 +#define I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_MASK I40E_MASK(0x3F, I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_SHIFT) +#define I40E_GLGEN_GPIO_SET 0x00088184 /* Reset: POR */ #define I40E_GLGEN_GPIO_SET_GPIO_INDX_SHIFT 0 -#define I40E_GLGEN_GPIO_SET_GPIO_INDX_MASK (0x1F << I40E_GLGEN_GPIO_SET_GPIO_INDX_SHIFT) +#define I40E_GLGEN_GPIO_SET_GPIO_INDX_MASK I40E_MASK(0x1F, I40E_GLGEN_GPIO_SET_GPIO_INDX_SHIFT) #define I40E_GLGEN_GPIO_SET_SDP_DATA_SHIFT 5 -#define I40E_GLGEN_GPIO_SET_SDP_DATA_MASK (0x1 << I40E_GLGEN_GPIO_SET_SDP_DATA_SHIFT) +#define I40E_GLGEN_GPIO_SET_SDP_DATA_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_SET_SDP_DATA_SHIFT) #define I40E_GLGEN_GPIO_SET_DRIVE_SDP_SHIFT 6 -#define I40E_GLGEN_GPIO_SET_DRIVE_SDP_MASK (0x1 << I40E_GLGEN_GPIO_SET_DRIVE_SDP_SHIFT) -#define I40E_GLGEN_GPIO_STAT 0x0008817C +#define I40E_GLGEN_GPIO_SET_DRIVE_SDP_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_SET_DRIVE_SDP_SHIFT) +#define I40E_GLGEN_GPIO_STAT 0x0008817C /* Reset: POR */ #define I40E_GLGEN_GPIO_STAT_GPIO_VALUE_SHIFT 0 -#define I40E_GLGEN_GPIO_STAT_GPIO_VALUE_MASK (0x3FFFFFFF << I40E_GLGEN_GPIO_STAT_GPIO_VALUE_SHIFT) -#define I40E_GLGEN_GPIO_TRANSIT 0x00088180 +#define I40E_GLGEN_GPIO_STAT_GPIO_VALUE_MASK I40E_MASK(0x3FFFFFFF, I40E_GLGEN_GPIO_STAT_GPIO_VALUE_SHIFT) +#define I40E_GLGEN_GPIO_TRANSIT 0x00088180 /* Reset: POR */ #define I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_SHIFT 0 -#define I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_MASK (0x3FFFFFFF << I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_SHIFT) -#define I40E_GLGEN_I2CCMD(_i) (0x000881E0 + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_MASK I40E_MASK(0x3FFFFFFF, I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_SHIFT) +#define I40E_GLGEN_I2CCMD(_i) (0x000881E0 + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ #define I40E_GLGEN_I2CCMD_MAX_INDEX 3 #define I40E_GLGEN_I2CCMD_DATA_SHIFT 0 -#define I40E_GLGEN_I2CCMD_DATA_MASK (0xFFFF << I40E_GLGEN_I2CCMD_DATA_SHIFT) +#define I40E_GLGEN_I2CCMD_DATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_I2CCMD_DATA_SHIFT) #define I40E_GLGEN_I2CCMD_REGADD_SHIFT 16 -#define I40E_GLGEN_I2CCMD_REGADD_MASK (0xFF << I40E_GLGEN_I2CCMD_REGADD_SHIFT) +#define I40E_GLGEN_I2CCMD_REGADD_MASK I40E_MASK(0xFF, I40E_GLGEN_I2CCMD_REGADD_SHIFT) #define I40E_GLGEN_I2CCMD_PHYADD_SHIFT 24 -#define I40E_GLGEN_I2CCMD_PHYADD_MASK (0x7 << I40E_GLGEN_I2CCMD_PHYADD_SHIFT) +#define I40E_GLGEN_I2CCMD_PHYADD_MASK I40E_MASK(0x7, I40E_GLGEN_I2CCMD_PHYADD_SHIFT) #define I40E_GLGEN_I2CCMD_OP_SHIFT 27 -#define I40E_GLGEN_I2CCMD_OP_MASK (0x1 << I40E_GLGEN_I2CCMD_OP_SHIFT) +#define I40E_GLGEN_I2CCMD_OP_MASK I40E_MASK(0x1, I40E_GLGEN_I2CCMD_OP_SHIFT) #define I40E_GLGEN_I2CCMD_RESET_SHIFT 28 -#define I40E_GLGEN_I2CCMD_RESET_MASK (0x1 << I40E_GLGEN_I2CCMD_RESET_SHIFT) +#define I40E_GLGEN_I2CCMD_RESET_MASK I40E_MASK(0x1, I40E_GLGEN_I2CCMD_RESET_SHIFT) #define I40E_GLGEN_I2CCMD_R_SHIFT 29 -#define I40E_GLGEN_I2CCMD_R_MASK (0x1 << I40E_GLGEN_I2CCMD_R_SHIFT) +#define I40E_GLGEN_I2CCMD_R_MASK I40E_MASK(0x1, I40E_GLGEN_I2CCMD_R_SHIFT) #define I40E_GLGEN_I2CCMD_E_SHIFT 31 -#define I40E_GLGEN_I2CCMD_E_MASK (0x1 << I40E_GLGEN_I2CCMD_E_SHIFT) -#define I40E_GLGEN_I2CPARAMS(_i) (0x000881AC + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_I2CCMD_E_MASK I40E_MASK(0x1, I40E_GLGEN_I2CCMD_E_SHIFT) +#define I40E_GLGEN_I2CPARAMS(_i) (0x000881AC + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ #define I40E_GLGEN_I2CPARAMS_MAX_INDEX 3 #define I40E_GLGEN_I2CPARAMS_WRITE_TIME_SHIFT 0 -#define I40E_GLGEN_I2CPARAMS_WRITE_TIME_MASK (0x1F << I40E_GLGEN_I2CPARAMS_WRITE_TIME_SHIFT) +#define I40E_GLGEN_I2CPARAMS_WRITE_TIME_MASK I40E_MASK(0x1F, I40E_GLGEN_I2CPARAMS_WRITE_TIME_SHIFT) #define I40E_GLGEN_I2CPARAMS_READ_TIME_SHIFT 5 -#define I40E_GLGEN_I2CPARAMS_READ_TIME_MASK (0x7 << I40E_GLGEN_I2CPARAMS_READ_TIME_SHIFT) +#define I40E_GLGEN_I2CPARAMS_READ_TIME_MASK I40E_MASK(0x7, I40E_GLGEN_I2CPARAMS_READ_TIME_SHIFT) #define I40E_GLGEN_I2CPARAMS_I2CBB_EN_SHIFT 8 -#define I40E_GLGEN_I2CPARAMS_I2CBB_EN_MASK (0x1 << I40E_GLGEN_I2CPARAMS_I2CBB_EN_SHIFT) +#define I40E_GLGEN_I2CPARAMS_I2CBB_EN_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_I2CBB_EN_SHIFT) #define I40E_GLGEN_I2CPARAMS_CLK_SHIFT 9 -#define I40E_GLGEN_I2CPARAMS_CLK_MASK (0x1 << I40E_GLGEN_I2CPARAMS_CLK_SHIFT) +#define I40E_GLGEN_I2CPARAMS_CLK_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_CLK_SHIFT) #define I40E_GLGEN_I2CPARAMS_DATA_OUT_SHIFT 10 -#define I40E_GLGEN_I2CPARAMS_DATA_OUT_MASK (0x1 << I40E_GLGEN_I2CPARAMS_DATA_OUT_SHIFT) +#define I40E_GLGEN_I2CPARAMS_DATA_OUT_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_DATA_OUT_SHIFT) #define I40E_GLGEN_I2CPARAMS_DATA_OE_N_SHIFT 11 -#define I40E_GLGEN_I2CPARAMS_DATA_OE_N_MASK (0x1 << I40E_GLGEN_I2CPARAMS_DATA_OE_N_SHIFT) +#define I40E_GLGEN_I2CPARAMS_DATA_OE_N_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_DATA_OE_N_SHIFT) #define I40E_GLGEN_I2CPARAMS_DATA_IN_SHIFT 12 -#define I40E_GLGEN_I2CPARAMS_DATA_IN_MASK (0x1 << I40E_GLGEN_I2CPARAMS_DATA_IN_SHIFT) +#define I40E_GLGEN_I2CPARAMS_DATA_IN_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_DATA_IN_SHIFT) #define I40E_GLGEN_I2CPARAMS_CLK_OE_N_SHIFT 13 -#define I40E_GLGEN_I2CPARAMS_CLK_OE_N_MASK (0x1 << I40E_GLGEN_I2CPARAMS_CLK_OE_N_SHIFT) +#define I40E_GLGEN_I2CPARAMS_CLK_OE_N_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_CLK_OE_N_SHIFT) #define I40E_GLGEN_I2CPARAMS_CLK_IN_SHIFT 14 -#define I40E_GLGEN_I2CPARAMS_CLK_IN_MASK (0x1 << I40E_GLGEN_I2CPARAMS_CLK_IN_SHIFT) +#define I40E_GLGEN_I2CPARAMS_CLK_IN_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_CLK_IN_SHIFT) #define I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_SHIFT 15 -#define I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_MASK (0x1 << I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_SHIFT) +#define I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_SHIFT) #define I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_SHIFT 31 -#define I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_MASK (0x1 << I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_SHIFT) -#define I40E_GLGEN_LED_CTL 0x00088178 +#define I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_SHIFT) +#define I40E_GLGEN_LED_CTL 0x00088178 /* Reset: POR */ #define I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_SHIFT 0 -#define I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_MASK (0x1 << I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_SHIFT) -#define I40E_GLGEN_MDIO_CTRL(_i) (0x000881D0 + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_MASK I40E_MASK(0x1, I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_SHIFT) +#define I40E_GLGEN_MDIO_CTRL(_i) (0x000881D0 + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ #define I40E_GLGEN_MDIO_CTRL_MAX_INDEX 3 #define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_SHIFT 0 -#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_MASK (0x1FFFF << I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_SHIFT) +#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_MASK I40E_MASK(0x1FFFF, I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_SHIFT) #define I40E_GLGEN_MDIO_CTRL_CONTMDC_SHIFT 17 -#define I40E_GLGEN_MDIO_CTRL_CONTMDC_MASK (0x1 << I40E_GLGEN_MDIO_CTRL_CONTMDC_SHIFT) +#define I40E_GLGEN_MDIO_CTRL_CONTMDC_MASK I40E_MASK(0x1, I40E_GLGEN_MDIO_CTRL_CONTMDC_SHIFT) #define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_SHIFT 18 -#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_MASK (0x3FFF << I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_SHIFT) -#define I40E_GLGEN_MDIO_I2C_SEL(_i) (0x000881C0 + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_MASK I40E_MASK(0x3FFF, I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL(_i) (0x000881C0 + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ #define I40E_GLGEN_MDIO_I2C_SEL_MAX_INDEX 3 #define I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_SHIFT 0 -#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_MASK (0x1 << I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_MASK I40E_MASK(0x1, I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_SHIFT 1 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_MASK (0xF << I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_MASK I40E_MASK(0xF, I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_SHIFT 5 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_MASK (0x1F << I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_MASK I40E_MASK(0x1F, I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_SHIFT 10 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_MASK (0x1F << I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_MASK I40E_MASK(0x1F, I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_SHIFT 15 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_MASK (0x1F << I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_MASK I40E_MASK(0x1F, I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_SHIFT 20 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_MASK (0x1F << I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_MASK I40E_MASK(0x1F, I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_SHIFT 25 -#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_MASK (0xF << I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_MASK I40E_MASK(0xF, I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_SHIFT 31 -#define I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_MASK (0x1 << I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_SHIFT) -#define I40E_GLGEN_MSCA(_i) (0x0008818C + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_MASK I40E_MASK(0x1, I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_SHIFT) +#define I40E_GLGEN_MSCA(_i) (0x0008818C + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ #define I40E_GLGEN_MSCA_MAX_INDEX 3 #define I40E_GLGEN_MSCA_MDIADD_SHIFT 0 -#define I40E_GLGEN_MSCA_MDIADD_MASK (0xFFFF << I40E_GLGEN_MSCA_MDIADD_SHIFT) +#define I40E_GLGEN_MSCA_MDIADD_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSCA_MDIADD_SHIFT) #define I40E_GLGEN_MSCA_DEVADD_SHIFT 16 -#define I40E_GLGEN_MSCA_DEVADD_MASK (0x1F << I40E_GLGEN_MSCA_DEVADD_SHIFT) +#define I40E_GLGEN_MSCA_DEVADD_MASK I40E_MASK(0x1F, I40E_GLGEN_MSCA_DEVADD_SHIFT) #define I40E_GLGEN_MSCA_PHYADD_SHIFT 21 -#define I40E_GLGEN_MSCA_PHYADD_MASK (0x1F << I40E_GLGEN_MSCA_PHYADD_SHIFT) +#define I40E_GLGEN_MSCA_PHYADD_MASK I40E_MASK(0x1F, I40E_GLGEN_MSCA_PHYADD_SHIFT) #define I40E_GLGEN_MSCA_OPCODE_SHIFT 26 -#define I40E_GLGEN_MSCA_OPCODE_MASK (0x3 << I40E_GLGEN_MSCA_OPCODE_SHIFT) +#define I40E_GLGEN_MSCA_OPCODE_MASK I40E_MASK(0x3, I40E_GLGEN_MSCA_OPCODE_SHIFT) #define I40E_GLGEN_MSCA_STCODE_SHIFT 28 -#define I40E_GLGEN_MSCA_STCODE_MASK (0x3 << I40E_GLGEN_MSCA_STCODE_SHIFT) +#define I40E_GLGEN_MSCA_STCODE_MASK I40E_MASK(0x3, I40E_GLGEN_MSCA_STCODE_SHIFT) #define I40E_GLGEN_MSCA_MDICMD_SHIFT 30 -#define I40E_GLGEN_MSCA_MDICMD_MASK (0x1 << I40E_GLGEN_MSCA_MDICMD_SHIFT) +#define I40E_GLGEN_MSCA_MDICMD_MASK I40E_MASK(0x1, I40E_GLGEN_MSCA_MDICMD_SHIFT) #define I40E_GLGEN_MSCA_MDIINPROGEN_SHIFT 31 -#define I40E_GLGEN_MSCA_MDIINPROGEN_MASK (0x1 << I40E_GLGEN_MSCA_MDIINPROGEN_SHIFT) -#define I40E_GLGEN_MSRWD(_i) (0x0008819C + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_MSCA_MDIINPROGEN_MASK I40E_MASK(0x1, I40E_GLGEN_MSCA_MDIINPROGEN_SHIFT) +#define I40E_GLGEN_MSRWD(_i) (0x0008819C + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ #define I40E_GLGEN_MSRWD_MAX_INDEX 3 #define I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT 0 -#define I40E_GLGEN_MSRWD_MDIWRDATA_MASK (0xFFFF << I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT) +#define I40E_GLGEN_MSRWD_MDIWRDATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT) #define I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT 16 -#define I40E_GLGEN_MSRWD_MDIRDDATA_MASK (0xFFFF << I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT) -#define I40E_GLGEN_PCIFCNCNT 0x001C0AB4 +#define I40E_GLGEN_MSRWD_MDIRDDATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT) +#define I40E_GLGEN_PCIFCNCNT 0x001C0AB4 /* Reset: PCIR */ #define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT 0 -#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK (0x1F << I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT) +#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK I40E_MASK(0x1F, I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT) #define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT 16 -#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_MASK (0xFF << I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT) -#define I40E_GLGEN_PE_ENA 0x000B81A0 -#define I40E_GLGEN_PE_ENA_PE_ENA_SHIFT 0 -#define I40E_GLGEN_PE_ENA_PE_ENA_MASK (0x1 << I40E_GLGEN_PE_ENA_PE_ENA_SHIFT) -#define I40E_GLGEN_PE_ENA_PE_CLK_SRC_SEL_SHIFT 1 -#define I40E_GLGEN_PE_ENA_PE_CLK_SRC_SEL_MASK (0x3 << I40E_GLGEN_PE_ENA_PE_CLK_SRC_SEL_SHIFT) -#define I40E_GLGEN_RSTAT 0x000B8188 +#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_MASK I40E_MASK(0xFF, I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT) +#define I40E_GLGEN_RSTAT 0x000B8188 /* Reset: POR */ #define I40E_GLGEN_RSTAT_DEVSTATE_SHIFT 0 -#define I40E_GLGEN_RSTAT_DEVSTATE_MASK (0x3 << I40E_GLGEN_RSTAT_DEVSTATE_SHIFT) +#define I40E_GLGEN_RSTAT_DEVSTATE_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_DEVSTATE_SHIFT) #define I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT 2 -#define I40E_GLGEN_RSTAT_RESET_TYPE_MASK (0x3 << I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT) +#define I40E_GLGEN_RSTAT_RESET_TYPE_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT) #define I40E_GLGEN_RSTAT_CORERCNT_SHIFT 4 -#define I40E_GLGEN_RSTAT_CORERCNT_MASK (0x3 << I40E_GLGEN_RSTAT_CORERCNT_SHIFT) +#define I40E_GLGEN_RSTAT_CORERCNT_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_CORERCNT_SHIFT) #define I40E_GLGEN_RSTAT_GLOBRCNT_SHIFT 6 -#define I40E_GLGEN_RSTAT_GLOBRCNT_MASK (0x3 << I40E_GLGEN_RSTAT_GLOBRCNT_SHIFT) +#define I40E_GLGEN_RSTAT_GLOBRCNT_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_GLOBRCNT_SHIFT) #define I40E_GLGEN_RSTAT_EMPRCNT_SHIFT 8 -#define I40E_GLGEN_RSTAT_EMPRCNT_MASK (0x3 << I40E_GLGEN_RSTAT_EMPRCNT_SHIFT) +#define I40E_GLGEN_RSTAT_EMPRCNT_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_EMPRCNT_SHIFT) #define I40E_GLGEN_RSTAT_TIME_TO_RST_SHIFT 10 -#define I40E_GLGEN_RSTAT_TIME_TO_RST_MASK (0x3F << I40E_GLGEN_RSTAT_TIME_TO_RST_SHIFT) -#define I40E_GLGEN_RSTCTL 0x000B8180 +#define I40E_GLGEN_RSTAT_TIME_TO_RST_MASK I40E_MASK(0x3F, I40E_GLGEN_RSTAT_TIME_TO_RST_SHIFT) +#define I40E_GLGEN_RSTCTL 0x000B8180 /* Reset: POR */ #define I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT 0 -#define I40E_GLGEN_RSTCTL_GRSTDEL_MASK (0x3F << I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT) +#define I40E_GLGEN_RSTCTL_GRSTDEL_MASK I40E_MASK(0x3F, I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT) #define I40E_GLGEN_RSTCTL_ECC_RST_ENA_SHIFT 8 -#define I40E_GLGEN_RSTCTL_ECC_RST_ENA_MASK (0x1 << I40E_GLGEN_RSTCTL_ECC_RST_ENA_SHIFT) -#define I40E_GLGEN_RSTENA_EMP 0x000B818C +#define I40E_GLGEN_RSTCTL_ECC_RST_ENA_MASK I40E_MASK(0x1, I40E_GLGEN_RSTCTL_ECC_RST_ENA_SHIFT) +#define I40E_GLGEN_RSTENA_EMP 0x000B818C /* Reset: POR */ #define I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_SHIFT 0 -#define I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_MASK (0x1 << I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_SHIFT) -#define I40E_GLGEN_RTRIG 0x000B8190 +#define I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_MASK I40E_MASK(0x1, I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_SHIFT) +#define I40E_GLGEN_RTRIG 0x000B8190 /* Reset: CORER */ #define I40E_GLGEN_RTRIG_CORER_SHIFT 0 -#define I40E_GLGEN_RTRIG_CORER_MASK (0x1 << I40E_GLGEN_RTRIG_CORER_SHIFT) +#define I40E_GLGEN_RTRIG_CORER_MASK I40E_MASK(0x1, I40E_GLGEN_RTRIG_CORER_SHIFT) #define I40E_GLGEN_RTRIG_GLOBR_SHIFT 1 -#define I40E_GLGEN_RTRIG_GLOBR_MASK (0x1 << I40E_GLGEN_RTRIG_GLOBR_SHIFT) +#define I40E_GLGEN_RTRIG_GLOBR_MASK I40E_MASK(0x1, I40E_GLGEN_RTRIG_GLOBR_SHIFT) #define I40E_GLGEN_RTRIG_EMPFWR_SHIFT 2 -#define I40E_GLGEN_RTRIG_EMPFWR_MASK (0x1 << I40E_GLGEN_RTRIG_EMPFWR_SHIFT) -#define I40E_GLGEN_STAT 0x000B612C +#define I40E_GLGEN_RTRIG_EMPFWR_MASK I40E_MASK(0x1, I40E_GLGEN_RTRIG_EMPFWR_SHIFT) +#define I40E_GLGEN_STAT 0x000B612C /* Reset: POR */ #define I40E_GLGEN_STAT_HWRSVD0_SHIFT 0 -#define I40E_GLGEN_STAT_HWRSVD0_MASK (0x3 << I40E_GLGEN_STAT_HWRSVD0_SHIFT) +#define I40E_GLGEN_STAT_HWRSVD0_MASK I40E_MASK(0x3, I40E_GLGEN_STAT_HWRSVD0_SHIFT) #define I40E_GLGEN_STAT_DCBEN_SHIFT 2 -#define I40E_GLGEN_STAT_DCBEN_MASK (0x1 << I40E_GLGEN_STAT_DCBEN_SHIFT) +#define I40E_GLGEN_STAT_DCBEN_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_DCBEN_SHIFT) #define I40E_GLGEN_STAT_VTEN_SHIFT 3 -#define I40E_GLGEN_STAT_VTEN_MASK (0x1 << I40E_GLGEN_STAT_VTEN_SHIFT) +#define I40E_GLGEN_STAT_VTEN_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_VTEN_SHIFT) #define I40E_GLGEN_STAT_FCOEN_SHIFT 4 -#define I40E_GLGEN_STAT_FCOEN_MASK (0x1 << I40E_GLGEN_STAT_FCOEN_SHIFT) +#define I40E_GLGEN_STAT_FCOEN_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_FCOEN_SHIFT) #define I40E_GLGEN_STAT_EVBEN_SHIFT 5 -#define I40E_GLGEN_STAT_EVBEN_MASK (0x1 << I40E_GLGEN_STAT_EVBEN_SHIFT) +#define I40E_GLGEN_STAT_EVBEN_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_EVBEN_SHIFT) #define I40E_GLGEN_STAT_HWRSVD1_SHIFT 6 -#define I40E_GLGEN_STAT_HWRSVD1_MASK (0x3 << I40E_GLGEN_STAT_HWRSVD1_SHIFT) -#define I40E_GLGEN_VFLRSTAT(_i) (0x00092600 + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_STAT_HWRSVD1_MASK I40E_MASK(0x3, I40E_GLGEN_STAT_HWRSVD1_SHIFT) +#define I40E_GLGEN_VFLRSTAT(_i) (0x00092600 + ((_i) * 4)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLGEN_VFLRSTAT_MAX_INDEX 3 #define I40E_GLGEN_VFLRSTAT_VFLRE_SHIFT 0 -#define I40E_GLGEN_VFLRSTAT_VFLRE_MASK (0xFFFFFFFF << I40E_GLGEN_VFLRSTAT_VFLRE_SHIFT) -#define I40E_GLVFGEN_TIMER 0x000881BC +#define I40E_GLGEN_VFLRSTAT_VFLRE_MASK I40E_MASK(0xFFFFFFFF, I40E_GLGEN_VFLRSTAT_VFLRE_SHIFT) +#define I40E_GLVFGEN_TIMER 0x000881BC /* Reset: CORER */ #define I40E_GLVFGEN_TIMER_GTIME_SHIFT 0 -#define I40E_GLVFGEN_TIMER_GTIME_MASK (0xFFFFFFFF << I40E_GLVFGEN_TIMER_GTIME_SHIFT) -#define I40E_PFGEN_CTRL 0x00092400 +#define I40E_GLVFGEN_TIMER_GTIME_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVFGEN_TIMER_GTIME_SHIFT) +#define I40E_PFGEN_CTRL 0x00092400 /* Reset: PFR */ #define I40E_PFGEN_CTRL_PFSWR_SHIFT 0 -#define I40E_PFGEN_CTRL_PFSWR_MASK (0x1 << I40E_PFGEN_CTRL_PFSWR_SHIFT) -#define I40E_PFGEN_DRUN 0x00092500 +#define I40E_PFGEN_CTRL_PFSWR_MASK I40E_MASK(0x1, I40E_PFGEN_CTRL_PFSWR_SHIFT) +#define I40E_PFGEN_DRUN 0x00092500 /* Reset: CORER */ #define I40E_PFGEN_DRUN_DRVUNLD_SHIFT 0 -#define I40E_PFGEN_DRUN_DRVUNLD_MASK (0x1 << I40E_PFGEN_DRUN_DRVUNLD_SHIFT) -#define I40E_PFGEN_PORTNUM 0x001C0480 +#define I40E_PFGEN_DRUN_DRVUNLD_MASK I40E_MASK(0x1, I40E_PFGEN_DRUN_DRVUNLD_SHIFT) +#define I40E_PFGEN_PORTNUM 0x001C0480 /* Reset: CORER */ #define I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT 0 -#define I40E_PFGEN_PORTNUM_PORT_NUM_MASK (0x3 << I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT) -#define I40E_PFGEN_STATE 0x00088000 -#define I40E_PFGEN_STATE_PFPEEN_SHIFT 0 -#define I40E_PFGEN_STATE_PFPEEN_MASK (0x1 << I40E_PFGEN_STATE_PFPEEN_SHIFT) +#define I40E_PFGEN_PORTNUM_PORT_NUM_MASK I40E_MASK(0x3, I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT) +#define I40E_PFGEN_STATE 0x00088000 /* Reset: CORER */ +#define I40E_PFGEN_STATE_RESERVED_0_SHIFT 0 +#define I40E_PFGEN_STATE_RESERVED_0_MASK I40E_MASK(0x1, I40E_PFGEN_STATE_RESERVED_0_SHIFT) #define I40E_PFGEN_STATE_PFFCEN_SHIFT 1 -#define I40E_PFGEN_STATE_PFFCEN_MASK (0x1 << I40E_PFGEN_STATE_PFFCEN_SHIFT) +#define I40E_PFGEN_STATE_PFFCEN_MASK I40E_MASK(0x1, I40E_PFGEN_STATE_PFFCEN_SHIFT) #define I40E_PFGEN_STATE_PFLINKEN_SHIFT 2 -#define I40E_PFGEN_STATE_PFLINKEN_MASK (0x1 << I40E_PFGEN_STATE_PFLINKEN_SHIFT) +#define I40E_PFGEN_STATE_PFLINKEN_MASK I40E_MASK(0x1, I40E_PFGEN_STATE_PFLINKEN_SHIFT) #define I40E_PFGEN_STATE_PFSCEN_SHIFT 3 -#define I40E_PFGEN_STATE_PFSCEN_MASK (0x1 << I40E_PFGEN_STATE_PFSCEN_SHIFT) -#define I40E_PRTGEN_CNF 0x000B8120 +#define I40E_PFGEN_STATE_PFSCEN_MASK I40E_MASK(0x1, I40E_PFGEN_STATE_PFSCEN_SHIFT) +#define I40E_PRTGEN_CNF 0x000B8120 /* Reset: POR */ #define I40E_PRTGEN_CNF_PORT_DIS_SHIFT 0 -#define I40E_PRTGEN_CNF_PORT_DIS_MASK (0x1 << I40E_PRTGEN_CNF_PORT_DIS_SHIFT) +#define I40E_PRTGEN_CNF_PORT_DIS_MASK I40E_MASK(0x1, I40E_PRTGEN_CNF_PORT_DIS_SHIFT) #define I40E_PRTGEN_CNF_ALLOW_PORT_DIS_SHIFT 1 -#define I40E_PRTGEN_CNF_ALLOW_PORT_DIS_MASK (0x1 << I40E_PRTGEN_CNF_ALLOW_PORT_DIS_SHIFT) +#define I40E_PRTGEN_CNF_ALLOW_PORT_DIS_MASK I40E_MASK(0x1, I40E_PRTGEN_CNF_ALLOW_PORT_DIS_SHIFT) #define I40E_PRTGEN_CNF_EMP_PORT_DIS_SHIFT 2 -#define I40E_PRTGEN_CNF_EMP_PORT_DIS_MASK (0x1 << I40E_PRTGEN_CNF_EMP_PORT_DIS_SHIFT) -#define I40E_PRTGEN_CNF2 0x000B8160 +#define I40E_PRTGEN_CNF_EMP_PORT_DIS_MASK I40E_MASK(0x1, I40E_PRTGEN_CNF_EMP_PORT_DIS_SHIFT) +#define I40E_PRTGEN_CNF2 0x000B8160 /* Reset: POR */ #define I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_SHIFT 0 -#define I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_MASK (0x1 << I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_SHIFT) -#define I40E_PRTGEN_STATUS 0x000B8100 +#define I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_MASK I40E_MASK(0x1, I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_SHIFT) +#define I40E_PRTGEN_STATUS 0x000B8100 /* Reset: POR */ #define I40E_PRTGEN_STATUS_PORT_VALID_SHIFT 0 -#define I40E_PRTGEN_STATUS_PORT_VALID_MASK (0x1 << I40E_PRTGEN_STATUS_PORT_VALID_SHIFT) +#define I40E_PRTGEN_STATUS_PORT_VALID_MASK I40E_MASK(0x1, I40E_PRTGEN_STATUS_PORT_VALID_SHIFT) #define I40E_PRTGEN_STATUS_PORT_ACTIVE_SHIFT 1 -#define I40E_PRTGEN_STATUS_PORT_ACTIVE_MASK (0x1 << I40E_PRTGEN_STATUS_PORT_ACTIVE_SHIFT) -#define I40E_VFGEN_RSTAT1(_VF) (0x00074400 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_PRTGEN_STATUS_PORT_ACTIVE_MASK I40E_MASK(0x1, I40E_PRTGEN_STATUS_PORT_ACTIVE_SHIFT) +#define I40E_VFGEN_RSTAT1(_VF) (0x00074400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VFGEN_RSTAT1_MAX_INDEX 127 #define I40E_VFGEN_RSTAT1_VFR_STATE_SHIFT 0 -#define I40E_VFGEN_RSTAT1_VFR_STATE_MASK (0x3 << I40E_VFGEN_RSTAT1_VFR_STATE_SHIFT) -#define I40E_VPGEN_VFRSTAT(_VF) (0x00091C00 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFGEN_RSTAT1_VFR_STATE_MASK I40E_MASK(0x3, I40E_VFGEN_RSTAT1_VFR_STATE_SHIFT) +#define I40E_VPGEN_VFRSTAT(_VF) (0x00091C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VPGEN_VFRSTAT_MAX_INDEX 127 #define I40E_VPGEN_VFRSTAT_VFRD_SHIFT 0 -#define I40E_VPGEN_VFRSTAT_VFRD_MASK (0x1 << I40E_VPGEN_VFRSTAT_VFRD_SHIFT) -#define I40E_VPGEN_VFRTRIG(_VF) (0x00091800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VPGEN_VFRSTAT_VFRD_MASK I40E_MASK(0x1, I40E_VPGEN_VFRSTAT_VFRD_SHIFT) +#define I40E_VPGEN_VFRTRIG(_VF) (0x00091800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VPGEN_VFRTRIG_MAX_INDEX 127 #define I40E_VPGEN_VFRTRIG_VFSWR_SHIFT 0 -#define I40E_VPGEN_VFRTRIG_VFSWR_MASK (0x1 << I40E_VPGEN_VFRTRIG_VFSWR_SHIFT) -#define I40E_VSIGEN_RSTAT(_VSI) (0x00090800 + ((_VSI) * 4)) /* _i=0...383 */ +#define I40E_VPGEN_VFRTRIG_VFSWR_MASK I40E_MASK(0x1, I40E_VPGEN_VFRTRIG_VFSWR_SHIFT) +#define I40E_VSIGEN_RSTAT(_VSI) (0x00090800 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_VSIGEN_RSTAT_MAX_INDEX 383 #define I40E_VSIGEN_RSTAT_VMRD_SHIFT 0 -#define I40E_VSIGEN_RSTAT_VMRD_MASK (0x1 << I40E_VSIGEN_RSTAT_VMRD_SHIFT) -#define I40E_VSIGEN_RTRIG(_VSI) (0x00090000 + ((_VSI) * 4)) /* _i=0...383 */ +#define I40E_VSIGEN_RSTAT_VMRD_MASK I40E_MASK(0x1, I40E_VSIGEN_RSTAT_VMRD_SHIFT) +#define I40E_VSIGEN_RTRIG(_VSI) (0x00090000 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_VSIGEN_RTRIG_MAX_INDEX 383 #define I40E_VSIGEN_RTRIG_VMSWR_SHIFT 0 -#define I40E_VSIGEN_RTRIG_VMSWR_MASK (0x1 << I40E_VSIGEN_RTRIG_VMSWR_SHIFT) -#define I40E_GLHMC_APBVTINUSEBASE(_i) (0x000C4a00 + ((_i) * 4)) -#define I40E_GLHMC_APBVTINUSEBASE_MAX_INDEX 15 -#define I40E_GLHMC_APBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT 0 -#define I40E_GLHMC_APBVTINUSEBASE_FPMAPBINUSEBASE_MASK (0xFFFFFF << I40E_GLHMC_APBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT) -#define I40E_GLHMC_CEQPART(_i) (0x001312C0 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_CEQPART_MAX_INDEX 15 -#define I40E_GLHMC_CEQPART_PMCEQBASE_SHIFT 0 -#define I40E_GLHMC_CEQPART_PMCEQBASE_MASK (0xFF << I40E_GLHMC_CEQPART_PMCEQBASE_SHIFT) -#define I40E_GLHMC_CEQPART_PMCEQSIZE_SHIFT 16 -#define I40E_GLHMC_CEQPART_PMCEQSIZE_MASK (0x1FF << I40E_GLHMC_CEQPART_PMCEQSIZE_SHIFT) -#define I40E_GLHMC_DBCQPART(_i) (0x00131240 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_DBCQPART_MAX_INDEX 15 -#define I40E_GLHMC_DBCQPART_PMDBCQBASE_SHIFT 0 -#define I40E_GLHMC_DBCQPART_PMDBCQBASE_MASK (0x3FFF << I40E_GLHMC_DBCQPART_PMDBCQBASE_SHIFT) -#define I40E_GLHMC_DBCQPART_PMDBCQSIZE_SHIFT 16 -#define I40E_GLHMC_DBCQPART_PMDBCQSIZE_MASK (0x7FFF << I40E_GLHMC_DBCQPART_PMDBCQSIZE_SHIFT) -#define I40E_GLHMC_DBQPPART(_i) (0x00138D80 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_DBQPPART_MAX_INDEX 15 -#define I40E_GLHMC_DBQPPART_PMDBQPBASE_SHIFT 0 -#define I40E_GLHMC_DBQPPART_PMDBQPBASE_MASK (0x3FFF << I40E_GLHMC_DBQPPART_PMDBQPBASE_SHIFT) -#define I40E_GLHMC_DBQPPART_PMDBQPSIZE_SHIFT 16 -#define I40E_GLHMC_DBQPPART_PMDBQPSIZE_MASK (0x7FFF << I40E_GLHMC_DBQPPART_PMDBQPSIZE_SHIFT) -#define I40E_GLHMC_FCOEDDPBASE(_i) (0x000C6600 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_VSIGEN_RTRIG_VMSWR_MASK I40E_MASK(0x1, I40E_VSIGEN_RTRIG_VMSWR_SHIFT) +#define I40E_GLHMC_FCOEDDPBASE(_i) (0x000C6600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FCOEDDPBASE_MAX_INDEX 15 #define I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_SHIFT 0 -#define I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_MASK (0xFFFFFF << I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_SHIFT) -#define I40E_GLHMC_FCOEDDPCNT(_i) (0x000C6700 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_SHIFT) +#define I40E_GLHMC_FCOEDDPCNT(_i) (0x000C6700 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FCOEDDPCNT_MAX_INDEX 15 #define I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_SHIFT 0 -#define I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_MASK (0xFFFFF << I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_SHIFT) -#define I40E_GLHMC_FCOEDDPOBJSZ 0x000C2010 +#define I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_MASK I40E_MASK(0xFFFFF, I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_SHIFT) +#define I40E_GLHMC_FCOEDDPOBJSZ 0x000C2010 /* Reset: CORER */ #define I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_SHIFT 0 -#define I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_MASK (0xF << I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_SHIFT) -#define I40E_GLHMC_FCOEFBASE(_i) (0x000C6800 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_SHIFT) +#define I40E_GLHMC_FCOEFBASE(_i) (0x000C6800 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FCOEFBASE_MAX_INDEX 15 #define I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_SHIFT 0 -#define I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_MASK (0xFFFFFF << I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_SHIFT) -#define I40E_GLHMC_FCOEFCNT(_i) (0x000C6900 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_SHIFT) +#define I40E_GLHMC_FCOEFCNT(_i) (0x000C6900 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FCOEFCNT_MAX_INDEX 15 #define I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_SHIFT 0 -#define I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_MASK (0x7FFFFF << I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_SHIFT) -#define I40E_GLHMC_FCOEFMAX 0x000C20D0 +#define I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_MASK I40E_MASK(0x7FFFFF, I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_SHIFT) +#define I40E_GLHMC_FCOEFMAX 0x000C20D0 /* Reset: CORER */ #define I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT 0 -#define I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_MASK (0xFFFF << I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT) -#define I40E_GLHMC_FCOEFOBJSZ 0x000C2018 +#define I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_MASK I40E_MASK(0xFFFF, I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT) +#define I40E_GLHMC_FCOEFOBJSZ 0x000C2018 /* Reset: CORER */ #define I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_SHIFT 0 -#define I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_MASK (0xF << I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_SHIFT) -#define I40E_GLHMC_FCOEMAX 0x000C2014 +#define I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_SHIFT) +#define I40E_GLHMC_FCOEMAX 0x000C2014 /* Reset: CORER */ #define I40E_GLHMC_FCOEMAX_PMFCOEMAX_SHIFT 0 -#define I40E_GLHMC_FCOEMAX_PMFCOEMAX_MASK (0x1FFF << I40E_GLHMC_FCOEMAX_PMFCOEMAX_SHIFT) -#define I40E_GLHMC_FSIAVBASE(_i) (0x000C5600 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FCOEMAX_PMFCOEMAX_MASK I40E_MASK(0x1FFF, I40E_GLHMC_FCOEMAX_PMFCOEMAX_SHIFT) +#define I40E_GLHMC_FSIAVBASE(_i) (0x000C5600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FSIAVBASE_MAX_INDEX 15 #define I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_SHIFT 0 -#define I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_MASK (0xFFFFFF << I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_SHIFT) -#define I40E_GLHMC_FSIAVCNT(_i) (0x000C5700 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_SHIFT) +#define I40E_GLHMC_FSIAVCNT(_i) (0x000C5700 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FSIAVCNT_MAX_INDEX 15 #define I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_SHIFT 0 -#define I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_MASK (0x1FFFFFFF << I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_SHIFT) +#define I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_SHIFT) #define I40E_GLHMC_FSIAVCNT_RSVD_SHIFT 29 -#define I40E_GLHMC_FSIAVCNT_RSVD_MASK (0x7 << I40E_GLHMC_FSIAVCNT_RSVD_SHIFT) -#define I40E_GLHMC_FSIAVMAX 0x000C2068 +#define I40E_GLHMC_FSIAVCNT_RSVD_MASK I40E_MASK(0x7, I40E_GLHMC_FSIAVCNT_RSVD_SHIFT) +#define I40E_GLHMC_FSIAVMAX 0x000C2068 /* Reset: CORER */ #define I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_SHIFT 0 -#define I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_MASK (0x1FFFF << I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_SHIFT) -#define I40E_GLHMC_FSIAVOBJSZ 0x000C2064 +#define I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_MASK I40E_MASK(0x1FFFF, I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_SHIFT) +#define I40E_GLHMC_FSIAVOBJSZ 0x000C2064 /* Reset: CORER */ #define I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_SHIFT 0 -#define I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_MASK (0xF << I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_SHIFT) -#define I40E_GLHMC_FSIMCBASE(_i) (0x000C6000 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_SHIFT) +#define I40E_GLHMC_FSIMCBASE(_i) (0x000C6000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FSIMCBASE_MAX_INDEX 15 #define I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_SHIFT 0 -#define I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_MASK (0xFFFFFF << I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_SHIFT) -#define I40E_GLHMC_FSIMCCNT(_i) (0x000C6100 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_SHIFT) +#define I40E_GLHMC_FSIMCCNT(_i) (0x000C6100 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FSIMCCNT_MAX_INDEX 15 #define I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_SHIFT 0 -#define I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_MASK (0x1FFFFFFF << I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_SHIFT) -#define I40E_GLHMC_FSIMCMAX 0x000C2060 +#define I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_SHIFT) +#define I40E_GLHMC_FSIMCMAX 0x000C2060 /* Reset: CORER */ #define I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_SHIFT 0 -#define I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_MASK (0x3FFF << I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_SHIFT) -#define I40E_GLHMC_FSIMCOBJSZ 0x000C205c +#define I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_MASK I40E_MASK(0x3FFF, I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_SHIFT) +#define I40E_GLHMC_FSIMCOBJSZ 0x000C205c /* Reset: CORER */ #define I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_SHIFT 0 -#define I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_MASK (0xF << I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_SHIFT) -#define I40E_GLHMC_LANQMAX 0x000C2008 +#define I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_SHIFT) +#define I40E_GLHMC_LANQMAX 0x000C2008 /* Reset: CORER */ #define I40E_GLHMC_LANQMAX_PMLANQMAX_SHIFT 0 -#define I40E_GLHMC_LANQMAX_PMLANQMAX_MASK (0x7FF << I40E_GLHMC_LANQMAX_PMLANQMAX_SHIFT) -#define I40E_GLHMC_LANRXBASE(_i) (0x000C6400 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_LANQMAX_PMLANQMAX_MASK I40E_MASK(0x7FF, I40E_GLHMC_LANQMAX_PMLANQMAX_SHIFT) +#define I40E_GLHMC_LANRXBASE(_i) (0x000C6400 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_LANRXBASE_MAX_INDEX 15 #define I40E_GLHMC_LANRXBASE_FPMLANRXBASE_SHIFT 0 -#define I40E_GLHMC_LANRXBASE_FPMLANRXBASE_MASK (0xFFFFFF << I40E_GLHMC_LANRXBASE_FPMLANRXBASE_SHIFT) -#define I40E_GLHMC_LANRXCNT(_i) (0x000C6500 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_LANRXBASE_FPMLANRXBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_LANRXBASE_FPMLANRXBASE_SHIFT) +#define I40E_GLHMC_LANRXCNT(_i) (0x000C6500 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_LANRXCNT_MAX_INDEX 15 #define I40E_GLHMC_LANRXCNT_FPMLANRXCNT_SHIFT 0 -#define I40E_GLHMC_LANRXCNT_FPMLANRXCNT_MASK (0x7FF << I40E_GLHMC_LANRXCNT_FPMLANRXCNT_SHIFT) -#define I40E_GLHMC_LANRXOBJSZ 0x000C200c +#define I40E_GLHMC_LANRXCNT_FPMLANRXCNT_MASK I40E_MASK(0x7FF, I40E_GLHMC_LANRXCNT_FPMLANRXCNT_SHIFT) +#define I40E_GLHMC_LANRXOBJSZ 0x000C200c /* Reset: CORER */ #define I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_SHIFT 0 -#define I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_MASK (0xF << I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_SHIFT) -#define I40E_GLHMC_LANTXBASE(_i) (0x000C6200 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_SHIFT) +#define I40E_GLHMC_LANTXBASE(_i) (0x000C6200 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_LANTXBASE_MAX_INDEX 15 #define I40E_GLHMC_LANTXBASE_FPMLANTXBASE_SHIFT 0 -#define I40E_GLHMC_LANTXBASE_FPMLANTXBASE_MASK (0xFFFFFF << I40E_GLHMC_LANTXBASE_FPMLANTXBASE_SHIFT) +#define I40E_GLHMC_LANTXBASE_FPMLANTXBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_LANTXBASE_FPMLANTXBASE_SHIFT) #define I40E_GLHMC_LANTXBASE_RSVD_SHIFT 24 -#define I40E_GLHMC_LANTXBASE_RSVD_MASK (0xFF << I40E_GLHMC_LANTXBASE_RSVD_SHIFT) -#define I40E_GLHMC_LANTXCNT(_i) (0x000C6300 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_LANTXBASE_RSVD_MASK I40E_MASK(0xFF, I40E_GLHMC_LANTXBASE_RSVD_SHIFT) +#define I40E_GLHMC_LANTXCNT(_i) (0x000C6300 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_LANTXCNT_MAX_INDEX 15 #define I40E_GLHMC_LANTXCNT_FPMLANTXCNT_SHIFT 0 -#define I40E_GLHMC_LANTXCNT_FPMLANTXCNT_MASK (0x7FF << I40E_GLHMC_LANTXCNT_FPMLANTXCNT_SHIFT) -#define I40E_GLHMC_LANTXOBJSZ 0x000C2004 +#define I40E_GLHMC_LANTXCNT_FPMLANTXCNT_MASK I40E_MASK(0x7FF, I40E_GLHMC_LANTXCNT_FPMLANTXCNT_SHIFT) +#define I40E_GLHMC_LANTXOBJSZ 0x000C2004 /* Reset: CORER */ #define I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_SHIFT 0 -#define I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_MASK (0xF << I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_SHIFT) -#define I40E_GLHMC_PEARPBASE(_i) (0x000C4800 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEARPBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEARPBASE_FPMPEARPBASE_SHIFT 0 -#define I40E_GLHMC_PEARPBASE_FPMPEARPBASE_MASK (0xFFFFFF << I40E_GLHMC_PEARPBASE_FPMPEARPBASE_SHIFT) -#define I40E_GLHMC_PEARPCNT(_i) (0x000C4900 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEARPCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEARPCNT_FPMPEARPCNT_SHIFT 0 -#define I40E_GLHMC_PEARPCNT_FPMPEARPCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEARPCNT_FPMPEARPCNT_SHIFT) -#define I40E_GLHMC_PEARPMAX 0x000C2038 -#define I40E_GLHMC_PEARPMAX_PMPEARPMAX_SHIFT 0 -#define I40E_GLHMC_PEARPMAX_PMPEARPMAX_MASK (0x1FFFF << I40E_GLHMC_PEARPMAX_PMPEARPMAX_SHIFT) -#define I40E_GLHMC_PEARPOBJSZ 0x000C2034 -#define I40E_GLHMC_PEARPOBJSZ_PMPEARPOBJSZ_SHIFT 0 -#define I40E_GLHMC_PEARPOBJSZ_PMPEARPOBJSZ_MASK (0x7 << I40E_GLHMC_PEARPOBJSZ_PMPEARPOBJSZ_SHIFT) -#define I40E_GLHMC_PECQBASE(_i) (0x000C4200 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PECQBASE_MAX_INDEX 15 -#define I40E_GLHMC_PECQBASE_FPMPECQBASE_SHIFT 0 -#define I40E_GLHMC_PECQBASE_FPMPECQBASE_MASK (0xFFFFFF << I40E_GLHMC_PECQBASE_FPMPECQBASE_SHIFT) -#define I40E_GLHMC_PECQCNT(_i) (0x000C4300 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PECQCNT_MAX_INDEX 15 -#define I40E_GLHMC_PECQCNT_FPMPECQCNT_SHIFT 0 -#define I40E_GLHMC_PECQCNT_FPMPECQCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PECQCNT_FPMPECQCNT_SHIFT) -#define I40E_GLHMC_PECQOBJSZ 0x000C2020 -#define I40E_GLHMC_PECQOBJSZ_PMPECQOBJSZ_SHIFT 0 -#define I40E_GLHMC_PECQOBJSZ_PMPECQOBJSZ_MASK (0xF << I40E_GLHMC_PECQOBJSZ_PMPECQOBJSZ_SHIFT) -#define I40E_GLHMC_PEHTCNT(_i) (0x000C4700 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEHTCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEHTCNT_FPMPEHTCNT_SHIFT 0 -#define I40E_GLHMC_PEHTCNT_FPMPEHTCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEHTCNT_FPMPEHTCNT_SHIFT) -#define I40E_GLHMC_PEHTEBASE(_i) (0x000C4600 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEHTEBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEHTEBASE_FPMPEHTEBASE_SHIFT 0 -#define I40E_GLHMC_PEHTEBASE_FPMPEHTEBASE_MASK (0xFFFFFF << I40E_GLHMC_PEHTEBASE_FPMPEHTEBASE_SHIFT) -#define I40E_GLHMC_PEHTEOBJSZ 0x000C202c -#define I40E_GLHMC_PEHTEOBJSZ_PMPEHTEOBJSZ_SHIFT 0 -#define I40E_GLHMC_PEHTEOBJSZ_PMPEHTEOBJSZ_MASK (0xF << I40E_GLHMC_PEHTEOBJSZ_PMPEHTEOBJSZ_SHIFT) -#define I40E_GLHMC_PEHTMAX 0x000C2030 -#define I40E_GLHMC_PEHTMAX_PMPEHTMAX_SHIFT 0 -#define I40E_GLHMC_PEHTMAX_PMPEHTMAX_MASK (0x1FFFFF << I40E_GLHMC_PEHTMAX_PMPEHTMAX_SHIFT) -#define I40E_GLHMC_PEMRBASE(_i) (0x000C4c00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEMRBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEMRBASE_FPMPEMRBASE_SHIFT 0 -#define I40E_GLHMC_PEMRBASE_FPMPEMRBASE_MASK (0xFFFFFF << I40E_GLHMC_PEMRBASE_FPMPEMRBASE_SHIFT) -#define I40E_GLHMC_PEMRCNT(_i) (0x000C4d00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEMRCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEMRCNT_FPMPEMRSZ_SHIFT 0 -#define I40E_GLHMC_PEMRCNT_FPMPEMRSZ_MASK (0x1FFFFFFF << I40E_GLHMC_PEMRCNT_FPMPEMRSZ_SHIFT) -#define I40E_GLHMC_PEMRMAX 0x000C2040 -#define I40E_GLHMC_PEMRMAX_PMPEMRMAX_SHIFT 0 -#define I40E_GLHMC_PEMRMAX_PMPEMRMAX_MASK (0x7FFFFF << I40E_GLHMC_PEMRMAX_PMPEMRMAX_SHIFT) -#define I40E_GLHMC_PEMROBJSZ 0x000C203c -#define I40E_GLHMC_PEMROBJSZ_PMPEMROBJSZ_SHIFT 0 -#define I40E_GLHMC_PEMROBJSZ_PMPEMROBJSZ_MASK (0xF << I40E_GLHMC_PEMROBJSZ_PMPEMROBJSZ_SHIFT) -#define I40E_GLHMC_PEPBLBASE(_i) (0x000C5800 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEPBLBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEPBLBASE_FPMPEPBLBASE_SHIFT 0 -#define I40E_GLHMC_PEPBLBASE_FPMPEPBLBASE_MASK (0xFFFFFF << I40E_GLHMC_PEPBLBASE_FPMPEPBLBASE_SHIFT) -#define I40E_GLHMC_PEPBLCNT(_i) (0x000C5900 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEPBLCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEPBLCNT_FPMPEPBLCNT_SHIFT 0 -#define I40E_GLHMC_PEPBLCNT_FPMPEPBLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEPBLCNT_FPMPEPBLCNT_SHIFT) -#define I40E_GLHMC_PEPBLMAX 0x000C206c -#define I40E_GLHMC_PEPBLMAX_PMPEPBLMAX_SHIFT 0 -#define I40E_GLHMC_PEPBLMAX_PMPEPBLMAX_MASK (0x1FFFFFFF << I40E_GLHMC_PEPBLMAX_PMPEPBLMAX_SHIFT) -#define I40E_GLHMC_PEQ1BASE(_i) (0x000C5200 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEQ1BASE_MAX_INDEX 15 -#define I40E_GLHMC_PEQ1BASE_FPMPEQ1BASE_SHIFT 0 -#define I40E_GLHMC_PEQ1BASE_FPMPEQ1BASE_MASK (0xFFFFFF << I40E_GLHMC_PEQ1BASE_FPMPEQ1BASE_SHIFT) -#define I40E_GLHMC_PEQ1CNT(_i) (0x000C5300 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEQ1CNT_MAX_INDEX 15 -#define I40E_GLHMC_PEQ1CNT_FPMPEQ1CNT_SHIFT 0 -#define I40E_GLHMC_PEQ1CNT_FPMPEQ1CNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEQ1CNT_FPMPEQ1CNT_SHIFT) -#define I40E_GLHMC_PEQ1FLBASE(_i) (0x000C5400 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEQ1FLBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEQ1FLBASE_FPMPEQ1FLBASE_SHIFT 0 -#define I40E_GLHMC_PEQ1FLBASE_FPMPEQ1FLBASE_MASK (0xFFFFFF << I40E_GLHMC_PEQ1FLBASE_FPMPEQ1FLBASE_SHIFT) -#define I40E_GLHMC_PEQ1FLCNT(_i) (0x000C5500 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEQ1FLCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEQ1FLCNT_FPMPEQ1FLCNT_SHIFT 0 -#define I40E_GLHMC_PEQ1FLCNT_FPMPEQ1FLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEQ1FLCNT_FPMPEQ1FLCNT_SHIFT) -#define I40E_GLHMC_PEQ1FLMAX 0x000C2058 -#define I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_SHIFT 0 -#define I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_MASK (0x3FFFFFF << I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_SHIFT) -#define I40E_GLHMC_PEQ1MAX 0x000C2054 -#define I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_SHIFT 0 -#define I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_MASK (0x3FFFFFF << I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_SHIFT) -#define I40E_GLHMC_PEQ1OBJSZ 0x000C2050 -#define I40E_GLHMC_PEQ1OBJSZ_PMPEQ1OBJSZ_SHIFT 0 -#define I40E_GLHMC_PEQ1OBJSZ_PMPEQ1OBJSZ_MASK (0xF << I40E_GLHMC_PEQ1OBJSZ_PMPEQ1OBJSZ_SHIFT) -#define I40E_GLHMC_PEQPBASE(_i) (0x000C4000 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEQPBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEQPBASE_FPMPEQPBASE_SHIFT 0 -#define I40E_GLHMC_PEQPBASE_FPMPEQPBASE_MASK (0xFFFFFF << I40E_GLHMC_PEQPBASE_FPMPEQPBASE_SHIFT) -#define I40E_GLHMC_PEQPCNT(_i) (0x000C4100 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEQPCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEQPCNT_FPMPEQPCNT_SHIFT 0 -#define I40E_GLHMC_PEQPCNT_FPMPEQPCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEQPCNT_FPMPEQPCNT_SHIFT) -#define I40E_GLHMC_PEQPOBJSZ 0x000C201c -#define I40E_GLHMC_PEQPOBJSZ_PMPEQPOBJSZ_SHIFT 0 -#define I40E_GLHMC_PEQPOBJSZ_PMPEQPOBJSZ_MASK (0xF << I40E_GLHMC_PEQPOBJSZ_PMPEQPOBJSZ_SHIFT) -#define I40E_GLHMC_PESRQBASE(_i) (0x000C4400 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PESRQBASE_MAX_INDEX 15 -#define I40E_GLHMC_PESRQBASE_FPMPESRQBASE_SHIFT 0 -#define I40E_GLHMC_PESRQBASE_FPMPESRQBASE_MASK (0xFFFFFF << I40E_GLHMC_PESRQBASE_FPMPESRQBASE_SHIFT) -#define I40E_GLHMC_PESRQCNT(_i) (0x000C4500 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PESRQCNT_MAX_INDEX 15 -#define I40E_GLHMC_PESRQCNT_FPMPESRQCNT_SHIFT 0 -#define I40E_GLHMC_PESRQCNT_FPMPESRQCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PESRQCNT_FPMPESRQCNT_SHIFT) -#define I40E_GLHMC_PESRQMAX 0x000C2028 -#define I40E_GLHMC_PESRQMAX_PMPESRQMAX_SHIFT 0 -#define I40E_GLHMC_PESRQMAX_PMPESRQMAX_MASK (0xFFFF << I40E_GLHMC_PESRQMAX_PMPESRQMAX_SHIFT) -#define I40E_GLHMC_PESRQOBJSZ 0x000C2024 -#define I40E_GLHMC_PESRQOBJSZ_PMPESRQOBJSZ_SHIFT 0 -#define I40E_GLHMC_PESRQOBJSZ_PMPESRQOBJSZ_MASK (0xF << I40E_GLHMC_PESRQOBJSZ_PMPESRQOBJSZ_SHIFT) -#define I40E_GLHMC_PESRQOBJSZ_RSVD_SHIFT 4 -#define I40E_GLHMC_PESRQOBJSZ_RSVD_MASK (0xFFFFFFF << I40E_GLHMC_PESRQOBJSZ_RSVD_SHIFT) -#define I40E_GLHMC_PETIMERBASE(_i) (0x000C5A00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PETIMERBASE_MAX_INDEX 15 -#define I40E_GLHMC_PETIMERBASE_FPMPETIMERBASE_SHIFT 0 -#define I40E_GLHMC_PETIMERBASE_FPMPETIMERBASE_MASK (0xFFFFFF << I40E_GLHMC_PETIMERBASE_FPMPETIMERBASE_SHIFT) -#define I40E_GLHMC_PETIMERCNT(_i) (0x000C5B00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PETIMERCNT_MAX_INDEX 15 -#define I40E_GLHMC_PETIMERCNT_FPMPETIMERCNT_SHIFT 0 -#define I40E_GLHMC_PETIMERCNT_FPMPETIMERCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PETIMERCNT_FPMPETIMERCNT_SHIFT) -#define I40E_GLHMC_PETIMERMAX 0x000C2084 -#define I40E_GLHMC_PETIMERMAX_PMPETIMERMAX_SHIFT 0 -#define I40E_GLHMC_PETIMERMAX_PMPETIMERMAX_MASK (0x1FFFFFFF << I40E_GLHMC_PETIMERMAX_PMPETIMERMAX_SHIFT) -#define I40E_GLHMC_PETIMEROBJSZ 0x000C2080 -#define I40E_GLHMC_PETIMEROBJSZ_PMPETIMEROBJSZ_SHIFT 0 -#define I40E_GLHMC_PETIMEROBJSZ_PMPETIMEROBJSZ_MASK (0xF << I40E_GLHMC_PETIMEROBJSZ_PMPETIMEROBJSZ_SHIFT) -#define I40E_GLHMC_PEXFBASE(_i) (0x000C4e00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEXFBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEXFBASE_FPMPEXFBASE_SHIFT 0 -#define I40E_GLHMC_PEXFBASE_FPMPEXFBASE_MASK (0xFFFFFF << I40E_GLHMC_PEXFBASE_FPMPEXFBASE_SHIFT) -#define I40E_GLHMC_PEXFCNT(_i) (0x000C4f00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEXFCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEXFCNT_FPMPEXFCNT_SHIFT 0 -#define I40E_GLHMC_PEXFCNT_FPMPEXFCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEXFCNT_FPMPEXFCNT_SHIFT) -#define I40E_GLHMC_PEXFFLBASE(_i) (0x000C5000 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEXFFLBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEXFFLBASE_FPMPEXFFLBASE_SHIFT 0 -#define I40E_GLHMC_PEXFFLBASE_FPMPEXFFLBASE_MASK (0xFFFFFF << I40E_GLHMC_PEXFFLBASE_FPMPEXFFLBASE_SHIFT) -#define I40E_GLHMC_PEXFFLCNT(_i) (0x000C5100 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEXFFLCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEXFFLCNT_FPMPEXFFLCNT_SHIFT 0 -#define I40E_GLHMC_PEXFFLCNT_FPMPEXFFLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEXFFLCNT_FPMPEXFFLCNT_SHIFT) -#define I40E_GLHMC_PEXFFLMAX 0x000C204c -#define I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_SHIFT 0 -#define I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_MASK (0x1FFFFFF << I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_SHIFT) -#define I40E_GLHMC_PEXFMAX 0x000C2048 -#define I40E_GLHMC_PEXFMAX_PMPEXFMAX_SHIFT 0 -#define I40E_GLHMC_PEXFMAX_PMPEXFMAX_MASK (0x3FFFFFF << I40E_GLHMC_PEXFMAX_PMPEXFMAX_SHIFT) -#define I40E_GLHMC_PEXFOBJSZ 0x000C2044 -#define I40E_GLHMC_PEXFOBJSZ_PMPEXFOBJSZ_SHIFT 0 -#define I40E_GLHMC_PEXFOBJSZ_PMPEXFOBJSZ_MASK (0xF << I40E_GLHMC_PEXFOBJSZ_PMPEXFOBJSZ_SHIFT) -#define I40E_GLHMC_PEXFOBJSZ_RSVD_SHIFT 4 -#define I40E_GLHMC_PEXFOBJSZ_RSVD_MASK (0xFFFFFFF << I40E_GLHMC_PEXFOBJSZ_RSVD_SHIFT) -#define I40E_GLHMC_PFASSIGN(_i) (0x000C0c00 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_SHIFT) +#define I40E_GLHMC_PFASSIGN(_i) (0x000C0c00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_PFASSIGN_MAX_INDEX 15 #define I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_SHIFT 0 -#define I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_MASK (0xF << I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_SHIFT) -#define I40E_GLHMC_SDPART(_i) (0x000C0800 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_MASK I40E_MASK(0xF, I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_SHIFT) +#define I40E_GLHMC_SDPART(_i) (0x000C0800 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_SDPART_MAX_INDEX 15 #define I40E_GLHMC_SDPART_PMSDBASE_SHIFT 0 -#define I40E_GLHMC_SDPART_PMSDBASE_MASK (0xFFF << I40E_GLHMC_SDPART_PMSDBASE_SHIFT) +#define I40E_GLHMC_SDPART_PMSDBASE_MASK I40E_MASK(0xFFF, I40E_GLHMC_SDPART_PMSDBASE_SHIFT) #define I40E_GLHMC_SDPART_PMSDSIZE_SHIFT 16 -#define I40E_GLHMC_SDPART_PMSDSIZE_MASK (0x1FFF << I40E_GLHMC_SDPART_PMSDSIZE_SHIFT) -#define I40E_GLHMC_VFAPBVTINUSEBASE(_i) (0x000Cca00 + ((_i) * 4)) -#define I40E_GLHMC_VFAPBVTINUSEBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFAPBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT 0 -#define I40E_GLHMC_VFAPBVTINUSEBASE_FPMAPBINUSEBASE_MASK (0xFFFFFF << I40E_GLHMC_VFAPBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT) -#define I40E_GLHMC_VFCEQPART(_i) (0x00132240 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFCEQPART_MAX_INDEX 31 -#define I40E_GLHMC_VFCEQPART_PMCEQBASE_SHIFT 0 -#define I40E_GLHMC_VFCEQPART_PMCEQBASE_MASK (0xFF << I40E_GLHMC_VFCEQPART_PMCEQBASE_SHIFT) -#define I40E_GLHMC_VFCEQPART_PMCEQSIZE_SHIFT 16 -#define I40E_GLHMC_VFCEQPART_PMCEQSIZE_MASK (0x1FF << I40E_GLHMC_VFCEQPART_PMCEQSIZE_SHIFT) -#define I40E_GLHMC_VFDBCQPART(_i) (0x00132140 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFDBCQPART_MAX_INDEX 31 -#define I40E_GLHMC_VFDBCQPART_PMDBCQBASE_SHIFT 0 -#define I40E_GLHMC_VFDBCQPART_PMDBCQBASE_MASK (0x3FFF << I40E_GLHMC_VFDBCQPART_PMDBCQBASE_SHIFT) -#define I40E_GLHMC_VFDBCQPART_PMDBCQSIZE_SHIFT 16 -#define I40E_GLHMC_VFDBCQPART_PMDBCQSIZE_MASK (0x7FFF << I40E_GLHMC_VFDBCQPART_PMDBCQSIZE_SHIFT) -#define I40E_GLHMC_VFDBQPPART(_i) (0x00138E00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFDBQPPART_MAX_INDEX 31 -#define I40E_GLHMC_VFDBQPPART_PMDBQPBASE_SHIFT 0 -#define I40E_GLHMC_VFDBQPPART_PMDBQPBASE_MASK (0x3FFF << I40E_GLHMC_VFDBQPPART_PMDBQPBASE_SHIFT) -#define I40E_GLHMC_VFDBQPPART_PMDBQPSIZE_SHIFT 16 -#define I40E_GLHMC_VFDBQPPART_PMDBQPSIZE_MASK (0x7FFF << I40E_GLHMC_VFDBQPPART_PMDBQPSIZE_SHIFT) -#define I40E_GLHMC_VFFSIAVBASE(_i) (0x000Cd600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFFSIAVBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFFSIAVBASE_FPMFSIAVBASE_SHIFT 0 -#define I40E_GLHMC_VFFSIAVBASE_FPMFSIAVBASE_MASK (0xFFFFFF << I40E_GLHMC_VFFSIAVBASE_FPMFSIAVBASE_SHIFT) -#define I40E_GLHMC_VFFSIAVCNT(_i) (0x000Cd700 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFFSIAVCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFFSIAVCNT_FPMFSIAVCNT_SHIFT 0 -#define I40E_GLHMC_VFFSIAVCNT_FPMFSIAVCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFFSIAVCNT_FPMFSIAVCNT_SHIFT) -#define I40E_GLHMC_VFFSIAVCNT_RSVD_SHIFT 29 -#define I40E_GLHMC_VFFSIAVCNT_RSVD_MASK (0x7 << I40E_GLHMC_VFFSIAVCNT_RSVD_SHIFT) -#define I40E_GLHMC_VFPDINV(_i) (0x000C8300 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPDINV_MAX_INDEX 31 -#define I40E_GLHMC_VFPDINV_PMSDIDX_SHIFT 0 -#define I40E_GLHMC_VFPDINV_PMSDIDX_MASK (0xFFF << I40E_GLHMC_VFPDINV_PMSDIDX_SHIFT) -#define I40E_GLHMC_VFPDINV_PMPDIDX_SHIFT 16 -#define I40E_GLHMC_VFPDINV_PMPDIDX_MASK (0x1FF << I40E_GLHMC_VFPDINV_PMPDIDX_SHIFT) -#define I40E_GLHMC_VFPEARPBASE(_i) (0x000Cc800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEARPBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEARPBASE_FPMPEARPBASE_SHIFT 0 -#define I40E_GLHMC_VFPEARPBASE_FPMPEARPBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEARPBASE_FPMPEARPBASE_SHIFT) -#define I40E_GLHMC_VFPEARPCNT(_i) (0x000Cc900 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEARPCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEARPCNT_FPMPEARPCNT_SHIFT 0 -#define I40E_GLHMC_VFPEARPCNT_FPMPEARPCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEARPCNT_FPMPEARPCNT_SHIFT) -#define I40E_GLHMC_VFPECQBASE(_i) (0x000Cc200 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPECQBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPECQBASE_FPMPECQBASE_SHIFT 0 -#define I40E_GLHMC_VFPECQBASE_FPMPECQBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPECQBASE_FPMPECQBASE_SHIFT) -#define I40E_GLHMC_VFPECQCNT(_i) (0x000Cc300 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPECQCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPECQCNT_FPMPECQCNT_SHIFT 0 -#define I40E_GLHMC_VFPECQCNT_FPMPECQCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPECQCNT_FPMPECQCNT_SHIFT) -#define I40E_GLHMC_VFPEHTCNT(_i) (0x000Cc700 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEHTCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEHTCNT_FPMPEHTCNT_SHIFT 0 -#define I40E_GLHMC_VFPEHTCNT_FPMPEHTCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEHTCNT_FPMPEHTCNT_SHIFT) -#define I40E_GLHMC_VFPEHTEBASE(_i) (0x000Cc600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEHTEBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEHTEBASE_FPMPEHTEBASE_SHIFT 0 -#define I40E_GLHMC_VFPEHTEBASE_FPMPEHTEBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEHTEBASE_FPMPEHTEBASE_SHIFT) -#define I40E_GLHMC_VFPEMRBASE(_i) (0x000Ccc00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEMRBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEMRBASE_FPMPEMRBASE_SHIFT 0 -#define I40E_GLHMC_VFPEMRBASE_FPMPEMRBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEMRBASE_FPMPEMRBASE_SHIFT) -#define I40E_GLHMC_VFPEMRCNT(_i) (0x000Ccd00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEMRCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEMRCNT_FPMPEMRSZ_SHIFT 0 -#define I40E_GLHMC_VFPEMRCNT_FPMPEMRSZ_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEMRCNT_FPMPEMRSZ_SHIFT) -#define I40E_GLHMC_VFPEPBLBASE(_i) (0x000Cd800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEPBLBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEPBLBASE_FPMPEPBLBASE_SHIFT 0 -#define I40E_GLHMC_VFPEPBLBASE_FPMPEPBLBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEPBLBASE_FPMPEPBLBASE_SHIFT) -#define I40E_GLHMC_VFPEPBLCNT(_i) (0x000Cd900 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEPBLCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEPBLCNT_FPMPEPBLCNT_SHIFT 0 -#define I40E_GLHMC_VFPEPBLCNT_FPMPEPBLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEPBLCNT_FPMPEPBLCNT_SHIFT) -#define I40E_GLHMC_VFPEQ1BASE(_i) (0x000Cd200 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEQ1BASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEQ1BASE_FPMPEQ1BASE_SHIFT 0 -#define I40E_GLHMC_VFPEQ1BASE_FPMPEQ1BASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEQ1BASE_FPMPEQ1BASE_SHIFT) -#define I40E_GLHMC_VFPEQ1CNT(_i) (0x000Cd300 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEQ1CNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEQ1CNT_FPMPEQ1CNT_SHIFT 0 -#define I40E_GLHMC_VFPEQ1CNT_FPMPEQ1CNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEQ1CNT_FPMPEQ1CNT_SHIFT) -#define I40E_GLHMC_VFPEQ1FLBASE(_i) (0x000Cd400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEQ1FLBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEQ1FLBASE_FPMPEQ1FLBASE_SHIFT 0 -#define I40E_GLHMC_VFPEQ1FLBASE_FPMPEQ1FLBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEQ1FLBASE_FPMPEQ1FLBASE_SHIFT) -#define I40E_GLHMC_VFPEQ1FLCNT(_i) (0x000Cd500 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEQ1FLCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEQ1FLCNT_FPMPEQ1FLCNT_SHIFT 0 -#define I40E_GLHMC_VFPEQ1FLCNT_FPMPEQ1FLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEQ1FLCNT_FPMPEQ1FLCNT_SHIFT) -#define I40E_GLHMC_VFPEQPBASE(_i) (0x000Cc000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEQPBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEQPBASE_FPMPEQPBASE_SHIFT 0 -#define I40E_GLHMC_VFPEQPBASE_FPMPEQPBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEQPBASE_FPMPEQPBASE_SHIFT) -#define I40E_GLHMC_VFPEQPCNT(_i) (0x000Cc100 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEQPCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEQPCNT_FPMPEQPCNT_SHIFT 0 -#define I40E_GLHMC_VFPEQPCNT_FPMPEQPCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEQPCNT_FPMPEQPCNT_SHIFT) -#define I40E_GLHMC_VFPESRQBASE(_i) (0x000Cc400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPESRQBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPESRQBASE_FPMPESRQBASE_SHIFT 0 -#define I40E_GLHMC_VFPESRQBASE_FPMPESRQBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPESRQBASE_FPMPESRQBASE_SHIFT) -#define I40E_GLHMC_VFPESRQCNT(_i) (0x000Cc500 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPESRQCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPESRQCNT_FPMPESRQCNT_SHIFT 0 -#define I40E_GLHMC_VFPESRQCNT_FPMPESRQCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPESRQCNT_FPMPESRQCNT_SHIFT) -#define I40E_GLHMC_VFPETIMERBASE(_i) (0x000CDA00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPETIMERBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPETIMERBASE_FPMPETIMERBASE_SHIFT 0 -#define I40E_GLHMC_VFPETIMERBASE_FPMPETIMERBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPETIMERBASE_FPMPETIMERBASE_SHIFT) -#define I40E_GLHMC_VFPETIMERCNT(_i) (0x000CDB00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPETIMERCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPETIMERCNT_FPMPETIMERCNT_SHIFT 0 -#define I40E_GLHMC_VFPETIMERCNT_FPMPETIMERCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPETIMERCNT_FPMPETIMERCNT_SHIFT) -#define I40E_GLHMC_VFPEXFBASE(_i) (0x000Cce00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEXFBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEXFBASE_FPMPEXFBASE_SHIFT 0 -#define I40E_GLHMC_VFPEXFBASE_FPMPEXFBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEXFBASE_FPMPEXFBASE_SHIFT) -#define I40E_GLHMC_VFPEXFCNT(_i) (0x000Ccf00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEXFCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEXFCNT_FPMPEXFCNT_SHIFT 0 -#define I40E_GLHMC_VFPEXFCNT_FPMPEXFCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEXFCNT_FPMPEXFCNT_SHIFT) -#define I40E_GLHMC_VFPEXFFLBASE(_i) (0x000Cd000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEXFFLBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEXFFLBASE_FPMPEXFFLBASE_SHIFT 0 -#define I40E_GLHMC_VFPEXFFLBASE_FPMPEXFFLBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEXFFLBASE_FPMPEXFFLBASE_SHIFT) -#define I40E_GLHMC_VFPEXFFLCNT(_i) (0x000Cd100 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEXFFLCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEXFFLCNT_FPMPEXFFLCNT_SHIFT 0 -#define I40E_GLHMC_VFPEXFFLCNT_FPMPEXFFLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEXFFLCNT_FPMPEXFFLCNT_SHIFT) -#define I40E_GLHMC_VFSDPART(_i) (0x000C8800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFSDPART_MAX_INDEX 31 -#define I40E_GLHMC_VFSDPART_PMSDBASE_SHIFT 0 -#define I40E_GLHMC_VFSDPART_PMSDBASE_MASK (0xFFF << I40E_GLHMC_VFSDPART_PMSDBASE_SHIFT) -#define I40E_GLHMC_VFSDPART_PMSDSIZE_SHIFT 16 -#define I40E_GLHMC_VFSDPART_PMSDSIZE_MASK (0x1FFF << I40E_GLHMC_VFSDPART_PMSDSIZE_SHIFT) -#define I40E_PFHMC_ERRORDATA 0x000C0500 +#define I40E_GLHMC_SDPART_PMSDSIZE_MASK I40E_MASK(0x1FFF, I40E_GLHMC_SDPART_PMSDSIZE_SHIFT) +#define I40E_PFHMC_ERRORDATA 0x000C0500 /* Reset: PFR */ #define I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_SHIFT 0 -#define I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_MASK (0x3FFFFFFF << I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_SHIFT) -#define I40E_PFHMC_ERRORINFO 0x000C0400 +#define I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_MASK I40E_MASK(0x3FFFFFFF, I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_SHIFT) +#define I40E_PFHMC_ERRORINFO 0x000C0400 /* Reset: PFR */ #define I40E_PFHMC_ERRORINFO_PMF_INDEX_SHIFT 0 -#define I40E_PFHMC_ERRORINFO_PMF_INDEX_MASK (0x1F << I40E_PFHMC_ERRORINFO_PMF_INDEX_SHIFT) +#define I40E_PFHMC_ERRORINFO_PMF_INDEX_MASK I40E_MASK(0x1F, I40E_PFHMC_ERRORINFO_PMF_INDEX_SHIFT) #define I40E_PFHMC_ERRORINFO_PMF_ISVF_SHIFT 7 -#define I40E_PFHMC_ERRORINFO_PMF_ISVF_MASK (0x1 << I40E_PFHMC_ERRORINFO_PMF_ISVF_SHIFT) +#define I40E_PFHMC_ERRORINFO_PMF_ISVF_MASK I40E_MASK(0x1, I40E_PFHMC_ERRORINFO_PMF_ISVF_SHIFT) #define I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_SHIFT 8 -#define I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_MASK (0xF << I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_SHIFT) +#define I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_MASK I40E_MASK(0xF, I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_SHIFT) #define I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_SHIFT 16 -#define I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_MASK (0x1F << I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_SHIFT) +#define I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_MASK I40E_MASK(0x1F, I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_SHIFT) #define I40E_PFHMC_ERRORINFO_ERROR_DETECTED_SHIFT 31 -#define I40E_PFHMC_ERRORINFO_ERROR_DETECTED_MASK (0x1 << I40E_PFHMC_ERRORINFO_ERROR_DETECTED_SHIFT) -#define I40E_PFHMC_PDINV 0x000C0300 +#define I40E_PFHMC_ERRORINFO_ERROR_DETECTED_MASK I40E_MASK(0x1, I40E_PFHMC_ERRORINFO_ERROR_DETECTED_SHIFT) +#define I40E_PFHMC_PDINV 0x000C0300 /* Reset: PFR */ #define I40E_PFHMC_PDINV_PMSDIDX_SHIFT 0 -#define I40E_PFHMC_PDINV_PMSDIDX_MASK (0xFFF << I40E_PFHMC_PDINV_PMSDIDX_SHIFT) +#define I40E_PFHMC_PDINV_PMSDIDX_MASK I40E_MASK(0xFFF, I40E_PFHMC_PDINV_PMSDIDX_SHIFT) #define I40E_PFHMC_PDINV_PMPDIDX_SHIFT 16 -#define I40E_PFHMC_PDINV_PMPDIDX_MASK (0x1FF << I40E_PFHMC_PDINV_PMPDIDX_SHIFT) -#define I40E_PFHMC_SDCMD 0x000C0000 +#define I40E_PFHMC_PDINV_PMPDIDX_MASK I40E_MASK(0x1FF, I40E_PFHMC_PDINV_PMPDIDX_SHIFT) +#define I40E_PFHMC_SDCMD 0x000C0000 /* Reset: PFR */ #define I40E_PFHMC_SDCMD_PMSDIDX_SHIFT 0 -#define I40E_PFHMC_SDCMD_PMSDIDX_MASK (0xFFF << I40E_PFHMC_SDCMD_PMSDIDX_SHIFT) +#define I40E_PFHMC_SDCMD_PMSDIDX_MASK I40E_MASK(0xFFF, I40E_PFHMC_SDCMD_PMSDIDX_SHIFT) #define I40E_PFHMC_SDCMD_PMSDWR_SHIFT 31 -#define I40E_PFHMC_SDCMD_PMSDWR_MASK (0x1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT) -#define I40E_PFHMC_SDDATAHIGH 0x000C0200 +#define I40E_PFHMC_SDCMD_PMSDWR_MASK I40E_MASK(0x1, I40E_PFHMC_SDCMD_PMSDWR_SHIFT) +#define I40E_PFHMC_SDDATAHIGH 0x000C0200 /* Reset: PFR */ #define I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_SHIFT 0 -#define I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_MASK (0xFFFFFFFF << I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_SHIFT) -#define I40E_PFHMC_SDDATALOW 0x000C0100 +#define I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_MASK I40E_MASK(0xFFFFFFFF, I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_SHIFT) +#define I40E_PFHMC_SDDATALOW 0x000C0100 /* Reset: PFR */ #define I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT 0 -#define I40E_PFHMC_SDDATALOW_PMSDVALID_MASK (0x1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT) +#define I40E_PFHMC_SDDATALOW_PMSDVALID_MASK I40E_MASK(0x1, I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT) #define I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT 1 -#define I40E_PFHMC_SDDATALOW_PMSDTYPE_MASK (0x1 << I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) +#define I40E_PFHMC_SDDATALOW_PMSDTYPE_MASK I40E_MASK(0x1, I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) #define I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT 2 -#define I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_MASK (0x3FF << I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) +#define I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_MASK I40E_MASK(0x3FF, I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) #define I40E_PFHMC_SDDATALOW_PMSDDATALOW_SHIFT 12 -#define I40E_PFHMC_SDDATALOW_PMSDDATALOW_MASK (0xFFFFF << I40E_PFHMC_SDDATALOW_PMSDDATALOW_SHIFT) -#define I40E_GL_UFUSE 0x00094008 +#define I40E_PFHMC_SDDATALOW_PMSDDATALOW_MASK I40E_MASK(0xFFFFF, I40E_PFHMC_SDDATALOW_PMSDDATALOW_SHIFT) +#define I40E_GL_GP_FUSE(_i) (0x0009400C + ((_i) * 4)) /* _i=0...28 */ /* Reset: POR */ +#define I40E_GL_GP_FUSE_MAX_INDEX 28 +#define I40E_GL_GP_FUSE_GL_GP_FUSE_SHIFT 0 +#define I40E_GL_GP_FUSE_GL_GP_FUSE_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_GP_FUSE_GL_GP_FUSE_SHIFT) +#define I40E_GL_UFUSE 0x00094008 /* Reset: POR */ #define I40E_GL_UFUSE_FOUR_PORT_ENABLE_SHIFT 1 -#define I40E_GL_UFUSE_FOUR_PORT_ENABLE_MASK (0x1 << I40E_GL_UFUSE_FOUR_PORT_ENABLE_SHIFT) +#define I40E_GL_UFUSE_FOUR_PORT_ENABLE_MASK I40E_MASK(0x1, I40E_GL_UFUSE_FOUR_PORT_ENABLE_SHIFT) #define I40E_GL_UFUSE_NIC_ID_SHIFT 2 -#define I40E_GL_UFUSE_NIC_ID_MASK (0x1 << I40E_GL_UFUSE_NIC_ID_SHIFT) +#define I40E_GL_UFUSE_NIC_ID_MASK I40E_MASK(0x1, I40E_GL_UFUSE_NIC_ID_SHIFT) #define I40E_GL_UFUSE_ULT_LOCKOUT_SHIFT 10 -#define I40E_GL_UFUSE_ULT_LOCKOUT_MASK (0x1 << I40E_GL_UFUSE_ULT_LOCKOUT_SHIFT) +#define I40E_GL_UFUSE_ULT_LOCKOUT_MASK I40E_MASK(0x1, I40E_GL_UFUSE_ULT_LOCKOUT_SHIFT) #define I40E_GL_UFUSE_CLS_LOCKOUT_SHIFT 11 -#define I40E_GL_UFUSE_CLS_LOCKOUT_MASK (0x1 << I40E_GL_UFUSE_CLS_LOCKOUT_SHIFT) -#define I40E_EMPINT_GPIO_ENA 0x00088188 +#define I40E_GL_UFUSE_CLS_LOCKOUT_MASK I40E_MASK(0x1, I40E_GL_UFUSE_CLS_LOCKOUT_SHIFT) +#define I40E_EMPINT_GPIO_ENA 0x00088188 /* Reset: POR */ #define I40E_EMPINT_GPIO_ENA_GPIO0_ENA_SHIFT 0 -#define I40E_EMPINT_GPIO_ENA_GPIO0_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO0_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO0_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO0_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO1_ENA_SHIFT 1 -#define I40E_EMPINT_GPIO_ENA_GPIO1_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO1_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO1_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO1_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO2_ENA_SHIFT 2 -#define I40E_EMPINT_GPIO_ENA_GPIO2_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO2_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO2_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO2_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO3_ENA_SHIFT 3 -#define I40E_EMPINT_GPIO_ENA_GPIO3_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO3_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO3_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO3_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO4_ENA_SHIFT 4 -#define I40E_EMPINT_GPIO_ENA_GPIO4_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO4_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO4_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO4_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO5_ENA_SHIFT 5 -#define I40E_EMPINT_GPIO_ENA_GPIO5_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO5_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO5_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO5_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO6_ENA_SHIFT 6 -#define I40E_EMPINT_GPIO_ENA_GPIO6_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO6_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO6_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO6_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO7_ENA_SHIFT 7 -#define I40E_EMPINT_GPIO_ENA_GPIO7_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO7_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO7_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO7_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO8_ENA_SHIFT 8 -#define I40E_EMPINT_GPIO_ENA_GPIO8_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO8_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO8_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO8_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO9_ENA_SHIFT 9 -#define I40E_EMPINT_GPIO_ENA_GPIO9_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO9_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO9_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO9_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO10_ENA_SHIFT 10 -#define I40E_EMPINT_GPIO_ENA_GPIO10_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO10_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO10_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO10_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO11_ENA_SHIFT 11 -#define I40E_EMPINT_GPIO_ENA_GPIO11_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO11_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO11_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO11_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO12_ENA_SHIFT 12 -#define I40E_EMPINT_GPIO_ENA_GPIO12_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO12_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO12_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO12_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO13_ENA_SHIFT 13 -#define I40E_EMPINT_GPIO_ENA_GPIO13_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO13_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO13_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO13_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO14_ENA_SHIFT 14 -#define I40E_EMPINT_GPIO_ENA_GPIO14_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO14_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO14_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO14_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO15_ENA_SHIFT 15 -#define I40E_EMPINT_GPIO_ENA_GPIO15_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO15_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO15_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO15_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO16_ENA_SHIFT 16 -#define I40E_EMPINT_GPIO_ENA_GPIO16_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO16_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO16_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO16_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO17_ENA_SHIFT 17 -#define I40E_EMPINT_GPIO_ENA_GPIO17_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO17_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO17_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO17_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO18_ENA_SHIFT 18 -#define I40E_EMPINT_GPIO_ENA_GPIO18_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO18_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO18_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO18_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO19_ENA_SHIFT 19 -#define I40E_EMPINT_GPIO_ENA_GPIO19_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO19_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO19_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO19_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO20_ENA_SHIFT 20 -#define I40E_EMPINT_GPIO_ENA_GPIO20_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO20_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO20_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO20_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO21_ENA_SHIFT 21 -#define I40E_EMPINT_GPIO_ENA_GPIO21_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO21_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO21_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO21_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO22_ENA_SHIFT 22 -#define I40E_EMPINT_GPIO_ENA_GPIO22_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO22_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO22_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO22_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO23_ENA_SHIFT 23 -#define I40E_EMPINT_GPIO_ENA_GPIO23_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO23_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO23_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO23_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO24_ENA_SHIFT 24 -#define I40E_EMPINT_GPIO_ENA_GPIO24_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO24_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO24_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO24_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO25_ENA_SHIFT 25 -#define I40E_EMPINT_GPIO_ENA_GPIO25_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO25_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO25_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO25_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO26_ENA_SHIFT 26 -#define I40E_EMPINT_GPIO_ENA_GPIO26_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO26_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO26_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO26_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO27_ENA_SHIFT 27 -#define I40E_EMPINT_GPIO_ENA_GPIO27_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO27_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO27_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO27_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO28_ENA_SHIFT 28 -#define I40E_EMPINT_GPIO_ENA_GPIO28_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO28_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO28_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO28_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO29_ENA_SHIFT 29 -#define I40E_EMPINT_GPIO_ENA_GPIO29_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO29_ENA_SHIFT) -#define I40E_PFGEN_PORTMDIO_NUM 0x0003F100 +#define I40E_EMPINT_GPIO_ENA_GPIO29_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO29_ENA_SHIFT) +#define I40E_PFGEN_PORTMDIO_NUM 0x0003F100 /* Reset: CORER */ #define I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_SHIFT 0 -#define I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_MASK (0x3 << I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_SHIFT) +#define I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_MASK I40E_MASK(0x3, I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_SHIFT) #define I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_SHIFT 4 -#define I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK (0x1 << I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_SHIFT) -#define I40E_PFINT_AEQCTL 0x00038700 +#define I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK I40E_MASK(0x1, I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_SHIFT) +#define I40E_PFINT_AEQCTL 0x00038700 /* Reset: CORER */ #define I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT 0 -#define I40E_PFINT_AEQCTL_MSIX_INDX_MASK (0xFF << I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT) +#define I40E_PFINT_AEQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT) #define I40E_PFINT_AEQCTL_ITR_INDX_SHIFT 11 -#define I40E_PFINT_AEQCTL_ITR_INDX_MASK (0x3 << I40E_PFINT_AEQCTL_ITR_INDX_SHIFT) +#define I40E_PFINT_AEQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_AEQCTL_ITR_INDX_SHIFT) #define I40E_PFINT_AEQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_PFINT_AEQCTL_MSIX0_INDX_MASK (0x7 << I40E_PFINT_AEQCTL_MSIX0_INDX_SHIFT) +#define I40E_PFINT_AEQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_PFINT_AEQCTL_MSIX0_INDX_SHIFT) #define I40E_PFINT_AEQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_PFINT_AEQCTL_CAUSE_ENA_MASK (0x1 << I40E_PFINT_AEQCTL_CAUSE_ENA_SHIFT) +#define I40E_PFINT_AEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_PFINT_AEQCTL_CAUSE_ENA_SHIFT) #define I40E_PFINT_AEQCTL_INTEVENT_SHIFT 31 -#define I40E_PFINT_AEQCTL_INTEVENT_MASK (0x1 << I40E_PFINT_AEQCTL_INTEVENT_SHIFT) -#define I40E_PFINT_CEQCTL(_INTPF) (0x00036800 + ((_INTPF) * 4)) /* _i=0...511 */ +#define I40E_PFINT_AEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_PFINT_AEQCTL_INTEVENT_SHIFT) +#define I40E_PFINT_CEQCTL(_INTPF) (0x00036800 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: CORER */ #define I40E_PFINT_CEQCTL_MAX_INDEX 511 #define I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT 0 -#define I40E_PFINT_CEQCTL_MSIX_INDX_MASK (0xFF << I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT) +#define I40E_PFINT_CEQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT) #define I40E_PFINT_CEQCTL_ITR_INDX_SHIFT 11 -#define I40E_PFINT_CEQCTL_ITR_INDX_MASK (0x3 << I40E_PFINT_CEQCTL_ITR_INDX_SHIFT) +#define I40E_PFINT_CEQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_CEQCTL_ITR_INDX_SHIFT) #define I40E_PFINT_CEQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_PFINT_CEQCTL_MSIX0_INDX_MASK (0x7 << I40E_PFINT_CEQCTL_MSIX0_INDX_SHIFT) +#define I40E_PFINT_CEQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_PFINT_CEQCTL_MSIX0_INDX_SHIFT) #define I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT 16 -#define I40E_PFINT_CEQCTL_NEXTQ_INDX_MASK (0x7FF << I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT) +#define I40E_PFINT_CEQCTL_NEXTQ_INDX_MASK I40E_MASK(0x7FF, I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT) #define I40E_PFINT_CEQCTL_NEXTQ_TYPE_SHIFT 27 -#define I40E_PFINT_CEQCTL_NEXTQ_TYPE_MASK (0x3 << I40E_PFINT_CEQCTL_NEXTQ_TYPE_SHIFT) +#define I40E_PFINT_CEQCTL_NEXTQ_TYPE_MASK I40E_MASK(0x3, I40E_PFINT_CEQCTL_NEXTQ_TYPE_SHIFT) #define I40E_PFINT_CEQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_PFINT_CEQCTL_CAUSE_ENA_MASK (0x1 << I40E_PFINT_CEQCTL_CAUSE_ENA_SHIFT) +#define I40E_PFINT_CEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_PFINT_CEQCTL_CAUSE_ENA_SHIFT) #define I40E_PFINT_CEQCTL_INTEVENT_SHIFT 31 -#define I40E_PFINT_CEQCTL_INTEVENT_MASK (0x1 << I40E_PFINT_CEQCTL_INTEVENT_SHIFT) -#define I40E_PFINT_DYN_CTL0 0x00038480 +#define I40E_PFINT_CEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_PFINT_CEQCTL_INTEVENT_SHIFT) +#define I40E_PFINT_DYN_CTL0 0x00038480 /* Reset: PFR */ #define I40E_PFINT_DYN_CTL0_INTENA_SHIFT 0 -#define I40E_PFINT_DYN_CTL0_INTENA_MASK (0x1 << I40E_PFINT_DYN_CTL0_INTENA_SHIFT) +#define I40E_PFINT_DYN_CTL0_INTENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_INTENA_SHIFT) #define I40E_PFINT_DYN_CTL0_CLEARPBA_SHIFT 1 -#define I40E_PFINT_DYN_CTL0_CLEARPBA_MASK (0x1 << I40E_PFINT_DYN_CTL0_CLEARPBA_SHIFT) +#define I40E_PFINT_DYN_CTL0_CLEARPBA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_CLEARPBA_SHIFT) #define I40E_PFINT_DYN_CTL0_SWINT_TRIG_SHIFT 2 -#define I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK (0x1 << I40E_PFINT_DYN_CTL0_SWINT_TRIG_SHIFT) +#define I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_SWINT_TRIG_SHIFT) #define I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT 3 -#define I40E_PFINT_DYN_CTL0_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT) +#define I40E_PFINT_DYN_CTL0_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT) #define I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT 5 -#define I40E_PFINT_DYN_CTL0_INTERVAL_MASK (0xFFF << I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT) +#define I40E_PFINT_DYN_CTL0_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT) #define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK (0x1 << I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT) +#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT) #define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_SHIFT 25 -#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTL0_SW_ITR_INDX_SHIFT) +#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTL0_SW_ITR_INDX_SHIFT) #define I40E_PFINT_DYN_CTL0_INTENA_MSK_SHIFT 31 -#define I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK (0x1 << I40E_PFINT_DYN_CTL0_INTENA_MSK_SHIFT) -#define I40E_PFINT_DYN_CTLN(_INTPF) (0x00034800 + ((_INTPF) * 4)) /* _i=0...511 */ +#define I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_INTENA_MSK_SHIFT) +#define I40E_PFINT_DYN_CTLN(_INTPF) (0x00034800 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: PFR */ #define I40E_PFINT_DYN_CTLN_MAX_INDEX 511 #define I40E_PFINT_DYN_CTLN_INTENA_SHIFT 0 -#define I40E_PFINT_DYN_CTLN_INTENA_MASK (0x1 << I40E_PFINT_DYN_CTLN_INTENA_SHIFT) +#define I40E_PFINT_DYN_CTLN_INTENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_INTENA_SHIFT) #define I40E_PFINT_DYN_CTLN_CLEARPBA_SHIFT 1 -#define I40E_PFINT_DYN_CTLN_CLEARPBA_MASK (0x1 << I40E_PFINT_DYN_CTLN_CLEARPBA_SHIFT) +#define I40E_PFINT_DYN_CTLN_CLEARPBA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_CLEARPBA_SHIFT) #define I40E_PFINT_DYN_CTLN_SWINT_TRIG_SHIFT 2 -#define I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK (0x1 << I40E_PFINT_DYN_CTLN_SWINT_TRIG_SHIFT) +#define I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_SWINT_TRIG_SHIFT) #define I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT 3 -#define I40E_PFINT_DYN_CTLN_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) +#define I40E_PFINT_DYN_CTLN_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) #define I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT 5 -#define I40E_PFINT_DYN_CTLN_INTERVAL_MASK (0xFFF << I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT) +#define I40E_PFINT_DYN_CTLN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT) #define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK (0x1 << I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT) +#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT) #define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT 25 -#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT) +#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT) #define I40E_PFINT_DYN_CTLN_INTENA_MSK_SHIFT 31 -#define I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK (0x1 << I40E_PFINT_DYN_CTLN_INTENA_MSK_SHIFT) -#define I40E_PFINT_GPIO_ENA 0x00088080 +#define I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_INTENA_MSK_SHIFT) +#define I40E_PFINT_GPIO_ENA 0x00088080 /* Reset: CORER */ #define I40E_PFINT_GPIO_ENA_GPIO0_ENA_SHIFT 0 -#define I40E_PFINT_GPIO_ENA_GPIO0_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO0_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO0_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO0_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO1_ENA_SHIFT 1 -#define I40E_PFINT_GPIO_ENA_GPIO1_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO1_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO1_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO1_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO2_ENA_SHIFT 2 -#define I40E_PFINT_GPIO_ENA_GPIO2_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO2_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO2_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO2_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO3_ENA_SHIFT 3 -#define I40E_PFINT_GPIO_ENA_GPIO3_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO3_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO3_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO3_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO4_ENA_SHIFT 4 -#define I40E_PFINT_GPIO_ENA_GPIO4_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO4_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO4_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO4_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO5_ENA_SHIFT 5 -#define I40E_PFINT_GPIO_ENA_GPIO5_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO5_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO5_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO5_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO6_ENA_SHIFT 6 -#define I40E_PFINT_GPIO_ENA_GPIO6_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO6_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO6_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO6_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO7_ENA_SHIFT 7 -#define I40E_PFINT_GPIO_ENA_GPIO7_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO7_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO7_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO7_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO8_ENA_SHIFT 8 -#define I40E_PFINT_GPIO_ENA_GPIO8_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO8_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO8_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO8_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO9_ENA_SHIFT 9 -#define I40E_PFINT_GPIO_ENA_GPIO9_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO9_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO9_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO9_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO10_ENA_SHIFT 10 -#define I40E_PFINT_GPIO_ENA_GPIO10_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO10_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO10_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO10_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO11_ENA_SHIFT 11 -#define I40E_PFINT_GPIO_ENA_GPIO11_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO11_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO11_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO11_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO12_ENA_SHIFT 12 -#define I40E_PFINT_GPIO_ENA_GPIO12_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO12_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO12_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO12_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO13_ENA_SHIFT 13 -#define I40E_PFINT_GPIO_ENA_GPIO13_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO13_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO13_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO13_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO14_ENA_SHIFT 14 -#define I40E_PFINT_GPIO_ENA_GPIO14_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO14_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO14_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO14_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO15_ENA_SHIFT 15 -#define I40E_PFINT_GPIO_ENA_GPIO15_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO15_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO15_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO15_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO16_ENA_SHIFT 16 -#define I40E_PFINT_GPIO_ENA_GPIO16_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO16_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO16_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO16_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO17_ENA_SHIFT 17 -#define I40E_PFINT_GPIO_ENA_GPIO17_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO17_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO17_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO17_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO18_ENA_SHIFT 18 -#define I40E_PFINT_GPIO_ENA_GPIO18_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO18_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO18_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO18_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO19_ENA_SHIFT 19 -#define I40E_PFINT_GPIO_ENA_GPIO19_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO19_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO19_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO19_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO20_ENA_SHIFT 20 -#define I40E_PFINT_GPIO_ENA_GPIO20_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO20_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO20_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO20_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO21_ENA_SHIFT 21 -#define I40E_PFINT_GPIO_ENA_GPIO21_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO21_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO21_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO21_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO22_ENA_SHIFT 22 -#define I40E_PFINT_GPIO_ENA_GPIO22_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO22_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO22_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO22_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO23_ENA_SHIFT 23 -#define I40E_PFINT_GPIO_ENA_GPIO23_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO23_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO23_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO23_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO24_ENA_SHIFT 24 -#define I40E_PFINT_GPIO_ENA_GPIO24_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO24_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO24_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO24_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO25_ENA_SHIFT 25 -#define I40E_PFINT_GPIO_ENA_GPIO25_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO25_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO25_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO25_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO26_ENA_SHIFT 26 -#define I40E_PFINT_GPIO_ENA_GPIO26_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO26_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO26_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO26_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO27_ENA_SHIFT 27 -#define I40E_PFINT_GPIO_ENA_GPIO27_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO27_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO27_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO27_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO28_ENA_SHIFT 28 -#define I40E_PFINT_GPIO_ENA_GPIO28_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO28_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO28_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO28_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO29_ENA_SHIFT 29 -#define I40E_PFINT_GPIO_ENA_GPIO29_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO29_ENA_SHIFT) -#define I40E_PFINT_ICR0 0x00038780 +#define I40E_PFINT_GPIO_ENA_GPIO29_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO29_ENA_SHIFT) +#define I40E_PFINT_ICR0 0x00038780 /* Reset: CORER */ #define I40E_PFINT_ICR0_INTEVENT_SHIFT 0 -#define I40E_PFINT_ICR0_INTEVENT_MASK (0x1 << I40E_PFINT_ICR0_INTEVENT_SHIFT) +#define I40E_PFINT_ICR0_INTEVENT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_INTEVENT_SHIFT) #define I40E_PFINT_ICR0_QUEUE_0_SHIFT 1 -#define I40E_PFINT_ICR0_QUEUE_0_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_0_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_0_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_0_SHIFT) #define I40E_PFINT_ICR0_QUEUE_1_SHIFT 2 -#define I40E_PFINT_ICR0_QUEUE_1_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_1_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_1_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_1_SHIFT) #define I40E_PFINT_ICR0_QUEUE_2_SHIFT 3 -#define I40E_PFINT_ICR0_QUEUE_2_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_2_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_2_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_2_SHIFT) #define I40E_PFINT_ICR0_QUEUE_3_SHIFT 4 -#define I40E_PFINT_ICR0_QUEUE_3_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_3_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_3_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_3_SHIFT) #define I40E_PFINT_ICR0_QUEUE_4_SHIFT 5 -#define I40E_PFINT_ICR0_QUEUE_4_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_4_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_4_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_4_SHIFT) #define I40E_PFINT_ICR0_QUEUE_5_SHIFT 6 -#define I40E_PFINT_ICR0_QUEUE_5_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_5_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_5_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_5_SHIFT) #define I40E_PFINT_ICR0_QUEUE_6_SHIFT 7 -#define I40E_PFINT_ICR0_QUEUE_6_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_6_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_6_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_6_SHIFT) #define I40E_PFINT_ICR0_QUEUE_7_SHIFT 8 -#define I40E_PFINT_ICR0_QUEUE_7_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_7_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_7_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_7_SHIFT) #define I40E_PFINT_ICR0_ECC_ERR_SHIFT 16 -#define I40E_PFINT_ICR0_ECC_ERR_MASK (0x1 << I40E_PFINT_ICR0_ECC_ERR_SHIFT) +#define I40E_PFINT_ICR0_ECC_ERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ECC_ERR_SHIFT) #define I40E_PFINT_ICR0_MAL_DETECT_SHIFT 19 -#define I40E_PFINT_ICR0_MAL_DETECT_MASK (0x1 << I40E_PFINT_ICR0_MAL_DETECT_SHIFT) +#define I40E_PFINT_ICR0_MAL_DETECT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_MAL_DETECT_SHIFT) #define I40E_PFINT_ICR0_GRST_SHIFT 20 -#define I40E_PFINT_ICR0_GRST_MASK (0x1 << I40E_PFINT_ICR0_GRST_SHIFT) +#define I40E_PFINT_ICR0_GRST_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_GRST_SHIFT) #define I40E_PFINT_ICR0_PCI_EXCEPTION_SHIFT 21 -#define I40E_PFINT_ICR0_PCI_EXCEPTION_MASK (0x1 << I40E_PFINT_ICR0_PCI_EXCEPTION_SHIFT) +#define I40E_PFINT_ICR0_PCI_EXCEPTION_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_PCI_EXCEPTION_SHIFT) #define I40E_PFINT_ICR0_GPIO_SHIFT 22 -#define I40E_PFINT_ICR0_GPIO_MASK (0x1 << I40E_PFINT_ICR0_GPIO_SHIFT) +#define I40E_PFINT_ICR0_GPIO_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_GPIO_SHIFT) #define I40E_PFINT_ICR0_TIMESYNC_SHIFT 23 -#define I40E_PFINT_ICR0_TIMESYNC_MASK (0x1 << I40E_PFINT_ICR0_TIMESYNC_SHIFT) +#define I40E_PFINT_ICR0_TIMESYNC_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_TIMESYNC_SHIFT) +#define I40E_PFINT_ICR0_STORM_DETECT_SHIFT 24 +#define I40E_PFINT_ICR0_STORM_DETECT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_STORM_DETECT_SHIFT) #define I40E_PFINT_ICR0_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_PFINT_ICR0_LINK_STAT_CHANGE_MASK (0x1 << I40E_PFINT_ICR0_LINK_STAT_CHANGE_SHIFT) +#define I40E_PFINT_ICR0_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_LINK_STAT_CHANGE_SHIFT) #define I40E_PFINT_ICR0_HMC_ERR_SHIFT 26 -#define I40E_PFINT_ICR0_HMC_ERR_MASK (0x1 << I40E_PFINT_ICR0_HMC_ERR_SHIFT) +#define I40E_PFINT_ICR0_HMC_ERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_HMC_ERR_SHIFT) #define I40E_PFINT_ICR0_PE_CRITERR_SHIFT 28 -#define I40E_PFINT_ICR0_PE_CRITERR_MASK (0x1 << I40E_PFINT_ICR0_PE_CRITERR_SHIFT) +#define I40E_PFINT_ICR0_PE_CRITERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_PE_CRITERR_SHIFT) #define I40E_PFINT_ICR0_VFLR_SHIFT 29 -#define I40E_PFINT_ICR0_VFLR_MASK (0x1 << I40E_PFINT_ICR0_VFLR_SHIFT) +#define I40E_PFINT_ICR0_VFLR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_VFLR_SHIFT) #define I40E_PFINT_ICR0_ADMINQ_SHIFT 30 -#define I40E_PFINT_ICR0_ADMINQ_MASK (0x1 << I40E_PFINT_ICR0_ADMINQ_SHIFT) +#define I40E_PFINT_ICR0_ADMINQ_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ADMINQ_SHIFT) #define I40E_PFINT_ICR0_SWINT_SHIFT 31 -#define I40E_PFINT_ICR0_SWINT_MASK (0x1 << I40E_PFINT_ICR0_SWINT_SHIFT) -#define I40E_PFINT_ICR0_ENA 0x00038800 +#define I40E_PFINT_ICR0_SWINT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_SWINT_SHIFT) +#define I40E_PFINT_ICR0_ENA 0x00038800 /* Reset: CORER */ #define I40E_PFINT_ICR0_ENA_ECC_ERR_SHIFT 16 -#define I40E_PFINT_ICR0_ENA_ECC_ERR_MASK (0x1 << I40E_PFINT_ICR0_ENA_ECC_ERR_SHIFT) +#define I40E_PFINT_ICR0_ENA_ECC_ERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_ECC_ERR_SHIFT) #define I40E_PFINT_ICR0_ENA_MAL_DETECT_SHIFT 19 -#define I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK (0x1 << I40E_PFINT_ICR0_ENA_MAL_DETECT_SHIFT) +#define I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_MAL_DETECT_SHIFT) #define I40E_PFINT_ICR0_ENA_GRST_SHIFT 20 -#define I40E_PFINT_ICR0_ENA_GRST_MASK (0x1 << I40E_PFINT_ICR0_ENA_GRST_SHIFT) +#define I40E_PFINT_ICR0_ENA_GRST_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_GRST_SHIFT) #define I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_SHIFT 21 -#define I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK (0x1 << I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_SHIFT) +#define I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_SHIFT) #define I40E_PFINT_ICR0_ENA_GPIO_SHIFT 22 -#define I40E_PFINT_ICR0_ENA_GPIO_MASK (0x1 << I40E_PFINT_ICR0_ENA_GPIO_SHIFT) +#define I40E_PFINT_ICR0_ENA_GPIO_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_GPIO_SHIFT) #define I40E_PFINT_ICR0_ENA_TIMESYNC_SHIFT 23 -#define I40E_PFINT_ICR0_ENA_TIMESYNC_MASK (0x1 << I40E_PFINT_ICR0_ENA_TIMESYNC_SHIFT) +#define I40E_PFINT_ICR0_ENA_TIMESYNC_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_TIMESYNC_SHIFT) +#define I40E_PFINT_ICR0_ENA_STORM_DETECT_SHIFT 24 +#define I40E_PFINT_ICR0_ENA_STORM_DETECT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_STORM_DETECT_SHIFT) #define I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK (0x1 << I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT) +#define I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT) #define I40E_PFINT_ICR0_ENA_HMC_ERR_SHIFT 26 -#define I40E_PFINT_ICR0_ENA_HMC_ERR_MASK (0x1 << I40E_PFINT_ICR0_ENA_HMC_ERR_SHIFT) +#define I40E_PFINT_ICR0_ENA_HMC_ERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_HMC_ERR_SHIFT) #define I40E_PFINT_ICR0_ENA_PE_CRITERR_SHIFT 28 -#define I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK (0x1 << I40E_PFINT_ICR0_ENA_PE_CRITERR_SHIFT) +#define I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_PE_CRITERR_SHIFT) #define I40E_PFINT_ICR0_ENA_VFLR_SHIFT 29 -#define I40E_PFINT_ICR0_ENA_VFLR_MASK (0x1 << I40E_PFINT_ICR0_ENA_VFLR_SHIFT) +#define I40E_PFINT_ICR0_ENA_VFLR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_VFLR_SHIFT) #define I40E_PFINT_ICR0_ENA_ADMINQ_SHIFT 30 -#define I40E_PFINT_ICR0_ENA_ADMINQ_MASK (0x1 << I40E_PFINT_ICR0_ENA_ADMINQ_SHIFT) +#define I40E_PFINT_ICR0_ENA_ADMINQ_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_ADMINQ_SHIFT) #define I40E_PFINT_ICR0_ENA_RSVD_SHIFT 31 -#define I40E_PFINT_ICR0_ENA_RSVD_MASK (0x1 << I40E_PFINT_ICR0_ENA_RSVD_SHIFT) -#define I40E_PFINT_ITR0(_i) (0x00038000 + ((_i) * 128)) /* _i=0...2 */ +#define I40E_PFINT_ICR0_ENA_RSVD_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_RSVD_SHIFT) +#define I40E_PFINT_ITR0(_i) (0x00038000 + ((_i) * 128)) /* _i=0...2 */ /* Reset: PFR */ #define I40E_PFINT_ITR0_MAX_INDEX 2 #define I40E_PFINT_ITR0_INTERVAL_SHIFT 0 -#define I40E_PFINT_ITR0_INTERVAL_MASK (0xFFF << I40E_PFINT_ITR0_INTERVAL_SHIFT) -#define I40E_PFINT_ITRN(_i, _INTPF) (0x00030000 + ((_i) * 2048 + (_INTPF) * 4)) +#define I40E_PFINT_ITR0_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_ITR0_INTERVAL_SHIFT) +#define I40E_PFINT_ITRN(_i, _INTPF) (0x00030000 + ((_i) * 2048 + (_INTPF) * 4)) /* _i=0...2, _INTPF=0...511 */ /* Reset: PFR */ #define I40E_PFINT_ITRN_MAX_INDEX 2 #define I40E_PFINT_ITRN_INTERVAL_SHIFT 0 -#define I40E_PFINT_ITRN_INTERVAL_MASK (0xFFF << I40E_PFINT_ITRN_INTERVAL_SHIFT) -#define I40E_PFINT_LNKLST0 0x00038500 +#define I40E_PFINT_ITRN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_ITRN_INTERVAL_SHIFT) +#define I40E_PFINT_LNKLST0 0x00038500 /* Reset: PFR */ #define I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT 0 -#define I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK (0x7FF << I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) +#define I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK I40E_MASK(0x7FF, I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) #define I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT 11 -#define I40E_PFINT_LNKLST0_FIRSTQ_TYPE_MASK (0x3 << I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT) -#define I40E_PFINT_LNKLSTN(_INTPF) (0x00035000 + ((_INTPF) * 4)) /* _i=0...511 */ +#define I40E_PFINT_LNKLST0_FIRSTQ_TYPE_MASK I40E_MASK(0x3, I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT) +#define I40E_PFINT_LNKLSTN(_INTPF) (0x00035000 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: PFR */ #define I40E_PFINT_LNKLSTN_MAX_INDEX 511 #define I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT 0 -#define I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK (0x7FF << I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) +#define I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK I40E_MASK(0x7FF, I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) #define I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT 11 -#define I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_MASK (0x3 << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) -#define I40E_PFINT_RATE0 0x00038580 +#define I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_MASK I40E_MASK(0x3, I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) +#define I40E_PFINT_RATE0 0x00038580 /* Reset: PFR */ #define I40E_PFINT_RATE0_INTERVAL_SHIFT 0 -#define I40E_PFINT_RATE0_INTERVAL_MASK (0x3F << I40E_PFINT_RATE0_INTERVAL_SHIFT) +#define I40E_PFINT_RATE0_INTERVAL_MASK I40E_MASK(0x3F, I40E_PFINT_RATE0_INTERVAL_SHIFT) #define I40E_PFINT_RATE0_INTRL_ENA_SHIFT 6 -#define I40E_PFINT_RATE0_INTRL_ENA_MASK (0x1 << I40E_PFINT_RATE0_INTRL_ENA_SHIFT) -#define I40E_PFINT_RATEN(_INTPF) (0x00035800 + ((_INTPF) * 4)) /* _i=0...511 */ +#define I40E_PFINT_RATE0_INTRL_ENA_MASK I40E_MASK(0x1, I40E_PFINT_RATE0_INTRL_ENA_SHIFT) +#define I40E_PFINT_RATEN(_INTPF) (0x00035800 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: PFR */ #define I40E_PFINT_RATEN_MAX_INDEX 511 #define I40E_PFINT_RATEN_INTERVAL_SHIFT 0 -#define I40E_PFINT_RATEN_INTERVAL_MASK (0x3F << I40E_PFINT_RATEN_INTERVAL_SHIFT) +#define I40E_PFINT_RATEN_INTERVAL_MASK I40E_MASK(0x3F, I40E_PFINT_RATEN_INTERVAL_SHIFT) #define I40E_PFINT_RATEN_INTRL_ENA_SHIFT 6 -#define I40E_PFINT_RATEN_INTRL_ENA_MASK (0x1 << I40E_PFINT_RATEN_INTRL_ENA_SHIFT) -#define I40E_PFINT_STAT_CTL0 0x00038400 +#define I40E_PFINT_RATEN_INTRL_ENA_MASK I40E_MASK(0x1, I40E_PFINT_RATEN_INTRL_ENA_SHIFT) +#define I40E_PFINT_STAT_CTL0 0x00038400 /* Reset: PFR */ #define I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT 2 -#define I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_MASK (0x3 << I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT) -#define I40E_QINT_RQCTL(_Q) (0x0003A000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT) +#define I40E_QINT_RQCTL(_Q) (0x0003A000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ #define I40E_QINT_RQCTL_MAX_INDEX 1535 #define I40E_QINT_RQCTL_MSIX_INDX_SHIFT 0 -#define I40E_QINT_RQCTL_MSIX_INDX_MASK (0xFF << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) +#define I40E_QINT_RQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_QINT_RQCTL_MSIX_INDX_SHIFT) #define I40E_QINT_RQCTL_ITR_INDX_SHIFT 11 -#define I40E_QINT_RQCTL_ITR_INDX_MASK (0x3 << I40E_QINT_RQCTL_ITR_INDX_SHIFT) +#define I40E_QINT_RQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_QINT_RQCTL_ITR_INDX_SHIFT) #define I40E_QINT_RQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_QINT_RQCTL_MSIX0_INDX_MASK (0x7 << I40E_QINT_RQCTL_MSIX0_INDX_SHIFT) +#define I40E_QINT_RQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_QINT_RQCTL_MSIX0_INDX_SHIFT) #define I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT 16 -#define I40E_QINT_RQCTL_NEXTQ_INDX_MASK (0x7FF << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) +#define I40E_QINT_RQCTL_NEXTQ_INDX_MASK I40E_MASK(0x7FF, I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) #define I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT 27 -#define I40E_QINT_RQCTL_NEXTQ_TYPE_MASK (0x3 << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) +#define I40E_QINT_RQCTL_NEXTQ_TYPE_MASK I40E_MASK(0x3, I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) #define I40E_QINT_RQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_QINT_RQCTL_CAUSE_ENA_MASK (0x1 << I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) +#define I40E_QINT_RQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) #define I40E_QINT_RQCTL_INTEVENT_SHIFT 31 -#define I40E_QINT_RQCTL_INTEVENT_MASK (0x1 << I40E_QINT_RQCTL_INTEVENT_SHIFT) -#define I40E_QINT_TQCTL(_Q) (0x0003C000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_QINT_RQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_QINT_RQCTL_INTEVENT_SHIFT) +#define I40E_QINT_TQCTL(_Q) (0x0003C000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ #define I40E_QINT_TQCTL_MAX_INDEX 1535 #define I40E_QINT_TQCTL_MSIX_INDX_SHIFT 0 -#define I40E_QINT_TQCTL_MSIX_INDX_MASK (0xFF << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) +#define I40E_QINT_TQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_QINT_TQCTL_MSIX_INDX_SHIFT) #define I40E_QINT_TQCTL_ITR_INDX_SHIFT 11 -#define I40E_QINT_TQCTL_ITR_INDX_MASK (0x3 << I40E_QINT_TQCTL_ITR_INDX_SHIFT) +#define I40E_QINT_TQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_QINT_TQCTL_ITR_INDX_SHIFT) #define I40E_QINT_TQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_QINT_TQCTL_MSIX0_INDX_MASK (0x7 << I40E_QINT_TQCTL_MSIX0_INDX_SHIFT) +#define I40E_QINT_TQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_QINT_TQCTL_MSIX0_INDX_SHIFT) #define I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT 16 -#define I40E_QINT_TQCTL_NEXTQ_INDX_MASK (0x7FF << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) +#define I40E_QINT_TQCTL_NEXTQ_INDX_MASK I40E_MASK(0x7FF, I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) #define I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT 27 -#define I40E_QINT_TQCTL_NEXTQ_TYPE_MASK (0x3 << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT) +#define I40E_QINT_TQCTL_NEXTQ_TYPE_MASK I40E_MASK(0x3, I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT) #define I40E_QINT_TQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_QINT_TQCTL_CAUSE_ENA_MASK (0x1 << I40E_QINT_TQCTL_CAUSE_ENA_SHIFT) +#define I40E_QINT_TQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_QINT_TQCTL_CAUSE_ENA_SHIFT) #define I40E_QINT_TQCTL_INTEVENT_SHIFT 31 -#define I40E_QINT_TQCTL_INTEVENT_MASK (0x1 << I40E_QINT_TQCTL_INTEVENT_SHIFT) -#define I40E_VFINT_DYN_CTL0(_VF) (0x0002A400 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_QINT_TQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_QINT_TQCTL_INTEVENT_SHIFT) +#define I40E_VFINT_DYN_CTL0(_VF) (0x0002A400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VFINT_DYN_CTL0_MAX_INDEX 127 #define I40E_VFINT_DYN_CTL0_INTENA_SHIFT 0 -#define I40E_VFINT_DYN_CTL0_INTENA_MASK (0x1 << I40E_VFINT_DYN_CTL0_INTENA_SHIFT) +#define I40E_VFINT_DYN_CTL0_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_INTENA_SHIFT) #define I40E_VFINT_DYN_CTL0_CLEARPBA_SHIFT 1 -#define I40E_VFINT_DYN_CTL0_CLEARPBA_MASK (0x1 << I40E_VFINT_DYN_CTL0_CLEARPBA_SHIFT) +#define I40E_VFINT_DYN_CTL0_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_CLEARPBA_SHIFT) #define I40E_VFINT_DYN_CTL0_SWINT_TRIG_SHIFT 2 -#define I40E_VFINT_DYN_CTL0_SWINT_TRIG_MASK (0x1 << I40E_VFINT_DYN_CTL0_SWINT_TRIG_SHIFT) +#define I40E_VFINT_DYN_CTL0_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_SWINT_TRIG_SHIFT) #define I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT 3 -#define I40E_VFINT_DYN_CTL0_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTL0_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTL0_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTL0_INTERVAL_MASK (0xFFF << I40E_VFINT_DYN_CTL0_INTERVAL_SHIFT) +#define I40E_VFINT_DYN_CTL0_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTL0_INTERVAL_SHIFT) #define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK (0x1 << I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT) +#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT) #define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_SHIFT 25 -#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTL0_SW_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL0_SW_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTL0_INTENA_MSK_SHIFT 31 -#define I40E_VFINT_DYN_CTL0_INTENA_MSK_MASK (0x1 << I40E_VFINT_DYN_CTL0_INTENA_MSK_SHIFT) -#define I40E_VFINT_DYN_CTLN(_INTVF) (0x00024800 + ((_INTVF) * 4)) /* _i=0...511 */ +#define I40E_VFINT_DYN_CTL0_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_INTENA_MSK_SHIFT) +#define I40E_VFINT_DYN_CTLN(_INTVF) (0x00024800 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: VFR */ #define I40E_VFINT_DYN_CTLN_MAX_INDEX 511 #define I40E_VFINT_DYN_CTLN_INTENA_SHIFT 0 -#define I40E_VFINT_DYN_CTLN_INTENA_MASK (0x1 << I40E_VFINT_DYN_CTLN_INTENA_SHIFT) +#define I40E_VFINT_DYN_CTLN_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_INTENA_SHIFT) #define I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT 1 -#define I40E_VFINT_DYN_CTLN_CLEARPBA_MASK (0x1 << I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT) +#define I40E_VFINT_DYN_CTLN_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT) #define I40E_VFINT_DYN_CTLN_SWINT_TRIG_SHIFT 2 -#define I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK (0x1 << I40E_VFINT_DYN_CTLN_SWINT_TRIG_SHIFT) +#define I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_SWINT_TRIG_SHIFT) #define I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT 3 -#define I40E_VFINT_DYN_CTLN_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTLN_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTLN_INTERVAL_MASK (0xFFF << I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT) +#define I40E_VFINT_DYN_CTLN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT) #define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK (0x1 << I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT) +#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT) #define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_SHIFT 25 -#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTLN_SW_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN_SW_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTLN_INTENA_MSK_SHIFT 31 -#define I40E_VFINT_DYN_CTLN_INTENA_MSK_MASK (0x1 << I40E_VFINT_DYN_CTLN_INTENA_MSK_SHIFT) -#define I40E_VFINT_ICR0(_VF) (0x0002BC00 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFINT_DYN_CTLN_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_INTENA_MSK_SHIFT) +#define I40E_VFINT_ICR0(_VF) (0x0002BC00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VFINT_ICR0_MAX_INDEX 127 #define I40E_VFINT_ICR0_INTEVENT_SHIFT 0 -#define I40E_VFINT_ICR0_INTEVENT_MASK (0x1 << I40E_VFINT_ICR0_INTEVENT_SHIFT) +#define I40E_VFINT_ICR0_INTEVENT_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_INTEVENT_SHIFT) #define I40E_VFINT_ICR0_QUEUE_0_SHIFT 1 -#define I40E_VFINT_ICR0_QUEUE_0_MASK (0x1 << I40E_VFINT_ICR0_QUEUE_0_SHIFT) +#define I40E_VFINT_ICR0_QUEUE_0_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_QUEUE_0_SHIFT) #define I40E_VFINT_ICR0_QUEUE_1_SHIFT 2 -#define I40E_VFINT_ICR0_QUEUE_1_MASK (0x1 << I40E_VFINT_ICR0_QUEUE_1_SHIFT) +#define I40E_VFINT_ICR0_QUEUE_1_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_QUEUE_1_SHIFT) #define I40E_VFINT_ICR0_QUEUE_2_SHIFT 3 -#define I40E_VFINT_ICR0_QUEUE_2_MASK (0x1 << I40E_VFINT_ICR0_QUEUE_2_SHIFT) +#define I40E_VFINT_ICR0_QUEUE_2_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_QUEUE_2_SHIFT) #define I40E_VFINT_ICR0_QUEUE_3_SHIFT 4 -#define I40E_VFINT_ICR0_QUEUE_3_MASK (0x1 << I40E_VFINT_ICR0_QUEUE_3_SHIFT) +#define I40E_VFINT_ICR0_QUEUE_3_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_QUEUE_3_SHIFT) #define I40E_VFINT_ICR0_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_VFINT_ICR0_LINK_STAT_CHANGE_MASK (0x1 << I40E_VFINT_ICR0_LINK_STAT_CHANGE_SHIFT) +#define I40E_VFINT_ICR0_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_LINK_STAT_CHANGE_SHIFT) #define I40E_VFINT_ICR0_ADMINQ_SHIFT 30 -#define I40E_VFINT_ICR0_ADMINQ_MASK (0x1 << I40E_VFINT_ICR0_ADMINQ_SHIFT) +#define I40E_VFINT_ICR0_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ADMINQ_SHIFT) #define I40E_VFINT_ICR0_SWINT_SHIFT 31 -#define I40E_VFINT_ICR0_SWINT_MASK (0x1 << I40E_VFINT_ICR0_SWINT_SHIFT) -#define I40E_VFINT_ICR0_ENA(_VF) (0x0002C000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFINT_ICR0_SWINT_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_SWINT_SHIFT) +#define I40E_VFINT_ICR0_ENA(_VF) (0x0002C000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VFINT_ICR0_ENA_MAX_INDEX 127 #define I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK (0x1 << I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT) +#define I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT) #define I40E_VFINT_ICR0_ENA_ADMINQ_SHIFT 30 -#define I40E_VFINT_ICR0_ENA_ADMINQ_MASK (0x1 << I40E_VFINT_ICR0_ENA_ADMINQ_SHIFT) +#define I40E_VFINT_ICR0_ENA_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA_ADMINQ_SHIFT) #define I40E_VFINT_ICR0_ENA_RSVD_SHIFT 31 -#define I40E_VFINT_ICR0_ENA_RSVD_MASK (0x1 << I40E_VFINT_ICR0_ENA_RSVD_SHIFT) -#define I40E_VFINT_ITR0(_i, _VF) (0x00028000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...2, _VF=0...127 */ +#define I40E_VFINT_ICR0_ENA_RSVD_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA_RSVD_SHIFT) +#define I40E_VFINT_ITR0(_i, _VF) (0x00028000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...2, _VF=0...127 */ /* Reset: VFR */ #define I40E_VFINT_ITR0_MAX_INDEX 2 #define I40E_VFINT_ITR0_INTERVAL_SHIFT 0 -#define I40E_VFINT_ITR0_INTERVAL_MASK (0xFFF << I40E_VFINT_ITR0_INTERVAL_SHIFT) -#define I40E_VFINT_ITRN(_i, _INTVF) (0x00020000 + ((_i) * 2048 + (_INTVF) * 4)) +#define I40E_VFINT_ITR0_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITR0_INTERVAL_SHIFT) +#define I40E_VFINT_ITRN(_i, _INTVF) (0x00020000 + ((_i) * 2048 + (_INTVF) * 4)) /* _i=0...2, _INTVF=0...511 */ /* Reset: VFR */ #define I40E_VFINT_ITRN_MAX_INDEX 2 #define I40E_VFINT_ITRN_INTERVAL_SHIFT 0 -#define I40E_VFINT_ITRN_INTERVAL_MASK (0xFFF << I40E_VFINT_ITRN_INTERVAL_SHIFT) -#define I40E_VFINT_STAT_CTL0(_VF) (0x0002A000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFINT_ITRN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITRN_INTERVAL_SHIFT) +#define I40E_VFINT_STAT_CTL0(_VF) (0x0002A000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VFINT_STAT_CTL0_MAX_INDEX 127 #define I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT 2 -#define I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_MASK (0x3 << I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT) -#define I40E_VPINT_AEQCTL(_VF) (0x0002B800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT) +#define I40E_VPINT_AEQCTL(_VF) (0x0002B800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VPINT_AEQCTL_MAX_INDEX 127 #define I40E_VPINT_AEQCTL_MSIX_INDX_SHIFT 0 -#define I40E_VPINT_AEQCTL_MSIX_INDX_MASK (0xFF << I40E_VPINT_AEQCTL_MSIX_INDX_SHIFT) +#define I40E_VPINT_AEQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_VPINT_AEQCTL_MSIX_INDX_SHIFT) #define I40E_VPINT_AEQCTL_ITR_INDX_SHIFT 11 -#define I40E_VPINT_AEQCTL_ITR_INDX_MASK (0x3 << I40E_VPINT_AEQCTL_ITR_INDX_SHIFT) +#define I40E_VPINT_AEQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_VPINT_AEQCTL_ITR_INDX_SHIFT) #define I40E_VPINT_AEQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_VPINT_AEQCTL_MSIX0_INDX_MASK (0x7 << I40E_VPINT_AEQCTL_MSIX0_INDX_SHIFT) +#define I40E_VPINT_AEQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_VPINT_AEQCTL_MSIX0_INDX_SHIFT) #define I40E_VPINT_AEQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_VPINT_AEQCTL_CAUSE_ENA_MASK (0x1 << I40E_VPINT_AEQCTL_CAUSE_ENA_SHIFT) +#define I40E_VPINT_AEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_VPINT_AEQCTL_CAUSE_ENA_SHIFT) #define I40E_VPINT_AEQCTL_INTEVENT_SHIFT 31 -#define I40E_VPINT_AEQCTL_INTEVENT_MASK (0x1 << I40E_VPINT_AEQCTL_INTEVENT_SHIFT) -#define I40E_VPINT_CEQCTL(_INTVF) (0x00026800 + ((_INTVF) * 4)) /* _i=0...511 */ +#define I40E_VPINT_AEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_VPINT_AEQCTL_INTEVENT_SHIFT) +#define I40E_VPINT_CEQCTL(_INTVF) (0x00026800 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: CORER */ #define I40E_VPINT_CEQCTL_MAX_INDEX 511 #define I40E_VPINT_CEQCTL_MSIX_INDX_SHIFT 0 -#define I40E_VPINT_CEQCTL_MSIX_INDX_MASK (0xFF << I40E_VPINT_CEQCTL_MSIX_INDX_SHIFT) +#define I40E_VPINT_CEQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_VPINT_CEQCTL_MSIX_INDX_SHIFT) #define I40E_VPINT_CEQCTL_ITR_INDX_SHIFT 11 -#define I40E_VPINT_CEQCTL_ITR_INDX_MASK (0x3 << I40E_VPINT_CEQCTL_ITR_INDX_SHIFT) +#define I40E_VPINT_CEQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_VPINT_CEQCTL_ITR_INDX_SHIFT) #define I40E_VPINT_CEQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_VPINT_CEQCTL_MSIX0_INDX_MASK (0x7 << I40E_VPINT_CEQCTL_MSIX0_INDX_SHIFT) +#define I40E_VPINT_CEQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_VPINT_CEQCTL_MSIX0_INDX_SHIFT) #define I40E_VPINT_CEQCTL_NEXTQ_INDX_SHIFT 16 -#define I40E_VPINT_CEQCTL_NEXTQ_INDX_MASK (0x7FF << I40E_VPINT_CEQCTL_NEXTQ_INDX_SHIFT) +#define I40E_VPINT_CEQCTL_NEXTQ_INDX_MASK I40E_MASK(0x7FF, I40E_VPINT_CEQCTL_NEXTQ_INDX_SHIFT) #define I40E_VPINT_CEQCTL_NEXTQ_TYPE_SHIFT 27 -#define I40E_VPINT_CEQCTL_NEXTQ_TYPE_MASK (0x3 << I40E_VPINT_CEQCTL_NEXTQ_TYPE_SHIFT) +#define I40E_VPINT_CEQCTL_NEXTQ_TYPE_MASK I40E_MASK(0x3, I40E_VPINT_CEQCTL_NEXTQ_TYPE_SHIFT) #define I40E_VPINT_CEQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_VPINT_CEQCTL_CAUSE_ENA_MASK (0x1 << I40E_VPINT_CEQCTL_CAUSE_ENA_SHIFT) +#define I40E_VPINT_CEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_VPINT_CEQCTL_CAUSE_ENA_SHIFT) #define I40E_VPINT_CEQCTL_INTEVENT_SHIFT 31 -#define I40E_VPINT_CEQCTL_INTEVENT_MASK (0x1 << I40E_VPINT_CEQCTL_INTEVENT_SHIFT) -#define I40E_VPINT_LNKLST0(_VF) (0x0002A800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VPINT_CEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_VPINT_CEQCTL_INTEVENT_SHIFT) +#define I40E_VPINT_LNKLST0(_VF) (0x0002A800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VPINT_LNKLST0_MAX_INDEX 127 #define I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT 0 -#define I40E_VPINT_LNKLST0_FIRSTQ_INDX_MASK (0x7FF << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) +#define I40E_VPINT_LNKLST0_FIRSTQ_INDX_MASK I40E_MASK(0x7FF, I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) #define I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT 11 -#define I40E_VPINT_LNKLST0_FIRSTQ_TYPE_MASK (0x3 << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT) -#define I40E_VPINT_LNKLSTN(_INTVF) (0x00025000 + ((_INTVF) * 4)) /* _i=0...511 */ +#define I40E_VPINT_LNKLST0_FIRSTQ_TYPE_MASK I40E_MASK(0x3, I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT) +#define I40E_VPINT_LNKLSTN(_INTVF) (0x00025000 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: VFR */ #define I40E_VPINT_LNKLSTN_MAX_INDEX 511 #define I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT 0 -#define I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK (0x7FF << I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) +#define I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK I40E_MASK(0x7FF, I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) #define I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT 11 -#define I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK (0x3 << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) -#define I40E_VPINT_RATE0(_VF) (0x0002AC00 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK I40E_MASK(0x3, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) +#define I40E_VPINT_RATE0(_VF) (0x0002AC00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VPINT_RATE0_MAX_INDEX 127 #define I40E_VPINT_RATE0_INTERVAL_SHIFT 0 -#define I40E_VPINT_RATE0_INTERVAL_MASK (0x3F << I40E_VPINT_RATE0_INTERVAL_SHIFT) +#define I40E_VPINT_RATE0_INTERVAL_MASK I40E_MASK(0x3F, I40E_VPINT_RATE0_INTERVAL_SHIFT) #define I40E_VPINT_RATE0_INTRL_ENA_SHIFT 6 -#define I40E_VPINT_RATE0_INTRL_ENA_MASK (0x1 << I40E_VPINT_RATE0_INTRL_ENA_SHIFT) -#define I40E_VPINT_RATEN(_INTVF) (0x00025800 + ((_INTVF) * 4)) /* _i=0...511 */ +#define I40E_VPINT_RATE0_INTRL_ENA_MASK I40E_MASK(0x1, I40E_VPINT_RATE0_INTRL_ENA_SHIFT) +#define I40E_VPINT_RATEN(_INTVF) (0x00025800 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: VFR */ #define I40E_VPINT_RATEN_MAX_INDEX 511 #define I40E_VPINT_RATEN_INTERVAL_SHIFT 0 -#define I40E_VPINT_RATEN_INTERVAL_MASK (0x3F << I40E_VPINT_RATEN_INTERVAL_SHIFT) +#define I40E_VPINT_RATEN_INTERVAL_MASK I40E_MASK(0x3F, I40E_VPINT_RATEN_INTERVAL_SHIFT) #define I40E_VPINT_RATEN_INTRL_ENA_SHIFT 6 -#define I40E_VPINT_RATEN_INTRL_ENA_MASK (0x1 << I40E_VPINT_RATEN_INTRL_ENA_SHIFT) -#define I40E_GL_RDPU_CNTRL 0x00051060 +#define I40E_VPINT_RATEN_INTRL_ENA_MASK I40E_MASK(0x1, I40E_VPINT_RATEN_INTRL_ENA_SHIFT) +#define I40E_GL_RDPU_CNTRL 0x00051060 /* Reset: CORER */ #define I40E_GL_RDPU_CNTRL_RX_PAD_EN_SHIFT 0 -#define I40E_GL_RDPU_CNTRL_RX_PAD_EN_MASK (0x1 << I40E_GL_RDPU_CNTRL_RX_PAD_EN_SHIFT) +#define I40E_GL_RDPU_CNTRL_RX_PAD_EN_MASK I40E_MASK(0x1, I40E_GL_RDPU_CNTRL_RX_PAD_EN_SHIFT) #define I40E_GL_RDPU_CNTRL_ECO_SHIFT 1 -#define I40E_GL_RDPU_CNTRL_ECO_MASK (0x7FFFFFFF << I40E_GL_RDPU_CNTRL_ECO_SHIFT) -#define I40E_GLLAN_RCTL_0 0x0012A500 +#define I40E_GL_RDPU_CNTRL_ECO_MASK I40E_MASK(0x7FFFFFFF, I40E_GL_RDPU_CNTRL_ECO_SHIFT) +#define I40E_GLLAN_RCTL_0 0x0012A500 /* Reset: CORER */ #define I40E_GLLAN_RCTL_0_PXE_MODE_SHIFT 0 -#define I40E_GLLAN_RCTL_0_PXE_MODE_MASK (0x1 << I40E_GLLAN_RCTL_0_PXE_MODE_SHIFT) -#define I40E_GLLAN_TSOMSK_F 0x000442D8 +#define I40E_GLLAN_RCTL_0_PXE_MODE_MASK I40E_MASK(0x1, I40E_GLLAN_RCTL_0_PXE_MODE_SHIFT) +#define I40E_GLLAN_TSOMSK_F 0x000442D8 /* Reset: CORER */ #define I40E_GLLAN_TSOMSK_F_TCPMSKF_SHIFT 0 -#define I40E_GLLAN_TSOMSK_F_TCPMSKF_MASK (0xFFF << I40E_GLLAN_TSOMSK_F_TCPMSKF_SHIFT) -#define I40E_GLLAN_TSOMSK_L 0x000442E0 +#define I40E_GLLAN_TSOMSK_F_TCPMSKF_MASK I40E_MASK(0xFFF, I40E_GLLAN_TSOMSK_F_TCPMSKF_SHIFT) +#define I40E_GLLAN_TSOMSK_L 0x000442E0 /* Reset: CORER */ #define I40E_GLLAN_TSOMSK_L_TCPMSKL_SHIFT 0 -#define I40E_GLLAN_TSOMSK_L_TCPMSKL_MASK (0xFFF << I40E_GLLAN_TSOMSK_L_TCPMSKL_SHIFT) -#define I40E_GLLAN_TSOMSK_M 0x000442DC +#define I40E_GLLAN_TSOMSK_L_TCPMSKL_MASK I40E_MASK(0xFFF, I40E_GLLAN_TSOMSK_L_TCPMSKL_SHIFT) +#define I40E_GLLAN_TSOMSK_M 0x000442DC /* Reset: CORER */ #define I40E_GLLAN_TSOMSK_M_TCPMSKM_SHIFT 0 -#define I40E_GLLAN_TSOMSK_M_TCPMSKM_MASK (0xFFF << I40E_GLLAN_TSOMSK_M_TCPMSKM_SHIFT) -#define I40E_GLLAN_TXPRE_QDIS(_i) (0x000E6500 + ((_i) * 4)) /* i=0..11 */ +#define I40E_GLLAN_TSOMSK_M_TCPMSKM_MASK I40E_MASK(0xFFF, I40E_GLLAN_TSOMSK_M_TCPMSKM_SHIFT) +#define I40E_GLLAN_TXPRE_QDIS(_i) (0x000e6500 + ((_i) * 4)) /* _i=0...11 */ /* Reset: CORER */ +#define I40E_GLLAN_TXPRE_QDIS_MAX_INDEX 11 #define I40E_GLLAN_TXPRE_QDIS_QINDX_SHIFT 0 -#define I40E_GLLAN_TXPRE_QDIS_QINDX_MASK (0x7FF << I40E_GLLAN_TXPRE_QDIS_QINDX_SHIFT) +#define I40E_GLLAN_TXPRE_QDIS_QINDX_MASK I40E_MASK(0x7FF, I40E_GLLAN_TXPRE_QDIS_QINDX_SHIFT) +#define I40E_GLLAN_TXPRE_QDIS_QDIS_STAT_SHIFT 16 +#define I40E_GLLAN_TXPRE_QDIS_QDIS_STAT_MASK I40E_MASK(0x1, I40E_GLLAN_TXPRE_QDIS_QDIS_STAT_SHIFT) #define I40E_GLLAN_TXPRE_QDIS_SET_QDIS_SHIFT 30 -#define I40E_GLLAN_TXPRE_QDIS_SET_QDIS_MASK (0x1 << I40E_GLLAN_TXPRE_QDIS_SET_QDIS_SHIFT) +#define I40E_GLLAN_TXPRE_QDIS_SET_QDIS_MASK I40E_MASK(0x1, I40E_GLLAN_TXPRE_QDIS_SET_QDIS_SHIFT) #define I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_SHIFT 31 -#define I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_MASK (0x1 << I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_SHIFT) - -#define I40E_PFLAN_QALLOC 0x001C0400 +#define I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_MASK I40E_MASK(0x1, I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_SHIFT) +#define I40E_PFLAN_QALLOC 0x001C0400 /* Reset: CORER */ #define I40E_PFLAN_QALLOC_FIRSTQ_SHIFT 0 -#define I40E_PFLAN_QALLOC_FIRSTQ_MASK (0x7FF << I40E_PFLAN_QALLOC_FIRSTQ_SHIFT) +#define I40E_PFLAN_QALLOC_FIRSTQ_MASK I40E_MASK(0x7FF, I40E_PFLAN_QALLOC_FIRSTQ_SHIFT) #define I40E_PFLAN_QALLOC_LASTQ_SHIFT 16 -#define I40E_PFLAN_QALLOC_LASTQ_MASK (0x7FF << I40E_PFLAN_QALLOC_LASTQ_SHIFT) +#define I40E_PFLAN_QALLOC_LASTQ_MASK I40E_MASK(0x7FF, I40E_PFLAN_QALLOC_LASTQ_SHIFT) #define I40E_PFLAN_QALLOC_VALID_SHIFT 31 -#define I40E_PFLAN_QALLOC_VALID_MASK (0x1 << I40E_PFLAN_QALLOC_VALID_SHIFT) -#define I40E_QRX_ENA(_Q) (0x00120000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_PFLAN_QALLOC_VALID_MASK I40E_MASK(0x1, I40E_PFLAN_QALLOC_VALID_SHIFT) +#define I40E_QRX_ENA(_Q) (0x00120000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: PFR */ #define I40E_QRX_ENA_MAX_INDEX 1535 #define I40E_QRX_ENA_QENA_REQ_SHIFT 0 -#define I40E_QRX_ENA_QENA_REQ_MASK (0x1 << I40E_QRX_ENA_QENA_REQ_SHIFT) +#define I40E_QRX_ENA_QENA_REQ_MASK I40E_MASK(0x1, I40E_QRX_ENA_QENA_REQ_SHIFT) #define I40E_QRX_ENA_FAST_QDIS_SHIFT 1 -#define I40E_QRX_ENA_FAST_QDIS_MASK (0x1 << I40E_QRX_ENA_FAST_QDIS_SHIFT) +#define I40E_QRX_ENA_FAST_QDIS_MASK I40E_MASK(0x1, I40E_QRX_ENA_FAST_QDIS_SHIFT) #define I40E_QRX_ENA_QENA_STAT_SHIFT 2 -#define I40E_QRX_ENA_QENA_STAT_MASK (0x1 << I40E_QRX_ENA_QENA_STAT_SHIFT) -#define I40E_QRX_TAIL(_Q) (0x00128000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_QRX_ENA_QENA_STAT_MASK I40E_MASK(0x1, I40E_QRX_ENA_QENA_STAT_SHIFT) +#define I40E_QRX_TAIL(_Q) (0x00128000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ #define I40E_QRX_TAIL_MAX_INDEX 1535 #define I40E_QRX_TAIL_TAIL_SHIFT 0 -#define I40E_QRX_TAIL_TAIL_MASK (0x1FFF << I40E_QRX_TAIL_TAIL_SHIFT) -#define I40E_QTX_CTL(_Q) (0x00104000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_QRX_TAIL_TAIL_MASK I40E_MASK(0x1FFF, I40E_QRX_TAIL_TAIL_SHIFT) +#define I40E_QTX_CTL(_Q) (0x00104000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ #define I40E_QTX_CTL_MAX_INDEX 1535 #define I40E_QTX_CTL_PFVF_Q_SHIFT 0 -#define I40E_QTX_CTL_PFVF_Q_MASK (0x3 << I40E_QTX_CTL_PFVF_Q_SHIFT) +#define I40E_QTX_CTL_PFVF_Q_MASK I40E_MASK(0x3, I40E_QTX_CTL_PFVF_Q_SHIFT) #define I40E_QTX_CTL_PF_INDX_SHIFT 2 -#define I40E_QTX_CTL_PF_INDX_MASK (0xF << I40E_QTX_CTL_PF_INDX_SHIFT) +#define I40E_QTX_CTL_PF_INDX_MASK I40E_MASK(0xF, I40E_QTX_CTL_PF_INDX_SHIFT) #define I40E_QTX_CTL_VFVM_INDX_SHIFT 7 -#define I40E_QTX_CTL_VFVM_INDX_MASK (0x1FF << I40E_QTX_CTL_VFVM_INDX_SHIFT) -#define I40E_QTX_ENA(_Q) (0x00100000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_QTX_CTL_VFVM_INDX_MASK I40E_MASK(0x1FF, I40E_QTX_CTL_VFVM_INDX_SHIFT) +#define I40E_QTX_ENA(_Q) (0x00100000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: PFR */ #define I40E_QTX_ENA_MAX_INDEX 1535 #define I40E_QTX_ENA_QENA_REQ_SHIFT 0 -#define I40E_QTX_ENA_QENA_REQ_MASK (0x1 << I40E_QTX_ENA_QENA_REQ_SHIFT) +#define I40E_QTX_ENA_QENA_REQ_MASK I40E_MASK(0x1, I40E_QTX_ENA_QENA_REQ_SHIFT) #define I40E_QTX_ENA_FAST_QDIS_SHIFT 1 -#define I40E_QTX_ENA_FAST_QDIS_MASK (0x1 << I40E_QTX_ENA_FAST_QDIS_SHIFT) +#define I40E_QTX_ENA_FAST_QDIS_MASK I40E_MASK(0x1, I40E_QTX_ENA_FAST_QDIS_SHIFT) #define I40E_QTX_ENA_QENA_STAT_SHIFT 2 -#define I40E_QTX_ENA_QENA_STAT_MASK (0x1 << I40E_QTX_ENA_QENA_STAT_SHIFT) -#define I40E_QTX_HEAD(_Q) (0x000E4000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_QTX_ENA_QENA_STAT_MASK I40E_MASK(0x1, I40E_QTX_ENA_QENA_STAT_SHIFT) +#define I40E_QTX_HEAD(_Q) (0x000E4000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ #define I40E_QTX_HEAD_MAX_INDEX 1535 #define I40E_QTX_HEAD_HEAD_SHIFT 0 -#define I40E_QTX_HEAD_HEAD_MASK (0x1FFF << I40E_QTX_HEAD_HEAD_SHIFT) +#define I40E_QTX_HEAD_HEAD_MASK I40E_MASK(0x1FFF, I40E_QTX_HEAD_HEAD_SHIFT) #define I40E_QTX_HEAD_RS_PENDING_SHIFT 16 -#define I40E_QTX_HEAD_RS_PENDING_MASK (0x1 << I40E_QTX_HEAD_RS_PENDING_SHIFT) -#define I40E_QTX_TAIL(_Q) (0x00108000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_QTX_HEAD_RS_PENDING_MASK I40E_MASK(0x1, I40E_QTX_HEAD_RS_PENDING_SHIFT) +#define I40E_QTX_TAIL(_Q) (0x00108000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: PFR */ #define I40E_QTX_TAIL_MAX_INDEX 1535 #define I40E_QTX_TAIL_TAIL_SHIFT 0 -#define I40E_QTX_TAIL_TAIL_MASK (0x1FFF << I40E_QTX_TAIL_TAIL_SHIFT) -#define I40E_VPLAN_MAPENA(_VF) (0x00074000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_QTX_TAIL_TAIL_MASK I40E_MASK(0x1FFF, I40E_QTX_TAIL_TAIL_SHIFT) +#define I40E_VPLAN_MAPENA(_VF) (0x00074000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VPLAN_MAPENA_MAX_INDEX 127 #define I40E_VPLAN_MAPENA_TXRX_ENA_SHIFT 0 -#define I40E_VPLAN_MAPENA_TXRX_ENA_MASK (0x1 << I40E_VPLAN_MAPENA_TXRX_ENA_SHIFT) -#define I40E_VPLAN_QTABLE(_i, _VF) (0x00070000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ +#define I40E_VPLAN_MAPENA_TXRX_ENA_MASK I40E_MASK(0x1, I40E_VPLAN_MAPENA_TXRX_ENA_SHIFT) +#define I40E_VPLAN_QTABLE(_i, _VF) (0x00070000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ /* Reset: VFR */ #define I40E_VPLAN_QTABLE_MAX_INDEX 15 #define I40E_VPLAN_QTABLE_QINDEX_SHIFT 0 -#define I40E_VPLAN_QTABLE_QINDEX_MASK (0x7FF << I40E_VPLAN_QTABLE_QINDEX_SHIFT) -#define I40E_VSILAN_QBASE(_VSI) (0x0020C800 + ((_VSI) * 4)) /* _i=0...383 */ +#define I40E_VPLAN_QTABLE_QINDEX_MASK I40E_MASK(0x7FF, I40E_VPLAN_QTABLE_QINDEX_SHIFT) +#define I40E_VSILAN_QBASE(_VSI) (0x0020C800 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: PFR */ #define I40E_VSILAN_QBASE_MAX_INDEX 383 #define I40E_VSILAN_QBASE_VSIBASE_SHIFT 0 -#define I40E_VSILAN_QBASE_VSIBASE_MASK (0x7FF << I40E_VSILAN_QBASE_VSIBASE_SHIFT) +#define I40E_VSILAN_QBASE_VSIBASE_MASK I40E_MASK(0x7FF, I40E_VSILAN_QBASE_VSIBASE_SHIFT) #define I40E_VSILAN_QBASE_VSIQTABLE_ENA_SHIFT 11 -#define I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK (0x1 << I40E_VSILAN_QBASE_VSIQTABLE_ENA_SHIFT) -#define I40E_VSILAN_QTABLE(_i, _VSI) (0x00200000 + ((_i) * 2048 + (_VSI) * 4)) +#define I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK I40E_MASK(0x1, I40E_VSILAN_QBASE_VSIQTABLE_ENA_SHIFT) +#define I40E_VSILAN_QTABLE(_i, _VSI) (0x00200000 + ((_i) * 2048 + (_VSI) * 4)) /* _i=0...7, _VSI=0...383 */ /* Reset: PFR */ #define I40E_VSILAN_QTABLE_MAX_INDEX 7 #define I40E_VSILAN_QTABLE_QINDEX_0_SHIFT 0 -#define I40E_VSILAN_QTABLE_QINDEX_0_MASK (0x7FF << I40E_VSILAN_QTABLE_QINDEX_0_SHIFT) +#define I40E_VSILAN_QTABLE_QINDEX_0_MASK I40E_MASK(0x7FF, I40E_VSILAN_QTABLE_QINDEX_0_SHIFT) #define I40E_VSILAN_QTABLE_QINDEX_1_SHIFT 16 -#define I40E_VSILAN_QTABLE_QINDEX_1_MASK (0x7FF << I40E_VSILAN_QTABLE_QINDEX_1_SHIFT) -#define I40E_PRTGL_SAH 0x001E2140 +#define I40E_VSILAN_QTABLE_QINDEX_1_MASK I40E_MASK(0x7FF, I40E_VSILAN_QTABLE_QINDEX_1_SHIFT) +#define I40E_PRTGL_SAH 0x001E2140 /* Reset: GLOBR */ #define I40E_PRTGL_SAH_FC_SAH_SHIFT 0 -#define I40E_PRTGL_SAH_FC_SAH_MASK (0xFFFF << I40E_PRTGL_SAH_FC_SAH_SHIFT) +#define I40E_PRTGL_SAH_FC_SAH_MASK I40E_MASK(0xFFFF, I40E_PRTGL_SAH_FC_SAH_SHIFT) #define I40E_PRTGL_SAH_MFS_SHIFT 16 -#define I40E_PRTGL_SAH_MFS_MASK (0xFFFF << I40E_PRTGL_SAH_MFS_SHIFT) -#define I40E_PRTGL_SAL 0x001E2120 +#define I40E_PRTGL_SAH_MFS_MASK I40E_MASK(0xFFFF, I40E_PRTGL_SAH_MFS_SHIFT) +#define I40E_PRTGL_SAL 0x001E2120 /* Reset: GLOBR */ #define I40E_PRTGL_SAL_FC_SAL_SHIFT 0 -#define I40E_PRTGL_SAL_FC_SAL_MASK (0xFFFFFFFF << I40E_PRTGL_SAL_FC_SAL_SHIFT) -#define I40E_PRTMAC_HLCTLA 0x001E4760 -#define I40E_PRTMAC_HLCTLA_DROP_US_PKTS_SHIFT 0 -#define I40E_PRTMAC_HLCTLA_DROP_US_PKTS_MASK (0x1 << I40E_PRTMAC_HLCTLA_DROP_US_PKTS_SHIFT) -#define I40E_PRTMAC_HLCTLA_RX_FWRD_CTRL_SHIFT 1 -#define I40E_PRTMAC_HLCTLA_RX_FWRD_CTRL_MASK (0x1 << I40E_PRTMAC_HLCTLA_RX_FWRD_CTRL_SHIFT) -#define I40E_PRTMAC_HLCTLA_CHOP_OS_PKT_SHIFT 2 -#define I40E_PRTMAC_HLCTLA_CHOP_OS_PKT_MASK (0x1 << I40E_PRTMAC_HLCTLA_CHOP_OS_PKT_SHIFT) -#define I40E_PRTMAC_HLCTLA_TX_HYSTERESIS_SHIFT 4 -#define I40E_PRTMAC_HLCTLA_TX_HYSTERESIS_MASK (0x7 << I40E_PRTMAC_HLCTLA_TX_HYSTERESIS_SHIFT) -#define I40E_PRTMAC_HLCTLA_HYS_FLUSH_PKT_SHIFT 7 -#define I40E_PRTMAC_HLCTLA_HYS_FLUSH_PKT_MASK (0x1 << I40E_PRTMAC_HLCTLA_HYS_FLUSH_PKT_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GCP 0x001E3130 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GCP_HSEC_CTL_RX_CHECK_SA_GCP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GCP_HSEC_CTL_RX_CHECK_SA_GCP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GCP_HSEC_CTL_RX_CHECK_SA_GCP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GPP 0x001E3290 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GPP_HSEC_CTL_RX_CHECK_SA_GPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GPP_HSEC_CTL_RX_CHECK_SA_GPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GPP_HSEC_CTL_RX_CHECK_SA_GPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_PPP 0x001E3310 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_PPP_HSEC_CTL_RX_CHECK_SA_PPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_PPP_HSEC_CTL_RX_CHECK_SA_PPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_PPP_HSEC_CTL_RX_CHECK_SA_PPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GCP 0x001E3100 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GCP_HSEC_CTL_RX_CHECK_UCAST_GCP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GCP_HSEC_CTL_RX_CHECK_UCAST_GCP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GCP_HSEC_CTL_RX_CHECK_UCAST_GCP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GPP 0x001E3280 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GPP_HSEC_CTL_RX_CHECK_UCAST_GPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GPP_HSEC_CTL_RX_CHECK_UCAST_GPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GPP_HSEC_CTL_RX_CHECK_UCAST_GPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_PPP 0x001E3300 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_PPP_HSEC_CTL_RX_CHECK_UCAST_PPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_PPP_HSEC_CTL_RX_CHECK_UCAST_PPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_PPP_HSEC_CTL_RX_CHECK_UCAST_PPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP 0x001E30E0 +#define I40E_PRTGL_SAL_FC_SAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTGL_SAL_FC_SAL_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP 0x001E30E0 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP 0x001E3260 +#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_MASK I40E_MASK(0x1, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP 0x001E3260 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP 0x001E32E0 +#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_MASK I40E_MASK(0x1, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP 0x001E32E0 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL 0x001E3360 +#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_MASK I40E_MASK(0x1, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL 0x001E3360 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1 0x001E3110 +#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_MASK I40E_MASK(0x1, I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1 0x001E3110 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_MASK (0xFFFFFFFF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2 0x001E3120 +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2 0x001E3120 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE 0x001E30C0 +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE 0x001E30C0 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_MASK (0x1FF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1 0x001E3140 +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_MASK I40E_MASK(0x1FF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1 0x001E3140 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_MASK (0xFFFFFFFF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2 0x001E3150 +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2 0x001E3150 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_ENABLE 0x001E3000 -#define I40E_PRTMAC_HSEC_CTL_TX_ENABLE_HSEC_CTL_TX_ENABLE_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_ENABLE_HSEC_CTL_TX_ENABLE_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_TX_ENABLE_HSEC_CTL_TX_ENABLE_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE 0x001E30D0 +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE 0x001E30D0 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_MASK (0x1FF << I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA(_i) (0x001E3370 + ((_i) * 16)) +#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_MASK I40E_MASK(0x1FF, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA(_i) (0x001E3370 + ((_i) * 16)) /* _i=0...8 */ /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_MAX_INDEX 8 #define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(_i) (0x001E3400 + ((_i) * 16)) +#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(_i) (0x001E3400 + ((_i) * 16)) /* _i=0...8 */ /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MAX_INDEX 8 #define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1 0x001E34B0 +#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1 0x001E34B0 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_MASK (0xFFFFFFFF << I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2 0x001E34C0 +#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2 0x001E34C0 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_SHIFT) -#define I40E_PRTMAC_HSECTL1 0x001E3560 -#define I40E_PRTMAC_HSECTL1_DROP_US_PKTS_SHIFT 0 -#define I40E_PRTMAC_HSECTL1_DROP_US_PKTS_MASK (0x1 << I40E_PRTMAC_HSECTL1_DROP_US_PKTS_SHIFT) -#define I40E_PRTMAC_HSECTL1_PAD_US_PKT_SHIFT 3 -#define I40E_PRTMAC_HSECTL1_PAD_US_PKT_MASK (0x1 << I40E_PRTMAC_HSECTL1_PAD_US_PKT_SHIFT) -#define I40E_PRTMAC_HSECTL1_TX_HYSTERESIS_SHIFT 4 -#define I40E_PRTMAC_HSECTL1_TX_HYSTERESIS_MASK (0x7 << I40E_PRTMAC_HSECTL1_TX_HYSTERESIS_SHIFT) -#define I40E_PRTMAC_HSECTL1_HYS_FLUSH_PKT_SHIFT 7 -#define I40E_PRTMAC_HSECTL1_HYS_FLUSH_PKT_MASK (0x1 << I40E_PRTMAC_HSECTL1_HYS_FLUSH_PKT_SHIFT) -#define I40E_PRTMAC_HSECTL1_EN_SFD_CHECK_SHIFT 30 -#define I40E_PRTMAC_HSECTL1_EN_SFD_CHECK_MASK (0x1 << I40E_PRTMAC_HSECTL1_EN_SFD_CHECK_SHIFT) -#define I40E_PRTMAC_HSECTL1_EN_PREAMBLE_CHECK_SHIFT 31 -#define I40E_PRTMAC_HSECTL1_EN_PREAMBLE_CHECK_MASK (0x1 << I40E_PRTMAC_HSECTL1_EN_PREAMBLE_CHECK_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_A 0x0008C480 +#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A 0x0008C480 /* Reset: GLOBR */ #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_SHIFT 0 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_SHIFT 2 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_SHIFT 4 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_SHIFT 6 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_SHIFT 8 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_SHIFT 10 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_SHIFT 12 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_SHIFT 14 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_B 0x0008C484 +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B 0x0008C484 /* Reset: GLOBR */ #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_SHIFT 0 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_SHIFT 2 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_SHIFT 4 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_SHIFT 6 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_SHIFT 8 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_SHIFT 10 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_SHIFT 12 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_SHIFT 14 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_SHIFT) -#define I40E_GL_MNG_FWSM 0x000B6134 -#define I40E_GL_MNG_FWSM_FW_MODES_SHIFT 1 -#define I40E_GL_MNG_FWSM_FW_MODES_MASK (0x7 << I40E_GL_MNG_FWSM_FW_MODES_SHIFT) -#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT 6 -#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_MASK (0x1 << I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_SHIFT) +#define I40E_GL_FWRESETCNT 0x00083100 /* Reset: POR */ +#define I40E_GL_FWRESETCNT_FWRESETCNT_SHIFT 0 +#define I40E_GL_FWRESETCNT_FWRESETCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FWRESETCNT_FWRESETCNT_SHIFT) +#define I40E_GL_MNG_FWSM 0x000B6134 /* Reset: POR */ +#define I40E_GL_MNG_FWSM_FW_MODES_SHIFT 0 +#define I40E_GL_MNG_FWSM_FW_MODES_MASK I40E_MASK(0x3, I40E_GL_MNG_FWSM_FW_MODES_SHIFT) +#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT 10 +#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT) #define I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_SHIFT 11 -#define I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_MASK (0xF << I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_SHIFT) +#define I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_MASK I40E_MASK(0xF, I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_SHIFT) #define I40E_GL_MNG_FWSM_FW_STATUS_VALID_SHIFT 15 -#define I40E_GL_MNG_FWSM_FW_STATUS_VALID_MASK (0x1 << I40E_GL_MNG_FWSM_FW_STATUS_VALID_SHIFT) +#define I40E_GL_MNG_FWSM_FW_STATUS_VALID_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_FW_STATUS_VALID_SHIFT) #define I40E_GL_MNG_FWSM_RESET_CNT_SHIFT 16 -#define I40E_GL_MNG_FWSM_RESET_CNT_MASK (0x7 << I40E_GL_MNG_FWSM_RESET_CNT_SHIFT) +#define I40E_GL_MNG_FWSM_RESET_CNT_MASK I40E_MASK(0x7, I40E_GL_MNG_FWSM_RESET_CNT_SHIFT) #define I40E_GL_MNG_FWSM_EXT_ERR_IND_SHIFT 19 -#define I40E_GL_MNG_FWSM_EXT_ERR_IND_MASK (0x3F << I40E_GL_MNG_FWSM_EXT_ERR_IND_SHIFT) -#define I40E_GL_MNG_FWSM_RSVD_SHIFT 25 -#define I40E_GL_MNG_FWSM_RSVD_MASK (0x1 << I40E_GL_MNG_FWSM_RSVD_SHIFT) +#define I40E_GL_MNG_FWSM_EXT_ERR_IND_MASK I40E_MASK(0x3F, I40E_GL_MNG_FWSM_EXT_ERR_IND_SHIFT) #define I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_SHIFT 26 -#define I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_SHIFT) +#define I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_SHIFT) #define I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_SHIFT 27 -#define I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_SHIFT) +#define I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_SHIFT) #define I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_SHIFT 28 -#define I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_SHIFT) +#define I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_SHIFT) #define I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_SHIFT 29 -#define I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_SHIFT) -#define I40E_GL_MNG_HWARB_CTRL 0x000B6130 +#define I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_SHIFT) +#define I40E_GL_MNG_HWARB_CTRL 0x000B6130 /* Reset: POR */ #define I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_SHIFT 0 -#define I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_MASK (0x1 << I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_SHIFT) -#define I40E_PRT_MNG_FTFT_DATA(_i) (0x000852A0 + ((_i) * 32)) /* _i=0...31 */ +#define I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_MASK I40E_MASK(0x1, I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_SHIFT) +#define I40E_PRT_MNG_FTFT_DATA(_i) (0x000852A0 + ((_i) * 32)) /* _i=0...31 */ /* Reset: POR */ #define I40E_PRT_MNG_FTFT_DATA_MAX_INDEX 31 #define I40E_PRT_MNG_FTFT_DATA_DWORD_SHIFT 0 -#define I40E_PRT_MNG_FTFT_DATA_DWORD_MASK (0xFFFFFFFF << I40E_PRT_MNG_FTFT_DATA_DWORD_SHIFT) -#define I40E_PRT_MNG_FTFT_LENGTH 0x00085260 +#define I40E_PRT_MNG_FTFT_DATA_DWORD_MASK I40E_MASK(0xFFFFFFFF, I40E_PRT_MNG_FTFT_DATA_DWORD_SHIFT) +#define I40E_PRT_MNG_FTFT_LENGTH 0x00085260 /* Reset: POR */ #define I40E_PRT_MNG_FTFT_LENGTH_LENGTH_SHIFT 0 -#define I40E_PRT_MNG_FTFT_LENGTH_LENGTH_MASK (0xFF << I40E_PRT_MNG_FTFT_LENGTH_LENGTH_SHIFT) -#define I40E_PRT_MNG_FTFT_MASK(_i) (0x00085160 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRT_MNG_FTFT_LENGTH_LENGTH_MASK I40E_MASK(0xFF, I40E_PRT_MNG_FTFT_LENGTH_LENGTH_SHIFT) +#define I40E_PRT_MNG_FTFT_MASK(_i) (0x00085160 + ((_i) * 32)) /* _i=0...7 */ /* Reset: POR */ #define I40E_PRT_MNG_FTFT_MASK_MAX_INDEX 7 #define I40E_PRT_MNG_FTFT_MASK_MASK_SHIFT 0 -#define I40E_PRT_MNG_FTFT_MASK_MASK_MASK (0xFFFF << I40E_PRT_MNG_FTFT_MASK_MASK_SHIFT) -#define I40E_PRT_MNG_MANC 0x00256A20 +#define I40E_PRT_MNG_FTFT_MASK_MASK_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_FTFT_MASK_MASK_SHIFT) +#define I40E_PRT_MNG_MANC 0x00256A20 /* Reset: POR */ #define I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_SHIFT 0 -#define I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_MASK (0x1 << I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_SHIFT) +#define I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_SHIFT) #define I40E_PRT_MNG_MANC_NCSI_DISCARD_SHIFT 1 -#define I40E_PRT_MNG_MANC_NCSI_DISCARD_MASK (0x1 << I40E_PRT_MNG_MANC_NCSI_DISCARD_SHIFT) +#define I40E_PRT_MNG_MANC_NCSI_DISCARD_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_NCSI_DISCARD_SHIFT) #define I40E_PRT_MNG_MANC_RCV_TCO_EN_SHIFT 17 -#define I40E_PRT_MNG_MANC_RCV_TCO_EN_MASK (0x1 << I40E_PRT_MNG_MANC_RCV_TCO_EN_SHIFT) +#define I40E_PRT_MNG_MANC_RCV_TCO_EN_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_RCV_TCO_EN_SHIFT) #define I40E_PRT_MNG_MANC_RCV_ALL_SHIFT 19 -#define I40E_PRT_MNG_MANC_RCV_ALL_MASK (0x1 << I40E_PRT_MNG_MANC_RCV_ALL_SHIFT) +#define I40E_PRT_MNG_MANC_RCV_ALL_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_RCV_ALL_SHIFT) #define I40E_PRT_MNG_MANC_FIXED_NET_TYPE_SHIFT 25 -#define I40E_PRT_MNG_MANC_FIXED_NET_TYPE_MASK (0x1 << I40E_PRT_MNG_MANC_FIXED_NET_TYPE_SHIFT) +#define I40E_PRT_MNG_MANC_FIXED_NET_TYPE_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_FIXED_NET_TYPE_SHIFT) #define I40E_PRT_MNG_MANC_NET_TYPE_SHIFT 26 -#define I40E_PRT_MNG_MANC_NET_TYPE_MASK (0x1 << I40E_PRT_MNG_MANC_NET_TYPE_SHIFT) +#define I40E_PRT_MNG_MANC_NET_TYPE_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_NET_TYPE_SHIFT) #define I40E_PRT_MNG_MANC_EN_BMC2OS_SHIFT 28 -#define I40E_PRT_MNG_MANC_EN_BMC2OS_MASK (0x1 << I40E_PRT_MNG_MANC_EN_BMC2OS_SHIFT) +#define I40E_PRT_MNG_MANC_EN_BMC2OS_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_EN_BMC2OS_SHIFT) #define I40E_PRT_MNG_MANC_EN_BMC2NET_SHIFT 29 -#define I40E_PRT_MNG_MANC_EN_BMC2NET_MASK (0x1 << I40E_PRT_MNG_MANC_EN_BMC2NET_SHIFT) -#define I40E_PRT_MNG_MAVTV(_i) (0x00255900 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRT_MNG_MANC_EN_BMC2NET_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_EN_BMC2NET_SHIFT) +#define I40E_PRT_MNG_MAVTV(_i) (0x00255900 + ((_i) * 32)) /* _i=0...7 */ /* Reset: POR */ #define I40E_PRT_MNG_MAVTV_MAX_INDEX 7 #define I40E_PRT_MNG_MAVTV_VID_SHIFT 0 -#define I40E_PRT_MNG_MAVTV_VID_MASK (0xFFF << I40E_PRT_MNG_MAVTV_VID_SHIFT) -#define I40E_PRT_MNG_MDEF(_i) (0x00255D00 + ((_i) * 32)) +#define I40E_PRT_MNG_MAVTV_VID_MASK I40E_MASK(0xFFF, I40E_PRT_MNG_MAVTV_VID_SHIFT) +#define I40E_PRT_MNG_MDEF(_i) (0x00255D00 + ((_i) * 32)) /* _i=0...7 */ /* Reset: POR */ #define I40E_PRT_MNG_MDEF_MAX_INDEX 7 #define I40E_PRT_MNG_MDEF_MAC_EXACT_AND_SHIFT 0 -#define I40E_PRT_MNG_MDEF_MAC_EXACT_AND_MASK (0xF << I40E_PRT_MNG_MDEF_MAC_EXACT_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_MAC_EXACT_AND_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_MAC_EXACT_AND_SHIFT) #define I40E_PRT_MNG_MDEF_BROADCAST_AND_SHIFT 4 -#define I40E_PRT_MNG_MDEF_BROADCAST_AND_MASK (0x1 << I40E_PRT_MNG_MDEF_BROADCAST_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_BROADCAST_AND_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_BROADCAST_AND_SHIFT) #define I40E_PRT_MNG_MDEF_VLAN_AND_SHIFT 5 -#define I40E_PRT_MNG_MDEF_VLAN_AND_MASK (0xFF << I40E_PRT_MNG_MDEF_VLAN_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_VLAN_AND_MASK I40E_MASK(0xFF, I40E_PRT_MNG_MDEF_VLAN_AND_SHIFT) #define I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_SHIFT 13 -#define I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_MASK (0xF << I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_SHIFT) #define I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_SHIFT 17 -#define I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_MASK (0xF << I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_SHIFT) #define I40E_PRT_MNG_MDEF_MAC_EXACT_OR_SHIFT 21 -#define I40E_PRT_MNG_MDEF_MAC_EXACT_OR_MASK (0xF << I40E_PRT_MNG_MDEF_MAC_EXACT_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_MAC_EXACT_OR_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_MAC_EXACT_OR_SHIFT) #define I40E_PRT_MNG_MDEF_BROADCAST_OR_SHIFT 25 -#define I40E_PRT_MNG_MDEF_BROADCAST_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_BROADCAST_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_BROADCAST_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_BROADCAST_OR_SHIFT) #define I40E_PRT_MNG_MDEF_MULTICAST_AND_SHIFT 26 -#define I40E_PRT_MNG_MDEF_MULTICAST_AND_MASK (0x1 << I40E_PRT_MNG_MDEF_MULTICAST_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_MULTICAST_AND_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_MULTICAST_AND_SHIFT) #define I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_SHIFT 27 -#define I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_SHIFT) #define I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_SHIFT 28 -#define I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_SHIFT) #define I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_SHIFT 29 -#define I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_SHIFT) #define I40E_PRT_MNG_MDEF_PORT_0X298_OR_SHIFT 30 -#define I40E_PRT_MNG_MDEF_PORT_0X298_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_PORT_0X298_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_PORT_0X298_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_PORT_0X298_OR_SHIFT) #define I40E_PRT_MNG_MDEF_PORT_0X26F_OR_SHIFT 31 -#define I40E_PRT_MNG_MDEF_PORT_0X26F_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_PORT_0X26F_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT(_i) (0x00255F00 + ((_i) * 32)) +#define I40E_PRT_MNG_MDEF_PORT_0X26F_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_PORT_0X26F_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT(_i) (0x00255F00 + ((_i) * 32)) /* _i=0...7 */ /* Reset: POR */ #define I40E_PRT_MNG_MDEF_EXT_MAX_INDEX 7 #define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_SHIFT 0 -#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_MASK (0xF << I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_SHIFT 4 -#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_MASK (0xF << I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_SHIFT 8 -#define I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_MASK (0xFFFF << I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_SHIFT 24 -#define I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_SHIFT 25 -#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_SHIFT 26 -#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_SHIFT 27 -#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_ICMP_OR_SHIFT 28 -#define I40E_PRT_MNG_MDEF_EXT_ICMP_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_ICMP_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_ICMP_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_ICMP_OR_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_MLD_SHIFT 29 -#define I40E_PRT_MNG_MDEF_EXT_MLD_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_MLD_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_MLD_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_MLD_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_SHIFT 30 -#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_SHIFT 31 -#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_SHIFT) -#define I40E_PRT_MNG_MDEFVSI(_i) (0x00256580 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_SHIFT) +#define I40E_PRT_MNG_MDEFVSI(_i) (0x00256580 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ #define I40E_PRT_MNG_MDEFVSI_MAX_INDEX 3 #define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_SHIFT 0 -#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_MASK (0xFFFF << I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_SHIFT) +#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_SHIFT) #define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_SHIFT 16 -#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_MASK (0xFFFF << I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_SHIFT) -#define I40E_PRT_MNG_METF(_i) (0x00256780 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_SHIFT) +#define I40E_PRT_MNG_METF(_i) (0x00256780 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ #define I40E_PRT_MNG_METF_MAX_INDEX 3 #define I40E_PRT_MNG_METF_ETYPE_SHIFT 0 -#define I40E_PRT_MNG_METF_ETYPE_MASK (0xFFFF << I40E_PRT_MNG_METF_ETYPE_SHIFT) +#define I40E_PRT_MNG_METF_ETYPE_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_METF_ETYPE_SHIFT) #define I40E_PRT_MNG_METF_POLARITY_SHIFT 30 -#define I40E_PRT_MNG_METF_POLARITY_MASK (0x1 << I40E_PRT_MNG_METF_POLARITY_SHIFT) -#define I40E_PRT_MNG_MFUTP(_i) (0x00254E00 + ((_i) * 32)) /* _i=0...15 */ +#define I40E_PRT_MNG_METF_POLARITY_MASK I40E_MASK(0x1, I40E_PRT_MNG_METF_POLARITY_SHIFT) +#define I40E_PRT_MNG_MFUTP(_i) (0x00254E00 + ((_i) * 32)) /* _i=0...15 */ /* Reset: POR */ #define I40E_PRT_MNG_MFUTP_MAX_INDEX 15 #define I40E_PRT_MNG_MFUTP_MFUTP_N_SHIFT 0 -#define I40E_PRT_MNG_MFUTP_MFUTP_N_MASK (0xFFFF << I40E_PRT_MNG_MFUTP_MFUTP_N_SHIFT) +#define I40E_PRT_MNG_MFUTP_MFUTP_N_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MFUTP_MFUTP_N_SHIFT) #define I40E_PRT_MNG_MFUTP_UDP_SHIFT 16 -#define I40E_PRT_MNG_MFUTP_UDP_MASK (0x1 << I40E_PRT_MNG_MFUTP_UDP_SHIFT) +#define I40E_PRT_MNG_MFUTP_UDP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MFUTP_UDP_SHIFT) #define I40E_PRT_MNG_MFUTP_TCP_SHIFT 17 -#define I40E_PRT_MNG_MFUTP_TCP_MASK (0x1 << I40E_PRT_MNG_MFUTP_TCP_SHIFT) +#define I40E_PRT_MNG_MFUTP_TCP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MFUTP_TCP_SHIFT) #define I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_SHIFT 18 -#define I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_MASK (0x1 << I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_SHIFT) -#define I40E_PRT_MNG_MIPAF4(_i) (0x00256280 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_MASK I40E_MASK(0x1, I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_SHIFT) +#define I40E_PRT_MNG_MIPAF4(_i) (0x00256280 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ #define I40E_PRT_MNG_MIPAF4_MAX_INDEX 3 #define I40E_PRT_MNG_MIPAF4_MIPAF_SHIFT 0 -#define I40E_PRT_MNG_MIPAF4_MIPAF_MASK (0xFFFFFFFF << I40E_PRT_MNG_MIPAF4_MIPAF_SHIFT) -#define I40E_PRT_MNG_MIPAF6(_i) (0x00254200 + ((_i) * 32)) /* _i=0...15 */ +#define I40E_PRT_MNG_MIPAF4_MIPAF_MASK I40E_MASK(0xFFFFFFFF, I40E_PRT_MNG_MIPAF4_MIPAF_SHIFT) +#define I40E_PRT_MNG_MIPAF6(_i) (0x00254200 + ((_i) * 32)) /* _i=0...15 */ /* Reset: POR */ #define I40E_PRT_MNG_MIPAF6_MAX_INDEX 15 #define I40E_PRT_MNG_MIPAF6_MIPAF_SHIFT 0 -#define I40E_PRT_MNG_MIPAF6_MIPAF_MASK (0xFFFFFFFF << I40E_PRT_MNG_MIPAF6_MIPAF_SHIFT) -#define I40E_PRT_MNG_MMAH(_i) (0x00256380 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRT_MNG_MIPAF6_MIPAF_MASK I40E_MASK(0xFFFFFFFF, I40E_PRT_MNG_MIPAF6_MIPAF_SHIFT) +#define I40E_PRT_MNG_MMAH(_i) (0x00256380 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ #define I40E_PRT_MNG_MMAH_MAX_INDEX 3 #define I40E_PRT_MNG_MMAH_MMAH_SHIFT 0 -#define I40E_PRT_MNG_MMAH_MMAH_MASK (0xFFFF << I40E_PRT_MNG_MMAH_MMAH_SHIFT) -#define I40E_PRT_MNG_MMAL(_i) (0x00256480 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRT_MNG_MMAH_MMAH_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MMAH_MMAH_SHIFT) +#define I40E_PRT_MNG_MMAL(_i) (0x00256480 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ #define I40E_PRT_MNG_MMAL_MAX_INDEX 3 #define I40E_PRT_MNG_MMAL_MMAL_SHIFT 0 -#define I40E_PRT_MNG_MMAL_MMAL_MASK (0xFFFFFFFF << I40E_PRT_MNG_MMAL_MMAL_SHIFT) -#define I40E_PRT_MNG_MNGONLY 0x00256A60 +#define I40E_PRT_MNG_MMAL_MMAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PRT_MNG_MMAL_MMAL_SHIFT) +#define I40E_PRT_MNG_MNGONLY 0x00256A60 /* Reset: POR */ #define I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_SHIFT 0 -#define I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_MASK (0xFF << I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_SHIFT) -#define I40E_PRT_MNG_MSFM 0x00256AA0 +#define I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_MASK I40E_MASK(0xFF, I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_SHIFT) +#define I40E_PRT_MNG_MSFM 0x00256AA0 /* Reset: POR */ #define I40E_PRT_MNG_MSFM_PORT_26F_UDP_SHIFT 0 -#define I40E_PRT_MNG_MSFM_PORT_26F_UDP_MASK (0x1 << I40E_PRT_MNG_MSFM_PORT_26F_UDP_SHIFT) +#define I40E_PRT_MNG_MSFM_PORT_26F_UDP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_PORT_26F_UDP_SHIFT) #define I40E_PRT_MNG_MSFM_PORT_26F_TCP_SHIFT 1 -#define I40E_PRT_MNG_MSFM_PORT_26F_TCP_MASK (0x1 << I40E_PRT_MNG_MSFM_PORT_26F_TCP_SHIFT) +#define I40E_PRT_MNG_MSFM_PORT_26F_TCP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_PORT_26F_TCP_SHIFT) #define I40E_PRT_MNG_MSFM_PORT_298_UDP_SHIFT 2 -#define I40E_PRT_MNG_MSFM_PORT_298_UDP_MASK (0x1 << I40E_PRT_MNG_MSFM_PORT_298_UDP_SHIFT) +#define I40E_PRT_MNG_MSFM_PORT_298_UDP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_PORT_298_UDP_SHIFT) #define I40E_PRT_MNG_MSFM_PORT_298_TCP_SHIFT 3 -#define I40E_PRT_MNG_MSFM_PORT_298_TCP_MASK (0x1 << I40E_PRT_MNG_MSFM_PORT_298_TCP_SHIFT) +#define I40E_PRT_MNG_MSFM_PORT_298_TCP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_PORT_298_TCP_SHIFT) #define I40E_PRT_MNG_MSFM_IPV6_0_MASK_SHIFT 4 -#define I40E_PRT_MNG_MSFM_IPV6_0_MASK_MASK (0x1 << I40E_PRT_MNG_MSFM_IPV6_0_MASK_SHIFT) +#define I40E_PRT_MNG_MSFM_IPV6_0_MASK_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_IPV6_0_MASK_SHIFT) #define I40E_PRT_MNG_MSFM_IPV6_1_MASK_SHIFT 5 -#define I40E_PRT_MNG_MSFM_IPV6_1_MASK_MASK (0x1 << I40E_PRT_MNG_MSFM_IPV6_1_MASK_SHIFT) +#define I40E_PRT_MNG_MSFM_IPV6_1_MASK_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_IPV6_1_MASK_SHIFT) #define I40E_PRT_MNG_MSFM_IPV6_2_MASK_SHIFT 6 -#define I40E_PRT_MNG_MSFM_IPV6_2_MASK_MASK (0x1 << I40E_PRT_MNG_MSFM_IPV6_2_MASK_SHIFT) +#define I40E_PRT_MNG_MSFM_IPV6_2_MASK_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_IPV6_2_MASK_SHIFT) #define I40E_PRT_MNG_MSFM_IPV6_3_MASK_SHIFT 7 -#define I40E_PRT_MNG_MSFM_IPV6_3_MASK_MASK (0x1 << I40E_PRT_MNG_MSFM_IPV6_3_MASK_SHIFT) -#define I40E_MSIX_PBA(_i) (0x00004900 + ((_i) * 4)) /* _i=0...5 */ +#define I40E_PRT_MNG_MSFM_IPV6_3_MASK_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_IPV6_3_MASK_SHIFT) +#define I40E_MSIX_PBA(_i) (0x00001000 + ((_i) * 4)) /* _i=0...5 */ /* Reset: FLR */ #define I40E_MSIX_PBA_MAX_INDEX 5 #define I40E_MSIX_PBA_PENBIT_SHIFT 0 -#define I40E_MSIX_PBA_PENBIT_MASK (0xFFFFFFFF << I40E_MSIX_PBA_PENBIT_SHIFT) -#define I40E_MSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...128 */ +#define I40E_MSIX_PBA_PENBIT_MASK I40E_MASK(0xFFFFFFFF, I40E_MSIX_PBA_PENBIT_SHIFT) +#define I40E_MSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...128 */ /* Reset: FLR */ #define I40E_MSIX_TADD_MAX_INDEX 128 #define I40E_MSIX_TADD_MSIXTADD10_SHIFT 0 -#define I40E_MSIX_TADD_MSIXTADD10_MASK (0x3 << I40E_MSIX_TADD_MSIXTADD10_SHIFT) +#define I40E_MSIX_TADD_MSIXTADD10_MASK I40E_MASK(0x3, I40E_MSIX_TADD_MSIXTADD10_SHIFT) #define I40E_MSIX_TADD_MSIXTADD_SHIFT 2 -#define I40E_MSIX_TADD_MSIXTADD_MASK (0x3FFFFFFF << I40E_MSIX_TADD_MSIXTADD_SHIFT) -#define I40E_MSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...128 */ +#define I40E_MSIX_TADD_MSIXTADD_MASK I40E_MASK(0x3FFFFFFF, I40E_MSIX_TADD_MSIXTADD_SHIFT) +#define I40E_MSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...128 */ /* Reset: FLR */ #define I40E_MSIX_TMSG_MAX_INDEX 128 #define I40E_MSIX_TMSG_MSIXTMSG_SHIFT 0 -#define I40E_MSIX_TMSG_MSIXTMSG_MASK (0xFFFFFFFF << I40E_MSIX_TMSG_MSIXTMSG_SHIFT) -#define I40E_MSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...128 */ +#define I40E_MSIX_TMSG_MSIXTMSG_MASK I40E_MASK(0xFFFFFFFF, I40E_MSIX_TMSG_MSIXTMSG_SHIFT) +#define I40E_MSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...128 */ /* Reset: FLR */ #define I40E_MSIX_TUADD_MAX_INDEX 128 #define I40E_MSIX_TUADD_MSIXTUADD_SHIFT 0 -#define I40E_MSIX_TUADD_MSIXTUADD_MASK (0xFFFFFFFF << I40E_MSIX_TUADD_MSIXTUADD_SHIFT) -#define I40E_MSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...128 */ +#define I40E_MSIX_TUADD_MSIXTUADD_MASK I40E_MASK(0xFFFFFFFF, I40E_MSIX_TUADD_MSIXTUADD_SHIFT) +#define I40E_MSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...128 */ /* Reset: FLR */ #define I40E_MSIX_TVCTRL_MAX_INDEX 128 #define I40E_MSIX_TVCTRL_MASK_SHIFT 0 -#define I40E_MSIX_TVCTRL_MASK_MASK (0x1 << I40E_MSIX_TVCTRL_MASK_SHIFT) -#define I40E_VFMSIX_PBA1(_i) (0x00004944 + ((_i) * 4)) /* _i=0...19 */ +#define I40E_MSIX_TVCTRL_MASK_MASK I40E_MASK(0x1, I40E_MSIX_TVCTRL_MASK_SHIFT) +#define I40E_VFMSIX_PBA1(_i) (0x00002000 + ((_i) * 4)) /* _i=0...19 */ /* Reset: VFLR */ #define I40E_VFMSIX_PBA1_MAX_INDEX 19 #define I40E_VFMSIX_PBA1_PENBIT_SHIFT 0 -#define I40E_VFMSIX_PBA1_PENBIT_MASK (0xFFFFFFFF << I40E_VFMSIX_PBA1_PENBIT_SHIFT) -#define I40E_VFMSIX_TADD1(_i) (0x00002100 + ((_i) * 16)) /* _i=0...639 */ +#define I40E_VFMSIX_PBA1_PENBIT_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_PBA1_PENBIT_SHIFT) +#define I40E_VFMSIX_TADD1(_i) (0x00002100 + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */ #define I40E_VFMSIX_TADD1_MAX_INDEX 639 #define I40E_VFMSIX_TADD1_MSIXTADD10_SHIFT 0 -#define I40E_VFMSIX_TADD1_MSIXTADD10_MASK (0x3 << I40E_VFMSIX_TADD1_MSIXTADD10_SHIFT) +#define I40E_VFMSIX_TADD1_MSIXTADD10_MASK I40E_MASK(0x3, I40E_VFMSIX_TADD1_MSIXTADD10_SHIFT) #define I40E_VFMSIX_TADD1_MSIXTADD_SHIFT 2 -#define I40E_VFMSIX_TADD1_MSIXTADD_MASK (0x3FFFFFFF << I40E_VFMSIX_TADD1_MSIXTADD_SHIFT) -#define I40E_VFMSIX_TMSG1(_i) (0x00002108 + ((_i) * 16)) /* _i=0...639 */ +#define I40E_VFMSIX_TADD1_MSIXTADD_MASK I40E_MASK(0x3FFFFFFF, I40E_VFMSIX_TADD1_MSIXTADD_SHIFT) +#define I40E_VFMSIX_TMSG1(_i) (0x00002108 + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */ #define I40E_VFMSIX_TMSG1_MAX_INDEX 639 #define I40E_VFMSIX_TMSG1_MSIXTMSG_SHIFT 0 -#define I40E_VFMSIX_TMSG1_MSIXTMSG_MASK (0xFFFFFFFF << I40E_VFMSIX_TMSG1_MSIXTMSG_SHIFT) -#define I40E_VFMSIX_TUADD1(_i) (0x00002104 + ((_i) * 16)) /* _i=0...639 */ +#define I40E_VFMSIX_TMSG1_MSIXTMSG_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TMSG1_MSIXTMSG_SHIFT) +#define I40E_VFMSIX_TUADD1(_i) (0x00002104 + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */ #define I40E_VFMSIX_TUADD1_MAX_INDEX 639 #define I40E_VFMSIX_TUADD1_MSIXTUADD_SHIFT 0 -#define I40E_VFMSIX_TUADD1_MSIXTUADD_MASK (0xFFFFFFFF << I40E_VFMSIX_TUADD1_MSIXTUADD_SHIFT) -#define I40E_VFMSIX_TVCTRL1(_i) (0x0000210C + ((_i) * 16)) /* _i=0...639 */ +#define I40E_VFMSIX_TUADD1_MSIXTUADD_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TUADD1_MSIXTUADD_SHIFT) +#define I40E_VFMSIX_TVCTRL1(_i) (0x0000210C + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */ #define I40E_VFMSIX_TVCTRL1_MAX_INDEX 639 #define I40E_VFMSIX_TVCTRL1_MASK_SHIFT 0 -#define I40E_VFMSIX_TVCTRL1_MASK_MASK (0x1 << I40E_VFMSIX_TVCTRL1_MASK_SHIFT) -#define I40E_GLNVM_FLA 0x000B6108 +#define I40E_VFMSIX_TVCTRL1_MASK_MASK I40E_MASK(0x1, I40E_VFMSIX_TVCTRL1_MASK_SHIFT) +#define I40E_GLNVM_FLA 0x000B6108 /* Reset: POR */ #define I40E_GLNVM_FLA_FL_SCK_SHIFT 0 -#define I40E_GLNVM_FLA_FL_SCK_MASK (0x1 << I40E_GLNVM_FLA_FL_SCK_SHIFT) +#define I40E_GLNVM_FLA_FL_SCK_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_SCK_SHIFT) #define I40E_GLNVM_FLA_FL_CE_SHIFT 1 -#define I40E_GLNVM_FLA_FL_CE_MASK (0x1 << I40E_GLNVM_FLA_FL_CE_SHIFT) +#define I40E_GLNVM_FLA_FL_CE_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_CE_SHIFT) #define I40E_GLNVM_FLA_FL_SI_SHIFT 2 -#define I40E_GLNVM_FLA_FL_SI_MASK (0x1 << I40E_GLNVM_FLA_FL_SI_SHIFT) +#define I40E_GLNVM_FLA_FL_SI_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_SI_SHIFT) #define I40E_GLNVM_FLA_FL_SO_SHIFT 3 -#define I40E_GLNVM_FLA_FL_SO_MASK (0x1 << I40E_GLNVM_FLA_FL_SO_SHIFT) +#define I40E_GLNVM_FLA_FL_SO_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_SO_SHIFT) #define I40E_GLNVM_FLA_FL_REQ_SHIFT 4 -#define I40E_GLNVM_FLA_FL_REQ_MASK (0x1 << I40E_GLNVM_FLA_FL_REQ_SHIFT) +#define I40E_GLNVM_FLA_FL_REQ_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_REQ_SHIFT) #define I40E_GLNVM_FLA_FL_GNT_SHIFT 5 -#define I40E_GLNVM_FLA_FL_GNT_MASK (0x1 << I40E_GLNVM_FLA_FL_GNT_SHIFT) +#define I40E_GLNVM_FLA_FL_GNT_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_GNT_SHIFT) #define I40E_GLNVM_FLA_LOCKED_SHIFT 6 -#define I40E_GLNVM_FLA_LOCKED_MASK (0x1 << I40E_GLNVM_FLA_LOCKED_SHIFT) +#define I40E_GLNVM_FLA_LOCKED_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_LOCKED_SHIFT) #define I40E_GLNVM_FLA_FL_SADDR_SHIFT 18 -#define I40E_GLNVM_FLA_FL_SADDR_MASK (0x7FF << I40E_GLNVM_FLA_FL_SADDR_SHIFT) +#define I40E_GLNVM_FLA_FL_SADDR_MASK I40E_MASK(0x7FF, I40E_GLNVM_FLA_FL_SADDR_SHIFT) #define I40E_GLNVM_FLA_FL_BUSY_SHIFT 30 -#define I40E_GLNVM_FLA_FL_BUSY_MASK (0x1 << I40E_GLNVM_FLA_FL_BUSY_SHIFT) +#define I40E_GLNVM_FLA_FL_BUSY_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_BUSY_SHIFT) #define I40E_GLNVM_FLA_FL_DER_SHIFT 31 -#define I40E_GLNVM_FLA_FL_DER_MASK (0x1 << I40E_GLNVM_FLA_FL_DER_SHIFT) -#define I40E_GLNVM_FLASHID 0x000B6104 +#define I40E_GLNVM_FLA_FL_DER_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_DER_SHIFT) +#define I40E_GLNVM_FLASHID 0x000B6104 /* Reset: POR */ #define I40E_GLNVM_FLASHID_FLASHID_SHIFT 0 -#define I40E_GLNVM_FLASHID_FLASHID_MASK (0xFFFFFF << I40E_GLNVM_FLASHID_FLASHID_SHIFT) -#define I40E_GLNVM_GENS 0x000B6100 +#define I40E_GLNVM_FLASHID_FLASHID_MASK I40E_MASK(0xFFFFFF, I40E_GLNVM_FLASHID_FLASHID_SHIFT) +#define I40E_GLNVM_FLASHID_FLEEP_PERF_SHIFT 31 +#define I40E_GLNVM_FLASHID_FLEEP_PERF_MASK I40E_MASK(0x1, I40E_GLNVM_FLASHID_FLEEP_PERF_SHIFT) +#define I40E_GLNVM_GENS 0x000B6100 /* Reset: POR */ #define I40E_GLNVM_GENS_NVM_PRES_SHIFT 0 -#define I40E_GLNVM_GENS_NVM_PRES_MASK (0x1 << I40E_GLNVM_GENS_NVM_PRES_SHIFT) +#define I40E_GLNVM_GENS_NVM_PRES_MASK I40E_MASK(0x1, I40E_GLNVM_GENS_NVM_PRES_SHIFT) #define I40E_GLNVM_GENS_SR_SIZE_SHIFT 5 -#define I40E_GLNVM_GENS_SR_SIZE_MASK (0x7 << I40E_GLNVM_GENS_SR_SIZE_SHIFT) +#define I40E_GLNVM_GENS_SR_SIZE_MASK I40E_MASK(0x7, I40E_GLNVM_GENS_SR_SIZE_SHIFT) #define I40E_GLNVM_GENS_BANK1VAL_SHIFT 8 -#define I40E_GLNVM_GENS_BANK1VAL_MASK (0x1 << I40E_GLNVM_GENS_BANK1VAL_SHIFT) +#define I40E_GLNVM_GENS_BANK1VAL_MASK I40E_MASK(0x1, I40E_GLNVM_GENS_BANK1VAL_SHIFT) #define I40E_GLNVM_GENS_ALT_PRST_SHIFT 23 -#define I40E_GLNVM_GENS_ALT_PRST_MASK (0x1 << I40E_GLNVM_GENS_ALT_PRST_SHIFT) +#define I40E_GLNVM_GENS_ALT_PRST_MASK I40E_MASK(0x1, I40E_GLNVM_GENS_ALT_PRST_SHIFT) #define I40E_GLNVM_GENS_FL_AUTO_RD_SHIFT 25 -#define I40E_GLNVM_GENS_FL_AUTO_RD_MASK (0x1 << I40E_GLNVM_GENS_FL_AUTO_RD_SHIFT) -#define I40E_GLNVM_PROTCSR(_i) (0x000B6010 + ((_i) * 4)) /* _i=0...59 */ +#define I40E_GLNVM_GENS_FL_AUTO_RD_MASK I40E_MASK(0x1, I40E_GLNVM_GENS_FL_AUTO_RD_SHIFT) +#define I40E_GLNVM_PROTCSR(_i) (0x000B6010 + ((_i) * 4)) /* _i=0...59 */ /* Reset: POR */ #define I40E_GLNVM_PROTCSR_MAX_INDEX 59 #define I40E_GLNVM_PROTCSR_ADDR_BLOCK_SHIFT 0 -#define I40E_GLNVM_PROTCSR_ADDR_BLOCK_MASK (0xFFFFFF << I40E_GLNVM_PROTCSR_ADDR_BLOCK_SHIFT) -#define I40E_GLNVM_SRCTL 0x000B6110 +#define I40E_GLNVM_PROTCSR_ADDR_BLOCK_MASK I40E_MASK(0xFFFFFF, I40E_GLNVM_PROTCSR_ADDR_BLOCK_SHIFT) +#define I40E_GLNVM_SRCTL 0x000B6110 /* Reset: POR */ #define I40E_GLNVM_SRCTL_SRBUSY_SHIFT 0 -#define I40E_GLNVM_SRCTL_SRBUSY_MASK (0x1 << I40E_GLNVM_SRCTL_SRBUSY_SHIFT) +#define I40E_GLNVM_SRCTL_SRBUSY_MASK I40E_MASK(0x1, I40E_GLNVM_SRCTL_SRBUSY_SHIFT) #define I40E_GLNVM_SRCTL_ADDR_SHIFT 14 -#define I40E_GLNVM_SRCTL_ADDR_MASK (0x7FFF << I40E_GLNVM_SRCTL_ADDR_SHIFT) +#define I40E_GLNVM_SRCTL_ADDR_MASK I40E_MASK(0x7FFF, I40E_GLNVM_SRCTL_ADDR_SHIFT) #define I40E_GLNVM_SRCTL_WRITE_SHIFT 29 -#define I40E_GLNVM_SRCTL_WRITE_MASK (0x1 << I40E_GLNVM_SRCTL_WRITE_SHIFT) +#define I40E_GLNVM_SRCTL_WRITE_MASK I40E_MASK(0x1, I40E_GLNVM_SRCTL_WRITE_SHIFT) #define I40E_GLNVM_SRCTL_START_SHIFT 30 -#define I40E_GLNVM_SRCTL_START_MASK (0x1 << I40E_GLNVM_SRCTL_START_SHIFT) +#define I40E_GLNVM_SRCTL_START_MASK I40E_MASK(0x1, I40E_GLNVM_SRCTL_START_SHIFT) #define I40E_GLNVM_SRCTL_DONE_SHIFT 31 -#define I40E_GLNVM_SRCTL_DONE_MASK (0x1 << I40E_GLNVM_SRCTL_DONE_SHIFT) -#define I40E_GLNVM_SRDATA 0x000B6114 +#define I40E_GLNVM_SRCTL_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_SRCTL_DONE_SHIFT) +#define I40E_GLNVM_SRDATA 0x000B6114 /* Reset: POR */ #define I40E_GLNVM_SRDATA_WRDATA_SHIFT 0 -#define I40E_GLNVM_SRDATA_WRDATA_MASK (0xFFFF << I40E_GLNVM_SRDATA_WRDATA_SHIFT) +#define I40E_GLNVM_SRDATA_WRDATA_MASK I40E_MASK(0xFFFF, I40E_GLNVM_SRDATA_WRDATA_SHIFT) #define I40E_GLNVM_SRDATA_RDDATA_SHIFT 16 -#define I40E_GLNVM_SRDATA_RDDATA_MASK (0xFFFF << I40E_GLNVM_SRDATA_RDDATA_SHIFT) -#define I40E_GLNVM_ULD 0x000B6008 +#define I40E_GLNVM_SRDATA_RDDATA_MASK I40E_MASK(0xFFFF, I40E_GLNVM_SRDATA_RDDATA_SHIFT) +#define I40E_GLNVM_ULD 0x000B6008 /* Reset: POR */ #define I40E_GLNVM_ULD_CONF_PCIR_DONE_SHIFT 0 -#define I40E_GLNVM_ULD_CONF_PCIR_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_PCIR_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_PCIR_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PCIR_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_PCIRTL_DONE_SHIFT 1 -#define I40E_GLNVM_ULD_CONF_PCIRTL_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_PCIRTL_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_PCIRTL_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PCIRTL_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_LCB_DONE_SHIFT 2 -#define I40E_GLNVM_ULD_CONF_LCB_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_LCB_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_LCB_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_LCB_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_CORE_DONE_SHIFT 3 -#define I40E_GLNVM_ULD_CONF_CORE_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_CORE_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_CORE_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_CORE_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_GLOBAL_DONE_SHIFT 4 -#define I40E_GLNVM_ULD_CONF_GLOBAL_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_GLOBAL_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_GLOBAL_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_GLOBAL_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_POR_DONE_SHIFT 5 -#define I40E_GLNVM_ULD_CONF_POR_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_POR_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_POR_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_POR_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_SHIFT 6 -#define I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_SHIFT 7 -#define I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_EMP_DONE_SHIFT 8 -#define I40E_GLNVM_ULD_CONF_EMP_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_EMP_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_EMP_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_EMP_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_PCIALT_DONE_SHIFT 9 -#define I40E_GLNVM_ULD_CONF_PCIALT_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_PCIALT_DONE_SHIFT) - -#define I40E_GLPCI_BYTCTH 0x0009C484 +#define I40E_GLNVM_ULD_CONF_PCIALT_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PCIALT_DONE_SHIFT) +#define I40E_GLPCI_BYTCTH 0x0009C484 /* Reset: PCIR */ #define I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_SHIFT 0 -#define I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_MASK (0xFFFFFFFF << I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_SHIFT) -#define I40E_GLPCI_BYTCTL 0x0009C488 +#define I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_SHIFT) +#define I40E_GLPCI_BYTCTL 0x0009C488 /* Reset: PCIR */ #define I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_SHIFT 0 -#define I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_MASK (0xFFFFFFFF << I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_SHIFT) -#define I40E_GLPCI_CAPCTRL 0x000BE4A4 +#define I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_SHIFT) +#define I40E_GLPCI_CAPCTRL 0x000BE4A4 /* Reset: PCIR */ #define I40E_GLPCI_CAPCTRL_VPD_EN_SHIFT 0 -#define I40E_GLPCI_CAPCTRL_VPD_EN_MASK (0x1 << I40E_GLPCI_CAPCTRL_VPD_EN_SHIFT) -#define I40E_GLPCI_CAPSUP 0x000BE4A8 +#define I40E_GLPCI_CAPCTRL_VPD_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPCTRL_VPD_EN_SHIFT) +#define I40E_GLPCI_CAPSUP 0x000BE4A8 /* Reset: PCIR */ #define I40E_GLPCI_CAPSUP_PCIE_VER_SHIFT 0 -#define I40E_GLPCI_CAPSUP_PCIE_VER_MASK (0x1 << I40E_GLPCI_CAPSUP_PCIE_VER_SHIFT) +#define I40E_GLPCI_CAPSUP_PCIE_VER_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_PCIE_VER_SHIFT) #define I40E_GLPCI_CAPSUP_LTR_EN_SHIFT 2 -#define I40E_GLPCI_CAPSUP_LTR_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_LTR_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_LTR_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_LTR_EN_SHIFT) #define I40E_GLPCI_CAPSUP_TPH_EN_SHIFT 3 -#define I40E_GLPCI_CAPSUP_TPH_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_TPH_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_TPH_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_TPH_EN_SHIFT) #define I40E_GLPCI_CAPSUP_ARI_EN_SHIFT 4 -#define I40E_GLPCI_CAPSUP_ARI_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_ARI_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_ARI_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_ARI_EN_SHIFT) #define I40E_GLPCI_CAPSUP_IOV_EN_SHIFT 5 -#define I40E_GLPCI_CAPSUP_IOV_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_IOV_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_IOV_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_IOV_EN_SHIFT) #define I40E_GLPCI_CAPSUP_ACS_EN_SHIFT 6 -#define I40E_GLPCI_CAPSUP_ACS_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_ACS_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_ACS_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_ACS_EN_SHIFT) #define I40E_GLPCI_CAPSUP_SEC_EN_SHIFT 7 -#define I40E_GLPCI_CAPSUP_SEC_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_SEC_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_SEC_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_SEC_EN_SHIFT) #define I40E_GLPCI_CAPSUP_ECRC_GEN_EN_SHIFT 16 -#define I40E_GLPCI_CAPSUP_ECRC_GEN_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_ECRC_GEN_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_ECRC_GEN_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_ECRC_GEN_EN_SHIFT) #define I40E_GLPCI_CAPSUP_ECRC_CHK_EN_SHIFT 17 -#define I40E_GLPCI_CAPSUP_ECRC_CHK_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_ECRC_CHK_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_ECRC_CHK_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_ECRC_CHK_EN_SHIFT) #define I40E_GLPCI_CAPSUP_IDO_EN_SHIFT 18 -#define I40E_GLPCI_CAPSUP_IDO_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_IDO_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_IDO_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_IDO_EN_SHIFT) #define I40E_GLPCI_CAPSUP_MSI_MASK_SHIFT 19 -#define I40E_GLPCI_CAPSUP_MSI_MASK_MASK (0x1 << I40E_GLPCI_CAPSUP_MSI_MASK_SHIFT) +#define I40E_GLPCI_CAPSUP_MSI_MASK_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_MSI_MASK_SHIFT) #define I40E_GLPCI_CAPSUP_CSR_CONF_EN_SHIFT 20 -#define I40E_GLPCI_CAPSUP_CSR_CONF_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_CSR_CONF_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_CSR_CONF_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_CSR_CONF_EN_SHIFT) #define I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_SHIFT 30 -#define I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_MASK (0x1 << I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_SHIFT) +#define I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_SHIFT) #define I40E_GLPCI_CAPSUP_LOAD_DEV_ID_SHIFT 31 -#define I40E_GLPCI_CAPSUP_LOAD_DEV_ID_MASK (0x1 << I40E_GLPCI_CAPSUP_LOAD_DEV_ID_SHIFT) -#define I40E_GLPCI_CNF 0x000BE4C0 +#define I40E_GLPCI_CAPSUP_LOAD_DEV_ID_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_LOAD_DEV_ID_SHIFT) +#define I40E_GLPCI_CNF 0x000BE4C0 /* Reset: POR */ #define I40E_GLPCI_CNF_FLEX10_SHIFT 1 -#define I40E_GLPCI_CNF_FLEX10_MASK (0x1 << I40E_GLPCI_CNF_FLEX10_SHIFT) +#define I40E_GLPCI_CNF_FLEX10_MASK I40E_MASK(0x1, I40E_GLPCI_CNF_FLEX10_SHIFT) #define I40E_GLPCI_CNF_WAKE_PIN_EN_SHIFT 2 -#define I40E_GLPCI_CNF_WAKE_PIN_EN_MASK (0x1 << I40E_GLPCI_CNF_WAKE_PIN_EN_SHIFT) -#define I40E_GLPCI_CNF2 0x000BE494 +#define I40E_GLPCI_CNF_WAKE_PIN_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CNF_WAKE_PIN_EN_SHIFT) +#define I40E_GLPCI_CNF2 0x000BE494 /* Reset: PCIR */ #define I40E_GLPCI_CNF2_RO_DIS_SHIFT 0 -#define I40E_GLPCI_CNF2_RO_DIS_MASK (0x1 << I40E_GLPCI_CNF2_RO_DIS_SHIFT) +#define I40E_GLPCI_CNF2_RO_DIS_MASK I40E_MASK(0x1, I40E_GLPCI_CNF2_RO_DIS_SHIFT) #define I40E_GLPCI_CNF2_CACHELINE_SIZE_SHIFT 1 -#define I40E_GLPCI_CNF2_CACHELINE_SIZE_MASK (0x1 << I40E_GLPCI_CNF2_CACHELINE_SIZE_SHIFT) +#define I40E_GLPCI_CNF2_CACHELINE_SIZE_MASK I40E_MASK(0x1, I40E_GLPCI_CNF2_CACHELINE_SIZE_SHIFT) #define I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT 2 -#define I40E_GLPCI_CNF2_MSI_X_PF_N_MASK (0x7FF << I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT) +#define I40E_GLPCI_CNF2_MSI_X_PF_N_MASK I40E_MASK(0x7FF, I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT) #define I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT 13 -#define I40E_GLPCI_CNF2_MSI_X_VF_N_MASK (0x7FF << I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT) -#define I40E_GLPCI_DREVID 0x0009C480 +#define I40E_GLPCI_CNF2_MSI_X_VF_N_MASK I40E_MASK(0x7FF, I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT) +#define I40E_GLPCI_DREVID 0x0009C480 /* Reset: PCIR */ #define I40E_GLPCI_DREVID_DEFAULT_REVID_SHIFT 0 -#define I40E_GLPCI_DREVID_DEFAULT_REVID_MASK (0xFF << I40E_GLPCI_DREVID_DEFAULT_REVID_SHIFT) -#define I40E_GLPCI_GSCL_1 0x0009C48C +#define I40E_GLPCI_DREVID_DEFAULT_REVID_MASK I40E_MASK(0xFF, I40E_GLPCI_DREVID_DEFAULT_REVID_SHIFT) +#define I40E_GLPCI_GSCL_1 0x0009C48C /* Reset: PCIR */ #define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_SHIFT 0 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_SHIFT 1 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_SHIFT 2 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_SHIFT 3 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_SHIFT) #define I40E_GLPCI_GSCL_1_LBC_ENABLE_0_SHIFT 4 -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_0_MASK (0x1 << I40E_GLPCI_GSCL_1_LBC_ENABLE_0_SHIFT) +#define I40E_GLPCI_GSCL_1_LBC_ENABLE_0_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_LBC_ENABLE_0_SHIFT) #define I40E_GLPCI_GSCL_1_LBC_ENABLE_1_SHIFT 5 -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_1_MASK (0x1 << I40E_GLPCI_GSCL_1_LBC_ENABLE_1_SHIFT) +#define I40E_GLPCI_GSCL_1_LBC_ENABLE_1_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_LBC_ENABLE_1_SHIFT) #define I40E_GLPCI_GSCL_1_LBC_ENABLE_2_SHIFT 6 -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_2_MASK (0x1 << I40E_GLPCI_GSCL_1_LBC_ENABLE_2_SHIFT) +#define I40E_GLPCI_GSCL_1_LBC_ENABLE_2_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_LBC_ENABLE_2_SHIFT) #define I40E_GLPCI_GSCL_1_LBC_ENABLE_3_SHIFT 7 -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_3_MASK (0x1 << I40E_GLPCI_GSCL_1_LBC_ENABLE_3_SHIFT) +#define I40E_GLPCI_GSCL_1_LBC_ENABLE_3_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_LBC_ENABLE_3_SHIFT) #define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_SHIFT 8 -#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_MASK (0x1 << I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_SHIFT) +#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_SHIFT) #define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_SHIFT 9 -#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_MASK (0x1F << I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_SHIFT) +#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_MASK I40E_MASK(0x1F, I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_SHIFT) #define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_SHIFT 14 -#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_MASK (0x1 << I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_SHIFT) +#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_SHIFT) #define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_SHIFT 15 -#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_MASK (0x1F << I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_SHIFT) +#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_MASK I40E_MASK(0x1F, I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_SHIFT 28 -#define I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_SHIFT 29 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_SHIFT 30 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_COUNT_START_SHIFT 31 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_START_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_START_SHIFT) -#define I40E_GLPCI_GSCL_2 0x0009C490 +#define I40E_GLPCI_GSCL_1_GIO_COUNT_START_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_START_SHIFT) +#define I40E_GLPCI_GSCL_2 0x0009C490 /* Reset: PCIR */ #define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_SHIFT 0 -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_MASK (0xFF << I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_SHIFT) +#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_MASK I40E_MASK(0xFF, I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_SHIFT) #define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_SHIFT 8 -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_MASK (0xFF << I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_SHIFT) +#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_MASK I40E_MASK(0xFF, I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_SHIFT) #define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_SHIFT 16 -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_MASK (0xFF << I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_SHIFT) +#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_MASK I40E_MASK(0xFF, I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_SHIFT) #define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_SHIFT 24 -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_MASK (0xFF << I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_SHIFT) -#define I40E_GLPCI_GSCL_5_8(_i) (0x0009C494 + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_MASK I40E_MASK(0xFF, I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_SHIFT) +#define I40E_GLPCI_GSCL_5_8(_i) (0x0009C494 + ((_i) * 4)) /* _i=0...3 */ /* Reset: PCIR */ #define I40E_GLPCI_GSCL_5_8_MAX_INDEX 3 #define I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_SHIFT 0 -#define I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_MASK (0xFFFF << I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_SHIFT) +#define I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_MASK I40E_MASK(0xFFFF, I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_SHIFT) #define I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_SHIFT 16 -#define I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_MASK (0xFFFF << I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_SHIFT) -#define I40E_GLPCI_GSCN_0_3(_i) (0x0009C4A4 + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_MASK I40E_MASK(0xFFFF, I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_SHIFT) +#define I40E_GLPCI_GSCN_0_3(_i) (0x0009C4A4 + ((_i) * 4)) /* _i=0...3 */ /* Reset: PCIR */ #define I40E_GLPCI_GSCN_0_3_MAX_INDEX 3 #define I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_SHIFT 0 -#define I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_MASK (0xFFFFFFFF << I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_SHIFT) -#define I40E_GLPCI_LATCT 0x0009C4B4 +#define I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_SHIFT) +#define I40E_GLPCI_LATCT 0x0009C4B4 /* Reset: PCIR */ #define I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_SHIFT 0 -#define I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_MASK (0xFFFFFFFF << I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_SHIFT) -#define I40E_GLPCI_LBARCTRL 0x000BE484 +#define I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_SHIFT) +#define I40E_GLPCI_LBARCTRL 0x000BE484 /* Reset: POR */ #define I40E_GLPCI_LBARCTRL_PREFBAR_SHIFT 0 -#define I40E_GLPCI_LBARCTRL_PREFBAR_MASK (0x1 << I40E_GLPCI_LBARCTRL_PREFBAR_SHIFT) +#define I40E_GLPCI_LBARCTRL_PREFBAR_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_PREFBAR_SHIFT) #define I40E_GLPCI_LBARCTRL_BAR32_SHIFT 1 -#define I40E_GLPCI_LBARCTRL_BAR32_MASK (0x1 << I40E_GLPCI_LBARCTRL_BAR32_SHIFT) +#define I40E_GLPCI_LBARCTRL_BAR32_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_BAR32_SHIFT) #define I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_SHIFT 3 -#define I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_MASK (0x1 << I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_SHIFT) -#define I40E_GLPCI_LBARCTRL_PE_DB_SIZE_SHIFT 4 -#define I40E_GLPCI_LBARCTRL_PE_DB_SIZE_MASK (0x3 << I40E_GLPCI_LBARCTRL_PE_DB_SIZE_SHIFT) +#define I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_SHIFT) +#define I40E_GLPCI_LBARCTRL_RSVD_4_SHIFT 4 +#define I40E_GLPCI_LBARCTRL_RSVD_4_MASK I40E_MASK(0x3, I40E_GLPCI_LBARCTRL_RSVD_4_SHIFT) #define I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT 6 -#define I40E_GLPCI_LBARCTRL_FL_SIZE_MASK (0x7 << I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT) -#define I40E_GLPCI_LBARCTRL_VF_PE_DB_SIZE_SHIFT 10 -#define I40E_GLPCI_LBARCTRL_VF_PE_DB_SIZE_MASK (0x1 << I40E_GLPCI_LBARCTRL_VF_PE_DB_SIZE_SHIFT) +#define I40E_GLPCI_LBARCTRL_FL_SIZE_MASK I40E_MASK(0x7, I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT) +#define I40E_GLPCI_LBARCTRL_RSVD_10_SHIFT 10 +#define I40E_GLPCI_LBARCTRL_RSVD_10_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_RSVD_10_SHIFT) #define I40E_GLPCI_LBARCTRL_EXROM_SIZE_SHIFT 11 -#define I40E_GLPCI_LBARCTRL_EXROM_SIZE_MASK (0x7 << I40E_GLPCI_LBARCTRL_EXROM_SIZE_SHIFT) -#define I40E_GLPCI_LINKCAP 0x000BE4AC +#define I40E_GLPCI_LBARCTRL_EXROM_SIZE_MASK I40E_MASK(0x7, I40E_GLPCI_LBARCTRL_EXROM_SIZE_SHIFT) +#define I40E_GLPCI_LINKCAP 0x000BE4AC /* Reset: PCIR */ #define I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_SHIFT 0 -#define I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_MASK (0x3F << I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_SHIFT) +#define I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_MASK I40E_MASK(0x3F, I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_SHIFT) #define I40E_GLPCI_LINKCAP_MAX_PAYLOAD_SHIFT 6 -#define I40E_GLPCI_LINKCAP_MAX_PAYLOAD_MASK (0x7 << I40E_GLPCI_LINKCAP_MAX_PAYLOAD_SHIFT) +#define I40E_GLPCI_LINKCAP_MAX_PAYLOAD_MASK I40E_MASK(0x7, I40E_GLPCI_LINKCAP_MAX_PAYLOAD_SHIFT) #define I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_SHIFT 9 -#define I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_MASK (0xF << I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_SHIFT) -#define I40E_GLPCI_PCIERR 0x000BE4FC +#define I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_MASK I40E_MASK(0xF, I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_SHIFT) +#define I40E_GLPCI_PCIERR 0x000BE4FC /* Reset: PCIR */ #define I40E_GLPCI_PCIERR_PCIE_ERR_REP_SHIFT 0 -#define I40E_GLPCI_PCIERR_PCIE_ERR_REP_MASK (0xFFFFFFFF << I40E_GLPCI_PCIERR_PCIE_ERR_REP_SHIFT) -#define I40E_GLPCI_PCITEST2 0x000BE4BC -#define I40E_GLPCI_PCITEST2_IOV_TEST_MODE_SHIFT 0 -#define I40E_GLPCI_PCITEST2_IOV_TEST_MODE_MASK (0x1 << I40E_GLPCI_PCITEST2_IOV_TEST_MODE_SHIFT) -#define I40E_GLPCI_PCITEST2_TAG_ALLOC_SHIFT 1 -#define I40E_GLPCI_PCITEST2_TAG_ALLOC_MASK (0x1 << I40E_GLPCI_PCITEST2_TAG_ALLOC_SHIFT) - -#define I40E_GLPCI_PKTCT 0x0009C4BC +#define I40E_GLPCI_PCIERR_PCIE_ERR_REP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_PCIERR_PCIE_ERR_REP_SHIFT) +#define I40E_GLPCI_PKTCT 0x0009C4BC /* Reset: PCIR */ #define I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_SHIFT 0 -#define I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_MASK (0xFFFFFFFF << I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_SHIFT) -#define I40E_GLPCI_PMSUP 0x000BE4B0 +#define I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_SHIFT) +#define I40E_GLPCI_PM_MUX_NPQ 0x0009C4F4 /* Reset: PCIR */ +#define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT 0 +#define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_MASK I40E_MASK(0x7, I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT) +#define I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_SHIFT 16 +#define I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_MASK I40E_MASK(0x1F, I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_SHIFT) +#define I40E_GLPCI_PM_MUX_PFB 0x0009C4F0 /* Reset: PCIR */ +#define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT 0 +#define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_MASK I40E_MASK(0x1F, I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT) +#define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT 16 +#define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_MASK I40E_MASK(0x7, I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT) +#define I40E_GLPCI_PMSUP 0x000BE4B0 /* Reset: PCIR */ #define I40E_GLPCI_PMSUP_ASPM_SUP_SHIFT 0 -#define I40E_GLPCI_PMSUP_ASPM_SUP_MASK (0x3 << I40E_GLPCI_PMSUP_ASPM_SUP_SHIFT) +#define I40E_GLPCI_PMSUP_ASPM_SUP_MASK I40E_MASK(0x3, I40E_GLPCI_PMSUP_ASPM_SUP_SHIFT) #define I40E_GLPCI_PMSUP_L0S_EXIT_LAT_SHIFT 2 -#define I40E_GLPCI_PMSUP_L0S_EXIT_LAT_MASK (0x7 << I40E_GLPCI_PMSUP_L0S_EXIT_LAT_SHIFT) +#define I40E_GLPCI_PMSUP_L0S_EXIT_LAT_MASK I40E_MASK(0x7, I40E_GLPCI_PMSUP_L0S_EXIT_LAT_SHIFT) #define I40E_GLPCI_PMSUP_L1_EXIT_LAT_SHIFT 5 -#define I40E_GLPCI_PMSUP_L1_EXIT_LAT_MASK (0x7 << I40E_GLPCI_PMSUP_L1_EXIT_LAT_SHIFT) +#define I40E_GLPCI_PMSUP_L1_EXIT_LAT_MASK I40E_MASK(0x7, I40E_GLPCI_PMSUP_L1_EXIT_LAT_SHIFT) #define I40E_GLPCI_PMSUP_L0S_ACC_LAT_SHIFT 8 -#define I40E_GLPCI_PMSUP_L0S_ACC_LAT_MASK (0x7 << I40E_GLPCI_PMSUP_L0S_ACC_LAT_SHIFT) +#define I40E_GLPCI_PMSUP_L0S_ACC_LAT_MASK I40E_MASK(0x7, I40E_GLPCI_PMSUP_L0S_ACC_LAT_SHIFT) #define I40E_GLPCI_PMSUP_L1_ACC_LAT_SHIFT 11 -#define I40E_GLPCI_PMSUP_L1_ACC_LAT_MASK (0x7 << I40E_GLPCI_PMSUP_L1_ACC_LAT_SHIFT) +#define I40E_GLPCI_PMSUP_L1_ACC_LAT_MASK I40E_MASK(0x7, I40E_GLPCI_PMSUP_L1_ACC_LAT_SHIFT) #define I40E_GLPCI_PMSUP_SLOT_CLK_SHIFT 14 -#define I40E_GLPCI_PMSUP_SLOT_CLK_MASK (0x1 << I40E_GLPCI_PMSUP_SLOT_CLK_SHIFT) +#define I40E_GLPCI_PMSUP_SLOT_CLK_MASK I40E_MASK(0x1, I40E_GLPCI_PMSUP_SLOT_CLK_SHIFT) #define I40E_GLPCI_PMSUP_OBFF_SUP_SHIFT 15 -#define I40E_GLPCI_PMSUP_OBFF_SUP_MASK (0x3 << I40E_GLPCI_PMSUP_OBFF_SUP_SHIFT) -#define I40E_GLPCI_PWRDATA 0x000BE490 +#define I40E_GLPCI_PMSUP_OBFF_SUP_MASK I40E_MASK(0x3, I40E_GLPCI_PMSUP_OBFF_SUP_SHIFT) +#define I40E_GLPCI_PQ_MAX_USED_SPC 0x0009C4EC /* Reset: PCIR */ +#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_SHIFT 0 +#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_MASK I40E_MASK(0xFF, I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_SHIFT) +#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_SHIFT 8 +#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_MASK I40E_MASK(0xFF, I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_SHIFT) +#define I40E_GLPCI_PWRDATA 0x000BE490 /* Reset: PCIR */ #define I40E_GLPCI_PWRDATA_D0_POWER_SHIFT 0 -#define I40E_GLPCI_PWRDATA_D0_POWER_MASK (0xFF << I40E_GLPCI_PWRDATA_D0_POWER_SHIFT) +#define I40E_GLPCI_PWRDATA_D0_POWER_MASK I40E_MASK(0xFF, I40E_GLPCI_PWRDATA_D0_POWER_SHIFT) #define I40E_GLPCI_PWRDATA_COMM_POWER_SHIFT 8 -#define I40E_GLPCI_PWRDATA_COMM_POWER_MASK (0xFF << I40E_GLPCI_PWRDATA_COMM_POWER_SHIFT) +#define I40E_GLPCI_PWRDATA_COMM_POWER_MASK I40E_MASK(0xFF, I40E_GLPCI_PWRDATA_COMM_POWER_SHIFT) #define I40E_GLPCI_PWRDATA_D3_POWER_SHIFT 16 -#define I40E_GLPCI_PWRDATA_D3_POWER_MASK (0xFF << I40E_GLPCI_PWRDATA_D3_POWER_SHIFT) +#define I40E_GLPCI_PWRDATA_D3_POWER_MASK I40E_MASK(0xFF, I40E_GLPCI_PWRDATA_D3_POWER_SHIFT) #define I40E_GLPCI_PWRDATA_DATA_SCALE_SHIFT 24 -#define I40E_GLPCI_PWRDATA_DATA_SCALE_MASK (0x3 << I40E_GLPCI_PWRDATA_DATA_SCALE_SHIFT) -#define I40E_GLPCI_REVID 0x000BE4B4 +#define I40E_GLPCI_PWRDATA_DATA_SCALE_MASK I40E_MASK(0x3, I40E_GLPCI_PWRDATA_DATA_SCALE_SHIFT) +#define I40E_GLPCI_REVID 0x000BE4B4 /* Reset: PCIR */ #define I40E_GLPCI_REVID_NVM_REVID_SHIFT 0 -#define I40E_GLPCI_REVID_NVM_REVID_MASK (0xFF << I40E_GLPCI_REVID_NVM_REVID_SHIFT) -#define I40E_GLPCI_SERH 0x000BE49C +#define I40E_GLPCI_REVID_NVM_REVID_MASK I40E_MASK(0xFF, I40E_GLPCI_REVID_NVM_REVID_SHIFT) +#define I40E_GLPCI_SERH 0x000BE49C /* Reset: PCIR */ #define I40E_GLPCI_SERH_SER_NUM_H_SHIFT 0 -#define I40E_GLPCI_SERH_SER_NUM_H_MASK (0xFFFF << I40E_GLPCI_SERH_SER_NUM_H_SHIFT) -#define I40E_GLPCI_SERL 0x000BE498 +#define I40E_GLPCI_SERH_SER_NUM_H_MASK I40E_MASK(0xFFFF, I40E_GLPCI_SERH_SER_NUM_H_SHIFT) +#define I40E_GLPCI_SERL 0x000BE498 /* Reset: PCIR */ #define I40E_GLPCI_SERL_SER_NUM_L_SHIFT 0 -#define I40E_GLPCI_SERL_SER_NUM_L_MASK (0xFFFFFFFF << I40E_GLPCI_SERL_SER_NUM_L_SHIFT) -#define I40E_GLPCI_SUBSYSID 0x000BE48C -#define I40E_GLPCI_SUBSYSID_SUB_VEN_ID_SHIFT 0 -#define I40E_GLPCI_SUBSYSID_SUB_VEN_ID_MASK (0xFFFF << I40E_GLPCI_SUBSYSID_SUB_VEN_ID_SHIFT) -#define I40E_GLPCI_SUBSYSID_SUB_ID_SHIFT 16 -#define I40E_GLPCI_SUBSYSID_SUB_ID_MASK (0xFFFF << I40E_GLPCI_SUBSYSID_SUB_ID_SHIFT) -#define I40E_GLPCI_UPADD 0x000BE4F8 +#define I40E_GLPCI_SERL_SER_NUM_L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_SERL_SER_NUM_L_SHIFT) +#define I40E_GLPCI_SPARE_BITS_0 0x0009C4F8 /* Reset: PCIR */ +#define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT 0 +#define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT) +#define I40E_GLPCI_SPARE_BITS_1 0x0009C4FC /* Reset: PCIR */ +#define I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_SHIFT 0 +#define I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_SHIFT) +#define I40E_GLPCI_SUBVENID 0x000BE48C /* Reset: PCIR */ +#define I40E_GLPCI_SUBVENID_SUB_VEN_ID_SHIFT 0 +#define I40E_GLPCI_SUBVENID_SUB_VEN_ID_MASK I40E_MASK(0xFFFF, I40E_GLPCI_SUBVENID_SUB_VEN_ID_SHIFT) +#define I40E_GLPCI_UPADD 0x000BE4F8 /* Reset: PCIR */ #define I40E_GLPCI_UPADD_ADDRESS_SHIFT 1 -#define I40E_GLPCI_UPADD_ADDRESS_MASK (0x7FFFFFFF << I40E_GLPCI_UPADD_ADDRESS_SHIFT) -#define I40E_GLPCI_VFSUP 0x000BE4B8 +#define I40E_GLPCI_UPADD_ADDRESS_MASK I40E_MASK(0x7FFFFFFF, I40E_GLPCI_UPADD_ADDRESS_SHIFT) +#define I40E_GLPCI_VENDORID 0x000BE518 /* Reset: PCIR */ +#define I40E_GLPCI_VENDORID_VENDORID_SHIFT 0 +#define I40E_GLPCI_VENDORID_VENDORID_MASK I40E_MASK(0xFFFF, I40E_GLPCI_VENDORID_VENDORID_SHIFT) +#define I40E_GLPCI_VFSUP 0x000BE4B8 /* Reset: PCIR */ #define I40E_GLPCI_VFSUP_VF_PREFETCH_SHIFT 0 -#define I40E_GLPCI_VFSUP_VF_PREFETCH_MASK (0x1 << I40E_GLPCI_VFSUP_VF_PREFETCH_SHIFT) +#define I40E_GLPCI_VFSUP_VF_PREFETCH_MASK I40E_MASK(0x1, I40E_GLPCI_VFSUP_VF_PREFETCH_SHIFT) #define I40E_GLPCI_VFSUP_VR_BAR_TYPE_SHIFT 1 -#define I40E_GLPCI_VFSUP_VR_BAR_TYPE_MASK (0x1 << I40E_GLPCI_VFSUP_VR_BAR_TYPE_SHIFT) -#define I40E_PF_FUNC_RID 0x0009C000 +#define I40E_GLPCI_VFSUP_VR_BAR_TYPE_MASK I40E_MASK(0x1, I40E_GLPCI_VFSUP_VR_BAR_TYPE_SHIFT) +#define I40E_PF_FUNC_RID 0x0009C000 /* Reset: PCIR */ #define I40E_PF_FUNC_RID_FUNCTION_NUMBER_SHIFT 0 -#define I40E_PF_FUNC_RID_FUNCTION_NUMBER_MASK (0x7 << I40E_PF_FUNC_RID_FUNCTION_NUMBER_SHIFT) +#define I40E_PF_FUNC_RID_FUNCTION_NUMBER_MASK I40E_MASK(0x7, I40E_PF_FUNC_RID_FUNCTION_NUMBER_SHIFT) #define I40E_PF_FUNC_RID_DEVICE_NUMBER_SHIFT 3 -#define I40E_PF_FUNC_RID_DEVICE_NUMBER_MASK (0x1F << I40E_PF_FUNC_RID_DEVICE_NUMBER_SHIFT) +#define I40E_PF_FUNC_RID_DEVICE_NUMBER_MASK I40E_MASK(0x1F, I40E_PF_FUNC_RID_DEVICE_NUMBER_SHIFT) #define I40E_PF_FUNC_RID_BUS_NUMBER_SHIFT 8 -#define I40E_PF_FUNC_RID_BUS_NUMBER_MASK (0xFF << I40E_PF_FUNC_RID_BUS_NUMBER_SHIFT) -#define I40E_PF_PCI_CIAA 0x0009C080 +#define I40E_PF_FUNC_RID_BUS_NUMBER_MASK I40E_MASK(0xFF, I40E_PF_FUNC_RID_BUS_NUMBER_SHIFT) +#define I40E_PF_PCI_CIAA 0x0009C080 /* Reset: FLR */ #define I40E_PF_PCI_CIAA_ADDRESS_SHIFT 0 -#define I40E_PF_PCI_CIAA_ADDRESS_MASK (0xFFF << I40E_PF_PCI_CIAA_ADDRESS_SHIFT) +#define I40E_PF_PCI_CIAA_ADDRESS_MASK I40E_MASK(0xFFF, I40E_PF_PCI_CIAA_ADDRESS_SHIFT) #define I40E_PF_PCI_CIAA_VF_NUM_SHIFT 12 -#define I40E_PF_PCI_CIAA_VF_NUM_MASK (0x7F << I40E_PF_PCI_CIAA_VF_NUM_SHIFT) -#define I40E_PF_PCI_CIAD 0x0009C100 +#define I40E_PF_PCI_CIAA_VF_NUM_MASK I40E_MASK(0x7F, I40E_PF_PCI_CIAA_VF_NUM_SHIFT) +#define I40E_PF_PCI_CIAD 0x0009C100 /* Reset: FLR */ #define I40E_PF_PCI_CIAD_DATA_SHIFT 0 -#define I40E_PF_PCI_CIAD_DATA_MASK (0xFFFFFFFF << I40E_PF_PCI_CIAD_DATA_SHIFT) -#define I40E_PFPCI_CLASS 0x000BE400 +#define I40E_PF_PCI_CIAD_DATA_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_PCI_CIAD_DATA_SHIFT) +#define I40E_PFPCI_CLASS 0x000BE400 /* Reset: PCIR */ #define I40E_PFPCI_CLASS_STORAGE_CLASS_SHIFT 0 -#define I40E_PFPCI_CLASS_STORAGE_CLASS_MASK (0x1 << I40E_PFPCI_CLASS_STORAGE_CLASS_SHIFT) -#define I40E_PFPCI_CNF 0x000BE000 +#define I40E_PFPCI_CLASS_STORAGE_CLASS_MASK I40E_MASK(0x1, I40E_PFPCI_CLASS_STORAGE_CLASS_SHIFT) +#define I40E_PFPCI_CLASS_RESERVED_1_SHIFT 1 +#define I40E_PFPCI_CLASS_RESERVED_1_MASK I40E_MASK(0x1, I40E_PFPCI_CLASS_RESERVED_1_SHIFT) +#define I40E_PFPCI_CLASS_PF_IS_LAN_SHIFT 2 +#define I40E_PFPCI_CLASS_PF_IS_LAN_MASK I40E_MASK(0x1, I40E_PFPCI_CLASS_PF_IS_LAN_SHIFT) +#define I40E_PFPCI_CNF 0x000BE000 /* Reset: PCIR */ #define I40E_PFPCI_CNF_MSI_EN_SHIFT 2 -#define I40E_PFPCI_CNF_MSI_EN_MASK (0x1 << I40E_PFPCI_CNF_MSI_EN_SHIFT) +#define I40E_PFPCI_CNF_MSI_EN_MASK I40E_MASK(0x1, I40E_PFPCI_CNF_MSI_EN_SHIFT) #define I40E_PFPCI_CNF_EXROM_DIS_SHIFT 3 -#define I40E_PFPCI_CNF_EXROM_DIS_MASK (0x1 << I40E_PFPCI_CNF_EXROM_DIS_SHIFT) +#define I40E_PFPCI_CNF_EXROM_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_CNF_EXROM_DIS_SHIFT) #define I40E_PFPCI_CNF_IO_BAR_SHIFT 4 -#define I40E_PFPCI_CNF_IO_BAR_MASK (0x1 << I40E_PFPCI_CNF_IO_BAR_SHIFT) +#define I40E_PFPCI_CNF_IO_BAR_MASK I40E_MASK(0x1, I40E_PFPCI_CNF_IO_BAR_SHIFT) #define I40E_PFPCI_CNF_INT_PIN_SHIFT 5 -#define I40E_PFPCI_CNF_INT_PIN_MASK (0x3 << I40E_PFPCI_CNF_INT_PIN_SHIFT) -#define I40E_PFPCI_FACTPS 0x0009C180 +#define I40E_PFPCI_CNF_INT_PIN_MASK I40E_MASK(0x3, I40E_PFPCI_CNF_INT_PIN_SHIFT) +#define I40E_PFPCI_DEVID 0x000BE080 /* Reset: PCIR */ +#define I40E_PFPCI_DEVID_PF_DEV_ID_SHIFT 0 +#define I40E_PFPCI_DEVID_PF_DEV_ID_MASK I40E_MASK(0xFFFF, I40E_PFPCI_DEVID_PF_DEV_ID_SHIFT) +#define I40E_PFPCI_DEVID_VF_DEV_ID_SHIFT 16 +#define I40E_PFPCI_DEVID_VF_DEV_ID_MASK I40E_MASK(0xFFFF, I40E_PFPCI_DEVID_VF_DEV_ID_SHIFT) +#define I40E_PFPCI_FACTPS 0x0009C180 /* Reset: FLR */ #define I40E_PFPCI_FACTPS_FUNC_POWER_STATE_SHIFT 0 -#define I40E_PFPCI_FACTPS_FUNC_POWER_STATE_MASK (0x3 << I40E_PFPCI_FACTPS_FUNC_POWER_STATE_SHIFT) +#define I40E_PFPCI_FACTPS_FUNC_POWER_STATE_MASK I40E_MASK(0x3, I40E_PFPCI_FACTPS_FUNC_POWER_STATE_SHIFT) #define I40E_PFPCI_FACTPS_FUNC_AUX_EN_SHIFT 3 -#define I40E_PFPCI_FACTPS_FUNC_AUX_EN_MASK (0x1 << I40E_PFPCI_FACTPS_FUNC_AUX_EN_SHIFT) -#define I40E_PFPCI_FUNC 0x000BE200 +#define I40E_PFPCI_FACTPS_FUNC_AUX_EN_MASK I40E_MASK(0x1, I40E_PFPCI_FACTPS_FUNC_AUX_EN_SHIFT) +#define I40E_PFPCI_FUNC 0x000BE200 /* Reset: POR */ #define I40E_PFPCI_FUNC_FUNC_DIS_SHIFT 0 -#define I40E_PFPCI_FUNC_FUNC_DIS_MASK (0x1 << I40E_PFPCI_FUNC_FUNC_DIS_SHIFT) +#define I40E_PFPCI_FUNC_FUNC_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_FUNC_FUNC_DIS_SHIFT) #define I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_SHIFT 1 -#define I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_MASK (0x1 << I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_SHIFT) +#define I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_SHIFT) #define I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_SHIFT 2 -#define I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_MASK (0x1 << I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_SHIFT) -#define I40E_PFPCI_FUNC2 0x000BE180 +#define I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_SHIFT) +#define I40E_PFPCI_FUNC2 0x000BE180 /* Reset: PCIR */ #define I40E_PFPCI_FUNC2_EMP_FUNC_DIS_SHIFT 0 -#define I40E_PFPCI_FUNC2_EMP_FUNC_DIS_MASK (0x1 << I40E_PFPCI_FUNC2_EMP_FUNC_DIS_SHIFT) -#define I40E_PFPCI_ICAUSE 0x0009C200 +#define I40E_PFPCI_FUNC2_EMP_FUNC_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_FUNC2_EMP_FUNC_DIS_SHIFT) +#define I40E_PFPCI_ICAUSE 0x0009C200 /* Reset: PFR */ #define I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_SHIFT 0 -#define I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_MASK (0xFFFFFFFF << I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_SHIFT) -#define I40E_PFPCI_IENA 0x0009C280 +#define I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_MASK I40E_MASK(0xFFFFFFFF, I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_SHIFT) +#define I40E_PFPCI_IENA 0x0009C280 /* Reset: PFR */ #define I40E_PFPCI_IENA_PCIE_ERR_EN_SHIFT 0 -#define I40E_PFPCI_IENA_PCIE_ERR_EN_MASK (0xFFFFFFFF << I40E_PFPCI_IENA_PCIE_ERR_EN_SHIFT) -#define I40E_PFPCI_PFDEVID 0x000BE080 -#define I40E_PFPCI_PFDEVID_PF_DEV_ID_LAN_SHIFT 0 -#define I40E_PFPCI_PFDEVID_PF_DEV_ID_LAN_MASK (0xFFFF << I40E_PFPCI_PFDEVID_PF_DEV_ID_LAN_SHIFT) -#define I40E_PFPCI_PFDEVID_PF_DEV_ID_SAN_SHIFT 16 -#define I40E_PFPCI_PFDEVID_PF_DEV_ID_SAN_MASK (0xFFFF << I40E_PFPCI_PFDEVID_PF_DEV_ID_SAN_SHIFT) -#define I40E_PFPCI_PM 0x000BE300 +#define I40E_PFPCI_IENA_PCIE_ERR_EN_MASK I40E_MASK(0xFFFFFFFF, I40E_PFPCI_IENA_PCIE_ERR_EN_SHIFT) +#define I40E_PFPCI_PF_FLUSH_DONE 0x0009C800 /* Reset: PCIR */ +#define I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_SHIFT 0 +#define I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_MASK I40E_MASK(0x1, I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_SHIFT) +#define I40E_PFPCI_PM 0x000BE300 /* Reset: POR */ #define I40E_PFPCI_PM_PME_EN_SHIFT 0 -#define I40E_PFPCI_PM_PME_EN_MASK (0x1 << I40E_PFPCI_PM_PME_EN_SHIFT) -#define I40E_PFPCI_STATUS1 0x000BE280 +#define I40E_PFPCI_PM_PME_EN_MASK I40E_MASK(0x1, I40E_PFPCI_PM_PME_EN_SHIFT) +#define I40E_PFPCI_STATUS1 0x000BE280 /* Reset: POR */ #define I40E_PFPCI_STATUS1_FUNC_VALID_SHIFT 0 -#define I40E_PFPCI_STATUS1_FUNC_VALID_MASK (0x1 << I40E_PFPCI_STATUS1_FUNC_VALID_SHIFT) -#define I40E_PFPCI_VFDEVID 0x000BE100 -#define I40E_PFPCI_VFDEVID_VF_DEV_ID_LAN_SHIFT 0 -#define I40E_PFPCI_VFDEVID_VF_DEV_ID_LAN_MASK (0xFFFF << I40E_PFPCI_VFDEVID_VF_DEV_ID_LAN_SHIFT) -#define I40E_PFPCI_VFDEVID_VF_DEV_ID_SAN_SHIFT 16 -#define I40E_PFPCI_VFDEVID_VF_DEV_ID_SAN_MASK (0xFFFF << I40E_PFPCI_VFDEVID_VF_DEV_ID_SAN_SHIFT) -#define I40E_PFPCI_VMINDEX 0x0009C300 +#define I40E_PFPCI_STATUS1_FUNC_VALID_MASK I40E_MASK(0x1, I40E_PFPCI_STATUS1_FUNC_VALID_SHIFT) +#define I40E_PFPCI_SUBSYSID 0x000BE100 /* Reset: PCIR */ +#define I40E_PFPCI_SUBSYSID_PF_SUBSYS_ID_SHIFT 0 +#define I40E_PFPCI_SUBSYSID_PF_SUBSYS_ID_MASK I40E_MASK(0xFFFF, I40E_PFPCI_SUBSYSID_PF_SUBSYS_ID_SHIFT) +#define I40E_PFPCI_SUBSYSID_VF_SUBSYS_ID_SHIFT 16 +#define I40E_PFPCI_SUBSYSID_VF_SUBSYS_ID_MASK I40E_MASK(0xFFFF, I40E_PFPCI_SUBSYSID_VF_SUBSYS_ID_SHIFT) +#define I40E_PFPCI_VF_FLUSH_DONE 0x0000E400 /* Reset: PCIR */ +#define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT 0 +#define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_MASK I40E_MASK(0x1, I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT) +#define I40E_PFPCI_VF_FLUSH_DONE1(_VF) (0x0009C600 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: PCIR */ +#define I40E_PFPCI_VF_FLUSH_DONE1_MAX_INDEX 127 +#define I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_SHIFT 0 +#define I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_MASK I40E_MASK(0x1, I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_SHIFT) +#define I40E_PFPCI_VM_FLUSH_DONE 0x0009C880 /* Reset: PCIR */ +#define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT 0 +#define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_MASK I40E_MASK(0x1, I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT) +#define I40E_PFPCI_VMINDEX 0x0009C300 /* Reset: PCIR */ #define I40E_PFPCI_VMINDEX_VMINDEX_SHIFT 0 -#define I40E_PFPCI_VMINDEX_VMINDEX_MASK (0x1FF << I40E_PFPCI_VMINDEX_VMINDEX_SHIFT) -#define I40E_PFPCI_VMPEND 0x0009C380 +#define I40E_PFPCI_VMINDEX_VMINDEX_MASK I40E_MASK(0x1FF, I40E_PFPCI_VMINDEX_VMINDEX_SHIFT) +#define I40E_PFPCI_VMPEND 0x0009C380 /* Reset: PCIR */ #define I40E_PFPCI_VMPEND_PENDING_SHIFT 0 -#define I40E_PFPCI_VMPEND_PENDING_MASK (0x1 << I40E_PFPCI_VMPEND_PENDING_SHIFT) -#define I40E_GLPE_CPUSTATUS0 0x0000D040 -#define I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_SHIFT 0 -#define I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_MASK (0xFFFFFFFF << I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_SHIFT) -#define I40E_GLPE_CPUSTATUS1 0x0000D044 -#define I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_SHIFT 0 -#define I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_MASK (0xFFFFFFFF << I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_SHIFT) -#define I40E_GLPE_CPUSTATUS2 0x0000D048 -#define I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_SHIFT 0 -#define I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_MASK (0xFFFFFFFF << I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_SHIFT) -#define I40E_GLPE_PFFLMOBJCTRL(_i) (0x0000D480 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPE_PFFLMOBJCTRL_MAX_INDEX 15 -#define I40E_GLPE_PFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT 0 -#define I40E_GLPE_PFFLMOBJCTRL_XMIT_BLOCKSIZE_MASK (0x7 << I40E_GLPE_PFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT) -#define I40E_GLPE_PFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT 8 -#define I40E_GLPE_PFFLMOBJCTRL_Q1_BLOCKSIZE_MASK (0x7 << I40E_GLPE_PFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT) -#define I40E_GLPE_VFFLMOBJCTRL(_i) (0x0000D400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPE_VFFLMOBJCTRL_MAX_INDEX 31 -#define I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT 0 -#define I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_MASK (0x7 << I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT) -#define I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT 8 -#define I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_MASK (0x7 << I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT) -#define I40E_GLPE_VFFLMQ1ALLOCERR(_i) (0x0000C700 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPE_VFFLMQ1ALLOCERR_MAX_INDEX 31 -#define I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_SHIFT 0 -#define I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_SHIFT) -#define I40E_GLPE_VFFLMXMITALLOCERR(_i) (0x0000C600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPE_VFFLMXMITALLOCERR_MAX_INDEX 31 -#define I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_SHIFT 0 -#define I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_SHIFT) -#define I40E_GLPE_VFUDACTRL(_i) (0x0000C000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPE_VFUDACTRL_MAX_INDEX 31 -#define I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_SHIFT 0 -#define I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_SHIFT) -#define I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_SHIFT 1 -#define I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_SHIFT) -#define I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_SHIFT 2 -#define I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_SHIFT) -#define I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_SHIFT 3 -#define I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_SHIFT) -#define I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_SHIFT 4 -#define I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_MASK (0x1 << I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_SHIFT) -#define I40E_GLPE_VFUDAUCFBQPN(_i) (0x0000C100 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPE_VFUDAUCFBQPN_MAX_INDEX 31 -#define I40E_GLPE_VFUDAUCFBQPN_QPN_SHIFT 0 -#define I40E_GLPE_VFUDAUCFBQPN_QPN_MASK (0x3FFFF << I40E_GLPE_VFUDAUCFBQPN_QPN_SHIFT) -#define I40E_GLPE_VFUDAUCFBQPN_VALID_SHIFT 31 -#define I40E_GLPE_VFUDAUCFBQPN_VALID_MASK (0x1 << I40E_GLPE_VFUDAUCFBQPN_VALID_SHIFT) -#define I40E_PFPE_AEQALLOC 0x00131180 -#define I40E_PFPE_AEQALLOC_AECOUNT_SHIFT 0 -#define I40E_PFPE_AEQALLOC_AECOUNT_MASK (0xFFFFFFFF << I40E_PFPE_AEQALLOC_AECOUNT_SHIFT) -#define I40E_PFPE_CCQPHIGH 0x00008200 -#define I40E_PFPE_CCQPHIGH_PECCQPHIGH_SHIFT 0 -#define I40E_PFPE_CCQPHIGH_PECCQPHIGH_MASK (0xFFFFFFFF << I40E_PFPE_CCQPHIGH_PECCQPHIGH_SHIFT) -#define I40E_PFPE_CCQPLOW 0x00008180 -#define I40E_PFPE_CCQPLOW_PECCQPLOW_SHIFT 0 -#define I40E_PFPE_CCQPLOW_PECCQPLOW_MASK (0xFFFFFFFF << I40E_PFPE_CCQPLOW_PECCQPLOW_SHIFT) -#define I40E_PFPE_CCQPSTATUS 0x00008100 -#define I40E_PFPE_CCQPSTATUS_CCQP_DONE_SHIFT 0 -#define I40E_PFPE_CCQPSTATUS_CCQP_DONE_MASK (0x1 << I40E_PFPE_CCQPSTATUS_CCQP_DONE_SHIFT) -#define I40E_PFPE_CCQPSTATUS_CCQP_ERR_SHIFT 31 -#define I40E_PFPE_CCQPSTATUS_CCQP_ERR_MASK (0x1 << I40E_PFPE_CCQPSTATUS_CCQP_ERR_SHIFT) -#define I40E_PFPE_CQACK 0x00131100 -#define I40E_PFPE_CQACK_PECQID_SHIFT 0 -#define I40E_PFPE_CQACK_PECQID_MASK (0x1FFFF << I40E_PFPE_CQACK_PECQID_SHIFT) -#define I40E_PFPE_CQARM 0x00131080 -#define I40E_PFPE_CQARM_PECQID_SHIFT 0 -#define I40E_PFPE_CQARM_PECQID_MASK (0x1FFFF << I40E_PFPE_CQARM_PECQID_SHIFT) -#define I40E_PFPE_CQPDB 0x00008000 -#define I40E_PFPE_CQPDB_WQHEAD_SHIFT 0 -#define I40E_PFPE_CQPDB_WQHEAD_MASK (0x7FF << I40E_PFPE_CQPDB_WQHEAD_SHIFT) -#define I40E_PFPE_CQPERRCODES 0x00008880 -#define I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT 0 -#define I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_MASK (0xFFFF << I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT) -#define I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT 16 -#define I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_MASK (0xFFFF << I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT) -#define I40E_PFPE_CQPTAIL 0x00008080 -#define I40E_PFPE_CQPTAIL_WQTAIL_SHIFT 0 -#define I40E_PFPE_CQPTAIL_WQTAIL_MASK (0x7FF << I40E_PFPE_CQPTAIL_WQTAIL_SHIFT) -#define I40E_PFPE_CQPTAIL_CQP_OP_ERR_SHIFT 31 -#define I40E_PFPE_CQPTAIL_CQP_OP_ERR_MASK (0x1 << I40E_PFPE_CQPTAIL_CQP_OP_ERR_SHIFT) -#define I40E_PFPE_FLMQ1ALLOCERR 0x00008980 -#define I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_SHIFT 0 -#define I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_SHIFT) -#define I40E_PFPE_FLMXMITALLOCERR 0x00008900 -#define I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_SHIFT 0 -#define I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_SHIFT) -#define I40E_PFPE_IPCONFIG0 0x00008280 -#define I40E_PFPE_IPCONFIG0_PEIPID_SHIFT 0 -#define I40E_PFPE_IPCONFIG0_PEIPID_MASK (0xFFFF << I40E_PFPE_IPCONFIG0_PEIPID_SHIFT) -#define I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT 16 -#define I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_MASK (0x1 << I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT) - -#define I40E_PFPE_MRTEIDXMASK 0x00008600 -#define I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT 0 -#define I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_MASK (0x1F << I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT) -#define I40E_PFPE_RCVUNEXPECTEDERROR 0x00008680 -#define I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT 0 -#define I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_MASK (0xFFFFFF << I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT) -#define I40E_PFPE_TCPNOWTIMER 0x00008580 -#define I40E_PFPE_TCPNOWTIMER_TCP_NOW_SHIFT 0 -#define I40E_PFPE_TCPNOWTIMER_TCP_NOW_MASK (0xFFFFFFFF << I40E_PFPE_TCPNOWTIMER_TCP_NOW_SHIFT) -#define I40E_PFPE_UDACTRL 0x00008700 -#define I40E_PFPE_UDACTRL_IPV4MCFRAGRESBP_SHIFT 0 -#define I40E_PFPE_UDACTRL_IPV4MCFRAGRESBP_MASK (0x1 << I40E_PFPE_UDACTRL_IPV4MCFRAGRESBP_SHIFT) -#define I40E_PFPE_UDACTRL_IPV4UCFRAGRESBP_SHIFT 1 -#define I40E_PFPE_UDACTRL_IPV4UCFRAGRESBP_MASK (0x1 << I40E_PFPE_UDACTRL_IPV4UCFRAGRESBP_SHIFT) -#define I40E_PFPE_UDACTRL_IPV6MCFRAGRESBP_SHIFT 2 -#define I40E_PFPE_UDACTRL_IPV6MCFRAGRESBP_MASK (0x1 << I40E_PFPE_UDACTRL_IPV6MCFRAGRESBP_SHIFT) -#define I40E_PFPE_UDACTRL_IPV6UCFRAGRESBP_SHIFT 3 -#define I40E_PFPE_UDACTRL_IPV6UCFRAGRESBP_MASK (0x1 << I40E_PFPE_UDACTRL_IPV6UCFRAGRESBP_SHIFT) -#define I40E_PFPE_UDACTRL_UDPMCFRAGRESFAIL_SHIFT 4 -#define I40E_PFPE_UDACTRL_UDPMCFRAGRESFAIL_MASK (0x1 << I40E_PFPE_UDACTRL_UDPMCFRAGRESFAIL_SHIFT) -#define I40E_PFPE_UDAUCFBQPN 0x00008780 -#define I40E_PFPE_UDAUCFBQPN_QPN_SHIFT 0 -#define I40E_PFPE_UDAUCFBQPN_QPN_MASK (0x3FFFF << I40E_PFPE_UDAUCFBQPN_QPN_SHIFT) -#define I40E_PFPE_UDAUCFBQPN_VALID_SHIFT 31 -#define I40E_PFPE_UDAUCFBQPN_VALID_MASK (0x1 << I40E_PFPE_UDAUCFBQPN_VALID_SHIFT) -#define I40E_PFPE_WQEALLOC 0x00138C00 -#define I40E_PFPE_WQEALLOC_PEQPID_SHIFT 0 -#define I40E_PFPE_WQEALLOC_PEQPID_MASK (0x3FFFF << I40E_PFPE_WQEALLOC_PEQPID_SHIFT) -#define I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT 20 -#define I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_MASK (0xFFF << I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT) -#define I40E_VFPE_AEQALLOC(_VF) (0x00130C00 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_AEQALLOC_MAX_INDEX 127 -#define I40E_VFPE_AEQALLOC_AECOUNT_SHIFT 0 -#define I40E_VFPE_AEQALLOC_AECOUNT_MASK (0xFFFFFFFF << I40E_VFPE_AEQALLOC_AECOUNT_SHIFT) -#define I40E_VFPE_CCQPHIGH(_VF) (0x00001000 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CCQPHIGH_MAX_INDEX 127 -#define I40E_VFPE_CCQPHIGH_PECCQPHIGH_SHIFT 0 -#define I40E_VFPE_CCQPHIGH_PECCQPHIGH_MASK (0xFFFFFFFF << I40E_VFPE_CCQPHIGH_PECCQPHIGH_SHIFT) -#define I40E_VFPE_CCQPLOW(_VF) (0x00000C00 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CCQPLOW_MAX_INDEX 127 -#define I40E_VFPE_CCQPLOW_PECCQPLOW_SHIFT 0 -#define I40E_VFPE_CCQPLOW_PECCQPLOW_MASK (0xFFFFFFFF << I40E_VFPE_CCQPLOW_PECCQPLOW_SHIFT) -#define I40E_VFPE_CCQPSTATUS(_VF) (0x00000800 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CCQPSTATUS_MAX_INDEX 127 -#define I40E_VFPE_CCQPSTATUS_CCQP_DONE_SHIFT 0 -#define I40E_VFPE_CCQPSTATUS_CCQP_DONE_MASK (0x1 << I40E_VFPE_CCQPSTATUS_CCQP_DONE_SHIFT) -#define I40E_VFPE_CCQPSTATUS_CCQP_ERR_SHIFT 31 -#define I40E_VFPE_CCQPSTATUS_CCQP_ERR_MASK (0x1 << I40E_VFPE_CCQPSTATUS_CCQP_ERR_SHIFT) -#define I40E_VFPE_CQACK(_VF) (0x00130800 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CQACK_MAX_INDEX 127 -#define I40E_VFPE_CQACK_PECQID_SHIFT 0 -#define I40E_VFPE_CQACK_PECQID_MASK (0x1FFFF << I40E_VFPE_CQACK_PECQID_SHIFT) -#define I40E_VFPE_CQARM(_VF) (0x00130400 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CQARM_MAX_INDEX 127 -#define I40E_VFPE_CQARM_PECQID_SHIFT 0 -#define I40E_VFPE_CQARM_PECQID_MASK (0x1FFFF << I40E_VFPE_CQARM_PECQID_SHIFT) -#define I40E_VFPE_CQPDB(_VF) (0x00000000 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CQPDB_MAX_INDEX 127 -#define I40E_VFPE_CQPDB_WQHEAD_SHIFT 0 -#define I40E_VFPE_CQPDB_WQHEAD_MASK (0x7FF << I40E_VFPE_CQPDB_WQHEAD_SHIFT) -#define I40E_VFPE_CQPERRCODES(_VF) (0x00001800 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CQPERRCODES_MAX_INDEX 127 -#define I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT 0 -#define I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT) -#define I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT 16 -#define I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT) -#define I40E_VFPE_CQPTAIL(_VF) (0x00000400 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CQPTAIL_MAX_INDEX 127 -#define I40E_VFPE_CQPTAIL_WQTAIL_SHIFT 0 -#define I40E_VFPE_CQPTAIL_WQTAIL_MASK (0x7FF << I40E_VFPE_CQPTAIL_WQTAIL_SHIFT) -#define I40E_VFPE_CQPTAIL_CQP_OP_ERR_SHIFT 31 -#define I40E_VFPE_CQPTAIL_CQP_OP_ERR_MASK (0x1 << I40E_VFPE_CQPTAIL_CQP_OP_ERR_SHIFT) -#define I40E_VFPE_IPCONFIG0(_VF) (0x00001400 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_IPCONFIG0_MAX_INDEX 127 -#define I40E_VFPE_IPCONFIG0_PEIPID_SHIFT 0 -#define I40E_VFPE_IPCONFIG0_PEIPID_MASK (0xFFFF << I40E_VFPE_IPCONFIG0_PEIPID_SHIFT) -#define I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT 16 -#define I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT) -#define I40E_VFPE_MRTEIDXMASK(_VF) (0x00003000 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_MRTEIDXMASK_MAX_INDEX 127 -#define I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT 0 -#define I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_MASK (0x1F << I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT) -#define I40E_VFPE_RCVUNEXPECTEDERROR(_VF) (0x00003400 + ((_VF) * 4)) -#define I40E_VFPE_RCVUNEXPECTEDERROR_MAX_INDEX 127 -#define I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT 0 -#define I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_MASK (0xFFFFFF << I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT) -#define I40E_VFPE_TCPNOWTIMER(_VF) (0x00002C00 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_TCPNOWTIMER_MAX_INDEX 127 -#define I40E_VFPE_TCPNOWTIMER_TCP_NOW_SHIFT 0 -#define I40E_VFPE_TCPNOWTIMER_TCP_NOW_MASK (0xFFFFFFFF << I40E_VFPE_TCPNOWTIMER_TCP_NOW_SHIFT) -#define I40E_VFPE_WQEALLOC(_VF) (0x00138000 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_WQEALLOC_MAX_INDEX 127 -#define I40E_VFPE_WQEALLOC_PEQPID_SHIFT 0 -#define I40E_VFPE_WQEALLOC_PEQPID_MASK (0x3FFFF << I40E_VFPE_WQEALLOC_PEQPID_SHIFT) -#define I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT 20 -#define I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_MASK (0xFFF << I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT) -#define I40E_GLPES_PFIP4RXDISCARD(_i) (0x00010600 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXDISCARD_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_SHIFT 0 -#define I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_SHIFT) -#define I40E_GLPES_PFIP4RXFRAGSHI(_i) (0x00010804 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXFRAGSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT 0 -#define I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT) -#define I40E_GLPES_PFIP4RXFRAGSLO(_i) (0x00010800 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXFRAGSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT 0 -#define I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT) -#define I40E_GLPES_PFIP4RXMCOCTSHI(_i) (0x00010A04 + ((_i) * 8)) -#define I40E_GLPES_PFIP4RXMCOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT) -#define I40E_GLPES_PFIP4RXMCOCTSLO(_i) (0x00010A00 + ((_i) * 8)) -#define I40E_GLPES_PFIP4RXMCOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT) -#define I40E_GLPES_PFIP4RXMCPKTSHI(_i) (0x00010C04 + ((_i) * 8)) -#define I40E_GLPES_PFIP4RXMCPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT) -#define I40E_GLPES_PFIP4RXMCPKTSLO(_i) (0x00010C00 + ((_i) * 8)) -#define I40E_GLPES_PFIP4RXMCPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT) -#define I40E_GLPES_PFIP4RXOCTSHI(_i) (0x00010204 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT) -#define I40E_GLPES_PFIP4RXOCTSLO(_i) (0x00010200 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT) -#define I40E_GLPES_PFIP4RXPKTSHI(_i) (0x00010404 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT) -#define I40E_GLPES_PFIP4RXPKTSLO(_i) (0x00010400 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT) -#define I40E_GLPES_PFIP4RXTRUNC(_i) (0x00010700 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXTRUNC_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_SHIFT 0 -#define I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_SHIFT) -#define I40E_GLPES_PFIP4TXFRAGSHI(_i) (0x00011E04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXFRAGSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT 0 -#define I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT) -#define I40E_GLPES_PFIP4TXFRAGSLO(_i) (0x00011E00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXFRAGSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT 0 -#define I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT) -#define I40E_GLPES_PFIP4TXMCOCTSHI(_i) (0x00012004 + ((_i) * 8)) -#define I40E_GLPES_PFIP4TXMCOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT) -#define I40E_GLPES_PFIP4TXMCOCTSLO(_i) (0x00012000 + ((_i) * 8)) -#define I40E_GLPES_PFIP4TXMCOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT) -#define I40E_GLPES_PFIP4TXMCPKTSHI(_i) (0x00012204 + ((_i) * 8)) -#define I40E_GLPES_PFIP4TXMCPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT) -#define I40E_GLPES_PFIP4TXMCPKTSLO(_i) (0x00012200 + ((_i) * 8)) -#define I40E_GLPES_PFIP4TXMCPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT) -#define I40E_GLPES_PFIP4TXNOROUTE(_i) (0x00012E00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXNOROUTE_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT 0 -#define I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT) -#define I40E_GLPES_PFIP4TXOCTSHI(_i) (0x00011A04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT) -#define I40E_GLPES_PFIP4TXOCTSLO(_i) (0x00011A00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT) -#define I40E_GLPES_PFIP4TXPKTSHI(_i) (0x00011C04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT) -#define I40E_GLPES_PFIP4TXPKTSLO(_i) (0x00011C00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT) -#define I40E_GLPES_PFIP6RXDISCARD(_i) (0x00011200 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXDISCARD_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_SHIFT 0 -#define I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_SHIFT) -#define I40E_GLPES_PFIP6RXFRAGSHI(_i) (0x00011404 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXFRAGSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT 0 -#define I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT) -#define I40E_GLPES_PFIP6RXFRAGSLO(_i) (0x00011400 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXFRAGSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT 0 -#define I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT) -#define I40E_GLPES_PFIP6RXMCOCTSHI(_i) (0x00011604 + ((_i) * 8)) -#define I40E_GLPES_PFIP6RXMCOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT) -#define I40E_GLPES_PFIP6RXMCOCTSLO(_i) (0x00011600 + ((_i) * 8)) -#define I40E_GLPES_PFIP6RXMCOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT) -#define I40E_GLPES_PFIP6RXMCPKTSHI(_i) (0x00011804 + ((_i) * 8)) -#define I40E_GLPES_PFIP6RXMCPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT) -#define I40E_GLPES_PFIP6RXMCPKTSLO(_i) (0x00011800 + ((_i) * 8)) -#define I40E_GLPES_PFIP6RXMCPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT) -#define I40E_GLPES_PFIP6RXOCTSHI(_i) (0x00010E04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT) -#define I40E_GLPES_PFIP6RXOCTSLO(_i) (0x00010E00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT) -#define I40E_GLPES_PFIP6RXPKTSHI(_i) (0x00011004 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT) -#define I40E_GLPES_PFIP6RXPKTSLO(_i) (0x00011000 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT) -#define I40E_GLPES_PFIP6RXTRUNC(_i) (0x00011300 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXTRUNC_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_SHIFT 0 -#define I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_SHIFT) -#define I40E_GLPES_PFIP6TXFRAGSHI(_i) (0x00012804 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXFRAGSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT 0 -#define I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT) -#define I40E_GLPES_PFIP6TXFRAGSLO(_i) (0x00012800 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXFRAGSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT 0 -#define I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT) -#define I40E_GLPES_PFIP6TXMCOCTSHI(_i) (0x00012A04 + ((_i) * 8)) -#define I40E_GLPES_PFIP6TXMCOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT) -#define I40E_GLPES_PFIP6TXMCOCTSLO(_i) (0x00012A00 + ((_i) * 8)) -#define I40E_GLPES_PFIP6TXMCOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT) -#define I40E_GLPES_PFIP6TXMCPKTSHI(_i) (0x00012C04 + ((_i) * 8)) -#define I40E_GLPES_PFIP6TXMCPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT) -#define I40E_GLPES_PFIP6TXMCPKTSLO(_i) (0x00012C00 + ((_i) * 8)) -#define I40E_GLPES_PFIP6TXMCPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT) -#define I40E_GLPES_PFIP6TXNOROUTE(_i) (0x00012F00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXNOROUTE_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT 0 -#define I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT) -#define I40E_GLPES_PFIP6TXOCTSHI(_i) (0x00012404 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT) -#define I40E_GLPES_PFIP6TXOCTSLO(_i) (0x00012400 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT) -#define I40E_GLPES_PFIP6TXPKTSHI(_i) (0x00012604 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT) -#define I40E_GLPES_PFIP6TXPKTSLO(_i) (0x00012600 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT) -#define I40E_GLPES_PFRDMARXRDSHI(_i) (0x00013E04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMARXRDSHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_SHIFT 0 -#define I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_SHIFT) -#define I40E_GLPES_PFRDMARXRDSLO(_i) (0x00013E00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMARXRDSLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_SHIFT 0 -#define I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_SHIFT) -#define I40E_GLPES_PFRDMARXSNDSHI(_i) (0x00014004 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMARXSNDSHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT 0 -#define I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT) -#define I40E_GLPES_PFRDMARXSNDSLO(_i) (0x00014000 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMARXSNDSLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT 0 -#define I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT) -#define I40E_GLPES_PFRDMARXWRSHI(_i) (0x00013C04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMARXWRSHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_SHIFT 0 -#define I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_SHIFT) -#define I40E_GLPES_PFRDMARXWRSLO(_i) (0x00013C00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMARXWRSLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_SHIFT 0 -#define I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_SHIFT) -#define I40E_GLPES_PFRDMATXRDSHI(_i) (0x00014404 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMATXRDSHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_SHIFT 0 -#define I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_SHIFT) -#define I40E_GLPES_PFRDMATXRDSLO(_i) (0x00014400 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMATXRDSLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_SHIFT 0 -#define I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_SHIFT) -#define I40E_GLPES_PFRDMATXSNDSHI(_i) (0x00014604 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMATXSNDSHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT 0 -#define I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT) -#define I40E_GLPES_PFRDMATXSNDSLO(_i) (0x00014600 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMATXSNDSLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT 0 -#define I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT) -#define I40E_GLPES_PFRDMATXWRSHI(_i) (0x00014204 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMATXWRSHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_SHIFT 0 -#define I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_SHIFT) -#define I40E_GLPES_PFRDMATXWRSLO(_i) (0x00014200 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMATXWRSLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_SHIFT 0 -#define I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_SHIFT) -#define I40E_GLPES_PFRDMAVBNDHI(_i) (0x00014804 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMAVBNDHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_SHIFT 0 -#define I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_SHIFT) -#define I40E_GLPES_PFRDMAVBNDLO(_i) (0x00014800 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMAVBNDLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_SHIFT 0 -#define I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_SHIFT) -#define I40E_GLPES_PFRDMAVINVHI(_i) (0x00014A04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMAVINVHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_SHIFT 0 -#define I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_SHIFT) -#define I40E_GLPES_PFRDMAVINVLO(_i) (0x00014A00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMAVINVLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_SHIFT 0 -#define I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_SHIFT) -#define I40E_GLPES_PFRXVLANERR(_i) (0x00010000 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFRXVLANERR_MAX_INDEX 15 -#define I40E_GLPES_PFRXVLANERR_RXVLANERR_SHIFT 0 -#define I40E_GLPES_PFRXVLANERR_RXVLANERR_MASK (0xFFFFFF << I40E_GLPES_PFRXVLANERR_RXVLANERR_SHIFT) -#define I40E_GLPES_PFTCPRTXSEG(_i) (0x00013600 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFTCPRTXSEG_MAX_INDEX 15 -#define I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_SHIFT 0 -#define I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_MASK (0xFFFFFFFF << I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_SHIFT) -#define I40E_GLPES_PFTCPRXOPTERR(_i) (0x00013200 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFTCPRXOPTERR_MAX_INDEX 15 -#define I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_SHIFT 0 -#define I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_MASK (0xFFFFFF << I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_SHIFT) -#define I40E_GLPES_PFTCPRXPROTOERR(_i) (0x00013300 + ((_i) * 4)) -#define I40E_GLPES_PFTCPRXPROTOERR_MAX_INDEX 15 -#define I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT 0 -#define I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_MASK (0xFFFFFF << I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT) -#define I40E_GLPES_PFTCPRXSEGSHI(_i) (0x00013004 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFTCPRXSEGSHI_MAX_INDEX 15 -#define I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT 0 -#define I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_MASK (0xFFFF << I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT) -#define I40E_GLPES_PFTCPRXSEGSLO(_i) (0x00013000 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFTCPRXSEGSLO_MAX_INDEX 15 -#define I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT 0 -#define I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT) -#define I40E_GLPES_PFTCPTXSEGHI(_i) (0x00013404 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFTCPTXSEGHI_MAX_INDEX 15 -#define I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_SHIFT 0 -#define I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_MASK (0xFFFF << I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_SHIFT) -#define I40E_GLPES_PFTCPTXSEGLO(_i) (0x00013400 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFTCPTXSEGLO_MAX_INDEX 15 -#define I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_SHIFT 0 -#define I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_MASK (0xFFFFFFFF << I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_SHIFT) -#define I40E_GLPES_PFUDPRXPKTSHI(_i) (0x00013804 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFUDPRXPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT 0 -#define I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT) -#define I40E_GLPES_PFUDPRXPKTSLO(_i) (0x00013800 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFUDPRXPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT 0 -#define I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT) -#define I40E_GLPES_PFUDPTXPKTSHI(_i) (0x00013A04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFUDPTXPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT 0 -#define I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT) -#define I40E_GLPES_PFUDPTXPKTSLO(_i) (0x00013A00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFUDPTXPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT 0 -#define I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT) -#define I40E_GLPES_RDMARXMULTFPDUSHI 0x0001E014 -#define I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_SHIFT 0 -#define I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_MASK (0xFFFFFF << I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_SHIFT) -#define I40E_GLPES_RDMARXMULTFPDUSLO 0x0001E010 -#define I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_SHIFT 0 -#define I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_SHIFT) -#define I40E_GLPES_RDMARXOOODDPHI 0x0001E01C -#define I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_SHIFT 0 -#define I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_MASK (0xFFFFFF << I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_SHIFT) -#define I40E_GLPES_RDMARXOOODDPLO 0x0001E018 -#define I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_SHIFT 0 -#define I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_SHIFT) -#define I40E_GLPES_RDMARXOOONOMARK 0x0001E004 -#define I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_SHIFT 0 -#define I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_SHIFT) -#define I40E_GLPES_RDMARXUNALIGN 0x0001E000 -#define I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_SHIFT 0 -#define I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_SHIFT) -#define I40E_GLPES_TCPRXFOURHOLEHI 0x0001E044 -#define I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_SHIFT 0 -#define I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_SHIFT) -#define I40E_GLPES_TCPRXFOURHOLELO 0x0001E040 -#define I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_SHIFT 0 -#define I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_SHIFT) -#define I40E_GLPES_TCPRXONEHOLEHI 0x0001E02C -#define I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_SHIFT 0 -#define I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_SHIFT) -#define I40E_GLPES_TCPRXONEHOLELO 0x0001E028 -#define I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_SHIFT 0 -#define I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_SHIFT) -#define I40E_GLPES_TCPRXPUREACKHI 0x0001E024 -#define I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_SHIFT 0 -#define I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_SHIFT) -#define I40E_GLPES_TCPRXPUREACKSLO 0x0001E020 -#define I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_SHIFT 0 -#define I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_SHIFT) -#define I40E_GLPES_TCPRXTHREEHOLEHI 0x0001E03C -#define I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_SHIFT 0 -#define I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_SHIFT) -#define I40E_GLPES_TCPRXTHREEHOLELO 0x0001E038 -#define I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_SHIFT 0 -#define I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_SHIFT) -#define I40E_GLPES_TCPRXTWOHOLEHI 0x0001E034 -#define I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_SHIFT 0 -#define I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_SHIFT) -#define I40E_GLPES_TCPRXTWOHOLELO 0x0001E030 -#define I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_SHIFT 0 -#define I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_SHIFT) -#define I40E_GLPES_TCPRXUNEXPERR 0x0001E008 -#define I40E_GLPES_TCPRXUNEXPERR_TCPRXUNEXPERR_SHIFT 0 -#define I40E_GLPES_TCPRXUNEXPERR_TCPRXUNEXPERR_MASK (0xFFFFFF << I40E_GLPES_TCPRXUNEXPERR_TCPRXUNEXPERR_SHIFT) -#define I40E_GLPES_TCPTXRETRANSFASTHI 0x0001E04C -#define I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_SHIFT 0 -#define I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_MASK (0xFFFFFF << I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_SHIFT) -#define I40E_GLPES_TCPTXRETRANSFASTLO 0x0001E048 -#define I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_SHIFT 0 -#define I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_SHIFT) -#define I40E_GLPES_TCPTXTOUTSFASTHI 0x0001E054 -#define I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_SHIFT 0 -#define I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_MASK (0xFFFFFF << I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_SHIFT) -#define I40E_GLPES_TCPTXTOUTSFASTLO 0x0001E050 -#define I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_SHIFT 0 -#define I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_SHIFT) -#define I40E_GLPES_TCPTXTOUTSHI 0x0001E05C -#define I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_SHIFT 0 -#define I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_MASK (0xFFFFFF << I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_SHIFT) -#define I40E_GLPES_TCPTXTOUTSLO 0x0001E058 -#define I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_SHIFT 0 -#define I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_SHIFT) -#define I40E_GLPES_VFIP4RXDISCARD(_i) (0x00018600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXDISCARD_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_SHIFT 0 -#define I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_SHIFT) -#define I40E_GLPES_VFIP4RXFRAGSHI(_i) (0x00018804 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXFRAGSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT 0 -#define I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT) -#define I40E_GLPES_VFIP4RXFRAGSLO(_i) (0x00018800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXFRAGSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT 0 -#define I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT) -#define I40E_GLPES_VFIP4RXMCOCTSHI(_i) (0x00018A04 + ((_i) * 4)) -#define I40E_GLPES_VFIP4RXMCOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT) -#define I40E_GLPES_VFIP4RXMCOCTSLO(_i) (0x00018A00 + ((_i) * 4)) -#define I40E_GLPES_VFIP4RXMCOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT) -#define I40E_GLPES_VFIP4RXMCPKTSHI(_i) (0x00018C04 + ((_i) * 4)) -#define I40E_GLPES_VFIP4RXMCPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT) -#define I40E_GLPES_VFIP4RXMCPKTSLO(_i) (0x00018C00 + ((_i) * 4)) -#define I40E_GLPES_VFIP4RXMCPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT) -#define I40E_GLPES_VFIP4RXOCTSHI(_i) (0x00018204 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT) -#define I40E_GLPES_VFIP4RXOCTSLO(_i) (0x00018200 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT) -#define I40E_GLPES_VFIP4RXPKTSHI(_i) (0x00018404 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT) -#define I40E_GLPES_VFIP4RXPKTSLO(_i) (0x00018400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT) -#define I40E_GLPES_VFIP4RXTRUNC(_i) (0x00018700 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXTRUNC_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_SHIFT 0 -#define I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_SHIFT) -#define I40E_GLPES_VFIP4TXFRAGSHI(_i) (0x00019E04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXFRAGSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT 0 -#define I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT) -#define I40E_GLPES_VFIP4TXFRAGSLO(_i) (0x00019E00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXFRAGSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT 0 -#define I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT) -#define I40E_GLPES_VFIP4TXMCOCTSHI(_i) (0x0001A004 + ((_i) * 4)) -#define I40E_GLPES_VFIP4TXMCOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT) -#define I40E_GLPES_VFIP4TXMCOCTSLO(_i) (0x0001A000 + ((_i) * 4)) -#define I40E_GLPES_VFIP4TXMCOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT) -#define I40E_GLPES_VFIP4TXMCPKTSHI(_i) (0x0001A204 + ((_i) * 4)) -#define I40E_GLPES_VFIP4TXMCPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT) -#define I40E_GLPES_VFIP4TXMCPKTSLO(_i) (0x0001A200 + ((_i) * 4)) -#define I40E_GLPES_VFIP4TXMCPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT) -#define I40E_GLPES_VFIP4TXNOROUTE(_i) (0x0001AE00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXNOROUTE_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT 0 -#define I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT) -#define I40E_GLPES_VFIP4TXOCTSHI(_i) (0x00019A04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT) -#define I40E_GLPES_VFIP4TXOCTSLO(_i) (0x00019A00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT) -#define I40E_GLPES_VFIP4TXPKTSHI(_i) (0x00019C04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT) -#define I40E_GLPES_VFIP4TXPKTSLO(_i) (0x00019C00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT) -#define I40E_GLPES_VFIP6RXDISCARD(_i) (0x00019200 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXDISCARD_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_SHIFT 0 -#define I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_SHIFT) -#define I40E_GLPES_VFIP6RXFRAGSHI(_i) (0x00019404 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXFRAGSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT 0 -#define I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT) -#define I40E_GLPES_VFIP6RXFRAGSLO(_i) (0x00019400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXFRAGSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT 0 -#define I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT) -#define I40E_GLPES_VFIP6RXMCOCTSHI(_i) (0x00019604 + ((_i) * 4)) -#define I40E_GLPES_VFIP6RXMCOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT) -#define I40E_GLPES_VFIP6RXMCOCTSLO(_i) (0x00019600 + ((_i) * 4)) -#define I40E_GLPES_VFIP6RXMCOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT) -#define I40E_GLPES_VFIP6RXMCPKTSHI(_i) (0x00019804 + ((_i) * 4)) -#define I40E_GLPES_VFIP6RXMCPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT) -#define I40E_GLPES_VFIP6RXMCPKTSLO(_i) (0x00019800 + ((_i) * 4)) -#define I40E_GLPES_VFIP6RXMCPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT) -#define I40E_GLPES_VFIP6RXOCTSHI(_i) (0x00018E04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT) -#define I40E_GLPES_VFIP6RXOCTSLO(_i) (0x00018E00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT) -#define I40E_GLPES_VFIP6RXPKTSHI(_i) (0x00019004 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT) -#define I40E_GLPES_VFIP6RXPKTSLO(_i) (0x00019000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT) -#define I40E_GLPES_VFIP6RXTRUNC(_i) (0x00019300 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXTRUNC_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_SHIFT 0 -#define I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_SHIFT) -#define I40E_GLPES_VFIP6TXFRAGSHI(_i) (0x0001A804 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXFRAGSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT 0 -#define I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT) -#define I40E_GLPES_VFIP6TXFRAGSLO(_i) (0x0001A800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXFRAGSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT 0 -#define I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT) -#define I40E_GLPES_VFIP6TXMCOCTSHI(_i) (0x0001AA04 + ((_i) * 4)) -#define I40E_GLPES_VFIP6TXMCOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT) -#define I40E_GLPES_VFIP6TXMCOCTSLO(_i) (0x0001AA00 + ((_i) * 4)) -#define I40E_GLPES_VFIP6TXMCOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT) -#define I40E_GLPES_VFIP6TXMCPKTSHI(_i) (0x0001AC04 + ((_i) * 4)) -#define I40E_GLPES_VFIP6TXMCPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT) -#define I40E_GLPES_VFIP6TXMCPKTSLO(_i) (0x0001AC00 + ((_i) * 4)) -#define I40E_GLPES_VFIP6TXMCPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT) -#define I40E_GLPES_VFIP6TXNOROUTE(_i) (0x0001AF00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXNOROUTE_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT 0 -#define I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT) -#define I40E_GLPES_VFIP6TXOCTSHI(_i) (0x0001A404 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT) -#define I40E_GLPES_VFIP6TXOCTSLO(_i) (0x0001A400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT) -#define I40E_GLPES_VFIP6TXPKTSHI(_i) (0x0001A604 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT) -#define I40E_GLPES_VFIP6TXPKTSLO(_i) (0x0001A600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT) -#define I40E_GLPES_VFRDMARXRDSHI(_i) (0x0001BE04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMARXRDSHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_SHIFT 0 -#define I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_SHIFT) -#define I40E_GLPES_VFRDMARXRDSLO(_i) (0x0001BE00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMARXRDSLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_SHIFT 0 -#define I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_SHIFT) -#define I40E_GLPES_VFRDMARXSNDSHI(_i) (0x0001C004 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMARXSNDSHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT 0 -#define I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT) -#define I40E_GLPES_VFRDMARXSNDSLO(_i) (0x0001C000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMARXSNDSLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT 0 -#define I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT) -#define I40E_GLPES_VFRDMARXWRSHI(_i) (0x0001BC04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMARXWRSHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_SHIFT 0 -#define I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_SHIFT) -#define I40E_GLPES_VFRDMARXWRSLO(_i) (0x0001BC00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMARXWRSLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_SHIFT 0 -#define I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_SHIFT) -#define I40E_GLPES_VFRDMATXRDSHI(_i) (0x0001C404 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMATXRDSHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_SHIFT 0 -#define I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_SHIFT) -#define I40E_GLPES_VFRDMATXRDSLO(_i) (0x0001C400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMATXRDSLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_SHIFT 0 -#define I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_SHIFT) -#define I40E_GLPES_VFRDMATXSNDSHI(_i) (0x0001C604 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMATXSNDSHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT 0 -#define I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT) -#define I40E_GLPES_VFRDMATXSNDSLO(_i) (0x0001C600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMATXSNDSLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT 0 -#define I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT) -#define I40E_GLPES_VFRDMATXWRSHI(_i) (0x0001C204 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMATXWRSHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_SHIFT 0 -#define I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_SHIFT) -#define I40E_GLPES_VFRDMATXWRSLO(_i) (0x0001C200 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMATXWRSLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_SHIFT 0 -#define I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_SHIFT) -#define I40E_GLPES_VFRDMAVBNDHI(_i) (0x0001C804 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMAVBNDHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_SHIFT 0 -#define I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_SHIFT) -#define I40E_GLPES_VFRDMAVBNDLO(_i) (0x0001C800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMAVBNDLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_SHIFT 0 -#define I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_SHIFT) -#define I40E_GLPES_VFRDMAVINVHI(_i) (0x0001CA04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMAVINVHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_SHIFT 0 -#define I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_SHIFT) -#define I40E_GLPES_VFRDMAVINVLO(_i) (0x0001CA00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMAVINVLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_SHIFT 0 -#define I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_SHIFT) -#define I40E_GLPES_VFRXVLANERR(_i) (0x00018000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRXVLANERR_MAX_INDEX 31 -#define I40E_GLPES_VFRXVLANERR_RXVLANERR_SHIFT 0 -#define I40E_GLPES_VFRXVLANERR_RXVLANERR_MASK (0xFFFFFF << I40E_GLPES_VFRXVLANERR_RXVLANERR_SHIFT) -#define I40E_GLPES_VFTCPRTXSEG(_i) (0x0001B600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFTCPRTXSEG_MAX_INDEX 31 -#define I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_SHIFT 0 -#define I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_MASK (0xFFFFFFFF << I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_SHIFT) -#define I40E_GLPES_VFTCPRXOPTERR(_i) (0x0001B200 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFTCPRXOPTERR_MAX_INDEX 31 -#define I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_SHIFT 0 -#define I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_MASK (0xFFFFFF << I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_SHIFT) -#define I40E_GLPES_VFTCPRXPROTOERR(_i) (0x0001B300 + ((_i) * 4)) -#define I40E_GLPES_VFTCPRXPROTOERR_MAX_INDEX 31 -#define I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT 0 -#define I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_MASK (0xFFFFFF << I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT) -#define I40E_GLPES_VFTCPRXSEGSHI(_i) (0x0001B004 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFTCPRXSEGSHI_MAX_INDEX 31 -#define I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT 0 -#define I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_MASK (0xFFFF << I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT) -#define I40E_GLPES_VFTCPRXSEGSLO(_i) (0x0001B000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFTCPRXSEGSLO_MAX_INDEX 31 -#define I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT 0 -#define I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT) -#define I40E_GLPES_VFTCPTXSEGHI(_i) (0x0001B404 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFTCPTXSEGHI_MAX_INDEX 31 -#define I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_SHIFT 0 -#define I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_MASK (0xFFFF << I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_SHIFT) -#define I40E_GLPES_VFTCPTXSEGLO(_i) (0x0001B400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFTCPTXSEGLO_MAX_INDEX 31 -#define I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_SHIFT 0 -#define I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_MASK (0xFFFFFFFF << I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_SHIFT) -#define I40E_GLPES_VFUDPRXPKTSHI(_i) (0x0001B804 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFUDPRXPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT 0 -#define I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT) -#define I40E_GLPES_VFUDPRXPKTSLO(_i) (0x0001B800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFUDPRXPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT 0 -#define I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT) -#define I40E_GLPES_VFUDPTXPKTSHI(_i) (0x0001BA04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFUDPTXPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT 0 -#define I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT) -#define I40E_GLPES_VFUDPTXPKTSLO(_i) (0x0001BA00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFUDPTXPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT 0 -#define I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT) -#define I40E_PRTPM_EEE_STAT 0x001E4320 +#define I40E_PFPCI_VMPEND_PENDING_MASK I40E_MASK(0x1, I40E_PFPCI_VMPEND_PENDING_SHIFT) +#define I40E_PRTPM_EEE_STAT 0x001E4320 /* Reset: GLOBR */ #define I40E_PRTPM_EEE_STAT_EEE_NEG_SHIFT 29 -#define I40E_PRTPM_EEE_STAT_EEE_NEG_MASK (0x1 << I40E_PRTPM_EEE_STAT_EEE_NEG_SHIFT) +#define I40E_PRTPM_EEE_STAT_EEE_NEG_MASK I40E_MASK(0x1, I40E_PRTPM_EEE_STAT_EEE_NEG_SHIFT) #define I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT 30 -#define I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_MASK (0x1 << I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT) +#define I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_MASK I40E_MASK(0x1, I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT) #define I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT 31 -#define I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_MASK (0x1 << I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT) -#define I40E_PRTPM_EEEC 0x001E4380 +#define I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_MASK I40E_MASK(0x1, I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT) +#define I40E_PRTPM_EEEC 0x001E4380 /* Reset: GLOBR */ #define I40E_PRTPM_EEEC_TW_WAKE_MIN_SHIFT 16 -#define I40E_PRTPM_EEEC_TW_WAKE_MIN_MASK (0x3F << I40E_PRTPM_EEEC_TW_WAKE_MIN_SHIFT) +#define I40E_PRTPM_EEEC_TW_WAKE_MIN_MASK I40E_MASK(0x3F, I40E_PRTPM_EEEC_TW_WAKE_MIN_SHIFT) #define I40E_PRTPM_EEEC_TX_LU_LPI_DLY_SHIFT 24 -#define I40E_PRTPM_EEEC_TX_LU_LPI_DLY_MASK (0x3 << I40E_PRTPM_EEEC_TX_LU_LPI_DLY_SHIFT) +#define I40E_PRTPM_EEEC_TX_LU_LPI_DLY_MASK I40E_MASK(0x3, I40E_PRTPM_EEEC_TX_LU_LPI_DLY_SHIFT) #define I40E_PRTPM_EEEC_TEEE_DLY_SHIFT 26 -#define I40E_PRTPM_EEEC_TEEE_DLY_MASK (0x3F << I40E_PRTPM_EEEC_TEEE_DLY_SHIFT) -#define I40E_PRTPM_EEEFWD 0x001E4400 +#define I40E_PRTPM_EEEC_TEEE_DLY_MASK I40E_MASK(0x3F, I40E_PRTPM_EEEC_TEEE_DLY_SHIFT) +#define I40E_PRTPM_EEEFWD 0x001E4400 /* Reset: GLOBR */ #define I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_SHIFT 31 -#define I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_MASK (0x1 << I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_SHIFT) -#define I40E_PRTPM_EEER 0x001E4360 +#define I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_MASK I40E_MASK(0x1, I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_SHIFT) +#define I40E_PRTPM_EEER 0x001E4360 /* Reset: GLOBR */ #define I40E_PRTPM_EEER_TW_SYSTEM_SHIFT 0 -#define I40E_PRTPM_EEER_TW_SYSTEM_MASK (0xFFFF << I40E_PRTPM_EEER_TW_SYSTEM_SHIFT) +#define I40E_PRTPM_EEER_TW_SYSTEM_MASK I40E_MASK(0xFFFF, I40E_PRTPM_EEER_TW_SYSTEM_SHIFT) #define I40E_PRTPM_EEER_TX_LPI_EN_SHIFT 16 -#define I40E_PRTPM_EEER_TX_LPI_EN_MASK (0x1 << I40E_PRTPM_EEER_TX_LPI_EN_SHIFT) -#define I40E_PRTPM_EEETXC 0x001E43E0 +#define I40E_PRTPM_EEER_TX_LPI_EN_MASK I40E_MASK(0x1, I40E_PRTPM_EEER_TX_LPI_EN_SHIFT) +#define I40E_PRTPM_EEETXC 0x001E43E0 /* Reset: GLOBR */ #define I40E_PRTPM_EEETXC_TW_PHY_SHIFT 0 -#define I40E_PRTPM_EEETXC_TW_PHY_MASK (0xFFFF << I40E_PRTPM_EEETXC_TW_PHY_SHIFT) -#define I40E_PRTPM_GC 0x000B8140 +#define I40E_PRTPM_EEETXC_TW_PHY_MASK I40E_MASK(0xFFFF, I40E_PRTPM_EEETXC_TW_PHY_SHIFT) +#define I40E_PRTPM_GC 0x000B8140 /* Reset: POR */ #define I40E_PRTPM_GC_EMP_LINK_ON_SHIFT 0 -#define I40E_PRTPM_GC_EMP_LINK_ON_MASK (0x1 << I40E_PRTPM_GC_EMP_LINK_ON_SHIFT) +#define I40E_PRTPM_GC_EMP_LINK_ON_MASK I40E_MASK(0x1, I40E_PRTPM_GC_EMP_LINK_ON_SHIFT) #define I40E_PRTPM_GC_MNG_VETO_SHIFT 1 -#define I40E_PRTPM_GC_MNG_VETO_MASK (0x1 << I40E_PRTPM_GC_MNG_VETO_SHIFT) +#define I40E_PRTPM_GC_MNG_VETO_MASK I40E_MASK(0x1, I40E_PRTPM_GC_MNG_VETO_SHIFT) #define I40E_PRTPM_GC_RATD_SHIFT 2 -#define I40E_PRTPM_GC_RATD_MASK (0x1 << I40E_PRTPM_GC_RATD_SHIFT) +#define I40E_PRTPM_GC_RATD_MASK I40E_MASK(0x1, I40E_PRTPM_GC_RATD_SHIFT) #define I40E_PRTPM_GC_LCDMP_SHIFT 3 -#define I40E_PRTPM_GC_LCDMP_MASK (0x1 << I40E_PRTPM_GC_LCDMP_SHIFT) +#define I40E_PRTPM_GC_LCDMP_MASK I40E_MASK(0x1, I40E_PRTPM_GC_LCDMP_SHIFT) #define I40E_PRTPM_GC_LPLU_ASSERTED_SHIFT 31 -#define I40E_PRTPM_GC_LPLU_ASSERTED_MASK (0x1 << I40E_PRTPM_GC_LPLU_ASSERTED_SHIFT) -#define I40E_PRTPM_RLPIC 0x001E43A0 +#define I40E_PRTPM_GC_LPLU_ASSERTED_MASK I40E_MASK(0x1, I40E_PRTPM_GC_LPLU_ASSERTED_SHIFT) +#define I40E_PRTPM_RLPIC 0x001E43A0 /* Reset: GLOBR */ #define I40E_PRTPM_RLPIC_ERLPIC_SHIFT 0 -#define I40E_PRTPM_RLPIC_ERLPIC_MASK (0xFFFFFFFF << I40E_PRTPM_RLPIC_ERLPIC_SHIFT) -#define I40E_PRTPM_TLPIC 0x001E43C0 +#define I40E_PRTPM_RLPIC_ERLPIC_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTPM_RLPIC_ERLPIC_SHIFT) +#define I40E_PRTPM_TLPIC 0x001E43C0 /* Reset: GLOBR */ #define I40E_PRTPM_TLPIC_ETLPIC_SHIFT 0 -#define I40E_PRTPM_TLPIC_ETLPIC_MASK (0xFFFFFFFF << I40E_PRTPM_TLPIC_ETLPIC_SHIFT) -#define I40E_GLRPB_DPSS 0x000AC828 +#define I40E_PRTPM_TLPIC_ETLPIC_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTPM_TLPIC_ETLPIC_SHIFT) +#define I40E_GLRPB_DPSS 0x000AC828 /* Reset: CORER */ #define I40E_GLRPB_DPSS_DPS_TCN_SHIFT 0 -#define I40E_GLRPB_DPSS_DPS_TCN_MASK (0xFFFFF << I40E_GLRPB_DPSS_DPS_TCN_SHIFT) -#define I40E_GLRPB_GHW 0x000AC830 +#define I40E_GLRPB_DPSS_DPS_TCN_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_DPSS_DPS_TCN_SHIFT) +#define I40E_GLRPB_GHW 0x000AC830 /* Reset: CORER */ #define I40E_GLRPB_GHW_GHW_SHIFT 0 -#define I40E_GLRPB_GHW_GHW_MASK (0xFFFFF << I40E_GLRPB_GHW_GHW_SHIFT) -#define I40E_GLRPB_GLW 0x000AC834 +#define I40E_GLRPB_GHW_GHW_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_GHW_GHW_SHIFT) +#define I40E_GLRPB_GLW 0x000AC834 /* Reset: CORER */ #define I40E_GLRPB_GLW_GLW_SHIFT 0 -#define I40E_GLRPB_GLW_GLW_MASK (0xFFFFF << I40E_GLRPB_GLW_GLW_SHIFT) -#define I40E_GLRPB_PHW 0x000AC844 +#define I40E_GLRPB_GLW_GLW_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_GLW_GLW_SHIFT) +#define I40E_GLRPB_PHW 0x000AC844 /* Reset: CORER */ #define I40E_GLRPB_PHW_PHW_SHIFT 0 -#define I40E_GLRPB_PHW_PHW_MASK (0xFFFFF << I40E_GLRPB_PHW_PHW_SHIFT) -#define I40E_GLRPB_PLW 0x000AC848 +#define I40E_GLRPB_PHW_PHW_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_PHW_PHW_SHIFT) +#define I40E_GLRPB_PLW 0x000AC848 /* Reset: CORER */ #define I40E_GLRPB_PLW_PLW_SHIFT 0 -#define I40E_GLRPB_PLW_PLW_MASK (0xFFFFF << I40E_GLRPB_PLW_PLW_SHIFT) -#define I40E_PRTRPB_DHW(_i) (0x000AC100 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_GLRPB_PLW_PLW_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_PLW_PLW_SHIFT) +#define I40E_PRTRPB_DHW(_i) (0x000AC100 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTRPB_DHW_MAX_INDEX 7 #define I40E_PRTRPB_DHW_DHW_TCN_SHIFT 0 -#define I40E_PRTRPB_DHW_DHW_TCN_MASK (0xFFFFF << I40E_PRTRPB_DHW_DHW_TCN_SHIFT) -#define I40E_PRTRPB_DLW(_i) (0x000AC220 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTRPB_DHW_DHW_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_DHW_DHW_TCN_SHIFT) +#define I40E_PRTRPB_DLW(_i) (0x000AC220 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTRPB_DLW_MAX_INDEX 7 #define I40E_PRTRPB_DLW_DLW_TCN_SHIFT 0 -#define I40E_PRTRPB_DLW_DLW_TCN_MASK (0xFFFFF << I40E_PRTRPB_DLW_DLW_TCN_SHIFT) -#define I40E_PRTRPB_DPS(_i) (0x000AC320 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTRPB_DLW_DLW_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_DLW_DLW_TCN_SHIFT) +#define I40E_PRTRPB_DPS(_i) (0x000AC320 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTRPB_DPS_MAX_INDEX 7 #define I40E_PRTRPB_DPS_DPS_TCN_SHIFT 0 -#define I40E_PRTRPB_DPS_DPS_TCN_MASK (0xFFFFF << I40E_PRTRPB_DPS_DPS_TCN_SHIFT) -#define I40E_PRTRPB_SHT(_i) (0x000AC480 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTRPB_DPS_DPS_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_DPS_DPS_TCN_SHIFT) +#define I40E_PRTRPB_SHT(_i) (0x000AC480 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTRPB_SHT_MAX_INDEX 7 #define I40E_PRTRPB_SHT_SHT_TCN_SHIFT 0 -#define I40E_PRTRPB_SHT_SHT_TCN_MASK (0xFFFFF << I40E_PRTRPB_SHT_SHT_TCN_SHIFT) -#define I40E_PRTRPB_SHW 0x000AC580 +#define I40E_PRTRPB_SHT_SHT_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SHT_SHT_TCN_SHIFT) +#define I40E_PRTRPB_SHW 0x000AC580 /* Reset: CORER */ #define I40E_PRTRPB_SHW_SHW_SHIFT 0 -#define I40E_PRTRPB_SHW_SHW_MASK (0xFFFFF << I40E_PRTRPB_SHW_SHW_SHIFT) -#define I40E_PRTRPB_SLT(_i) (0x000AC5A0 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTRPB_SHW_SHW_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SHW_SHW_SHIFT) +#define I40E_PRTRPB_SLT(_i) (0x000AC5A0 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTRPB_SLT_MAX_INDEX 7 #define I40E_PRTRPB_SLT_SLT_TCN_SHIFT 0 -#define I40E_PRTRPB_SLT_SLT_TCN_MASK (0xFFFFF << I40E_PRTRPB_SLT_SLT_TCN_SHIFT) -#define I40E_PRTRPB_SLW 0x000AC6A0 +#define I40E_PRTRPB_SLT_SLT_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SLT_SLT_TCN_SHIFT) +#define I40E_PRTRPB_SLW 0x000AC6A0 /* Reset: CORER */ #define I40E_PRTRPB_SLW_SLW_SHIFT 0 -#define I40E_PRTRPB_SLW_SLW_MASK (0xFFFFF << I40E_PRTRPB_SLW_SLW_SHIFT) -#define I40E_PRTRPB_SPS 0x000AC7C0 +#define I40E_PRTRPB_SLW_SLW_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SLW_SLW_SHIFT) +#define I40E_PRTRPB_SPS 0x000AC7C0 /* Reset: CORER */ #define I40E_PRTRPB_SPS_SPS_SHIFT 0 -#define I40E_PRTRPB_SPS_SPS_MASK (0xFFFFF << I40E_PRTRPB_SPS_SPS_SHIFT) -#define I40E_GLQF_APBVT(_i) (0x00260000 + ((_i) * 4)) /* _i=0...2047 */ -#define I40E_GLQF_APBVT_MAX_INDEX 2047 -#define I40E_GLQF_APBVT_APBVT_SHIFT 0 -#define I40E_GLQF_APBVT_APBVT_MASK (0xFFFFFFFF << I40E_GLQF_APBVT_APBVT_SHIFT) -#define I40E_GLQF_CTL 0x00269BA4 +#define I40E_PRTRPB_SPS_SPS_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SPS_SPS_SHIFT) +#define I40E_GLQF_CTL 0x00269BA4 /* Reset: CORER */ #define I40E_GLQF_CTL_HTOEP_SHIFT 1 -#define I40E_GLQF_CTL_HTOEP_MASK (0x1 << I40E_GLQF_CTL_HTOEP_SHIFT) +#define I40E_GLQF_CTL_HTOEP_MASK I40E_MASK(0x1, I40E_GLQF_CTL_HTOEP_SHIFT) #define I40E_GLQF_CTL_HTOEP_FCOE_SHIFT 2 -#define I40E_GLQF_CTL_HTOEP_FCOE_MASK (0x1 << I40E_GLQF_CTL_HTOEP_FCOE_SHIFT) +#define I40E_GLQF_CTL_HTOEP_FCOE_MASK I40E_MASK(0x1, I40E_GLQF_CTL_HTOEP_FCOE_SHIFT) #define I40E_GLQF_CTL_PCNT_ALLOC_SHIFT 3 -#define I40E_GLQF_CTL_PCNT_ALLOC_MASK (0x7 << I40E_GLQF_CTL_PCNT_ALLOC_SHIFT) +#define I40E_GLQF_CTL_PCNT_ALLOC_MASK I40E_MASK(0x7, I40E_GLQF_CTL_PCNT_ALLOC_SHIFT) +#define I40E_GLQF_CTL_FD_AUTO_PCTYPE_SHIFT 6 +#define I40E_GLQF_CTL_FD_AUTO_PCTYPE_MASK I40E_MASK(0x1, I40E_GLQF_CTL_FD_AUTO_PCTYPE_SHIFT) #define I40E_GLQF_CTL_RSVD_SHIFT 7 -#define I40E_GLQF_CTL_RSVD_MASK (0x1 << I40E_GLQF_CTL_RSVD_SHIFT) +#define I40E_GLQF_CTL_RSVD_MASK I40E_MASK(0x1, I40E_GLQF_CTL_RSVD_SHIFT) #define I40E_GLQF_CTL_MAXPEBLEN_SHIFT 8 -#define I40E_GLQF_CTL_MAXPEBLEN_MASK (0x7 << I40E_GLQF_CTL_MAXPEBLEN_SHIFT) +#define I40E_GLQF_CTL_MAXPEBLEN_MASK I40E_MASK(0x7, I40E_GLQF_CTL_MAXPEBLEN_SHIFT) #define I40E_GLQF_CTL_MAXFCBLEN_SHIFT 11 -#define I40E_GLQF_CTL_MAXFCBLEN_MASK (0x7 << I40E_GLQF_CTL_MAXFCBLEN_SHIFT) +#define I40E_GLQF_CTL_MAXFCBLEN_MASK I40E_MASK(0x7, I40E_GLQF_CTL_MAXFCBLEN_SHIFT) #define I40E_GLQF_CTL_MAXFDBLEN_SHIFT 14 -#define I40E_GLQF_CTL_MAXFDBLEN_MASK (0x7 << I40E_GLQF_CTL_MAXFDBLEN_SHIFT) +#define I40E_GLQF_CTL_MAXFDBLEN_MASK I40E_MASK(0x7, I40E_GLQF_CTL_MAXFDBLEN_SHIFT) #define I40E_GLQF_CTL_FDBEST_SHIFT 17 -#define I40E_GLQF_CTL_FDBEST_MASK (0xFF << I40E_GLQF_CTL_FDBEST_SHIFT) +#define I40E_GLQF_CTL_FDBEST_MASK I40E_MASK(0xFF, I40E_GLQF_CTL_FDBEST_SHIFT) #define I40E_GLQF_CTL_PROGPRIO_SHIFT 25 -#define I40E_GLQF_CTL_PROGPRIO_MASK (0x1 << I40E_GLQF_CTL_PROGPRIO_SHIFT) +#define I40E_GLQF_CTL_PROGPRIO_MASK I40E_MASK(0x1, I40E_GLQF_CTL_PROGPRIO_SHIFT) #define I40E_GLQF_CTL_INVALPRIO_SHIFT 26 -#define I40E_GLQF_CTL_INVALPRIO_MASK (0x1 << I40E_GLQF_CTL_INVALPRIO_SHIFT) +#define I40E_GLQF_CTL_INVALPRIO_MASK I40E_MASK(0x1, I40E_GLQF_CTL_INVALPRIO_SHIFT) #define I40E_GLQF_CTL_IGNORE_IP_SHIFT 27 -#define I40E_GLQF_CTL_IGNORE_IP_MASK (0x1 << I40E_GLQF_CTL_IGNORE_IP_SHIFT) -#define I40E_GLQF_FDCNT_0 0x00269BAC +#define I40E_GLQF_CTL_IGNORE_IP_MASK I40E_MASK(0x1, I40E_GLQF_CTL_IGNORE_IP_SHIFT) +#define I40E_GLQF_FDCNT_0 0x00269BAC /* Reset: CORER */ #define I40E_GLQF_FDCNT_0_GUARANT_CNT_SHIFT 0 -#define I40E_GLQF_FDCNT_0_GUARANT_CNT_MASK (0x1FFF << I40E_GLQF_FDCNT_0_GUARANT_CNT_SHIFT) +#define I40E_GLQF_FDCNT_0_GUARANT_CNT_MASK I40E_MASK(0x1FFF, I40E_GLQF_FDCNT_0_GUARANT_CNT_SHIFT) #define I40E_GLQF_FDCNT_0_BESTCNT_SHIFT 13 -#define I40E_GLQF_FDCNT_0_BESTCNT_MASK (0x1FFF << I40E_GLQF_FDCNT_0_BESTCNT_SHIFT) -#define I40E_GLQF_HSYM(_i) (0x00269D00 + ((_i) * 4)) /* _i=0...63 */ +#define I40E_GLQF_FDCNT_0_BESTCNT_MASK I40E_MASK(0x1FFF, I40E_GLQF_FDCNT_0_BESTCNT_SHIFT) +#define I40E_GLQF_HKEY(_i) (0x00270140 + ((_i) * 4)) /* _i=0...12 */ /* Reset: CORER */ +#define I40E_GLQF_HKEY_MAX_INDEX 12 +#define I40E_GLQF_HKEY_KEY_0_SHIFT 0 +#define I40E_GLQF_HKEY_KEY_0_MASK I40E_MASK(0xFF, I40E_GLQF_HKEY_KEY_0_SHIFT) +#define I40E_GLQF_HKEY_KEY_1_SHIFT 8 +#define I40E_GLQF_HKEY_KEY_1_MASK I40E_MASK(0xFF, I40E_GLQF_HKEY_KEY_1_SHIFT) +#define I40E_GLQF_HKEY_KEY_2_SHIFT 16 +#define I40E_GLQF_HKEY_KEY_2_MASK I40E_MASK(0xFF, I40E_GLQF_HKEY_KEY_2_SHIFT) +#define I40E_GLQF_HKEY_KEY_3_SHIFT 24 +#define I40E_GLQF_HKEY_KEY_3_MASK I40E_MASK(0xFF, I40E_GLQF_HKEY_KEY_3_SHIFT) +#define I40E_GLQF_HSYM(_i) (0x00269D00 + ((_i) * 4)) /* _i=0...63 */ /* Reset: CORER */ #define I40E_GLQF_HSYM_MAX_INDEX 63 #define I40E_GLQF_HSYM_SYMH_ENA_SHIFT 0 -#define I40E_GLQF_HSYM_SYMH_ENA_MASK (0x1 << I40E_GLQF_HSYM_SYMH_ENA_SHIFT) -#define I40E_GLQF_PCNT(_i) (0x00266800 + ((_i) * 4)) /* _i=0...511 */ +#define I40E_GLQF_HSYM_SYMH_ENA_MASK I40E_MASK(0x1, I40E_GLQF_HSYM_SYMH_ENA_SHIFT) +#define I40E_GLQF_PCNT(_i) (0x00266800 + ((_i) * 4)) /* _i=0...511 */ /* Reset: CORER */ #define I40E_GLQF_PCNT_MAX_INDEX 511 #define I40E_GLQF_PCNT_PCNT_SHIFT 0 -#define I40E_GLQF_PCNT_PCNT_MASK (0xFFFFFFFF << I40E_GLQF_PCNT_PCNT_SHIFT) -#define I40E_GLQF_SWAP(_i, _j) (0x00267E00 + ((_i) * 4 + (_j) * 8)) /* _i=0...1, _j=0...63 */ +#define I40E_GLQF_PCNT_PCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLQF_PCNT_PCNT_SHIFT) +#define I40E_GLQF_SWAP(_i, _j) (0x00267E00 + ((_i) * 4 + (_j) * 8)) /* _i=0...1, _j=0...63 */ /* Reset: CORER */ #define I40E_GLQF_SWAP_MAX_INDEX 1 #define I40E_GLQF_SWAP_OFF0_SRC0_SHIFT 0 -#define I40E_GLQF_SWAP_OFF0_SRC0_MASK (0x3F << I40E_GLQF_SWAP_OFF0_SRC0_SHIFT) +#define I40E_GLQF_SWAP_OFF0_SRC0_MASK I40E_MASK(0x3F, I40E_GLQF_SWAP_OFF0_SRC0_SHIFT) #define I40E_GLQF_SWAP_OFF0_SRC1_SHIFT 6 -#define I40E_GLQF_SWAP_OFF0_SRC1_MASK (0x3F << I40E_GLQF_SWAP_OFF0_SRC1_SHIFT) +#define I40E_GLQF_SWAP_OFF0_SRC1_MASK I40E_MASK(0x3F, I40E_GLQF_SWAP_OFF0_SRC1_SHIFT) #define I40E_GLQF_SWAP_FLEN0_SHIFT 12 -#define I40E_GLQF_SWAP_FLEN0_MASK (0xF << I40E_GLQF_SWAP_FLEN0_SHIFT) +#define I40E_GLQF_SWAP_FLEN0_MASK I40E_MASK(0xF, I40E_GLQF_SWAP_FLEN0_SHIFT) #define I40E_GLQF_SWAP_OFF1_SRC0_SHIFT 16 -#define I40E_GLQF_SWAP_OFF1_SRC0_MASK (0x3F << I40E_GLQF_SWAP_OFF1_SRC0_SHIFT) +#define I40E_GLQF_SWAP_OFF1_SRC0_MASK I40E_MASK(0x3F, I40E_GLQF_SWAP_OFF1_SRC0_SHIFT) #define I40E_GLQF_SWAP_OFF1_SRC1_SHIFT 22 -#define I40E_GLQF_SWAP_OFF1_SRC1_MASK (0x3F << I40E_GLQF_SWAP_OFF1_SRC1_SHIFT) +#define I40E_GLQF_SWAP_OFF1_SRC1_MASK I40E_MASK(0x3F, I40E_GLQF_SWAP_OFF1_SRC1_SHIFT) #define I40E_GLQF_SWAP_FLEN1_SHIFT 28 -#define I40E_GLQF_SWAP_FLEN1_MASK (0xF << I40E_GLQF_SWAP_FLEN1_SHIFT) -#define I40E_PFQF_CTL_0 0x001C0AC0 +#define I40E_GLQF_SWAP_FLEN1_MASK I40E_MASK(0xF, I40E_GLQF_SWAP_FLEN1_SHIFT) +#define I40E_PFQF_CTL_0 0x001C0AC0 /* Reset: CORER */ #define I40E_PFQF_CTL_0_PEHSIZE_SHIFT 0 -#define I40E_PFQF_CTL_0_PEHSIZE_MASK (0x1F << I40E_PFQF_CTL_0_PEHSIZE_SHIFT) +#define I40E_PFQF_CTL_0_PEHSIZE_MASK I40E_MASK(0x1F, I40E_PFQF_CTL_0_PEHSIZE_SHIFT) #define I40E_PFQF_CTL_0_PEDSIZE_SHIFT 5 -#define I40E_PFQF_CTL_0_PEDSIZE_MASK (0x1F << I40E_PFQF_CTL_0_PEDSIZE_SHIFT) +#define I40E_PFQF_CTL_0_PEDSIZE_MASK I40E_MASK(0x1F, I40E_PFQF_CTL_0_PEDSIZE_SHIFT) #define I40E_PFQF_CTL_0_PFFCHSIZE_SHIFT 10 -#define I40E_PFQF_CTL_0_PFFCHSIZE_MASK (0xF << I40E_PFQF_CTL_0_PFFCHSIZE_SHIFT) +#define I40E_PFQF_CTL_0_PFFCHSIZE_MASK I40E_MASK(0xF, I40E_PFQF_CTL_0_PFFCHSIZE_SHIFT) #define I40E_PFQF_CTL_0_PFFCDSIZE_SHIFT 14 -#define I40E_PFQF_CTL_0_PFFCDSIZE_MASK (0x3 << I40E_PFQF_CTL_0_PFFCDSIZE_SHIFT) +#define I40E_PFQF_CTL_0_PFFCDSIZE_MASK I40E_MASK(0x3, I40E_PFQF_CTL_0_PFFCDSIZE_SHIFT) #define I40E_PFQF_CTL_0_HASHLUTSIZE_SHIFT 16 -#define I40E_PFQF_CTL_0_HASHLUTSIZE_MASK (0x1 << I40E_PFQF_CTL_0_HASHLUTSIZE_SHIFT) +#define I40E_PFQF_CTL_0_HASHLUTSIZE_MASK I40E_MASK(0x1, I40E_PFQF_CTL_0_HASHLUTSIZE_SHIFT) #define I40E_PFQF_CTL_0_FD_ENA_SHIFT 17 -#define I40E_PFQF_CTL_0_FD_ENA_MASK (0x1 << I40E_PFQF_CTL_0_FD_ENA_SHIFT) +#define I40E_PFQF_CTL_0_FD_ENA_MASK I40E_MASK(0x1, I40E_PFQF_CTL_0_FD_ENA_SHIFT) #define I40E_PFQF_CTL_0_ETYPE_ENA_SHIFT 18 -#define I40E_PFQF_CTL_0_ETYPE_ENA_MASK (0x1 << I40E_PFQF_CTL_0_ETYPE_ENA_SHIFT) +#define I40E_PFQF_CTL_0_ETYPE_ENA_MASK I40E_MASK(0x1, I40E_PFQF_CTL_0_ETYPE_ENA_SHIFT) #define I40E_PFQF_CTL_0_MACVLAN_ENA_SHIFT 19 -#define I40E_PFQF_CTL_0_MACVLAN_ENA_MASK (0x1 << I40E_PFQF_CTL_0_MACVLAN_ENA_SHIFT) +#define I40E_PFQF_CTL_0_MACVLAN_ENA_MASK I40E_MASK(0x1, I40E_PFQF_CTL_0_MACVLAN_ENA_SHIFT) #define I40E_PFQF_CTL_0_VFFCHSIZE_SHIFT 20 -#define I40E_PFQF_CTL_0_VFFCHSIZE_MASK (0xF << I40E_PFQF_CTL_0_VFFCHSIZE_SHIFT) +#define I40E_PFQF_CTL_0_VFFCHSIZE_MASK I40E_MASK(0xF, I40E_PFQF_CTL_0_VFFCHSIZE_SHIFT) #define I40E_PFQF_CTL_0_VFFCDSIZE_SHIFT 24 -#define I40E_PFQF_CTL_0_VFFCDSIZE_MASK (0x3 << I40E_PFQF_CTL_0_VFFCDSIZE_SHIFT) -#define I40E_PFQF_CTL_1 0x00245D80 +#define I40E_PFQF_CTL_0_VFFCDSIZE_MASK I40E_MASK(0x3, I40E_PFQF_CTL_0_VFFCDSIZE_SHIFT) +#define I40E_PFQF_CTL_1 0x00245D80 /* Reset: CORER */ #define I40E_PFQF_CTL_1_CLEARFDTABLE_SHIFT 0 -#define I40E_PFQF_CTL_1_CLEARFDTABLE_MASK (0x1 << I40E_PFQF_CTL_1_CLEARFDTABLE_SHIFT) -#define I40E_PFQF_FDALLOC 0x00246280 +#define I40E_PFQF_CTL_1_CLEARFDTABLE_MASK I40E_MASK(0x1, I40E_PFQF_CTL_1_CLEARFDTABLE_SHIFT) +#define I40E_PFQF_FDALLOC 0x00246280 /* Reset: CORER */ #define I40E_PFQF_FDALLOC_FDALLOC_SHIFT 0 -#define I40E_PFQF_FDALLOC_FDALLOC_MASK (0xFF << I40E_PFQF_FDALLOC_FDALLOC_SHIFT) +#define I40E_PFQF_FDALLOC_FDALLOC_MASK I40E_MASK(0xFF, I40E_PFQF_FDALLOC_FDALLOC_SHIFT) #define I40E_PFQF_FDALLOC_FDBEST_SHIFT 8 -#define I40E_PFQF_FDALLOC_FDBEST_MASK (0xFF << I40E_PFQF_FDALLOC_FDBEST_SHIFT) -#define I40E_PFQF_FDSTAT 0x00246380 +#define I40E_PFQF_FDALLOC_FDBEST_MASK I40E_MASK(0xFF, I40E_PFQF_FDALLOC_FDBEST_SHIFT) +#define I40E_PFQF_FDSTAT 0x00246380 /* Reset: CORER */ #define I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT 0 -#define I40E_PFQF_FDSTAT_GUARANT_CNT_MASK (0x1FFF << I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT) +#define I40E_PFQF_FDSTAT_GUARANT_CNT_MASK I40E_MASK(0x1FFF, I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT) #define I40E_PFQF_FDSTAT_BEST_CNT_SHIFT 16 -#define I40E_PFQF_FDSTAT_BEST_CNT_MASK (0x1FFF << I40E_PFQF_FDSTAT_BEST_CNT_SHIFT) -#define I40E_PFQF_HENA(_i) (0x00245900 + ((_i) * 128)) /* _i=0...1 */ +#define I40E_PFQF_FDSTAT_BEST_CNT_MASK I40E_MASK(0x1FFF, I40E_PFQF_FDSTAT_BEST_CNT_SHIFT) +#define I40E_PFQF_HENA(_i) (0x00245900 + ((_i) * 128)) /* _i=0...1 */ /* Reset: CORER */ #define I40E_PFQF_HENA_MAX_INDEX 1 #define I40E_PFQF_HENA_PTYPE_ENA_SHIFT 0 -#define I40E_PFQF_HENA_PTYPE_ENA_MASK (0xFFFFFFFF << I40E_PFQF_HENA_PTYPE_ENA_SHIFT) -#define I40E_PFQF_HKEY(_i) (0x00244800 + ((_i) * 128)) /* _i=0...12 */ +#define I40E_PFQF_HENA_PTYPE_ENA_MASK I40E_MASK(0xFFFFFFFF, I40E_PFQF_HENA_PTYPE_ENA_SHIFT) +#define I40E_PFQF_HKEY(_i) (0x00244800 + ((_i) * 128)) /* _i=0...12 */ /* Reset: CORER */ #define I40E_PFQF_HKEY_MAX_INDEX 12 #define I40E_PFQF_HKEY_KEY_0_SHIFT 0 -#define I40E_PFQF_HKEY_KEY_0_MASK (0xFF << I40E_PFQF_HKEY_KEY_0_SHIFT) +#define I40E_PFQF_HKEY_KEY_0_MASK I40E_MASK(0xFF, I40E_PFQF_HKEY_KEY_0_SHIFT) #define I40E_PFQF_HKEY_KEY_1_SHIFT 8 -#define I40E_PFQF_HKEY_KEY_1_MASK (0xFF << I40E_PFQF_HKEY_KEY_1_SHIFT) +#define I40E_PFQF_HKEY_KEY_1_MASK I40E_MASK(0xFF, I40E_PFQF_HKEY_KEY_1_SHIFT) #define I40E_PFQF_HKEY_KEY_2_SHIFT 16 -#define I40E_PFQF_HKEY_KEY_2_MASK (0xFF << I40E_PFQF_HKEY_KEY_2_SHIFT) +#define I40E_PFQF_HKEY_KEY_2_MASK I40E_MASK(0xFF, I40E_PFQF_HKEY_KEY_2_SHIFT) #define I40E_PFQF_HKEY_KEY_3_SHIFT 24 -#define I40E_PFQF_HKEY_KEY_3_MASK (0xFF << I40E_PFQF_HKEY_KEY_3_SHIFT) -#define I40E_PFQF_HLUT(_i) (0x00240000 + ((_i) * 128)) /* _i=0...127 */ +#define I40E_PFQF_HKEY_KEY_3_MASK I40E_MASK(0xFF, I40E_PFQF_HKEY_KEY_3_SHIFT) +#define I40E_PFQF_HLUT(_i) (0x00240000 + ((_i) * 128)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_PFQF_HLUT_MAX_INDEX 127 #define I40E_PFQF_HLUT_LUT0_SHIFT 0 -#define I40E_PFQF_HLUT_LUT0_MASK (0x3F << I40E_PFQF_HLUT_LUT0_SHIFT) +#define I40E_PFQF_HLUT_LUT0_MASK I40E_MASK(0x3F, I40E_PFQF_HLUT_LUT0_SHIFT) #define I40E_PFQF_HLUT_LUT1_SHIFT 8 -#define I40E_PFQF_HLUT_LUT1_MASK (0x3F << I40E_PFQF_HLUT_LUT1_SHIFT) +#define I40E_PFQF_HLUT_LUT1_MASK I40E_MASK(0x3F, I40E_PFQF_HLUT_LUT1_SHIFT) #define I40E_PFQF_HLUT_LUT2_SHIFT 16 -#define I40E_PFQF_HLUT_LUT2_MASK (0x3F << I40E_PFQF_HLUT_LUT2_SHIFT) +#define I40E_PFQF_HLUT_LUT2_MASK I40E_MASK(0x3F, I40E_PFQF_HLUT_LUT2_SHIFT) #define I40E_PFQF_HLUT_LUT3_SHIFT 24 -#define I40E_PFQF_HLUT_LUT3_MASK (0x3F << I40E_PFQF_HLUT_LUT3_SHIFT) -#define I40E_PFQF_HREGION(_i) (0x00245400 + ((_i) * 128)) /* _i=0...7 */ -#define I40E_PFQF_HREGION_MAX_INDEX 7 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_0_SHIFT 0 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_0_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_0_SHIFT) -#define I40E_PFQF_HREGION_REGION_0_SHIFT 1 -#define I40E_PFQF_HREGION_REGION_0_MASK (0x7 << I40E_PFQF_HREGION_REGION_0_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_1_SHIFT 4 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_1_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_1_SHIFT) -#define I40E_PFQF_HREGION_REGION_1_SHIFT 5 -#define I40E_PFQF_HREGION_REGION_1_MASK (0x7 << I40E_PFQF_HREGION_REGION_1_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_2_SHIFT 8 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_2_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_2_SHIFT) -#define I40E_PFQF_HREGION_REGION_2_SHIFT 9 -#define I40E_PFQF_HREGION_REGION_2_MASK (0x7 << I40E_PFQF_HREGION_REGION_2_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_3_SHIFT 12 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_3_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_3_SHIFT) -#define I40E_PFQF_HREGION_REGION_3_SHIFT 13 -#define I40E_PFQF_HREGION_REGION_3_MASK (0x7 << I40E_PFQF_HREGION_REGION_3_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_4_SHIFT 16 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_4_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_4_SHIFT) -#define I40E_PFQF_HREGION_REGION_4_SHIFT 17 -#define I40E_PFQF_HREGION_REGION_4_MASK (0x7 << I40E_PFQF_HREGION_REGION_4_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_5_SHIFT 20 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_5_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_5_SHIFT) -#define I40E_PFQF_HREGION_REGION_5_SHIFT 21 -#define I40E_PFQF_HREGION_REGION_5_MASK (0x7 << I40E_PFQF_HREGION_REGION_5_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_6_SHIFT 24 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_6_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_6_SHIFT) -#define I40E_PFQF_HREGION_REGION_6_SHIFT 25 -#define I40E_PFQF_HREGION_REGION_6_MASK (0x7 << I40E_PFQF_HREGION_REGION_6_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_7_SHIFT 28 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_7_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_7_SHIFT) -#define I40E_PFQF_HREGION_REGION_7_SHIFT 29 -#define I40E_PFQF_HREGION_REGION_7_MASK (0x7 << I40E_PFQF_HREGION_REGION_7_SHIFT) -#define I40E_PRTQF_CTL_0 0x00256E60 +#define I40E_PFQF_HLUT_LUT3_MASK I40E_MASK(0x3F, I40E_PFQF_HLUT_LUT3_SHIFT) +#define I40E_PRTQF_CTL_0 0x00256E60 /* Reset: CORER */ #define I40E_PRTQF_CTL_0_HSYM_ENA_SHIFT 0 -#define I40E_PRTQF_CTL_0_HSYM_ENA_MASK (0x1 << I40E_PRTQF_CTL_0_HSYM_ENA_SHIFT) -#define I40E_PRTQF_FD_FLXINSET(_i) (0x00253800 + ((_i) * 32)) /* _i=0...63 */ +#define I40E_PRTQF_CTL_0_HSYM_ENA_MASK I40E_MASK(0x1, I40E_PRTQF_CTL_0_HSYM_ENA_SHIFT) +#define I40E_PRTQF_FD_FLXINSET(_i) (0x00253800 + ((_i) * 32)) /* _i=0...63 */ /* Reset: CORER */ #define I40E_PRTQF_FD_FLXINSET_MAX_INDEX 63 #define I40E_PRTQF_FD_FLXINSET_INSET_SHIFT 0 -#define I40E_PRTQF_FD_FLXINSET_INSET_MASK (0xFF << I40E_PRTQF_FD_FLXINSET_INSET_SHIFT) -#define I40E_PRTQF_FD_MSK(_i, _j) (0x00252000 + ((_i) * 64 + (_j) * 32)) /* _i=0...63, _j=0...1 */ +#define I40E_PRTQF_FD_FLXINSET_INSET_MASK I40E_MASK(0xFF, I40E_PRTQF_FD_FLXINSET_INSET_SHIFT) +#define I40E_PRTQF_FD_MSK(_i, _j) (0x00252000 + ((_i) * 64 + (_j) * 32)) /* _i=0...63, _j=0...1 */ /* Reset: CORER */ #define I40E_PRTQF_FD_MSK_MAX_INDEX 63 #define I40E_PRTQF_FD_MSK_MASK_SHIFT 0 -#define I40E_PRTQF_FD_MSK_MASK_MASK (0xFFFF << I40E_PRTQF_FD_MSK_MASK_SHIFT) +#define I40E_PRTQF_FD_MSK_MASK_MASK I40E_MASK(0xFFFF, I40E_PRTQF_FD_MSK_MASK_SHIFT) #define I40E_PRTQF_FD_MSK_OFFSET_SHIFT 16 -#define I40E_PRTQF_FD_MSK_OFFSET_MASK (0x3F << I40E_PRTQF_FD_MSK_OFFSET_SHIFT) -#define I40E_PRTQF_FLX_PIT(_i) (0x00255200 + ((_i) * 32)) /* _i=0...8 */ +#define I40E_PRTQF_FD_MSK_OFFSET_MASK I40E_MASK(0x3F, I40E_PRTQF_FD_MSK_OFFSET_SHIFT) +#define I40E_PRTQF_FLX_PIT(_i) (0x00255200 + ((_i) * 32)) /* _i=0...8 */ /* Reset: CORER */ #define I40E_PRTQF_FLX_PIT_MAX_INDEX 8 #define I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT 0 -#define I40E_PRTQF_FLX_PIT_SOURCE_OFF_MASK (0x1F << I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT) +#define I40E_PRTQF_FLX_PIT_SOURCE_OFF_MASK I40E_MASK(0x1F, I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT) #define I40E_PRTQF_FLX_PIT_FSIZE_SHIFT 5 -#define I40E_PRTQF_FLX_PIT_FSIZE_MASK (0x1F << I40E_PRTQF_FLX_PIT_FSIZE_SHIFT) +#define I40E_PRTQF_FLX_PIT_FSIZE_MASK I40E_MASK(0x1F, I40E_PRTQF_FLX_PIT_FSIZE_SHIFT) #define I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT 10 -#define I40E_PRTQF_FLX_PIT_DEST_OFF_MASK (0x3F << I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT) -#define I40E_VFQF_HENA1(_i, _VF) (0x00230800 + ((_i) * 1024 + (_VF) * 4)) +#define I40E_PRTQF_FLX_PIT_DEST_OFF_MASK I40E_MASK(0x3F, I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT) +#define I40E_VFQF_HENA1(_i, _VF) (0x00230800 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...1, _VF=0...127 */ /* Reset: CORER */ #define I40E_VFQF_HENA1_MAX_INDEX 1 #define I40E_VFQF_HENA1_PTYPE_ENA_SHIFT 0 -#define I40E_VFQF_HENA1_PTYPE_ENA_MASK (0xFFFFFFFF << I40E_VFQF_HENA1_PTYPE_ENA_SHIFT) -#define I40E_VFQF_HKEY1(_i, _VF) (0x00228000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...12, _VF=0...127 */ +#define I40E_VFQF_HENA1_PTYPE_ENA_MASK I40E_MASK(0xFFFFFFFF, I40E_VFQF_HENA1_PTYPE_ENA_SHIFT) +#define I40E_VFQF_HKEY1(_i, _VF) (0x00228000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...12, _VF=0...127 */ /* Reset: CORER */ #define I40E_VFQF_HKEY1_MAX_INDEX 12 #define I40E_VFQF_HKEY1_KEY_0_SHIFT 0 -#define I40E_VFQF_HKEY1_KEY_0_MASK (0xFF << I40E_VFQF_HKEY1_KEY_0_SHIFT) +#define I40E_VFQF_HKEY1_KEY_0_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY1_KEY_0_SHIFT) #define I40E_VFQF_HKEY1_KEY_1_SHIFT 8 -#define I40E_VFQF_HKEY1_KEY_1_MASK (0xFF << I40E_VFQF_HKEY1_KEY_1_SHIFT) +#define I40E_VFQF_HKEY1_KEY_1_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY1_KEY_1_SHIFT) #define I40E_VFQF_HKEY1_KEY_2_SHIFT 16 -#define I40E_VFQF_HKEY1_KEY_2_MASK (0xFF << I40E_VFQF_HKEY1_KEY_2_SHIFT) +#define I40E_VFQF_HKEY1_KEY_2_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY1_KEY_2_SHIFT) #define I40E_VFQF_HKEY1_KEY_3_SHIFT 24 -#define I40E_VFQF_HKEY1_KEY_3_MASK (0xFF << I40E_VFQF_HKEY1_KEY_3_SHIFT) -#define I40E_VFQF_HLUT1(_i, _VF) (0x00220000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ +#define I40E_VFQF_HKEY1_KEY_3_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY1_KEY_3_SHIFT) +#define I40E_VFQF_HLUT1(_i, _VF) (0x00220000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ /* Reset: CORER */ #define I40E_VFQF_HLUT1_MAX_INDEX 15 #define I40E_VFQF_HLUT1_LUT0_SHIFT 0 -#define I40E_VFQF_HLUT1_LUT0_MASK (0xF << I40E_VFQF_HLUT1_LUT0_SHIFT) +#define I40E_VFQF_HLUT1_LUT0_MASK I40E_MASK(0xF, I40E_VFQF_HLUT1_LUT0_SHIFT) #define I40E_VFQF_HLUT1_LUT1_SHIFT 8 -#define I40E_VFQF_HLUT1_LUT1_MASK (0xF << I40E_VFQF_HLUT1_LUT1_SHIFT) +#define I40E_VFQF_HLUT1_LUT1_MASK I40E_MASK(0xF, I40E_VFQF_HLUT1_LUT1_SHIFT) #define I40E_VFQF_HLUT1_LUT2_SHIFT 16 -#define I40E_VFQF_HLUT1_LUT2_MASK (0xF << I40E_VFQF_HLUT1_LUT2_SHIFT) +#define I40E_VFQF_HLUT1_LUT2_MASK I40E_MASK(0xF, I40E_VFQF_HLUT1_LUT2_SHIFT) #define I40E_VFQF_HLUT1_LUT3_SHIFT 24 -#define I40E_VFQF_HLUT1_LUT3_MASK (0xF << I40E_VFQF_HLUT1_LUT3_SHIFT) -#define I40E_VFQF_HREGION1(_i, _VF) (0x0022E000 + ((_i) * 1024 + (_VF) * 4)) +#define I40E_VFQF_HLUT1_LUT3_MASK I40E_MASK(0xF, I40E_VFQF_HLUT1_LUT3_SHIFT) +#define I40E_VFQF_HREGION1(_i, _VF) (0x0022E000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...7, _VF=0...127 */ /* Reset: CORER */ #define I40E_VFQF_HREGION1_MAX_INDEX 7 #define I40E_VFQF_HREGION1_OVERRIDE_ENA_0_SHIFT 0 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_0_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_0_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_0_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_0_SHIFT) #define I40E_VFQF_HREGION1_REGION_0_SHIFT 1 -#define I40E_VFQF_HREGION1_REGION_0_MASK (0x7 << I40E_VFQF_HREGION1_REGION_0_SHIFT) +#define I40E_VFQF_HREGION1_REGION_0_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_0_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_1_SHIFT 4 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_1_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_1_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_1_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_1_SHIFT) #define I40E_VFQF_HREGION1_REGION_1_SHIFT 5 -#define I40E_VFQF_HREGION1_REGION_1_MASK (0x7 << I40E_VFQF_HREGION1_REGION_1_SHIFT) +#define I40E_VFQF_HREGION1_REGION_1_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_1_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_2_SHIFT 8 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_2_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_2_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_2_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_2_SHIFT) #define I40E_VFQF_HREGION1_REGION_2_SHIFT 9 -#define I40E_VFQF_HREGION1_REGION_2_MASK (0x7 << I40E_VFQF_HREGION1_REGION_2_SHIFT) +#define I40E_VFQF_HREGION1_REGION_2_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_2_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_3_SHIFT 12 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_3_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_3_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_3_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_3_SHIFT) #define I40E_VFQF_HREGION1_REGION_3_SHIFT 13 -#define I40E_VFQF_HREGION1_REGION_3_MASK (0x7 << I40E_VFQF_HREGION1_REGION_3_SHIFT) +#define I40E_VFQF_HREGION1_REGION_3_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_3_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_4_SHIFT 16 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_4_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_4_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_4_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_4_SHIFT) #define I40E_VFQF_HREGION1_REGION_4_SHIFT 17 -#define I40E_VFQF_HREGION1_REGION_4_MASK (0x7 << I40E_VFQF_HREGION1_REGION_4_SHIFT) +#define I40E_VFQF_HREGION1_REGION_4_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_4_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_5_SHIFT 20 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_5_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_5_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_5_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_5_SHIFT) #define I40E_VFQF_HREGION1_REGION_5_SHIFT 21 -#define I40E_VFQF_HREGION1_REGION_5_MASK (0x7 << I40E_VFQF_HREGION1_REGION_5_SHIFT) +#define I40E_VFQF_HREGION1_REGION_5_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_5_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_6_SHIFT 24 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_6_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_6_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_6_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_6_SHIFT) #define I40E_VFQF_HREGION1_REGION_6_SHIFT 25 -#define I40E_VFQF_HREGION1_REGION_6_MASK (0x7 << I40E_VFQF_HREGION1_REGION_6_SHIFT) +#define I40E_VFQF_HREGION1_REGION_6_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_6_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_7_SHIFT 28 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_7_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_7_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_7_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_7_SHIFT) #define I40E_VFQF_HREGION1_REGION_7_SHIFT 29 -#define I40E_VFQF_HREGION1_REGION_7_MASK (0x7 << I40E_VFQF_HREGION1_REGION_7_SHIFT) -#define I40E_VPQF_CTL(_VF) (0x001C0000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFQF_HREGION1_REGION_7_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_7_SHIFT) +#define I40E_VPQF_CTL(_VF) (0x001C0000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VPQF_CTL_MAX_INDEX 127 #define I40E_VPQF_CTL_PEHSIZE_SHIFT 0 -#define I40E_VPQF_CTL_PEHSIZE_MASK (0x1F << I40E_VPQF_CTL_PEHSIZE_SHIFT) +#define I40E_VPQF_CTL_PEHSIZE_MASK I40E_MASK(0x1F, I40E_VPQF_CTL_PEHSIZE_SHIFT) #define I40E_VPQF_CTL_PEDSIZE_SHIFT 5 -#define I40E_VPQF_CTL_PEDSIZE_MASK (0x1F << I40E_VPQF_CTL_PEDSIZE_SHIFT) +#define I40E_VPQF_CTL_PEDSIZE_MASK I40E_MASK(0x1F, I40E_VPQF_CTL_PEDSIZE_SHIFT) #define I40E_VPQF_CTL_FCHSIZE_SHIFT 10 -#define I40E_VPQF_CTL_FCHSIZE_MASK (0xF << I40E_VPQF_CTL_FCHSIZE_SHIFT) +#define I40E_VPQF_CTL_FCHSIZE_MASK I40E_MASK(0xF, I40E_VPQF_CTL_FCHSIZE_SHIFT) #define I40E_VPQF_CTL_FCDSIZE_SHIFT 14 -#define I40E_VPQF_CTL_FCDSIZE_MASK (0x3 << I40E_VPQF_CTL_FCDSIZE_SHIFT) -#define I40E_VSIQF_CTL(_VSI) (0x0020D800 + ((_VSI) * 4)) /* _i=0...383 */ +#define I40E_VPQF_CTL_FCDSIZE_MASK I40E_MASK(0x3, I40E_VPQF_CTL_FCDSIZE_SHIFT) +#define I40E_VSIQF_CTL(_VSI) (0x0020D800 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: PFR */ #define I40E_VSIQF_CTL_MAX_INDEX 383 #define I40E_VSIQF_CTL_FCOE_ENA_SHIFT 0 -#define I40E_VSIQF_CTL_FCOE_ENA_MASK (0x1 << I40E_VSIQF_CTL_FCOE_ENA_SHIFT) +#define I40E_VSIQF_CTL_FCOE_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_FCOE_ENA_SHIFT) #define I40E_VSIQF_CTL_PETCP_ENA_SHIFT 1 -#define I40E_VSIQF_CTL_PETCP_ENA_MASK (0x1 << I40E_VSIQF_CTL_PETCP_ENA_SHIFT) +#define I40E_VSIQF_CTL_PETCP_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PETCP_ENA_SHIFT) #define I40E_VSIQF_CTL_PEUUDP_ENA_SHIFT 2 -#define I40E_VSIQF_CTL_PEUUDP_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEUUDP_ENA_SHIFT) +#define I40E_VSIQF_CTL_PEUUDP_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PEUUDP_ENA_SHIFT) #define I40E_VSIQF_CTL_PEMUDP_ENA_SHIFT 3 -#define I40E_VSIQF_CTL_PEMUDP_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEMUDP_ENA_SHIFT) +#define I40E_VSIQF_CTL_PEMUDP_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PEMUDP_ENA_SHIFT) #define I40E_VSIQF_CTL_PEUFRAG_ENA_SHIFT 4 -#define I40E_VSIQF_CTL_PEUFRAG_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEUFRAG_ENA_SHIFT) +#define I40E_VSIQF_CTL_PEUFRAG_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PEUFRAG_ENA_SHIFT) #define I40E_VSIQF_CTL_PEMFRAG_ENA_SHIFT 5 -#define I40E_VSIQF_CTL_PEMFRAG_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEMFRAG_ENA_SHIFT) -#define I40E_VSIQF_TCREGION(_i, _VSI) (0x00206000 + ((_i) * 2048 + (_VSI) * 4)) +#define I40E_VSIQF_CTL_PEMFRAG_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PEMFRAG_ENA_SHIFT) +#define I40E_VSIQF_TCREGION(_i, _VSI) (0x00206000 + ((_i) * 2048 + (_VSI) * 4)) /* _i=0...3, _VSI=0...383 */ /* Reset: PFR */ #define I40E_VSIQF_TCREGION_MAX_INDEX 3 #define I40E_VSIQF_TCREGION_TC_OFFSET_SHIFT 0 -#define I40E_VSIQF_TCREGION_TC_OFFSET_MASK (0x1FF << I40E_VSIQF_TCREGION_TC_OFFSET_SHIFT) +#define I40E_VSIQF_TCREGION_TC_OFFSET_MASK I40E_MASK(0x1FF, I40E_VSIQF_TCREGION_TC_OFFSET_SHIFT) #define I40E_VSIQF_TCREGION_TC_SIZE_SHIFT 9 -#define I40E_VSIQF_TCREGION_TC_SIZE_MASK (0x7 << I40E_VSIQF_TCREGION_TC_SIZE_SHIFT) +#define I40E_VSIQF_TCREGION_TC_SIZE_MASK I40E_MASK(0x7, I40E_VSIQF_TCREGION_TC_SIZE_SHIFT) #define I40E_VSIQF_TCREGION_TC_OFFSET2_SHIFT 16 -#define I40E_VSIQF_TCREGION_TC_OFFSET2_MASK (0x1FF << I40E_VSIQF_TCREGION_TC_OFFSET2_SHIFT) +#define I40E_VSIQF_TCREGION_TC_OFFSET2_MASK I40E_MASK(0x1FF, I40E_VSIQF_TCREGION_TC_OFFSET2_SHIFT) #define I40E_VSIQF_TCREGION_TC_SIZE2_SHIFT 25 -#define I40E_VSIQF_TCREGION_TC_SIZE2_MASK (0x7 << I40E_VSIQF_TCREGION_TC_SIZE2_SHIFT) -#define I40E_GL_FCOECRC(_i) (0x00314d80 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_VSIQF_TCREGION_TC_SIZE2_MASK I40E_MASK(0x7, I40E_VSIQF_TCREGION_TC_SIZE2_SHIFT) +#define I40E_GL_FCOECRC(_i) (0x00314d80 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOECRC_MAX_INDEX 143 #define I40E_GL_FCOECRC_FCOECRC_SHIFT 0 -#define I40E_GL_FCOECRC_FCOECRC_MASK (0xFFFFFFFF << I40E_GL_FCOECRC_FCOECRC_SHIFT) -#define I40E_GL_FCOEDDPC(_i) (0x00314480 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOECRC_FCOECRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOECRC_FCOECRC_SHIFT) +#define I40E_GL_FCOEDDPC(_i) (0x00314480 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDDPC_MAX_INDEX 143 #define I40E_GL_FCOEDDPC_FCOEDDPC_SHIFT 0 -#define I40E_GL_FCOEDDPC_FCOEDDPC_MASK (0xFFFFFFFF << I40E_GL_FCOEDDPC_FCOEDDPC_SHIFT) -/* _i=0...143 */ -#define I40E_GL_FCOEDIFEC(_i) (0x00318480 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDDPC_FCOEDDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDDPC_FCOEDDPC_SHIFT) +#define I40E_GL_FCOEDIFEC(_i) (0x00318480 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDIFEC_MAX_INDEX 143 #define I40E_GL_FCOEDIFEC_FCOEDIFRC_SHIFT 0 -#define I40E_GL_FCOEDIFEC_FCOEDIFRC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIFEC_FCOEDIFRC_SHIFT) -#define I40E_GL_FCOEDIFRC(_i) (0x00318000 + ((_i) * 8)) /* _i=0...143 */ -#define I40E_GL_FCOEDIFRC_MAX_INDEX 143 -#define I40E_GL_FCOEDIFRC_FCOEDIFRC_SHIFT 0 -#define I40E_GL_FCOEDIFRC_FCOEDIFRC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIFRC_FCOEDIFRC_SHIFT) -#define I40E_GL_FCOEDIFTCL(_i) (0x00354000 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDIFEC_FCOEDIFRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDIFEC_FCOEDIFRC_SHIFT) +#define I40E_GL_FCOEDIFTCL(_i) (0x00354000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDIFTCL_MAX_INDEX 143 #define I40E_GL_FCOEDIFTCL_FCOEDIFTC_SHIFT 0 -#define I40E_GL_FCOEDIFTCL_FCOEDIFTC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIFTCL_FCOEDIFTC_SHIFT) -#define I40E_GL_FCOEDIXAC(_i) (0x0031c000 + ((_i) * 8)) /* _i=0...143 */ -#define I40E_GL_FCOEDIXAC_MAX_INDEX 143 -#define I40E_GL_FCOEDIXAC_FCOEDIXAC_SHIFT 0 -#define I40E_GL_FCOEDIXAC_FCOEDIXAC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIXAC_FCOEDIXAC_SHIFT) -#define I40E_GL_FCOEDIXEC(_i) (0x0034c000 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDIFTCL_FCOEDIFTC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDIFTCL_FCOEDIFTC_SHIFT) +#define I40E_GL_FCOEDIXEC(_i) (0x0034c000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDIXEC_MAX_INDEX 143 #define I40E_GL_FCOEDIXEC_FCOEDIXEC_SHIFT 0 -#define I40E_GL_FCOEDIXEC_FCOEDIXEC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIXEC_FCOEDIXEC_SHIFT) -#define I40E_GL_FCOEDIXVC(_i) (0x00350000 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDIXEC_FCOEDIXEC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDIXEC_FCOEDIXEC_SHIFT) +#define I40E_GL_FCOEDIXVC(_i) (0x00350000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDIXVC_MAX_INDEX 143 #define I40E_GL_FCOEDIXVC_FCOEDIXVC_SHIFT 0 -#define I40E_GL_FCOEDIXVC_FCOEDIXVC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIXVC_FCOEDIXVC_SHIFT) -#define I40E_GL_FCOEDWRCH(_i) (0x00320004 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDIXVC_FCOEDIXVC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDIXVC_FCOEDIXVC_SHIFT) +#define I40E_GL_FCOEDWRCH(_i) (0x00320004 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDWRCH_MAX_INDEX 143 #define I40E_GL_FCOEDWRCH_FCOEDWRCH_SHIFT 0 -#define I40E_GL_FCOEDWRCH_FCOEDWRCH_MASK (0xFFFF << I40E_GL_FCOEDWRCH_FCOEDWRCH_SHIFT) -#define I40E_GL_FCOEDWRCL(_i) (0x00320000 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDWRCH_FCOEDWRCH_MASK I40E_MASK(0xFFFF, I40E_GL_FCOEDWRCH_FCOEDWRCH_SHIFT) +#define I40E_GL_FCOEDWRCL(_i) (0x00320000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDWRCL_MAX_INDEX 143 #define I40E_GL_FCOEDWRCL_FCOEDWRCL_SHIFT 0 -#define I40E_GL_FCOEDWRCL_FCOEDWRCL_MASK (0xFFFFFFFF << I40E_GL_FCOEDWRCL_FCOEDWRCL_SHIFT) -#define I40E_GL_FCOEDWTCH(_i) (0x00348084 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDWRCL_FCOEDWRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDWRCL_FCOEDWRCL_SHIFT) +#define I40E_GL_FCOEDWTCH(_i) (0x00348084 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDWTCH_MAX_INDEX 143 #define I40E_GL_FCOEDWTCH_FCOEDWTCH_SHIFT 0 -#define I40E_GL_FCOEDWTCH_FCOEDWTCH_MASK (0xFFFF << I40E_GL_FCOEDWTCH_FCOEDWTCH_SHIFT) -#define I40E_GL_FCOEDWTCL(_i) (0x00348080 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDWTCH_FCOEDWTCH_MASK I40E_MASK(0xFFFF, I40E_GL_FCOEDWTCH_FCOEDWTCH_SHIFT) +#define I40E_GL_FCOEDWTCL(_i) (0x00348080 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDWTCL_MAX_INDEX 143 #define I40E_GL_FCOEDWTCL_FCOEDWTCL_SHIFT 0 -#define I40E_GL_FCOEDWTCL_FCOEDWTCL_MASK (0xFFFFFFFF << I40E_GL_FCOEDWTCL_FCOEDWTCL_SHIFT) -#define I40E_GL_FCOELAST(_i) (0x00314000 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDWTCL_FCOEDWTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDWTCL_FCOEDWTCL_SHIFT) +#define I40E_GL_FCOELAST(_i) (0x00314000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOELAST_MAX_INDEX 143 #define I40E_GL_FCOELAST_FCOELAST_SHIFT 0 -#define I40E_GL_FCOELAST_FCOELAST_MASK (0xFFFFFFFF << I40E_GL_FCOELAST_FCOELAST_SHIFT) -#define I40E_GL_FCOEPRC(_i) (0x00315200 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOELAST_FCOELAST_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOELAST_FCOELAST_SHIFT) +#define I40E_GL_FCOEPRC(_i) (0x00315200 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEPRC_MAX_INDEX 143 #define I40E_GL_FCOEPRC_FCOEPRC_SHIFT 0 -#define I40E_GL_FCOEPRC_FCOEPRC_MASK (0xFFFFFFFF << I40E_GL_FCOEPRC_FCOEPRC_SHIFT) -#define I40E_GL_FCOEPTC(_i) (0x00344C00 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEPRC_FCOEPRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEPRC_FCOEPRC_SHIFT) +#define I40E_GL_FCOEPTC(_i) (0x00344C00 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEPTC_MAX_INDEX 143 #define I40E_GL_FCOEPTC_FCOEPTC_SHIFT 0 -#define I40E_GL_FCOEPTC_FCOEPTC_MASK (0xFFFFFFFF << I40E_GL_FCOEPTC_FCOEPTC_SHIFT) -#define I40E_GL_FCOERPDC(_i) (0x00324000 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEPTC_FCOEPTC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEPTC_FCOEPTC_SHIFT) +#define I40E_GL_FCOERPDC(_i) (0x00324000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOERPDC_MAX_INDEX 143 #define I40E_GL_FCOERPDC_FCOERPDC_SHIFT 0 -#define I40E_GL_FCOERPDC_FCOERPDC_MASK (0xFFFFFFFF << I40E_GL_FCOERPDC_FCOERPDC_SHIFT) -#define I40E_GLPRT_BPRCH(_i) (0x003005E4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GL_FCOERPDC_FCOERPDC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOERPDC_FCOERPDC_SHIFT) +#define I40E_GL_RXERR1_L(_i) (0x00318000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ +#define I40E_GL_RXERR1_L_MAX_INDEX 143 +#define I40E_GL_RXERR1_L_FCOEDIFRC_SHIFT 0 +#define I40E_GL_RXERR1_L_FCOEDIFRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR1_L_FCOEDIFRC_SHIFT) +#define I40E_GL_RXERR2_L(_i) (0x0031c000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ +#define I40E_GL_RXERR2_L_MAX_INDEX 143 +#define I40E_GL_RXERR2_L_FCOEDIXAC_SHIFT 0 +#define I40E_GL_RXERR2_L_FCOEDIXAC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR2_L_FCOEDIXAC_SHIFT) +#define I40E_GLPRT_BPRCH(_i) (0x003005E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_BPRCH_MAX_INDEX 3 #define I40E_GLPRT_BPRCH_UPRCH_SHIFT 0 -#define I40E_GLPRT_BPRCH_UPRCH_MASK (0xFFFF << I40E_GLPRT_BPRCH_UPRCH_SHIFT) -#define I40E_GLPRT_BPRCL(_i) (0x003005E0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_BPRCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_BPRCH_UPRCH_SHIFT) +#define I40E_GLPRT_BPRCL(_i) (0x003005E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_BPRCL_MAX_INDEX 3 #define I40E_GLPRT_BPRCL_UPRCH_SHIFT 0 -#define I40E_GLPRT_BPRCL_UPRCH_MASK (0xFFFFFFFF << I40E_GLPRT_BPRCL_UPRCH_SHIFT) -#define I40E_GLPRT_BPTCH(_i) (0x00300A04 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_BPRCL_UPRCH_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_BPRCL_UPRCH_SHIFT) +#define I40E_GLPRT_BPTCH(_i) (0x00300A04 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_BPTCH_MAX_INDEX 3 #define I40E_GLPRT_BPTCH_UPRCH_SHIFT 0 -#define I40E_GLPRT_BPTCH_UPRCH_MASK (0xFFFF << I40E_GLPRT_BPTCH_UPRCH_SHIFT) -#define I40E_GLPRT_BPTCL(_i) (0x00300A00 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_BPTCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_BPTCH_UPRCH_SHIFT) +#define I40E_GLPRT_BPTCL(_i) (0x00300A00 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_BPTCL_MAX_INDEX 3 #define I40E_GLPRT_BPTCL_UPRCH_SHIFT 0 -#define I40E_GLPRT_BPTCL_UPRCH_MASK (0xFFFFFFFF << I40E_GLPRT_BPTCL_UPRCH_SHIFT) -#define I40E_GLPRT_CRCERRS(_i) (0x00300080 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_BPTCL_UPRCH_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_BPTCL_UPRCH_SHIFT) +#define I40E_GLPRT_CRCERRS(_i) (0x00300080 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_CRCERRS_MAX_INDEX 3 #define I40E_GLPRT_CRCERRS_CRCERRS_SHIFT 0 -#define I40E_GLPRT_CRCERRS_CRCERRS_MASK (0xFFFFFFFF << I40E_GLPRT_CRCERRS_CRCERRS_SHIFT) -#define I40E_GLPRT_GORCH(_i) (0x00300004 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_CRCERRS_CRCERRS_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_CRCERRS_CRCERRS_SHIFT) +#define I40E_GLPRT_GORCH(_i) (0x00300004 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_GORCH_MAX_INDEX 3 #define I40E_GLPRT_GORCH_GORCH_SHIFT 0 -#define I40E_GLPRT_GORCH_GORCH_MASK (0xFFFF << I40E_GLPRT_GORCH_GORCH_SHIFT) -#define I40E_GLPRT_GORCL(_i) (0x00300000 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_GORCH_GORCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_GORCH_GORCH_SHIFT) +#define I40E_GLPRT_GORCL(_i) (0x00300000 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_GORCL_MAX_INDEX 3 #define I40E_GLPRT_GORCL_GORCL_SHIFT 0 -#define I40E_GLPRT_GORCL_GORCL_MASK (0xFFFFFFFF << I40E_GLPRT_GORCL_GORCL_SHIFT) -#define I40E_GLPRT_GOTCH(_i) (0x00300684 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_GORCL_GORCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_GORCL_GORCL_SHIFT) +#define I40E_GLPRT_GOTCH(_i) (0x00300684 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_GOTCH_MAX_INDEX 3 #define I40E_GLPRT_GOTCH_GOTCH_SHIFT 0 -#define I40E_GLPRT_GOTCH_GOTCH_MASK (0xFFFF << I40E_GLPRT_GOTCH_GOTCH_SHIFT) -#define I40E_GLPRT_GOTCL(_i) (0x00300680 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_GOTCH_GOTCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_GOTCH_GOTCH_SHIFT) +#define I40E_GLPRT_GOTCL(_i) (0x00300680 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_GOTCL_MAX_INDEX 3 #define I40E_GLPRT_GOTCL_GOTCL_SHIFT 0 -#define I40E_GLPRT_GOTCL_GOTCL_MASK (0xFFFFFFFF << I40E_GLPRT_GOTCL_GOTCL_SHIFT) -#define I40E_GLPRT_ILLERRC(_i) (0x003000E0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_GOTCL_GOTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_GOTCL_GOTCL_SHIFT) +#define I40E_GLPRT_ILLERRC(_i) (0x003000E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_ILLERRC_MAX_INDEX 3 #define I40E_GLPRT_ILLERRC_ILLERRC_SHIFT 0 -#define I40E_GLPRT_ILLERRC_ILLERRC_MASK (0xFFFFFFFF << I40E_GLPRT_ILLERRC_ILLERRC_SHIFT) -#define I40E_GLPRT_LDPC(_i) (0x00300620 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_ILLERRC_ILLERRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_ILLERRC_ILLERRC_SHIFT) +#define I40E_GLPRT_LDPC(_i) (0x00300620 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_LDPC_MAX_INDEX 3 #define I40E_GLPRT_LDPC_LDPC_SHIFT 0 -#define I40E_GLPRT_LDPC_LDPC_MASK (0xFFFFFFFF << I40E_GLPRT_LDPC_LDPC_SHIFT) -#define I40E_GLPRT_LXOFFRXC(_i) (0x00300160 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_LDPC_LDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LDPC_LDPC_SHIFT) +#define I40E_GLPRT_LXOFFRXC(_i) (0x00300160 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_LXOFFRXC_MAX_INDEX 3 #define I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_SHIFT 0 -#define I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_SHIFT) -#define I40E_GLPRT_LXOFFTXC(_i) (0x003009A0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_SHIFT) +#define I40E_GLPRT_LXOFFTXC(_i) (0x003009A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_LXOFFTXC_MAX_INDEX 3 #define I40E_GLPRT_LXOFFTXC_LXOFFTXC_SHIFT 0 -#define I40E_GLPRT_LXOFFTXC_LXOFFTXC_MASK (0xFFFFFFFF << I40E_GLPRT_LXOFFTXC_LXOFFTXC_SHIFT) -#define I40E_GLPRT_LXONRXC(_i) (0x00300140 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_LXOFFTXC_LXOFFTXC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LXOFFTXC_LXOFFTXC_SHIFT) +#define I40E_GLPRT_LXONRXC(_i) (0x00300140 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_LXONRXC_MAX_INDEX 3 #define I40E_GLPRT_LXONRXC_LXONRXCNT_SHIFT 0 -#define I40E_GLPRT_LXONRXC_LXONRXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_LXONRXC_LXONRXCNT_SHIFT) -#define I40E_GLPRT_LXONTXC(_i) (0x00300980 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_LXONRXC_LXONRXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LXONRXC_LXONRXCNT_SHIFT) +#define I40E_GLPRT_LXONTXC(_i) (0x00300980 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_LXONTXC_MAX_INDEX 3 #define I40E_GLPRT_LXONTXC_LXONTXC_SHIFT 0 -#define I40E_GLPRT_LXONTXC_LXONTXC_MASK (0xFFFFFFFF << I40E_GLPRT_LXONTXC_LXONTXC_SHIFT) -#define I40E_GLPRT_MLFC(_i) (0x00300020 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_LXONTXC_LXONTXC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LXONTXC_LXONTXC_SHIFT) +#define I40E_GLPRT_MLFC(_i) (0x00300020 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_MLFC_MAX_INDEX 3 #define I40E_GLPRT_MLFC_MLFC_SHIFT 0 -#define I40E_GLPRT_MLFC_MLFC_MASK (0xFFFFFFFF << I40E_GLPRT_MLFC_MLFC_SHIFT) -#define I40E_GLPRT_MPRCH(_i) (0x003005C4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_MLFC_MLFC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_MLFC_MLFC_SHIFT) +#define I40E_GLPRT_MPRCH(_i) (0x003005C4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_MPRCH_MAX_INDEX 3 #define I40E_GLPRT_MPRCH_MPRCH_SHIFT 0 -#define I40E_GLPRT_MPRCH_MPRCH_MASK (0xFFFF << I40E_GLPRT_MPRCH_MPRCH_SHIFT) -#define I40E_GLPRT_MPRCL(_i) (0x003005C0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_MPRCH_MPRCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_MPRCH_MPRCH_SHIFT) +#define I40E_GLPRT_MPRCL(_i) (0x003005C0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_MPRCL_MAX_INDEX 3 #define I40E_GLPRT_MPRCL_MPRCL_SHIFT 0 -#define I40E_GLPRT_MPRCL_MPRCL_MASK (0xFFFFFFFF << I40E_GLPRT_MPRCL_MPRCL_SHIFT) -#define I40E_GLPRT_MPTCH(_i) (0x003009E4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_MPRCL_MPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_MPRCL_MPRCL_SHIFT) +#define I40E_GLPRT_MPTCH(_i) (0x003009E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_MPTCH_MAX_INDEX 3 #define I40E_GLPRT_MPTCH_MPTCH_SHIFT 0 -#define I40E_GLPRT_MPTCH_MPTCH_MASK (0xFFFF << I40E_GLPRT_MPTCH_MPTCH_SHIFT) -#define I40E_GLPRT_MPTCL(_i) (0x003009E0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_MPTCH_MPTCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_MPTCH_MPTCH_SHIFT) +#define I40E_GLPRT_MPTCL(_i) (0x003009E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_MPTCL_MAX_INDEX 3 #define I40E_GLPRT_MPTCL_MPTCL_SHIFT 0 -#define I40E_GLPRT_MPTCL_MPTCL_MASK (0xFFFFFFFF << I40E_GLPRT_MPTCL_MPTCL_SHIFT) -#define I40E_GLPRT_MRFC(_i) (0x00300040 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_MPTCL_MPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_MPTCL_MPTCL_SHIFT) +#define I40E_GLPRT_MRFC(_i) (0x00300040 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_MRFC_MAX_INDEX 3 #define I40E_GLPRT_MRFC_MRFC_SHIFT 0 -#define I40E_GLPRT_MRFC_MRFC_MASK (0xFFFFFFFF << I40E_GLPRT_MRFC_MRFC_SHIFT) -#define I40E_GLPRT_PRC1023H(_i) (0x00300504 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_MRFC_MRFC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_MRFC_MRFC_SHIFT) +#define I40E_GLPRT_PRC1023H(_i) (0x00300504 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC1023H_MAX_INDEX 3 #define I40E_GLPRT_PRC1023H_PRC1023H_SHIFT 0 -#define I40E_GLPRT_PRC1023H_PRC1023H_MASK (0xFFFF << I40E_GLPRT_PRC1023H_PRC1023H_SHIFT) -#define I40E_GLPRT_PRC1023L(_i) (0x00300500 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC1023H_PRC1023H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC1023H_PRC1023H_SHIFT) +#define I40E_GLPRT_PRC1023L(_i) (0x00300500 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC1023L_MAX_INDEX 3 #define I40E_GLPRT_PRC1023L_PRC1023L_SHIFT 0 -#define I40E_GLPRT_PRC1023L_PRC1023L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC1023L_PRC1023L_SHIFT) -#define I40E_GLPRT_PRC127H(_i) (0x003004A4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC1023L_PRC1023L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC1023L_PRC1023L_SHIFT) +#define I40E_GLPRT_PRC127H(_i) (0x003004A4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC127H_MAX_INDEX 3 #define I40E_GLPRT_PRC127H_PRC127H_SHIFT 0 -#define I40E_GLPRT_PRC127H_PRC127H_MASK (0xFFFF << I40E_GLPRT_PRC127H_PRC127H_SHIFT) -#define I40E_GLPRT_PRC127L(_i) (0x003004A0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC127H_PRC127H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC127H_PRC127H_SHIFT) +#define I40E_GLPRT_PRC127L(_i) (0x003004A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC127L_MAX_INDEX 3 #define I40E_GLPRT_PRC127L_PRC127L_SHIFT 0 -#define I40E_GLPRT_PRC127L_PRC127L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC127L_PRC127L_SHIFT) -#define I40E_GLPRT_PRC1522H(_i) (0x00300524 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC127L_PRC127L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC127L_PRC127L_SHIFT) +#define I40E_GLPRT_PRC1522H(_i) (0x00300524 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC1522H_MAX_INDEX 3 #define I40E_GLPRT_PRC1522H_PRC1522H_SHIFT 0 -#define I40E_GLPRT_PRC1522H_PRC1522H_MASK (0xFFFF << I40E_GLPRT_PRC1522H_PRC1522H_SHIFT) -#define I40E_GLPRT_PRC1522L(_i) (0x00300520 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC1522H_PRC1522H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC1522H_PRC1522H_SHIFT) +#define I40E_GLPRT_PRC1522L(_i) (0x00300520 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC1522L_MAX_INDEX 3 #define I40E_GLPRT_PRC1522L_PRC1522L_SHIFT 0 -#define I40E_GLPRT_PRC1522L_PRC1522L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC1522L_PRC1522L_SHIFT) -#define I40E_GLPRT_PRC255H(_i) (0x003004C4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC1522L_PRC1522L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC1522L_PRC1522L_SHIFT) +#define I40E_GLPRT_PRC255H(_i) (0x003004C4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC255H_MAX_INDEX 3 #define I40E_GLPRT_PRC255H_PRTPRC255H_SHIFT 0 -#define I40E_GLPRT_PRC255H_PRTPRC255H_MASK (0xFFFF << I40E_GLPRT_PRC255H_PRTPRC255H_SHIFT) -#define I40E_GLPRT_PRC255L(_i) (0x003004C0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC255H_PRTPRC255H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC255H_PRTPRC255H_SHIFT) +#define I40E_GLPRT_PRC255L(_i) (0x003004C0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC255L_MAX_INDEX 3 #define I40E_GLPRT_PRC255L_PRC255L_SHIFT 0 -#define I40E_GLPRT_PRC255L_PRC255L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC255L_PRC255L_SHIFT) -#define I40E_GLPRT_PRC511H(_i) (0x003004E4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC255L_PRC255L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC255L_PRC255L_SHIFT) +#define I40E_GLPRT_PRC511H(_i) (0x003004E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC511H_MAX_INDEX 3 #define I40E_GLPRT_PRC511H_PRC511H_SHIFT 0 -#define I40E_GLPRT_PRC511H_PRC511H_MASK (0xFFFF << I40E_GLPRT_PRC511H_PRC511H_SHIFT) -#define I40E_GLPRT_PRC511L(_i) (0x003004E0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC511H_PRC511H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC511H_PRC511H_SHIFT) +#define I40E_GLPRT_PRC511L(_i) (0x003004E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC511L_MAX_INDEX 3 #define I40E_GLPRT_PRC511L_PRC511L_SHIFT 0 -#define I40E_GLPRT_PRC511L_PRC511L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC511L_PRC511L_SHIFT) -#define I40E_GLPRT_PRC64H(_i) (0x00300484 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC511L_PRC511L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC511L_PRC511L_SHIFT) +#define I40E_GLPRT_PRC64H(_i) (0x00300484 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC64H_MAX_INDEX 3 #define I40E_GLPRT_PRC64H_PRC64H_SHIFT 0 -#define I40E_GLPRT_PRC64H_PRC64H_MASK (0xFFFF << I40E_GLPRT_PRC64H_PRC64H_SHIFT) -#define I40E_GLPRT_PRC64L(_i) (0x00300480 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC64H_PRC64H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC64H_PRC64H_SHIFT) +#define I40E_GLPRT_PRC64L(_i) (0x00300480 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC64L_MAX_INDEX 3 #define I40E_GLPRT_PRC64L_PRC64L_SHIFT 0 -#define I40E_GLPRT_PRC64L_PRC64L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC64L_PRC64L_SHIFT) -#define I40E_GLPRT_PRC9522H(_i) (0x00300544 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC64L_PRC64L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC64L_PRC64L_SHIFT) +#define I40E_GLPRT_PRC9522H(_i) (0x00300544 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC9522H_MAX_INDEX 3 #define I40E_GLPRT_PRC9522H_PRC1522H_SHIFT 0 -#define I40E_GLPRT_PRC9522H_PRC1522H_MASK (0xFFFF << I40E_GLPRT_PRC9522H_PRC1522H_SHIFT) -#define I40E_GLPRT_PRC9522L(_i) (0x00300540 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC9522H_PRC1522H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC9522H_PRC1522H_SHIFT) +#define I40E_GLPRT_PRC9522L(_i) (0x00300540 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC9522L_MAX_INDEX 3 #define I40E_GLPRT_PRC9522L_PRC1522L_SHIFT 0 -#define I40E_GLPRT_PRC9522L_PRC1522L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC9522L_PRC1522L_SHIFT) -#define I40E_GLPRT_PTC1023H(_i) (0x00300724 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC9522L_PRC1522L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC9522L_PRC1522L_SHIFT) +#define I40E_GLPRT_PTC1023H(_i) (0x00300724 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC1023H_MAX_INDEX 3 #define I40E_GLPRT_PTC1023H_PTC1023H_SHIFT 0 -#define I40E_GLPRT_PTC1023H_PTC1023H_MASK (0xFFFF << I40E_GLPRT_PTC1023H_PTC1023H_SHIFT) -#define I40E_GLPRT_PTC1023L(_i) (0x00300720 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC1023H_PTC1023H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC1023H_PTC1023H_SHIFT) +#define I40E_GLPRT_PTC1023L(_i) (0x00300720 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC1023L_MAX_INDEX 3 #define I40E_GLPRT_PTC1023L_PTC1023L_SHIFT 0 -#define I40E_GLPRT_PTC1023L_PTC1023L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC1023L_PTC1023L_SHIFT) -#define I40E_GLPRT_PTC127H(_i) (0x003006C4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC1023L_PTC1023L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC1023L_PTC1023L_SHIFT) +#define I40E_GLPRT_PTC127H(_i) (0x003006C4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC127H_MAX_INDEX 3 #define I40E_GLPRT_PTC127H_PTC127H_SHIFT 0 -#define I40E_GLPRT_PTC127H_PTC127H_MASK (0xFFFF << I40E_GLPRT_PTC127H_PTC127H_SHIFT) -#define I40E_GLPRT_PTC127L(_i) (0x003006C0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC127H_PTC127H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC127H_PTC127H_SHIFT) +#define I40E_GLPRT_PTC127L(_i) (0x003006C0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC127L_MAX_INDEX 3 #define I40E_GLPRT_PTC127L_PTC127L_SHIFT 0 -#define I40E_GLPRT_PTC127L_PTC127L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC127L_PTC127L_SHIFT) -#define I40E_GLPRT_PTC1522H(_i) (0x00300744 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC127L_PTC127L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC127L_PTC127L_SHIFT) +#define I40E_GLPRT_PTC1522H(_i) (0x00300744 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC1522H_MAX_INDEX 3 #define I40E_GLPRT_PTC1522H_PTC1522H_SHIFT 0 -#define I40E_GLPRT_PTC1522H_PTC1522H_MASK (0xFFFF << I40E_GLPRT_PTC1522H_PTC1522H_SHIFT) -#define I40E_GLPRT_PTC1522L(_i) (0x00300740 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC1522H_PTC1522H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC1522H_PTC1522H_SHIFT) +#define I40E_GLPRT_PTC1522L(_i) (0x00300740 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC1522L_MAX_INDEX 3 #define I40E_GLPRT_PTC1522L_PTC1522L_SHIFT 0 -#define I40E_GLPRT_PTC1522L_PTC1522L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC1522L_PTC1522L_SHIFT) -#define I40E_GLPRT_PTC255H(_i) (0x003006E4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC1522L_PTC1522L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC1522L_PTC1522L_SHIFT) +#define I40E_GLPRT_PTC255H(_i) (0x003006E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC255H_MAX_INDEX 3 #define I40E_GLPRT_PTC255H_PTC255H_SHIFT 0 -#define I40E_GLPRT_PTC255H_PTC255H_MASK (0xFFFF << I40E_GLPRT_PTC255H_PTC255H_SHIFT) -#define I40E_GLPRT_PTC255L(_i) (0x003006E0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC255H_PTC255H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC255H_PTC255H_SHIFT) +#define I40E_GLPRT_PTC255L(_i) (0x003006E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC255L_MAX_INDEX 3 #define I40E_GLPRT_PTC255L_PTC255L_SHIFT 0 -#define I40E_GLPRT_PTC255L_PTC255L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC255L_PTC255L_SHIFT) -#define I40E_GLPRT_PTC511H(_i) (0x00300704 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC255L_PTC255L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC255L_PTC255L_SHIFT) +#define I40E_GLPRT_PTC511H(_i) (0x00300704 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC511H_MAX_INDEX 3 #define I40E_GLPRT_PTC511H_PTC511H_SHIFT 0 -#define I40E_GLPRT_PTC511H_PTC511H_MASK (0xFFFF << I40E_GLPRT_PTC511H_PTC511H_SHIFT) -#define I40E_GLPRT_PTC511L(_i) (0x00300700 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC511H_PTC511H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC511H_PTC511H_SHIFT) +#define I40E_GLPRT_PTC511L(_i) (0x00300700 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC511L_MAX_INDEX 3 #define I40E_GLPRT_PTC511L_PTC511L_SHIFT 0 -#define I40E_GLPRT_PTC511L_PTC511L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC511L_PTC511L_SHIFT) -#define I40E_GLPRT_PTC64H(_i) (0x003006A4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC511L_PTC511L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC511L_PTC511L_SHIFT) +#define I40E_GLPRT_PTC64H(_i) (0x003006A4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC64H_MAX_INDEX 3 #define I40E_GLPRT_PTC64H_PTC64H_SHIFT 0 -#define I40E_GLPRT_PTC64H_PTC64H_MASK (0xFFFF << I40E_GLPRT_PTC64H_PTC64H_SHIFT) -#define I40E_GLPRT_PTC64L(_i) (0x003006A0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC64H_PTC64H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC64H_PTC64H_SHIFT) +#define I40E_GLPRT_PTC64L(_i) (0x003006A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC64L_MAX_INDEX 3 #define I40E_GLPRT_PTC64L_PTC64L_SHIFT 0 -#define I40E_GLPRT_PTC64L_PTC64L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC64L_PTC64L_SHIFT) -#define I40E_GLPRT_PTC9522H(_i) (0x00300764 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC64L_PTC64L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC64L_PTC64L_SHIFT) +#define I40E_GLPRT_PTC9522H(_i) (0x00300764 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC9522H_MAX_INDEX 3 #define I40E_GLPRT_PTC9522H_PTC9522H_SHIFT 0 -#define I40E_GLPRT_PTC9522H_PTC9522H_MASK (0xFFFF << I40E_GLPRT_PTC9522H_PTC9522H_SHIFT) -#define I40E_GLPRT_PTC9522L(_i) (0x00300760 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC9522H_PTC9522H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC9522H_PTC9522H_SHIFT) +#define I40E_GLPRT_PTC9522L(_i) (0x00300760 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC9522L_MAX_INDEX 3 #define I40E_GLPRT_PTC9522L_PTC9522L_SHIFT 0 -#define I40E_GLPRT_PTC9522L_PTC9522L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC9522L_PTC9522L_SHIFT) -#define I40E_GLPRT_PXOFFRXC(_i, _j) (0x00300280 + ((_i) * 8 + (_j) * 32)) +#define I40E_GLPRT_PTC9522L_PTC9522L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC9522L_PTC9522L_SHIFT) +#define I40E_GLPRT_PXOFFRXC(_i, _j) (0x00300280 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ #define I40E_GLPRT_PXOFFRXC_MAX_INDEX 3 #define I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_SHIFT 0 -#define I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_SHIFT) -#define I40E_GLPRT_PXOFFTXC(_i, _j) (0x00300880 + ((_i) * 8 + (_j) * 32)) +#define I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_SHIFT) +#define I40E_GLPRT_PXOFFTXC(_i, _j) (0x00300880 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ #define I40E_GLPRT_PXOFFTXC_MAX_INDEX 3 #define I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_SHIFT 0 -#define I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_SHIFT) -#define I40E_GLPRT_PXONRXC(_i, _j) (0x00300180 + ((_i) * 8 + (_j) * 32)) +#define I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_SHIFT) +#define I40E_GLPRT_PXONRXC(_i, _j) (0x00300180 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ #define I40E_GLPRT_PXONRXC_MAX_INDEX 3 #define I40E_GLPRT_PXONRXC_PRPXONRXCNT_SHIFT 0 -#define I40E_GLPRT_PXONRXC_PRPXONRXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_PXONRXC_PRPXONRXCNT_SHIFT) -#define I40E_GLPRT_PXONTXC(_i, _j) (0x00300780 + ((_i) * 8 + (_j) * 32)) +#define I40E_GLPRT_PXONRXC_PRPXONRXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PXONRXC_PRPXONRXCNT_SHIFT) +#define I40E_GLPRT_PXONTXC(_i, _j) (0x00300780 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ #define I40E_GLPRT_PXONTXC_MAX_INDEX 3 #define I40E_GLPRT_PXONTXC_PRPXONTXC_SHIFT 0 -#define I40E_GLPRT_PXONTXC_PRPXONTXC_MASK (0xFFFFFFFF << I40E_GLPRT_PXONTXC_PRPXONTXC_SHIFT) -#define I40E_GLPRT_RDPC(_i) (0x00300600 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PXONTXC_PRPXONTXC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PXONTXC_PRPXONTXC_SHIFT) +#define I40E_GLPRT_RDPC(_i) (0x00300600 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_RDPC_MAX_INDEX 3 #define I40E_GLPRT_RDPC_RDPC_SHIFT 0 -#define I40E_GLPRT_RDPC_RDPC_MASK (0xFFFFFFFF << I40E_GLPRT_RDPC_RDPC_SHIFT) -#define I40E_GLPRT_RFC(_i) (0x00300560 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_RDPC_RDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RDPC_RDPC_SHIFT) +#define I40E_GLPRT_RFC(_i) (0x00300560 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_RFC_MAX_INDEX 3 #define I40E_GLPRT_RFC_RFC_SHIFT 0 -#define I40E_GLPRT_RFC_RFC_MASK (0xFFFFFFFF << I40E_GLPRT_RFC_RFC_SHIFT) -#define I40E_GLPRT_RJC(_i) (0x00300580 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_RFC_RFC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RFC_RFC_SHIFT) +#define I40E_GLPRT_RJC(_i) (0x00300580 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_RJC_MAX_INDEX 3 #define I40E_GLPRT_RJC_RJC_SHIFT 0 -#define I40E_GLPRT_RJC_RJC_MASK (0xFFFFFFFF << I40E_GLPRT_RJC_RJC_SHIFT) -#define I40E_GLPRT_RLEC(_i) (0x003000A0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_RJC_RJC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RJC_RJC_SHIFT) +#define I40E_GLPRT_RLEC(_i) (0x003000A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_RLEC_MAX_INDEX 3 #define I40E_GLPRT_RLEC_RLEC_SHIFT 0 -#define I40E_GLPRT_RLEC_RLEC_MASK (0xFFFFFFFF << I40E_GLPRT_RLEC_RLEC_SHIFT) -#define I40E_GLPRT_ROC(_i) (0x00300120 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_RLEC_RLEC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RLEC_RLEC_SHIFT) +#define I40E_GLPRT_ROC(_i) (0x00300120 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_ROC_MAX_INDEX 3 #define I40E_GLPRT_ROC_ROC_SHIFT 0 -#define I40E_GLPRT_ROC_ROC_MASK (0xFFFFFFFF << I40E_GLPRT_ROC_ROC_SHIFT) -#define I40E_GLPRT_RUC(_i) (0x00300100 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_ROC_ROC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_ROC_ROC_SHIFT) +#define I40E_GLPRT_RUC(_i) (0x00300100 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_RUC_MAX_INDEX 3 #define I40E_GLPRT_RUC_RUC_SHIFT 0 -#define I40E_GLPRT_RUC_RUC_MASK (0xFFFFFFFF << I40E_GLPRT_RUC_RUC_SHIFT) -#define I40E_GLPRT_RUPP(_i) (0x00300660 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_RUC_RUC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RUC_RUC_SHIFT) +#define I40E_GLPRT_RUPP(_i) (0x00300660 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_RUPP_MAX_INDEX 3 #define I40E_GLPRT_RUPP_RUPP_SHIFT 0 -#define I40E_GLPRT_RUPP_RUPP_MASK (0xFFFFFFFF << I40E_GLPRT_RUPP_RUPP_SHIFT) -#define I40E_GLPRT_RXON2OFFCNT(_i, _j) (0x00300380 + ((_i) * 8 + (_j) * 32)) +#define I40E_GLPRT_RUPP_RUPP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RUPP_RUPP_SHIFT) +#define I40E_GLPRT_RXON2OFFCNT(_i, _j) (0x00300380 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ #define I40E_GLPRT_RXON2OFFCNT_MAX_INDEX 3 #define I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_SHIFT 0 -#define I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_MASK (0xFFFFFFFF << I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_SHIFT) -#define I40E_GLPRT_STDC(_i) (0x00300640 + ((_i) * 8)) /* _i=0...3 */ -#define I40E_GLPRT_STDC_MAX_INDEX 3 -#define I40E_GLPRT_STDC_STDC_SHIFT 0 -#define I40E_GLPRT_STDC_STDC_MASK (0xFFFFFFFF << I40E_GLPRT_STDC_STDC_SHIFT) -#define I40E_GLPRT_TDOLD(_i) (0x00300A20 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_SHIFT) +#define I40E_GLPRT_TDOLD(_i) (0x00300A20 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_TDOLD_MAX_INDEX 3 #define I40E_GLPRT_TDOLD_GLPRT_TDOLD_SHIFT 0 -#define I40E_GLPRT_TDOLD_GLPRT_TDOLD_MASK (0xFFFFFFFF << I40E_GLPRT_TDOLD_GLPRT_TDOLD_SHIFT) -#define I40E_GLPRT_TDPC(_i) (0x00375400 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_TDOLD_GLPRT_TDOLD_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_TDOLD_GLPRT_TDOLD_SHIFT) +#define I40E_GLPRT_TDPC(_i) (0x00375400 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_TDPC_MAX_INDEX 3 #define I40E_GLPRT_TDPC_TDPC_SHIFT 0 -#define I40E_GLPRT_TDPC_TDPC_MASK (0xFFFFFFFF << I40E_GLPRT_TDPC_TDPC_SHIFT) -#define I40E_GLPRT_UPRCH(_i) (0x003005A4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_TDPC_TDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_TDPC_TDPC_SHIFT) +#define I40E_GLPRT_UPRCH(_i) (0x003005A4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_UPRCH_MAX_INDEX 3 #define I40E_GLPRT_UPRCH_UPRCH_SHIFT 0 -#define I40E_GLPRT_UPRCH_UPRCH_MASK (0xFFFF << I40E_GLPRT_UPRCH_UPRCH_SHIFT) -#define I40E_GLPRT_UPRCL(_i) (0x003005A0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_UPRCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_UPRCH_UPRCH_SHIFT) +#define I40E_GLPRT_UPRCL(_i) (0x003005A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_UPRCL_MAX_INDEX 3 #define I40E_GLPRT_UPRCL_UPRCL_SHIFT 0 -#define I40E_GLPRT_UPRCL_UPRCL_MASK (0xFFFFFFFF << I40E_GLPRT_UPRCL_UPRCL_SHIFT) -#define I40E_GLPRT_UPTCH(_i) (0x003009C4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_UPRCL_UPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_UPRCL_UPRCL_SHIFT) +#define I40E_GLPRT_UPTCH(_i) (0x003009C4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_UPTCH_MAX_INDEX 3 #define I40E_GLPRT_UPTCH_UPTCH_SHIFT 0 -#define I40E_GLPRT_UPTCH_UPTCH_MASK (0xFFFF << I40E_GLPRT_UPTCH_UPTCH_SHIFT) -#define I40E_GLPRT_UPTCL(_i) (0x003009C0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_UPTCH_UPTCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_UPTCH_UPTCH_SHIFT) +#define I40E_GLPRT_UPTCL(_i) (0x003009C0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_UPTCL_MAX_INDEX 3 #define I40E_GLPRT_UPTCL_VUPTCH_SHIFT 0 -#define I40E_GLPRT_UPTCL_VUPTCH_MASK (0xFFFFFFFF << I40E_GLPRT_UPTCL_VUPTCH_SHIFT) -#define I40E_GLSW_BPRCH(_i) (0x00370104 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLPRT_UPTCL_VUPTCH_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_UPTCL_VUPTCH_SHIFT) +#define I40E_GLSW_BPRCH(_i) (0x00370104 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_BPRCH_MAX_INDEX 15 #define I40E_GLSW_BPRCH_BPRCH_SHIFT 0 -#define I40E_GLSW_BPRCH_BPRCH_MASK (0xFFFF << I40E_GLSW_BPRCH_BPRCH_SHIFT) -#define I40E_GLSW_BPRCL(_i) (0x00370100 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_BPRCH_BPRCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_BPRCH_BPRCH_SHIFT) +#define I40E_GLSW_BPRCL(_i) (0x00370100 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_BPRCL_MAX_INDEX 15 #define I40E_GLSW_BPRCL_BPRCL_SHIFT 0 -#define I40E_GLSW_BPRCL_BPRCL_MASK (0xFFFFFFFF << I40E_GLSW_BPRCL_BPRCL_SHIFT) -#define I40E_GLSW_BPTCH(_i) (0x00340104 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_BPRCL_BPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_BPRCL_BPRCL_SHIFT) +#define I40E_GLSW_BPTCH(_i) (0x00340104 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_BPTCH_MAX_INDEX 15 #define I40E_GLSW_BPTCH_BPTCH_SHIFT 0 -#define I40E_GLSW_BPTCH_BPTCH_MASK (0xFFFF << I40E_GLSW_BPTCH_BPTCH_SHIFT) -#define I40E_GLSW_BPTCL(_i) (0x00340100 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_BPTCH_BPTCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_BPTCH_BPTCH_SHIFT) +#define I40E_GLSW_BPTCL(_i) (0x00340100 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_BPTCL_MAX_INDEX 15 #define I40E_GLSW_BPTCL_BPTCL_SHIFT 0 -#define I40E_GLSW_BPTCL_BPTCL_MASK (0xFFFFFFFF << I40E_GLSW_BPTCL_BPTCL_SHIFT) -#define I40E_GLSW_GORCH(_i) (0x0035C004 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_BPTCL_BPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_BPTCL_BPTCL_SHIFT) +#define I40E_GLSW_GORCH(_i) (0x0035C004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_GORCH_MAX_INDEX 15 #define I40E_GLSW_GORCH_GORCH_SHIFT 0 -#define I40E_GLSW_GORCH_GORCH_MASK (0xFFFF << I40E_GLSW_GORCH_GORCH_SHIFT) -#define I40E_GLSW_GORCL(_i) (0x0035c000 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_GORCH_GORCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_GORCH_GORCH_SHIFT) +#define I40E_GLSW_GORCL(_i) (0x0035c000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_GORCL_MAX_INDEX 15 #define I40E_GLSW_GORCL_GORCL_SHIFT 0 -#define I40E_GLSW_GORCL_GORCL_MASK (0xFFFFFFFF << I40E_GLSW_GORCL_GORCL_SHIFT) -#define I40E_GLSW_GOTCH(_i) (0x0032C004 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_GORCL_GORCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_GORCL_GORCL_SHIFT) +#define I40E_GLSW_GOTCH(_i) (0x0032C004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_GOTCH_MAX_INDEX 15 #define I40E_GLSW_GOTCH_GOTCH_SHIFT 0 -#define I40E_GLSW_GOTCH_GOTCH_MASK (0xFFFF << I40E_GLSW_GOTCH_GOTCH_SHIFT) -#define I40E_GLSW_GOTCL(_i) (0x0032c000 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_GOTCH_GOTCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_GOTCH_GOTCH_SHIFT) +#define I40E_GLSW_GOTCL(_i) (0x0032c000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_GOTCL_MAX_INDEX 15 #define I40E_GLSW_GOTCL_GOTCL_SHIFT 0 -#define I40E_GLSW_GOTCL_GOTCL_MASK (0xFFFFFFFF << I40E_GLSW_GOTCL_GOTCL_SHIFT) -#define I40E_GLSW_MPRCH(_i) (0x00370084 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_GOTCL_GOTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_GOTCL_GOTCL_SHIFT) +#define I40E_GLSW_MPRCH(_i) (0x00370084 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_MPRCH_MAX_INDEX 15 #define I40E_GLSW_MPRCH_MPRCH_SHIFT 0 -#define I40E_GLSW_MPRCH_MPRCH_MASK (0xFFFF << I40E_GLSW_MPRCH_MPRCH_SHIFT) -#define I40E_GLSW_MPRCL(_i) (0x00370080 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_MPRCH_MPRCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_MPRCH_MPRCH_SHIFT) +#define I40E_GLSW_MPRCL(_i) (0x00370080 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_MPRCL_MAX_INDEX 15 #define I40E_GLSW_MPRCL_MPRCL_SHIFT 0 -#define I40E_GLSW_MPRCL_MPRCL_MASK (0xFFFFFFFF << I40E_GLSW_MPRCL_MPRCL_SHIFT) -#define I40E_GLSW_MPTCH(_i) (0x00340084 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_MPRCL_MPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_MPRCL_MPRCL_SHIFT) +#define I40E_GLSW_MPTCH(_i) (0x00340084 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_MPTCH_MAX_INDEX 15 #define I40E_GLSW_MPTCH_MPTCH_SHIFT 0 -#define I40E_GLSW_MPTCH_MPTCH_MASK (0xFFFF << I40E_GLSW_MPTCH_MPTCH_SHIFT) -#define I40E_GLSW_MPTCL(_i) (0x00340080 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_MPTCH_MPTCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_MPTCH_MPTCH_SHIFT) +#define I40E_GLSW_MPTCL(_i) (0x00340080 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_MPTCL_MAX_INDEX 15 #define I40E_GLSW_MPTCL_MPTCL_SHIFT 0 -#define I40E_GLSW_MPTCL_MPTCL_MASK (0xFFFFFFFF << I40E_GLSW_MPTCL_MPTCL_SHIFT) -#define I40E_GLSW_RUPP(_i) (0x00370180 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_MPTCL_MPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_MPTCL_MPTCL_SHIFT) +#define I40E_GLSW_RUPP(_i) (0x00370180 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_RUPP_MAX_INDEX 15 #define I40E_GLSW_RUPP_RUPP_SHIFT 0 -#define I40E_GLSW_RUPP_RUPP_MASK (0xFFFFFFFF << I40E_GLSW_RUPP_RUPP_SHIFT) -#define I40E_GLSW_TDPC(_i) (0x00348000 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_RUPP_RUPP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_RUPP_RUPP_SHIFT) +#define I40E_GLSW_TDPC(_i) (0x00348000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_TDPC_MAX_INDEX 15 #define I40E_GLSW_TDPC_TDPC_SHIFT 0 -#define I40E_GLSW_TDPC_TDPC_MASK (0xFFFFFFFF << I40E_GLSW_TDPC_TDPC_SHIFT) -#define I40E_GLSW_UPRCH(_i) (0x00370004 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_TDPC_TDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_TDPC_TDPC_SHIFT) +#define I40E_GLSW_UPRCH(_i) (0x00370004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_UPRCH_MAX_INDEX 15 #define I40E_GLSW_UPRCH_UPRCH_SHIFT 0 -#define I40E_GLSW_UPRCH_UPRCH_MASK (0xFFFF << I40E_GLSW_UPRCH_UPRCH_SHIFT) -#define I40E_GLSW_UPRCL(_i) (0x00370000 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_UPRCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_UPRCH_UPRCH_SHIFT) +#define I40E_GLSW_UPRCL(_i) (0x00370000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_UPRCL_MAX_INDEX 15 #define I40E_GLSW_UPRCL_UPRCL_SHIFT 0 -#define I40E_GLSW_UPRCL_UPRCL_MASK (0xFFFFFFFF << I40E_GLSW_UPRCL_UPRCL_SHIFT) -#define I40E_GLSW_UPTCH(_i) (0x00340004 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_UPRCL_UPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_UPRCL_UPRCL_SHIFT) +#define I40E_GLSW_UPTCH(_i) (0x00340004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_UPTCH_MAX_INDEX 15 #define I40E_GLSW_UPTCH_UPTCH_SHIFT 0 -#define I40E_GLSW_UPTCH_UPTCH_MASK (0xFFFF << I40E_GLSW_UPTCH_UPTCH_SHIFT) -#define I40E_GLSW_UPTCL(_i) (0x00340000 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_UPTCH_UPTCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_UPTCH_UPTCH_SHIFT) +#define I40E_GLSW_UPTCL(_i) (0x00340000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_UPTCL_MAX_INDEX 15 #define I40E_GLSW_UPTCL_UPTCL_SHIFT 0 -#define I40E_GLSW_UPTCL_UPTCL_MASK (0xFFFFFFFF << I40E_GLSW_UPTCL_UPTCL_SHIFT) -#define I40E_GLV_BPRCH(_i) (0x0036D804 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLSW_UPTCL_UPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_UPTCL_UPTCL_SHIFT) +#define I40E_GLV_BPRCH(_i) (0x0036D804 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_BPRCH_MAX_INDEX 383 #define I40E_GLV_BPRCH_BPRCH_SHIFT 0 -#define I40E_GLV_BPRCH_BPRCH_MASK (0xFFFF << I40E_GLV_BPRCH_BPRCH_SHIFT) -#define I40E_GLV_BPRCL(_i) (0x0036d800 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_BPRCH_BPRCH_MASK I40E_MASK(0xFFFF, I40E_GLV_BPRCH_BPRCH_SHIFT) +#define I40E_GLV_BPRCL(_i) (0x0036d800 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_BPRCL_MAX_INDEX 383 #define I40E_GLV_BPRCL_BPRCL_SHIFT 0 -#define I40E_GLV_BPRCL_BPRCL_MASK (0xFFFFFFFF << I40E_GLV_BPRCL_BPRCL_SHIFT) -#define I40E_GLV_BPTCH(_i) (0x0033D804 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_BPRCL_BPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_BPRCL_BPRCL_SHIFT) +#define I40E_GLV_BPTCH(_i) (0x0033D804 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_BPTCH_MAX_INDEX 383 #define I40E_GLV_BPTCH_BPTCH_SHIFT 0 -#define I40E_GLV_BPTCH_BPTCH_MASK (0xFFFF << I40E_GLV_BPTCH_BPTCH_SHIFT) -#define I40E_GLV_BPTCL(_i) (0x0033d800 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_BPTCH_BPTCH_MASK I40E_MASK(0xFFFF, I40E_GLV_BPTCH_BPTCH_SHIFT) +#define I40E_GLV_BPTCL(_i) (0x0033d800 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_BPTCL_MAX_INDEX 383 #define I40E_GLV_BPTCL_BPTCL_SHIFT 0 -#define I40E_GLV_BPTCL_BPTCL_MASK (0xFFFFFFFF << I40E_GLV_BPTCL_BPTCL_SHIFT) -#define I40E_GLV_GORCH(_i) (0x00358004 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_BPTCL_BPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_BPTCL_BPTCL_SHIFT) +#define I40E_GLV_GORCH(_i) (0x00358004 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_GORCH_MAX_INDEX 383 #define I40E_GLV_GORCH_GORCH_SHIFT 0 -#define I40E_GLV_GORCH_GORCH_MASK (0xFFFF << I40E_GLV_GORCH_GORCH_SHIFT) -#define I40E_GLV_GORCL(_i) (0x00358000 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_GORCH_GORCH_MASK I40E_MASK(0xFFFF, I40E_GLV_GORCH_GORCH_SHIFT) +#define I40E_GLV_GORCL(_i) (0x00358000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_GORCL_MAX_INDEX 383 #define I40E_GLV_GORCL_GORCL_SHIFT 0 -#define I40E_GLV_GORCL_GORCL_MASK (0xFFFFFFFF << I40E_GLV_GORCL_GORCL_SHIFT) -#define I40E_GLV_GOTCH(_i) (0x00328004 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_GORCL_GORCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_GORCL_GORCL_SHIFT) +#define I40E_GLV_GOTCH(_i) (0x00328004 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_GOTCH_MAX_INDEX 383 #define I40E_GLV_GOTCH_GOTCH_SHIFT 0 -#define I40E_GLV_GOTCH_GOTCH_MASK (0xFFFF << I40E_GLV_GOTCH_GOTCH_SHIFT) -#define I40E_GLV_GOTCL(_i) (0x00328000 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_GOTCH_GOTCH_MASK I40E_MASK(0xFFFF, I40E_GLV_GOTCH_GOTCH_SHIFT) +#define I40E_GLV_GOTCL(_i) (0x00328000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_GOTCL_MAX_INDEX 383 #define I40E_GLV_GOTCL_GOTCL_SHIFT 0 -#define I40E_GLV_GOTCL_GOTCL_MASK (0xFFFFFFFF << I40E_GLV_GOTCL_GOTCL_SHIFT) -#define I40E_GLV_MPRCH(_i) (0x0036CC04 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_GOTCL_GOTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_GOTCL_GOTCL_SHIFT) +#define I40E_GLV_MPRCH(_i) (0x0036CC04 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_MPRCH_MAX_INDEX 383 #define I40E_GLV_MPRCH_MPRCH_SHIFT 0 -#define I40E_GLV_MPRCH_MPRCH_MASK (0xFFFF << I40E_GLV_MPRCH_MPRCH_SHIFT) -#define I40E_GLV_MPRCL(_i) (0x0036cc00 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_MPRCH_MPRCH_MASK I40E_MASK(0xFFFF, I40E_GLV_MPRCH_MPRCH_SHIFT) +#define I40E_GLV_MPRCL(_i) (0x0036cc00 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_MPRCL_MAX_INDEX 383 #define I40E_GLV_MPRCL_MPRCL_SHIFT 0 -#define I40E_GLV_MPRCL_MPRCL_MASK (0xFFFFFFFF << I40E_GLV_MPRCL_MPRCL_SHIFT) -#define I40E_GLV_MPTCH(_i) (0x0033CC04 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_MPRCL_MPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_MPRCL_MPRCL_SHIFT) +#define I40E_GLV_MPTCH(_i) (0x0033CC04 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_MPTCH_MAX_INDEX 383 #define I40E_GLV_MPTCH_MPTCH_SHIFT 0 -#define I40E_GLV_MPTCH_MPTCH_MASK (0xFFFF << I40E_GLV_MPTCH_MPTCH_SHIFT) -#define I40E_GLV_MPTCL(_i) (0x0033cc00 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_MPTCH_MPTCH_MASK I40E_MASK(0xFFFF, I40E_GLV_MPTCH_MPTCH_SHIFT) +#define I40E_GLV_MPTCL(_i) (0x0033cc00 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_MPTCL_MAX_INDEX 383 #define I40E_GLV_MPTCL_MPTCL_SHIFT 0 -#define I40E_GLV_MPTCL_MPTCL_MASK (0xFFFFFFFF << I40E_GLV_MPTCL_MPTCL_SHIFT) -#define I40E_GLV_RDPC(_i) (0x00310000 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_MPTCL_MPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_MPTCL_MPTCL_SHIFT) +#define I40E_GLV_RDPC(_i) (0x00310000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_RDPC_MAX_INDEX 383 #define I40E_GLV_RDPC_RDPC_SHIFT 0 -#define I40E_GLV_RDPC_RDPC_MASK (0xFFFFFFFF << I40E_GLV_RDPC_RDPC_SHIFT) -#define I40E_GLV_RUPP(_i) (0x0036E400 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_RDPC_RDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_RDPC_RDPC_SHIFT) +#define I40E_GLV_RUPP(_i) (0x0036E400 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_RUPP_MAX_INDEX 383 #define I40E_GLV_RUPP_RUPP_SHIFT 0 -#define I40E_GLV_RUPP_RUPP_MASK (0xFFFFFFFF << I40E_GLV_RUPP_RUPP_SHIFT) -#define I40E_GLV_TEPC(_VSI) (0x00344000 + ((_VSI) * 8)) /* _i=0...383 */ +#define I40E_GLV_RUPP_RUPP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_RUPP_RUPP_SHIFT) +#define I40E_GLV_TEPC(_VSI) (0x00344000 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_TEPC_MAX_INDEX 383 #define I40E_GLV_TEPC_TEPC_SHIFT 0 -#define I40E_GLV_TEPC_TEPC_MASK (0xFFFFFFFF << I40E_GLV_TEPC_TEPC_SHIFT) -#define I40E_GLV_UPRCH(_i) (0x0036C004 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_TEPC_TEPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_TEPC_TEPC_SHIFT) +#define I40E_GLV_UPRCH(_i) (0x0036C004 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_UPRCH_MAX_INDEX 383 #define I40E_GLV_UPRCH_UPRCH_SHIFT 0 -#define I40E_GLV_UPRCH_UPRCH_MASK (0xFFFF << I40E_GLV_UPRCH_UPRCH_SHIFT) -#define I40E_GLV_UPRCL(_i) (0x0036c000 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_UPRCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLV_UPRCH_UPRCH_SHIFT) +#define I40E_GLV_UPRCL(_i) (0x0036c000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_UPRCL_MAX_INDEX 383 #define I40E_GLV_UPRCL_UPRCL_SHIFT 0 -#define I40E_GLV_UPRCL_UPRCL_MASK (0xFFFFFFFF << I40E_GLV_UPRCL_UPRCL_SHIFT) -#define I40E_GLV_UPTCH(_i) (0x0033C004 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_UPRCL_UPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_UPRCL_UPRCL_SHIFT) +#define I40E_GLV_UPTCH(_i) (0x0033C004 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_UPTCH_MAX_INDEX 383 #define I40E_GLV_UPTCH_GLVUPTCH_SHIFT 0 -#define I40E_GLV_UPTCH_GLVUPTCH_MASK (0xFFFF << I40E_GLV_UPTCH_GLVUPTCH_SHIFT) -#define I40E_GLV_UPTCL(_i) (0x0033c000 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_UPTCH_GLVUPTCH_MASK I40E_MASK(0xFFFF, I40E_GLV_UPTCH_GLVUPTCH_SHIFT) +#define I40E_GLV_UPTCL(_i) (0x0033c000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_UPTCL_MAX_INDEX 383 #define I40E_GLV_UPTCL_UPTCL_SHIFT 0 -#define I40E_GLV_UPTCL_UPTCL_MASK (0xFFFFFFFF << I40E_GLV_UPTCL_UPTCL_SHIFT) -#define I40E_GLVEBTC_RBCH(_i, _j) (0x00364004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLV_UPTCL_UPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_UPTCL_UPTCL_SHIFT) +#define I40E_GLVEBTC_RBCH(_i, _j) (0x00364004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_RBCH_MAX_INDEX 7 #define I40E_GLVEBTC_RBCH_TCBCH_SHIFT 0 -#define I40E_GLVEBTC_RBCH_TCBCH_MASK (0xFFFF << I40E_GLVEBTC_RBCH_TCBCH_SHIFT) -#define I40E_GLVEBTC_RBCL(_i, _j) (0x00364000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_RBCH_TCBCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBTC_RBCH_TCBCH_SHIFT) +#define I40E_GLVEBTC_RBCL(_i, _j) (0x00364000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_RBCL_MAX_INDEX 7 #define I40E_GLVEBTC_RBCL_TCBCL_SHIFT 0 -#define I40E_GLVEBTC_RBCL_TCBCL_MASK (0xFFFFFFFF << I40E_GLVEBTC_RBCL_TCBCL_SHIFT) -#define I40E_GLVEBTC_RPCH(_i, _j) (0x00368004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_RBCL_TCBCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBTC_RBCL_TCBCL_SHIFT) +#define I40E_GLVEBTC_RPCH(_i, _j) (0x00368004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_RPCH_MAX_INDEX 7 #define I40E_GLVEBTC_RPCH_TCPCH_SHIFT 0 -#define I40E_GLVEBTC_RPCH_TCPCH_MASK (0xFFFF << I40E_GLVEBTC_RPCH_TCPCH_SHIFT) -#define I40E_GLVEBTC_RPCL(_i, _j) (0x00368000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_RPCH_TCPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBTC_RPCH_TCPCH_SHIFT) +#define I40E_GLVEBTC_RPCL(_i, _j) (0x00368000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_RPCL_MAX_INDEX 7 #define I40E_GLVEBTC_RPCL_TCPCL_SHIFT 0 -#define I40E_GLVEBTC_RPCL_TCPCL_MASK (0xFFFFFFFF << I40E_GLVEBTC_RPCL_TCPCL_SHIFT) -#define I40E_GLVEBTC_TBCH(_i, _j) (0x00334004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_RPCL_TCPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBTC_RPCL_TCPCL_SHIFT) +#define I40E_GLVEBTC_TBCH(_i, _j) (0x00334004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_TBCH_MAX_INDEX 7 #define I40E_GLVEBTC_TBCH_TCBCH_SHIFT 0 -#define I40E_GLVEBTC_TBCH_TCBCH_MASK (0xFFFF << I40E_GLVEBTC_TBCH_TCBCH_SHIFT) -#define I40E_GLVEBTC_TBCL(_i, _j) (0x00334000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_TBCH_TCBCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBTC_TBCH_TCBCH_SHIFT) +#define I40E_GLVEBTC_TBCL(_i, _j) (0x00334000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_TBCL_MAX_INDEX 7 #define I40E_GLVEBTC_TBCL_TCBCL_SHIFT 0 -#define I40E_GLVEBTC_TBCL_TCBCL_MASK (0xFFFFFFFF << I40E_GLVEBTC_TBCL_TCBCL_SHIFT) -#define I40E_GLVEBTC_TPCH(_i, _j) (0x00338004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_TBCL_TCBCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBTC_TBCL_TCBCL_SHIFT) +#define I40E_GLVEBTC_TPCH(_i, _j) (0x00338004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_TPCH_MAX_INDEX 7 #define I40E_GLVEBTC_TPCH_TCPCH_SHIFT 0 -#define I40E_GLVEBTC_TPCH_TCPCH_MASK (0xFFFF << I40E_GLVEBTC_TPCH_TCPCH_SHIFT) -#define I40E_GLVEBTC_TPCL(_i, _j) (0x00338000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_TPCH_TCPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBTC_TPCH_TCPCH_SHIFT) +#define I40E_GLVEBTC_TPCL(_i, _j) (0x00338000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_TPCL_MAX_INDEX 7 #define I40E_GLVEBTC_TPCL_TCPCL_SHIFT 0 -#define I40E_GLVEBTC_TPCL_TCPCL_MASK (0xFFFFFFFF << I40E_GLVEBTC_TPCL_TCPCL_SHIFT) -#define I40E_GLVEBVL_BPCH(_i) (0x00374804 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBTC_TPCL_TCPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBTC_TPCL_TCPCL_SHIFT) +#define I40E_GLVEBVL_BPCH(_i) (0x00374804 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_BPCH_MAX_INDEX 127 #define I40E_GLVEBVL_BPCH_VLBPCH_SHIFT 0 -#define I40E_GLVEBVL_BPCH_VLBPCH_MASK (0xFFFF << I40E_GLVEBVL_BPCH_VLBPCH_SHIFT) -#define I40E_GLVEBVL_BPCL(_i) (0x00374800 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_BPCH_VLBPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_BPCH_VLBPCH_SHIFT) +#define I40E_GLVEBVL_BPCL(_i) (0x00374800 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_BPCL_MAX_INDEX 127 #define I40E_GLVEBVL_BPCL_VLBPCL_SHIFT 0 -#define I40E_GLVEBVL_BPCL_VLBPCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_BPCL_VLBPCL_SHIFT) -#define I40E_GLVEBVL_GORCH(_i) (0x00360004 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_BPCL_VLBPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_BPCL_VLBPCL_SHIFT) +#define I40E_GLVEBVL_GORCH(_i) (0x00360004 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_GORCH_MAX_INDEX 127 #define I40E_GLVEBVL_GORCH_VLBCH_SHIFT 0 -#define I40E_GLVEBVL_GORCH_VLBCH_MASK (0xFFFF << I40E_GLVEBVL_GORCH_VLBCH_SHIFT) -#define I40E_GLVEBVL_GORCL(_i) (0x00360000 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_GORCH_VLBCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_GORCH_VLBCH_SHIFT) +#define I40E_GLVEBVL_GORCL(_i) (0x00360000 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_GORCL_MAX_INDEX 127 #define I40E_GLVEBVL_GORCL_VLBCL_SHIFT 0 -#define I40E_GLVEBVL_GORCL_VLBCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_GORCL_VLBCL_SHIFT) -#define I40E_GLVEBVL_GOTCH(_i) (0x00330004 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_GORCL_VLBCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_GORCL_VLBCL_SHIFT) +#define I40E_GLVEBVL_GOTCH(_i) (0x00330004 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_GOTCH_MAX_INDEX 127 #define I40E_GLVEBVL_GOTCH_VLBCH_SHIFT 0 -#define I40E_GLVEBVL_GOTCH_VLBCH_MASK (0xFFFF << I40E_GLVEBVL_GOTCH_VLBCH_SHIFT) -#define I40E_GLVEBVL_GOTCL(_i) (0x00330000 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_GOTCH_VLBCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_GOTCH_VLBCH_SHIFT) +#define I40E_GLVEBVL_GOTCL(_i) (0x00330000 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_GOTCL_MAX_INDEX 127 #define I40E_GLVEBVL_GOTCL_VLBCL_SHIFT 0 -#define I40E_GLVEBVL_GOTCL_VLBCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_GOTCL_VLBCL_SHIFT) -#define I40E_GLVEBVL_MPCH(_i) (0x00374404 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_GOTCL_VLBCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_GOTCL_VLBCL_SHIFT) +#define I40E_GLVEBVL_MPCH(_i) (0x00374404 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_MPCH_MAX_INDEX 127 #define I40E_GLVEBVL_MPCH_VLMPCH_SHIFT 0 -#define I40E_GLVEBVL_MPCH_VLMPCH_MASK (0xFFFF << I40E_GLVEBVL_MPCH_VLMPCH_SHIFT) -#define I40E_GLVEBVL_MPCL(_i) (0x00374400 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_MPCH_VLMPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_MPCH_VLMPCH_SHIFT) +#define I40E_GLVEBVL_MPCL(_i) (0x00374400 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_MPCL_MAX_INDEX 127 #define I40E_GLVEBVL_MPCL_VLMPCL_SHIFT 0 -#define I40E_GLVEBVL_MPCL_VLMPCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_MPCL_VLMPCL_SHIFT) -#define I40E_GLVEBVL_UPCH(_i) (0x00374004 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_MPCL_VLMPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_MPCL_VLMPCL_SHIFT) +#define I40E_GLVEBVL_UPCH(_i) (0x00374004 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_UPCH_MAX_INDEX 127 #define I40E_GLVEBVL_UPCH_VLUPCH_SHIFT 0 -#define I40E_GLVEBVL_UPCH_VLUPCH_MASK (0xFFFF << I40E_GLVEBVL_UPCH_VLUPCH_SHIFT) -#define I40E_GLVEBVL_UPCL(_i) (0x00374000 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_UPCH_VLUPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_UPCH_VLUPCH_SHIFT) +#define I40E_GLVEBVL_UPCL(_i) (0x00374000 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_UPCL_MAX_INDEX 127 #define I40E_GLVEBVL_UPCL_VLUPCL_SHIFT 0 -#define I40E_GLVEBVL_UPCL_VLUPCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_UPCL_VLUPCL_SHIFT) -#define I40E_GL_MTG_FLU_MSK_H 0x00269F4C +#define I40E_GLVEBVL_UPCL_VLUPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_UPCL_VLUPCL_SHIFT) +#define I40E_GL_MTG_FLU_MSK_H 0x00269F4C /* Reset: CORER */ #define I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_SHIFT 0 -#define I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_MASK (0xFFFF << I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_SHIFT) -#define I40E_GL_MTG_FLU_MSK_L 0x00269F44 -#define I40E_GL_MTG_FLU_MSK_L_MASK_LOW_SHIFT 0 -#define I40E_GL_MTG_FLU_MSK_L_MASK_LOW_MASK (0xFFFFFFFF << I40E_GL_MTG_FLU_MSK_L_MASK_LOW_SHIFT) -#define I40E_GL_SWR_DEF_ACT(_i) (0x0026CF00 + ((_i) * 4)) /* _i=0...25 */ -#define I40E_GL_SWR_DEF_ACT_MAX_INDEX 25 +#define I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_MASK I40E_MASK(0xFFFF, I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_SHIFT) +#define I40E_GL_SWR_DEF_ACT(_i) (0x00270200 + ((_i) * 4)) /* _i=0...35 */ /* Reset: CORER */ +#define I40E_GL_SWR_DEF_ACT_MAX_INDEX 35 #define I40E_GL_SWR_DEF_ACT_DEF_ACTION_SHIFT 0 -#define I40E_GL_SWR_DEF_ACT_DEF_ACTION_MASK (0xFFFFFFFF << I40E_GL_SWR_DEF_ACT_DEF_ACTION_SHIFT) -#define I40E_GL_SWR_DEF_ACT_EN 0x0026CF84 +#define I40E_GL_SWR_DEF_ACT_DEF_ACTION_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_SWR_DEF_ACT_DEF_ACTION_SHIFT) +#define I40E_GL_SWR_DEF_ACT_EN(_i) (0x0026CFB8 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */ +#define I40E_GL_SWR_DEF_ACT_EN_MAX_INDEX 1 #define I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_SHIFT 0 -#define I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_MASK (0xFFFFFFFF << I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_SHIFT) -#define I40E_PRT_MSCCNT 0x00256BA0 -#define I40E_PRT_MSCCNT_CCOUNT_SHIFT 0 -#define I40E_PRT_MSCCNT_CCOUNT_MASK (0x1FFFFFF << I40E_PRT_MSCCNT_CCOUNT_SHIFT) -#define I40E_PRT_SCSTS 0x00256C20 -#define I40E_PRT_SCSTS_BSCA_SHIFT 0 -#define I40E_PRT_SCSTS_BSCA_MASK (0x1 << I40E_PRT_SCSTS_BSCA_SHIFT) -#define I40E_PRT_SCSTS_BSCAP_SHIFT 1 -#define I40E_PRT_SCSTS_BSCAP_MASK (0x1 << I40E_PRT_SCSTS_BSCAP_SHIFT) -#define I40E_PRT_SCSTS_MSCA_SHIFT 2 -#define I40E_PRT_SCSTS_MSCA_MASK (0x1 << I40E_PRT_SCSTS_MSCA_SHIFT) -#define I40E_PRT_SCSTS_MSCAP_SHIFT 3 -#define I40E_PRT_SCSTS_MSCAP_MASK (0x1 << I40E_PRT_SCSTS_MSCAP_SHIFT) -#define I40E_PRT_SWT_BSCCNT 0x00256C60 -#define I40E_PRT_SWT_BSCCNT_CCOUNT_SHIFT 0 -#define I40E_PRT_SWT_BSCCNT_CCOUNT_MASK (0x1FFFFFF << I40E_PRT_SWT_BSCCNT_CCOUNT_SHIFT) -#define I40E_PRTTSYN_ADJ 0x001E4280 +#define I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_SHIFT) +#define I40E_PRTTSYN_ADJ 0x001E4280 /* Reset: GLOBR */ #define I40E_PRTTSYN_ADJ_TSYNADJ_SHIFT 0 -#define I40E_PRTTSYN_ADJ_TSYNADJ_MASK (0x7FFFFFFF << I40E_PRTTSYN_ADJ_TSYNADJ_SHIFT) +#define I40E_PRTTSYN_ADJ_TSYNADJ_MASK I40E_MASK(0x7FFFFFFF, I40E_PRTTSYN_ADJ_TSYNADJ_SHIFT) #define I40E_PRTTSYN_ADJ_SIGN_SHIFT 31 -#define I40E_PRTTSYN_ADJ_SIGN_MASK (0x1 << I40E_PRTTSYN_ADJ_SIGN_SHIFT) -#define I40E_PRTTSYN_AUX_0(_i) (0x001E42A0 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_ADJ_SIGN_MASK I40E_MASK(0x1, I40E_PRTTSYN_ADJ_SIGN_SHIFT) +#define I40E_PRTTSYN_AUX_0(_i) (0x001E42A0 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_AUX_0_MAX_INDEX 1 #define I40E_PRTTSYN_AUX_0_OUT_ENA_SHIFT 0 -#define I40E_PRTTSYN_AUX_0_OUT_ENA_MASK (0x1 << I40E_PRTTSYN_AUX_0_OUT_ENA_SHIFT) +#define I40E_PRTTSYN_AUX_0_OUT_ENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_AUX_0_OUT_ENA_SHIFT) #define I40E_PRTTSYN_AUX_0_OUTMOD_SHIFT 1 -#define I40E_PRTTSYN_AUX_0_OUTMOD_MASK (0x3 << I40E_PRTTSYN_AUX_0_OUTMOD_SHIFT) +#define I40E_PRTTSYN_AUX_0_OUTMOD_MASK I40E_MASK(0x3, I40E_PRTTSYN_AUX_0_OUTMOD_SHIFT) #define I40E_PRTTSYN_AUX_0_OUTLVL_SHIFT 3 -#define I40E_PRTTSYN_AUX_0_OUTLVL_MASK (0x1 << I40E_PRTTSYN_AUX_0_OUTLVL_SHIFT) +#define I40E_PRTTSYN_AUX_0_OUTLVL_MASK I40E_MASK(0x1, I40E_PRTTSYN_AUX_0_OUTLVL_SHIFT) #define I40E_PRTTSYN_AUX_0_PULSEW_SHIFT 8 -#define I40E_PRTTSYN_AUX_0_PULSEW_MASK (0xF << I40E_PRTTSYN_AUX_0_PULSEW_SHIFT) +#define I40E_PRTTSYN_AUX_0_PULSEW_MASK I40E_MASK(0xF, I40E_PRTTSYN_AUX_0_PULSEW_SHIFT) #define I40E_PRTTSYN_AUX_0_EVNTLVL_SHIFT 16 -#define I40E_PRTTSYN_AUX_0_EVNTLVL_MASK (0x3 << I40E_PRTTSYN_AUX_0_EVNTLVL_SHIFT) -#define I40E_PRTTSYN_AUX_1(_i) (0x001E42E0 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_AUX_0_EVNTLVL_MASK I40E_MASK(0x3, I40E_PRTTSYN_AUX_0_EVNTLVL_SHIFT) +#define I40E_PRTTSYN_AUX_1(_i) (0x001E42E0 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_AUX_1_MAX_INDEX 1 #define I40E_PRTTSYN_AUX_1_INSTNT_SHIFT 0 -#define I40E_PRTTSYN_AUX_1_INSTNT_MASK (0x1 << I40E_PRTTSYN_AUX_1_INSTNT_SHIFT) +#define I40E_PRTTSYN_AUX_1_INSTNT_MASK I40E_MASK(0x1, I40E_PRTTSYN_AUX_1_INSTNT_SHIFT) #define I40E_PRTTSYN_AUX_1_SAMPLE_TIME_SHIFT 1 -#define I40E_PRTTSYN_AUX_1_SAMPLE_TIME_MASK (0x1 << I40E_PRTTSYN_AUX_1_SAMPLE_TIME_SHIFT) -#define I40E_PRTTSYN_CLKO(_i) (0x001E4240 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_AUX_1_SAMPLE_TIME_MASK I40E_MASK(0x1, I40E_PRTTSYN_AUX_1_SAMPLE_TIME_SHIFT) +#define I40E_PRTTSYN_CLKO(_i) (0x001E4240 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_CLKO_MAX_INDEX 1 #define I40E_PRTTSYN_CLKO_TSYNCLKO_SHIFT 0 -#define I40E_PRTTSYN_CLKO_TSYNCLKO_MASK (0xFFFFFFFF << I40E_PRTTSYN_CLKO_TSYNCLKO_SHIFT) -#define I40E_PRTTSYN_CTL0 0x001E4200 +#define I40E_PRTTSYN_CLKO_TSYNCLKO_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_CLKO_TSYNCLKO_SHIFT) +#define I40E_PRTTSYN_CTL0 0x001E4200 /* Reset: GLOBR */ #define I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_SHIFT 0 -#define I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_MASK (0x1 << I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_SHIFT) +#define I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_SHIFT) #define I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_SHIFT 1 -#define I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK (0x1 << I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_SHIFT) +#define I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_SHIFT) #define I40E_PRTTSYN_CTL0_EVENT_INT_ENA_SHIFT 2 -#define I40E_PRTTSYN_CTL0_EVENT_INT_ENA_MASK (0x1 << I40E_PRTTSYN_CTL0_EVENT_INT_ENA_SHIFT) +#define I40E_PRTTSYN_CTL0_EVENT_INT_ENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_EVENT_INT_ENA_SHIFT) #define I40E_PRTTSYN_CTL0_TGT_INT_ENA_SHIFT 3 -#define I40E_PRTTSYN_CTL0_TGT_INT_ENA_MASK (0x1 << I40E_PRTTSYN_CTL0_TGT_INT_ENA_SHIFT) +#define I40E_PRTTSYN_CTL0_TGT_INT_ENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_TGT_INT_ENA_SHIFT) #define I40E_PRTTSYN_CTL0_PF_ID_SHIFT 8 -#define I40E_PRTTSYN_CTL0_PF_ID_MASK (0xF << I40E_PRTTSYN_CTL0_PF_ID_SHIFT) +#define I40E_PRTTSYN_CTL0_PF_ID_MASK I40E_MASK(0xF, I40E_PRTTSYN_CTL0_PF_ID_SHIFT) #define I40E_PRTTSYN_CTL0_TSYNACT_SHIFT 12 -#define I40E_PRTTSYN_CTL0_TSYNACT_MASK (0x3 << I40E_PRTTSYN_CTL0_TSYNACT_SHIFT) +#define I40E_PRTTSYN_CTL0_TSYNACT_MASK I40E_MASK(0x3, I40E_PRTTSYN_CTL0_TSYNACT_SHIFT) #define I40E_PRTTSYN_CTL0_TSYNENA_SHIFT 31 -#define I40E_PRTTSYN_CTL0_TSYNENA_MASK (0x1 << I40E_PRTTSYN_CTL0_TSYNENA_SHIFT) -#define I40E_PRTTSYN_CTL1 0x00085020 +#define I40E_PRTTSYN_CTL0_TSYNENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_TSYNENA_SHIFT) +#define I40E_PRTTSYN_CTL1 0x00085020 /* Reset: CORER */ #define I40E_PRTTSYN_CTL1_V1MESSTYPE0_SHIFT 0 -#define I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK (0xFF << I40E_PRTTSYN_CTL1_V1MESSTYPE0_SHIFT) +#define I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK I40E_MASK(0xFF, I40E_PRTTSYN_CTL1_V1MESSTYPE0_SHIFT) #define I40E_PRTTSYN_CTL1_V1MESSTYPE1_SHIFT 8 -#define I40E_PRTTSYN_CTL1_V1MESSTYPE1_MASK (0xFF << I40E_PRTTSYN_CTL1_V1MESSTYPE1_SHIFT) +#define I40E_PRTTSYN_CTL1_V1MESSTYPE1_MASK I40E_MASK(0xFF, I40E_PRTTSYN_CTL1_V1MESSTYPE1_SHIFT) #define I40E_PRTTSYN_CTL1_V2MESSTYPE0_SHIFT 16 -#define I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK (0xF << I40E_PRTTSYN_CTL1_V2MESSTYPE0_SHIFT) +#define I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK I40E_MASK(0xF, I40E_PRTTSYN_CTL1_V2MESSTYPE0_SHIFT) #define I40E_PRTTSYN_CTL1_V2MESSTYPE1_SHIFT 20 -#define I40E_PRTTSYN_CTL1_V2MESSTYPE1_MASK (0xF << I40E_PRTTSYN_CTL1_V2MESSTYPE1_SHIFT) +#define I40E_PRTTSYN_CTL1_V2MESSTYPE1_MASK I40E_MASK(0xF, I40E_PRTTSYN_CTL1_V2MESSTYPE1_SHIFT) #define I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT 24 -#define I40E_PRTTSYN_CTL1_TSYNTYPE_MASK (0x3 << I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) +#define I40E_PRTTSYN_CTL1_TSYNTYPE_MASK I40E_MASK(0x3, I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) #define I40E_PRTTSYN_CTL1_UDP_ENA_SHIFT 26 -#define I40E_PRTTSYN_CTL1_UDP_ENA_MASK (0x3 << I40E_PRTTSYN_CTL1_UDP_ENA_SHIFT) +#define I40E_PRTTSYN_CTL1_UDP_ENA_MASK I40E_MASK(0x3, I40E_PRTTSYN_CTL1_UDP_ENA_SHIFT) #define I40E_PRTTSYN_CTL1_TSYNENA_SHIFT 31 -#define I40E_PRTTSYN_CTL1_TSYNENA_MASK (0x1 << I40E_PRTTSYN_CTL1_TSYNENA_SHIFT) -#define I40E_PRTTSYN_EVNT_H(_i) (0x001E40C0 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_CTL1_TSYNENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL1_TSYNENA_SHIFT) +#define I40E_PRTTSYN_EVNT_H(_i) (0x001E40C0 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_EVNT_H_MAX_INDEX 1 #define I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_SHIFT 0 -#define I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_SHIFT) -#define I40E_PRTTSYN_EVNT_L(_i) (0x001E4080 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_SHIFT) +#define I40E_PRTTSYN_EVNT_L(_i) (0x001E4080 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_EVNT_L_MAX_INDEX 1 #define I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_SHIFT 0 -#define I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_SHIFT) -#define I40E_PRTTSYN_INC_H 0x001E4060 +#define I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_SHIFT) +#define I40E_PRTTSYN_INC_H 0x001E4060 /* Reset: GLOBR */ #define I40E_PRTTSYN_INC_H_TSYNINC_H_SHIFT 0 -#define I40E_PRTTSYN_INC_H_TSYNINC_H_MASK (0x3F << I40E_PRTTSYN_INC_H_TSYNINC_H_SHIFT) -#define I40E_PRTTSYN_INC_L 0x001E4040 +#define I40E_PRTTSYN_INC_H_TSYNINC_H_MASK I40E_MASK(0x3F, I40E_PRTTSYN_INC_H_TSYNINC_H_SHIFT) +#define I40E_PRTTSYN_INC_L 0x001E4040 /* Reset: GLOBR */ #define I40E_PRTTSYN_INC_L_TSYNINC_L_SHIFT 0 -#define I40E_PRTTSYN_INC_L_TSYNINC_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_INC_L_TSYNINC_L_SHIFT) -#define I40E_PRTTSYN_RXTIME_H(_i) (0x00085040 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRTTSYN_INC_L_TSYNINC_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_INC_L_TSYNINC_L_SHIFT) +#define I40E_PRTTSYN_RXTIME_H(_i) (0x00085040 + ((_i) * 32)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_PRTTSYN_RXTIME_H_MAX_INDEX 3 #define I40E_PRTTSYN_RXTIME_H_RXTIEM_H_SHIFT 0 -#define I40E_PRTTSYN_RXTIME_H_RXTIEM_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_RXTIME_H_RXTIEM_H_SHIFT) -#define I40E_PRTTSYN_RXTIME_L(_i) (0x000850C0 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRTTSYN_RXTIME_H_RXTIEM_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_RXTIME_H_RXTIEM_H_SHIFT) +#define I40E_PRTTSYN_RXTIME_L(_i) (0x000850C0 + ((_i) * 32)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_PRTTSYN_RXTIME_L_MAX_INDEX 3 #define I40E_PRTTSYN_RXTIME_L_RXTIEM_L_SHIFT 0 -#define I40E_PRTTSYN_RXTIME_L_RXTIEM_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_RXTIME_L_RXTIEM_L_SHIFT) -#define I40E_PRTTSYN_STAT_0 0x001E4220 +#define I40E_PRTTSYN_RXTIME_L_RXTIEM_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_RXTIME_L_RXTIEM_L_SHIFT) +#define I40E_PRTTSYN_STAT_0 0x001E4220 /* Reset: GLOBR */ #define I40E_PRTTSYN_STAT_0_EVENT0_SHIFT 0 -#define I40E_PRTTSYN_STAT_0_EVENT0_MASK (0x1 << I40E_PRTTSYN_STAT_0_EVENT0_SHIFT) +#define I40E_PRTTSYN_STAT_0_EVENT0_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_EVENT0_SHIFT) #define I40E_PRTTSYN_STAT_0_EVENT1_SHIFT 1 -#define I40E_PRTTSYN_STAT_0_EVENT1_MASK (0x1 << I40E_PRTTSYN_STAT_0_EVENT1_SHIFT) +#define I40E_PRTTSYN_STAT_0_EVENT1_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_EVENT1_SHIFT) #define I40E_PRTTSYN_STAT_0_TGT0_SHIFT 2 -#define I40E_PRTTSYN_STAT_0_TGT0_MASK (0x1 << I40E_PRTTSYN_STAT_0_TGT0_SHIFT) +#define I40E_PRTTSYN_STAT_0_TGT0_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_TGT0_SHIFT) #define I40E_PRTTSYN_STAT_0_TGT1_SHIFT 3 -#define I40E_PRTTSYN_STAT_0_TGT1_MASK (0x1 << I40E_PRTTSYN_STAT_0_TGT1_SHIFT) +#define I40E_PRTTSYN_STAT_0_TGT1_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_TGT1_SHIFT) #define I40E_PRTTSYN_STAT_0_TXTIME_SHIFT 4 -#define I40E_PRTTSYN_STAT_0_TXTIME_MASK (0x1 << I40E_PRTTSYN_STAT_0_TXTIME_SHIFT) -#define I40E_PRTTSYN_STAT_1 0x00085140 +#define I40E_PRTTSYN_STAT_0_TXTIME_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_TXTIME_SHIFT) +#define I40E_PRTTSYN_STAT_1 0x00085140 /* Reset: CORER */ #define I40E_PRTTSYN_STAT_1_RXT0_SHIFT 0 -#define I40E_PRTTSYN_STAT_1_RXT0_MASK (0x1 << I40E_PRTTSYN_STAT_1_RXT0_SHIFT) +#define I40E_PRTTSYN_STAT_1_RXT0_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_1_RXT0_SHIFT) #define I40E_PRTTSYN_STAT_1_RXT1_SHIFT 1 -#define I40E_PRTTSYN_STAT_1_RXT1_MASK (0x1 << I40E_PRTTSYN_STAT_1_RXT1_SHIFT) +#define I40E_PRTTSYN_STAT_1_RXT1_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_1_RXT1_SHIFT) #define I40E_PRTTSYN_STAT_1_RXT2_SHIFT 2 -#define I40E_PRTTSYN_STAT_1_RXT2_MASK (0x1 << I40E_PRTTSYN_STAT_1_RXT2_SHIFT) +#define I40E_PRTTSYN_STAT_1_RXT2_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_1_RXT2_SHIFT) #define I40E_PRTTSYN_STAT_1_RXT3_SHIFT 3 -#define I40E_PRTTSYN_STAT_1_RXT3_MASK (0x1 << I40E_PRTTSYN_STAT_1_RXT3_SHIFT) -#define I40E_PRTTSYN_TGT_H(_i) (0x001E4180 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_STAT_1_RXT3_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_1_RXT3_SHIFT) +#define I40E_PRTTSYN_TGT_H(_i) (0x001E4180 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_TGT_H_MAX_INDEX 1 #define I40E_PRTTSYN_TGT_H_TSYNTGTT_H_SHIFT 0 -#define I40E_PRTTSYN_TGT_H_TSYNTGTT_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_TGT_H_TSYNTGTT_H_SHIFT) -#define I40E_PRTTSYN_TGT_L(_i) (0x001E4140 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_TGT_H_TSYNTGTT_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TGT_H_TSYNTGTT_H_SHIFT) +#define I40E_PRTTSYN_TGT_L(_i) (0x001E4140 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_TGT_L_MAX_INDEX 1 #define I40E_PRTTSYN_TGT_L_TSYNTGTT_L_SHIFT 0 -#define I40E_PRTTSYN_TGT_L_TSYNTGTT_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_TGT_L_TSYNTGTT_L_SHIFT) -#define I40E_PRTTSYN_TIME_H 0x001E4120 +#define I40E_PRTTSYN_TGT_L_TSYNTGTT_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TGT_L_TSYNTGTT_L_SHIFT) +#define I40E_PRTTSYN_TIME_H 0x001E4120 /* Reset: GLOBR */ #define I40E_PRTTSYN_TIME_H_TSYNTIME_H_SHIFT 0 -#define I40E_PRTTSYN_TIME_H_TSYNTIME_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_TIME_H_TSYNTIME_H_SHIFT) -#define I40E_PRTTSYN_TIME_L 0x001E4100 +#define I40E_PRTTSYN_TIME_H_TSYNTIME_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TIME_H_TSYNTIME_H_SHIFT) +#define I40E_PRTTSYN_TIME_L 0x001E4100 /* Reset: GLOBR */ #define I40E_PRTTSYN_TIME_L_TSYNTIME_L_SHIFT 0 -#define I40E_PRTTSYN_TIME_L_TSYNTIME_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_TIME_L_TSYNTIME_L_SHIFT) -#define I40E_PRTTSYN_TXTIME_H 0x001E41E0 +#define I40E_PRTTSYN_TIME_L_TSYNTIME_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TIME_L_TSYNTIME_L_SHIFT) +#define I40E_PRTTSYN_TXTIME_H 0x001E41E0 /* Reset: GLOBR */ #define I40E_PRTTSYN_TXTIME_H_TXTIEM_H_SHIFT 0 -#define I40E_PRTTSYN_TXTIME_H_TXTIEM_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_TXTIME_H_TXTIEM_H_SHIFT) -#define I40E_PRTTSYN_TXTIME_L 0x001E41C0 +#define I40E_PRTTSYN_TXTIME_H_TXTIEM_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TXTIME_H_TXTIEM_H_SHIFT) +#define I40E_PRTTSYN_TXTIME_L 0x001E41C0 /* Reset: GLOBR */ #define I40E_PRTTSYN_TXTIME_L_TXTIEM_L_SHIFT 0 -#define I40E_PRTTSYN_TXTIME_L_TXTIEM_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_TXTIME_L_TXTIEM_L_SHIFT) -#define I40E_GLSCD_QUANTA 0x000B2080 +#define I40E_PRTTSYN_TXTIME_L_TXTIEM_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TXTIME_L_TXTIEM_L_SHIFT) +#define I40E_GLSCD_QUANTA 0x000B2080 /* Reset: CORER */ #define I40E_GLSCD_QUANTA_TSCDQUANTA_SHIFT 0 -#define I40E_GLSCD_QUANTA_TSCDQUANTA_MASK (0x7 << I40E_GLSCD_QUANTA_TSCDQUANTA_SHIFT) -#define I40E_GL_MDET_RX 0x0012A510 +#define I40E_GLSCD_QUANTA_TSCDQUANTA_MASK I40E_MASK(0x7, I40E_GLSCD_QUANTA_TSCDQUANTA_SHIFT) +#define I40E_GL_MDET_RX 0x0012A510 /* Reset: CORER */ #define I40E_GL_MDET_RX_FUNCTION_SHIFT 0 -#define I40E_GL_MDET_RX_FUNCTION_MASK (0xFF << I40E_GL_MDET_RX_FUNCTION_SHIFT) +#define I40E_GL_MDET_RX_FUNCTION_MASK I40E_MASK(0xFF, I40E_GL_MDET_RX_FUNCTION_SHIFT) #define I40E_GL_MDET_RX_EVENT_SHIFT 8 -#define I40E_GL_MDET_RX_EVENT_MASK (0x1FF << I40E_GL_MDET_RX_EVENT_SHIFT) +#define I40E_GL_MDET_RX_EVENT_MASK I40E_MASK(0x1FF, I40E_GL_MDET_RX_EVENT_SHIFT) #define I40E_GL_MDET_RX_QUEUE_SHIFT 17 -#define I40E_GL_MDET_RX_QUEUE_MASK (0x3FFF << I40E_GL_MDET_RX_QUEUE_SHIFT) +#define I40E_GL_MDET_RX_QUEUE_MASK I40E_MASK(0x3FFF, I40E_GL_MDET_RX_QUEUE_SHIFT) #define I40E_GL_MDET_RX_VALID_SHIFT 31 -#define I40E_GL_MDET_RX_VALID_MASK (0x1 << I40E_GL_MDET_RX_VALID_SHIFT) -#define I40E_GL_MDET_TX 0x000E6480 -#define I40E_GL_MDET_TX_FUNCTION_SHIFT 0 -#define I40E_GL_MDET_TX_FUNCTION_MASK (0xFF << I40E_GL_MDET_TX_FUNCTION_SHIFT) -#define I40E_GL_MDET_TX_EVENT_SHIFT 8 -#define I40E_GL_MDET_TX_EVENT_MASK (0x1FF << I40E_GL_MDET_TX_EVENT_SHIFT) -#define I40E_GL_MDET_TX_QUEUE_SHIFT 17 -#define I40E_GL_MDET_TX_QUEUE_MASK (0x3FFF << I40E_GL_MDET_TX_QUEUE_SHIFT) +#define I40E_GL_MDET_RX_VALID_MASK I40E_MASK(0x1, I40E_GL_MDET_RX_VALID_SHIFT) +#define I40E_GL_MDET_TX 0x000E6480 /* Reset: CORER */ +#define I40E_GL_MDET_TX_QUEUE_SHIFT 0 +#define I40E_GL_MDET_TX_QUEUE_MASK I40E_MASK(0xFFF, I40E_GL_MDET_TX_QUEUE_SHIFT) +#define I40E_GL_MDET_TX_VF_NUM_SHIFT 12 +#define I40E_GL_MDET_TX_VF_NUM_MASK I40E_MASK(0x1FF, I40E_GL_MDET_TX_VF_NUM_SHIFT) +#define I40E_GL_MDET_TX_PF_NUM_SHIFT 21 +#define I40E_GL_MDET_TX_PF_NUM_MASK I40E_MASK(0xF, I40E_GL_MDET_TX_PF_NUM_SHIFT) +#define I40E_GL_MDET_TX_EVENT_SHIFT 25 +#define I40E_GL_MDET_TX_EVENT_MASK I40E_MASK(0x1F, I40E_GL_MDET_TX_EVENT_SHIFT) #define I40E_GL_MDET_TX_VALID_SHIFT 31 -#define I40E_GL_MDET_TX_VALID_MASK (0x1 << I40E_GL_MDET_TX_VALID_SHIFT) -#define I40E_PF_MDET_RX 0x0012A400 +#define I40E_GL_MDET_TX_VALID_MASK I40E_MASK(0x1, I40E_GL_MDET_TX_VALID_SHIFT) +#define I40E_PF_MDET_RX 0x0012A400 /* Reset: CORER */ #define I40E_PF_MDET_RX_VALID_SHIFT 0 -#define I40E_PF_MDET_RX_VALID_MASK (0x1 << I40E_PF_MDET_RX_VALID_SHIFT) -#define I40E_PF_MDET_TX 0x000E6400 +#define I40E_PF_MDET_RX_VALID_MASK I40E_MASK(0x1, I40E_PF_MDET_RX_VALID_SHIFT) +#define I40E_PF_MDET_TX 0x000E6400 /* Reset: CORER */ #define I40E_PF_MDET_TX_VALID_SHIFT 0 -#define I40E_PF_MDET_TX_VALID_MASK (0x1 << I40E_PF_MDET_TX_VALID_SHIFT) -#define I40E_PF_VT_PFALLOC 0x001C0500 +#define I40E_PF_MDET_TX_VALID_MASK I40E_MASK(0x1, I40E_PF_MDET_TX_VALID_SHIFT) +#define I40E_PF_VT_PFALLOC 0x001C0500 /* Reset: CORER */ #define I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT 0 -#define I40E_PF_VT_PFALLOC_FIRSTVF_MASK (0xFF << I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT) +#define I40E_PF_VT_PFALLOC_FIRSTVF_MASK I40E_MASK(0xFF, I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT) #define I40E_PF_VT_PFALLOC_LASTVF_SHIFT 8 -#define I40E_PF_VT_PFALLOC_LASTVF_MASK (0xFF << I40E_PF_VT_PFALLOC_LASTVF_SHIFT) +#define I40E_PF_VT_PFALLOC_LASTVF_MASK I40E_MASK(0xFF, I40E_PF_VT_PFALLOC_LASTVF_SHIFT) #define I40E_PF_VT_PFALLOC_VALID_SHIFT 31 -#define I40E_PF_VT_PFALLOC_VALID_MASK (0x1 << I40E_PF_VT_PFALLOC_VALID_SHIFT) -#define I40E_VP_MDET_RX(_VF) (0x0012A000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_PF_VT_PFALLOC_VALID_MASK I40E_MASK(0x1, I40E_PF_VT_PFALLOC_VALID_SHIFT) +#define I40E_VP_MDET_RX(_VF) (0x0012A000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VP_MDET_RX_MAX_INDEX 127 #define I40E_VP_MDET_RX_VALID_SHIFT 0 -#define I40E_VP_MDET_RX_VALID_MASK (0x1 << I40E_VP_MDET_RX_VALID_SHIFT) -#define I40E_VP_MDET_TX(_VF) (0x000E6000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VP_MDET_RX_VALID_MASK I40E_MASK(0x1, I40E_VP_MDET_RX_VALID_SHIFT) +#define I40E_VP_MDET_TX(_VF) (0x000E6000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VP_MDET_TX_MAX_INDEX 127 #define I40E_VP_MDET_TX_VALID_SHIFT 0 -#define I40E_VP_MDET_TX_VALID_MASK (0x1 << I40E_VP_MDET_TX_VALID_SHIFT) -#define I40E_GLPM_WUMC 0x0006C800 +#define I40E_VP_MDET_TX_VALID_MASK I40E_MASK(0x1, I40E_VP_MDET_TX_VALID_SHIFT) +#define I40E_GLPM_WUMC 0x0006C800 /* Reset: POR */ #define I40E_GLPM_WUMC_NOTCO_SHIFT 0 -#define I40E_GLPM_WUMC_NOTCO_MASK (0x1 << I40E_GLPM_WUMC_NOTCO_SHIFT) +#define I40E_GLPM_WUMC_NOTCO_MASK I40E_MASK(0x1, I40E_GLPM_WUMC_NOTCO_SHIFT) #define I40E_GLPM_WUMC_SRST_PIN_VAL_SHIFT 1 -#define I40E_GLPM_WUMC_SRST_PIN_VAL_MASK (0x1 << I40E_GLPM_WUMC_SRST_PIN_VAL_SHIFT) +#define I40E_GLPM_WUMC_SRST_PIN_VAL_MASK I40E_MASK(0x1, I40E_GLPM_WUMC_SRST_PIN_VAL_SHIFT) #define I40E_GLPM_WUMC_ROL_MODE_SHIFT 2 -#define I40E_GLPM_WUMC_ROL_MODE_MASK (0x1 << I40E_GLPM_WUMC_ROL_MODE_SHIFT) +#define I40E_GLPM_WUMC_ROL_MODE_MASK I40E_MASK(0x1, I40E_GLPM_WUMC_ROL_MODE_SHIFT) #define I40E_GLPM_WUMC_RESERVED_4_SHIFT 3 -#define I40E_GLPM_WUMC_RESERVED_4_MASK (0x1FFF << I40E_GLPM_WUMC_RESERVED_4_SHIFT) +#define I40E_GLPM_WUMC_RESERVED_4_MASK I40E_MASK(0x1FFF, I40E_GLPM_WUMC_RESERVED_4_SHIFT) #define I40E_GLPM_WUMC_MNG_WU_PF_SHIFT 16 -#define I40E_GLPM_WUMC_MNG_WU_PF_MASK (0xFFFF << I40E_GLPM_WUMC_MNG_WU_PF_SHIFT) -#define I40E_PFPM_APM 0x000B8080 +#define I40E_GLPM_WUMC_MNG_WU_PF_MASK I40E_MASK(0xFFFF, I40E_GLPM_WUMC_MNG_WU_PF_SHIFT) +#define I40E_PFPM_APM 0x000B8080 /* Reset: POR */ #define I40E_PFPM_APM_APME_SHIFT 0 -#define I40E_PFPM_APM_APME_MASK (0x1 << I40E_PFPM_APM_APME_SHIFT) -#define I40E_PFPM_FHFT_LENGTH(_i) (0x0006A000 + ((_i) * 128)) /* _i=0...7 */ +#define I40E_PFPM_APM_APME_MASK I40E_MASK(0x1, I40E_PFPM_APM_APME_SHIFT) +#define I40E_PFPM_FHFT_LENGTH(_i) (0x0006A000 + ((_i) * 128)) /* _i=0...7 */ /* Reset: POR */ #define I40E_PFPM_FHFT_LENGTH_MAX_INDEX 7 #define I40E_PFPM_FHFT_LENGTH_LENGTH_SHIFT 0 -#define I40E_PFPM_FHFT_LENGTH_LENGTH_MASK (0xFF << I40E_PFPM_FHFT_LENGTH_LENGTH_SHIFT) -#define I40E_PFPM_WUC 0x0006B200 +#define I40E_PFPM_FHFT_LENGTH_LENGTH_MASK I40E_MASK(0xFF, I40E_PFPM_FHFT_LENGTH_LENGTH_SHIFT) +#define I40E_PFPM_WUC 0x0006B200 /* Reset: POR */ #define I40E_PFPM_WUC_EN_APM_D0_SHIFT 5 -#define I40E_PFPM_WUC_EN_APM_D0_MASK (0x1 << I40E_PFPM_WUC_EN_APM_D0_SHIFT) -#define I40E_PFPM_WUFC 0x0006B400 +#define I40E_PFPM_WUC_EN_APM_D0_MASK I40E_MASK(0x1, I40E_PFPM_WUC_EN_APM_D0_SHIFT) +#define I40E_PFPM_WUFC 0x0006B400 /* Reset: POR */ #define I40E_PFPM_WUFC_LNKC_SHIFT 0 -#define I40E_PFPM_WUFC_LNKC_MASK (0x1 << I40E_PFPM_WUFC_LNKC_SHIFT) +#define I40E_PFPM_WUFC_LNKC_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_LNKC_SHIFT) #define I40E_PFPM_WUFC_MAG_SHIFT 1 -#define I40E_PFPM_WUFC_MAG_MASK (0x1 << I40E_PFPM_WUFC_MAG_SHIFT) +#define I40E_PFPM_WUFC_MAG_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_MAG_SHIFT) #define I40E_PFPM_WUFC_MNG_SHIFT 3 -#define I40E_PFPM_WUFC_MNG_MASK (0x1 << I40E_PFPM_WUFC_MNG_SHIFT) +#define I40E_PFPM_WUFC_MNG_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_MNG_SHIFT) #define I40E_PFPM_WUFC_FLX0_ACT_SHIFT 4 -#define I40E_PFPM_WUFC_FLX0_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX0_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX0_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX0_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX1_ACT_SHIFT 5 -#define I40E_PFPM_WUFC_FLX1_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX1_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX1_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX1_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX2_ACT_SHIFT 6 -#define I40E_PFPM_WUFC_FLX2_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX2_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX2_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX2_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX3_ACT_SHIFT 7 -#define I40E_PFPM_WUFC_FLX3_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX3_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX3_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX3_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX4_ACT_SHIFT 8 -#define I40E_PFPM_WUFC_FLX4_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX4_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX4_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX4_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX5_ACT_SHIFT 9 -#define I40E_PFPM_WUFC_FLX5_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX5_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX5_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX5_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX6_ACT_SHIFT 10 -#define I40E_PFPM_WUFC_FLX6_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX6_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX6_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX6_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX7_ACT_SHIFT 11 -#define I40E_PFPM_WUFC_FLX7_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX7_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX7_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX7_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX0_SHIFT 16 -#define I40E_PFPM_WUFC_FLX0_MASK (0x1 << I40E_PFPM_WUFC_FLX0_SHIFT) +#define I40E_PFPM_WUFC_FLX0_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX0_SHIFT) #define I40E_PFPM_WUFC_FLX1_SHIFT 17 -#define I40E_PFPM_WUFC_FLX1_MASK (0x1 << I40E_PFPM_WUFC_FLX1_SHIFT) +#define I40E_PFPM_WUFC_FLX1_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX1_SHIFT) #define I40E_PFPM_WUFC_FLX2_SHIFT 18 -#define I40E_PFPM_WUFC_FLX2_MASK (0x1 << I40E_PFPM_WUFC_FLX2_SHIFT) +#define I40E_PFPM_WUFC_FLX2_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX2_SHIFT) #define I40E_PFPM_WUFC_FLX3_SHIFT 19 -#define I40E_PFPM_WUFC_FLX3_MASK (0x1 << I40E_PFPM_WUFC_FLX3_SHIFT) +#define I40E_PFPM_WUFC_FLX3_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX3_SHIFT) #define I40E_PFPM_WUFC_FLX4_SHIFT 20 -#define I40E_PFPM_WUFC_FLX4_MASK (0x1 << I40E_PFPM_WUFC_FLX4_SHIFT) +#define I40E_PFPM_WUFC_FLX4_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX4_SHIFT) #define I40E_PFPM_WUFC_FLX5_SHIFT 21 -#define I40E_PFPM_WUFC_FLX5_MASK (0x1 << I40E_PFPM_WUFC_FLX5_SHIFT) +#define I40E_PFPM_WUFC_FLX5_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX5_SHIFT) #define I40E_PFPM_WUFC_FLX6_SHIFT 22 -#define I40E_PFPM_WUFC_FLX6_MASK (0x1 << I40E_PFPM_WUFC_FLX6_SHIFT) +#define I40E_PFPM_WUFC_FLX6_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX6_SHIFT) #define I40E_PFPM_WUFC_FLX7_SHIFT 23 -#define I40E_PFPM_WUFC_FLX7_MASK (0x1 << I40E_PFPM_WUFC_FLX7_SHIFT) +#define I40E_PFPM_WUFC_FLX7_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX7_SHIFT) #define I40E_PFPM_WUFC_FW_RST_WK_SHIFT 31 -#define I40E_PFPM_WUFC_FW_RST_WK_MASK (0x1 << I40E_PFPM_WUFC_FW_RST_WK_SHIFT) -#define I40E_PFPM_WUS 0x0006B600 +#define I40E_PFPM_WUFC_FW_RST_WK_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FW_RST_WK_SHIFT) +#define I40E_PFPM_WUS 0x0006B600 /* Reset: POR */ #define I40E_PFPM_WUS_LNKC_SHIFT 0 -#define I40E_PFPM_WUS_LNKC_MASK (0x1 << I40E_PFPM_WUS_LNKC_SHIFT) +#define I40E_PFPM_WUS_LNKC_MASK I40E_MASK(0x1, I40E_PFPM_WUS_LNKC_SHIFT) #define I40E_PFPM_WUS_MAG_SHIFT 1 -#define I40E_PFPM_WUS_MAG_MASK (0x1 << I40E_PFPM_WUS_MAG_SHIFT) +#define I40E_PFPM_WUS_MAG_MASK I40E_MASK(0x1, I40E_PFPM_WUS_MAG_SHIFT) #define I40E_PFPM_WUS_PME_STATUS_SHIFT 2 -#define I40E_PFPM_WUS_PME_STATUS_MASK (0x1 << I40E_PFPM_WUS_PME_STATUS_SHIFT) +#define I40E_PFPM_WUS_PME_STATUS_MASK I40E_MASK(0x1, I40E_PFPM_WUS_PME_STATUS_SHIFT) #define I40E_PFPM_WUS_MNG_SHIFT 3 -#define I40E_PFPM_WUS_MNG_MASK (0x1 << I40E_PFPM_WUS_MNG_SHIFT) +#define I40E_PFPM_WUS_MNG_MASK I40E_MASK(0x1, I40E_PFPM_WUS_MNG_SHIFT) #define I40E_PFPM_WUS_FLX0_SHIFT 16 -#define I40E_PFPM_WUS_FLX0_MASK (0x1 << I40E_PFPM_WUS_FLX0_SHIFT) +#define I40E_PFPM_WUS_FLX0_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX0_SHIFT) #define I40E_PFPM_WUS_FLX1_SHIFT 17 -#define I40E_PFPM_WUS_FLX1_MASK (0x1 << I40E_PFPM_WUS_FLX1_SHIFT) +#define I40E_PFPM_WUS_FLX1_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX1_SHIFT) #define I40E_PFPM_WUS_FLX2_SHIFT 18 -#define I40E_PFPM_WUS_FLX2_MASK (0x1 << I40E_PFPM_WUS_FLX2_SHIFT) +#define I40E_PFPM_WUS_FLX2_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX2_SHIFT) #define I40E_PFPM_WUS_FLX3_SHIFT 19 -#define I40E_PFPM_WUS_FLX3_MASK (0x1 << I40E_PFPM_WUS_FLX3_SHIFT) +#define I40E_PFPM_WUS_FLX3_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX3_SHIFT) #define I40E_PFPM_WUS_FLX4_SHIFT 20 -#define I40E_PFPM_WUS_FLX4_MASK (0x1 << I40E_PFPM_WUS_FLX4_SHIFT) +#define I40E_PFPM_WUS_FLX4_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX4_SHIFT) #define I40E_PFPM_WUS_FLX5_SHIFT 21 -#define I40E_PFPM_WUS_FLX5_MASK (0x1 << I40E_PFPM_WUS_FLX5_SHIFT) +#define I40E_PFPM_WUS_FLX5_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX5_SHIFT) #define I40E_PFPM_WUS_FLX6_SHIFT 22 -#define I40E_PFPM_WUS_FLX6_MASK (0x1 << I40E_PFPM_WUS_FLX6_SHIFT) +#define I40E_PFPM_WUS_FLX6_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX6_SHIFT) #define I40E_PFPM_WUS_FLX7_SHIFT 23 -#define I40E_PFPM_WUS_FLX7_MASK (0x1 << I40E_PFPM_WUS_FLX7_SHIFT) +#define I40E_PFPM_WUS_FLX7_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX7_SHIFT) #define I40E_PFPM_WUS_FW_RST_WK_SHIFT 31 -#define I40E_PFPM_WUS_FW_RST_WK_MASK (0x1 << I40E_PFPM_WUS_FW_RST_WK_SHIFT) -#define I40E_PRTPM_FHFHR 0x0006C000 +#define I40E_PFPM_WUS_FW_RST_WK_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FW_RST_WK_SHIFT) +#define I40E_PRTPM_FHFHR 0x0006C000 /* Reset: POR */ #define I40E_PRTPM_FHFHR_UNICAST_SHIFT 0 -#define I40E_PRTPM_FHFHR_UNICAST_MASK (0x1 << I40E_PRTPM_FHFHR_UNICAST_SHIFT) +#define I40E_PRTPM_FHFHR_UNICAST_MASK I40E_MASK(0x1, I40E_PRTPM_FHFHR_UNICAST_SHIFT) #define I40E_PRTPM_FHFHR_MULTICAST_SHIFT 1 -#define I40E_PRTPM_FHFHR_MULTICAST_MASK (0x1 << I40E_PRTPM_FHFHR_MULTICAST_SHIFT) -#define I40E_PRTPM_SAH(_i) (0x001E44C0 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRTPM_FHFHR_MULTICAST_MASK I40E_MASK(0x1, I40E_PRTPM_FHFHR_MULTICAST_SHIFT) +#define I40E_PRTPM_SAH(_i) (0x001E44C0 + ((_i) * 32)) /* _i=0...3 */ /* Reset: PFR */ #define I40E_PRTPM_SAH_MAX_INDEX 3 #define I40E_PRTPM_SAH_PFPM_SAH_SHIFT 0 -#define I40E_PRTPM_SAH_PFPM_SAH_MASK (0xFFFF << I40E_PRTPM_SAH_PFPM_SAH_SHIFT) +#define I40E_PRTPM_SAH_PFPM_SAH_MASK I40E_MASK(0xFFFF, I40E_PRTPM_SAH_PFPM_SAH_SHIFT) #define I40E_PRTPM_SAH_PF_NUM_SHIFT 26 -#define I40E_PRTPM_SAH_PF_NUM_MASK (0xF << I40E_PRTPM_SAH_PF_NUM_SHIFT) +#define I40E_PRTPM_SAH_PF_NUM_MASK I40E_MASK(0xF, I40E_PRTPM_SAH_PF_NUM_SHIFT) #define I40E_PRTPM_SAH_MC_MAG_EN_SHIFT 30 -#define I40E_PRTPM_SAH_MC_MAG_EN_MASK (0x1 << I40E_PRTPM_SAH_MC_MAG_EN_SHIFT) +#define I40E_PRTPM_SAH_MC_MAG_EN_MASK I40E_MASK(0x1, I40E_PRTPM_SAH_MC_MAG_EN_SHIFT) #define I40E_PRTPM_SAH_AV_SHIFT 31 -#define I40E_PRTPM_SAH_AV_MASK (0x1 << I40E_PRTPM_SAH_AV_SHIFT) -#define I40E_PRTPM_SAL(_i) (0x001E4440 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRTPM_SAH_AV_MASK I40E_MASK(0x1, I40E_PRTPM_SAH_AV_SHIFT) +#define I40E_PRTPM_SAL(_i) (0x001E4440 + ((_i) * 32)) /* _i=0...3 */ /* Reset: PFR */ #define I40E_PRTPM_SAL_MAX_INDEX 3 #define I40E_PRTPM_SAL_PFPM_SAL_SHIFT 0 -#define I40E_PRTPM_SAL_PFPM_SAL_MASK (0xFFFFFFFF << I40E_PRTPM_SAL_PFPM_SAL_SHIFT) -#define I40E_VF_ARQBAH1 0x00006000 +#define I40E_PRTPM_SAL_PFPM_SAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTPM_SAL_PFPM_SAL_SHIFT) +#define I40E_VF_ARQBAH1 0x00006000 /* Reset: EMPR */ #define I40E_VF_ARQBAH1_ARQBAH_SHIFT 0 -#define I40E_VF_ARQBAH1_ARQBAH_MASK (0xFFFFFFFF << I40E_VF_ARQBAH1_ARQBAH_SHIFT) -#define I40E_VF_ARQBAL1 0x00006C00 +#define I40E_VF_ARQBAH1_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAH1_ARQBAH_SHIFT) +#define I40E_VF_ARQBAL1 0x00006C00 /* Reset: EMPR */ #define I40E_VF_ARQBAL1_ARQBAL_SHIFT 0 -#define I40E_VF_ARQBAL1_ARQBAL_MASK (0xFFFFFFFF << I40E_VF_ARQBAL1_ARQBAL_SHIFT) -#define I40E_VF_ARQH1 0x00007400 +#define I40E_VF_ARQBAL1_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAL1_ARQBAL_SHIFT) +#define I40E_VF_ARQH1 0x00007400 /* Reset: EMPR */ #define I40E_VF_ARQH1_ARQH_SHIFT 0 -#define I40E_VF_ARQH1_ARQH_MASK (0x3FF << I40E_VF_ARQH1_ARQH_SHIFT) -#define I40E_VF_ARQLEN1 0x00008000 +#define I40E_VF_ARQH1_ARQH_MASK I40E_MASK(0x3FF, I40E_VF_ARQH1_ARQH_SHIFT) +#define I40E_VF_ARQLEN1 0x00008000 /* Reset: EMPR */ #define I40E_VF_ARQLEN1_ARQLEN_SHIFT 0 -#define I40E_VF_ARQLEN1_ARQLEN_MASK (0x3FF << I40E_VF_ARQLEN1_ARQLEN_SHIFT) +#define I40E_VF_ARQLEN1_ARQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ARQLEN1_ARQLEN_SHIFT) #define I40E_VF_ARQLEN1_ARQVFE_SHIFT 28 -#define I40E_VF_ARQLEN1_ARQVFE_MASK (0x1 << I40E_VF_ARQLEN1_ARQVFE_SHIFT) +#define I40E_VF_ARQLEN1_ARQVFE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQVFE_SHIFT) #define I40E_VF_ARQLEN1_ARQOVFL_SHIFT 29 -#define I40E_VF_ARQLEN1_ARQOVFL_MASK (0x1 << I40E_VF_ARQLEN1_ARQOVFL_SHIFT) +#define I40E_VF_ARQLEN1_ARQOVFL_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQOVFL_SHIFT) #define I40E_VF_ARQLEN1_ARQCRIT_SHIFT 30 -#define I40E_VF_ARQLEN1_ARQCRIT_MASK (0x1 << I40E_VF_ARQLEN1_ARQCRIT_SHIFT) +#define I40E_VF_ARQLEN1_ARQCRIT_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQCRIT_SHIFT) #define I40E_VF_ARQLEN1_ARQENABLE_SHIFT 31 -#define I40E_VF_ARQLEN1_ARQENABLE_MASK (0x1 << I40E_VF_ARQLEN1_ARQENABLE_SHIFT) -#define I40E_VF_ARQT1 0x00007000 +#define I40E_VF_ARQLEN1_ARQENABLE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQENABLE_SHIFT) +#define I40E_VF_ARQT1 0x00007000 /* Reset: EMPR */ #define I40E_VF_ARQT1_ARQT_SHIFT 0 -#define I40E_VF_ARQT1_ARQT_MASK (0x3FF << I40E_VF_ARQT1_ARQT_SHIFT) -#define I40E_VF_ATQBAH1 0x00007800 +#define I40E_VF_ARQT1_ARQT_MASK I40E_MASK(0x3FF, I40E_VF_ARQT1_ARQT_SHIFT) +#define I40E_VF_ATQBAH1 0x00007800 /* Reset: EMPR */ #define I40E_VF_ATQBAH1_ATQBAH_SHIFT 0 -#define I40E_VF_ATQBAH1_ATQBAH_MASK (0xFFFFFFFF << I40E_VF_ATQBAH1_ATQBAH_SHIFT) -#define I40E_VF_ATQBAL1 0x00007C00 +#define I40E_VF_ATQBAH1_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAH1_ATQBAH_SHIFT) +#define I40E_VF_ATQBAL1 0x00007C00 /* Reset: EMPR */ #define I40E_VF_ATQBAL1_ATQBAL_SHIFT 0 -#define I40E_VF_ATQBAL1_ATQBAL_MASK (0xFFFFFFFF << I40E_VF_ATQBAL1_ATQBAL_SHIFT) -#define I40E_VF_ATQH1 0x00006400 +#define I40E_VF_ATQBAL1_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAL1_ATQBAL_SHIFT) +#define I40E_VF_ATQH1 0x00006400 /* Reset: EMPR */ #define I40E_VF_ATQH1_ATQH_SHIFT 0 -#define I40E_VF_ATQH1_ATQH_MASK (0x3FF << I40E_VF_ATQH1_ATQH_SHIFT) -#define I40E_VF_ATQLEN1 0x00006800 +#define I40E_VF_ATQH1_ATQH_MASK I40E_MASK(0x3FF, I40E_VF_ATQH1_ATQH_SHIFT) +#define I40E_VF_ATQLEN1 0x00006800 /* Reset: EMPR */ #define I40E_VF_ATQLEN1_ATQLEN_SHIFT 0 -#define I40E_VF_ATQLEN1_ATQLEN_MASK (0x3FF << I40E_VF_ATQLEN1_ATQLEN_SHIFT) +#define I40E_VF_ATQLEN1_ATQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ATQLEN1_ATQLEN_SHIFT) #define I40E_VF_ATQLEN1_ATQVFE_SHIFT 28 -#define I40E_VF_ATQLEN1_ATQVFE_MASK (0x1 << I40E_VF_ATQLEN1_ATQVFE_SHIFT) +#define I40E_VF_ATQLEN1_ATQVFE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQVFE_SHIFT) #define I40E_VF_ATQLEN1_ATQOVFL_SHIFT 29 -#define I40E_VF_ATQLEN1_ATQOVFL_MASK (0x1 << I40E_VF_ATQLEN1_ATQOVFL_SHIFT) +#define I40E_VF_ATQLEN1_ATQOVFL_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQOVFL_SHIFT) #define I40E_VF_ATQLEN1_ATQCRIT_SHIFT 30 -#define I40E_VF_ATQLEN1_ATQCRIT_MASK (0x1 << I40E_VF_ATQLEN1_ATQCRIT_SHIFT) +#define I40E_VF_ATQLEN1_ATQCRIT_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQCRIT_SHIFT) #define I40E_VF_ATQLEN1_ATQENABLE_SHIFT 31 -#define I40E_VF_ATQLEN1_ATQENABLE_MASK (0x1 << I40E_VF_ATQLEN1_ATQENABLE_SHIFT) -#define I40E_VF_ATQT1 0x00008400 +#define I40E_VF_ATQLEN1_ATQENABLE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQENABLE_SHIFT) +#define I40E_VF_ATQT1 0x00008400 /* Reset: EMPR */ #define I40E_VF_ATQT1_ATQT_SHIFT 0 -#define I40E_VF_ATQT1_ATQT_MASK (0x3FF << I40E_VF_ATQT1_ATQT_SHIFT) -#define I40E_VFGEN_RSTAT 0x00008800 +#define I40E_VF_ATQT1_ATQT_MASK I40E_MASK(0x3FF, I40E_VF_ATQT1_ATQT_SHIFT) +#define I40E_VFGEN_RSTAT 0x00008800 /* Reset: VFR */ #define I40E_VFGEN_RSTAT_VFR_STATE_SHIFT 0 -#define I40E_VFGEN_RSTAT_VFR_STATE_MASK (0x3 << I40E_VFGEN_RSTAT_VFR_STATE_SHIFT) -#define I40E_VFINT_DYN_CTL01 0x00005C00 +#define I40E_VFGEN_RSTAT_VFR_STATE_MASK I40E_MASK(0x3, I40E_VFGEN_RSTAT_VFR_STATE_SHIFT) +#define I40E_VFINT_DYN_CTL01 0x00005C00 /* Reset: VFR */ #define I40E_VFINT_DYN_CTL01_INTENA_SHIFT 0 -#define I40E_VFINT_DYN_CTL01_INTENA_MASK (0x1 << I40E_VFINT_DYN_CTL01_INTENA_SHIFT) +#define I40E_VFINT_DYN_CTL01_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_INTENA_SHIFT) #define I40E_VFINT_DYN_CTL01_CLEARPBA_SHIFT 1 -#define I40E_VFINT_DYN_CTL01_CLEARPBA_MASK (0x1 << I40E_VFINT_DYN_CTL01_CLEARPBA_SHIFT) +#define I40E_VFINT_DYN_CTL01_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_CLEARPBA_SHIFT) #define I40E_VFINT_DYN_CTL01_SWINT_TRIG_SHIFT 2 -#define I40E_VFINT_DYN_CTL01_SWINT_TRIG_MASK (0x1 << I40E_VFINT_DYN_CTL01_SWINT_TRIG_SHIFT) +#define I40E_VFINT_DYN_CTL01_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_SWINT_TRIG_SHIFT) #define I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT 3 -#define I40E_VFINT_DYN_CTL01_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTL01_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTL01_INTERVAL_MASK (0xFFF << I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT) +#define I40E_VFINT_DYN_CTL01_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT) #define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_MASK (0x1 << I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_SHIFT) +#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_SHIFT) #define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_SHIFT 25 -#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTL01_SW_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL01_SW_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTL01_INTENA_MSK_SHIFT 31 -#define I40E_VFINT_DYN_CTL01_INTENA_MSK_MASK (0x1 << I40E_VFINT_DYN_CTL01_INTENA_MSK_SHIFT) -#define I40E_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) +#define I40E_VFINT_DYN_CTL01_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_INTENA_MSK_SHIFT) +#define I40E_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...15 */ /* Reset: VFR */ #define I40E_VFINT_DYN_CTLN1_MAX_INDEX 15 #define I40E_VFINT_DYN_CTLN1_INTENA_SHIFT 0 -#define I40E_VFINT_DYN_CTLN1_INTENA_MASK (0x1 << I40E_VFINT_DYN_CTLN1_INTENA_SHIFT) +#define I40E_VFINT_DYN_CTLN1_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_INTENA_SHIFT) #define I40E_VFINT_DYN_CTLN1_CLEARPBA_SHIFT 1 -#define I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK (0x1 << I40E_VFINT_DYN_CTLN1_CLEARPBA_SHIFT) +#define I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_CLEARPBA_SHIFT) #define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT 2 -#define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK (0x1 << I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT) +#define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT) #define I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT 3 -#define I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTLN1_INTERVAL_MASK (0xFFF << I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT) +#define I40E_VFINT_DYN_CTLN1_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT) #define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK (0x1 << I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT) +#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT) #define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_SHIFT 25 -#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTLN1_INTENA_MSK_SHIFT 31 -#define I40E_VFINT_DYN_CTLN1_INTENA_MSK_MASK (0x1 << I40E_VFINT_DYN_CTLN1_INTENA_MSK_SHIFT) -#define I40E_VFINT_ICR0_ENA1 0x00005000 +#define I40E_VFINT_DYN_CTLN1_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_INTENA_MSK_SHIFT) +#define I40E_VFINT_ICR0_ENA1 0x00005000 /* Reset: CORER */ #define I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_MASK (0x1 << I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_SHIFT) +#define I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_SHIFT) #define I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT 30 -#define I40E_VFINT_ICR0_ENA1_ADMINQ_MASK (0x1 << I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT) +#define I40E_VFINT_ICR0_ENA1_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT) #define I40E_VFINT_ICR0_ENA1_RSVD_SHIFT 31 -#define I40E_VFINT_ICR0_ENA1_RSVD_MASK (0x1 << I40E_VFINT_ICR0_ENA1_RSVD_SHIFT) -#define I40E_VFINT_ICR01 0x00004800 +#define I40E_VFINT_ICR0_ENA1_RSVD_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_RSVD_SHIFT) +#define I40E_VFINT_ICR01 0x00004800 /* Reset: CORER */ #define I40E_VFINT_ICR01_INTEVENT_SHIFT 0 -#define I40E_VFINT_ICR01_INTEVENT_MASK (0x1 << I40E_VFINT_ICR01_INTEVENT_SHIFT) +#define I40E_VFINT_ICR01_INTEVENT_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_INTEVENT_SHIFT) #define I40E_VFINT_ICR01_QUEUE_0_SHIFT 1 -#define I40E_VFINT_ICR01_QUEUE_0_MASK (0x1 << I40E_VFINT_ICR01_QUEUE_0_SHIFT) +#define I40E_VFINT_ICR01_QUEUE_0_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_0_SHIFT) #define I40E_VFINT_ICR01_QUEUE_1_SHIFT 2 -#define I40E_VFINT_ICR01_QUEUE_1_MASK (0x1 << I40E_VFINT_ICR01_QUEUE_1_SHIFT) +#define I40E_VFINT_ICR01_QUEUE_1_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_1_SHIFT) #define I40E_VFINT_ICR01_QUEUE_2_SHIFT 3 -#define I40E_VFINT_ICR01_QUEUE_2_MASK (0x1 << I40E_VFINT_ICR01_QUEUE_2_SHIFT) +#define I40E_VFINT_ICR01_QUEUE_2_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_2_SHIFT) #define I40E_VFINT_ICR01_QUEUE_3_SHIFT 4 -#define I40E_VFINT_ICR01_QUEUE_3_MASK (0x1 << I40E_VFINT_ICR01_QUEUE_3_SHIFT) +#define I40E_VFINT_ICR01_QUEUE_3_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_3_SHIFT) #define I40E_VFINT_ICR01_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_VFINT_ICR01_LINK_STAT_CHANGE_MASK (0x1 << I40E_VFINT_ICR01_LINK_STAT_CHANGE_SHIFT) +#define I40E_VFINT_ICR01_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_LINK_STAT_CHANGE_SHIFT) #define I40E_VFINT_ICR01_ADMINQ_SHIFT 30 -#define I40E_VFINT_ICR01_ADMINQ_MASK (0x1 << I40E_VFINT_ICR01_ADMINQ_SHIFT) +#define I40E_VFINT_ICR01_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_ADMINQ_SHIFT) #define I40E_VFINT_ICR01_SWINT_SHIFT 31 -#define I40E_VFINT_ICR01_SWINT_MASK (0x1 << I40E_VFINT_ICR01_SWINT_SHIFT) -#define I40E_VFINT_ITR01(_i) (0x00004C00 + ((_i) * 4)) /* _i=0...2 */ +#define I40E_VFINT_ICR01_SWINT_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_SWINT_SHIFT) +#define I40E_VFINT_ITR01(_i) (0x00004C00 + ((_i) * 4)) /* _i=0...2 */ /* Reset: VFR */ #define I40E_VFINT_ITR01_MAX_INDEX 2 #define I40E_VFINT_ITR01_INTERVAL_SHIFT 0 -#define I40E_VFINT_ITR01_INTERVAL_MASK (0xFFF << I40E_VFINT_ITR01_INTERVAL_SHIFT) -#define I40E_VFINT_ITRN1(_i, _INTVF) (0x00002800 + ((_i) * 64 + (_INTVF) * 4)) +#define I40E_VFINT_ITR01_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITR01_INTERVAL_SHIFT) +#define I40E_VFINT_ITRN1(_i, _INTVF) (0x00002800 + ((_i) * 64 + (_INTVF) * 4)) /* _i=0...2, _INTVF=0...15 */ /* Reset: VFR */ #define I40E_VFINT_ITRN1_MAX_INDEX 2 #define I40E_VFINT_ITRN1_INTERVAL_SHIFT 0 -#define I40E_VFINT_ITRN1_INTERVAL_MASK (0xFFF << I40E_VFINT_ITRN1_INTERVAL_SHIFT) -#define I40E_VFINT_STAT_CTL01 0x00005400 +#define I40E_VFINT_ITRN1_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITRN1_INTERVAL_SHIFT) +#define I40E_VFINT_STAT_CTL01 0x00005400 /* Reset: VFR */ #define I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_SHIFT 2 -#define I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_MASK (0x3 << I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_SHIFT) -#define I40E_QRX_TAIL1(_Q) (0x00002000 + ((_Q) * 4)) /* _i=0...15 */ +#define I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_SHIFT) +#define I40E_QRX_TAIL1(_Q) (0x00002000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_QRX_TAIL1_MAX_INDEX 15 #define I40E_QRX_TAIL1_TAIL_SHIFT 0 -#define I40E_QRX_TAIL1_TAIL_MASK (0x1FFF << I40E_QRX_TAIL1_TAIL_SHIFT) -#define I40E_QTX_TAIL1(_Q) (0x00000000 + ((_Q) * 4)) /* _i=0...15 */ +#define I40E_QRX_TAIL1_TAIL_MASK I40E_MASK(0x1FFF, I40E_QRX_TAIL1_TAIL_SHIFT) +#define I40E_QTX_TAIL1(_Q) (0x00000000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: PFR */ #define I40E_QTX_TAIL1_MAX_INDEX 15 #define I40E_QTX_TAIL1_TAIL_SHIFT 0 -#define I40E_QTX_TAIL1_TAIL_MASK (0x1FFF << I40E_QTX_TAIL1_TAIL_SHIFT) -#define I40E_VFMSIX_PBA 0x00002000 +#define I40E_QTX_TAIL1_TAIL_MASK I40E_MASK(0x1FFF, I40E_QTX_TAIL1_TAIL_SHIFT) +#define I40E_VFMSIX_PBA 0x00002000 /* Reset: VFLR */ #define I40E_VFMSIX_PBA_PENBIT_SHIFT 0 -#define I40E_VFMSIX_PBA_PENBIT_MASK (0xFFFFFFFF << I40E_VFMSIX_PBA_PENBIT_SHIFT) -#define I40E_VFMSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...16 */ +#define I40E_VFMSIX_PBA_PENBIT_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_PBA_PENBIT_SHIFT) +#define I40E_VFMSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */ #define I40E_VFMSIX_TADD_MAX_INDEX 16 #define I40E_VFMSIX_TADD_MSIXTADD10_SHIFT 0 -#define I40E_VFMSIX_TADD_MSIXTADD10_MASK (0x3 << I40E_VFMSIX_TADD_MSIXTADD10_SHIFT) +#define I40E_VFMSIX_TADD_MSIXTADD10_MASK I40E_MASK(0x3, I40E_VFMSIX_TADD_MSIXTADD10_SHIFT) #define I40E_VFMSIX_TADD_MSIXTADD_SHIFT 2 -#define I40E_VFMSIX_TADD_MSIXTADD_MASK (0x3FFFFFFF << I40E_VFMSIX_TADD_MSIXTADD_SHIFT) -#define I40E_VFMSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...16 */ +#define I40E_VFMSIX_TADD_MSIXTADD_MASK I40E_MASK(0x3FFFFFFF, I40E_VFMSIX_TADD_MSIXTADD_SHIFT) +#define I40E_VFMSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */ #define I40E_VFMSIX_TMSG_MAX_INDEX 16 #define I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT 0 -#define I40E_VFMSIX_TMSG_MSIXTMSG_MASK (0xFFFFFFFF << I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT) -#define I40E_VFMSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...16 */ +#define I40E_VFMSIX_TMSG_MSIXTMSG_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT) +#define I40E_VFMSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */ #define I40E_VFMSIX_TUADD_MAX_INDEX 16 #define I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT 0 -#define I40E_VFMSIX_TUADD_MSIXTUADD_MASK (0xFFFFFFFF << I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT) -#define I40E_VFMSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...16 */ +#define I40E_VFMSIX_TUADD_MSIXTUADD_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT) +#define I40E_VFMSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */ #define I40E_VFMSIX_TVCTRL_MAX_INDEX 16 #define I40E_VFMSIX_TVCTRL_MASK_SHIFT 0 -#define I40E_VFMSIX_TVCTRL_MASK_MASK (0x1 << I40E_VFMSIX_TVCTRL_MASK_SHIFT) -#define I40E_VFCM_PE_ERRDATA 0x0000DC00 +#define I40E_VFMSIX_TVCTRL_MASK_MASK I40E_MASK(0x1, I40E_VFMSIX_TVCTRL_MASK_SHIFT) +#define I40E_VFCM_PE_ERRDATA 0x0000DC00 /* Reset: VFR */ #define I40E_VFCM_PE_ERRDATA_ERROR_CODE_SHIFT 0 -#define I40E_VFCM_PE_ERRDATA_ERROR_CODE_MASK (0xF << I40E_VFCM_PE_ERRDATA_ERROR_CODE_SHIFT) +#define I40E_VFCM_PE_ERRDATA_ERROR_CODE_MASK I40E_MASK(0xF, I40E_VFCM_PE_ERRDATA_ERROR_CODE_SHIFT) #define I40E_VFCM_PE_ERRDATA_Q_TYPE_SHIFT 4 -#define I40E_VFCM_PE_ERRDATA_Q_TYPE_MASK (0x7 << I40E_VFCM_PE_ERRDATA_Q_TYPE_SHIFT) +#define I40E_VFCM_PE_ERRDATA_Q_TYPE_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRDATA_Q_TYPE_SHIFT) #define I40E_VFCM_PE_ERRDATA_Q_NUM_SHIFT 8 -#define I40E_VFCM_PE_ERRDATA_Q_NUM_MASK (0x3FFFF << I40E_VFCM_PE_ERRDATA_Q_NUM_SHIFT) -#define I40E_VFCM_PE_ERRINFO 0x0000D800 +#define I40E_VFCM_PE_ERRDATA_Q_NUM_MASK I40E_MASK(0x3FFFF, I40E_VFCM_PE_ERRDATA_Q_NUM_SHIFT) +#define I40E_VFCM_PE_ERRINFO 0x0000D800 /* Reset: VFR */ #define I40E_VFCM_PE_ERRINFO_ERROR_VALID_SHIFT 0 -#define I40E_VFCM_PE_ERRINFO_ERROR_VALID_MASK (0x1 << I40E_VFCM_PE_ERRINFO_ERROR_VALID_SHIFT) +#define I40E_VFCM_PE_ERRINFO_ERROR_VALID_MASK I40E_MASK(0x1, I40E_VFCM_PE_ERRINFO_ERROR_VALID_SHIFT) #define I40E_VFCM_PE_ERRINFO_ERROR_INST_SHIFT 4 -#define I40E_VFCM_PE_ERRINFO_ERROR_INST_MASK (0x7 << I40E_VFCM_PE_ERRINFO_ERROR_INST_SHIFT) +#define I40E_VFCM_PE_ERRINFO_ERROR_INST_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRINFO_ERROR_INST_SHIFT) #define I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT 8 -#define I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT) +#define I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT) #define I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT 16 -#define I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT) +#define I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT) #define I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT 24 -#define I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT) -#define I40E_VFPE_AEQALLOC1 0x0000A400 -#define I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT 0 -#define I40E_VFPE_AEQALLOC1_AECOUNT_MASK (0xFFFFFFFF << I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT) -#define I40E_VFPE_CCQPHIGH1 0x00009800 -#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT 0 -#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_MASK (0xFFFFFFFF << I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT) -#define I40E_VFPE_CCQPLOW1 0x0000AC00 -#define I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT 0 -#define I40E_VFPE_CCQPLOW1_PECCQPLOW_MASK (0xFFFFFFFF << I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT) -#define I40E_VFPE_CCQPSTATUS1 0x0000B800 -#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT 0 -#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_MASK (0x1 << I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT) -#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT 31 -#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_MASK (0x1 << I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT) -#define I40E_VFPE_CQACK1 0x0000B000 -#define I40E_VFPE_CQACK1_PECQID_SHIFT 0 -#define I40E_VFPE_CQACK1_PECQID_MASK (0x1FFFF << I40E_VFPE_CQACK1_PECQID_SHIFT) -#define I40E_VFPE_CQARM1 0x0000B400 -#define I40E_VFPE_CQARM1_PECQID_SHIFT 0 -#define I40E_VFPE_CQARM1_PECQID_MASK (0x1FFFF << I40E_VFPE_CQARM1_PECQID_SHIFT) -#define I40E_VFPE_CQPDB1 0x0000BC00 -#define I40E_VFPE_CQPDB1_WQHEAD_SHIFT 0 -#define I40E_VFPE_CQPDB1_WQHEAD_MASK (0x7FF << I40E_VFPE_CQPDB1_WQHEAD_SHIFT) -#define I40E_VFPE_CQPERRCODES1 0x00009C00 -#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT 0 -#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT) -#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT 16 -#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT) -#define I40E_VFPE_CQPTAIL1 0x0000A000 -#define I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT 0 -#define I40E_VFPE_CQPTAIL1_WQTAIL_MASK (0x7FF << I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT) -#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT 31 -#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_MASK (0x1 << I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT) -#define I40E_VFPE_IPCONFIG01 0x00008C00 -#define I40E_VFPE_IPCONFIG01_PEIPID_SHIFT 0 -#define I40E_VFPE_IPCONFIG01_PEIPID_MASK (0xFFFF << I40E_VFPE_IPCONFIG01_PEIPID_SHIFT) -#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT 16 -#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT) -#define I40E_VFPE_MRTEIDXMASK1 0x00009000 -#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT 0 -#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_MASK (0x1F << I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT) -#define I40E_VFPE_RCVUNEXPECTEDERROR1 0x00009400 -#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT 0 -#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_MASK (0xFFFFFF << I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT) -#define I40E_VFPE_TCPNOWTIMER1 0x0000A800 -#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT 0 -#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_MASK (0xFFFFFFFF << I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT) -#define I40E_VFPE_WQEALLOC1 0x0000C000 -#define I40E_VFPE_WQEALLOC1_PEQPID_SHIFT 0 -#define I40E_VFPE_WQEALLOC1_PEQPID_MASK (0x3FFFF << I40E_VFPE_WQEALLOC1_PEQPID_SHIFT) -#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT 20 -#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_MASK (0xFFF << I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT) -#define I40E_VFQF_HENA(_i) (0x0000C400 + ((_i) * 4)) /* _i=0...1 */ +#define I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT) +#define I40E_VFQF_HENA(_i) (0x0000C400 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */ #define I40E_VFQF_HENA_MAX_INDEX 1 #define I40E_VFQF_HENA_PTYPE_ENA_SHIFT 0 -#define I40E_VFQF_HENA_PTYPE_ENA_MASK (0xFFFFFFFF << I40E_VFQF_HENA_PTYPE_ENA_SHIFT) -#define I40E_VFQF_HKEY(_i) (0x0000CC00 + ((_i) * 4)) /* _i=0...12 */ +#define I40E_VFQF_HENA_PTYPE_ENA_MASK I40E_MASK(0xFFFFFFFF, I40E_VFQF_HENA_PTYPE_ENA_SHIFT) +#define I40E_VFQF_HKEY(_i) (0x0000CC00 + ((_i) * 4)) /* _i=0...12 */ /* Reset: CORER */ #define I40E_VFQF_HKEY_MAX_INDEX 12 #define I40E_VFQF_HKEY_KEY_0_SHIFT 0 -#define I40E_VFQF_HKEY_KEY_0_MASK (0xFF << I40E_VFQF_HKEY_KEY_0_SHIFT) +#define I40E_VFQF_HKEY_KEY_0_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_0_SHIFT) #define I40E_VFQF_HKEY_KEY_1_SHIFT 8 -#define I40E_VFQF_HKEY_KEY_1_MASK (0xFF << I40E_VFQF_HKEY_KEY_1_SHIFT) +#define I40E_VFQF_HKEY_KEY_1_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_1_SHIFT) #define I40E_VFQF_HKEY_KEY_2_SHIFT 16 -#define I40E_VFQF_HKEY_KEY_2_MASK (0xFF << I40E_VFQF_HKEY_KEY_2_SHIFT) +#define I40E_VFQF_HKEY_KEY_2_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_2_SHIFT) #define I40E_VFQF_HKEY_KEY_3_SHIFT 24 -#define I40E_VFQF_HKEY_KEY_3_MASK (0xFF << I40E_VFQF_HKEY_KEY_3_SHIFT) -#define I40E_VFQF_HLUT(_i) (0x0000D000 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_VFQF_HKEY_KEY_3_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_3_SHIFT) +#define I40E_VFQF_HLUT(_i) (0x0000D000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_VFQF_HLUT_MAX_INDEX 15 #define I40E_VFQF_HLUT_LUT0_SHIFT 0 -#define I40E_VFQF_HLUT_LUT0_MASK (0xF << I40E_VFQF_HLUT_LUT0_SHIFT) +#define I40E_VFQF_HLUT_LUT0_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT0_SHIFT) #define I40E_VFQF_HLUT_LUT1_SHIFT 8 -#define I40E_VFQF_HLUT_LUT1_MASK (0xF << I40E_VFQF_HLUT_LUT1_SHIFT) +#define I40E_VFQF_HLUT_LUT1_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT1_SHIFT) #define I40E_VFQF_HLUT_LUT2_SHIFT 16 -#define I40E_VFQF_HLUT_LUT2_MASK (0xF << I40E_VFQF_HLUT_LUT2_SHIFT) +#define I40E_VFQF_HLUT_LUT2_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT2_SHIFT) #define I40E_VFQF_HLUT_LUT3_SHIFT 24 -#define I40E_VFQF_HLUT_LUT3_MASK (0xF << I40E_VFQF_HLUT_LUT3_SHIFT) -#define I40E_VFQF_HREGION(_i) (0x0000D400 + ((_i) * 4)) /* _i=0...7 */ +#define I40E_VFQF_HLUT_LUT3_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT3_SHIFT) +#define I40E_VFQF_HREGION(_i) (0x0000D400 + ((_i) * 4)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_VFQF_HREGION_MAX_INDEX 7 #define I40E_VFQF_HREGION_OVERRIDE_ENA_0_SHIFT 0 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_0_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_0_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_0_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_0_SHIFT) #define I40E_VFQF_HREGION_REGION_0_SHIFT 1 -#define I40E_VFQF_HREGION_REGION_0_MASK (0x7 << I40E_VFQF_HREGION_REGION_0_SHIFT) +#define I40E_VFQF_HREGION_REGION_0_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_0_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_1_SHIFT 4 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_1_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_1_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_1_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_1_SHIFT) #define I40E_VFQF_HREGION_REGION_1_SHIFT 5 -#define I40E_VFQF_HREGION_REGION_1_MASK (0x7 << I40E_VFQF_HREGION_REGION_1_SHIFT) +#define I40E_VFQF_HREGION_REGION_1_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_1_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_2_SHIFT 8 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_2_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_2_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_2_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_2_SHIFT) #define I40E_VFQF_HREGION_REGION_2_SHIFT 9 -#define I40E_VFQF_HREGION_REGION_2_MASK (0x7 << I40E_VFQF_HREGION_REGION_2_SHIFT) +#define I40E_VFQF_HREGION_REGION_2_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_2_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_3_SHIFT 12 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_3_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_3_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_3_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_3_SHIFT) #define I40E_VFQF_HREGION_REGION_3_SHIFT 13 -#define I40E_VFQF_HREGION_REGION_3_MASK (0x7 << I40E_VFQF_HREGION_REGION_3_SHIFT) +#define I40E_VFQF_HREGION_REGION_3_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_3_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_4_SHIFT 16 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_4_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_4_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_4_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_4_SHIFT) #define I40E_VFQF_HREGION_REGION_4_SHIFT 17 -#define I40E_VFQF_HREGION_REGION_4_MASK (0x7 << I40E_VFQF_HREGION_REGION_4_SHIFT) +#define I40E_VFQF_HREGION_REGION_4_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_4_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_5_SHIFT 20 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_5_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_5_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_5_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_5_SHIFT) #define I40E_VFQF_HREGION_REGION_5_SHIFT 21 -#define I40E_VFQF_HREGION_REGION_5_MASK (0x7 << I40E_VFQF_HREGION_REGION_5_SHIFT) +#define I40E_VFQF_HREGION_REGION_5_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_5_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_6_SHIFT 24 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_6_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_6_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_6_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_6_SHIFT) #define I40E_VFQF_HREGION_REGION_6_SHIFT 25 -#define I40E_VFQF_HREGION_REGION_6_MASK (0x7 << I40E_VFQF_HREGION_REGION_6_SHIFT) +#define I40E_VFQF_HREGION_REGION_6_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_6_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT 28 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_7_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_7_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT) #define I40E_VFQF_HREGION_REGION_7_SHIFT 29 -#define I40E_VFQF_HREGION_REGION_7_MASK (0x7 << I40E_VFQF_HREGION_REGION_7_SHIFT) -#define I40E_RCU_PST_FOC_ACCESS_STATUS 0x00270110 -#define I40E_RCU_PST_FOC_ACCESS_STATUS_WR_ACCESS_CNT_SHIFT 0 -#define I40E_RCU_PST_FOC_ACCESS_STATUS_WR_ACCESS_CNT_MASK (0xFF << I40E_RCU_PST_FOC_ACCESS_STATUS_WR_ACCESS_CNT_SHIFT) -#define I40E_RCU_PST_FOC_ACCESS_STATUS_RD_ACCESS_CNT_SHIFT 8 -#define I40E_RCU_PST_FOC_ACCESS_STATUS_RD_ACCESS_CNT_MASK (0xFF << I40E_RCU_PST_FOC_ACCESS_STATUS_RD_ACCESS_CNT_SHIFT) -#define I40E_RCU_PST_FOC_ACCESS_STATUS_ERR_CNT_SHIFT 16 -#define I40E_RCU_PST_FOC_ACCESS_STATUS_ERR_CNT_MASK (0xFF << I40E_RCU_PST_FOC_ACCESS_STATUS_ERR_CNT_SHIFT) -#define I40E_RCU_PST_FOC_ACCESS_STATUS_LAST_ERR_CODE_SHIFT 24 -#define I40E_RCU_PST_FOC_ACCESS_STATUS_LAST_ERR_CODE_MASK (0x7 << I40E_RCU_PST_FOC_ACCESS_STATUS_LAST_ERR_CODE_SHIFT) +#define I40E_VFQF_HREGION_REGION_7_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_7_SHIFT) #endif diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 9d39ff23c5fb..a688ab86f650 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -50,6 +50,9 @@ (d) == I40E_DEV_ID_QSFP_B || \ (d) == I40E_DEV_ID_QSFP_C) +/* I40E_MASK is a macro used on 32 bit registers */ +#define I40E_MASK(mask, shift) (mask << shift) + #define I40E_MAX_VSI_QP 16 #define I40E_MAX_VF_VSI 3 #define I40E_MAX_CHAINED_RX_BUFFERS 5 diff --git a/drivers/net/ethernet/intel/i40evf/i40e_register.h b/drivers/net/ethernet/intel/i40evf/i40e_register.h index 369839655818..c1f6a59bfea0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_register.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_register.h @@ -27,4648 +27,3343 @@ #ifndef _I40E_REGISTER_H_ #define _I40E_REGISTER_H_ -#define I40E_GL_GP_FUSE(_i) (0x0009400C + ((_i) * 4)) /* _i=0...28 */ -#define I40E_GL_GP_FUSE_MAX_INDEX 28 -#define I40E_GL_GP_FUSE_GL_GP_FUSE_SHIFT 0 -#define I40E_GL_GP_FUSE_GL_GP_FUSE_MASK (0xFFFFFFFF << I40E_GL_GP_FUSE_GL_GP_FUSE_SHIFT) -#define I40E_GLPCI_PM_MUX_NPQ 0x0009C4F4 -#define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT 0 -#define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_MASK (0x7 << I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT) -#define I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_SHIFT 16 -#define I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_MASK (0x1F << I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_SHIFT) -#define I40E_GLPCI_PM_MUX_PFB 0x0009C4F0 -#define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT 0 -#define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_MASK (0x1F << I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT) -#define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT 16 -#define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_MASK (0x7 << I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT) -#define I40E_GLPCI_PQ_MAX_USED_SPC 0x0009C4EC -#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_SHIFT 0 -#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_MASK (0xFF << I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_SHIFT) -#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_SHIFT 8 -#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_MASK (0xFF << I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_SHIFT) -#define I40E_GLPCI_SPARE_BITS_0 0x0009C4F8 -#define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT 0 -#define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_MASK (0xFFFFFFFF << I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT) -#define I40E_GLPCI_SPARE_BITS_1 0x0009C4FC -#define I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_SHIFT 0 -#define I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_MASK (0xFFFFFFFF << I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_SHIFT) -#define I40E_PFPCI_PF_FLUSH_DONE 0x0009C800 -#define I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_SHIFT 0 -#define I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_SHIFT) -#define I40E_PFPCI_VF_FLUSH_DONE 0x0009C600 -#define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT 0 -#define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT) -#define I40E_PFPCI_VF_FLUSH_DONE1(_VF) (0x0009C600 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_PFPCI_VF_FLUSH_DONE1_MAX_INDEX 127 -#define I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_SHIFT 0 -#define I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_SHIFT) -#define I40E_PFPCI_VM_FLUSH_DONE 0x0009C880 -#define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT 0 -#define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT) - -#define I40E_PF_ARQBAH 0x00080180 +#define I40E_GL_ARQBAH 0x000801C0 /* Reset: EMPR */ +#define I40E_GL_ARQBAH_ARQBAH_SHIFT 0 +#define I40E_GL_ARQBAH_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ARQBAH_ARQBAH_SHIFT) +#define I40E_GL_ARQBAL 0x000800C0 /* Reset: EMPR */ +#define I40E_GL_ARQBAL_ARQBAL_SHIFT 0 +#define I40E_GL_ARQBAL_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ARQBAL_ARQBAL_SHIFT) +#define I40E_GL_ARQH 0x000803C0 /* Reset: EMPR */ +#define I40E_GL_ARQH_ARQH_SHIFT 0 +#define I40E_GL_ARQH_ARQH_MASK I40E_MASK(0x3FF, I40E_GL_ARQH_ARQH_SHIFT) +#define I40E_GL_ARQT 0x000804C0 /* Reset: EMPR */ +#define I40E_GL_ARQT_ARQT_SHIFT 0 +#define I40E_GL_ARQT_ARQT_MASK I40E_MASK(0x3FF, I40E_GL_ARQT_ARQT_SHIFT) +#define I40E_GL_ATQBAH 0x00080140 /* Reset: EMPR */ +#define I40E_GL_ATQBAH_ATQBAH_SHIFT 0 +#define I40E_GL_ATQBAH_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ATQBAH_ATQBAH_SHIFT) +#define I40E_GL_ATQBAL 0x00080040 /* Reset: EMPR */ +#define I40E_GL_ATQBAL_ATQBAL_SHIFT 0 +#define I40E_GL_ATQBAL_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ATQBAL_ATQBAL_SHIFT) +#define I40E_GL_ATQH 0x00080340 /* Reset: EMPR */ +#define I40E_GL_ATQH_ATQH_SHIFT 0 +#define I40E_GL_ATQH_ATQH_MASK I40E_MASK(0x3FF, I40E_GL_ATQH_ATQH_SHIFT) +#define I40E_GL_ATQLEN 0x00080240 /* Reset: EMPR */ +#define I40E_GL_ATQLEN_ATQLEN_SHIFT 0 +#define I40E_GL_ATQLEN_ATQLEN_MASK I40E_MASK(0x3FF, I40E_GL_ATQLEN_ATQLEN_SHIFT) +#define I40E_GL_ATQLEN_ATQVFE_SHIFT 28 +#define I40E_GL_ATQLEN_ATQVFE_MASK I40E_MASK(0x1, I40E_GL_ATQLEN_ATQVFE_SHIFT) +#define I40E_GL_ATQLEN_ATQOVFL_SHIFT 29 +#define I40E_GL_ATQLEN_ATQOVFL_MASK I40E_MASK(0x1, I40E_GL_ATQLEN_ATQOVFL_SHIFT) +#define I40E_GL_ATQLEN_ATQCRIT_SHIFT 30 +#define I40E_GL_ATQLEN_ATQCRIT_MASK I40E_MASK(0x1, I40E_GL_ATQLEN_ATQCRIT_SHIFT) +#define I40E_GL_ATQLEN_ATQENABLE_SHIFT 31 +#define I40E_GL_ATQLEN_ATQENABLE_MASK I40E_MASK(0x1, I40E_GL_ATQLEN_ATQENABLE_SHIFT) +#define I40E_GL_ATQT 0x00080440 /* Reset: EMPR */ +#define I40E_GL_ATQT_ATQT_SHIFT 0 +#define I40E_GL_ATQT_ATQT_MASK I40E_MASK(0x3FF, I40E_GL_ATQT_ATQT_SHIFT) +#define I40E_PF_ARQBAH 0x00080180 /* Reset: EMPR */ #define I40E_PF_ARQBAH_ARQBAH_SHIFT 0 -#define I40E_PF_ARQBAH_ARQBAH_MASK (0xFFFFFFFF << I40E_PF_ARQBAH_ARQBAH_SHIFT) -#define I40E_PF_ARQBAL 0x00080080 +#define I40E_PF_ARQBAH_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_ARQBAH_ARQBAH_SHIFT) +#define I40E_PF_ARQBAL 0x00080080 /* Reset: EMPR */ #define I40E_PF_ARQBAL_ARQBAL_SHIFT 0 -#define I40E_PF_ARQBAL_ARQBAL_MASK (0xFFFFFFFF << I40E_PF_ARQBAL_ARQBAL_SHIFT) -#define I40E_PF_ARQH 0x00080380 +#define I40E_PF_ARQBAL_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_ARQBAL_ARQBAL_SHIFT) +#define I40E_PF_ARQH 0x00080380 /* Reset: EMPR */ #define I40E_PF_ARQH_ARQH_SHIFT 0 -#define I40E_PF_ARQH_ARQH_MASK (0x3FF << I40E_PF_ARQH_ARQH_SHIFT) -#define I40E_PF_ARQLEN 0x00080280 +#define I40E_PF_ARQH_ARQH_MASK I40E_MASK(0x3FF, I40E_PF_ARQH_ARQH_SHIFT) +#define I40E_PF_ARQLEN 0x00080280 /* Reset: EMPR */ #define I40E_PF_ARQLEN_ARQLEN_SHIFT 0 -#define I40E_PF_ARQLEN_ARQLEN_MASK (0x3FF << I40E_PF_ARQLEN_ARQLEN_SHIFT) +#define I40E_PF_ARQLEN_ARQLEN_MASK I40E_MASK(0x3FF, I40E_PF_ARQLEN_ARQLEN_SHIFT) #define I40E_PF_ARQLEN_ARQVFE_SHIFT 28 -#define I40E_PF_ARQLEN_ARQVFE_MASK (0x1 << I40E_PF_ARQLEN_ARQVFE_SHIFT) +#define I40E_PF_ARQLEN_ARQVFE_MASK I40E_MASK(0x1, I40E_PF_ARQLEN_ARQVFE_SHIFT) #define I40E_PF_ARQLEN_ARQOVFL_SHIFT 29 -#define I40E_PF_ARQLEN_ARQOVFL_MASK (0x1 << I40E_PF_ARQLEN_ARQOVFL_SHIFT) +#define I40E_PF_ARQLEN_ARQOVFL_MASK I40E_MASK(0x1, I40E_PF_ARQLEN_ARQOVFL_SHIFT) #define I40E_PF_ARQLEN_ARQCRIT_SHIFT 30 -#define I40E_PF_ARQLEN_ARQCRIT_MASK (0x1 << I40E_PF_ARQLEN_ARQCRIT_SHIFT) +#define I40E_PF_ARQLEN_ARQCRIT_MASK I40E_MASK(0x1, I40E_PF_ARQLEN_ARQCRIT_SHIFT) #define I40E_PF_ARQLEN_ARQENABLE_SHIFT 31 -#define I40E_PF_ARQLEN_ARQENABLE_MASK (0x1 << I40E_PF_ARQLEN_ARQENABLE_SHIFT) -#define I40E_PF_ARQT 0x00080480 +#define I40E_PF_ARQLEN_ARQENABLE_MASK I40E_MASK(0x1, I40E_PF_ARQLEN_ARQENABLE_SHIFT) +#define I40E_PF_ARQT 0x00080480 /* Reset: EMPR */ #define I40E_PF_ARQT_ARQT_SHIFT 0 -#define I40E_PF_ARQT_ARQT_MASK (0x3FF << I40E_PF_ARQT_ARQT_SHIFT) -#define I40E_PF_ATQBAH 0x00080100 +#define I40E_PF_ARQT_ARQT_MASK I40E_MASK(0x3FF, I40E_PF_ARQT_ARQT_SHIFT) +#define I40E_PF_ATQBAH 0x00080100 /* Reset: EMPR */ #define I40E_PF_ATQBAH_ATQBAH_SHIFT 0 -#define I40E_PF_ATQBAH_ATQBAH_MASK (0xFFFFFFFF << I40E_PF_ATQBAH_ATQBAH_SHIFT) -#define I40E_PF_ATQBAL 0x00080000 +#define I40E_PF_ATQBAH_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_ATQBAH_ATQBAH_SHIFT) +#define I40E_PF_ATQBAL 0x00080000 /* Reset: EMPR */ #define I40E_PF_ATQBAL_ATQBAL_SHIFT 0 -#define I40E_PF_ATQBAL_ATQBAL_MASK (0xFFFFFFFF << I40E_PF_ATQBAL_ATQBAL_SHIFT) -#define I40E_PF_ATQH 0x00080300 +#define I40E_PF_ATQBAL_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_ATQBAL_ATQBAL_SHIFT) +#define I40E_PF_ATQH 0x00080300 /* Reset: EMPR */ #define I40E_PF_ATQH_ATQH_SHIFT 0 -#define I40E_PF_ATQH_ATQH_MASK (0x3FF << I40E_PF_ATQH_ATQH_SHIFT) -#define I40E_PF_ATQLEN 0x00080200 +#define I40E_PF_ATQH_ATQH_MASK I40E_MASK(0x3FF, I40E_PF_ATQH_ATQH_SHIFT) +#define I40E_PF_ATQLEN 0x00080200 /* Reset: EMPR */ #define I40E_PF_ATQLEN_ATQLEN_SHIFT 0 -#define I40E_PF_ATQLEN_ATQLEN_MASK (0x3FF << I40E_PF_ATQLEN_ATQLEN_SHIFT) +#define I40E_PF_ATQLEN_ATQLEN_MASK I40E_MASK(0x3FF, I40E_PF_ATQLEN_ATQLEN_SHIFT) #define I40E_PF_ATQLEN_ATQVFE_SHIFT 28 -#define I40E_PF_ATQLEN_ATQVFE_MASK (0x1 << I40E_PF_ATQLEN_ATQVFE_SHIFT) +#define I40E_PF_ATQLEN_ATQVFE_MASK I40E_MASK(0x1, I40E_PF_ATQLEN_ATQVFE_SHIFT) #define I40E_PF_ATQLEN_ATQOVFL_SHIFT 29 -#define I40E_PF_ATQLEN_ATQOVFL_MASK (0x1 << I40E_PF_ATQLEN_ATQOVFL_SHIFT) +#define I40E_PF_ATQLEN_ATQOVFL_MASK I40E_MASK(0x1, I40E_PF_ATQLEN_ATQOVFL_SHIFT) #define I40E_PF_ATQLEN_ATQCRIT_SHIFT 30 -#define I40E_PF_ATQLEN_ATQCRIT_MASK (0x1 << I40E_PF_ATQLEN_ATQCRIT_SHIFT) +#define I40E_PF_ATQLEN_ATQCRIT_MASK I40E_MASK(0x1, I40E_PF_ATQLEN_ATQCRIT_SHIFT) #define I40E_PF_ATQLEN_ATQENABLE_SHIFT 31 -#define I40E_PF_ATQLEN_ATQENABLE_MASK (0x1 << I40E_PF_ATQLEN_ATQENABLE_SHIFT) -#define I40E_PF_ATQT 0x00080400 +#define I40E_PF_ATQLEN_ATQENABLE_MASK I40E_MASK(0x1, I40E_PF_ATQLEN_ATQENABLE_SHIFT) +#define I40E_PF_ATQT 0x00080400 /* Reset: EMPR */ #define I40E_PF_ATQT_ATQT_SHIFT 0 -#define I40E_PF_ATQT_ATQT_MASK (0x3FF << I40E_PF_ATQT_ATQT_SHIFT) -#define I40E_VF_ARQBAH(_VF) (0x00081400 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_PF_ATQT_ATQT_MASK I40E_MASK(0x3FF, I40E_PF_ATQT_ATQT_SHIFT) +#define I40E_VF_ARQBAH(_VF) (0x00081400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ARQBAH_MAX_INDEX 127 #define I40E_VF_ARQBAH_ARQBAH_SHIFT 0 -#define I40E_VF_ARQBAH_ARQBAH_MASK (0xFFFFFFFF << I40E_VF_ARQBAH_ARQBAH_SHIFT) -#define I40E_VF_ARQBAL(_VF) (0x00080C00 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ARQBAH_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAH_ARQBAH_SHIFT) +#define I40E_VF_ARQBAL(_VF) (0x00080C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ARQBAL_MAX_INDEX 127 #define I40E_VF_ARQBAL_ARQBAL_SHIFT 0 -#define I40E_VF_ARQBAL_ARQBAL_MASK (0xFFFFFFFF << I40E_VF_ARQBAL_ARQBAL_SHIFT) -#define I40E_VF_ARQH(_VF) (0x00082400 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ARQBAL_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAL_ARQBAL_SHIFT) +#define I40E_VF_ARQH(_VF) (0x00082400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ARQH_MAX_INDEX 127 #define I40E_VF_ARQH_ARQH_SHIFT 0 -#define I40E_VF_ARQH_ARQH_MASK (0x3FF << I40E_VF_ARQH_ARQH_SHIFT) -#define I40E_VF_ARQLEN(_VF) (0x00081C00 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ARQH_ARQH_MASK I40E_MASK(0x3FF, I40E_VF_ARQH_ARQH_SHIFT) +#define I40E_VF_ARQLEN(_VF) (0x00081C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ARQLEN_MAX_INDEX 127 #define I40E_VF_ARQLEN_ARQLEN_SHIFT 0 -#define I40E_VF_ARQLEN_ARQLEN_MASK (0x3FF << I40E_VF_ARQLEN_ARQLEN_SHIFT) +#define I40E_VF_ARQLEN_ARQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ARQLEN_ARQLEN_SHIFT) #define I40E_VF_ARQLEN_ARQVFE_SHIFT 28 -#define I40E_VF_ARQLEN_ARQVFE_MASK (0x1 << I40E_VF_ARQLEN_ARQVFE_SHIFT) +#define I40E_VF_ARQLEN_ARQVFE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN_ARQVFE_SHIFT) #define I40E_VF_ARQLEN_ARQOVFL_SHIFT 29 -#define I40E_VF_ARQLEN_ARQOVFL_MASK (0x1 << I40E_VF_ARQLEN_ARQOVFL_SHIFT) +#define I40E_VF_ARQLEN_ARQOVFL_MASK I40E_MASK(0x1, I40E_VF_ARQLEN_ARQOVFL_SHIFT) #define I40E_VF_ARQLEN_ARQCRIT_SHIFT 30 -#define I40E_VF_ARQLEN_ARQCRIT_MASK (0x1 << I40E_VF_ARQLEN_ARQCRIT_SHIFT) +#define I40E_VF_ARQLEN_ARQCRIT_MASK I40E_MASK(0x1, I40E_VF_ARQLEN_ARQCRIT_SHIFT) #define I40E_VF_ARQLEN_ARQENABLE_SHIFT 31 -#define I40E_VF_ARQLEN_ARQENABLE_MASK (0x1 << I40E_VF_ARQLEN_ARQENABLE_SHIFT) -#define I40E_VF_ARQT(_VF) (0x00082C00 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ARQLEN_ARQENABLE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN_ARQENABLE_SHIFT) +#define I40E_VF_ARQT(_VF) (0x00082C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ARQT_MAX_INDEX 127 #define I40E_VF_ARQT_ARQT_SHIFT 0 -#define I40E_VF_ARQT_ARQT_MASK (0x3FF << I40E_VF_ARQT_ARQT_SHIFT) -#define I40E_VF_ATQBAH(_VF) (0x00081000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ARQT_ARQT_MASK I40E_MASK(0x3FF, I40E_VF_ARQT_ARQT_SHIFT) +#define I40E_VF_ATQBAH(_VF) (0x00081000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ATQBAH_MAX_INDEX 127 #define I40E_VF_ATQBAH_ATQBAH_SHIFT 0 -#define I40E_VF_ATQBAH_ATQBAH_MASK (0xFFFFFFFF << I40E_VF_ATQBAH_ATQBAH_SHIFT) -#define I40E_VF_ATQBAL(_VF) (0x00080800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ATQBAH_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAH_ATQBAH_SHIFT) +#define I40E_VF_ATQBAL(_VF) (0x00080800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ATQBAL_MAX_INDEX 127 #define I40E_VF_ATQBAL_ATQBAL_SHIFT 0 -#define I40E_VF_ATQBAL_ATQBAL_MASK (0xFFFFFFFF << I40E_VF_ATQBAL_ATQBAL_SHIFT) -#define I40E_VF_ATQH(_VF) (0x00082000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ATQBAL_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAL_ATQBAL_SHIFT) +#define I40E_VF_ATQH(_VF) (0x00082000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ATQH_MAX_INDEX 127 #define I40E_VF_ATQH_ATQH_SHIFT 0 -#define I40E_VF_ATQH_ATQH_MASK (0x3FF << I40E_VF_ATQH_ATQH_SHIFT) -#define I40E_VF_ATQLEN(_VF) (0x00081800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ATQH_ATQH_MASK I40E_MASK(0x3FF, I40E_VF_ATQH_ATQH_SHIFT) +#define I40E_VF_ATQLEN(_VF) (0x00081800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ATQLEN_MAX_INDEX 127 #define I40E_VF_ATQLEN_ATQLEN_SHIFT 0 -#define I40E_VF_ATQLEN_ATQLEN_MASK (0x3FF << I40E_VF_ATQLEN_ATQLEN_SHIFT) +#define I40E_VF_ATQLEN_ATQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ATQLEN_ATQLEN_SHIFT) #define I40E_VF_ATQLEN_ATQVFE_SHIFT 28 -#define I40E_VF_ATQLEN_ATQVFE_MASK (0x1 << I40E_VF_ATQLEN_ATQVFE_SHIFT) +#define I40E_VF_ATQLEN_ATQVFE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN_ATQVFE_SHIFT) #define I40E_VF_ATQLEN_ATQOVFL_SHIFT 29 -#define I40E_VF_ATQLEN_ATQOVFL_MASK (0x1 << I40E_VF_ATQLEN_ATQOVFL_SHIFT) +#define I40E_VF_ATQLEN_ATQOVFL_MASK I40E_MASK(0x1, I40E_VF_ATQLEN_ATQOVFL_SHIFT) #define I40E_VF_ATQLEN_ATQCRIT_SHIFT 30 -#define I40E_VF_ATQLEN_ATQCRIT_MASK (0x1 << I40E_VF_ATQLEN_ATQCRIT_SHIFT) +#define I40E_VF_ATQLEN_ATQCRIT_MASK I40E_MASK(0x1, I40E_VF_ATQLEN_ATQCRIT_SHIFT) #define I40E_VF_ATQLEN_ATQENABLE_SHIFT 31 -#define I40E_VF_ATQLEN_ATQENABLE_MASK (0x1 << I40E_VF_ATQLEN_ATQENABLE_SHIFT) -#define I40E_VF_ATQT(_VF) (0x00082800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VF_ATQLEN_ATQENABLE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN_ATQENABLE_SHIFT) +#define I40E_VF_ATQT(_VF) (0x00082800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ #define I40E_VF_ATQT_MAX_INDEX 127 #define I40E_VF_ATQT_ATQT_SHIFT 0 -#define I40E_VF_ATQT_ATQT_MASK (0x3FF << I40E_VF_ATQT_ATQT_SHIFT) -#define I40E_PRT_L2TAGSEN 0x001C0B20 +#define I40E_VF_ATQT_ATQT_MASK I40E_MASK(0x3FF, I40E_VF_ATQT_ATQT_SHIFT) +#define I40E_PRT_L2TAGSEN 0x001C0B20 /* Reset: CORER */ #define I40E_PRT_L2TAGSEN_ENABLE_SHIFT 0 -#define I40E_PRT_L2TAGSEN_ENABLE_MASK (0xFF << I40E_PRT_L2TAGSEN_ENABLE_SHIFT) -#define I40E_PFCM_LAN_ERRDATA 0x0010C080 +#define I40E_PRT_L2TAGSEN_ENABLE_MASK I40E_MASK(0xFF, I40E_PRT_L2TAGSEN_ENABLE_SHIFT) +#define I40E_PFCM_LAN_ERRDATA 0x0010C080 /* Reset: PFR */ #define I40E_PFCM_LAN_ERRDATA_ERROR_CODE_SHIFT 0 -#define I40E_PFCM_LAN_ERRDATA_ERROR_CODE_MASK (0xF << I40E_PFCM_LAN_ERRDATA_ERROR_CODE_SHIFT) +#define I40E_PFCM_LAN_ERRDATA_ERROR_CODE_MASK I40E_MASK(0xF, I40E_PFCM_LAN_ERRDATA_ERROR_CODE_SHIFT) #define I40E_PFCM_LAN_ERRDATA_Q_TYPE_SHIFT 4 -#define I40E_PFCM_LAN_ERRDATA_Q_TYPE_MASK (0x7 << I40E_PFCM_LAN_ERRDATA_Q_TYPE_SHIFT) +#define I40E_PFCM_LAN_ERRDATA_Q_TYPE_MASK I40E_MASK(0x7, I40E_PFCM_LAN_ERRDATA_Q_TYPE_SHIFT) #define I40E_PFCM_LAN_ERRDATA_Q_NUM_SHIFT 8 -#define I40E_PFCM_LAN_ERRDATA_Q_NUM_MASK (0xFFF << I40E_PFCM_LAN_ERRDATA_Q_NUM_SHIFT) -#define I40E_PFCM_LAN_ERRINFO 0x0010C000 +#define I40E_PFCM_LAN_ERRDATA_Q_NUM_MASK I40E_MASK(0xFFF, I40E_PFCM_LAN_ERRDATA_Q_NUM_SHIFT) +#define I40E_PFCM_LAN_ERRINFO 0x0010C000 /* Reset: PFR */ #define I40E_PFCM_LAN_ERRINFO_ERROR_VALID_SHIFT 0 -#define I40E_PFCM_LAN_ERRINFO_ERROR_VALID_MASK (0x1 << I40E_PFCM_LAN_ERRINFO_ERROR_VALID_SHIFT) +#define I40E_PFCM_LAN_ERRINFO_ERROR_VALID_MASK I40E_MASK(0x1, I40E_PFCM_LAN_ERRINFO_ERROR_VALID_SHIFT) #define I40E_PFCM_LAN_ERRINFO_ERROR_INST_SHIFT 4 -#define I40E_PFCM_LAN_ERRINFO_ERROR_INST_MASK (0x7 << I40E_PFCM_LAN_ERRINFO_ERROR_INST_SHIFT) +#define I40E_PFCM_LAN_ERRINFO_ERROR_INST_MASK I40E_MASK(0x7, I40E_PFCM_LAN_ERRINFO_ERROR_INST_SHIFT) #define I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_SHIFT 8 -#define I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_MASK (0xFF << I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_SHIFT) +#define I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_SHIFT) #define I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_SHIFT 16 -#define I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_MASK (0xFF << I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_SHIFT) +#define I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_SHIFT) #define I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_SHIFT 24 -#define I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_MASK (0xFF << I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_SHIFT) -#define I40E_PFCM_LANCTXCTL(_pf) (0x0010C300 + ((_pf) * 4))/* _pf=0..15 */ +#define I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_SHIFT) +#define I40E_PFCM_LANCTXCTL 0x0010C300 /* Reset: CORER */ #define I40E_PFCM_LANCTXCTL_QUEUE_NUM_SHIFT 0 -#define I40E_PFCM_LANCTXCTL_QUEUE_NUM_MASK (0xFFF << I40E_PFCM_LANCTXCTL_QUEUE_NUM_SHIFT) +#define I40E_PFCM_LANCTXCTL_QUEUE_NUM_MASK I40E_MASK(0xFFF, I40E_PFCM_LANCTXCTL_QUEUE_NUM_SHIFT) #define I40E_PFCM_LANCTXCTL_SUB_LINE_SHIFT 12 -#define I40E_PFCM_LANCTXCTL_SUB_LINE_MASK (0x7 << I40E_PFCM_LANCTXCTL_SUB_LINE_SHIFT) +#define I40E_PFCM_LANCTXCTL_SUB_LINE_MASK I40E_MASK(0x7, I40E_PFCM_LANCTXCTL_SUB_LINE_SHIFT) #define I40E_PFCM_LANCTXCTL_QUEUE_TYPE_SHIFT 15 -#define I40E_PFCM_LANCTXCTL_QUEUE_TYPE_MASK (0x3 << I40E_PFCM_LANCTXCTL_QUEUE_TYPE_SHIFT) +#define I40E_PFCM_LANCTXCTL_QUEUE_TYPE_MASK I40E_MASK(0x3, I40E_PFCM_LANCTXCTL_QUEUE_TYPE_SHIFT) #define I40E_PFCM_LANCTXCTL_OP_CODE_SHIFT 17 -#define I40E_PFCM_LANCTXCTL_OP_CODE_MASK (0x3 << I40E_PFCM_LANCTXCTL_OP_CODE_SHIFT) -#define I40E_PFCM_LANCTXDATA(_i, _pf) (0x0010C100 + ((_i) * 4) + ((_pf) * 16))/* _i=0...3 _pf=0..15 */ +#define I40E_PFCM_LANCTXCTL_OP_CODE_MASK I40E_MASK(0x3, I40E_PFCM_LANCTXCTL_OP_CODE_SHIFT) +#define I40E_PFCM_LANCTXDATA(_i) (0x0010C100 + ((_i) * 128)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_PFCM_LANCTXDATA_MAX_INDEX 3 #define I40E_PFCM_LANCTXDATA_DATA_SHIFT 0 -#define I40E_PFCM_LANCTXDATA_DATA_MASK (0xFFFFFFFF << I40E_PFCM_LANCTXDATA_DATA_SHIFT) -#define I40E_PFCM_LANCTXSTAT(_pf) (0x0010C380 + ((_pf) * 4))/* _pf=0..15 */ +#define I40E_PFCM_LANCTXDATA_DATA_MASK I40E_MASK(0xFFFFFFFF, I40E_PFCM_LANCTXDATA_DATA_SHIFT) +#define I40E_PFCM_LANCTXSTAT 0x0010C380 /* Reset: CORER */ #define I40E_PFCM_LANCTXSTAT_CTX_DONE_SHIFT 0 -#define I40E_PFCM_LANCTXSTAT_CTX_DONE_MASK (0x1 << I40E_PFCM_LANCTXSTAT_CTX_DONE_SHIFT) +#define I40E_PFCM_LANCTXSTAT_CTX_DONE_MASK I40E_MASK(0x1, I40E_PFCM_LANCTXSTAT_CTX_DONE_SHIFT) #define I40E_PFCM_LANCTXSTAT_CTX_MISS_SHIFT 1 -#define I40E_PFCM_LANCTXSTAT_CTX_MISS_MASK (0x1 << I40E_PFCM_LANCTXSTAT_CTX_MISS_SHIFT) -#define I40E_PFCM_PE_ERRDATA 0x00138D00 -#define I40E_PFCM_PE_ERRDATA_ERROR_CODE_SHIFT 0 -#define I40E_PFCM_PE_ERRDATA_ERROR_CODE_MASK (0xF << I40E_PFCM_PE_ERRDATA_ERROR_CODE_SHIFT) -#define I40E_PFCM_PE_ERRDATA_Q_TYPE_SHIFT 4 -#define I40E_PFCM_PE_ERRDATA_Q_TYPE_MASK (0x7 << I40E_PFCM_PE_ERRDATA_Q_TYPE_SHIFT) -#define I40E_PFCM_PE_ERRDATA_Q_NUM_SHIFT 8 -#define I40E_PFCM_PE_ERRDATA_Q_NUM_MASK (0x3FFFF << I40E_PFCM_PE_ERRDATA_Q_NUM_SHIFT) -#define I40E_PFCM_PE_ERRINFO 0x00138C80 -#define I40E_PFCM_PE_ERRINFO_ERROR_VALID_SHIFT 0 -#define I40E_PFCM_PE_ERRINFO_ERROR_VALID_MASK (0x1 << I40E_PFCM_PE_ERRINFO_ERROR_VALID_SHIFT) -#define I40E_PFCM_PE_ERRINFO_ERROR_INST_SHIFT 4 -#define I40E_PFCM_PE_ERRINFO_ERROR_INST_MASK (0x7 << I40E_PFCM_PE_ERRINFO_ERROR_INST_SHIFT) -#define I40E_PFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT 8 -#define I40E_PFCM_PE_ERRINFO_DBL_ERROR_CNT_MASK (0xFF << I40E_PFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT) -#define I40E_PFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT 16 -#define I40E_PFCM_PE_ERRINFO_RLU_ERROR_CNT_MASK (0xFF << I40E_PFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT) -#define I40E_PFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT 24 -#define I40E_PFCM_PE_ERRINFO_RLS_ERROR_CNT_MASK (0xFF << I40E_PFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT) -#define I40E_VFCM_PE_ERRDATA1(_VF) (0x00138800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_PFCM_LANCTXSTAT_CTX_MISS_MASK I40E_MASK(0x1, I40E_PFCM_LANCTXSTAT_CTX_MISS_SHIFT) +#define I40E_VFCM_PE_ERRDATA1(_VF) (0x00138800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VFCM_PE_ERRDATA1_MAX_INDEX 127 #define I40E_VFCM_PE_ERRDATA1_ERROR_CODE_SHIFT 0 -#define I40E_VFCM_PE_ERRDATA1_ERROR_CODE_MASK (0xF << I40E_VFCM_PE_ERRDATA1_ERROR_CODE_SHIFT) +#define I40E_VFCM_PE_ERRDATA1_ERROR_CODE_MASK I40E_MASK(0xF, I40E_VFCM_PE_ERRDATA1_ERROR_CODE_SHIFT) #define I40E_VFCM_PE_ERRDATA1_Q_TYPE_SHIFT 4 -#define I40E_VFCM_PE_ERRDATA1_Q_TYPE_MASK (0x7 << I40E_VFCM_PE_ERRDATA1_Q_TYPE_SHIFT) +#define I40E_VFCM_PE_ERRDATA1_Q_TYPE_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRDATA1_Q_TYPE_SHIFT) #define I40E_VFCM_PE_ERRDATA1_Q_NUM_SHIFT 8 -#define I40E_VFCM_PE_ERRDATA1_Q_NUM_MASK (0x3FFFF << I40E_VFCM_PE_ERRDATA1_Q_NUM_SHIFT) -#define I40E_VFCM_PE_ERRINFO1(_VF) (0x00138400 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFCM_PE_ERRDATA1_Q_NUM_MASK I40E_MASK(0x3FFFF, I40E_VFCM_PE_ERRDATA1_Q_NUM_SHIFT) +#define I40E_VFCM_PE_ERRINFO1(_VF) (0x00138400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VFCM_PE_ERRINFO1_MAX_INDEX 127 #define I40E_VFCM_PE_ERRINFO1_ERROR_VALID_SHIFT 0 -#define I40E_VFCM_PE_ERRINFO1_ERROR_VALID_MASK (0x1 << I40E_VFCM_PE_ERRINFO1_ERROR_VALID_SHIFT) +#define I40E_VFCM_PE_ERRINFO1_ERROR_VALID_MASK I40E_MASK(0x1, I40E_VFCM_PE_ERRINFO1_ERROR_VALID_SHIFT) #define I40E_VFCM_PE_ERRINFO1_ERROR_INST_SHIFT 4 -#define I40E_VFCM_PE_ERRINFO1_ERROR_INST_MASK (0x7 << I40E_VFCM_PE_ERRINFO1_ERROR_INST_SHIFT) +#define I40E_VFCM_PE_ERRINFO1_ERROR_INST_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRINFO1_ERROR_INST_SHIFT) #define I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_SHIFT 8 -#define I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_SHIFT) +#define I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_SHIFT) #define I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_SHIFT 16 -#define I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_SHIFT) +#define I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_SHIFT) #define I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_SHIFT 24 -#define I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_SHIFT) -#define I40E_GLDCB_GENC 0x00083044 +#define I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_SHIFT) +#define I40E_GLDCB_GENC 0x00083044 /* Reset: CORER */ #define I40E_GLDCB_GENC_PCIRTT_SHIFT 0 -#define I40E_GLDCB_GENC_PCIRTT_MASK (0xFFFF << I40E_GLDCB_GENC_PCIRTT_SHIFT) -#define I40E_GLDCB_RUPTI 0x00122618 +#define I40E_GLDCB_GENC_PCIRTT_MASK I40E_MASK(0xFFFF, I40E_GLDCB_GENC_PCIRTT_SHIFT) +#define I40E_GLDCB_RUPTI 0x00122618 /* Reset: CORER */ #define I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_SHIFT 0 -#define I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_MASK (0xFFFFFFFF << I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_SHIFT) -#define I40E_PRTDCB_FCCFG 0x001E4640 +#define I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_SHIFT) +#define I40E_PRTDCB_FCCFG 0x001E4640 /* Reset: GLOBR */ #define I40E_PRTDCB_FCCFG_TFCE_SHIFT 3 -#define I40E_PRTDCB_FCCFG_TFCE_MASK (0x3 << I40E_PRTDCB_FCCFG_TFCE_SHIFT) -#define I40E_PRTDCB_FCRTV 0x001E4600 +#define I40E_PRTDCB_FCCFG_TFCE_MASK I40E_MASK(0x3, I40E_PRTDCB_FCCFG_TFCE_SHIFT) +#define I40E_PRTDCB_FCRTV 0x001E4600 /* Reset: GLOBR */ #define I40E_PRTDCB_FCRTV_FC_REFRESH_TH_SHIFT 0 -#define I40E_PRTDCB_FCRTV_FC_REFRESH_TH_MASK (0xFFFF << I40E_PRTDCB_FCRTV_FC_REFRESH_TH_SHIFT) -#define I40E_PRTDCB_FCTTVN(_i) (0x001E4580 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRTDCB_FCRTV_FC_REFRESH_TH_MASK I40E_MASK(0xFFFF, I40E_PRTDCB_FCRTV_FC_REFRESH_TH_SHIFT) +#define I40E_PRTDCB_FCTTVN(_i) (0x001E4580 + ((_i) * 32)) /* _i=0...3 */ /* Reset: GLOBR */ #define I40E_PRTDCB_FCTTVN_MAX_INDEX 3 #define I40E_PRTDCB_FCTTVN_TTV_2N_SHIFT 0 -#define I40E_PRTDCB_FCTTVN_TTV_2N_MASK (0xFFFF << I40E_PRTDCB_FCTTVN_TTV_2N_SHIFT) +#define I40E_PRTDCB_FCTTVN_TTV_2N_MASK I40E_MASK(0xFFFF, I40E_PRTDCB_FCTTVN_TTV_2N_SHIFT) #define I40E_PRTDCB_FCTTVN_TTV_2N_P1_SHIFT 16 -#define I40E_PRTDCB_FCTTVN_TTV_2N_P1_MASK (0xFFFF << I40E_PRTDCB_FCTTVN_TTV_2N_P1_SHIFT) -#define I40E_PRTDCB_GENC 0x00083000 +#define I40E_PRTDCB_FCTTVN_TTV_2N_P1_MASK I40E_MASK(0xFFFF, I40E_PRTDCB_FCTTVN_TTV_2N_P1_SHIFT) +#define I40E_PRTDCB_GENC 0x00083000 /* Reset: CORER */ #define I40E_PRTDCB_GENC_RESERVED_1_SHIFT 0 -#define I40E_PRTDCB_GENC_RESERVED_1_MASK (0x3 << I40E_PRTDCB_GENC_RESERVED_1_SHIFT) +#define I40E_PRTDCB_GENC_RESERVED_1_MASK I40E_MASK(0x3, I40E_PRTDCB_GENC_RESERVED_1_SHIFT) #define I40E_PRTDCB_GENC_NUMTC_SHIFT 2 -#define I40E_PRTDCB_GENC_NUMTC_MASK (0xF << I40E_PRTDCB_GENC_NUMTC_SHIFT) +#define I40E_PRTDCB_GENC_NUMTC_MASK I40E_MASK(0xF, I40E_PRTDCB_GENC_NUMTC_SHIFT) #define I40E_PRTDCB_GENC_FCOEUP_SHIFT 6 -#define I40E_PRTDCB_GENC_FCOEUP_MASK (0x7 << I40E_PRTDCB_GENC_FCOEUP_SHIFT) +#define I40E_PRTDCB_GENC_FCOEUP_MASK I40E_MASK(0x7, I40E_PRTDCB_GENC_FCOEUP_SHIFT) #define I40E_PRTDCB_GENC_FCOEUP_VALID_SHIFT 9 -#define I40E_PRTDCB_GENC_FCOEUP_VALID_MASK (0x1 << I40E_PRTDCB_GENC_FCOEUP_VALID_SHIFT) +#define I40E_PRTDCB_GENC_FCOEUP_VALID_MASK I40E_MASK(0x1, I40E_PRTDCB_GENC_FCOEUP_VALID_SHIFT) #define I40E_PRTDCB_GENC_PFCLDA_SHIFT 16 -#define I40E_PRTDCB_GENC_PFCLDA_MASK (0xFFFF << I40E_PRTDCB_GENC_PFCLDA_SHIFT) -#define I40E_PRTDCB_GENS 0x00083020 +#define I40E_PRTDCB_GENC_PFCLDA_MASK I40E_MASK(0xFFFF, I40E_PRTDCB_GENC_PFCLDA_SHIFT) +#define I40E_PRTDCB_GENS 0x00083020 /* Reset: CORER */ #define I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT 0 -#define I40E_PRTDCB_GENS_DCBX_STATUS_MASK (0x7 << I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT) -#define I40E_PRTDCB_MFLCN 0x001E2400 +#define I40E_PRTDCB_GENS_DCBX_STATUS_MASK I40E_MASK(0x7, I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT) +#define I40E_PRTDCB_MFLCN 0x001E2400 /* Reset: GLOBR */ #define I40E_PRTDCB_MFLCN_PMCF_SHIFT 0 -#define I40E_PRTDCB_MFLCN_PMCF_MASK (0x1 << I40E_PRTDCB_MFLCN_PMCF_SHIFT) +#define I40E_PRTDCB_MFLCN_PMCF_MASK I40E_MASK(0x1, I40E_PRTDCB_MFLCN_PMCF_SHIFT) #define I40E_PRTDCB_MFLCN_DPF_SHIFT 1 -#define I40E_PRTDCB_MFLCN_DPF_MASK (0x1 << I40E_PRTDCB_MFLCN_DPF_SHIFT) +#define I40E_PRTDCB_MFLCN_DPF_MASK I40E_MASK(0x1, I40E_PRTDCB_MFLCN_DPF_SHIFT) #define I40E_PRTDCB_MFLCN_RPFCM_SHIFT 2 -#define I40E_PRTDCB_MFLCN_RPFCM_MASK (0x1 << I40E_PRTDCB_MFLCN_RPFCM_SHIFT) +#define I40E_PRTDCB_MFLCN_RPFCM_MASK I40E_MASK(0x1, I40E_PRTDCB_MFLCN_RPFCM_SHIFT) #define I40E_PRTDCB_MFLCN_RFCE_SHIFT 3 -#define I40E_PRTDCB_MFLCN_RFCE_MASK (0x1 << I40E_PRTDCB_MFLCN_RFCE_SHIFT) +#define I40E_PRTDCB_MFLCN_RFCE_MASK I40E_MASK(0x1, I40E_PRTDCB_MFLCN_RFCE_SHIFT) #define I40E_PRTDCB_MFLCN_RPFCE_SHIFT 4 -#define I40E_PRTDCB_MFLCN_RPFCE_MASK (0xFF << I40E_PRTDCB_MFLCN_RPFCE_SHIFT) -#define I40E_PRTDCB_RETSC 0x001223E0 +#define I40E_PRTDCB_MFLCN_RPFCE_MASK I40E_MASK(0xFF, I40E_PRTDCB_MFLCN_RPFCE_SHIFT) +#define I40E_PRTDCB_RETSC 0x001223E0 /* Reset: CORER */ #define I40E_PRTDCB_RETSC_ETS_MODE_SHIFT 0 -#define I40E_PRTDCB_RETSC_ETS_MODE_MASK (0x1 << I40E_PRTDCB_RETSC_ETS_MODE_SHIFT) +#define I40E_PRTDCB_RETSC_ETS_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_RETSC_ETS_MODE_SHIFT) #define I40E_PRTDCB_RETSC_NON_ETS_MODE_SHIFT 1 -#define I40E_PRTDCB_RETSC_NON_ETS_MODE_MASK (0x1 << I40E_PRTDCB_RETSC_NON_ETS_MODE_SHIFT) +#define I40E_PRTDCB_RETSC_NON_ETS_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_RETSC_NON_ETS_MODE_SHIFT) #define I40E_PRTDCB_RETSC_ETS_MAX_EXP_SHIFT 2 -#define I40E_PRTDCB_RETSC_ETS_MAX_EXP_MASK (0xF << I40E_PRTDCB_RETSC_ETS_MAX_EXP_SHIFT) +#define I40E_PRTDCB_RETSC_ETS_MAX_EXP_MASK I40E_MASK(0xF, I40E_PRTDCB_RETSC_ETS_MAX_EXP_SHIFT) #define I40E_PRTDCB_RETSC_LLTC_SHIFT 8 -#define I40E_PRTDCB_RETSC_LLTC_MASK (0xFF << I40E_PRTDCB_RETSC_LLTC_SHIFT) -#define I40E_PRTDCB_RETSTCC(_i) (0x00122180 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTDCB_RETSC_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_RETSC_LLTC_SHIFT) +#define I40E_PRTDCB_RETSTCC(_i) (0x00122180 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTDCB_RETSTCC_MAX_INDEX 7 #define I40E_PRTDCB_RETSTCC_BWSHARE_SHIFT 0 -#define I40E_PRTDCB_RETSTCC_BWSHARE_MASK (0x7F << I40E_PRTDCB_RETSTCC_BWSHARE_SHIFT) +#define I40E_PRTDCB_RETSTCC_BWSHARE_MASK I40E_MASK(0x7F, I40E_PRTDCB_RETSTCC_BWSHARE_SHIFT) #define I40E_PRTDCB_RETSTCC_UPINTC_MODE_SHIFT 30 -#define I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK (0x1 << I40E_PRTDCB_RETSTCC_UPINTC_MODE_SHIFT) +#define I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_RETSTCC_UPINTC_MODE_SHIFT) #define I40E_PRTDCB_RETSTCC_ETSTC_SHIFT 31 -#define I40E_PRTDCB_RETSTCC_ETSTC_MASK (0x1 << I40E_PRTDCB_RETSTCC_ETSTC_SHIFT) -#define I40E_PRTDCB_RPPMC 0x001223A0 +#define I40E_PRTDCB_RETSTCC_ETSTC_MASK I40E_MASK(0x1, I40E_PRTDCB_RETSTCC_ETSTC_SHIFT) +#define I40E_PRTDCB_RPPMC 0x001223A0 /* Reset: CORER */ #define I40E_PRTDCB_RPPMC_LANRPPM_SHIFT 0 -#define I40E_PRTDCB_RPPMC_LANRPPM_MASK (0xFF << I40E_PRTDCB_RPPMC_LANRPPM_SHIFT) +#define I40E_PRTDCB_RPPMC_LANRPPM_MASK I40E_MASK(0xFF, I40E_PRTDCB_RPPMC_LANRPPM_SHIFT) #define I40E_PRTDCB_RPPMC_RDMARPPM_SHIFT 8 -#define I40E_PRTDCB_RPPMC_RDMARPPM_MASK (0xFF << I40E_PRTDCB_RPPMC_RDMARPPM_SHIFT) +#define I40E_PRTDCB_RPPMC_RDMARPPM_MASK I40E_MASK(0xFF, I40E_PRTDCB_RPPMC_RDMARPPM_SHIFT) #define I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_SHIFT 16 -#define I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_MASK (0xFF << I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_SHIFT) -#define I40E_PRTDCB_RUP 0x001C0B00 +#define I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_MASK I40E_MASK(0xFF, I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_SHIFT) +#define I40E_PRTDCB_RUP 0x001C0B00 /* Reset: CORER */ #define I40E_PRTDCB_RUP_NOVLANUP_SHIFT 0 -#define I40E_PRTDCB_RUP_NOVLANUP_MASK (0x7 << I40E_PRTDCB_RUP_NOVLANUP_SHIFT) -#define I40E_PRTDCB_RUP2TC 0x001C09A0 +#define I40E_PRTDCB_RUP_NOVLANUP_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP_NOVLANUP_SHIFT) +#define I40E_PRTDCB_RUP2TC 0x001C09A0 /* Reset: CORER */ #define I40E_PRTDCB_RUP2TC_UP0TC_SHIFT 0 -#define I40E_PRTDCB_RUP2TC_UP0TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP0TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP0TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP0TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP1TC_SHIFT 3 -#define I40E_PRTDCB_RUP2TC_UP1TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP1TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP1TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP1TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP2TC_SHIFT 6 -#define I40E_PRTDCB_RUP2TC_UP2TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP2TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP2TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP2TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP3TC_SHIFT 9 -#define I40E_PRTDCB_RUP2TC_UP3TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP3TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP3TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP3TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP4TC_SHIFT 12 -#define I40E_PRTDCB_RUP2TC_UP4TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP4TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP4TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP4TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP5TC_SHIFT 15 -#define I40E_PRTDCB_RUP2TC_UP5TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP5TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP5TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP5TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP6TC_SHIFT 18 -#define I40E_PRTDCB_RUP2TC_UP6TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP6TC_SHIFT) +#define I40E_PRTDCB_RUP2TC_UP6TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP6TC_SHIFT) #define I40E_PRTDCB_RUP2TC_UP7TC_SHIFT 21 -#define I40E_PRTDCB_RUP2TC_UP7TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP7TC_SHIFT) -#define I40E_PRTDCB_TC2PFC 0x001C0980 +#define I40E_PRTDCB_RUP2TC_UP7TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP7TC_SHIFT) +#define I40E_PRTDCB_TC2PFC 0x001C0980 /* Reset: CORER */ #define I40E_PRTDCB_TC2PFC_TC2PFC_SHIFT 0 -#define I40E_PRTDCB_TC2PFC_TC2PFC_MASK (0xFF << I40E_PRTDCB_TC2PFC_TC2PFC_SHIFT) -#define I40E_PRTDCB_TCPMC 0x000A21A0 +#define I40E_PRTDCB_TC2PFC_TC2PFC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TC2PFC_TC2PFC_SHIFT) +#define I40E_PRTDCB_TCMSTC(_i) (0x000A0040 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ +#define I40E_PRTDCB_TCMSTC_MAX_INDEX 7 +#define I40E_PRTDCB_TCMSTC_MSTC_SHIFT 0 +#define I40E_PRTDCB_TCMSTC_MSTC_MASK I40E_MASK(0xFFFFF, I40E_PRTDCB_TCMSTC_MSTC_SHIFT) +#define I40E_PRTDCB_TCPMC 0x000A21A0 /* Reset: CORER */ #define I40E_PRTDCB_TCPMC_CPM_SHIFT 0 -#define I40E_PRTDCB_TCPMC_CPM_MASK (0x1FFF << I40E_PRTDCB_TCPMC_CPM_SHIFT) +#define I40E_PRTDCB_TCPMC_CPM_MASK I40E_MASK(0x1FFF, I40E_PRTDCB_TCPMC_CPM_SHIFT) #define I40E_PRTDCB_TCPMC_LLTC_SHIFT 13 -#define I40E_PRTDCB_TCPMC_LLTC_MASK (0xFF << I40E_PRTDCB_TCPMC_LLTC_SHIFT) +#define I40E_PRTDCB_TCPMC_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TCPMC_LLTC_SHIFT) #define I40E_PRTDCB_TCPMC_TCPM_MODE_SHIFT 30 -#define I40E_PRTDCB_TCPMC_TCPM_MODE_MASK (0x1 << I40E_PRTDCB_TCPMC_TCPM_MODE_SHIFT) -#define I40E_PRTDCB_TCWSTC(_i) (0x000A2040 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTDCB_TCPMC_TCPM_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_TCPMC_TCPM_MODE_SHIFT) +#define I40E_PRTDCB_TCWSTC(_i) (0x000A2040 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTDCB_TCWSTC_MAX_INDEX 7 #define I40E_PRTDCB_TCWSTC_MSTC_SHIFT 0 -#define I40E_PRTDCB_TCWSTC_MSTC_MASK (0xFFFFF << I40E_PRTDCB_TCWSTC_MSTC_SHIFT) -#define I40E_PRTDCB_TDPMC 0x000A0180 +#define I40E_PRTDCB_TCWSTC_MSTC_MASK I40E_MASK(0xFFFFF, I40E_PRTDCB_TCWSTC_MSTC_SHIFT) +#define I40E_PRTDCB_TDPMC 0x000A0180 /* Reset: CORER */ #define I40E_PRTDCB_TDPMC_DPM_SHIFT 0 -#define I40E_PRTDCB_TDPMC_DPM_MASK (0xFF << I40E_PRTDCB_TDPMC_DPM_SHIFT) +#define I40E_PRTDCB_TDPMC_DPM_MASK I40E_MASK(0xFF, I40E_PRTDCB_TDPMC_DPM_SHIFT) #define I40E_PRTDCB_TDPMC_TCPM_MODE_SHIFT 30 -#define I40E_PRTDCB_TDPMC_TCPM_MODE_MASK (0x1 << I40E_PRTDCB_TDPMC_TCPM_MODE_SHIFT) -#define I40E_PRTDCB_TDPUC 0x00044100 -#define I40E_PRTDCB_TDPUC_MAX_TXFRAME_SHIFT 0 -#define I40E_PRTDCB_TDPUC_MAX_TXFRAME_MASK (0xFFFF << I40E_PRTDCB_TDPUC_MAX_TXFRAME_SHIFT) -#define I40E_PRTDCB_TETSC_TCB 0x000AE060 +#define I40E_PRTDCB_TDPMC_TCPM_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_TDPMC_TCPM_MODE_SHIFT) +#define I40E_PRTDCB_TETSC_TCB 0x000AE060 /* Reset: CORER */ #define I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_SHIFT 0 -#define I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_MASK (0x1 << I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_SHIFT) +#define I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_MASK I40E_MASK(0x1, I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_SHIFT) #define I40E_PRTDCB_TETSC_TCB_LLTC_SHIFT 8 -#define I40E_PRTDCB_TETSC_TCB_LLTC_MASK (0xFF << I40E_PRTDCB_TETSC_TCB_LLTC_SHIFT) -#define I40E_PRTDCB_TETSC_TPB 0x00098060 +#define I40E_PRTDCB_TETSC_TCB_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TETSC_TCB_LLTC_SHIFT) +#define I40E_PRTDCB_TETSC_TPB 0x00098060 /* Reset: CORER */ #define I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_SHIFT 0 -#define I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_MASK (0x1 << I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_SHIFT) +#define I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_MASK I40E_MASK(0x1, I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_SHIFT) #define I40E_PRTDCB_TETSC_TPB_LLTC_SHIFT 8 -#define I40E_PRTDCB_TETSC_TPB_LLTC_MASK (0xFF << I40E_PRTDCB_TETSC_TPB_LLTC_SHIFT) -#define I40E_PRTDCB_TFCS 0x001E4560 +#define I40E_PRTDCB_TETSC_TPB_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TETSC_TPB_LLTC_SHIFT) +#define I40E_PRTDCB_TFCS 0x001E4560 /* Reset: GLOBR */ #define I40E_PRTDCB_TFCS_TXOFF_SHIFT 0 -#define I40E_PRTDCB_TFCS_TXOFF_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF0_SHIFT 8 -#define I40E_PRTDCB_TFCS_TXOFF0_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF0_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF0_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF0_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF1_SHIFT 9 -#define I40E_PRTDCB_TFCS_TXOFF1_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF1_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF1_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF1_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF2_SHIFT 10 -#define I40E_PRTDCB_TFCS_TXOFF2_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF2_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF2_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF2_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF3_SHIFT 11 -#define I40E_PRTDCB_TFCS_TXOFF3_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF3_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF3_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF3_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF4_SHIFT 12 -#define I40E_PRTDCB_TFCS_TXOFF4_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF4_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF4_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF4_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF5_SHIFT 13 -#define I40E_PRTDCB_TFCS_TXOFF5_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF5_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF5_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF5_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF6_SHIFT 14 -#define I40E_PRTDCB_TFCS_TXOFF6_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF6_SHIFT) +#define I40E_PRTDCB_TFCS_TXOFF6_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF6_SHIFT) #define I40E_PRTDCB_TFCS_TXOFF7_SHIFT 15 -#define I40E_PRTDCB_TFCS_TXOFF7_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF7_SHIFT) -#define I40E_PRTDCB_TFWSTC(_i) (0x000A0040 + ((_i) * 32)) /* _i=0...7 */ -#define I40E_PRTDCB_TFWSTC_MAX_INDEX 7 -#define I40E_PRTDCB_TFWSTC_MSTC_SHIFT 0 -#define I40E_PRTDCB_TFWSTC_MSTC_MASK (0xFFFFF << I40E_PRTDCB_TFWSTC_MSTC_SHIFT) -#define I40E_PRTDCB_TPFCTS(_i) (0x001E4660 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTDCB_TFCS_TXOFF7_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF7_SHIFT) +#define I40E_PRTDCB_TPFCTS(_i) (0x001E4660 + ((_i) * 32)) /* _i=0...7 */ /* Reset: GLOBR */ #define I40E_PRTDCB_TPFCTS_MAX_INDEX 7 #define I40E_PRTDCB_TPFCTS_PFCTIMER_SHIFT 0 -#define I40E_PRTDCB_TPFCTS_PFCTIMER_MASK (0x3FFF << I40E_PRTDCB_TPFCTS_PFCTIMER_SHIFT) -#define I40E_GLFCOE_RCTL 0x00269B94 +#define I40E_PRTDCB_TPFCTS_PFCTIMER_MASK I40E_MASK(0x3FFF, I40E_PRTDCB_TPFCTS_PFCTIMER_SHIFT) +#define I40E_GLFCOE_RCTL 0x00269B94 /* Reset: CORER */ #define I40E_GLFCOE_RCTL_FCOEVER_SHIFT 0 -#define I40E_GLFCOE_RCTL_FCOEVER_MASK (0xF << I40E_GLFCOE_RCTL_FCOEVER_SHIFT) +#define I40E_GLFCOE_RCTL_FCOEVER_MASK I40E_MASK(0xF, I40E_GLFCOE_RCTL_FCOEVER_SHIFT) #define I40E_GLFCOE_RCTL_SAVBAD_SHIFT 4 -#define I40E_GLFCOE_RCTL_SAVBAD_MASK (0x1 << I40E_GLFCOE_RCTL_SAVBAD_SHIFT) +#define I40E_GLFCOE_RCTL_SAVBAD_MASK I40E_MASK(0x1, I40E_GLFCOE_RCTL_SAVBAD_SHIFT) #define I40E_GLFCOE_RCTL_ICRC_SHIFT 5 -#define I40E_GLFCOE_RCTL_ICRC_MASK (0x1 << I40E_GLFCOE_RCTL_ICRC_SHIFT) +#define I40E_GLFCOE_RCTL_ICRC_MASK I40E_MASK(0x1, I40E_GLFCOE_RCTL_ICRC_SHIFT) #define I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT 16 -#define I40E_GLFCOE_RCTL_MAX_SIZE_MASK (0x3FFF << I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT) -#define I40E_GL_FWSTS 0x00083048 +#define I40E_GLFCOE_RCTL_MAX_SIZE_MASK I40E_MASK(0x3FFF, I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT) +#define I40E_GL_FWSTS 0x00083048 /* Reset: POR */ #define I40E_GL_FWSTS_FWS0B_SHIFT 0 -#define I40E_GL_FWSTS_FWS0B_MASK (0xFF << I40E_GL_FWSTS_FWS0B_SHIFT) +#define I40E_GL_FWSTS_FWS0B_MASK I40E_MASK(0xFF, I40E_GL_FWSTS_FWS0B_SHIFT) #define I40E_GL_FWSTS_FWRI_SHIFT 9 -#define I40E_GL_FWSTS_FWRI_MASK (0x1 << I40E_GL_FWSTS_FWRI_SHIFT) +#define I40E_GL_FWSTS_FWRI_MASK I40E_MASK(0x1, I40E_GL_FWSTS_FWRI_SHIFT) #define I40E_GL_FWSTS_FWS1B_SHIFT 16 -#define I40E_GL_FWSTS_FWS1B_MASK (0xFF << I40E_GL_FWSTS_FWS1B_SHIFT) -#define I40E_GLGEN_CLKSTAT 0x000B8184 +#define I40E_GL_FWSTS_FWS1B_MASK I40E_MASK(0xFF, I40E_GL_FWSTS_FWS1B_SHIFT) +#define I40E_GLGEN_CLKSTAT 0x000B8184 /* Reset: POR */ #define I40E_GLGEN_CLKSTAT_CLKMODE_SHIFT 0 -#define I40E_GLGEN_CLKSTAT_CLKMODE_MASK (0x1 << I40E_GLGEN_CLKSTAT_CLKMODE_SHIFT) +#define I40E_GLGEN_CLKSTAT_CLKMODE_MASK I40E_MASK(0x1, I40E_GLGEN_CLKSTAT_CLKMODE_SHIFT) #define I40E_GLGEN_CLKSTAT_U_CLK_SPEED_SHIFT 4 -#define I40E_GLGEN_CLKSTAT_U_CLK_SPEED_MASK (0x3 << I40E_GLGEN_CLKSTAT_U_CLK_SPEED_SHIFT) +#define I40E_GLGEN_CLKSTAT_U_CLK_SPEED_MASK I40E_MASK(0x3, I40E_GLGEN_CLKSTAT_U_CLK_SPEED_SHIFT) #define I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_SHIFT 8 -#define I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_MASK (0x7 << I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_SHIFT) +#define I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_MASK I40E_MASK(0x7, I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_SHIFT) #define I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_SHIFT 12 -#define I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_MASK (0x7 << I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_SHIFT) +#define I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_MASK I40E_MASK(0x7, I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_SHIFT) #define I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_SHIFT 16 -#define I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_MASK (0x7 << I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_SHIFT) +#define I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_MASK I40E_MASK(0x7, I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_SHIFT) #define I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_SHIFT 20 -#define I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_MASK (0x7 << I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_SHIFT) -#define I40E_GLGEN_GPIO_CTL(_i) (0x00088100 + ((_i) * 4)) /* _i=0...29 */ +#define I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_MASK I40E_MASK(0x7, I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_SHIFT) +#define I40E_GLGEN_GPIO_CTL(_i) (0x00088100 + ((_i) * 4)) /* _i=0...29 */ /* Reset: POR */ #define I40E_GLGEN_GPIO_CTL_MAX_INDEX 29 #define I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT 0 -#define I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK (0x3 << I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT) +#define I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK I40E_MASK(0x3, I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT) #define I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_SHIFT 3 -#define I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_MASK (0x1 << I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_SHIFT) +#define I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_SHIFT) #define I40E_GLGEN_GPIO_CTL_PIN_DIR_SHIFT 4 -#define I40E_GLGEN_GPIO_CTL_PIN_DIR_MASK (0x1 << I40E_GLGEN_GPIO_CTL_PIN_DIR_SHIFT) +#define I40E_GLGEN_GPIO_CTL_PIN_DIR_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_PIN_DIR_SHIFT) #define I40E_GLGEN_GPIO_CTL_TRI_CTL_SHIFT 5 -#define I40E_GLGEN_GPIO_CTL_TRI_CTL_MASK (0x1 << I40E_GLGEN_GPIO_CTL_TRI_CTL_SHIFT) +#define I40E_GLGEN_GPIO_CTL_TRI_CTL_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_TRI_CTL_SHIFT) #define I40E_GLGEN_GPIO_CTL_OUT_CTL_SHIFT 6 -#define I40E_GLGEN_GPIO_CTL_OUT_CTL_MASK (0x1 << I40E_GLGEN_GPIO_CTL_OUT_CTL_SHIFT) +#define I40E_GLGEN_GPIO_CTL_OUT_CTL_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_OUT_CTL_SHIFT) #define I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT 7 -#define I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK (0x7 << I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT) +#define I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK I40E_MASK(0x7, I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT) #define I40E_GLGEN_GPIO_CTL_LED_INVRT_SHIFT 10 -#define I40E_GLGEN_GPIO_CTL_LED_INVRT_MASK (0x1 << I40E_GLGEN_GPIO_CTL_LED_INVRT_SHIFT) +#define I40E_GLGEN_GPIO_CTL_LED_INVRT_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_LED_INVRT_SHIFT) #define I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT 11 -#define I40E_GLGEN_GPIO_CTL_LED_BLINK_MASK (0x1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT) +#define I40E_GLGEN_GPIO_CTL_LED_BLINK_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT) #define I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT 12 -#define I40E_GLGEN_GPIO_CTL_LED_MODE_MASK (0xF << I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT) +#define I40E_GLGEN_GPIO_CTL_LED_MODE_MASK I40E_MASK(0x1F, I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT) #define I40E_GLGEN_GPIO_CTL_INT_MODE_SHIFT 17 -#define I40E_GLGEN_GPIO_CTL_INT_MODE_MASK (0x3 << I40E_GLGEN_GPIO_CTL_INT_MODE_SHIFT) +#define I40E_GLGEN_GPIO_CTL_INT_MODE_MASK I40E_MASK(0x3, I40E_GLGEN_GPIO_CTL_INT_MODE_SHIFT) #define I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_SHIFT 19 -#define I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_MASK (0x1 << I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_SHIFT) +#define I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_SHIFT) #define I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_SHIFT 20 -#define I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_MASK (0x3F << I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_SHIFT) -#define I40E_GLGEN_GPIO_SET 0x00088184 +#define I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_MASK I40E_MASK(0x3F, I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_SHIFT) +#define I40E_GLGEN_GPIO_SET 0x00088184 /* Reset: POR */ #define I40E_GLGEN_GPIO_SET_GPIO_INDX_SHIFT 0 -#define I40E_GLGEN_GPIO_SET_GPIO_INDX_MASK (0x1F << I40E_GLGEN_GPIO_SET_GPIO_INDX_SHIFT) +#define I40E_GLGEN_GPIO_SET_GPIO_INDX_MASK I40E_MASK(0x1F, I40E_GLGEN_GPIO_SET_GPIO_INDX_SHIFT) #define I40E_GLGEN_GPIO_SET_SDP_DATA_SHIFT 5 -#define I40E_GLGEN_GPIO_SET_SDP_DATA_MASK (0x1 << I40E_GLGEN_GPIO_SET_SDP_DATA_SHIFT) +#define I40E_GLGEN_GPIO_SET_SDP_DATA_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_SET_SDP_DATA_SHIFT) #define I40E_GLGEN_GPIO_SET_DRIVE_SDP_SHIFT 6 -#define I40E_GLGEN_GPIO_SET_DRIVE_SDP_MASK (0x1 << I40E_GLGEN_GPIO_SET_DRIVE_SDP_SHIFT) -#define I40E_GLGEN_GPIO_STAT 0x0008817C +#define I40E_GLGEN_GPIO_SET_DRIVE_SDP_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_SET_DRIVE_SDP_SHIFT) +#define I40E_GLGEN_GPIO_STAT 0x0008817C /* Reset: POR */ #define I40E_GLGEN_GPIO_STAT_GPIO_VALUE_SHIFT 0 -#define I40E_GLGEN_GPIO_STAT_GPIO_VALUE_MASK (0x3FFFFFFF << I40E_GLGEN_GPIO_STAT_GPIO_VALUE_SHIFT) -#define I40E_GLGEN_GPIO_TRANSIT 0x00088180 +#define I40E_GLGEN_GPIO_STAT_GPIO_VALUE_MASK I40E_MASK(0x3FFFFFFF, I40E_GLGEN_GPIO_STAT_GPIO_VALUE_SHIFT) +#define I40E_GLGEN_GPIO_TRANSIT 0x00088180 /* Reset: POR */ #define I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_SHIFT 0 -#define I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_MASK (0x3FFFFFFF << I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_SHIFT) -#define I40E_GLGEN_I2CCMD(_i) (0x000881E0 + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_MASK I40E_MASK(0x3FFFFFFF, I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_SHIFT) +#define I40E_GLGEN_I2CCMD(_i) (0x000881E0 + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ #define I40E_GLGEN_I2CCMD_MAX_INDEX 3 #define I40E_GLGEN_I2CCMD_DATA_SHIFT 0 -#define I40E_GLGEN_I2CCMD_DATA_MASK (0xFFFF << I40E_GLGEN_I2CCMD_DATA_SHIFT) +#define I40E_GLGEN_I2CCMD_DATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_I2CCMD_DATA_SHIFT) #define I40E_GLGEN_I2CCMD_REGADD_SHIFT 16 -#define I40E_GLGEN_I2CCMD_REGADD_MASK (0xFF << I40E_GLGEN_I2CCMD_REGADD_SHIFT) +#define I40E_GLGEN_I2CCMD_REGADD_MASK I40E_MASK(0xFF, I40E_GLGEN_I2CCMD_REGADD_SHIFT) #define I40E_GLGEN_I2CCMD_PHYADD_SHIFT 24 -#define I40E_GLGEN_I2CCMD_PHYADD_MASK (0x7 << I40E_GLGEN_I2CCMD_PHYADD_SHIFT) +#define I40E_GLGEN_I2CCMD_PHYADD_MASK I40E_MASK(0x7, I40E_GLGEN_I2CCMD_PHYADD_SHIFT) #define I40E_GLGEN_I2CCMD_OP_SHIFT 27 -#define I40E_GLGEN_I2CCMD_OP_MASK (0x1 << I40E_GLGEN_I2CCMD_OP_SHIFT) +#define I40E_GLGEN_I2CCMD_OP_MASK I40E_MASK(0x1, I40E_GLGEN_I2CCMD_OP_SHIFT) #define I40E_GLGEN_I2CCMD_RESET_SHIFT 28 -#define I40E_GLGEN_I2CCMD_RESET_MASK (0x1 << I40E_GLGEN_I2CCMD_RESET_SHIFT) +#define I40E_GLGEN_I2CCMD_RESET_MASK I40E_MASK(0x1, I40E_GLGEN_I2CCMD_RESET_SHIFT) #define I40E_GLGEN_I2CCMD_R_SHIFT 29 -#define I40E_GLGEN_I2CCMD_R_MASK (0x1 << I40E_GLGEN_I2CCMD_R_SHIFT) +#define I40E_GLGEN_I2CCMD_R_MASK I40E_MASK(0x1, I40E_GLGEN_I2CCMD_R_SHIFT) #define I40E_GLGEN_I2CCMD_E_SHIFT 31 -#define I40E_GLGEN_I2CCMD_E_MASK (0x1 << I40E_GLGEN_I2CCMD_E_SHIFT) -#define I40E_GLGEN_I2CPARAMS(_i) (0x000881AC + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_I2CCMD_E_MASK I40E_MASK(0x1, I40E_GLGEN_I2CCMD_E_SHIFT) +#define I40E_GLGEN_I2CPARAMS(_i) (0x000881AC + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ #define I40E_GLGEN_I2CPARAMS_MAX_INDEX 3 #define I40E_GLGEN_I2CPARAMS_WRITE_TIME_SHIFT 0 -#define I40E_GLGEN_I2CPARAMS_WRITE_TIME_MASK (0x1F << I40E_GLGEN_I2CPARAMS_WRITE_TIME_SHIFT) +#define I40E_GLGEN_I2CPARAMS_WRITE_TIME_MASK I40E_MASK(0x1F, I40E_GLGEN_I2CPARAMS_WRITE_TIME_SHIFT) #define I40E_GLGEN_I2CPARAMS_READ_TIME_SHIFT 5 -#define I40E_GLGEN_I2CPARAMS_READ_TIME_MASK (0x7 << I40E_GLGEN_I2CPARAMS_READ_TIME_SHIFT) +#define I40E_GLGEN_I2CPARAMS_READ_TIME_MASK I40E_MASK(0x7, I40E_GLGEN_I2CPARAMS_READ_TIME_SHIFT) #define I40E_GLGEN_I2CPARAMS_I2CBB_EN_SHIFT 8 -#define I40E_GLGEN_I2CPARAMS_I2CBB_EN_MASK (0x1 << I40E_GLGEN_I2CPARAMS_I2CBB_EN_SHIFT) +#define I40E_GLGEN_I2CPARAMS_I2CBB_EN_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_I2CBB_EN_SHIFT) #define I40E_GLGEN_I2CPARAMS_CLK_SHIFT 9 -#define I40E_GLGEN_I2CPARAMS_CLK_MASK (0x1 << I40E_GLGEN_I2CPARAMS_CLK_SHIFT) +#define I40E_GLGEN_I2CPARAMS_CLK_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_CLK_SHIFT) #define I40E_GLGEN_I2CPARAMS_DATA_OUT_SHIFT 10 -#define I40E_GLGEN_I2CPARAMS_DATA_OUT_MASK (0x1 << I40E_GLGEN_I2CPARAMS_DATA_OUT_SHIFT) +#define I40E_GLGEN_I2CPARAMS_DATA_OUT_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_DATA_OUT_SHIFT) #define I40E_GLGEN_I2CPARAMS_DATA_OE_N_SHIFT 11 -#define I40E_GLGEN_I2CPARAMS_DATA_OE_N_MASK (0x1 << I40E_GLGEN_I2CPARAMS_DATA_OE_N_SHIFT) +#define I40E_GLGEN_I2CPARAMS_DATA_OE_N_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_DATA_OE_N_SHIFT) #define I40E_GLGEN_I2CPARAMS_DATA_IN_SHIFT 12 -#define I40E_GLGEN_I2CPARAMS_DATA_IN_MASK (0x1 << I40E_GLGEN_I2CPARAMS_DATA_IN_SHIFT) +#define I40E_GLGEN_I2CPARAMS_DATA_IN_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_DATA_IN_SHIFT) #define I40E_GLGEN_I2CPARAMS_CLK_OE_N_SHIFT 13 -#define I40E_GLGEN_I2CPARAMS_CLK_OE_N_MASK (0x1 << I40E_GLGEN_I2CPARAMS_CLK_OE_N_SHIFT) +#define I40E_GLGEN_I2CPARAMS_CLK_OE_N_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_CLK_OE_N_SHIFT) #define I40E_GLGEN_I2CPARAMS_CLK_IN_SHIFT 14 -#define I40E_GLGEN_I2CPARAMS_CLK_IN_MASK (0x1 << I40E_GLGEN_I2CPARAMS_CLK_IN_SHIFT) +#define I40E_GLGEN_I2CPARAMS_CLK_IN_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_CLK_IN_SHIFT) #define I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_SHIFT 15 -#define I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_MASK (0x1 << I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_SHIFT) +#define I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_SHIFT) #define I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_SHIFT 31 -#define I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_MASK (0x1 << I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_SHIFT) -#define I40E_GLGEN_LED_CTL 0x00088178 +#define I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_SHIFT) +#define I40E_GLGEN_LED_CTL 0x00088178 /* Reset: POR */ #define I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_SHIFT 0 -#define I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_MASK (0x1 << I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_SHIFT) -#define I40E_GLGEN_MDIO_CTRL(_i) (0x000881D0 + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_MASK I40E_MASK(0x1, I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_SHIFT) +#define I40E_GLGEN_MDIO_CTRL(_i) (0x000881D0 + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ #define I40E_GLGEN_MDIO_CTRL_MAX_INDEX 3 #define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_SHIFT 0 -#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_MASK (0x1FFFF << I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_SHIFT) +#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_MASK I40E_MASK(0x1FFFF, I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_SHIFT) #define I40E_GLGEN_MDIO_CTRL_CONTMDC_SHIFT 17 -#define I40E_GLGEN_MDIO_CTRL_CONTMDC_MASK (0x1 << I40E_GLGEN_MDIO_CTRL_CONTMDC_SHIFT) +#define I40E_GLGEN_MDIO_CTRL_CONTMDC_MASK I40E_MASK(0x1, I40E_GLGEN_MDIO_CTRL_CONTMDC_SHIFT) #define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_SHIFT 18 -#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_MASK (0x3FFF << I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_SHIFT) -#define I40E_GLGEN_MDIO_I2C_SEL(_i) (0x000881C0 + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_MASK I40E_MASK(0x3FFF, I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL(_i) (0x000881C0 + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ #define I40E_GLGEN_MDIO_I2C_SEL_MAX_INDEX 3 #define I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_SHIFT 0 -#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_MASK (0x1 << I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_MASK I40E_MASK(0x1, I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_SHIFT 1 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_MASK (0xF << I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_MASK I40E_MASK(0xF, I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_SHIFT 5 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_MASK (0x1F << I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_MASK I40E_MASK(0x1F, I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_SHIFT 10 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_MASK (0x1F << I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_MASK I40E_MASK(0x1F, I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_SHIFT 15 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_MASK (0x1F << I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_MASK I40E_MASK(0x1F, I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_SHIFT 20 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_MASK (0x1F << I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_MASK I40E_MASK(0x1F, I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_SHIFT 25 -#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_MASK (0xF << I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_SHIFT) +#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_MASK I40E_MASK(0xF, I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_SHIFT) #define I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_SHIFT 31 -#define I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_MASK (0x1 << I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_SHIFT) -#define I40E_GLGEN_MSCA(_i) (0x0008818C + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_MASK I40E_MASK(0x1, I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_SHIFT) +#define I40E_GLGEN_MSCA(_i) (0x0008818C + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ #define I40E_GLGEN_MSCA_MAX_INDEX 3 #define I40E_GLGEN_MSCA_MDIADD_SHIFT 0 -#define I40E_GLGEN_MSCA_MDIADD_MASK (0xFFFF << I40E_GLGEN_MSCA_MDIADD_SHIFT) +#define I40E_GLGEN_MSCA_MDIADD_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSCA_MDIADD_SHIFT) #define I40E_GLGEN_MSCA_DEVADD_SHIFT 16 -#define I40E_GLGEN_MSCA_DEVADD_MASK (0x1F << I40E_GLGEN_MSCA_DEVADD_SHIFT) +#define I40E_GLGEN_MSCA_DEVADD_MASK I40E_MASK(0x1F, I40E_GLGEN_MSCA_DEVADD_SHIFT) #define I40E_GLGEN_MSCA_PHYADD_SHIFT 21 -#define I40E_GLGEN_MSCA_PHYADD_MASK (0x1F << I40E_GLGEN_MSCA_PHYADD_SHIFT) +#define I40E_GLGEN_MSCA_PHYADD_MASK I40E_MASK(0x1F, I40E_GLGEN_MSCA_PHYADD_SHIFT) #define I40E_GLGEN_MSCA_OPCODE_SHIFT 26 -#define I40E_GLGEN_MSCA_OPCODE_MASK (0x3 << I40E_GLGEN_MSCA_OPCODE_SHIFT) +#define I40E_GLGEN_MSCA_OPCODE_MASK I40E_MASK(0x3, I40E_GLGEN_MSCA_OPCODE_SHIFT) #define I40E_GLGEN_MSCA_STCODE_SHIFT 28 -#define I40E_GLGEN_MSCA_STCODE_MASK (0x3 << I40E_GLGEN_MSCA_STCODE_SHIFT) +#define I40E_GLGEN_MSCA_STCODE_MASK I40E_MASK(0x3, I40E_GLGEN_MSCA_STCODE_SHIFT) #define I40E_GLGEN_MSCA_MDICMD_SHIFT 30 -#define I40E_GLGEN_MSCA_MDICMD_MASK (0x1 << I40E_GLGEN_MSCA_MDICMD_SHIFT) +#define I40E_GLGEN_MSCA_MDICMD_MASK I40E_MASK(0x1, I40E_GLGEN_MSCA_MDICMD_SHIFT) #define I40E_GLGEN_MSCA_MDIINPROGEN_SHIFT 31 -#define I40E_GLGEN_MSCA_MDIINPROGEN_MASK (0x1 << I40E_GLGEN_MSCA_MDIINPROGEN_SHIFT) -#define I40E_GLGEN_MSRWD(_i) (0x0008819C + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_MSCA_MDIINPROGEN_MASK I40E_MASK(0x1, I40E_GLGEN_MSCA_MDIINPROGEN_SHIFT) +#define I40E_GLGEN_MSRWD(_i) (0x0008819C + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ #define I40E_GLGEN_MSRWD_MAX_INDEX 3 #define I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT 0 -#define I40E_GLGEN_MSRWD_MDIWRDATA_MASK (0xFFFF << I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT) +#define I40E_GLGEN_MSRWD_MDIWRDATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT) #define I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT 16 -#define I40E_GLGEN_MSRWD_MDIRDDATA_MASK (0xFFFF << I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT) -#define I40E_GLGEN_PCIFCNCNT 0x001C0AB4 +#define I40E_GLGEN_MSRWD_MDIRDDATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT) +#define I40E_GLGEN_PCIFCNCNT 0x001C0AB4 /* Reset: PCIR */ #define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT 0 -#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK (0x1F << I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT) +#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK I40E_MASK(0x1F, I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT) #define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT 16 -#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_MASK (0xFF << I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT) -#define I40E_GLGEN_PE_ENA 0x000B81A0 -#define I40E_GLGEN_PE_ENA_PE_ENA_SHIFT 0 -#define I40E_GLGEN_PE_ENA_PE_ENA_MASK (0x1 << I40E_GLGEN_PE_ENA_PE_ENA_SHIFT) -#define I40E_GLGEN_PE_ENA_PE_CLK_SRC_SEL_SHIFT 1 -#define I40E_GLGEN_PE_ENA_PE_CLK_SRC_SEL_MASK (0x3 << I40E_GLGEN_PE_ENA_PE_CLK_SRC_SEL_SHIFT) -#define I40E_GLGEN_RSTAT 0x000B8188 +#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_MASK I40E_MASK(0xFF, I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT) +#define I40E_GLGEN_RSTAT 0x000B8188 /* Reset: POR */ #define I40E_GLGEN_RSTAT_DEVSTATE_SHIFT 0 -#define I40E_GLGEN_RSTAT_DEVSTATE_MASK (0x3 << I40E_GLGEN_RSTAT_DEVSTATE_SHIFT) +#define I40E_GLGEN_RSTAT_DEVSTATE_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_DEVSTATE_SHIFT) #define I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT 2 -#define I40E_GLGEN_RSTAT_RESET_TYPE_MASK (0x3 << I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT) +#define I40E_GLGEN_RSTAT_RESET_TYPE_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT) #define I40E_GLGEN_RSTAT_CORERCNT_SHIFT 4 -#define I40E_GLGEN_RSTAT_CORERCNT_MASK (0x3 << I40E_GLGEN_RSTAT_CORERCNT_SHIFT) +#define I40E_GLGEN_RSTAT_CORERCNT_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_CORERCNT_SHIFT) #define I40E_GLGEN_RSTAT_GLOBRCNT_SHIFT 6 -#define I40E_GLGEN_RSTAT_GLOBRCNT_MASK (0x3 << I40E_GLGEN_RSTAT_GLOBRCNT_SHIFT) +#define I40E_GLGEN_RSTAT_GLOBRCNT_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_GLOBRCNT_SHIFT) #define I40E_GLGEN_RSTAT_EMPRCNT_SHIFT 8 -#define I40E_GLGEN_RSTAT_EMPRCNT_MASK (0x3 << I40E_GLGEN_RSTAT_EMPRCNT_SHIFT) +#define I40E_GLGEN_RSTAT_EMPRCNT_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_EMPRCNT_SHIFT) #define I40E_GLGEN_RSTAT_TIME_TO_RST_SHIFT 10 -#define I40E_GLGEN_RSTAT_TIME_TO_RST_MASK (0x3F << I40E_GLGEN_RSTAT_TIME_TO_RST_SHIFT) -#define I40E_GLGEN_RSTCTL 0x000B8180 +#define I40E_GLGEN_RSTAT_TIME_TO_RST_MASK I40E_MASK(0x3F, I40E_GLGEN_RSTAT_TIME_TO_RST_SHIFT) +#define I40E_GLGEN_RSTCTL 0x000B8180 /* Reset: POR */ #define I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT 0 -#define I40E_GLGEN_RSTCTL_GRSTDEL_MASK (0x3F << I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT) +#define I40E_GLGEN_RSTCTL_GRSTDEL_MASK I40E_MASK(0x3F, I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT) #define I40E_GLGEN_RSTCTL_ECC_RST_ENA_SHIFT 8 -#define I40E_GLGEN_RSTCTL_ECC_RST_ENA_MASK (0x1 << I40E_GLGEN_RSTCTL_ECC_RST_ENA_SHIFT) -#define I40E_GLGEN_RSTENA_EMP 0x000B818C +#define I40E_GLGEN_RSTCTL_ECC_RST_ENA_MASK I40E_MASK(0x1, I40E_GLGEN_RSTCTL_ECC_RST_ENA_SHIFT) +#define I40E_GLGEN_RSTENA_EMP 0x000B818C /* Reset: POR */ #define I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_SHIFT 0 -#define I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_MASK (0x1 << I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_SHIFT) -#define I40E_GLGEN_RTRIG 0x000B8190 +#define I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_MASK I40E_MASK(0x1, I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_SHIFT) +#define I40E_GLGEN_RTRIG 0x000B8190 /* Reset: CORER */ #define I40E_GLGEN_RTRIG_CORER_SHIFT 0 -#define I40E_GLGEN_RTRIG_CORER_MASK (0x1 << I40E_GLGEN_RTRIG_CORER_SHIFT) +#define I40E_GLGEN_RTRIG_CORER_MASK I40E_MASK(0x1, I40E_GLGEN_RTRIG_CORER_SHIFT) #define I40E_GLGEN_RTRIG_GLOBR_SHIFT 1 -#define I40E_GLGEN_RTRIG_GLOBR_MASK (0x1 << I40E_GLGEN_RTRIG_GLOBR_SHIFT) +#define I40E_GLGEN_RTRIG_GLOBR_MASK I40E_MASK(0x1, I40E_GLGEN_RTRIG_GLOBR_SHIFT) #define I40E_GLGEN_RTRIG_EMPFWR_SHIFT 2 -#define I40E_GLGEN_RTRIG_EMPFWR_MASK (0x1 << I40E_GLGEN_RTRIG_EMPFWR_SHIFT) -#define I40E_GLGEN_STAT 0x000B612C +#define I40E_GLGEN_RTRIG_EMPFWR_MASK I40E_MASK(0x1, I40E_GLGEN_RTRIG_EMPFWR_SHIFT) +#define I40E_GLGEN_STAT 0x000B612C /* Reset: POR */ #define I40E_GLGEN_STAT_HWRSVD0_SHIFT 0 -#define I40E_GLGEN_STAT_HWRSVD0_MASK (0x3 << I40E_GLGEN_STAT_HWRSVD0_SHIFT) +#define I40E_GLGEN_STAT_HWRSVD0_MASK I40E_MASK(0x3, I40E_GLGEN_STAT_HWRSVD0_SHIFT) #define I40E_GLGEN_STAT_DCBEN_SHIFT 2 -#define I40E_GLGEN_STAT_DCBEN_MASK (0x1 << I40E_GLGEN_STAT_DCBEN_SHIFT) +#define I40E_GLGEN_STAT_DCBEN_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_DCBEN_SHIFT) #define I40E_GLGEN_STAT_VTEN_SHIFT 3 -#define I40E_GLGEN_STAT_VTEN_MASK (0x1 << I40E_GLGEN_STAT_VTEN_SHIFT) +#define I40E_GLGEN_STAT_VTEN_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_VTEN_SHIFT) #define I40E_GLGEN_STAT_FCOEN_SHIFT 4 -#define I40E_GLGEN_STAT_FCOEN_MASK (0x1 << I40E_GLGEN_STAT_FCOEN_SHIFT) +#define I40E_GLGEN_STAT_FCOEN_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_FCOEN_SHIFT) #define I40E_GLGEN_STAT_EVBEN_SHIFT 5 -#define I40E_GLGEN_STAT_EVBEN_MASK (0x1 << I40E_GLGEN_STAT_EVBEN_SHIFT) +#define I40E_GLGEN_STAT_EVBEN_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_EVBEN_SHIFT) #define I40E_GLGEN_STAT_HWRSVD1_SHIFT 6 -#define I40E_GLGEN_STAT_HWRSVD1_MASK (0x3 << I40E_GLGEN_STAT_HWRSVD1_SHIFT) -#define I40E_GLGEN_VFLRSTAT(_i) (0x00092600 + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLGEN_STAT_HWRSVD1_MASK I40E_MASK(0x3, I40E_GLGEN_STAT_HWRSVD1_SHIFT) +#define I40E_GLGEN_VFLRSTAT(_i) (0x00092600 + ((_i) * 4)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLGEN_VFLRSTAT_MAX_INDEX 3 #define I40E_GLGEN_VFLRSTAT_VFLRE_SHIFT 0 -#define I40E_GLGEN_VFLRSTAT_VFLRE_MASK (0xFFFFFFFF << I40E_GLGEN_VFLRSTAT_VFLRE_SHIFT) -#define I40E_GLVFGEN_TIMER 0x000881BC +#define I40E_GLGEN_VFLRSTAT_VFLRE_MASK I40E_MASK(0xFFFFFFFF, I40E_GLGEN_VFLRSTAT_VFLRE_SHIFT) +#define I40E_GLVFGEN_TIMER 0x000881BC /* Reset: CORER */ #define I40E_GLVFGEN_TIMER_GTIME_SHIFT 0 -#define I40E_GLVFGEN_TIMER_GTIME_MASK (0xFFFFFFFF << I40E_GLVFGEN_TIMER_GTIME_SHIFT) -#define I40E_PFGEN_CTRL 0x00092400 +#define I40E_GLVFGEN_TIMER_GTIME_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVFGEN_TIMER_GTIME_SHIFT) +#define I40E_PFGEN_CTRL 0x00092400 /* Reset: PFR */ #define I40E_PFGEN_CTRL_PFSWR_SHIFT 0 -#define I40E_PFGEN_CTRL_PFSWR_MASK (0x1 << I40E_PFGEN_CTRL_PFSWR_SHIFT) -#define I40E_PFGEN_DRUN 0x00092500 +#define I40E_PFGEN_CTRL_PFSWR_MASK I40E_MASK(0x1, I40E_PFGEN_CTRL_PFSWR_SHIFT) +#define I40E_PFGEN_DRUN 0x00092500 /* Reset: CORER */ #define I40E_PFGEN_DRUN_DRVUNLD_SHIFT 0 -#define I40E_PFGEN_DRUN_DRVUNLD_MASK (0x1 << I40E_PFGEN_DRUN_DRVUNLD_SHIFT) -#define I40E_PFGEN_PORTNUM 0x001C0480 +#define I40E_PFGEN_DRUN_DRVUNLD_MASK I40E_MASK(0x1, I40E_PFGEN_DRUN_DRVUNLD_SHIFT) +#define I40E_PFGEN_PORTNUM 0x001C0480 /* Reset: CORER */ #define I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT 0 -#define I40E_PFGEN_PORTNUM_PORT_NUM_MASK (0x3 << I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT) -#define I40E_PFGEN_STATE 0x00088000 -#define I40E_PFGEN_STATE_PFPEEN_SHIFT 0 -#define I40E_PFGEN_STATE_PFPEEN_MASK (0x1 << I40E_PFGEN_STATE_PFPEEN_SHIFT) +#define I40E_PFGEN_PORTNUM_PORT_NUM_MASK I40E_MASK(0x3, I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT) +#define I40E_PFGEN_STATE 0x00088000 /* Reset: CORER */ +#define I40E_PFGEN_STATE_RESERVED_0_SHIFT 0 +#define I40E_PFGEN_STATE_RESERVED_0_MASK I40E_MASK(0x1, I40E_PFGEN_STATE_RESERVED_0_SHIFT) #define I40E_PFGEN_STATE_PFFCEN_SHIFT 1 -#define I40E_PFGEN_STATE_PFFCEN_MASK (0x1 << I40E_PFGEN_STATE_PFFCEN_SHIFT) +#define I40E_PFGEN_STATE_PFFCEN_MASK I40E_MASK(0x1, I40E_PFGEN_STATE_PFFCEN_SHIFT) #define I40E_PFGEN_STATE_PFLINKEN_SHIFT 2 -#define I40E_PFGEN_STATE_PFLINKEN_MASK (0x1 << I40E_PFGEN_STATE_PFLINKEN_SHIFT) +#define I40E_PFGEN_STATE_PFLINKEN_MASK I40E_MASK(0x1, I40E_PFGEN_STATE_PFLINKEN_SHIFT) #define I40E_PFGEN_STATE_PFSCEN_SHIFT 3 -#define I40E_PFGEN_STATE_PFSCEN_MASK (0x1 << I40E_PFGEN_STATE_PFSCEN_SHIFT) -#define I40E_PRTGEN_CNF 0x000B8120 +#define I40E_PFGEN_STATE_PFSCEN_MASK I40E_MASK(0x1, I40E_PFGEN_STATE_PFSCEN_SHIFT) +#define I40E_PRTGEN_CNF 0x000B8120 /* Reset: POR */ #define I40E_PRTGEN_CNF_PORT_DIS_SHIFT 0 -#define I40E_PRTGEN_CNF_PORT_DIS_MASK (0x1 << I40E_PRTGEN_CNF_PORT_DIS_SHIFT) +#define I40E_PRTGEN_CNF_PORT_DIS_MASK I40E_MASK(0x1, I40E_PRTGEN_CNF_PORT_DIS_SHIFT) #define I40E_PRTGEN_CNF_ALLOW_PORT_DIS_SHIFT 1 -#define I40E_PRTGEN_CNF_ALLOW_PORT_DIS_MASK (0x1 << I40E_PRTGEN_CNF_ALLOW_PORT_DIS_SHIFT) +#define I40E_PRTGEN_CNF_ALLOW_PORT_DIS_MASK I40E_MASK(0x1, I40E_PRTGEN_CNF_ALLOW_PORT_DIS_SHIFT) #define I40E_PRTGEN_CNF_EMP_PORT_DIS_SHIFT 2 -#define I40E_PRTGEN_CNF_EMP_PORT_DIS_MASK (0x1 << I40E_PRTGEN_CNF_EMP_PORT_DIS_SHIFT) -#define I40E_PRTGEN_CNF2 0x000B8160 +#define I40E_PRTGEN_CNF_EMP_PORT_DIS_MASK I40E_MASK(0x1, I40E_PRTGEN_CNF_EMP_PORT_DIS_SHIFT) +#define I40E_PRTGEN_CNF2 0x000B8160 /* Reset: POR */ #define I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_SHIFT 0 -#define I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_MASK (0x1 << I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_SHIFT) -#define I40E_PRTGEN_STATUS 0x000B8100 +#define I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_MASK I40E_MASK(0x1, I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_SHIFT) +#define I40E_PRTGEN_STATUS 0x000B8100 /* Reset: POR */ #define I40E_PRTGEN_STATUS_PORT_VALID_SHIFT 0 -#define I40E_PRTGEN_STATUS_PORT_VALID_MASK (0x1 << I40E_PRTGEN_STATUS_PORT_VALID_SHIFT) +#define I40E_PRTGEN_STATUS_PORT_VALID_MASK I40E_MASK(0x1, I40E_PRTGEN_STATUS_PORT_VALID_SHIFT) #define I40E_PRTGEN_STATUS_PORT_ACTIVE_SHIFT 1 -#define I40E_PRTGEN_STATUS_PORT_ACTIVE_MASK (0x1 << I40E_PRTGEN_STATUS_PORT_ACTIVE_SHIFT) -#define I40E_VFGEN_RSTAT1(_VF) (0x00074400 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_PRTGEN_STATUS_PORT_ACTIVE_MASK I40E_MASK(0x1, I40E_PRTGEN_STATUS_PORT_ACTIVE_SHIFT) +#define I40E_VFGEN_RSTAT1(_VF) (0x00074400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VFGEN_RSTAT1_MAX_INDEX 127 #define I40E_VFGEN_RSTAT1_VFR_STATE_SHIFT 0 -#define I40E_VFGEN_RSTAT1_VFR_STATE_MASK (0x3 << I40E_VFGEN_RSTAT1_VFR_STATE_SHIFT) -#define I40E_VPGEN_VFRSTAT(_VF) (0x00091C00 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFGEN_RSTAT1_VFR_STATE_MASK I40E_MASK(0x3, I40E_VFGEN_RSTAT1_VFR_STATE_SHIFT) +#define I40E_VPGEN_VFRSTAT(_VF) (0x00091C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VPGEN_VFRSTAT_MAX_INDEX 127 #define I40E_VPGEN_VFRSTAT_VFRD_SHIFT 0 -#define I40E_VPGEN_VFRSTAT_VFRD_MASK (0x1 << I40E_VPGEN_VFRSTAT_VFRD_SHIFT) -#define I40E_VPGEN_VFRTRIG(_VF) (0x00091800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VPGEN_VFRSTAT_VFRD_MASK I40E_MASK(0x1, I40E_VPGEN_VFRSTAT_VFRD_SHIFT) +#define I40E_VPGEN_VFRTRIG(_VF) (0x00091800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VPGEN_VFRTRIG_MAX_INDEX 127 #define I40E_VPGEN_VFRTRIG_VFSWR_SHIFT 0 -#define I40E_VPGEN_VFRTRIG_VFSWR_MASK (0x1 << I40E_VPGEN_VFRTRIG_VFSWR_SHIFT) -#define I40E_VSIGEN_RSTAT(_VSI) (0x00090800 + ((_VSI) * 4)) /* _i=0...383 */ +#define I40E_VPGEN_VFRTRIG_VFSWR_MASK I40E_MASK(0x1, I40E_VPGEN_VFRTRIG_VFSWR_SHIFT) +#define I40E_VSIGEN_RSTAT(_VSI) (0x00090800 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_VSIGEN_RSTAT_MAX_INDEX 383 #define I40E_VSIGEN_RSTAT_VMRD_SHIFT 0 -#define I40E_VSIGEN_RSTAT_VMRD_MASK (0x1 << I40E_VSIGEN_RSTAT_VMRD_SHIFT) -#define I40E_VSIGEN_RTRIG(_VSI) (0x00090000 + ((_VSI) * 4)) /* _i=0...383 */ +#define I40E_VSIGEN_RSTAT_VMRD_MASK I40E_MASK(0x1, I40E_VSIGEN_RSTAT_VMRD_SHIFT) +#define I40E_VSIGEN_RTRIG(_VSI) (0x00090000 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_VSIGEN_RTRIG_MAX_INDEX 383 #define I40E_VSIGEN_RTRIG_VMSWR_SHIFT 0 -#define I40E_VSIGEN_RTRIG_VMSWR_MASK (0x1 << I40E_VSIGEN_RTRIG_VMSWR_SHIFT) -#define I40E_GLHMC_APBVTINUSEBASE(_i) (0x000C4a00 + ((_i) * 4)) -#define I40E_GLHMC_APBVTINUSEBASE_MAX_INDEX 15 -#define I40E_GLHMC_APBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT 0 -#define I40E_GLHMC_APBVTINUSEBASE_FPMAPBINUSEBASE_MASK (0xFFFFFF << I40E_GLHMC_APBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT) -#define I40E_GLHMC_CEQPART(_i) (0x001312C0 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_CEQPART_MAX_INDEX 15 -#define I40E_GLHMC_CEQPART_PMCEQBASE_SHIFT 0 -#define I40E_GLHMC_CEQPART_PMCEQBASE_MASK (0xFF << I40E_GLHMC_CEQPART_PMCEQBASE_SHIFT) -#define I40E_GLHMC_CEQPART_PMCEQSIZE_SHIFT 16 -#define I40E_GLHMC_CEQPART_PMCEQSIZE_MASK (0x1FF << I40E_GLHMC_CEQPART_PMCEQSIZE_SHIFT) -#define I40E_GLHMC_DBCQPART(_i) (0x00131240 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_DBCQPART_MAX_INDEX 15 -#define I40E_GLHMC_DBCQPART_PMDBCQBASE_SHIFT 0 -#define I40E_GLHMC_DBCQPART_PMDBCQBASE_MASK (0x3FFF << I40E_GLHMC_DBCQPART_PMDBCQBASE_SHIFT) -#define I40E_GLHMC_DBCQPART_PMDBCQSIZE_SHIFT 16 -#define I40E_GLHMC_DBCQPART_PMDBCQSIZE_MASK (0x7FFF << I40E_GLHMC_DBCQPART_PMDBCQSIZE_SHIFT) -#define I40E_GLHMC_DBQPPART(_i) (0x00138D80 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_DBQPPART_MAX_INDEX 15 -#define I40E_GLHMC_DBQPPART_PMDBQPBASE_SHIFT 0 -#define I40E_GLHMC_DBQPPART_PMDBQPBASE_MASK (0x3FFF << I40E_GLHMC_DBQPPART_PMDBQPBASE_SHIFT) -#define I40E_GLHMC_DBQPPART_PMDBQPSIZE_SHIFT 16 -#define I40E_GLHMC_DBQPPART_PMDBQPSIZE_MASK (0x7FFF << I40E_GLHMC_DBQPPART_PMDBQPSIZE_SHIFT) -#define I40E_GLHMC_FCOEDDPBASE(_i) (0x000C6600 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_VSIGEN_RTRIG_VMSWR_MASK I40E_MASK(0x1, I40E_VSIGEN_RTRIG_VMSWR_SHIFT) +#define I40E_GLHMC_FCOEDDPBASE(_i) (0x000C6600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FCOEDDPBASE_MAX_INDEX 15 #define I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_SHIFT 0 -#define I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_MASK (0xFFFFFF << I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_SHIFT) -#define I40E_GLHMC_FCOEDDPCNT(_i) (0x000C6700 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_SHIFT) +#define I40E_GLHMC_FCOEDDPCNT(_i) (0x000C6700 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FCOEDDPCNT_MAX_INDEX 15 #define I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_SHIFT 0 -#define I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_MASK (0xFFFFF << I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_SHIFT) -#define I40E_GLHMC_FCOEDDPOBJSZ 0x000C2010 +#define I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_MASK I40E_MASK(0xFFFFF, I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_SHIFT) +#define I40E_GLHMC_FCOEDDPOBJSZ 0x000C2010 /* Reset: CORER */ #define I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_SHIFT 0 -#define I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_MASK (0xF << I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_SHIFT) -#define I40E_GLHMC_FCOEFBASE(_i) (0x000C6800 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_SHIFT) +#define I40E_GLHMC_FCOEFBASE(_i) (0x000C6800 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FCOEFBASE_MAX_INDEX 15 #define I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_SHIFT 0 -#define I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_MASK (0xFFFFFF << I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_SHIFT) -#define I40E_GLHMC_FCOEFCNT(_i) (0x000C6900 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_SHIFT) +#define I40E_GLHMC_FCOEFCNT(_i) (0x000C6900 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FCOEFCNT_MAX_INDEX 15 #define I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_SHIFT 0 -#define I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_MASK (0x7FFFFF << I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_SHIFT) -#define I40E_GLHMC_FCOEFMAX 0x000C20D0 +#define I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_MASK I40E_MASK(0x7FFFFF, I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_SHIFT) +#define I40E_GLHMC_FCOEFMAX 0x000C20D0 /* Reset: CORER */ #define I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT 0 -#define I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_MASK (0xFFFF << I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT) -#define I40E_GLHMC_FCOEFOBJSZ 0x000C2018 +#define I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_MASK I40E_MASK(0xFFFF, I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT) +#define I40E_GLHMC_FCOEFOBJSZ 0x000C2018 /* Reset: CORER */ #define I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_SHIFT 0 -#define I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_MASK (0xF << I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_SHIFT) -#define I40E_GLHMC_FCOEMAX 0x000C2014 +#define I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_SHIFT) +#define I40E_GLHMC_FCOEMAX 0x000C2014 /* Reset: CORER */ #define I40E_GLHMC_FCOEMAX_PMFCOEMAX_SHIFT 0 -#define I40E_GLHMC_FCOEMAX_PMFCOEMAX_MASK (0x1FFF << I40E_GLHMC_FCOEMAX_PMFCOEMAX_SHIFT) -#define I40E_GLHMC_FSIAVBASE(_i) (0x000C5600 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FCOEMAX_PMFCOEMAX_MASK I40E_MASK(0x1FFF, I40E_GLHMC_FCOEMAX_PMFCOEMAX_SHIFT) +#define I40E_GLHMC_FSIAVBASE(_i) (0x000C5600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FSIAVBASE_MAX_INDEX 15 #define I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_SHIFT 0 -#define I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_MASK (0xFFFFFF << I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_SHIFT) -#define I40E_GLHMC_FSIAVCNT(_i) (0x000C5700 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_SHIFT) +#define I40E_GLHMC_FSIAVCNT(_i) (0x000C5700 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FSIAVCNT_MAX_INDEX 15 #define I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_SHIFT 0 -#define I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_MASK (0x1FFFFFFF << I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_SHIFT) +#define I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_SHIFT) #define I40E_GLHMC_FSIAVCNT_RSVD_SHIFT 29 -#define I40E_GLHMC_FSIAVCNT_RSVD_MASK (0x7 << I40E_GLHMC_FSIAVCNT_RSVD_SHIFT) -#define I40E_GLHMC_FSIAVMAX 0x000C2068 +#define I40E_GLHMC_FSIAVCNT_RSVD_MASK I40E_MASK(0x7, I40E_GLHMC_FSIAVCNT_RSVD_SHIFT) +#define I40E_GLHMC_FSIAVMAX 0x000C2068 /* Reset: CORER */ #define I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_SHIFT 0 -#define I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_MASK (0x1FFFF << I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_SHIFT) -#define I40E_GLHMC_FSIAVOBJSZ 0x000C2064 +#define I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_MASK I40E_MASK(0x1FFFF, I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_SHIFT) +#define I40E_GLHMC_FSIAVOBJSZ 0x000C2064 /* Reset: CORER */ #define I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_SHIFT 0 -#define I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_MASK (0xF << I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_SHIFT) -#define I40E_GLHMC_FSIMCBASE(_i) (0x000C6000 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_SHIFT) +#define I40E_GLHMC_FSIMCBASE(_i) (0x000C6000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FSIMCBASE_MAX_INDEX 15 #define I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_SHIFT 0 -#define I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_MASK (0xFFFFFF << I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_SHIFT) -#define I40E_GLHMC_FSIMCCNT(_i) (0x000C6100 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_SHIFT) +#define I40E_GLHMC_FSIMCCNT(_i) (0x000C6100 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_FSIMCCNT_MAX_INDEX 15 #define I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_SHIFT 0 -#define I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_MASK (0x1FFFFFFF << I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_SHIFT) -#define I40E_GLHMC_FSIMCMAX 0x000C2060 +#define I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_SHIFT) +#define I40E_GLHMC_FSIMCMAX 0x000C2060 /* Reset: CORER */ #define I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_SHIFT 0 -#define I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_MASK (0x3FFF << I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_SHIFT) -#define I40E_GLHMC_FSIMCOBJSZ 0x000C205c +#define I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_MASK I40E_MASK(0x3FFF, I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_SHIFT) +#define I40E_GLHMC_FSIMCOBJSZ 0x000C205c /* Reset: CORER */ #define I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_SHIFT 0 -#define I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_MASK (0xF << I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_SHIFT) -#define I40E_GLHMC_LANQMAX 0x000C2008 +#define I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_SHIFT) +#define I40E_GLHMC_LANQMAX 0x000C2008 /* Reset: CORER */ #define I40E_GLHMC_LANQMAX_PMLANQMAX_SHIFT 0 -#define I40E_GLHMC_LANQMAX_PMLANQMAX_MASK (0x7FF << I40E_GLHMC_LANQMAX_PMLANQMAX_SHIFT) -#define I40E_GLHMC_LANRXBASE(_i) (0x000C6400 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_LANQMAX_PMLANQMAX_MASK I40E_MASK(0x7FF, I40E_GLHMC_LANQMAX_PMLANQMAX_SHIFT) +#define I40E_GLHMC_LANRXBASE(_i) (0x000C6400 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_LANRXBASE_MAX_INDEX 15 #define I40E_GLHMC_LANRXBASE_FPMLANRXBASE_SHIFT 0 -#define I40E_GLHMC_LANRXBASE_FPMLANRXBASE_MASK (0xFFFFFF << I40E_GLHMC_LANRXBASE_FPMLANRXBASE_SHIFT) -#define I40E_GLHMC_LANRXCNT(_i) (0x000C6500 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_LANRXBASE_FPMLANRXBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_LANRXBASE_FPMLANRXBASE_SHIFT) +#define I40E_GLHMC_LANRXCNT(_i) (0x000C6500 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_LANRXCNT_MAX_INDEX 15 #define I40E_GLHMC_LANRXCNT_FPMLANRXCNT_SHIFT 0 -#define I40E_GLHMC_LANRXCNT_FPMLANRXCNT_MASK (0x7FF << I40E_GLHMC_LANRXCNT_FPMLANRXCNT_SHIFT) -#define I40E_GLHMC_LANRXOBJSZ 0x000C200c +#define I40E_GLHMC_LANRXCNT_FPMLANRXCNT_MASK I40E_MASK(0x7FF, I40E_GLHMC_LANRXCNT_FPMLANRXCNT_SHIFT) +#define I40E_GLHMC_LANRXOBJSZ 0x000C200c /* Reset: CORER */ #define I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_SHIFT 0 -#define I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_MASK (0xF << I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_SHIFT) -#define I40E_GLHMC_LANTXBASE(_i) (0x000C6200 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_SHIFT) +#define I40E_GLHMC_LANTXBASE(_i) (0x000C6200 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_LANTXBASE_MAX_INDEX 15 #define I40E_GLHMC_LANTXBASE_FPMLANTXBASE_SHIFT 0 -#define I40E_GLHMC_LANTXBASE_FPMLANTXBASE_MASK (0xFFFFFF << I40E_GLHMC_LANTXBASE_FPMLANTXBASE_SHIFT) +#define I40E_GLHMC_LANTXBASE_FPMLANTXBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_LANTXBASE_FPMLANTXBASE_SHIFT) #define I40E_GLHMC_LANTXBASE_RSVD_SHIFT 24 -#define I40E_GLHMC_LANTXBASE_RSVD_MASK (0xFF << I40E_GLHMC_LANTXBASE_RSVD_SHIFT) -#define I40E_GLHMC_LANTXCNT(_i) (0x000C6300 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_LANTXBASE_RSVD_MASK I40E_MASK(0xFF, I40E_GLHMC_LANTXBASE_RSVD_SHIFT) +#define I40E_GLHMC_LANTXCNT(_i) (0x000C6300 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_LANTXCNT_MAX_INDEX 15 #define I40E_GLHMC_LANTXCNT_FPMLANTXCNT_SHIFT 0 -#define I40E_GLHMC_LANTXCNT_FPMLANTXCNT_MASK (0x7FF << I40E_GLHMC_LANTXCNT_FPMLANTXCNT_SHIFT) -#define I40E_GLHMC_LANTXOBJSZ 0x000C2004 +#define I40E_GLHMC_LANTXCNT_FPMLANTXCNT_MASK I40E_MASK(0x7FF, I40E_GLHMC_LANTXCNT_FPMLANTXCNT_SHIFT) +#define I40E_GLHMC_LANTXOBJSZ 0x000C2004 /* Reset: CORER */ #define I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_SHIFT 0 -#define I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_MASK (0xF << I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_SHIFT) -#define I40E_GLHMC_PEARPBASE(_i) (0x000C4800 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEARPBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEARPBASE_FPMPEARPBASE_SHIFT 0 -#define I40E_GLHMC_PEARPBASE_FPMPEARPBASE_MASK (0xFFFFFF << I40E_GLHMC_PEARPBASE_FPMPEARPBASE_SHIFT) -#define I40E_GLHMC_PEARPCNT(_i) (0x000C4900 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEARPCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEARPCNT_FPMPEARPCNT_SHIFT 0 -#define I40E_GLHMC_PEARPCNT_FPMPEARPCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEARPCNT_FPMPEARPCNT_SHIFT) -#define I40E_GLHMC_PEARPMAX 0x000C2038 -#define I40E_GLHMC_PEARPMAX_PMPEARPMAX_SHIFT 0 -#define I40E_GLHMC_PEARPMAX_PMPEARPMAX_MASK (0x1FFFF << I40E_GLHMC_PEARPMAX_PMPEARPMAX_SHIFT) -#define I40E_GLHMC_PEARPOBJSZ 0x000C2034 -#define I40E_GLHMC_PEARPOBJSZ_PMPEARPOBJSZ_SHIFT 0 -#define I40E_GLHMC_PEARPOBJSZ_PMPEARPOBJSZ_MASK (0x7 << I40E_GLHMC_PEARPOBJSZ_PMPEARPOBJSZ_SHIFT) -#define I40E_GLHMC_PECQBASE(_i) (0x000C4200 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PECQBASE_MAX_INDEX 15 -#define I40E_GLHMC_PECQBASE_FPMPECQBASE_SHIFT 0 -#define I40E_GLHMC_PECQBASE_FPMPECQBASE_MASK (0xFFFFFF << I40E_GLHMC_PECQBASE_FPMPECQBASE_SHIFT) -#define I40E_GLHMC_PECQCNT(_i) (0x000C4300 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PECQCNT_MAX_INDEX 15 -#define I40E_GLHMC_PECQCNT_FPMPECQCNT_SHIFT 0 -#define I40E_GLHMC_PECQCNT_FPMPECQCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PECQCNT_FPMPECQCNT_SHIFT) -#define I40E_GLHMC_PECQOBJSZ 0x000C2020 -#define I40E_GLHMC_PECQOBJSZ_PMPECQOBJSZ_SHIFT 0 -#define I40E_GLHMC_PECQOBJSZ_PMPECQOBJSZ_MASK (0xF << I40E_GLHMC_PECQOBJSZ_PMPECQOBJSZ_SHIFT) -#define I40E_GLHMC_PEHTCNT(_i) (0x000C4700 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEHTCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEHTCNT_FPMPEHTCNT_SHIFT 0 -#define I40E_GLHMC_PEHTCNT_FPMPEHTCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEHTCNT_FPMPEHTCNT_SHIFT) -#define I40E_GLHMC_PEHTEBASE(_i) (0x000C4600 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEHTEBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEHTEBASE_FPMPEHTEBASE_SHIFT 0 -#define I40E_GLHMC_PEHTEBASE_FPMPEHTEBASE_MASK (0xFFFFFF << I40E_GLHMC_PEHTEBASE_FPMPEHTEBASE_SHIFT) -#define I40E_GLHMC_PEHTEOBJSZ 0x000C202c -#define I40E_GLHMC_PEHTEOBJSZ_PMPEHTEOBJSZ_SHIFT 0 -#define I40E_GLHMC_PEHTEOBJSZ_PMPEHTEOBJSZ_MASK (0xF << I40E_GLHMC_PEHTEOBJSZ_PMPEHTEOBJSZ_SHIFT) -#define I40E_GLHMC_PEHTMAX 0x000C2030 -#define I40E_GLHMC_PEHTMAX_PMPEHTMAX_SHIFT 0 -#define I40E_GLHMC_PEHTMAX_PMPEHTMAX_MASK (0x1FFFFF << I40E_GLHMC_PEHTMAX_PMPEHTMAX_SHIFT) -#define I40E_GLHMC_PEMRBASE(_i) (0x000C4c00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEMRBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEMRBASE_FPMPEMRBASE_SHIFT 0 -#define I40E_GLHMC_PEMRBASE_FPMPEMRBASE_MASK (0xFFFFFF << I40E_GLHMC_PEMRBASE_FPMPEMRBASE_SHIFT) -#define I40E_GLHMC_PEMRCNT(_i) (0x000C4d00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEMRCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEMRCNT_FPMPEMRSZ_SHIFT 0 -#define I40E_GLHMC_PEMRCNT_FPMPEMRSZ_MASK (0x1FFFFFFF << I40E_GLHMC_PEMRCNT_FPMPEMRSZ_SHIFT) -#define I40E_GLHMC_PEMRMAX 0x000C2040 -#define I40E_GLHMC_PEMRMAX_PMPEMRMAX_SHIFT 0 -#define I40E_GLHMC_PEMRMAX_PMPEMRMAX_MASK (0x7FFFFF << I40E_GLHMC_PEMRMAX_PMPEMRMAX_SHIFT) -#define I40E_GLHMC_PEMROBJSZ 0x000C203c -#define I40E_GLHMC_PEMROBJSZ_PMPEMROBJSZ_SHIFT 0 -#define I40E_GLHMC_PEMROBJSZ_PMPEMROBJSZ_MASK (0xF << I40E_GLHMC_PEMROBJSZ_PMPEMROBJSZ_SHIFT) -#define I40E_GLHMC_PEPBLBASE(_i) (0x000C5800 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEPBLBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEPBLBASE_FPMPEPBLBASE_SHIFT 0 -#define I40E_GLHMC_PEPBLBASE_FPMPEPBLBASE_MASK (0xFFFFFF << I40E_GLHMC_PEPBLBASE_FPMPEPBLBASE_SHIFT) -#define I40E_GLHMC_PEPBLCNT(_i) (0x000C5900 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEPBLCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEPBLCNT_FPMPEPBLCNT_SHIFT 0 -#define I40E_GLHMC_PEPBLCNT_FPMPEPBLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEPBLCNT_FPMPEPBLCNT_SHIFT) -#define I40E_GLHMC_PEPBLMAX 0x000C206c -#define I40E_GLHMC_PEPBLMAX_PMPEPBLMAX_SHIFT 0 -#define I40E_GLHMC_PEPBLMAX_PMPEPBLMAX_MASK (0x1FFFFFFF << I40E_GLHMC_PEPBLMAX_PMPEPBLMAX_SHIFT) -#define I40E_GLHMC_PEQ1BASE(_i) (0x000C5200 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEQ1BASE_MAX_INDEX 15 -#define I40E_GLHMC_PEQ1BASE_FPMPEQ1BASE_SHIFT 0 -#define I40E_GLHMC_PEQ1BASE_FPMPEQ1BASE_MASK (0xFFFFFF << I40E_GLHMC_PEQ1BASE_FPMPEQ1BASE_SHIFT) -#define I40E_GLHMC_PEQ1CNT(_i) (0x000C5300 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEQ1CNT_MAX_INDEX 15 -#define I40E_GLHMC_PEQ1CNT_FPMPEQ1CNT_SHIFT 0 -#define I40E_GLHMC_PEQ1CNT_FPMPEQ1CNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEQ1CNT_FPMPEQ1CNT_SHIFT) -#define I40E_GLHMC_PEQ1FLBASE(_i) (0x000C5400 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEQ1FLBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEQ1FLBASE_FPMPEQ1FLBASE_SHIFT 0 -#define I40E_GLHMC_PEQ1FLBASE_FPMPEQ1FLBASE_MASK (0xFFFFFF << I40E_GLHMC_PEQ1FLBASE_FPMPEQ1FLBASE_SHIFT) -#define I40E_GLHMC_PEQ1FLCNT(_i) (0x000C5500 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEQ1FLCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEQ1FLCNT_FPMPEQ1FLCNT_SHIFT 0 -#define I40E_GLHMC_PEQ1FLCNT_FPMPEQ1FLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEQ1FLCNT_FPMPEQ1FLCNT_SHIFT) -#define I40E_GLHMC_PEQ1FLMAX 0x000C2058 -#define I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_SHIFT 0 -#define I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_MASK (0x3FFFFFF << I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_SHIFT) -#define I40E_GLHMC_PEQ1MAX 0x000C2054 -#define I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_SHIFT 0 -#define I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_MASK (0x3FFFFFF << I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_SHIFT) -#define I40E_GLHMC_PEQ1OBJSZ 0x000C2050 -#define I40E_GLHMC_PEQ1OBJSZ_PMPEQ1OBJSZ_SHIFT 0 -#define I40E_GLHMC_PEQ1OBJSZ_PMPEQ1OBJSZ_MASK (0xF << I40E_GLHMC_PEQ1OBJSZ_PMPEQ1OBJSZ_SHIFT) -#define I40E_GLHMC_PEQPBASE(_i) (0x000C4000 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEQPBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEQPBASE_FPMPEQPBASE_SHIFT 0 -#define I40E_GLHMC_PEQPBASE_FPMPEQPBASE_MASK (0xFFFFFF << I40E_GLHMC_PEQPBASE_FPMPEQPBASE_SHIFT) -#define I40E_GLHMC_PEQPCNT(_i) (0x000C4100 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEQPCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEQPCNT_FPMPEQPCNT_SHIFT 0 -#define I40E_GLHMC_PEQPCNT_FPMPEQPCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEQPCNT_FPMPEQPCNT_SHIFT) -#define I40E_GLHMC_PEQPOBJSZ 0x000C201c -#define I40E_GLHMC_PEQPOBJSZ_PMPEQPOBJSZ_SHIFT 0 -#define I40E_GLHMC_PEQPOBJSZ_PMPEQPOBJSZ_MASK (0xF << I40E_GLHMC_PEQPOBJSZ_PMPEQPOBJSZ_SHIFT) -#define I40E_GLHMC_PESRQBASE(_i) (0x000C4400 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PESRQBASE_MAX_INDEX 15 -#define I40E_GLHMC_PESRQBASE_FPMPESRQBASE_SHIFT 0 -#define I40E_GLHMC_PESRQBASE_FPMPESRQBASE_MASK (0xFFFFFF << I40E_GLHMC_PESRQBASE_FPMPESRQBASE_SHIFT) -#define I40E_GLHMC_PESRQCNT(_i) (0x000C4500 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PESRQCNT_MAX_INDEX 15 -#define I40E_GLHMC_PESRQCNT_FPMPESRQCNT_SHIFT 0 -#define I40E_GLHMC_PESRQCNT_FPMPESRQCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PESRQCNT_FPMPESRQCNT_SHIFT) -#define I40E_GLHMC_PESRQMAX 0x000C2028 -#define I40E_GLHMC_PESRQMAX_PMPESRQMAX_SHIFT 0 -#define I40E_GLHMC_PESRQMAX_PMPESRQMAX_MASK (0xFFFF << I40E_GLHMC_PESRQMAX_PMPESRQMAX_SHIFT) -#define I40E_GLHMC_PESRQOBJSZ 0x000C2024 -#define I40E_GLHMC_PESRQOBJSZ_PMPESRQOBJSZ_SHIFT 0 -#define I40E_GLHMC_PESRQOBJSZ_PMPESRQOBJSZ_MASK (0xF << I40E_GLHMC_PESRQOBJSZ_PMPESRQOBJSZ_SHIFT) -#define I40E_GLHMC_PESRQOBJSZ_RSVD_SHIFT 4 -#define I40E_GLHMC_PESRQOBJSZ_RSVD_MASK (0xFFFFFFF << I40E_GLHMC_PESRQOBJSZ_RSVD_SHIFT) -#define I40E_GLHMC_PETIMERBASE(_i) (0x000C5A00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PETIMERBASE_MAX_INDEX 15 -#define I40E_GLHMC_PETIMERBASE_FPMPETIMERBASE_SHIFT 0 -#define I40E_GLHMC_PETIMERBASE_FPMPETIMERBASE_MASK (0xFFFFFF << I40E_GLHMC_PETIMERBASE_FPMPETIMERBASE_SHIFT) -#define I40E_GLHMC_PETIMERCNT(_i) (0x000C5B00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PETIMERCNT_MAX_INDEX 15 -#define I40E_GLHMC_PETIMERCNT_FPMPETIMERCNT_SHIFT 0 -#define I40E_GLHMC_PETIMERCNT_FPMPETIMERCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PETIMERCNT_FPMPETIMERCNT_SHIFT) -#define I40E_GLHMC_PETIMERMAX 0x000C2084 -#define I40E_GLHMC_PETIMERMAX_PMPETIMERMAX_SHIFT 0 -#define I40E_GLHMC_PETIMERMAX_PMPETIMERMAX_MASK (0x1FFFFFFF << I40E_GLHMC_PETIMERMAX_PMPETIMERMAX_SHIFT) -#define I40E_GLHMC_PETIMEROBJSZ 0x000C2080 -#define I40E_GLHMC_PETIMEROBJSZ_PMPETIMEROBJSZ_SHIFT 0 -#define I40E_GLHMC_PETIMEROBJSZ_PMPETIMEROBJSZ_MASK (0xF << I40E_GLHMC_PETIMEROBJSZ_PMPETIMEROBJSZ_SHIFT) -#define I40E_GLHMC_PEXFBASE(_i) (0x000C4e00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEXFBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEXFBASE_FPMPEXFBASE_SHIFT 0 -#define I40E_GLHMC_PEXFBASE_FPMPEXFBASE_MASK (0xFFFFFF << I40E_GLHMC_PEXFBASE_FPMPEXFBASE_SHIFT) -#define I40E_GLHMC_PEXFCNT(_i) (0x000C4f00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEXFCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEXFCNT_FPMPEXFCNT_SHIFT 0 -#define I40E_GLHMC_PEXFCNT_FPMPEXFCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEXFCNT_FPMPEXFCNT_SHIFT) -#define I40E_GLHMC_PEXFFLBASE(_i) (0x000C5000 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEXFFLBASE_MAX_INDEX 15 -#define I40E_GLHMC_PEXFFLBASE_FPMPEXFFLBASE_SHIFT 0 -#define I40E_GLHMC_PEXFFLBASE_FPMPEXFFLBASE_MASK (0xFFFFFF << I40E_GLHMC_PEXFFLBASE_FPMPEXFFLBASE_SHIFT) -#define I40E_GLHMC_PEXFFLCNT(_i) (0x000C5100 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLHMC_PEXFFLCNT_MAX_INDEX 15 -#define I40E_GLHMC_PEXFFLCNT_FPMPEXFFLCNT_SHIFT 0 -#define I40E_GLHMC_PEXFFLCNT_FPMPEXFFLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEXFFLCNT_FPMPEXFFLCNT_SHIFT) -#define I40E_GLHMC_PEXFFLMAX 0x000C204c -#define I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_SHIFT 0 -#define I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_MASK (0x1FFFFFF << I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_SHIFT) -#define I40E_GLHMC_PEXFMAX 0x000C2048 -#define I40E_GLHMC_PEXFMAX_PMPEXFMAX_SHIFT 0 -#define I40E_GLHMC_PEXFMAX_PMPEXFMAX_MASK (0x3FFFFFF << I40E_GLHMC_PEXFMAX_PMPEXFMAX_SHIFT) -#define I40E_GLHMC_PEXFOBJSZ 0x000C2044 -#define I40E_GLHMC_PEXFOBJSZ_PMPEXFOBJSZ_SHIFT 0 -#define I40E_GLHMC_PEXFOBJSZ_PMPEXFOBJSZ_MASK (0xF << I40E_GLHMC_PEXFOBJSZ_PMPEXFOBJSZ_SHIFT) -#define I40E_GLHMC_PEXFOBJSZ_RSVD_SHIFT 4 -#define I40E_GLHMC_PEXFOBJSZ_RSVD_MASK (0xFFFFFFF << I40E_GLHMC_PEXFOBJSZ_RSVD_SHIFT) -#define I40E_GLHMC_PFASSIGN(_i) (0x000C0c00 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_SHIFT) +#define I40E_GLHMC_PFASSIGN(_i) (0x000C0c00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_PFASSIGN_MAX_INDEX 15 #define I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_SHIFT 0 -#define I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_MASK (0xF << I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_SHIFT) -#define I40E_GLHMC_SDPART(_i) (0x000C0800 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_MASK I40E_MASK(0xF, I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_SHIFT) +#define I40E_GLHMC_SDPART(_i) (0x000C0800 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLHMC_SDPART_MAX_INDEX 15 #define I40E_GLHMC_SDPART_PMSDBASE_SHIFT 0 -#define I40E_GLHMC_SDPART_PMSDBASE_MASK (0xFFF << I40E_GLHMC_SDPART_PMSDBASE_SHIFT) +#define I40E_GLHMC_SDPART_PMSDBASE_MASK I40E_MASK(0xFFF, I40E_GLHMC_SDPART_PMSDBASE_SHIFT) #define I40E_GLHMC_SDPART_PMSDSIZE_SHIFT 16 -#define I40E_GLHMC_SDPART_PMSDSIZE_MASK (0x1FFF << I40E_GLHMC_SDPART_PMSDSIZE_SHIFT) -#define I40E_GLHMC_VFAPBVTINUSEBASE(_i) (0x000Cca00 + ((_i) * 4)) -#define I40E_GLHMC_VFAPBVTINUSEBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFAPBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT 0 -#define I40E_GLHMC_VFAPBVTINUSEBASE_FPMAPBINUSEBASE_MASK (0xFFFFFF << I40E_GLHMC_VFAPBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT) -#define I40E_GLHMC_VFCEQPART(_i) (0x00132240 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFCEQPART_MAX_INDEX 31 -#define I40E_GLHMC_VFCEQPART_PMCEQBASE_SHIFT 0 -#define I40E_GLHMC_VFCEQPART_PMCEQBASE_MASK (0xFF << I40E_GLHMC_VFCEQPART_PMCEQBASE_SHIFT) -#define I40E_GLHMC_VFCEQPART_PMCEQSIZE_SHIFT 16 -#define I40E_GLHMC_VFCEQPART_PMCEQSIZE_MASK (0x1FF << I40E_GLHMC_VFCEQPART_PMCEQSIZE_SHIFT) -#define I40E_GLHMC_VFDBCQPART(_i) (0x00132140 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFDBCQPART_MAX_INDEX 31 -#define I40E_GLHMC_VFDBCQPART_PMDBCQBASE_SHIFT 0 -#define I40E_GLHMC_VFDBCQPART_PMDBCQBASE_MASK (0x3FFF << I40E_GLHMC_VFDBCQPART_PMDBCQBASE_SHIFT) -#define I40E_GLHMC_VFDBCQPART_PMDBCQSIZE_SHIFT 16 -#define I40E_GLHMC_VFDBCQPART_PMDBCQSIZE_MASK (0x7FFF << I40E_GLHMC_VFDBCQPART_PMDBCQSIZE_SHIFT) -#define I40E_GLHMC_VFDBQPPART(_i) (0x00138E00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFDBQPPART_MAX_INDEX 31 -#define I40E_GLHMC_VFDBQPPART_PMDBQPBASE_SHIFT 0 -#define I40E_GLHMC_VFDBQPPART_PMDBQPBASE_MASK (0x3FFF << I40E_GLHMC_VFDBQPPART_PMDBQPBASE_SHIFT) -#define I40E_GLHMC_VFDBQPPART_PMDBQPSIZE_SHIFT 16 -#define I40E_GLHMC_VFDBQPPART_PMDBQPSIZE_MASK (0x7FFF << I40E_GLHMC_VFDBQPPART_PMDBQPSIZE_SHIFT) -#define I40E_GLHMC_VFFSIAVBASE(_i) (0x000Cd600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFFSIAVBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFFSIAVBASE_FPMFSIAVBASE_SHIFT 0 -#define I40E_GLHMC_VFFSIAVBASE_FPMFSIAVBASE_MASK (0xFFFFFF << I40E_GLHMC_VFFSIAVBASE_FPMFSIAVBASE_SHIFT) -#define I40E_GLHMC_VFFSIAVCNT(_i) (0x000Cd700 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFFSIAVCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFFSIAVCNT_FPMFSIAVCNT_SHIFT 0 -#define I40E_GLHMC_VFFSIAVCNT_FPMFSIAVCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFFSIAVCNT_FPMFSIAVCNT_SHIFT) -#define I40E_GLHMC_VFFSIAVCNT_RSVD_SHIFT 29 -#define I40E_GLHMC_VFFSIAVCNT_RSVD_MASK (0x7 << I40E_GLHMC_VFFSIAVCNT_RSVD_SHIFT) -#define I40E_GLHMC_VFPDINV(_i) (0x000C8300 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPDINV_MAX_INDEX 31 -#define I40E_GLHMC_VFPDINV_PMSDIDX_SHIFT 0 -#define I40E_GLHMC_VFPDINV_PMSDIDX_MASK (0xFFF << I40E_GLHMC_VFPDINV_PMSDIDX_SHIFT) -#define I40E_GLHMC_VFPDINV_PMPDIDX_SHIFT 16 -#define I40E_GLHMC_VFPDINV_PMPDIDX_MASK (0x1FF << I40E_GLHMC_VFPDINV_PMPDIDX_SHIFT) -#define I40E_GLHMC_VFPEARPBASE(_i) (0x000Cc800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEARPBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEARPBASE_FPMPEARPBASE_SHIFT 0 -#define I40E_GLHMC_VFPEARPBASE_FPMPEARPBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEARPBASE_FPMPEARPBASE_SHIFT) -#define I40E_GLHMC_VFPEARPCNT(_i) (0x000Cc900 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEARPCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEARPCNT_FPMPEARPCNT_SHIFT 0 -#define I40E_GLHMC_VFPEARPCNT_FPMPEARPCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEARPCNT_FPMPEARPCNT_SHIFT) -#define I40E_GLHMC_VFPECQBASE(_i) (0x000Cc200 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPECQBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPECQBASE_FPMPECQBASE_SHIFT 0 -#define I40E_GLHMC_VFPECQBASE_FPMPECQBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPECQBASE_FPMPECQBASE_SHIFT) -#define I40E_GLHMC_VFPECQCNT(_i) (0x000Cc300 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPECQCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPECQCNT_FPMPECQCNT_SHIFT 0 -#define I40E_GLHMC_VFPECQCNT_FPMPECQCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPECQCNT_FPMPECQCNT_SHIFT) -#define I40E_GLHMC_VFPEHTCNT(_i) (0x000Cc700 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEHTCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEHTCNT_FPMPEHTCNT_SHIFT 0 -#define I40E_GLHMC_VFPEHTCNT_FPMPEHTCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEHTCNT_FPMPEHTCNT_SHIFT) -#define I40E_GLHMC_VFPEHTEBASE(_i) (0x000Cc600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEHTEBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEHTEBASE_FPMPEHTEBASE_SHIFT 0 -#define I40E_GLHMC_VFPEHTEBASE_FPMPEHTEBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEHTEBASE_FPMPEHTEBASE_SHIFT) -#define I40E_GLHMC_VFPEMRBASE(_i) (0x000Ccc00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEMRBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEMRBASE_FPMPEMRBASE_SHIFT 0 -#define I40E_GLHMC_VFPEMRBASE_FPMPEMRBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEMRBASE_FPMPEMRBASE_SHIFT) -#define I40E_GLHMC_VFPEMRCNT(_i) (0x000Ccd00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEMRCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEMRCNT_FPMPEMRSZ_SHIFT 0 -#define I40E_GLHMC_VFPEMRCNT_FPMPEMRSZ_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEMRCNT_FPMPEMRSZ_SHIFT) -#define I40E_GLHMC_VFPEPBLBASE(_i) (0x000Cd800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEPBLBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEPBLBASE_FPMPEPBLBASE_SHIFT 0 -#define I40E_GLHMC_VFPEPBLBASE_FPMPEPBLBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEPBLBASE_FPMPEPBLBASE_SHIFT) -#define I40E_GLHMC_VFPEPBLCNT(_i) (0x000Cd900 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEPBLCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEPBLCNT_FPMPEPBLCNT_SHIFT 0 -#define I40E_GLHMC_VFPEPBLCNT_FPMPEPBLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEPBLCNT_FPMPEPBLCNT_SHIFT) -#define I40E_GLHMC_VFPEQ1BASE(_i) (0x000Cd200 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEQ1BASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEQ1BASE_FPMPEQ1BASE_SHIFT 0 -#define I40E_GLHMC_VFPEQ1BASE_FPMPEQ1BASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEQ1BASE_FPMPEQ1BASE_SHIFT) -#define I40E_GLHMC_VFPEQ1CNT(_i) (0x000Cd300 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEQ1CNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEQ1CNT_FPMPEQ1CNT_SHIFT 0 -#define I40E_GLHMC_VFPEQ1CNT_FPMPEQ1CNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEQ1CNT_FPMPEQ1CNT_SHIFT) -#define I40E_GLHMC_VFPEQ1FLBASE(_i) (0x000Cd400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEQ1FLBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEQ1FLBASE_FPMPEQ1FLBASE_SHIFT 0 -#define I40E_GLHMC_VFPEQ1FLBASE_FPMPEQ1FLBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEQ1FLBASE_FPMPEQ1FLBASE_SHIFT) -#define I40E_GLHMC_VFPEQ1FLCNT(_i) (0x000Cd500 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEQ1FLCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEQ1FLCNT_FPMPEQ1FLCNT_SHIFT 0 -#define I40E_GLHMC_VFPEQ1FLCNT_FPMPEQ1FLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEQ1FLCNT_FPMPEQ1FLCNT_SHIFT) -#define I40E_GLHMC_VFPEQPBASE(_i) (0x000Cc000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEQPBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEQPBASE_FPMPEQPBASE_SHIFT 0 -#define I40E_GLHMC_VFPEQPBASE_FPMPEQPBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEQPBASE_FPMPEQPBASE_SHIFT) -#define I40E_GLHMC_VFPEQPCNT(_i) (0x000Cc100 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEQPCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEQPCNT_FPMPEQPCNT_SHIFT 0 -#define I40E_GLHMC_VFPEQPCNT_FPMPEQPCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEQPCNT_FPMPEQPCNT_SHIFT) -#define I40E_GLHMC_VFPESRQBASE(_i) (0x000Cc400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPESRQBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPESRQBASE_FPMPESRQBASE_SHIFT 0 -#define I40E_GLHMC_VFPESRQBASE_FPMPESRQBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPESRQBASE_FPMPESRQBASE_SHIFT) -#define I40E_GLHMC_VFPESRQCNT(_i) (0x000Cc500 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPESRQCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPESRQCNT_FPMPESRQCNT_SHIFT 0 -#define I40E_GLHMC_VFPESRQCNT_FPMPESRQCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPESRQCNT_FPMPESRQCNT_SHIFT) -#define I40E_GLHMC_VFPETIMERBASE(_i) (0x000CDA00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPETIMERBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPETIMERBASE_FPMPETIMERBASE_SHIFT 0 -#define I40E_GLHMC_VFPETIMERBASE_FPMPETIMERBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPETIMERBASE_FPMPETIMERBASE_SHIFT) -#define I40E_GLHMC_VFPETIMERCNT(_i) (0x000CDB00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPETIMERCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPETIMERCNT_FPMPETIMERCNT_SHIFT 0 -#define I40E_GLHMC_VFPETIMERCNT_FPMPETIMERCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPETIMERCNT_FPMPETIMERCNT_SHIFT) -#define I40E_GLHMC_VFPEXFBASE(_i) (0x000Cce00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEXFBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEXFBASE_FPMPEXFBASE_SHIFT 0 -#define I40E_GLHMC_VFPEXFBASE_FPMPEXFBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEXFBASE_FPMPEXFBASE_SHIFT) -#define I40E_GLHMC_VFPEXFCNT(_i) (0x000Ccf00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEXFCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEXFCNT_FPMPEXFCNT_SHIFT 0 -#define I40E_GLHMC_VFPEXFCNT_FPMPEXFCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEXFCNT_FPMPEXFCNT_SHIFT) -#define I40E_GLHMC_VFPEXFFLBASE(_i) (0x000Cd000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEXFFLBASE_MAX_INDEX 31 -#define I40E_GLHMC_VFPEXFFLBASE_FPMPEXFFLBASE_SHIFT 0 -#define I40E_GLHMC_VFPEXFFLBASE_FPMPEXFFLBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEXFFLBASE_FPMPEXFFLBASE_SHIFT) -#define I40E_GLHMC_VFPEXFFLCNT(_i) (0x000Cd100 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFPEXFFLCNT_MAX_INDEX 31 -#define I40E_GLHMC_VFPEXFFLCNT_FPMPEXFFLCNT_SHIFT 0 -#define I40E_GLHMC_VFPEXFFLCNT_FPMPEXFFLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEXFFLCNT_FPMPEXFFLCNT_SHIFT) -#define I40E_GLHMC_VFSDPART(_i) (0x000C8800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLHMC_VFSDPART_MAX_INDEX 31 -#define I40E_GLHMC_VFSDPART_PMSDBASE_SHIFT 0 -#define I40E_GLHMC_VFSDPART_PMSDBASE_MASK (0xFFF << I40E_GLHMC_VFSDPART_PMSDBASE_SHIFT) -#define I40E_GLHMC_VFSDPART_PMSDSIZE_SHIFT 16 -#define I40E_GLHMC_VFSDPART_PMSDSIZE_MASK (0x1FFF << I40E_GLHMC_VFSDPART_PMSDSIZE_SHIFT) -#define I40E_PFHMC_ERRORDATA 0x000C0500 +#define I40E_GLHMC_SDPART_PMSDSIZE_MASK I40E_MASK(0x1FFF, I40E_GLHMC_SDPART_PMSDSIZE_SHIFT) +#define I40E_PFHMC_ERRORDATA 0x000C0500 /* Reset: PFR */ #define I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_SHIFT 0 -#define I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_MASK (0x3FFFFFFF << I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_SHIFT) -#define I40E_PFHMC_ERRORINFO 0x000C0400 +#define I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_MASK I40E_MASK(0x3FFFFFFF, I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_SHIFT) +#define I40E_PFHMC_ERRORINFO 0x000C0400 /* Reset: PFR */ #define I40E_PFHMC_ERRORINFO_PMF_INDEX_SHIFT 0 -#define I40E_PFHMC_ERRORINFO_PMF_INDEX_MASK (0x1F << I40E_PFHMC_ERRORINFO_PMF_INDEX_SHIFT) +#define I40E_PFHMC_ERRORINFO_PMF_INDEX_MASK I40E_MASK(0x1F, I40E_PFHMC_ERRORINFO_PMF_INDEX_SHIFT) #define I40E_PFHMC_ERRORINFO_PMF_ISVF_SHIFT 7 -#define I40E_PFHMC_ERRORINFO_PMF_ISVF_MASK (0x1 << I40E_PFHMC_ERRORINFO_PMF_ISVF_SHIFT) +#define I40E_PFHMC_ERRORINFO_PMF_ISVF_MASK I40E_MASK(0x1, I40E_PFHMC_ERRORINFO_PMF_ISVF_SHIFT) #define I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_SHIFT 8 -#define I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_MASK (0xF << I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_SHIFT) +#define I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_MASK I40E_MASK(0xF, I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_SHIFT) #define I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_SHIFT 16 -#define I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_MASK (0x1F << I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_SHIFT) +#define I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_MASK I40E_MASK(0x1F, I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_SHIFT) #define I40E_PFHMC_ERRORINFO_ERROR_DETECTED_SHIFT 31 -#define I40E_PFHMC_ERRORINFO_ERROR_DETECTED_MASK (0x1 << I40E_PFHMC_ERRORINFO_ERROR_DETECTED_SHIFT) -#define I40E_PFHMC_PDINV 0x000C0300 +#define I40E_PFHMC_ERRORINFO_ERROR_DETECTED_MASK I40E_MASK(0x1, I40E_PFHMC_ERRORINFO_ERROR_DETECTED_SHIFT) +#define I40E_PFHMC_PDINV 0x000C0300 /* Reset: PFR */ #define I40E_PFHMC_PDINV_PMSDIDX_SHIFT 0 -#define I40E_PFHMC_PDINV_PMSDIDX_MASK (0xFFF << I40E_PFHMC_PDINV_PMSDIDX_SHIFT) +#define I40E_PFHMC_PDINV_PMSDIDX_MASK I40E_MASK(0xFFF, I40E_PFHMC_PDINV_PMSDIDX_SHIFT) #define I40E_PFHMC_PDINV_PMPDIDX_SHIFT 16 -#define I40E_PFHMC_PDINV_PMPDIDX_MASK (0x1FF << I40E_PFHMC_PDINV_PMPDIDX_SHIFT) -#define I40E_PFHMC_SDCMD 0x000C0000 +#define I40E_PFHMC_PDINV_PMPDIDX_MASK I40E_MASK(0x1FF, I40E_PFHMC_PDINV_PMPDIDX_SHIFT) +#define I40E_PFHMC_SDCMD 0x000C0000 /* Reset: PFR */ #define I40E_PFHMC_SDCMD_PMSDIDX_SHIFT 0 -#define I40E_PFHMC_SDCMD_PMSDIDX_MASK (0xFFF << I40E_PFHMC_SDCMD_PMSDIDX_SHIFT) +#define I40E_PFHMC_SDCMD_PMSDIDX_MASK I40E_MASK(0xFFF, I40E_PFHMC_SDCMD_PMSDIDX_SHIFT) #define I40E_PFHMC_SDCMD_PMSDWR_SHIFT 31 -#define I40E_PFHMC_SDCMD_PMSDWR_MASK (0x1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT) -#define I40E_PFHMC_SDDATAHIGH 0x000C0200 +#define I40E_PFHMC_SDCMD_PMSDWR_MASK I40E_MASK(0x1, I40E_PFHMC_SDCMD_PMSDWR_SHIFT) +#define I40E_PFHMC_SDDATAHIGH 0x000C0200 /* Reset: PFR */ #define I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_SHIFT 0 -#define I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_MASK (0xFFFFFFFF << I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_SHIFT) -#define I40E_PFHMC_SDDATALOW 0x000C0100 +#define I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_MASK I40E_MASK(0xFFFFFFFF, I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_SHIFT) +#define I40E_PFHMC_SDDATALOW 0x000C0100 /* Reset: PFR */ #define I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT 0 -#define I40E_PFHMC_SDDATALOW_PMSDVALID_MASK (0x1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT) +#define I40E_PFHMC_SDDATALOW_PMSDVALID_MASK I40E_MASK(0x1, I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT) #define I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT 1 -#define I40E_PFHMC_SDDATALOW_PMSDTYPE_MASK (0x1 << I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) +#define I40E_PFHMC_SDDATALOW_PMSDTYPE_MASK I40E_MASK(0x1, I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) #define I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT 2 -#define I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_MASK (0x3FF << I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) +#define I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_MASK I40E_MASK(0x3FF, I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) #define I40E_PFHMC_SDDATALOW_PMSDDATALOW_SHIFT 12 -#define I40E_PFHMC_SDDATALOW_PMSDDATALOW_MASK (0xFFFFF << I40E_PFHMC_SDDATALOW_PMSDDATALOW_SHIFT) -#define I40E_GL_UFUSE 0x00094008 +#define I40E_PFHMC_SDDATALOW_PMSDDATALOW_MASK I40E_MASK(0xFFFFF, I40E_PFHMC_SDDATALOW_PMSDDATALOW_SHIFT) +#define I40E_GL_GP_FUSE(_i) (0x0009400C + ((_i) * 4)) /* _i=0...28 */ /* Reset: POR */ +#define I40E_GL_GP_FUSE_MAX_INDEX 28 +#define I40E_GL_GP_FUSE_GL_GP_FUSE_SHIFT 0 +#define I40E_GL_GP_FUSE_GL_GP_FUSE_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_GP_FUSE_GL_GP_FUSE_SHIFT) +#define I40E_GL_UFUSE 0x00094008 /* Reset: POR */ #define I40E_GL_UFUSE_FOUR_PORT_ENABLE_SHIFT 1 -#define I40E_GL_UFUSE_FOUR_PORT_ENABLE_MASK (0x1 << I40E_GL_UFUSE_FOUR_PORT_ENABLE_SHIFT) +#define I40E_GL_UFUSE_FOUR_PORT_ENABLE_MASK I40E_MASK(0x1, I40E_GL_UFUSE_FOUR_PORT_ENABLE_SHIFT) #define I40E_GL_UFUSE_NIC_ID_SHIFT 2 -#define I40E_GL_UFUSE_NIC_ID_MASK (0x1 << I40E_GL_UFUSE_NIC_ID_SHIFT) +#define I40E_GL_UFUSE_NIC_ID_MASK I40E_MASK(0x1, I40E_GL_UFUSE_NIC_ID_SHIFT) #define I40E_GL_UFUSE_ULT_LOCKOUT_SHIFT 10 -#define I40E_GL_UFUSE_ULT_LOCKOUT_MASK (0x1 << I40E_GL_UFUSE_ULT_LOCKOUT_SHIFT) +#define I40E_GL_UFUSE_ULT_LOCKOUT_MASK I40E_MASK(0x1, I40E_GL_UFUSE_ULT_LOCKOUT_SHIFT) #define I40E_GL_UFUSE_CLS_LOCKOUT_SHIFT 11 -#define I40E_GL_UFUSE_CLS_LOCKOUT_MASK (0x1 << I40E_GL_UFUSE_CLS_LOCKOUT_SHIFT) -#define I40E_EMPINT_GPIO_ENA 0x00088188 +#define I40E_GL_UFUSE_CLS_LOCKOUT_MASK I40E_MASK(0x1, I40E_GL_UFUSE_CLS_LOCKOUT_SHIFT) +#define I40E_EMPINT_GPIO_ENA 0x00088188 /* Reset: POR */ #define I40E_EMPINT_GPIO_ENA_GPIO0_ENA_SHIFT 0 -#define I40E_EMPINT_GPIO_ENA_GPIO0_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO0_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO0_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO0_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO1_ENA_SHIFT 1 -#define I40E_EMPINT_GPIO_ENA_GPIO1_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO1_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO1_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO1_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO2_ENA_SHIFT 2 -#define I40E_EMPINT_GPIO_ENA_GPIO2_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO2_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO2_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO2_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO3_ENA_SHIFT 3 -#define I40E_EMPINT_GPIO_ENA_GPIO3_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO3_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO3_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO3_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO4_ENA_SHIFT 4 -#define I40E_EMPINT_GPIO_ENA_GPIO4_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO4_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO4_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO4_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO5_ENA_SHIFT 5 -#define I40E_EMPINT_GPIO_ENA_GPIO5_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO5_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO5_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO5_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO6_ENA_SHIFT 6 -#define I40E_EMPINT_GPIO_ENA_GPIO6_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO6_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO6_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO6_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO7_ENA_SHIFT 7 -#define I40E_EMPINT_GPIO_ENA_GPIO7_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO7_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO7_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO7_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO8_ENA_SHIFT 8 -#define I40E_EMPINT_GPIO_ENA_GPIO8_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO8_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO8_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO8_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO9_ENA_SHIFT 9 -#define I40E_EMPINT_GPIO_ENA_GPIO9_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO9_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO9_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO9_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO10_ENA_SHIFT 10 -#define I40E_EMPINT_GPIO_ENA_GPIO10_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO10_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO10_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO10_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO11_ENA_SHIFT 11 -#define I40E_EMPINT_GPIO_ENA_GPIO11_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO11_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO11_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO11_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO12_ENA_SHIFT 12 -#define I40E_EMPINT_GPIO_ENA_GPIO12_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO12_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO12_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO12_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO13_ENA_SHIFT 13 -#define I40E_EMPINT_GPIO_ENA_GPIO13_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO13_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO13_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO13_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO14_ENA_SHIFT 14 -#define I40E_EMPINT_GPIO_ENA_GPIO14_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO14_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO14_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO14_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO15_ENA_SHIFT 15 -#define I40E_EMPINT_GPIO_ENA_GPIO15_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO15_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO15_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO15_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO16_ENA_SHIFT 16 -#define I40E_EMPINT_GPIO_ENA_GPIO16_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO16_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO16_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO16_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO17_ENA_SHIFT 17 -#define I40E_EMPINT_GPIO_ENA_GPIO17_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO17_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO17_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO17_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO18_ENA_SHIFT 18 -#define I40E_EMPINT_GPIO_ENA_GPIO18_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO18_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO18_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO18_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO19_ENA_SHIFT 19 -#define I40E_EMPINT_GPIO_ENA_GPIO19_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO19_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO19_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO19_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO20_ENA_SHIFT 20 -#define I40E_EMPINT_GPIO_ENA_GPIO20_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO20_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO20_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO20_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO21_ENA_SHIFT 21 -#define I40E_EMPINT_GPIO_ENA_GPIO21_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO21_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO21_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO21_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO22_ENA_SHIFT 22 -#define I40E_EMPINT_GPIO_ENA_GPIO22_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO22_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO22_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO22_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO23_ENA_SHIFT 23 -#define I40E_EMPINT_GPIO_ENA_GPIO23_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO23_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO23_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO23_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO24_ENA_SHIFT 24 -#define I40E_EMPINT_GPIO_ENA_GPIO24_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO24_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO24_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO24_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO25_ENA_SHIFT 25 -#define I40E_EMPINT_GPIO_ENA_GPIO25_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO25_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO25_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO25_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO26_ENA_SHIFT 26 -#define I40E_EMPINT_GPIO_ENA_GPIO26_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO26_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO26_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO26_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO27_ENA_SHIFT 27 -#define I40E_EMPINT_GPIO_ENA_GPIO27_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO27_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO27_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO27_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO28_ENA_SHIFT 28 -#define I40E_EMPINT_GPIO_ENA_GPIO28_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO28_ENA_SHIFT) +#define I40E_EMPINT_GPIO_ENA_GPIO28_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO28_ENA_SHIFT) #define I40E_EMPINT_GPIO_ENA_GPIO29_ENA_SHIFT 29 -#define I40E_EMPINT_GPIO_ENA_GPIO29_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO29_ENA_SHIFT) -#define I40E_PFGEN_PORTMDIO_NUM 0x0003F100 +#define I40E_EMPINT_GPIO_ENA_GPIO29_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO29_ENA_SHIFT) +#define I40E_PFGEN_PORTMDIO_NUM 0x0003F100 /* Reset: CORER */ #define I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_SHIFT 0 -#define I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_MASK (0x3 << I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_SHIFT) +#define I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_MASK I40E_MASK(0x3, I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_SHIFT) #define I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_SHIFT 4 -#define I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK (0x1 << I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_SHIFT) -#define I40E_PFINT_AEQCTL 0x00038700 +#define I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK I40E_MASK(0x1, I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_SHIFT) +#define I40E_PFINT_AEQCTL 0x00038700 /* Reset: CORER */ #define I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT 0 -#define I40E_PFINT_AEQCTL_MSIX_INDX_MASK (0xFF << I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT) +#define I40E_PFINT_AEQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT) #define I40E_PFINT_AEQCTL_ITR_INDX_SHIFT 11 -#define I40E_PFINT_AEQCTL_ITR_INDX_MASK (0x3 << I40E_PFINT_AEQCTL_ITR_INDX_SHIFT) +#define I40E_PFINT_AEQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_AEQCTL_ITR_INDX_SHIFT) #define I40E_PFINT_AEQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_PFINT_AEQCTL_MSIX0_INDX_MASK (0x7 << I40E_PFINT_AEQCTL_MSIX0_INDX_SHIFT) +#define I40E_PFINT_AEQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_PFINT_AEQCTL_MSIX0_INDX_SHIFT) #define I40E_PFINT_AEQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_PFINT_AEQCTL_CAUSE_ENA_MASK (0x1 << I40E_PFINT_AEQCTL_CAUSE_ENA_SHIFT) +#define I40E_PFINT_AEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_PFINT_AEQCTL_CAUSE_ENA_SHIFT) #define I40E_PFINT_AEQCTL_INTEVENT_SHIFT 31 -#define I40E_PFINT_AEQCTL_INTEVENT_MASK (0x1 << I40E_PFINT_AEQCTL_INTEVENT_SHIFT) -#define I40E_PFINT_CEQCTL(_INTPF) (0x00036800 + ((_INTPF) * 4)) /* _i=0...511 */ +#define I40E_PFINT_AEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_PFINT_AEQCTL_INTEVENT_SHIFT) +#define I40E_PFINT_CEQCTL(_INTPF) (0x00036800 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: CORER */ #define I40E_PFINT_CEQCTL_MAX_INDEX 511 #define I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT 0 -#define I40E_PFINT_CEQCTL_MSIX_INDX_MASK (0xFF << I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT) +#define I40E_PFINT_CEQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT) #define I40E_PFINT_CEQCTL_ITR_INDX_SHIFT 11 -#define I40E_PFINT_CEQCTL_ITR_INDX_MASK (0x3 << I40E_PFINT_CEQCTL_ITR_INDX_SHIFT) +#define I40E_PFINT_CEQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_CEQCTL_ITR_INDX_SHIFT) #define I40E_PFINT_CEQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_PFINT_CEQCTL_MSIX0_INDX_MASK (0x7 << I40E_PFINT_CEQCTL_MSIX0_INDX_SHIFT) +#define I40E_PFINT_CEQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_PFINT_CEQCTL_MSIX0_INDX_SHIFT) #define I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT 16 -#define I40E_PFINT_CEQCTL_NEXTQ_INDX_MASK (0x7FF << I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT) +#define I40E_PFINT_CEQCTL_NEXTQ_INDX_MASK I40E_MASK(0x7FF, I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT) #define I40E_PFINT_CEQCTL_NEXTQ_TYPE_SHIFT 27 -#define I40E_PFINT_CEQCTL_NEXTQ_TYPE_MASK (0x3 << I40E_PFINT_CEQCTL_NEXTQ_TYPE_SHIFT) +#define I40E_PFINT_CEQCTL_NEXTQ_TYPE_MASK I40E_MASK(0x3, I40E_PFINT_CEQCTL_NEXTQ_TYPE_SHIFT) #define I40E_PFINT_CEQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_PFINT_CEQCTL_CAUSE_ENA_MASK (0x1 << I40E_PFINT_CEQCTL_CAUSE_ENA_SHIFT) +#define I40E_PFINT_CEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_PFINT_CEQCTL_CAUSE_ENA_SHIFT) #define I40E_PFINT_CEQCTL_INTEVENT_SHIFT 31 -#define I40E_PFINT_CEQCTL_INTEVENT_MASK (0x1 << I40E_PFINT_CEQCTL_INTEVENT_SHIFT) -#define I40E_PFINT_DYN_CTL0 0x00038480 +#define I40E_PFINT_CEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_PFINT_CEQCTL_INTEVENT_SHIFT) +#define I40E_PFINT_DYN_CTL0 0x00038480 /* Reset: PFR */ #define I40E_PFINT_DYN_CTL0_INTENA_SHIFT 0 -#define I40E_PFINT_DYN_CTL0_INTENA_MASK (0x1 << I40E_PFINT_DYN_CTL0_INTENA_SHIFT) +#define I40E_PFINT_DYN_CTL0_INTENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_INTENA_SHIFT) #define I40E_PFINT_DYN_CTL0_CLEARPBA_SHIFT 1 -#define I40E_PFINT_DYN_CTL0_CLEARPBA_MASK (0x1 << I40E_PFINT_DYN_CTL0_CLEARPBA_SHIFT) +#define I40E_PFINT_DYN_CTL0_CLEARPBA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_CLEARPBA_SHIFT) #define I40E_PFINT_DYN_CTL0_SWINT_TRIG_SHIFT 2 -#define I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK (0x1 << I40E_PFINT_DYN_CTL0_SWINT_TRIG_SHIFT) +#define I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_SWINT_TRIG_SHIFT) #define I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT 3 -#define I40E_PFINT_DYN_CTL0_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT) +#define I40E_PFINT_DYN_CTL0_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT) #define I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT 5 -#define I40E_PFINT_DYN_CTL0_INTERVAL_MASK (0xFFF << I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT) +#define I40E_PFINT_DYN_CTL0_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT) #define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK (0x1 << I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT) +#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT) #define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_SHIFT 25 -#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTL0_SW_ITR_INDX_SHIFT) +#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTL0_SW_ITR_INDX_SHIFT) #define I40E_PFINT_DYN_CTL0_INTENA_MSK_SHIFT 31 -#define I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK (0x1 << I40E_PFINT_DYN_CTL0_INTENA_MSK_SHIFT) -#define I40E_PFINT_DYN_CTLN(_INTPF) (0x00034800 + ((_INTPF) * 4)) /* _i=0...511 */ +#define I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_INTENA_MSK_SHIFT) +#define I40E_PFINT_DYN_CTLN(_INTPF) (0x00034800 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: PFR */ #define I40E_PFINT_DYN_CTLN_MAX_INDEX 511 #define I40E_PFINT_DYN_CTLN_INTENA_SHIFT 0 -#define I40E_PFINT_DYN_CTLN_INTENA_MASK (0x1 << I40E_PFINT_DYN_CTLN_INTENA_SHIFT) +#define I40E_PFINT_DYN_CTLN_INTENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_INTENA_SHIFT) #define I40E_PFINT_DYN_CTLN_CLEARPBA_SHIFT 1 -#define I40E_PFINT_DYN_CTLN_CLEARPBA_MASK (0x1 << I40E_PFINT_DYN_CTLN_CLEARPBA_SHIFT) +#define I40E_PFINT_DYN_CTLN_CLEARPBA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_CLEARPBA_SHIFT) #define I40E_PFINT_DYN_CTLN_SWINT_TRIG_SHIFT 2 -#define I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK (0x1 << I40E_PFINT_DYN_CTLN_SWINT_TRIG_SHIFT) +#define I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_SWINT_TRIG_SHIFT) #define I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT 3 -#define I40E_PFINT_DYN_CTLN_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) +#define I40E_PFINT_DYN_CTLN_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) #define I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT 5 -#define I40E_PFINT_DYN_CTLN_INTERVAL_MASK (0xFFF << I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT) +#define I40E_PFINT_DYN_CTLN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT) #define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK (0x1 << I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT) +#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT) #define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT 25 -#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT) +#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT) #define I40E_PFINT_DYN_CTLN_INTENA_MSK_SHIFT 31 -#define I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK (0x1 << I40E_PFINT_DYN_CTLN_INTENA_MSK_SHIFT) -#define I40E_PFINT_GPIO_ENA 0x00088080 +#define I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_INTENA_MSK_SHIFT) +#define I40E_PFINT_GPIO_ENA 0x00088080 /* Reset: CORER */ #define I40E_PFINT_GPIO_ENA_GPIO0_ENA_SHIFT 0 -#define I40E_PFINT_GPIO_ENA_GPIO0_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO0_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO0_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO0_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO1_ENA_SHIFT 1 -#define I40E_PFINT_GPIO_ENA_GPIO1_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO1_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO1_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO1_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO2_ENA_SHIFT 2 -#define I40E_PFINT_GPIO_ENA_GPIO2_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO2_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO2_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO2_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO3_ENA_SHIFT 3 -#define I40E_PFINT_GPIO_ENA_GPIO3_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO3_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO3_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO3_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO4_ENA_SHIFT 4 -#define I40E_PFINT_GPIO_ENA_GPIO4_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO4_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO4_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO4_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO5_ENA_SHIFT 5 -#define I40E_PFINT_GPIO_ENA_GPIO5_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO5_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO5_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO5_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO6_ENA_SHIFT 6 -#define I40E_PFINT_GPIO_ENA_GPIO6_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO6_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO6_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO6_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO7_ENA_SHIFT 7 -#define I40E_PFINT_GPIO_ENA_GPIO7_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO7_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO7_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO7_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO8_ENA_SHIFT 8 -#define I40E_PFINT_GPIO_ENA_GPIO8_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO8_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO8_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO8_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO9_ENA_SHIFT 9 -#define I40E_PFINT_GPIO_ENA_GPIO9_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO9_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO9_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO9_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO10_ENA_SHIFT 10 -#define I40E_PFINT_GPIO_ENA_GPIO10_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO10_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO10_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO10_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO11_ENA_SHIFT 11 -#define I40E_PFINT_GPIO_ENA_GPIO11_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO11_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO11_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO11_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO12_ENA_SHIFT 12 -#define I40E_PFINT_GPIO_ENA_GPIO12_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO12_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO12_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO12_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO13_ENA_SHIFT 13 -#define I40E_PFINT_GPIO_ENA_GPIO13_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO13_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO13_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO13_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO14_ENA_SHIFT 14 -#define I40E_PFINT_GPIO_ENA_GPIO14_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO14_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO14_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO14_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO15_ENA_SHIFT 15 -#define I40E_PFINT_GPIO_ENA_GPIO15_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO15_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO15_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO15_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO16_ENA_SHIFT 16 -#define I40E_PFINT_GPIO_ENA_GPIO16_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO16_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO16_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO16_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO17_ENA_SHIFT 17 -#define I40E_PFINT_GPIO_ENA_GPIO17_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO17_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO17_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO17_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO18_ENA_SHIFT 18 -#define I40E_PFINT_GPIO_ENA_GPIO18_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO18_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO18_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO18_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO19_ENA_SHIFT 19 -#define I40E_PFINT_GPIO_ENA_GPIO19_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO19_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO19_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO19_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO20_ENA_SHIFT 20 -#define I40E_PFINT_GPIO_ENA_GPIO20_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO20_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO20_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO20_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO21_ENA_SHIFT 21 -#define I40E_PFINT_GPIO_ENA_GPIO21_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO21_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO21_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO21_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO22_ENA_SHIFT 22 -#define I40E_PFINT_GPIO_ENA_GPIO22_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO22_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO22_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO22_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO23_ENA_SHIFT 23 -#define I40E_PFINT_GPIO_ENA_GPIO23_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO23_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO23_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO23_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO24_ENA_SHIFT 24 -#define I40E_PFINT_GPIO_ENA_GPIO24_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO24_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO24_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO24_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO25_ENA_SHIFT 25 -#define I40E_PFINT_GPIO_ENA_GPIO25_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO25_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO25_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO25_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO26_ENA_SHIFT 26 -#define I40E_PFINT_GPIO_ENA_GPIO26_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO26_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO26_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO26_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO27_ENA_SHIFT 27 -#define I40E_PFINT_GPIO_ENA_GPIO27_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO27_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO27_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO27_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO28_ENA_SHIFT 28 -#define I40E_PFINT_GPIO_ENA_GPIO28_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO28_ENA_SHIFT) +#define I40E_PFINT_GPIO_ENA_GPIO28_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO28_ENA_SHIFT) #define I40E_PFINT_GPIO_ENA_GPIO29_ENA_SHIFT 29 -#define I40E_PFINT_GPIO_ENA_GPIO29_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO29_ENA_SHIFT) -#define I40E_PFINT_ICR0 0x00038780 +#define I40E_PFINT_GPIO_ENA_GPIO29_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO29_ENA_SHIFT) +#define I40E_PFINT_ICR0 0x00038780 /* Reset: CORER */ #define I40E_PFINT_ICR0_INTEVENT_SHIFT 0 -#define I40E_PFINT_ICR0_INTEVENT_MASK (0x1 << I40E_PFINT_ICR0_INTEVENT_SHIFT) +#define I40E_PFINT_ICR0_INTEVENT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_INTEVENT_SHIFT) #define I40E_PFINT_ICR0_QUEUE_0_SHIFT 1 -#define I40E_PFINT_ICR0_QUEUE_0_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_0_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_0_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_0_SHIFT) #define I40E_PFINT_ICR0_QUEUE_1_SHIFT 2 -#define I40E_PFINT_ICR0_QUEUE_1_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_1_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_1_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_1_SHIFT) #define I40E_PFINT_ICR0_QUEUE_2_SHIFT 3 -#define I40E_PFINT_ICR0_QUEUE_2_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_2_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_2_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_2_SHIFT) #define I40E_PFINT_ICR0_QUEUE_3_SHIFT 4 -#define I40E_PFINT_ICR0_QUEUE_3_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_3_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_3_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_3_SHIFT) #define I40E_PFINT_ICR0_QUEUE_4_SHIFT 5 -#define I40E_PFINT_ICR0_QUEUE_4_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_4_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_4_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_4_SHIFT) #define I40E_PFINT_ICR0_QUEUE_5_SHIFT 6 -#define I40E_PFINT_ICR0_QUEUE_5_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_5_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_5_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_5_SHIFT) #define I40E_PFINT_ICR0_QUEUE_6_SHIFT 7 -#define I40E_PFINT_ICR0_QUEUE_6_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_6_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_6_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_6_SHIFT) #define I40E_PFINT_ICR0_QUEUE_7_SHIFT 8 -#define I40E_PFINT_ICR0_QUEUE_7_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_7_SHIFT) +#define I40E_PFINT_ICR0_QUEUE_7_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_7_SHIFT) #define I40E_PFINT_ICR0_ECC_ERR_SHIFT 16 -#define I40E_PFINT_ICR0_ECC_ERR_MASK (0x1 << I40E_PFINT_ICR0_ECC_ERR_SHIFT) +#define I40E_PFINT_ICR0_ECC_ERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ECC_ERR_SHIFT) #define I40E_PFINT_ICR0_MAL_DETECT_SHIFT 19 -#define I40E_PFINT_ICR0_MAL_DETECT_MASK (0x1 << I40E_PFINT_ICR0_MAL_DETECT_SHIFT) +#define I40E_PFINT_ICR0_MAL_DETECT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_MAL_DETECT_SHIFT) #define I40E_PFINT_ICR0_GRST_SHIFT 20 -#define I40E_PFINT_ICR0_GRST_MASK (0x1 << I40E_PFINT_ICR0_GRST_SHIFT) +#define I40E_PFINT_ICR0_GRST_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_GRST_SHIFT) #define I40E_PFINT_ICR0_PCI_EXCEPTION_SHIFT 21 -#define I40E_PFINT_ICR0_PCI_EXCEPTION_MASK (0x1 << I40E_PFINT_ICR0_PCI_EXCEPTION_SHIFT) +#define I40E_PFINT_ICR0_PCI_EXCEPTION_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_PCI_EXCEPTION_SHIFT) #define I40E_PFINT_ICR0_GPIO_SHIFT 22 -#define I40E_PFINT_ICR0_GPIO_MASK (0x1 << I40E_PFINT_ICR0_GPIO_SHIFT) +#define I40E_PFINT_ICR0_GPIO_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_GPIO_SHIFT) #define I40E_PFINT_ICR0_TIMESYNC_SHIFT 23 -#define I40E_PFINT_ICR0_TIMESYNC_MASK (0x1 << I40E_PFINT_ICR0_TIMESYNC_SHIFT) +#define I40E_PFINT_ICR0_TIMESYNC_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_TIMESYNC_SHIFT) +#define I40E_PFINT_ICR0_STORM_DETECT_SHIFT 24 +#define I40E_PFINT_ICR0_STORM_DETECT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_STORM_DETECT_SHIFT) #define I40E_PFINT_ICR0_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_PFINT_ICR0_LINK_STAT_CHANGE_MASK (0x1 << I40E_PFINT_ICR0_LINK_STAT_CHANGE_SHIFT) +#define I40E_PFINT_ICR0_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_LINK_STAT_CHANGE_SHIFT) #define I40E_PFINT_ICR0_HMC_ERR_SHIFT 26 -#define I40E_PFINT_ICR0_HMC_ERR_MASK (0x1 << I40E_PFINT_ICR0_HMC_ERR_SHIFT) +#define I40E_PFINT_ICR0_HMC_ERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_HMC_ERR_SHIFT) #define I40E_PFINT_ICR0_PE_CRITERR_SHIFT 28 -#define I40E_PFINT_ICR0_PE_CRITERR_MASK (0x1 << I40E_PFINT_ICR0_PE_CRITERR_SHIFT) +#define I40E_PFINT_ICR0_PE_CRITERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_PE_CRITERR_SHIFT) #define I40E_PFINT_ICR0_VFLR_SHIFT 29 -#define I40E_PFINT_ICR0_VFLR_MASK (0x1 << I40E_PFINT_ICR0_VFLR_SHIFT) +#define I40E_PFINT_ICR0_VFLR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_VFLR_SHIFT) #define I40E_PFINT_ICR0_ADMINQ_SHIFT 30 -#define I40E_PFINT_ICR0_ADMINQ_MASK (0x1 << I40E_PFINT_ICR0_ADMINQ_SHIFT) +#define I40E_PFINT_ICR0_ADMINQ_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ADMINQ_SHIFT) #define I40E_PFINT_ICR0_SWINT_SHIFT 31 -#define I40E_PFINT_ICR0_SWINT_MASK (0x1 << I40E_PFINT_ICR0_SWINT_SHIFT) -#define I40E_PFINT_ICR0_ENA 0x00038800 +#define I40E_PFINT_ICR0_SWINT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_SWINT_SHIFT) +#define I40E_PFINT_ICR0_ENA 0x00038800 /* Reset: CORER */ #define I40E_PFINT_ICR0_ENA_ECC_ERR_SHIFT 16 -#define I40E_PFINT_ICR0_ENA_ECC_ERR_MASK (0x1 << I40E_PFINT_ICR0_ENA_ECC_ERR_SHIFT) +#define I40E_PFINT_ICR0_ENA_ECC_ERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_ECC_ERR_SHIFT) #define I40E_PFINT_ICR0_ENA_MAL_DETECT_SHIFT 19 -#define I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK (0x1 << I40E_PFINT_ICR0_ENA_MAL_DETECT_SHIFT) +#define I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_MAL_DETECT_SHIFT) #define I40E_PFINT_ICR0_ENA_GRST_SHIFT 20 -#define I40E_PFINT_ICR0_ENA_GRST_MASK (0x1 << I40E_PFINT_ICR0_ENA_GRST_SHIFT) +#define I40E_PFINT_ICR0_ENA_GRST_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_GRST_SHIFT) #define I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_SHIFT 21 -#define I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK (0x1 << I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_SHIFT) +#define I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_SHIFT) #define I40E_PFINT_ICR0_ENA_GPIO_SHIFT 22 -#define I40E_PFINT_ICR0_ENA_GPIO_MASK (0x1 << I40E_PFINT_ICR0_ENA_GPIO_SHIFT) +#define I40E_PFINT_ICR0_ENA_GPIO_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_GPIO_SHIFT) #define I40E_PFINT_ICR0_ENA_TIMESYNC_SHIFT 23 -#define I40E_PFINT_ICR0_ENA_TIMESYNC_MASK (0x1 << I40E_PFINT_ICR0_ENA_TIMESYNC_SHIFT) +#define I40E_PFINT_ICR0_ENA_TIMESYNC_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_TIMESYNC_SHIFT) +#define I40E_PFINT_ICR0_ENA_STORM_DETECT_SHIFT 24 +#define I40E_PFINT_ICR0_ENA_STORM_DETECT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_STORM_DETECT_SHIFT) #define I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK (0x1 << I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT) +#define I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT) #define I40E_PFINT_ICR0_ENA_HMC_ERR_SHIFT 26 -#define I40E_PFINT_ICR0_ENA_HMC_ERR_MASK (0x1 << I40E_PFINT_ICR0_ENA_HMC_ERR_SHIFT) +#define I40E_PFINT_ICR0_ENA_HMC_ERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_HMC_ERR_SHIFT) #define I40E_PFINT_ICR0_ENA_PE_CRITERR_SHIFT 28 -#define I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK (0x1 << I40E_PFINT_ICR0_ENA_PE_CRITERR_SHIFT) +#define I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_PE_CRITERR_SHIFT) #define I40E_PFINT_ICR0_ENA_VFLR_SHIFT 29 -#define I40E_PFINT_ICR0_ENA_VFLR_MASK (0x1 << I40E_PFINT_ICR0_ENA_VFLR_SHIFT) +#define I40E_PFINT_ICR0_ENA_VFLR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_VFLR_SHIFT) #define I40E_PFINT_ICR0_ENA_ADMINQ_SHIFT 30 -#define I40E_PFINT_ICR0_ENA_ADMINQ_MASK (0x1 << I40E_PFINT_ICR0_ENA_ADMINQ_SHIFT) +#define I40E_PFINT_ICR0_ENA_ADMINQ_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_ADMINQ_SHIFT) #define I40E_PFINT_ICR0_ENA_RSVD_SHIFT 31 -#define I40E_PFINT_ICR0_ENA_RSVD_MASK (0x1 << I40E_PFINT_ICR0_ENA_RSVD_SHIFT) -#define I40E_PFINT_ITR0(_i) (0x00038000 + ((_i) * 128)) /* _i=0...2 */ +#define I40E_PFINT_ICR0_ENA_RSVD_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_RSVD_SHIFT) +#define I40E_PFINT_ITR0(_i) (0x00038000 + ((_i) * 128)) /* _i=0...2 */ /* Reset: PFR */ #define I40E_PFINT_ITR0_MAX_INDEX 2 #define I40E_PFINT_ITR0_INTERVAL_SHIFT 0 -#define I40E_PFINT_ITR0_INTERVAL_MASK (0xFFF << I40E_PFINT_ITR0_INTERVAL_SHIFT) -#define I40E_PFINT_ITRN(_i, _INTPF) (0x00030000 + ((_i) * 2048 + (_INTPF) * 4)) +#define I40E_PFINT_ITR0_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_ITR0_INTERVAL_SHIFT) +#define I40E_PFINT_ITRN(_i, _INTPF) (0x00030000 + ((_i) * 2048 + (_INTPF) * 4)) /* _i=0...2, _INTPF=0...511 */ /* Reset: PFR */ #define I40E_PFINT_ITRN_MAX_INDEX 2 #define I40E_PFINT_ITRN_INTERVAL_SHIFT 0 -#define I40E_PFINT_ITRN_INTERVAL_MASK (0xFFF << I40E_PFINT_ITRN_INTERVAL_SHIFT) -#define I40E_PFINT_LNKLST0 0x00038500 +#define I40E_PFINT_ITRN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_ITRN_INTERVAL_SHIFT) +#define I40E_PFINT_LNKLST0 0x00038500 /* Reset: PFR */ #define I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT 0 -#define I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK (0x7FF << I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) +#define I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK I40E_MASK(0x7FF, I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) #define I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT 11 -#define I40E_PFINT_LNKLST0_FIRSTQ_TYPE_MASK (0x3 << I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT) -#define I40E_PFINT_LNKLSTN(_INTPF) (0x00035000 + ((_INTPF) * 4)) /* _i=0...511 */ +#define I40E_PFINT_LNKLST0_FIRSTQ_TYPE_MASK I40E_MASK(0x3, I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT) +#define I40E_PFINT_LNKLSTN(_INTPF) (0x00035000 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: PFR */ #define I40E_PFINT_LNKLSTN_MAX_INDEX 511 #define I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT 0 -#define I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK (0x7FF << I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) +#define I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK I40E_MASK(0x7FF, I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) #define I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT 11 -#define I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_MASK (0x3 << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) -#define I40E_PFINT_RATE0 0x00038580 +#define I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_MASK I40E_MASK(0x3, I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) +#define I40E_PFINT_RATE0 0x00038580 /* Reset: PFR */ #define I40E_PFINT_RATE0_INTERVAL_SHIFT 0 -#define I40E_PFINT_RATE0_INTERVAL_MASK (0x3F << I40E_PFINT_RATE0_INTERVAL_SHIFT) +#define I40E_PFINT_RATE0_INTERVAL_MASK I40E_MASK(0x3F, I40E_PFINT_RATE0_INTERVAL_SHIFT) #define I40E_PFINT_RATE0_INTRL_ENA_SHIFT 6 -#define I40E_PFINT_RATE0_INTRL_ENA_MASK (0x1 << I40E_PFINT_RATE0_INTRL_ENA_SHIFT) -#define I40E_PFINT_RATEN(_INTPF) (0x00035800 + ((_INTPF) * 4)) /* _i=0...511 */ +#define I40E_PFINT_RATE0_INTRL_ENA_MASK I40E_MASK(0x1, I40E_PFINT_RATE0_INTRL_ENA_SHIFT) +#define I40E_PFINT_RATEN(_INTPF) (0x00035800 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: PFR */ #define I40E_PFINT_RATEN_MAX_INDEX 511 #define I40E_PFINT_RATEN_INTERVAL_SHIFT 0 -#define I40E_PFINT_RATEN_INTERVAL_MASK (0x3F << I40E_PFINT_RATEN_INTERVAL_SHIFT) +#define I40E_PFINT_RATEN_INTERVAL_MASK I40E_MASK(0x3F, I40E_PFINT_RATEN_INTERVAL_SHIFT) #define I40E_PFINT_RATEN_INTRL_ENA_SHIFT 6 -#define I40E_PFINT_RATEN_INTRL_ENA_MASK (0x1 << I40E_PFINT_RATEN_INTRL_ENA_SHIFT) -#define I40E_PFINT_STAT_CTL0 0x00038400 +#define I40E_PFINT_RATEN_INTRL_ENA_MASK I40E_MASK(0x1, I40E_PFINT_RATEN_INTRL_ENA_SHIFT) +#define I40E_PFINT_STAT_CTL0 0x00038400 /* Reset: PFR */ #define I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT 2 -#define I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_MASK (0x3 << I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT) -#define I40E_QINT_RQCTL(_Q) (0x0003A000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT) +#define I40E_QINT_RQCTL(_Q) (0x0003A000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ #define I40E_QINT_RQCTL_MAX_INDEX 1535 #define I40E_QINT_RQCTL_MSIX_INDX_SHIFT 0 -#define I40E_QINT_RQCTL_MSIX_INDX_MASK (0xFF << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) +#define I40E_QINT_RQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_QINT_RQCTL_MSIX_INDX_SHIFT) #define I40E_QINT_RQCTL_ITR_INDX_SHIFT 11 -#define I40E_QINT_RQCTL_ITR_INDX_MASK (0x3 << I40E_QINT_RQCTL_ITR_INDX_SHIFT) +#define I40E_QINT_RQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_QINT_RQCTL_ITR_INDX_SHIFT) #define I40E_QINT_RQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_QINT_RQCTL_MSIX0_INDX_MASK (0x7 << I40E_QINT_RQCTL_MSIX0_INDX_SHIFT) +#define I40E_QINT_RQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_QINT_RQCTL_MSIX0_INDX_SHIFT) #define I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT 16 -#define I40E_QINT_RQCTL_NEXTQ_INDX_MASK (0x7FF << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) +#define I40E_QINT_RQCTL_NEXTQ_INDX_MASK I40E_MASK(0x7FF, I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) #define I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT 27 -#define I40E_QINT_RQCTL_NEXTQ_TYPE_MASK (0x3 << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) +#define I40E_QINT_RQCTL_NEXTQ_TYPE_MASK I40E_MASK(0x3, I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) #define I40E_QINT_RQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_QINT_RQCTL_CAUSE_ENA_MASK (0x1 << I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) +#define I40E_QINT_RQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) #define I40E_QINT_RQCTL_INTEVENT_SHIFT 31 -#define I40E_QINT_RQCTL_INTEVENT_MASK (0x1 << I40E_QINT_RQCTL_INTEVENT_SHIFT) -#define I40E_QINT_TQCTL(_Q) (0x0003C000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_QINT_RQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_QINT_RQCTL_INTEVENT_SHIFT) +#define I40E_QINT_TQCTL(_Q) (0x0003C000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ #define I40E_QINT_TQCTL_MAX_INDEX 1535 #define I40E_QINT_TQCTL_MSIX_INDX_SHIFT 0 -#define I40E_QINT_TQCTL_MSIX_INDX_MASK (0xFF << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) +#define I40E_QINT_TQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_QINT_TQCTL_MSIX_INDX_SHIFT) #define I40E_QINT_TQCTL_ITR_INDX_SHIFT 11 -#define I40E_QINT_TQCTL_ITR_INDX_MASK (0x3 << I40E_QINT_TQCTL_ITR_INDX_SHIFT) +#define I40E_QINT_TQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_QINT_TQCTL_ITR_INDX_SHIFT) #define I40E_QINT_TQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_QINT_TQCTL_MSIX0_INDX_MASK (0x7 << I40E_QINT_TQCTL_MSIX0_INDX_SHIFT) +#define I40E_QINT_TQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_QINT_TQCTL_MSIX0_INDX_SHIFT) #define I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT 16 -#define I40E_QINT_TQCTL_NEXTQ_INDX_MASK (0x7FF << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) +#define I40E_QINT_TQCTL_NEXTQ_INDX_MASK I40E_MASK(0x7FF, I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) #define I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT 27 -#define I40E_QINT_TQCTL_NEXTQ_TYPE_MASK (0x3 << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT) +#define I40E_QINT_TQCTL_NEXTQ_TYPE_MASK I40E_MASK(0x3, I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT) #define I40E_QINT_TQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_QINT_TQCTL_CAUSE_ENA_MASK (0x1 << I40E_QINT_TQCTL_CAUSE_ENA_SHIFT) +#define I40E_QINT_TQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_QINT_TQCTL_CAUSE_ENA_SHIFT) #define I40E_QINT_TQCTL_INTEVENT_SHIFT 31 -#define I40E_QINT_TQCTL_INTEVENT_MASK (0x1 << I40E_QINT_TQCTL_INTEVENT_SHIFT) -#define I40E_VFINT_DYN_CTL0(_VF) (0x0002A400 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_QINT_TQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_QINT_TQCTL_INTEVENT_SHIFT) +#define I40E_VFINT_DYN_CTL0(_VF) (0x0002A400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VFINT_DYN_CTL0_MAX_INDEX 127 #define I40E_VFINT_DYN_CTL0_INTENA_SHIFT 0 -#define I40E_VFINT_DYN_CTL0_INTENA_MASK (0x1 << I40E_VFINT_DYN_CTL0_INTENA_SHIFT) +#define I40E_VFINT_DYN_CTL0_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_INTENA_SHIFT) #define I40E_VFINT_DYN_CTL0_CLEARPBA_SHIFT 1 -#define I40E_VFINT_DYN_CTL0_CLEARPBA_MASK (0x1 << I40E_VFINT_DYN_CTL0_CLEARPBA_SHIFT) +#define I40E_VFINT_DYN_CTL0_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_CLEARPBA_SHIFT) #define I40E_VFINT_DYN_CTL0_SWINT_TRIG_SHIFT 2 -#define I40E_VFINT_DYN_CTL0_SWINT_TRIG_MASK (0x1 << I40E_VFINT_DYN_CTL0_SWINT_TRIG_SHIFT) +#define I40E_VFINT_DYN_CTL0_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_SWINT_TRIG_SHIFT) #define I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT 3 -#define I40E_VFINT_DYN_CTL0_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTL0_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTL0_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTL0_INTERVAL_MASK (0xFFF << I40E_VFINT_DYN_CTL0_INTERVAL_SHIFT) +#define I40E_VFINT_DYN_CTL0_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTL0_INTERVAL_SHIFT) #define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK (0x1 << I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT) +#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT) #define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_SHIFT 25 -#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTL0_SW_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL0_SW_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTL0_INTENA_MSK_SHIFT 31 -#define I40E_VFINT_DYN_CTL0_INTENA_MSK_MASK (0x1 << I40E_VFINT_DYN_CTL0_INTENA_MSK_SHIFT) -#define I40E_VFINT_DYN_CTLN(_INTVF) (0x00024800 + ((_INTVF) * 4)) /* _i=0...511 */ +#define I40E_VFINT_DYN_CTL0_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_INTENA_MSK_SHIFT) +#define I40E_VFINT_DYN_CTLN(_INTVF) (0x00024800 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: VFR */ #define I40E_VFINT_DYN_CTLN_MAX_INDEX 511 #define I40E_VFINT_DYN_CTLN_INTENA_SHIFT 0 -#define I40E_VFINT_DYN_CTLN_INTENA_MASK (0x1 << I40E_VFINT_DYN_CTLN_INTENA_SHIFT) +#define I40E_VFINT_DYN_CTLN_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_INTENA_SHIFT) #define I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT 1 -#define I40E_VFINT_DYN_CTLN_CLEARPBA_MASK (0x1 << I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT) +#define I40E_VFINT_DYN_CTLN_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT) #define I40E_VFINT_DYN_CTLN_SWINT_TRIG_SHIFT 2 -#define I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK (0x1 << I40E_VFINT_DYN_CTLN_SWINT_TRIG_SHIFT) +#define I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_SWINT_TRIG_SHIFT) #define I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT 3 -#define I40E_VFINT_DYN_CTLN_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTLN_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTLN_INTERVAL_MASK (0xFFF << I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT) +#define I40E_VFINT_DYN_CTLN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT) #define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK (0x1 << I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT) +#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT) #define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_SHIFT 25 -#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTLN_SW_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN_SW_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTLN_INTENA_MSK_SHIFT 31 -#define I40E_VFINT_DYN_CTLN_INTENA_MSK_MASK (0x1 << I40E_VFINT_DYN_CTLN_INTENA_MSK_SHIFT) -#define I40E_VFINT_ICR0(_VF) (0x0002BC00 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFINT_DYN_CTLN_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_INTENA_MSK_SHIFT) +#define I40E_VFINT_ICR0(_VF) (0x0002BC00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VFINT_ICR0_MAX_INDEX 127 #define I40E_VFINT_ICR0_INTEVENT_SHIFT 0 -#define I40E_VFINT_ICR0_INTEVENT_MASK (0x1 << I40E_VFINT_ICR0_INTEVENT_SHIFT) +#define I40E_VFINT_ICR0_INTEVENT_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_INTEVENT_SHIFT) #define I40E_VFINT_ICR0_QUEUE_0_SHIFT 1 -#define I40E_VFINT_ICR0_QUEUE_0_MASK (0x1 << I40E_VFINT_ICR0_QUEUE_0_SHIFT) +#define I40E_VFINT_ICR0_QUEUE_0_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_QUEUE_0_SHIFT) #define I40E_VFINT_ICR0_QUEUE_1_SHIFT 2 -#define I40E_VFINT_ICR0_QUEUE_1_MASK (0x1 << I40E_VFINT_ICR0_QUEUE_1_SHIFT) +#define I40E_VFINT_ICR0_QUEUE_1_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_QUEUE_1_SHIFT) #define I40E_VFINT_ICR0_QUEUE_2_SHIFT 3 -#define I40E_VFINT_ICR0_QUEUE_2_MASK (0x1 << I40E_VFINT_ICR0_QUEUE_2_SHIFT) +#define I40E_VFINT_ICR0_QUEUE_2_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_QUEUE_2_SHIFT) #define I40E_VFINT_ICR0_QUEUE_3_SHIFT 4 -#define I40E_VFINT_ICR0_QUEUE_3_MASK (0x1 << I40E_VFINT_ICR0_QUEUE_3_SHIFT) +#define I40E_VFINT_ICR0_QUEUE_3_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_QUEUE_3_SHIFT) #define I40E_VFINT_ICR0_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_VFINT_ICR0_LINK_STAT_CHANGE_MASK (0x1 << I40E_VFINT_ICR0_LINK_STAT_CHANGE_SHIFT) +#define I40E_VFINT_ICR0_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_LINK_STAT_CHANGE_SHIFT) #define I40E_VFINT_ICR0_ADMINQ_SHIFT 30 -#define I40E_VFINT_ICR0_ADMINQ_MASK (0x1 << I40E_VFINT_ICR0_ADMINQ_SHIFT) +#define I40E_VFINT_ICR0_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ADMINQ_SHIFT) #define I40E_VFINT_ICR0_SWINT_SHIFT 31 -#define I40E_VFINT_ICR0_SWINT_MASK (0x1 << I40E_VFINT_ICR0_SWINT_SHIFT) -#define I40E_VFINT_ICR0_ENA(_VF) (0x0002C000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFINT_ICR0_SWINT_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_SWINT_SHIFT) +#define I40E_VFINT_ICR0_ENA(_VF) (0x0002C000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VFINT_ICR0_ENA_MAX_INDEX 127 #define I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK (0x1 << I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT) +#define I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT) #define I40E_VFINT_ICR0_ENA_ADMINQ_SHIFT 30 -#define I40E_VFINT_ICR0_ENA_ADMINQ_MASK (0x1 << I40E_VFINT_ICR0_ENA_ADMINQ_SHIFT) +#define I40E_VFINT_ICR0_ENA_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA_ADMINQ_SHIFT) #define I40E_VFINT_ICR0_ENA_RSVD_SHIFT 31 -#define I40E_VFINT_ICR0_ENA_RSVD_MASK (0x1 << I40E_VFINT_ICR0_ENA_RSVD_SHIFT) -#define I40E_VFINT_ITR0(_i, _VF) (0x00028000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...2, _VF=0...127 */ +#define I40E_VFINT_ICR0_ENA_RSVD_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA_RSVD_SHIFT) +#define I40E_VFINT_ITR0(_i, _VF) (0x00028000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...2, _VF=0...127 */ /* Reset: VFR */ #define I40E_VFINT_ITR0_MAX_INDEX 2 #define I40E_VFINT_ITR0_INTERVAL_SHIFT 0 -#define I40E_VFINT_ITR0_INTERVAL_MASK (0xFFF << I40E_VFINT_ITR0_INTERVAL_SHIFT) -#define I40E_VFINT_ITRN(_i, _INTVF) (0x00020000 + ((_i) * 2048 + (_INTVF) * 4)) +#define I40E_VFINT_ITR0_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITR0_INTERVAL_SHIFT) +#define I40E_VFINT_ITRN(_i, _INTVF) (0x00020000 + ((_i) * 2048 + (_INTVF) * 4)) /* _i=0...2, _INTVF=0...511 */ /* Reset: VFR */ #define I40E_VFINT_ITRN_MAX_INDEX 2 #define I40E_VFINT_ITRN_INTERVAL_SHIFT 0 -#define I40E_VFINT_ITRN_INTERVAL_MASK (0xFFF << I40E_VFINT_ITRN_INTERVAL_SHIFT) -#define I40E_VFINT_STAT_CTL0(_VF) (0x0002A000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFINT_ITRN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITRN_INTERVAL_SHIFT) +#define I40E_VFINT_STAT_CTL0(_VF) (0x0002A000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VFINT_STAT_CTL0_MAX_INDEX 127 #define I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT 2 -#define I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_MASK (0x3 << I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT) -#define I40E_VPINT_AEQCTL(_VF) (0x0002B800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT) +#define I40E_VPINT_AEQCTL(_VF) (0x0002B800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VPINT_AEQCTL_MAX_INDEX 127 #define I40E_VPINT_AEQCTL_MSIX_INDX_SHIFT 0 -#define I40E_VPINT_AEQCTL_MSIX_INDX_MASK (0xFF << I40E_VPINT_AEQCTL_MSIX_INDX_SHIFT) +#define I40E_VPINT_AEQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_VPINT_AEQCTL_MSIX_INDX_SHIFT) #define I40E_VPINT_AEQCTL_ITR_INDX_SHIFT 11 -#define I40E_VPINT_AEQCTL_ITR_INDX_MASK (0x3 << I40E_VPINT_AEQCTL_ITR_INDX_SHIFT) +#define I40E_VPINT_AEQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_VPINT_AEQCTL_ITR_INDX_SHIFT) #define I40E_VPINT_AEQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_VPINT_AEQCTL_MSIX0_INDX_MASK (0x7 << I40E_VPINT_AEQCTL_MSIX0_INDX_SHIFT) +#define I40E_VPINT_AEQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_VPINT_AEQCTL_MSIX0_INDX_SHIFT) #define I40E_VPINT_AEQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_VPINT_AEQCTL_CAUSE_ENA_MASK (0x1 << I40E_VPINT_AEQCTL_CAUSE_ENA_SHIFT) +#define I40E_VPINT_AEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_VPINT_AEQCTL_CAUSE_ENA_SHIFT) #define I40E_VPINT_AEQCTL_INTEVENT_SHIFT 31 -#define I40E_VPINT_AEQCTL_INTEVENT_MASK (0x1 << I40E_VPINT_AEQCTL_INTEVENT_SHIFT) -#define I40E_VPINT_CEQCTL(_INTVF) (0x00026800 + ((_INTVF) * 4)) /* _i=0...511 */ +#define I40E_VPINT_AEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_VPINT_AEQCTL_INTEVENT_SHIFT) +#define I40E_VPINT_CEQCTL(_INTVF) (0x00026800 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: CORER */ #define I40E_VPINT_CEQCTL_MAX_INDEX 511 #define I40E_VPINT_CEQCTL_MSIX_INDX_SHIFT 0 -#define I40E_VPINT_CEQCTL_MSIX_INDX_MASK (0xFF << I40E_VPINT_CEQCTL_MSIX_INDX_SHIFT) +#define I40E_VPINT_CEQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_VPINT_CEQCTL_MSIX_INDX_SHIFT) #define I40E_VPINT_CEQCTL_ITR_INDX_SHIFT 11 -#define I40E_VPINT_CEQCTL_ITR_INDX_MASK (0x3 << I40E_VPINT_CEQCTL_ITR_INDX_SHIFT) +#define I40E_VPINT_CEQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_VPINT_CEQCTL_ITR_INDX_SHIFT) #define I40E_VPINT_CEQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_VPINT_CEQCTL_MSIX0_INDX_MASK (0x7 << I40E_VPINT_CEQCTL_MSIX0_INDX_SHIFT) +#define I40E_VPINT_CEQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_VPINT_CEQCTL_MSIX0_INDX_SHIFT) #define I40E_VPINT_CEQCTL_NEXTQ_INDX_SHIFT 16 -#define I40E_VPINT_CEQCTL_NEXTQ_INDX_MASK (0x7FF << I40E_VPINT_CEQCTL_NEXTQ_INDX_SHIFT) +#define I40E_VPINT_CEQCTL_NEXTQ_INDX_MASK I40E_MASK(0x7FF, I40E_VPINT_CEQCTL_NEXTQ_INDX_SHIFT) #define I40E_VPINT_CEQCTL_NEXTQ_TYPE_SHIFT 27 -#define I40E_VPINT_CEQCTL_NEXTQ_TYPE_MASK (0x3 << I40E_VPINT_CEQCTL_NEXTQ_TYPE_SHIFT) +#define I40E_VPINT_CEQCTL_NEXTQ_TYPE_MASK I40E_MASK(0x3, I40E_VPINT_CEQCTL_NEXTQ_TYPE_SHIFT) #define I40E_VPINT_CEQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_VPINT_CEQCTL_CAUSE_ENA_MASK (0x1 << I40E_VPINT_CEQCTL_CAUSE_ENA_SHIFT) +#define I40E_VPINT_CEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_VPINT_CEQCTL_CAUSE_ENA_SHIFT) #define I40E_VPINT_CEQCTL_INTEVENT_SHIFT 31 -#define I40E_VPINT_CEQCTL_INTEVENT_MASK (0x1 << I40E_VPINT_CEQCTL_INTEVENT_SHIFT) -#define I40E_VPINT_LNKLST0(_VF) (0x0002A800 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VPINT_CEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_VPINT_CEQCTL_INTEVENT_SHIFT) +#define I40E_VPINT_LNKLST0(_VF) (0x0002A800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VPINT_LNKLST0_MAX_INDEX 127 #define I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT 0 -#define I40E_VPINT_LNKLST0_FIRSTQ_INDX_MASK (0x7FF << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) +#define I40E_VPINT_LNKLST0_FIRSTQ_INDX_MASK I40E_MASK(0x7FF, I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) #define I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT 11 -#define I40E_VPINT_LNKLST0_FIRSTQ_TYPE_MASK (0x3 << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT) -#define I40E_VPINT_LNKLSTN(_INTVF) (0x00025000 + ((_INTVF) * 4)) /* _i=0...511 */ +#define I40E_VPINT_LNKLST0_FIRSTQ_TYPE_MASK I40E_MASK(0x3, I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT) +#define I40E_VPINT_LNKLSTN(_INTVF) (0x00025000 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: VFR */ #define I40E_VPINT_LNKLSTN_MAX_INDEX 511 #define I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT 0 -#define I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK (0x7FF << I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) +#define I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK I40E_MASK(0x7FF, I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) #define I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT 11 -#define I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK (0x3 << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) -#define I40E_VPINT_RATE0(_VF) (0x0002AC00 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK I40E_MASK(0x3, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) +#define I40E_VPINT_RATE0(_VF) (0x0002AC00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VPINT_RATE0_MAX_INDEX 127 #define I40E_VPINT_RATE0_INTERVAL_SHIFT 0 -#define I40E_VPINT_RATE0_INTERVAL_MASK (0x3F << I40E_VPINT_RATE0_INTERVAL_SHIFT) +#define I40E_VPINT_RATE0_INTERVAL_MASK I40E_MASK(0x3F, I40E_VPINT_RATE0_INTERVAL_SHIFT) #define I40E_VPINT_RATE0_INTRL_ENA_SHIFT 6 -#define I40E_VPINT_RATE0_INTRL_ENA_MASK (0x1 << I40E_VPINT_RATE0_INTRL_ENA_SHIFT) -#define I40E_VPINT_RATEN(_INTVF) (0x00025800 + ((_INTVF) * 4)) /* _i=0...511 */ +#define I40E_VPINT_RATE0_INTRL_ENA_MASK I40E_MASK(0x1, I40E_VPINT_RATE0_INTRL_ENA_SHIFT) +#define I40E_VPINT_RATEN(_INTVF) (0x00025800 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: VFR */ #define I40E_VPINT_RATEN_MAX_INDEX 511 #define I40E_VPINT_RATEN_INTERVAL_SHIFT 0 -#define I40E_VPINT_RATEN_INTERVAL_MASK (0x3F << I40E_VPINT_RATEN_INTERVAL_SHIFT) +#define I40E_VPINT_RATEN_INTERVAL_MASK I40E_MASK(0x3F, I40E_VPINT_RATEN_INTERVAL_SHIFT) #define I40E_VPINT_RATEN_INTRL_ENA_SHIFT 6 -#define I40E_VPINT_RATEN_INTRL_ENA_MASK (0x1 << I40E_VPINT_RATEN_INTRL_ENA_SHIFT) -#define I40E_GL_RDPU_CNTRL 0x00051060 +#define I40E_VPINT_RATEN_INTRL_ENA_MASK I40E_MASK(0x1, I40E_VPINT_RATEN_INTRL_ENA_SHIFT) +#define I40E_GL_RDPU_CNTRL 0x00051060 /* Reset: CORER */ #define I40E_GL_RDPU_CNTRL_RX_PAD_EN_SHIFT 0 -#define I40E_GL_RDPU_CNTRL_RX_PAD_EN_MASK (0x1 << I40E_GL_RDPU_CNTRL_RX_PAD_EN_SHIFT) +#define I40E_GL_RDPU_CNTRL_RX_PAD_EN_MASK I40E_MASK(0x1, I40E_GL_RDPU_CNTRL_RX_PAD_EN_SHIFT) #define I40E_GL_RDPU_CNTRL_ECO_SHIFT 1 -#define I40E_GL_RDPU_CNTRL_ECO_MASK (0x7FFFFFFF << I40E_GL_RDPU_CNTRL_ECO_SHIFT) -#define I40E_GLLAN_RCTL_0 0x0012A500 +#define I40E_GL_RDPU_CNTRL_ECO_MASK I40E_MASK(0x7FFFFFFF, I40E_GL_RDPU_CNTRL_ECO_SHIFT) +#define I40E_GLLAN_RCTL_0 0x0012A500 /* Reset: CORER */ #define I40E_GLLAN_RCTL_0_PXE_MODE_SHIFT 0 -#define I40E_GLLAN_RCTL_0_PXE_MODE_MASK (0x1 << I40E_GLLAN_RCTL_0_PXE_MODE_SHIFT) -#define I40E_GLLAN_TSOMSK_F 0x000442D8 +#define I40E_GLLAN_RCTL_0_PXE_MODE_MASK I40E_MASK(0x1, I40E_GLLAN_RCTL_0_PXE_MODE_SHIFT) +#define I40E_GLLAN_TSOMSK_F 0x000442D8 /* Reset: CORER */ #define I40E_GLLAN_TSOMSK_F_TCPMSKF_SHIFT 0 -#define I40E_GLLAN_TSOMSK_F_TCPMSKF_MASK (0xFFF << I40E_GLLAN_TSOMSK_F_TCPMSKF_SHIFT) -#define I40E_GLLAN_TSOMSK_L 0x000442E0 +#define I40E_GLLAN_TSOMSK_F_TCPMSKF_MASK I40E_MASK(0xFFF, I40E_GLLAN_TSOMSK_F_TCPMSKF_SHIFT) +#define I40E_GLLAN_TSOMSK_L 0x000442E0 /* Reset: CORER */ #define I40E_GLLAN_TSOMSK_L_TCPMSKL_SHIFT 0 -#define I40E_GLLAN_TSOMSK_L_TCPMSKL_MASK (0xFFF << I40E_GLLAN_TSOMSK_L_TCPMSKL_SHIFT) -#define I40E_GLLAN_TSOMSK_M 0x000442DC +#define I40E_GLLAN_TSOMSK_L_TCPMSKL_MASK I40E_MASK(0xFFF, I40E_GLLAN_TSOMSK_L_TCPMSKL_SHIFT) +#define I40E_GLLAN_TSOMSK_M 0x000442DC /* Reset: CORER */ #define I40E_GLLAN_TSOMSK_M_TCPMSKM_SHIFT 0 -#define I40E_GLLAN_TSOMSK_M_TCPMSKM_MASK (0xFFF << I40E_GLLAN_TSOMSK_M_TCPMSKM_SHIFT) -#define I40E_GLLAN_TXPRE_QDIS(_i) (0x000E6500 + ((_i) * 4)) /* i=0..11 */ +#define I40E_GLLAN_TSOMSK_M_TCPMSKM_MASK I40E_MASK(0xFFF, I40E_GLLAN_TSOMSK_M_TCPMSKM_SHIFT) +#define I40E_GLLAN_TXPRE_QDIS(_i) (0x000e6500 + ((_i) * 4)) /* _i=0...11 */ /* Reset: CORER */ +#define I40E_GLLAN_TXPRE_QDIS_MAX_INDEX 11 #define I40E_GLLAN_TXPRE_QDIS_QINDX_SHIFT 0 -#define I40E_GLLAN_TXPRE_QDIS_QINDX_MASK (0x7FF << I40E_GLLAN_TXPRE_QDIS_QINDX_SHIFT) +#define I40E_GLLAN_TXPRE_QDIS_QINDX_MASK I40E_MASK(0x7FF, I40E_GLLAN_TXPRE_QDIS_QINDX_SHIFT) +#define I40E_GLLAN_TXPRE_QDIS_QDIS_STAT_SHIFT 16 +#define I40E_GLLAN_TXPRE_QDIS_QDIS_STAT_MASK I40E_MASK(0x1, I40E_GLLAN_TXPRE_QDIS_QDIS_STAT_SHIFT) #define I40E_GLLAN_TXPRE_QDIS_SET_QDIS_SHIFT 30 -#define I40E_GLLAN_TXPRE_QDIS_SET_QDIS_MASK (0x1 << I40E_GLLAN_TXPRE_QDIS_SET_QDIS_SHIFT) +#define I40E_GLLAN_TXPRE_QDIS_SET_QDIS_MASK I40E_MASK(0x1, I40E_GLLAN_TXPRE_QDIS_SET_QDIS_SHIFT) #define I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_SHIFT 31 -#define I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_MASK (0x1 << I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_SHIFT) - -#define I40E_PFLAN_QALLOC 0x001C0400 +#define I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_MASK I40E_MASK(0x1, I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_SHIFT) +#define I40E_PFLAN_QALLOC 0x001C0400 /* Reset: CORER */ #define I40E_PFLAN_QALLOC_FIRSTQ_SHIFT 0 -#define I40E_PFLAN_QALLOC_FIRSTQ_MASK (0x7FF << I40E_PFLAN_QALLOC_FIRSTQ_SHIFT) +#define I40E_PFLAN_QALLOC_FIRSTQ_MASK I40E_MASK(0x7FF, I40E_PFLAN_QALLOC_FIRSTQ_SHIFT) #define I40E_PFLAN_QALLOC_LASTQ_SHIFT 16 -#define I40E_PFLAN_QALLOC_LASTQ_MASK (0x7FF << I40E_PFLAN_QALLOC_LASTQ_SHIFT) +#define I40E_PFLAN_QALLOC_LASTQ_MASK I40E_MASK(0x7FF, I40E_PFLAN_QALLOC_LASTQ_SHIFT) #define I40E_PFLAN_QALLOC_VALID_SHIFT 31 -#define I40E_PFLAN_QALLOC_VALID_MASK (0x1 << I40E_PFLAN_QALLOC_VALID_SHIFT) -#define I40E_QRX_ENA(_Q) (0x00120000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_PFLAN_QALLOC_VALID_MASK I40E_MASK(0x1, I40E_PFLAN_QALLOC_VALID_SHIFT) +#define I40E_QRX_ENA(_Q) (0x00120000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: PFR */ #define I40E_QRX_ENA_MAX_INDEX 1535 #define I40E_QRX_ENA_QENA_REQ_SHIFT 0 -#define I40E_QRX_ENA_QENA_REQ_MASK (0x1 << I40E_QRX_ENA_QENA_REQ_SHIFT) +#define I40E_QRX_ENA_QENA_REQ_MASK I40E_MASK(0x1, I40E_QRX_ENA_QENA_REQ_SHIFT) #define I40E_QRX_ENA_FAST_QDIS_SHIFT 1 -#define I40E_QRX_ENA_FAST_QDIS_MASK (0x1 << I40E_QRX_ENA_FAST_QDIS_SHIFT) +#define I40E_QRX_ENA_FAST_QDIS_MASK I40E_MASK(0x1, I40E_QRX_ENA_FAST_QDIS_SHIFT) #define I40E_QRX_ENA_QENA_STAT_SHIFT 2 -#define I40E_QRX_ENA_QENA_STAT_MASK (0x1 << I40E_QRX_ENA_QENA_STAT_SHIFT) -#define I40E_QRX_TAIL(_Q) (0x00128000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_QRX_ENA_QENA_STAT_MASK I40E_MASK(0x1, I40E_QRX_ENA_QENA_STAT_SHIFT) +#define I40E_QRX_TAIL(_Q) (0x00128000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ #define I40E_QRX_TAIL_MAX_INDEX 1535 #define I40E_QRX_TAIL_TAIL_SHIFT 0 -#define I40E_QRX_TAIL_TAIL_MASK (0x1FFF << I40E_QRX_TAIL_TAIL_SHIFT) -#define I40E_QTX_CTL(_Q) (0x00104000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_QRX_TAIL_TAIL_MASK I40E_MASK(0x1FFF, I40E_QRX_TAIL_TAIL_SHIFT) +#define I40E_QTX_CTL(_Q) (0x00104000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ #define I40E_QTX_CTL_MAX_INDEX 1535 #define I40E_QTX_CTL_PFVF_Q_SHIFT 0 -#define I40E_QTX_CTL_PFVF_Q_MASK (0x3 << I40E_QTX_CTL_PFVF_Q_SHIFT) +#define I40E_QTX_CTL_PFVF_Q_MASK I40E_MASK(0x3, I40E_QTX_CTL_PFVF_Q_SHIFT) #define I40E_QTX_CTL_PF_INDX_SHIFT 2 -#define I40E_QTX_CTL_PF_INDX_MASK (0xF << I40E_QTX_CTL_PF_INDX_SHIFT) +#define I40E_QTX_CTL_PF_INDX_MASK I40E_MASK(0xF, I40E_QTX_CTL_PF_INDX_SHIFT) #define I40E_QTX_CTL_VFVM_INDX_SHIFT 7 -#define I40E_QTX_CTL_VFVM_INDX_MASK (0x1FF << I40E_QTX_CTL_VFVM_INDX_SHIFT) -#define I40E_QTX_ENA(_Q) (0x00100000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_QTX_CTL_VFVM_INDX_MASK I40E_MASK(0x1FF, I40E_QTX_CTL_VFVM_INDX_SHIFT) +#define I40E_QTX_ENA(_Q) (0x00100000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: PFR */ #define I40E_QTX_ENA_MAX_INDEX 1535 #define I40E_QTX_ENA_QENA_REQ_SHIFT 0 -#define I40E_QTX_ENA_QENA_REQ_MASK (0x1 << I40E_QTX_ENA_QENA_REQ_SHIFT) +#define I40E_QTX_ENA_QENA_REQ_MASK I40E_MASK(0x1, I40E_QTX_ENA_QENA_REQ_SHIFT) #define I40E_QTX_ENA_FAST_QDIS_SHIFT 1 -#define I40E_QTX_ENA_FAST_QDIS_MASK (0x1 << I40E_QTX_ENA_FAST_QDIS_SHIFT) +#define I40E_QTX_ENA_FAST_QDIS_MASK I40E_MASK(0x1, I40E_QTX_ENA_FAST_QDIS_SHIFT) #define I40E_QTX_ENA_QENA_STAT_SHIFT 2 -#define I40E_QTX_ENA_QENA_STAT_MASK (0x1 << I40E_QTX_ENA_QENA_STAT_SHIFT) -#define I40E_QTX_HEAD(_Q) (0x000E4000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_QTX_ENA_QENA_STAT_MASK I40E_MASK(0x1, I40E_QTX_ENA_QENA_STAT_SHIFT) +#define I40E_QTX_HEAD(_Q) (0x000E4000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ #define I40E_QTX_HEAD_MAX_INDEX 1535 #define I40E_QTX_HEAD_HEAD_SHIFT 0 -#define I40E_QTX_HEAD_HEAD_MASK (0x1FFF << I40E_QTX_HEAD_HEAD_SHIFT) +#define I40E_QTX_HEAD_HEAD_MASK I40E_MASK(0x1FFF, I40E_QTX_HEAD_HEAD_SHIFT) #define I40E_QTX_HEAD_RS_PENDING_SHIFT 16 -#define I40E_QTX_HEAD_RS_PENDING_MASK (0x1 << I40E_QTX_HEAD_RS_PENDING_SHIFT) -#define I40E_QTX_TAIL(_Q) (0x00108000 + ((_Q) * 4)) /* _i=0...1535 */ +#define I40E_QTX_HEAD_RS_PENDING_MASK I40E_MASK(0x1, I40E_QTX_HEAD_RS_PENDING_SHIFT) +#define I40E_QTX_TAIL(_Q) (0x00108000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: PFR */ #define I40E_QTX_TAIL_MAX_INDEX 1535 #define I40E_QTX_TAIL_TAIL_SHIFT 0 -#define I40E_QTX_TAIL_TAIL_MASK (0x1FFF << I40E_QTX_TAIL_TAIL_SHIFT) -#define I40E_VPLAN_MAPENA(_VF) (0x00074000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_QTX_TAIL_TAIL_MASK I40E_MASK(0x1FFF, I40E_QTX_TAIL_TAIL_SHIFT) +#define I40E_VPLAN_MAPENA(_VF) (0x00074000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VPLAN_MAPENA_MAX_INDEX 127 #define I40E_VPLAN_MAPENA_TXRX_ENA_SHIFT 0 -#define I40E_VPLAN_MAPENA_TXRX_ENA_MASK (0x1 << I40E_VPLAN_MAPENA_TXRX_ENA_SHIFT) -#define I40E_VPLAN_QTABLE(_i, _VF) (0x00070000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ +#define I40E_VPLAN_MAPENA_TXRX_ENA_MASK I40E_MASK(0x1, I40E_VPLAN_MAPENA_TXRX_ENA_SHIFT) +#define I40E_VPLAN_QTABLE(_i, _VF) (0x00070000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ /* Reset: VFR */ #define I40E_VPLAN_QTABLE_MAX_INDEX 15 #define I40E_VPLAN_QTABLE_QINDEX_SHIFT 0 -#define I40E_VPLAN_QTABLE_QINDEX_MASK (0x7FF << I40E_VPLAN_QTABLE_QINDEX_SHIFT) -#define I40E_VSILAN_QBASE(_VSI) (0x0020C800 + ((_VSI) * 4)) /* _i=0...383 */ +#define I40E_VPLAN_QTABLE_QINDEX_MASK I40E_MASK(0x7FF, I40E_VPLAN_QTABLE_QINDEX_SHIFT) +#define I40E_VSILAN_QBASE(_VSI) (0x0020C800 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: PFR */ #define I40E_VSILAN_QBASE_MAX_INDEX 383 #define I40E_VSILAN_QBASE_VSIBASE_SHIFT 0 -#define I40E_VSILAN_QBASE_VSIBASE_MASK (0x7FF << I40E_VSILAN_QBASE_VSIBASE_SHIFT) +#define I40E_VSILAN_QBASE_VSIBASE_MASK I40E_MASK(0x7FF, I40E_VSILAN_QBASE_VSIBASE_SHIFT) #define I40E_VSILAN_QBASE_VSIQTABLE_ENA_SHIFT 11 -#define I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK (0x1 << I40E_VSILAN_QBASE_VSIQTABLE_ENA_SHIFT) -#define I40E_VSILAN_QTABLE(_i, _VSI) (0x00200000 + ((_i) * 2048 + (_VSI) * 4)) +#define I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK I40E_MASK(0x1, I40E_VSILAN_QBASE_VSIQTABLE_ENA_SHIFT) +#define I40E_VSILAN_QTABLE(_i, _VSI) (0x00200000 + ((_i) * 2048 + (_VSI) * 4)) /* _i=0...7, _VSI=0...383 */ /* Reset: PFR */ #define I40E_VSILAN_QTABLE_MAX_INDEX 7 #define I40E_VSILAN_QTABLE_QINDEX_0_SHIFT 0 -#define I40E_VSILAN_QTABLE_QINDEX_0_MASK (0x7FF << I40E_VSILAN_QTABLE_QINDEX_0_SHIFT) +#define I40E_VSILAN_QTABLE_QINDEX_0_MASK I40E_MASK(0x7FF, I40E_VSILAN_QTABLE_QINDEX_0_SHIFT) #define I40E_VSILAN_QTABLE_QINDEX_1_SHIFT 16 -#define I40E_VSILAN_QTABLE_QINDEX_1_MASK (0x7FF << I40E_VSILAN_QTABLE_QINDEX_1_SHIFT) -#define I40E_PRTGL_SAH 0x001E2140 +#define I40E_VSILAN_QTABLE_QINDEX_1_MASK I40E_MASK(0x7FF, I40E_VSILAN_QTABLE_QINDEX_1_SHIFT) +#define I40E_PRTGL_SAH 0x001E2140 /* Reset: GLOBR */ #define I40E_PRTGL_SAH_FC_SAH_SHIFT 0 -#define I40E_PRTGL_SAH_FC_SAH_MASK (0xFFFF << I40E_PRTGL_SAH_FC_SAH_SHIFT) +#define I40E_PRTGL_SAH_FC_SAH_MASK I40E_MASK(0xFFFF, I40E_PRTGL_SAH_FC_SAH_SHIFT) #define I40E_PRTGL_SAH_MFS_SHIFT 16 -#define I40E_PRTGL_SAH_MFS_MASK (0xFFFF << I40E_PRTGL_SAH_MFS_SHIFT) -#define I40E_PRTGL_SAL 0x001E2120 +#define I40E_PRTGL_SAH_MFS_MASK I40E_MASK(0xFFFF, I40E_PRTGL_SAH_MFS_SHIFT) +#define I40E_PRTGL_SAL 0x001E2120 /* Reset: GLOBR */ #define I40E_PRTGL_SAL_FC_SAL_SHIFT 0 -#define I40E_PRTGL_SAL_FC_SAL_MASK (0xFFFFFFFF << I40E_PRTGL_SAL_FC_SAL_SHIFT) -#define I40E_PRTMAC_HLCTLA 0x001E4760 -#define I40E_PRTMAC_HLCTLA_DROP_US_PKTS_SHIFT 0 -#define I40E_PRTMAC_HLCTLA_DROP_US_PKTS_MASK (0x1 << I40E_PRTMAC_HLCTLA_DROP_US_PKTS_SHIFT) -#define I40E_PRTMAC_HLCTLA_RX_FWRD_CTRL_SHIFT 1 -#define I40E_PRTMAC_HLCTLA_RX_FWRD_CTRL_MASK (0x1 << I40E_PRTMAC_HLCTLA_RX_FWRD_CTRL_SHIFT) -#define I40E_PRTMAC_HLCTLA_CHOP_OS_PKT_SHIFT 2 -#define I40E_PRTMAC_HLCTLA_CHOP_OS_PKT_MASK (0x1 << I40E_PRTMAC_HLCTLA_CHOP_OS_PKT_SHIFT) -#define I40E_PRTMAC_HLCTLA_TX_HYSTERESIS_SHIFT 4 -#define I40E_PRTMAC_HLCTLA_TX_HYSTERESIS_MASK (0x7 << I40E_PRTMAC_HLCTLA_TX_HYSTERESIS_SHIFT) -#define I40E_PRTMAC_HLCTLA_HYS_FLUSH_PKT_SHIFT 7 -#define I40E_PRTMAC_HLCTLA_HYS_FLUSH_PKT_MASK (0x1 << I40E_PRTMAC_HLCTLA_HYS_FLUSH_PKT_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GCP 0x001E3130 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GCP_HSEC_CTL_RX_CHECK_SA_GCP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GCP_HSEC_CTL_RX_CHECK_SA_GCP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GCP_HSEC_CTL_RX_CHECK_SA_GCP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GPP 0x001E3290 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GPP_HSEC_CTL_RX_CHECK_SA_GPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GPP_HSEC_CTL_RX_CHECK_SA_GPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GPP_HSEC_CTL_RX_CHECK_SA_GPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_PPP 0x001E3310 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_PPP_HSEC_CTL_RX_CHECK_SA_PPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_PPP_HSEC_CTL_RX_CHECK_SA_PPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_PPP_HSEC_CTL_RX_CHECK_SA_PPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GCP 0x001E3100 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GCP_HSEC_CTL_RX_CHECK_UCAST_GCP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GCP_HSEC_CTL_RX_CHECK_UCAST_GCP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GCP_HSEC_CTL_RX_CHECK_UCAST_GCP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GPP 0x001E3280 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GPP_HSEC_CTL_RX_CHECK_UCAST_GPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GPP_HSEC_CTL_RX_CHECK_UCAST_GPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GPP_HSEC_CTL_RX_CHECK_UCAST_GPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_PPP 0x001E3300 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_PPP_HSEC_CTL_RX_CHECK_UCAST_PPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_PPP_HSEC_CTL_RX_CHECK_UCAST_PPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_PPP_HSEC_CTL_RX_CHECK_UCAST_PPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP 0x001E30E0 +#define I40E_PRTGL_SAL_FC_SAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTGL_SAL_FC_SAL_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP 0x001E30E0 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP 0x001E3260 +#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_MASK I40E_MASK(0x1, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP 0x001E3260 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP 0x001E32E0 +#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_MASK I40E_MASK(0x1, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP 0x001E32E0 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL 0x001E3360 +#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_MASK I40E_MASK(0x1, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL 0x001E3360 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1 0x001E3110 +#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_MASK I40E_MASK(0x1, I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1 0x001E3110 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_MASK (0xFFFFFFFF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2 0x001E3120 +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2 0x001E3120 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE 0x001E30C0 +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE 0x001E30C0 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_MASK (0x1FF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1 0x001E3140 +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_MASK I40E_MASK(0x1FF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1 0x001E3140 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_MASK (0xFFFFFFFF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2 0x001E3150 +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2 0x001E3150 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_ENABLE 0x001E3000 -#define I40E_PRTMAC_HSEC_CTL_TX_ENABLE_HSEC_CTL_TX_ENABLE_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_ENABLE_HSEC_CTL_TX_ENABLE_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_TX_ENABLE_HSEC_CTL_TX_ENABLE_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE 0x001E30D0 +#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE 0x001E30D0 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_MASK (0x1FF << I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA(_i) (0x001E3370 + ((_i) * 16)) +#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_MASK I40E_MASK(0x1FF, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA(_i) (0x001E3370 + ((_i) * 16)) /* _i=0...8 */ /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_MAX_INDEX 8 #define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(_i) (0x001E3400 + ((_i) * 16)) +#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(_i) (0x001E3400 + ((_i) * 16)) /* _i=0...8 */ /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MAX_INDEX 8 #define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1 0x001E34B0 +#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1 0x001E34B0 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_MASK (0xFFFFFFFF << I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2 0x001E34C0 +#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_SHIFT) +#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2 0x001E34C0 /* Reset: GLOBR */ #define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_SHIFT) -#define I40E_PRTMAC_HSECTL1 0x001E3560 -#define I40E_PRTMAC_HSECTL1_DROP_US_PKTS_SHIFT 0 -#define I40E_PRTMAC_HSECTL1_DROP_US_PKTS_MASK (0x1 << I40E_PRTMAC_HSECTL1_DROP_US_PKTS_SHIFT) -#define I40E_PRTMAC_HSECTL1_PAD_US_PKT_SHIFT 3 -#define I40E_PRTMAC_HSECTL1_PAD_US_PKT_MASK (0x1 << I40E_PRTMAC_HSECTL1_PAD_US_PKT_SHIFT) -#define I40E_PRTMAC_HSECTL1_TX_HYSTERESIS_SHIFT 4 -#define I40E_PRTMAC_HSECTL1_TX_HYSTERESIS_MASK (0x7 << I40E_PRTMAC_HSECTL1_TX_HYSTERESIS_SHIFT) -#define I40E_PRTMAC_HSECTL1_HYS_FLUSH_PKT_SHIFT 7 -#define I40E_PRTMAC_HSECTL1_HYS_FLUSH_PKT_MASK (0x1 << I40E_PRTMAC_HSECTL1_HYS_FLUSH_PKT_SHIFT) -#define I40E_PRTMAC_HSECTL1_EN_SFD_CHECK_SHIFT 30 -#define I40E_PRTMAC_HSECTL1_EN_SFD_CHECK_MASK (0x1 << I40E_PRTMAC_HSECTL1_EN_SFD_CHECK_SHIFT) -#define I40E_PRTMAC_HSECTL1_EN_PREAMBLE_CHECK_SHIFT 31 -#define I40E_PRTMAC_HSECTL1_EN_PREAMBLE_CHECK_MASK (0x1 << I40E_PRTMAC_HSECTL1_EN_PREAMBLE_CHECK_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_A 0x0008C480 +#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A 0x0008C480 /* Reset: GLOBR */ #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_SHIFT 0 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_SHIFT 2 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_SHIFT 4 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_SHIFT 6 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_SHIFT 8 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_SHIFT 10 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_SHIFT 12 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_SHIFT 14 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_B 0x0008C484 +#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B 0x0008C484 /* Reset: GLOBR */ #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_SHIFT 0 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_SHIFT 2 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_SHIFT 4 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_SHIFT 6 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_SHIFT 8 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_SHIFT 10 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_SHIFT 12 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_SHIFT) #define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_SHIFT 14 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_SHIFT) -#define I40E_GL_MNG_FWSM 0x000B6134 -#define I40E_GL_MNG_FWSM_FW_MODES_SHIFT 1 -#define I40E_GL_MNG_FWSM_FW_MODES_MASK (0x7 << I40E_GL_MNG_FWSM_FW_MODES_SHIFT) -#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT 6 -#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_MASK (0x1 << I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT) +#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_SHIFT) +#define I40E_GL_FWRESETCNT 0x00083100 /* Reset: POR */ +#define I40E_GL_FWRESETCNT_FWRESETCNT_SHIFT 0 +#define I40E_GL_FWRESETCNT_FWRESETCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FWRESETCNT_FWRESETCNT_SHIFT) +#define I40E_GL_MNG_FWSM 0x000B6134 /* Reset: POR */ +#define I40E_GL_MNG_FWSM_FW_MODES_SHIFT 0 +#define I40E_GL_MNG_FWSM_FW_MODES_MASK I40E_MASK(0x3, I40E_GL_MNG_FWSM_FW_MODES_SHIFT) +#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT 10 +#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT) #define I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_SHIFT 11 -#define I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_MASK (0xF << I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_SHIFT) +#define I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_MASK I40E_MASK(0xF, I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_SHIFT) #define I40E_GL_MNG_FWSM_FW_STATUS_VALID_SHIFT 15 -#define I40E_GL_MNG_FWSM_FW_STATUS_VALID_MASK (0x1 << I40E_GL_MNG_FWSM_FW_STATUS_VALID_SHIFT) +#define I40E_GL_MNG_FWSM_FW_STATUS_VALID_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_FW_STATUS_VALID_SHIFT) #define I40E_GL_MNG_FWSM_RESET_CNT_SHIFT 16 -#define I40E_GL_MNG_FWSM_RESET_CNT_MASK (0x7 << I40E_GL_MNG_FWSM_RESET_CNT_SHIFT) +#define I40E_GL_MNG_FWSM_RESET_CNT_MASK I40E_MASK(0x7, I40E_GL_MNG_FWSM_RESET_CNT_SHIFT) #define I40E_GL_MNG_FWSM_EXT_ERR_IND_SHIFT 19 -#define I40E_GL_MNG_FWSM_EXT_ERR_IND_MASK (0x3F << I40E_GL_MNG_FWSM_EXT_ERR_IND_SHIFT) -#define I40E_GL_MNG_FWSM_RSVD_SHIFT 25 -#define I40E_GL_MNG_FWSM_RSVD_MASK (0x1 << I40E_GL_MNG_FWSM_RSVD_SHIFT) +#define I40E_GL_MNG_FWSM_EXT_ERR_IND_MASK I40E_MASK(0x3F, I40E_GL_MNG_FWSM_EXT_ERR_IND_SHIFT) #define I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_SHIFT 26 -#define I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_SHIFT) +#define I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_SHIFT) #define I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_SHIFT 27 -#define I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_SHIFT) +#define I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_SHIFT) #define I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_SHIFT 28 -#define I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_SHIFT) +#define I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_SHIFT) #define I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_SHIFT 29 -#define I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_SHIFT) -#define I40E_GL_MNG_HWARB_CTRL 0x000B6130 +#define I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_SHIFT) +#define I40E_GL_MNG_HWARB_CTRL 0x000B6130 /* Reset: POR */ #define I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_SHIFT 0 -#define I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_MASK (0x1 << I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_SHIFT) -#define I40E_PRT_MNG_FTFT_DATA(_i) (0x000852A0 + ((_i) * 32)) /* _i=0...31 */ +#define I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_MASK I40E_MASK(0x1, I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_SHIFT) +#define I40E_PRT_MNG_FTFT_DATA(_i) (0x000852A0 + ((_i) * 32)) /* _i=0...31 */ /* Reset: POR */ #define I40E_PRT_MNG_FTFT_DATA_MAX_INDEX 31 #define I40E_PRT_MNG_FTFT_DATA_DWORD_SHIFT 0 -#define I40E_PRT_MNG_FTFT_DATA_DWORD_MASK (0xFFFFFFFF << I40E_PRT_MNG_FTFT_DATA_DWORD_SHIFT) -#define I40E_PRT_MNG_FTFT_LENGTH 0x00085260 +#define I40E_PRT_MNG_FTFT_DATA_DWORD_MASK I40E_MASK(0xFFFFFFFF, I40E_PRT_MNG_FTFT_DATA_DWORD_SHIFT) +#define I40E_PRT_MNG_FTFT_LENGTH 0x00085260 /* Reset: POR */ #define I40E_PRT_MNG_FTFT_LENGTH_LENGTH_SHIFT 0 -#define I40E_PRT_MNG_FTFT_LENGTH_LENGTH_MASK (0xFF << I40E_PRT_MNG_FTFT_LENGTH_LENGTH_SHIFT) -#define I40E_PRT_MNG_FTFT_MASK(_i) (0x00085160 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRT_MNG_FTFT_LENGTH_LENGTH_MASK I40E_MASK(0xFF, I40E_PRT_MNG_FTFT_LENGTH_LENGTH_SHIFT) +#define I40E_PRT_MNG_FTFT_MASK(_i) (0x00085160 + ((_i) * 32)) /* _i=0...7 */ /* Reset: POR */ #define I40E_PRT_MNG_FTFT_MASK_MAX_INDEX 7 #define I40E_PRT_MNG_FTFT_MASK_MASK_SHIFT 0 -#define I40E_PRT_MNG_FTFT_MASK_MASK_MASK (0xFFFF << I40E_PRT_MNG_FTFT_MASK_MASK_SHIFT) -#define I40E_PRT_MNG_MANC 0x00256A20 +#define I40E_PRT_MNG_FTFT_MASK_MASK_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_FTFT_MASK_MASK_SHIFT) +#define I40E_PRT_MNG_MANC 0x00256A20 /* Reset: POR */ #define I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_SHIFT 0 -#define I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_MASK (0x1 << I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_SHIFT) +#define I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_SHIFT) #define I40E_PRT_MNG_MANC_NCSI_DISCARD_SHIFT 1 -#define I40E_PRT_MNG_MANC_NCSI_DISCARD_MASK (0x1 << I40E_PRT_MNG_MANC_NCSI_DISCARD_SHIFT) +#define I40E_PRT_MNG_MANC_NCSI_DISCARD_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_NCSI_DISCARD_SHIFT) #define I40E_PRT_MNG_MANC_RCV_TCO_EN_SHIFT 17 -#define I40E_PRT_MNG_MANC_RCV_TCO_EN_MASK (0x1 << I40E_PRT_MNG_MANC_RCV_TCO_EN_SHIFT) +#define I40E_PRT_MNG_MANC_RCV_TCO_EN_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_RCV_TCO_EN_SHIFT) #define I40E_PRT_MNG_MANC_RCV_ALL_SHIFT 19 -#define I40E_PRT_MNG_MANC_RCV_ALL_MASK (0x1 << I40E_PRT_MNG_MANC_RCV_ALL_SHIFT) +#define I40E_PRT_MNG_MANC_RCV_ALL_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_RCV_ALL_SHIFT) #define I40E_PRT_MNG_MANC_FIXED_NET_TYPE_SHIFT 25 -#define I40E_PRT_MNG_MANC_FIXED_NET_TYPE_MASK (0x1 << I40E_PRT_MNG_MANC_FIXED_NET_TYPE_SHIFT) +#define I40E_PRT_MNG_MANC_FIXED_NET_TYPE_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_FIXED_NET_TYPE_SHIFT) #define I40E_PRT_MNG_MANC_NET_TYPE_SHIFT 26 -#define I40E_PRT_MNG_MANC_NET_TYPE_MASK (0x1 << I40E_PRT_MNG_MANC_NET_TYPE_SHIFT) +#define I40E_PRT_MNG_MANC_NET_TYPE_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_NET_TYPE_SHIFT) #define I40E_PRT_MNG_MANC_EN_BMC2OS_SHIFT 28 -#define I40E_PRT_MNG_MANC_EN_BMC2OS_MASK (0x1 << I40E_PRT_MNG_MANC_EN_BMC2OS_SHIFT) +#define I40E_PRT_MNG_MANC_EN_BMC2OS_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_EN_BMC2OS_SHIFT) #define I40E_PRT_MNG_MANC_EN_BMC2NET_SHIFT 29 -#define I40E_PRT_MNG_MANC_EN_BMC2NET_MASK (0x1 << I40E_PRT_MNG_MANC_EN_BMC2NET_SHIFT) -#define I40E_PRT_MNG_MAVTV(_i) (0x00255900 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRT_MNG_MANC_EN_BMC2NET_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_EN_BMC2NET_SHIFT) +#define I40E_PRT_MNG_MAVTV(_i) (0x00255900 + ((_i) * 32)) /* _i=0...7 */ /* Reset: POR */ #define I40E_PRT_MNG_MAVTV_MAX_INDEX 7 #define I40E_PRT_MNG_MAVTV_VID_SHIFT 0 -#define I40E_PRT_MNG_MAVTV_VID_MASK (0xFFF << I40E_PRT_MNG_MAVTV_VID_SHIFT) -#define I40E_PRT_MNG_MDEF(_i) (0x00255D00 + ((_i) * 32)) +#define I40E_PRT_MNG_MAVTV_VID_MASK I40E_MASK(0xFFF, I40E_PRT_MNG_MAVTV_VID_SHIFT) +#define I40E_PRT_MNG_MDEF(_i) (0x00255D00 + ((_i) * 32)) /* _i=0...7 */ /* Reset: POR */ #define I40E_PRT_MNG_MDEF_MAX_INDEX 7 #define I40E_PRT_MNG_MDEF_MAC_EXACT_AND_SHIFT 0 -#define I40E_PRT_MNG_MDEF_MAC_EXACT_AND_MASK (0xF << I40E_PRT_MNG_MDEF_MAC_EXACT_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_MAC_EXACT_AND_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_MAC_EXACT_AND_SHIFT) #define I40E_PRT_MNG_MDEF_BROADCAST_AND_SHIFT 4 -#define I40E_PRT_MNG_MDEF_BROADCAST_AND_MASK (0x1 << I40E_PRT_MNG_MDEF_BROADCAST_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_BROADCAST_AND_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_BROADCAST_AND_SHIFT) #define I40E_PRT_MNG_MDEF_VLAN_AND_SHIFT 5 -#define I40E_PRT_MNG_MDEF_VLAN_AND_MASK (0xFF << I40E_PRT_MNG_MDEF_VLAN_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_VLAN_AND_MASK I40E_MASK(0xFF, I40E_PRT_MNG_MDEF_VLAN_AND_SHIFT) #define I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_SHIFT 13 -#define I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_MASK (0xF << I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_SHIFT) #define I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_SHIFT 17 -#define I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_MASK (0xF << I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_SHIFT) #define I40E_PRT_MNG_MDEF_MAC_EXACT_OR_SHIFT 21 -#define I40E_PRT_MNG_MDEF_MAC_EXACT_OR_MASK (0xF << I40E_PRT_MNG_MDEF_MAC_EXACT_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_MAC_EXACT_OR_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_MAC_EXACT_OR_SHIFT) #define I40E_PRT_MNG_MDEF_BROADCAST_OR_SHIFT 25 -#define I40E_PRT_MNG_MDEF_BROADCAST_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_BROADCAST_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_BROADCAST_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_BROADCAST_OR_SHIFT) #define I40E_PRT_MNG_MDEF_MULTICAST_AND_SHIFT 26 -#define I40E_PRT_MNG_MDEF_MULTICAST_AND_MASK (0x1 << I40E_PRT_MNG_MDEF_MULTICAST_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_MULTICAST_AND_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_MULTICAST_AND_SHIFT) #define I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_SHIFT 27 -#define I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_SHIFT) #define I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_SHIFT 28 -#define I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_SHIFT) #define I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_SHIFT 29 -#define I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_SHIFT) #define I40E_PRT_MNG_MDEF_PORT_0X298_OR_SHIFT 30 -#define I40E_PRT_MNG_MDEF_PORT_0X298_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_PORT_0X298_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_PORT_0X298_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_PORT_0X298_OR_SHIFT) #define I40E_PRT_MNG_MDEF_PORT_0X26F_OR_SHIFT 31 -#define I40E_PRT_MNG_MDEF_PORT_0X26F_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_PORT_0X26F_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT(_i) (0x00255F00 + ((_i) * 32)) +#define I40E_PRT_MNG_MDEF_PORT_0X26F_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_PORT_0X26F_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT(_i) (0x00255F00 + ((_i) * 32)) /* _i=0...7 */ /* Reset: POR */ #define I40E_PRT_MNG_MDEF_EXT_MAX_INDEX 7 #define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_SHIFT 0 -#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_MASK (0xF << I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_SHIFT 4 -#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_MASK (0xF << I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_SHIFT 8 -#define I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_MASK (0xFFFF << I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_SHIFT 24 -#define I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_SHIFT 25 -#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_SHIFT 26 -#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_SHIFT 27 -#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_ICMP_OR_SHIFT 28 -#define I40E_PRT_MNG_MDEF_EXT_ICMP_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_ICMP_OR_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_ICMP_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_ICMP_OR_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_MLD_SHIFT 29 -#define I40E_PRT_MNG_MDEF_EXT_MLD_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_MLD_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_MLD_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_MLD_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_SHIFT 30 -#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_SHIFT) +#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_SHIFT) #define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_SHIFT 31 -#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_SHIFT) -#define I40E_PRT_MNG_MDEFVSI(_i) (0x00256580 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_SHIFT) +#define I40E_PRT_MNG_MDEFVSI(_i) (0x00256580 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ #define I40E_PRT_MNG_MDEFVSI_MAX_INDEX 3 #define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_SHIFT 0 -#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_MASK (0xFFFF << I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_SHIFT) +#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_SHIFT) #define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_SHIFT 16 -#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_MASK (0xFFFF << I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_SHIFT) -#define I40E_PRT_MNG_METF(_i) (0x00256780 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_SHIFT) +#define I40E_PRT_MNG_METF(_i) (0x00256780 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ #define I40E_PRT_MNG_METF_MAX_INDEX 3 #define I40E_PRT_MNG_METF_ETYPE_SHIFT 0 -#define I40E_PRT_MNG_METF_ETYPE_MASK (0xFFFF << I40E_PRT_MNG_METF_ETYPE_SHIFT) +#define I40E_PRT_MNG_METF_ETYPE_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_METF_ETYPE_SHIFT) #define I40E_PRT_MNG_METF_POLARITY_SHIFT 30 -#define I40E_PRT_MNG_METF_POLARITY_MASK (0x1 << I40E_PRT_MNG_METF_POLARITY_SHIFT) -#define I40E_PRT_MNG_MFUTP(_i) (0x00254E00 + ((_i) * 32)) /* _i=0...15 */ +#define I40E_PRT_MNG_METF_POLARITY_MASK I40E_MASK(0x1, I40E_PRT_MNG_METF_POLARITY_SHIFT) +#define I40E_PRT_MNG_MFUTP(_i) (0x00254E00 + ((_i) * 32)) /* _i=0...15 */ /* Reset: POR */ #define I40E_PRT_MNG_MFUTP_MAX_INDEX 15 #define I40E_PRT_MNG_MFUTP_MFUTP_N_SHIFT 0 -#define I40E_PRT_MNG_MFUTP_MFUTP_N_MASK (0xFFFF << I40E_PRT_MNG_MFUTP_MFUTP_N_SHIFT) +#define I40E_PRT_MNG_MFUTP_MFUTP_N_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MFUTP_MFUTP_N_SHIFT) #define I40E_PRT_MNG_MFUTP_UDP_SHIFT 16 -#define I40E_PRT_MNG_MFUTP_UDP_MASK (0x1 << I40E_PRT_MNG_MFUTP_UDP_SHIFT) +#define I40E_PRT_MNG_MFUTP_UDP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MFUTP_UDP_SHIFT) #define I40E_PRT_MNG_MFUTP_TCP_SHIFT 17 -#define I40E_PRT_MNG_MFUTP_TCP_MASK (0x1 << I40E_PRT_MNG_MFUTP_TCP_SHIFT) +#define I40E_PRT_MNG_MFUTP_TCP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MFUTP_TCP_SHIFT) #define I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_SHIFT 18 -#define I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_MASK (0x1 << I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_SHIFT) -#define I40E_PRT_MNG_MIPAF4(_i) (0x00256280 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_MASK I40E_MASK(0x1, I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_SHIFT) +#define I40E_PRT_MNG_MIPAF4(_i) (0x00256280 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ #define I40E_PRT_MNG_MIPAF4_MAX_INDEX 3 #define I40E_PRT_MNG_MIPAF4_MIPAF_SHIFT 0 -#define I40E_PRT_MNG_MIPAF4_MIPAF_MASK (0xFFFFFFFF << I40E_PRT_MNG_MIPAF4_MIPAF_SHIFT) -#define I40E_PRT_MNG_MIPAF6(_i) (0x00254200 + ((_i) * 32)) /* _i=0...15 */ +#define I40E_PRT_MNG_MIPAF4_MIPAF_MASK I40E_MASK(0xFFFFFFFF, I40E_PRT_MNG_MIPAF4_MIPAF_SHIFT) +#define I40E_PRT_MNG_MIPAF6(_i) (0x00254200 + ((_i) * 32)) /* _i=0...15 */ /* Reset: POR */ #define I40E_PRT_MNG_MIPAF6_MAX_INDEX 15 #define I40E_PRT_MNG_MIPAF6_MIPAF_SHIFT 0 -#define I40E_PRT_MNG_MIPAF6_MIPAF_MASK (0xFFFFFFFF << I40E_PRT_MNG_MIPAF6_MIPAF_SHIFT) -#define I40E_PRT_MNG_MMAH(_i) (0x00256380 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRT_MNG_MIPAF6_MIPAF_MASK I40E_MASK(0xFFFFFFFF, I40E_PRT_MNG_MIPAF6_MIPAF_SHIFT) +#define I40E_PRT_MNG_MMAH(_i) (0x00256380 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ #define I40E_PRT_MNG_MMAH_MAX_INDEX 3 #define I40E_PRT_MNG_MMAH_MMAH_SHIFT 0 -#define I40E_PRT_MNG_MMAH_MMAH_MASK (0xFFFF << I40E_PRT_MNG_MMAH_MMAH_SHIFT) -#define I40E_PRT_MNG_MMAL(_i) (0x00256480 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRT_MNG_MMAH_MMAH_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MMAH_MMAH_SHIFT) +#define I40E_PRT_MNG_MMAL(_i) (0x00256480 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ #define I40E_PRT_MNG_MMAL_MAX_INDEX 3 #define I40E_PRT_MNG_MMAL_MMAL_SHIFT 0 -#define I40E_PRT_MNG_MMAL_MMAL_MASK (0xFFFFFFFF << I40E_PRT_MNG_MMAL_MMAL_SHIFT) -#define I40E_PRT_MNG_MNGONLY 0x00256A60 +#define I40E_PRT_MNG_MMAL_MMAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PRT_MNG_MMAL_MMAL_SHIFT) +#define I40E_PRT_MNG_MNGONLY 0x00256A60 /* Reset: POR */ #define I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_SHIFT 0 -#define I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_MASK (0xFF << I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_SHIFT) -#define I40E_PRT_MNG_MSFM 0x00256AA0 +#define I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_MASK I40E_MASK(0xFF, I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_SHIFT) +#define I40E_PRT_MNG_MSFM 0x00256AA0 /* Reset: POR */ #define I40E_PRT_MNG_MSFM_PORT_26F_UDP_SHIFT 0 -#define I40E_PRT_MNG_MSFM_PORT_26F_UDP_MASK (0x1 << I40E_PRT_MNG_MSFM_PORT_26F_UDP_SHIFT) +#define I40E_PRT_MNG_MSFM_PORT_26F_UDP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_PORT_26F_UDP_SHIFT) #define I40E_PRT_MNG_MSFM_PORT_26F_TCP_SHIFT 1 -#define I40E_PRT_MNG_MSFM_PORT_26F_TCP_MASK (0x1 << I40E_PRT_MNG_MSFM_PORT_26F_TCP_SHIFT) +#define I40E_PRT_MNG_MSFM_PORT_26F_TCP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_PORT_26F_TCP_SHIFT) #define I40E_PRT_MNG_MSFM_PORT_298_UDP_SHIFT 2 -#define I40E_PRT_MNG_MSFM_PORT_298_UDP_MASK (0x1 << I40E_PRT_MNG_MSFM_PORT_298_UDP_SHIFT) +#define I40E_PRT_MNG_MSFM_PORT_298_UDP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_PORT_298_UDP_SHIFT) #define I40E_PRT_MNG_MSFM_PORT_298_TCP_SHIFT 3 -#define I40E_PRT_MNG_MSFM_PORT_298_TCP_MASK (0x1 << I40E_PRT_MNG_MSFM_PORT_298_TCP_SHIFT) +#define I40E_PRT_MNG_MSFM_PORT_298_TCP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_PORT_298_TCP_SHIFT) #define I40E_PRT_MNG_MSFM_IPV6_0_MASK_SHIFT 4 -#define I40E_PRT_MNG_MSFM_IPV6_0_MASK_MASK (0x1 << I40E_PRT_MNG_MSFM_IPV6_0_MASK_SHIFT) +#define I40E_PRT_MNG_MSFM_IPV6_0_MASK_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_IPV6_0_MASK_SHIFT) #define I40E_PRT_MNG_MSFM_IPV6_1_MASK_SHIFT 5 -#define I40E_PRT_MNG_MSFM_IPV6_1_MASK_MASK (0x1 << I40E_PRT_MNG_MSFM_IPV6_1_MASK_SHIFT) +#define I40E_PRT_MNG_MSFM_IPV6_1_MASK_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_IPV6_1_MASK_SHIFT) #define I40E_PRT_MNG_MSFM_IPV6_2_MASK_SHIFT 6 -#define I40E_PRT_MNG_MSFM_IPV6_2_MASK_MASK (0x1 << I40E_PRT_MNG_MSFM_IPV6_2_MASK_SHIFT) +#define I40E_PRT_MNG_MSFM_IPV6_2_MASK_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_IPV6_2_MASK_SHIFT) #define I40E_PRT_MNG_MSFM_IPV6_3_MASK_SHIFT 7 -#define I40E_PRT_MNG_MSFM_IPV6_3_MASK_MASK (0x1 << I40E_PRT_MNG_MSFM_IPV6_3_MASK_SHIFT) -#define I40E_MSIX_PBA(_i) (0x00004900 + ((_i) * 4)) /* _i=0...5 */ +#define I40E_PRT_MNG_MSFM_IPV6_3_MASK_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_IPV6_3_MASK_SHIFT) +#define I40E_MSIX_PBA(_i) (0x00001000 + ((_i) * 4)) /* _i=0...5 */ /* Reset: FLR */ #define I40E_MSIX_PBA_MAX_INDEX 5 #define I40E_MSIX_PBA_PENBIT_SHIFT 0 -#define I40E_MSIX_PBA_PENBIT_MASK (0xFFFFFFFF << I40E_MSIX_PBA_PENBIT_SHIFT) -#define I40E_MSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...128 */ +#define I40E_MSIX_PBA_PENBIT_MASK I40E_MASK(0xFFFFFFFF, I40E_MSIX_PBA_PENBIT_SHIFT) +#define I40E_MSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...128 */ /* Reset: FLR */ #define I40E_MSIX_TADD_MAX_INDEX 128 #define I40E_MSIX_TADD_MSIXTADD10_SHIFT 0 -#define I40E_MSIX_TADD_MSIXTADD10_MASK (0x3 << I40E_MSIX_TADD_MSIXTADD10_SHIFT) +#define I40E_MSIX_TADD_MSIXTADD10_MASK I40E_MASK(0x3, I40E_MSIX_TADD_MSIXTADD10_SHIFT) #define I40E_MSIX_TADD_MSIXTADD_SHIFT 2 -#define I40E_MSIX_TADD_MSIXTADD_MASK (0x3FFFFFFF << I40E_MSIX_TADD_MSIXTADD_SHIFT) -#define I40E_MSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...128 */ +#define I40E_MSIX_TADD_MSIXTADD_MASK I40E_MASK(0x3FFFFFFF, I40E_MSIX_TADD_MSIXTADD_SHIFT) +#define I40E_MSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...128 */ /* Reset: FLR */ #define I40E_MSIX_TMSG_MAX_INDEX 128 #define I40E_MSIX_TMSG_MSIXTMSG_SHIFT 0 -#define I40E_MSIX_TMSG_MSIXTMSG_MASK (0xFFFFFFFF << I40E_MSIX_TMSG_MSIXTMSG_SHIFT) -#define I40E_MSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...128 */ +#define I40E_MSIX_TMSG_MSIXTMSG_MASK I40E_MASK(0xFFFFFFFF, I40E_MSIX_TMSG_MSIXTMSG_SHIFT) +#define I40E_MSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...128 */ /* Reset: FLR */ #define I40E_MSIX_TUADD_MAX_INDEX 128 #define I40E_MSIX_TUADD_MSIXTUADD_SHIFT 0 -#define I40E_MSIX_TUADD_MSIXTUADD_MASK (0xFFFFFFFF << I40E_MSIX_TUADD_MSIXTUADD_SHIFT) -#define I40E_MSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...128 */ +#define I40E_MSIX_TUADD_MSIXTUADD_MASK I40E_MASK(0xFFFFFFFF, I40E_MSIX_TUADD_MSIXTUADD_SHIFT) +#define I40E_MSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...128 */ /* Reset: FLR */ #define I40E_MSIX_TVCTRL_MAX_INDEX 128 #define I40E_MSIX_TVCTRL_MASK_SHIFT 0 -#define I40E_MSIX_TVCTRL_MASK_MASK (0x1 << I40E_MSIX_TVCTRL_MASK_SHIFT) -#define I40E_VFMSIX_PBA1(_i) (0x00004944 + ((_i) * 4)) /* _i=0...19 */ +#define I40E_MSIX_TVCTRL_MASK_MASK I40E_MASK(0x1, I40E_MSIX_TVCTRL_MASK_SHIFT) +#define I40E_VFMSIX_PBA1(_i) (0x00002000 + ((_i) * 4)) /* _i=0...19 */ /* Reset: VFLR */ #define I40E_VFMSIX_PBA1_MAX_INDEX 19 #define I40E_VFMSIX_PBA1_PENBIT_SHIFT 0 -#define I40E_VFMSIX_PBA1_PENBIT_MASK (0xFFFFFFFF << I40E_VFMSIX_PBA1_PENBIT_SHIFT) -#define I40E_VFMSIX_TADD1(_i) (0x00002100 + ((_i) * 16)) /* _i=0...639 */ +#define I40E_VFMSIX_PBA1_PENBIT_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_PBA1_PENBIT_SHIFT) +#define I40E_VFMSIX_TADD1(_i) (0x00002100 + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */ #define I40E_VFMSIX_TADD1_MAX_INDEX 639 #define I40E_VFMSIX_TADD1_MSIXTADD10_SHIFT 0 -#define I40E_VFMSIX_TADD1_MSIXTADD10_MASK (0x3 << I40E_VFMSIX_TADD1_MSIXTADD10_SHIFT) +#define I40E_VFMSIX_TADD1_MSIXTADD10_MASK I40E_MASK(0x3, I40E_VFMSIX_TADD1_MSIXTADD10_SHIFT) #define I40E_VFMSIX_TADD1_MSIXTADD_SHIFT 2 -#define I40E_VFMSIX_TADD1_MSIXTADD_MASK (0x3FFFFFFF << I40E_VFMSIX_TADD1_MSIXTADD_SHIFT) -#define I40E_VFMSIX_TMSG1(_i) (0x00002108 + ((_i) * 16)) /* _i=0...639 */ +#define I40E_VFMSIX_TADD1_MSIXTADD_MASK I40E_MASK(0x3FFFFFFF, I40E_VFMSIX_TADD1_MSIXTADD_SHIFT) +#define I40E_VFMSIX_TMSG1(_i) (0x00002108 + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */ #define I40E_VFMSIX_TMSG1_MAX_INDEX 639 #define I40E_VFMSIX_TMSG1_MSIXTMSG_SHIFT 0 -#define I40E_VFMSIX_TMSG1_MSIXTMSG_MASK (0xFFFFFFFF << I40E_VFMSIX_TMSG1_MSIXTMSG_SHIFT) -#define I40E_VFMSIX_TUADD1(_i) (0x00002104 + ((_i) * 16)) /* _i=0...639 */ +#define I40E_VFMSIX_TMSG1_MSIXTMSG_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TMSG1_MSIXTMSG_SHIFT) +#define I40E_VFMSIX_TUADD1(_i) (0x00002104 + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */ #define I40E_VFMSIX_TUADD1_MAX_INDEX 639 #define I40E_VFMSIX_TUADD1_MSIXTUADD_SHIFT 0 -#define I40E_VFMSIX_TUADD1_MSIXTUADD_MASK (0xFFFFFFFF << I40E_VFMSIX_TUADD1_MSIXTUADD_SHIFT) -#define I40E_VFMSIX_TVCTRL1(_i) (0x0000210C + ((_i) * 16)) /* _i=0...639 */ +#define I40E_VFMSIX_TUADD1_MSIXTUADD_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TUADD1_MSIXTUADD_SHIFT) +#define I40E_VFMSIX_TVCTRL1(_i) (0x0000210C + ((_i) * 16)) /* _i=0...639 */ /* Reset: VFLR */ #define I40E_VFMSIX_TVCTRL1_MAX_INDEX 639 #define I40E_VFMSIX_TVCTRL1_MASK_SHIFT 0 -#define I40E_VFMSIX_TVCTRL1_MASK_MASK (0x1 << I40E_VFMSIX_TVCTRL1_MASK_SHIFT) -#define I40E_GLNVM_FLA 0x000B6108 +#define I40E_VFMSIX_TVCTRL1_MASK_MASK I40E_MASK(0x1, I40E_VFMSIX_TVCTRL1_MASK_SHIFT) +#define I40E_GLNVM_FLA 0x000B6108 /* Reset: POR */ #define I40E_GLNVM_FLA_FL_SCK_SHIFT 0 -#define I40E_GLNVM_FLA_FL_SCK_MASK (0x1 << I40E_GLNVM_FLA_FL_SCK_SHIFT) +#define I40E_GLNVM_FLA_FL_SCK_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_SCK_SHIFT) #define I40E_GLNVM_FLA_FL_CE_SHIFT 1 -#define I40E_GLNVM_FLA_FL_CE_MASK (0x1 << I40E_GLNVM_FLA_FL_CE_SHIFT) +#define I40E_GLNVM_FLA_FL_CE_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_CE_SHIFT) #define I40E_GLNVM_FLA_FL_SI_SHIFT 2 -#define I40E_GLNVM_FLA_FL_SI_MASK (0x1 << I40E_GLNVM_FLA_FL_SI_SHIFT) +#define I40E_GLNVM_FLA_FL_SI_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_SI_SHIFT) #define I40E_GLNVM_FLA_FL_SO_SHIFT 3 -#define I40E_GLNVM_FLA_FL_SO_MASK (0x1 << I40E_GLNVM_FLA_FL_SO_SHIFT) +#define I40E_GLNVM_FLA_FL_SO_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_SO_SHIFT) #define I40E_GLNVM_FLA_FL_REQ_SHIFT 4 -#define I40E_GLNVM_FLA_FL_REQ_MASK (0x1 << I40E_GLNVM_FLA_FL_REQ_SHIFT) +#define I40E_GLNVM_FLA_FL_REQ_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_REQ_SHIFT) #define I40E_GLNVM_FLA_FL_GNT_SHIFT 5 -#define I40E_GLNVM_FLA_FL_GNT_MASK (0x1 << I40E_GLNVM_FLA_FL_GNT_SHIFT) +#define I40E_GLNVM_FLA_FL_GNT_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_GNT_SHIFT) #define I40E_GLNVM_FLA_LOCKED_SHIFT 6 -#define I40E_GLNVM_FLA_LOCKED_MASK (0x1 << I40E_GLNVM_FLA_LOCKED_SHIFT) +#define I40E_GLNVM_FLA_LOCKED_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_LOCKED_SHIFT) #define I40E_GLNVM_FLA_FL_SADDR_SHIFT 18 -#define I40E_GLNVM_FLA_FL_SADDR_MASK (0x7FF << I40E_GLNVM_FLA_FL_SADDR_SHIFT) +#define I40E_GLNVM_FLA_FL_SADDR_MASK I40E_MASK(0x7FF, I40E_GLNVM_FLA_FL_SADDR_SHIFT) #define I40E_GLNVM_FLA_FL_BUSY_SHIFT 30 -#define I40E_GLNVM_FLA_FL_BUSY_MASK (0x1 << I40E_GLNVM_FLA_FL_BUSY_SHIFT) +#define I40E_GLNVM_FLA_FL_BUSY_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_BUSY_SHIFT) #define I40E_GLNVM_FLA_FL_DER_SHIFT 31 -#define I40E_GLNVM_FLA_FL_DER_MASK (0x1 << I40E_GLNVM_FLA_FL_DER_SHIFT) -#define I40E_GLNVM_FLASHID 0x000B6104 +#define I40E_GLNVM_FLA_FL_DER_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_DER_SHIFT) +#define I40E_GLNVM_FLASHID 0x000B6104 /* Reset: POR */ #define I40E_GLNVM_FLASHID_FLASHID_SHIFT 0 -#define I40E_GLNVM_FLASHID_FLASHID_MASK (0xFFFFFF << I40E_GLNVM_FLASHID_FLASHID_SHIFT) -#define I40E_GLNVM_GENS 0x000B6100 +#define I40E_GLNVM_FLASHID_FLASHID_MASK I40E_MASK(0xFFFFFF, I40E_GLNVM_FLASHID_FLASHID_SHIFT) +#define I40E_GLNVM_FLASHID_FLEEP_PERF_SHIFT 31 +#define I40E_GLNVM_FLASHID_FLEEP_PERF_MASK I40E_MASK(0x1, I40E_GLNVM_FLASHID_FLEEP_PERF_SHIFT) +#define I40E_GLNVM_GENS 0x000B6100 /* Reset: POR */ #define I40E_GLNVM_GENS_NVM_PRES_SHIFT 0 -#define I40E_GLNVM_GENS_NVM_PRES_MASK (0x1 << I40E_GLNVM_GENS_NVM_PRES_SHIFT) +#define I40E_GLNVM_GENS_NVM_PRES_MASK I40E_MASK(0x1, I40E_GLNVM_GENS_NVM_PRES_SHIFT) #define I40E_GLNVM_GENS_SR_SIZE_SHIFT 5 -#define I40E_GLNVM_GENS_SR_SIZE_MASK (0x7 << I40E_GLNVM_GENS_SR_SIZE_SHIFT) +#define I40E_GLNVM_GENS_SR_SIZE_MASK I40E_MASK(0x7, I40E_GLNVM_GENS_SR_SIZE_SHIFT) #define I40E_GLNVM_GENS_BANK1VAL_SHIFT 8 -#define I40E_GLNVM_GENS_BANK1VAL_MASK (0x1 << I40E_GLNVM_GENS_BANK1VAL_SHIFT) +#define I40E_GLNVM_GENS_BANK1VAL_MASK I40E_MASK(0x1, I40E_GLNVM_GENS_BANK1VAL_SHIFT) #define I40E_GLNVM_GENS_ALT_PRST_SHIFT 23 -#define I40E_GLNVM_GENS_ALT_PRST_MASK (0x1 << I40E_GLNVM_GENS_ALT_PRST_SHIFT) +#define I40E_GLNVM_GENS_ALT_PRST_MASK I40E_MASK(0x1, I40E_GLNVM_GENS_ALT_PRST_SHIFT) #define I40E_GLNVM_GENS_FL_AUTO_RD_SHIFT 25 -#define I40E_GLNVM_GENS_FL_AUTO_RD_MASK (0x1 << I40E_GLNVM_GENS_FL_AUTO_RD_SHIFT) -#define I40E_GLNVM_PROTCSR(_i) (0x000B6010 + ((_i) * 4)) /* _i=0...59 */ +#define I40E_GLNVM_GENS_FL_AUTO_RD_MASK I40E_MASK(0x1, I40E_GLNVM_GENS_FL_AUTO_RD_SHIFT) +#define I40E_GLNVM_PROTCSR(_i) (0x000B6010 + ((_i) * 4)) /* _i=0...59 */ /* Reset: POR */ #define I40E_GLNVM_PROTCSR_MAX_INDEX 59 #define I40E_GLNVM_PROTCSR_ADDR_BLOCK_SHIFT 0 -#define I40E_GLNVM_PROTCSR_ADDR_BLOCK_MASK (0xFFFFFF << I40E_GLNVM_PROTCSR_ADDR_BLOCK_SHIFT) -#define I40E_GLNVM_SRCTL 0x000B6110 +#define I40E_GLNVM_PROTCSR_ADDR_BLOCK_MASK I40E_MASK(0xFFFFFF, I40E_GLNVM_PROTCSR_ADDR_BLOCK_SHIFT) +#define I40E_GLNVM_SRCTL 0x000B6110 /* Reset: POR */ #define I40E_GLNVM_SRCTL_SRBUSY_SHIFT 0 -#define I40E_GLNVM_SRCTL_SRBUSY_MASK (0x1 << I40E_GLNVM_SRCTL_SRBUSY_SHIFT) +#define I40E_GLNVM_SRCTL_SRBUSY_MASK I40E_MASK(0x1, I40E_GLNVM_SRCTL_SRBUSY_SHIFT) #define I40E_GLNVM_SRCTL_ADDR_SHIFT 14 -#define I40E_GLNVM_SRCTL_ADDR_MASK (0x7FFF << I40E_GLNVM_SRCTL_ADDR_SHIFT) +#define I40E_GLNVM_SRCTL_ADDR_MASK I40E_MASK(0x7FFF, I40E_GLNVM_SRCTL_ADDR_SHIFT) #define I40E_GLNVM_SRCTL_WRITE_SHIFT 29 -#define I40E_GLNVM_SRCTL_WRITE_MASK (0x1 << I40E_GLNVM_SRCTL_WRITE_SHIFT) +#define I40E_GLNVM_SRCTL_WRITE_MASK I40E_MASK(0x1, I40E_GLNVM_SRCTL_WRITE_SHIFT) #define I40E_GLNVM_SRCTL_START_SHIFT 30 -#define I40E_GLNVM_SRCTL_START_MASK (0x1 << I40E_GLNVM_SRCTL_START_SHIFT) +#define I40E_GLNVM_SRCTL_START_MASK I40E_MASK(0x1, I40E_GLNVM_SRCTL_START_SHIFT) #define I40E_GLNVM_SRCTL_DONE_SHIFT 31 -#define I40E_GLNVM_SRCTL_DONE_MASK (0x1 << I40E_GLNVM_SRCTL_DONE_SHIFT) -#define I40E_GLNVM_SRDATA 0x000B6114 +#define I40E_GLNVM_SRCTL_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_SRCTL_DONE_SHIFT) +#define I40E_GLNVM_SRDATA 0x000B6114 /* Reset: POR */ #define I40E_GLNVM_SRDATA_WRDATA_SHIFT 0 -#define I40E_GLNVM_SRDATA_WRDATA_MASK (0xFFFF << I40E_GLNVM_SRDATA_WRDATA_SHIFT) +#define I40E_GLNVM_SRDATA_WRDATA_MASK I40E_MASK(0xFFFF, I40E_GLNVM_SRDATA_WRDATA_SHIFT) #define I40E_GLNVM_SRDATA_RDDATA_SHIFT 16 -#define I40E_GLNVM_SRDATA_RDDATA_MASK (0xFFFF << I40E_GLNVM_SRDATA_RDDATA_SHIFT) -#define I40E_GLNVM_ULD 0x000B6008 +#define I40E_GLNVM_SRDATA_RDDATA_MASK I40E_MASK(0xFFFF, I40E_GLNVM_SRDATA_RDDATA_SHIFT) +#define I40E_GLNVM_ULD 0x000B6008 /* Reset: POR */ #define I40E_GLNVM_ULD_CONF_PCIR_DONE_SHIFT 0 -#define I40E_GLNVM_ULD_CONF_PCIR_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_PCIR_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_PCIR_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PCIR_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_PCIRTL_DONE_SHIFT 1 -#define I40E_GLNVM_ULD_CONF_PCIRTL_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_PCIRTL_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_PCIRTL_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PCIRTL_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_LCB_DONE_SHIFT 2 -#define I40E_GLNVM_ULD_CONF_LCB_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_LCB_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_LCB_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_LCB_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_CORE_DONE_SHIFT 3 -#define I40E_GLNVM_ULD_CONF_CORE_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_CORE_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_CORE_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_CORE_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_GLOBAL_DONE_SHIFT 4 -#define I40E_GLNVM_ULD_CONF_GLOBAL_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_GLOBAL_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_GLOBAL_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_GLOBAL_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_POR_DONE_SHIFT 5 -#define I40E_GLNVM_ULD_CONF_POR_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_POR_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_POR_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_POR_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_SHIFT 6 -#define I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_SHIFT 7 -#define I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_EMP_DONE_SHIFT 8 -#define I40E_GLNVM_ULD_CONF_EMP_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_EMP_DONE_SHIFT) +#define I40E_GLNVM_ULD_CONF_EMP_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_EMP_DONE_SHIFT) #define I40E_GLNVM_ULD_CONF_PCIALT_DONE_SHIFT 9 -#define I40E_GLNVM_ULD_CONF_PCIALT_DONE_MASK (0x1 << I40E_GLNVM_ULD_CONF_PCIALT_DONE_SHIFT) - -#define I40E_GLPCI_BYTCTH 0x0009C484 +#define I40E_GLNVM_ULD_CONF_PCIALT_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PCIALT_DONE_SHIFT) +#define I40E_GLPCI_BYTCTH 0x0009C484 /* Reset: PCIR */ #define I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_SHIFT 0 -#define I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_MASK (0xFFFFFFFF << I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_SHIFT) -#define I40E_GLPCI_BYTCTL 0x0009C488 +#define I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_SHIFT) +#define I40E_GLPCI_BYTCTL 0x0009C488 /* Reset: PCIR */ #define I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_SHIFT 0 -#define I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_MASK (0xFFFFFFFF << I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_SHIFT) -#define I40E_GLPCI_CAPCTRL 0x000BE4A4 +#define I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_SHIFT) +#define I40E_GLPCI_CAPCTRL 0x000BE4A4 /* Reset: PCIR */ #define I40E_GLPCI_CAPCTRL_VPD_EN_SHIFT 0 -#define I40E_GLPCI_CAPCTRL_VPD_EN_MASK (0x1 << I40E_GLPCI_CAPCTRL_VPD_EN_SHIFT) -#define I40E_GLPCI_CAPSUP 0x000BE4A8 +#define I40E_GLPCI_CAPCTRL_VPD_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPCTRL_VPD_EN_SHIFT) +#define I40E_GLPCI_CAPSUP 0x000BE4A8 /* Reset: PCIR */ #define I40E_GLPCI_CAPSUP_PCIE_VER_SHIFT 0 -#define I40E_GLPCI_CAPSUP_PCIE_VER_MASK (0x1 << I40E_GLPCI_CAPSUP_PCIE_VER_SHIFT) +#define I40E_GLPCI_CAPSUP_PCIE_VER_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_PCIE_VER_SHIFT) #define I40E_GLPCI_CAPSUP_LTR_EN_SHIFT 2 -#define I40E_GLPCI_CAPSUP_LTR_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_LTR_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_LTR_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_LTR_EN_SHIFT) #define I40E_GLPCI_CAPSUP_TPH_EN_SHIFT 3 -#define I40E_GLPCI_CAPSUP_TPH_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_TPH_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_TPH_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_TPH_EN_SHIFT) #define I40E_GLPCI_CAPSUP_ARI_EN_SHIFT 4 -#define I40E_GLPCI_CAPSUP_ARI_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_ARI_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_ARI_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_ARI_EN_SHIFT) #define I40E_GLPCI_CAPSUP_IOV_EN_SHIFT 5 -#define I40E_GLPCI_CAPSUP_IOV_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_IOV_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_IOV_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_IOV_EN_SHIFT) #define I40E_GLPCI_CAPSUP_ACS_EN_SHIFT 6 -#define I40E_GLPCI_CAPSUP_ACS_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_ACS_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_ACS_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_ACS_EN_SHIFT) #define I40E_GLPCI_CAPSUP_SEC_EN_SHIFT 7 -#define I40E_GLPCI_CAPSUP_SEC_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_SEC_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_SEC_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_SEC_EN_SHIFT) #define I40E_GLPCI_CAPSUP_ECRC_GEN_EN_SHIFT 16 -#define I40E_GLPCI_CAPSUP_ECRC_GEN_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_ECRC_GEN_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_ECRC_GEN_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_ECRC_GEN_EN_SHIFT) #define I40E_GLPCI_CAPSUP_ECRC_CHK_EN_SHIFT 17 -#define I40E_GLPCI_CAPSUP_ECRC_CHK_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_ECRC_CHK_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_ECRC_CHK_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_ECRC_CHK_EN_SHIFT) #define I40E_GLPCI_CAPSUP_IDO_EN_SHIFT 18 -#define I40E_GLPCI_CAPSUP_IDO_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_IDO_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_IDO_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_IDO_EN_SHIFT) #define I40E_GLPCI_CAPSUP_MSI_MASK_SHIFT 19 -#define I40E_GLPCI_CAPSUP_MSI_MASK_MASK (0x1 << I40E_GLPCI_CAPSUP_MSI_MASK_SHIFT) +#define I40E_GLPCI_CAPSUP_MSI_MASK_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_MSI_MASK_SHIFT) #define I40E_GLPCI_CAPSUP_CSR_CONF_EN_SHIFT 20 -#define I40E_GLPCI_CAPSUP_CSR_CONF_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_CSR_CONF_EN_SHIFT) +#define I40E_GLPCI_CAPSUP_CSR_CONF_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_CSR_CONF_EN_SHIFT) #define I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_SHIFT 30 -#define I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_MASK (0x1 << I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_SHIFT) +#define I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_SHIFT) #define I40E_GLPCI_CAPSUP_LOAD_DEV_ID_SHIFT 31 -#define I40E_GLPCI_CAPSUP_LOAD_DEV_ID_MASK (0x1 << I40E_GLPCI_CAPSUP_LOAD_DEV_ID_SHIFT) -#define I40E_GLPCI_CNF 0x000BE4C0 +#define I40E_GLPCI_CAPSUP_LOAD_DEV_ID_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_LOAD_DEV_ID_SHIFT) +#define I40E_GLPCI_CNF 0x000BE4C0 /* Reset: POR */ #define I40E_GLPCI_CNF_FLEX10_SHIFT 1 -#define I40E_GLPCI_CNF_FLEX10_MASK (0x1 << I40E_GLPCI_CNF_FLEX10_SHIFT) +#define I40E_GLPCI_CNF_FLEX10_MASK I40E_MASK(0x1, I40E_GLPCI_CNF_FLEX10_SHIFT) #define I40E_GLPCI_CNF_WAKE_PIN_EN_SHIFT 2 -#define I40E_GLPCI_CNF_WAKE_PIN_EN_MASK (0x1 << I40E_GLPCI_CNF_WAKE_PIN_EN_SHIFT) -#define I40E_GLPCI_CNF2 0x000BE494 +#define I40E_GLPCI_CNF_WAKE_PIN_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CNF_WAKE_PIN_EN_SHIFT) +#define I40E_GLPCI_CNF2 0x000BE494 /* Reset: PCIR */ #define I40E_GLPCI_CNF2_RO_DIS_SHIFT 0 -#define I40E_GLPCI_CNF2_RO_DIS_MASK (0x1 << I40E_GLPCI_CNF2_RO_DIS_SHIFT) +#define I40E_GLPCI_CNF2_RO_DIS_MASK I40E_MASK(0x1, I40E_GLPCI_CNF2_RO_DIS_SHIFT) #define I40E_GLPCI_CNF2_CACHELINE_SIZE_SHIFT 1 -#define I40E_GLPCI_CNF2_CACHELINE_SIZE_MASK (0x1 << I40E_GLPCI_CNF2_CACHELINE_SIZE_SHIFT) +#define I40E_GLPCI_CNF2_CACHELINE_SIZE_MASK I40E_MASK(0x1, I40E_GLPCI_CNF2_CACHELINE_SIZE_SHIFT) #define I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT 2 -#define I40E_GLPCI_CNF2_MSI_X_PF_N_MASK (0x7FF << I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT) +#define I40E_GLPCI_CNF2_MSI_X_PF_N_MASK I40E_MASK(0x7FF, I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT) #define I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT 13 -#define I40E_GLPCI_CNF2_MSI_X_VF_N_MASK (0x7FF << I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT) -#define I40E_GLPCI_DREVID 0x0009C480 +#define I40E_GLPCI_CNF2_MSI_X_VF_N_MASK I40E_MASK(0x7FF, I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT) +#define I40E_GLPCI_DREVID 0x0009C480 /* Reset: PCIR */ #define I40E_GLPCI_DREVID_DEFAULT_REVID_SHIFT 0 -#define I40E_GLPCI_DREVID_DEFAULT_REVID_MASK (0xFF << I40E_GLPCI_DREVID_DEFAULT_REVID_SHIFT) -#define I40E_GLPCI_GSCL_1 0x0009C48C +#define I40E_GLPCI_DREVID_DEFAULT_REVID_MASK I40E_MASK(0xFF, I40E_GLPCI_DREVID_DEFAULT_REVID_SHIFT) +#define I40E_GLPCI_GSCL_1 0x0009C48C /* Reset: PCIR */ #define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_SHIFT 0 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_SHIFT 1 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_SHIFT 2 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_SHIFT 3 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_SHIFT) #define I40E_GLPCI_GSCL_1_LBC_ENABLE_0_SHIFT 4 -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_0_MASK (0x1 << I40E_GLPCI_GSCL_1_LBC_ENABLE_0_SHIFT) +#define I40E_GLPCI_GSCL_1_LBC_ENABLE_0_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_LBC_ENABLE_0_SHIFT) #define I40E_GLPCI_GSCL_1_LBC_ENABLE_1_SHIFT 5 -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_1_MASK (0x1 << I40E_GLPCI_GSCL_1_LBC_ENABLE_1_SHIFT) +#define I40E_GLPCI_GSCL_1_LBC_ENABLE_1_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_LBC_ENABLE_1_SHIFT) #define I40E_GLPCI_GSCL_1_LBC_ENABLE_2_SHIFT 6 -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_2_MASK (0x1 << I40E_GLPCI_GSCL_1_LBC_ENABLE_2_SHIFT) +#define I40E_GLPCI_GSCL_1_LBC_ENABLE_2_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_LBC_ENABLE_2_SHIFT) #define I40E_GLPCI_GSCL_1_LBC_ENABLE_3_SHIFT 7 -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_3_MASK (0x1 << I40E_GLPCI_GSCL_1_LBC_ENABLE_3_SHIFT) +#define I40E_GLPCI_GSCL_1_LBC_ENABLE_3_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_LBC_ENABLE_3_SHIFT) #define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_SHIFT 8 -#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_MASK (0x1 << I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_SHIFT) +#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_SHIFT) #define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_SHIFT 9 -#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_MASK (0x1F << I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_SHIFT) +#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_MASK I40E_MASK(0x1F, I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_SHIFT) #define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_SHIFT 14 -#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_MASK (0x1 << I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_SHIFT) +#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_SHIFT) #define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_SHIFT 15 -#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_MASK (0x1F << I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_SHIFT) +#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_MASK I40E_MASK(0x1F, I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_SHIFT 28 -#define I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_SHIFT 29 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_SHIFT 30 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_SHIFT) +#define I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_SHIFT) #define I40E_GLPCI_GSCL_1_GIO_COUNT_START_SHIFT 31 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_START_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_START_SHIFT) -#define I40E_GLPCI_GSCL_2 0x0009C490 +#define I40E_GLPCI_GSCL_1_GIO_COUNT_START_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_START_SHIFT) +#define I40E_GLPCI_GSCL_2 0x0009C490 /* Reset: PCIR */ #define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_SHIFT 0 -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_MASK (0xFF << I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_SHIFT) +#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_MASK I40E_MASK(0xFF, I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_SHIFT) #define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_SHIFT 8 -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_MASK (0xFF << I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_SHIFT) +#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_MASK I40E_MASK(0xFF, I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_SHIFT) #define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_SHIFT 16 -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_MASK (0xFF << I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_SHIFT) +#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_MASK I40E_MASK(0xFF, I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_SHIFT) #define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_SHIFT 24 -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_MASK (0xFF << I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_SHIFT) -#define I40E_GLPCI_GSCL_5_8(_i) (0x0009C494 + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_MASK I40E_MASK(0xFF, I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_SHIFT) +#define I40E_GLPCI_GSCL_5_8(_i) (0x0009C494 + ((_i) * 4)) /* _i=0...3 */ /* Reset: PCIR */ #define I40E_GLPCI_GSCL_5_8_MAX_INDEX 3 #define I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_SHIFT 0 -#define I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_MASK (0xFFFF << I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_SHIFT) +#define I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_MASK I40E_MASK(0xFFFF, I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_SHIFT) #define I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_SHIFT 16 -#define I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_MASK (0xFFFF << I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_SHIFT) -#define I40E_GLPCI_GSCN_0_3(_i) (0x0009C4A4 + ((_i) * 4)) /* _i=0...3 */ +#define I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_MASK I40E_MASK(0xFFFF, I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_SHIFT) +#define I40E_GLPCI_GSCN_0_3(_i) (0x0009C4A4 + ((_i) * 4)) /* _i=0...3 */ /* Reset: PCIR */ #define I40E_GLPCI_GSCN_0_3_MAX_INDEX 3 #define I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_SHIFT 0 -#define I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_MASK (0xFFFFFFFF << I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_SHIFT) -#define I40E_GLPCI_LATCT 0x0009C4B4 +#define I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_SHIFT) +#define I40E_GLPCI_LATCT 0x0009C4B4 /* Reset: PCIR */ #define I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_SHIFT 0 -#define I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_MASK (0xFFFFFFFF << I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_SHIFT) -#define I40E_GLPCI_LBARCTRL 0x000BE484 +#define I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_SHIFT) +#define I40E_GLPCI_LBARCTRL 0x000BE484 /* Reset: POR */ #define I40E_GLPCI_LBARCTRL_PREFBAR_SHIFT 0 -#define I40E_GLPCI_LBARCTRL_PREFBAR_MASK (0x1 << I40E_GLPCI_LBARCTRL_PREFBAR_SHIFT) +#define I40E_GLPCI_LBARCTRL_PREFBAR_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_PREFBAR_SHIFT) #define I40E_GLPCI_LBARCTRL_BAR32_SHIFT 1 -#define I40E_GLPCI_LBARCTRL_BAR32_MASK (0x1 << I40E_GLPCI_LBARCTRL_BAR32_SHIFT) +#define I40E_GLPCI_LBARCTRL_BAR32_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_BAR32_SHIFT) #define I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_SHIFT 3 -#define I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_MASK (0x1 << I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_SHIFT) -#define I40E_GLPCI_LBARCTRL_PE_DB_SIZE_SHIFT 4 -#define I40E_GLPCI_LBARCTRL_PE_DB_SIZE_MASK (0x3 << I40E_GLPCI_LBARCTRL_PE_DB_SIZE_SHIFT) +#define I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_SHIFT) +#define I40E_GLPCI_LBARCTRL_RSVD_4_SHIFT 4 +#define I40E_GLPCI_LBARCTRL_RSVD_4_MASK I40E_MASK(0x3, I40E_GLPCI_LBARCTRL_RSVD_4_SHIFT) #define I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT 6 -#define I40E_GLPCI_LBARCTRL_FL_SIZE_MASK (0x7 << I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT) -#define I40E_GLPCI_LBARCTRL_VF_PE_DB_SIZE_SHIFT 10 -#define I40E_GLPCI_LBARCTRL_VF_PE_DB_SIZE_MASK (0x1 << I40E_GLPCI_LBARCTRL_VF_PE_DB_SIZE_SHIFT) +#define I40E_GLPCI_LBARCTRL_FL_SIZE_MASK I40E_MASK(0x7, I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT) +#define I40E_GLPCI_LBARCTRL_RSVD_10_SHIFT 10 +#define I40E_GLPCI_LBARCTRL_RSVD_10_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_RSVD_10_SHIFT) #define I40E_GLPCI_LBARCTRL_EXROM_SIZE_SHIFT 11 -#define I40E_GLPCI_LBARCTRL_EXROM_SIZE_MASK (0x7 << I40E_GLPCI_LBARCTRL_EXROM_SIZE_SHIFT) -#define I40E_GLPCI_LINKCAP 0x000BE4AC +#define I40E_GLPCI_LBARCTRL_EXROM_SIZE_MASK I40E_MASK(0x7, I40E_GLPCI_LBARCTRL_EXROM_SIZE_SHIFT) +#define I40E_GLPCI_LINKCAP 0x000BE4AC /* Reset: PCIR */ #define I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_SHIFT 0 -#define I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_MASK (0x3F << I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_SHIFT) +#define I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_MASK I40E_MASK(0x3F, I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_SHIFT) #define I40E_GLPCI_LINKCAP_MAX_PAYLOAD_SHIFT 6 -#define I40E_GLPCI_LINKCAP_MAX_PAYLOAD_MASK (0x7 << I40E_GLPCI_LINKCAP_MAX_PAYLOAD_SHIFT) +#define I40E_GLPCI_LINKCAP_MAX_PAYLOAD_MASK I40E_MASK(0x7, I40E_GLPCI_LINKCAP_MAX_PAYLOAD_SHIFT) #define I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_SHIFT 9 -#define I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_MASK (0xF << I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_SHIFT) -#define I40E_GLPCI_PCIERR 0x000BE4FC +#define I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_MASK I40E_MASK(0xF, I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_SHIFT) +#define I40E_GLPCI_PCIERR 0x000BE4FC /* Reset: PCIR */ #define I40E_GLPCI_PCIERR_PCIE_ERR_REP_SHIFT 0 -#define I40E_GLPCI_PCIERR_PCIE_ERR_REP_MASK (0xFFFFFFFF << I40E_GLPCI_PCIERR_PCIE_ERR_REP_SHIFT) -#define I40E_GLPCI_PCITEST2 0x000BE4BC -#define I40E_GLPCI_PCITEST2_IOV_TEST_MODE_SHIFT 0 -#define I40E_GLPCI_PCITEST2_IOV_TEST_MODE_MASK (0x1 << I40E_GLPCI_PCITEST2_IOV_TEST_MODE_SHIFT) -#define I40E_GLPCI_PCITEST2_TAG_ALLOC_SHIFT 1 -#define I40E_GLPCI_PCITEST2_TAG_ALLOC_MASK (0x1 << I40E_GLPCI_PCITEST2_TAG_ALLOC_SHIFT) - -#define I40E_GLPCI_PKTCT 0x0009C4BC +#define I40E_GLPCI_PCIERR_PCIE_ERR_REP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_PCIERR_PCIE_ERR_REP_SHIFT) +#define I40E_GLPCI_PKTCT 0x0009C4BC /* Reset: PCIR */ #define I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_SHIFT 0 -#define I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_MASK (0xFFFFFFFF << I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_SHIFT) -#define I40E_GLPCI_PMSUP 0x000BE4B0 +#define I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_SHIFT) +#define I40E_GLPCI_PM_MUX_NPQ 0x0009C4F4 /* Reset: PCIR */ +#define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT 0 +#define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_MASK I40E_MASK(0x7, I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT) +#define I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_SHIFT 16 +#define I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_MASK I40E_MASK(0x1F, I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_SHIFT) +#define I40E_GLPCI_PM_MUX_PFB 0x0009C4F0 /* Reset: PCIR */ +#define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT 0 +#define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_MASK I40E_MASK(0x1F, I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT) +#define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT 16 +#define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_MASK I40E_MASK(0x7, I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT) +#define I40E_GLPCI_PMSUP 0x000BE4B0 /* Reset: PCIR */ #define I40E_GLPCI_PMSUP_ASPM_SUP_SHIFT 0 -#define I40E_GLPCI_PMSUP_ASPM_SUP_MASK (0x3 << I40E_GLPCI_PMSUP_ASPM_SUP_SHIFT) +#define I40E_GLPCI_PMSUP_ASPM_SUP_MASK I40E_MASK(0x3, I40E_GLPCI_PMSUP_ASPM_SUP_SHIFT) #define I40E_GLPCI_PMSUP_L0S_EXIT_LAT_SHIFT 2 -#define I40E_GLPCI_PMSUP_L0S_EXIT_LAT_MASK (0x7 << I40E_GLPCI_PMSUP_L0S_EXIT_LAT_SHIFT) +#define I40E_GLPCI_PMSUP_L0S_EXIT_LAT_MASK I40E_MASK(0x7, I40E_GLPCI_PMSUP_L0S_EXIT_LAT_SHIFT) #define I40E_GLPCI_PMSUP_L1_EXIT_LAT_SHIFT 5 -#define I40E_GLPCI_PMSUP_L1_EXIT_LAT_MASK (0x7 << I40E_GLPCI_PMSUP_L1_EXIT_LAT_SHIFT) +#define I40E_GLPCI_PMSUP_L1_EXIT_LAT_MASK I40E_MASK(0x7, I40E_GLPCI_PMSUP_L1_EXIT_LAT_SHIFT) #define I40E_GLPCI_PMSUP_L0S_ACC_LAT_SHIFT 8 -#define I40E_GLPCI_PMSUP_L0S_ACC_LAT_MASK (0x7 << I40E_GLPCI_PMSUP_L0S_ACC_LAT_SHIFT) +#define I40E_GLPCI_PMSUP_L0S_ACC_LAT_MASK I40E_MASK(0x7, I40E_GLPCI_PMSUP_L0S_ACC_LAT_SHIFT) #define I40E_GLPCI_PMSUP_L1_ACC_LAT_SHIFT 11 -#define I40E_GLPCI_PMSUP_L1_ACC_LAT_MASK (0x7 << I40E_GLPCI_PMSUP_L1_ACC_LAT_SHIFT) +#define I40E_GLPCI_PMSUP_L1_ACC_LAT_MASK I40E_MASK(0x7, I40E_GLPCI_PMSUP_L1_ACC_LAT_SHIFT) #define I40E_GLPCI_PMSUP_SLOT_CLK_SHIFT 14 -#define I40E_GLPCI_PMSUP_SLOT_CLK_MASK (0x1 << I40E_GLPCI_PMSUP_SLOT_CLK_SHIFT) +#define I40E_GLPCI_PMSUP_SLOT_CLK_MASK I40E_MASK(0x1, I40E_GLPCI_PMSUP_SLOT_CLK_SHIFT) #define I40E_GLPCI_PMSUP_OBFF_SUP_SHIFT 15 -#define I40E_GLPCI_PMSUP_OBFF_SUP_MASK (0x3 << I40E_GLPCI_PMSUP_OBFF_SUP_SHIFT) -#define I40E_GLPCI_PWRDATA 0x000BE490 +#define I40E_GLPCI_PMSUP_OBFF_SUP_MASK I40E_MASK(0x3, I40E_GLPCI_PMSUP_OBFF_SUP_SHIFT) +#define I40E_GLPCI_PQ_MAX_USED_SPC 0x0009C4EC /* Reset: PCIR */ +#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_SHIFT 0 +#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_MASK I40E_MASK(0xFF, I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_SHIFT) +#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_SHIFT 8 +#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_MASK I40E_MASK(0xFF, I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_SHIFT) +#define I40E_GLPCI_PWRDATA 0x000BE490 /* Reset: PCIR */ #define I40E_GLPCI_PWRDATA_D0_POWER_SHIFT 0 -#define I40E_GLPCI_PWRDATA_D0_POWER_MASK (0xFF << I40E_GLPCI_PWRDATA_D0_POWER_SHIFT) +#define I40E_GLPCI_PWRDATA_D0_POWER_MASK I40E_MASK(0xFF, I40E_GLPCI_PWRDATA_D0_POWER_SHIFT) #define I40E_GLPCI_PWRDATA_COMM_POWER_SHIFT 8 -#define I40E_GLPCI_PWRDATA_COMM_POWER_MASK (0xFF << I40E_GLPCI_PWRDATA_COMM_POWER_SHIFT) +#define I40E_GLPCI_PWRDATA_COMM_POWER_MASK I40E_MASK(0xFF, I40E_GLPCI_PWRDATA_COMM_POWER_SHIFT) #define I40E_GLPCI_PWRDATA_D3_POWER_SHIFT 16 -#define I40E_GLPCI_PWRDATA_D3_POWER_MASK (0xFF << I40E_GLPCI_PWRDATA_D3_POWER_SHIFT) +#define I40E_GLPCI_PWRDATA_D3_POWER_MASK I40E_MASK(0xFF, I40E_GLPCI_PWRDATA_D3_POWER_SHIFT) #define I40E_GLPCI_PWRDATA_DATA_SCALE_SHIFT 24 -#define I40E_GLPCI_PWRDATA_DATA_SCALE_MASK (0x3 << I40E_GLPCI_PWRDATA_DATA_SCALE_SHIFT) -#define I40E_GLPCI_REVID 0x000BE4B4 +#define I40E_GLPCI_PWRDATA_DATA_SCALE_MASK I40E_MASK(0x3, I40E_GLPCI_PWRDATA_DATA_SCALE_SHIFT) +#define I40E_GLPCI_REVID 0x000BE4B4 /* Reset: PCIR */ #define I40E_GLPCI_REVID_NVM_REVID_SHIFT 0 -#define I40E_GLPCI_REVID_NVM_REVID_MASK (0xFF << I40E_GLPCI_REVID_NVM_REVID_SHIFT) -#define I40E_GLPCI_SERH 0x000BE49C +#define I40E_GLPCI_REVID_NVM_REVID_MASK I40E_MASK(0xFF, I40E_GLPCI_REVID_NVM_REVID_SHIFT) +#define I40E_GLPCI_SERH 0x000BE49C /* Reset: PCIR */ #define I40E_GLPCI_SERH_SER_NUM_H_SHIFT 0 -#define I40E_GLPCI_SERH_SER_NUM_H_MASK (0xFFFF << I40E_GLPCI_SERH_SER_NUM_H_SHIFT) -#define I40E_GLPCI_SERL 0x000BE498 +#define I40E_GLPCI_SERH_SER_NUM_H_MASK I40E_MASK(0xFFFF, I40E_GLPCI_SERH_SER_NUM_H_SHIFT) +#define I40E_GLPCI_SERL 0x000BE498 /* Reset: PCIR */ #define I40E_GLPCI_SERL_SER_NUM_L_SHIFT 0 -#define I40E_GLPCI_SERL_SER_NUM_L_MASK (0xFFFFFFFF << I40E_GLPCI_SERL_SER_NUM_L_SHIFT) -#define I40E_GLPCI_SUBSYSID 0x000BE48C -#define I40E_GLPCI_SUBSYSID_SUB_VEN_ID_SHIFT 0 -#define I40E_GLPCI_SUBSYSID_SUB_VEN_ID_MASK (0xFFFF << I40E_GLPCI_SUBSYSID_SUB_VEN_ID_SHIFT) -#define I40E_GLPCI_SUBSYSID_SUB_ID_SHIFT 16 -#define I40E_GLPCI_SUBSYSID_SUB_ID_MASK (0xFFFF << I40E_GLPCI_SUBSYSID_SUB_ID_SHIFT) -#define I40E_GLPCI_UPADD 0x000BE4F8 +#define I40E_GLPCI_SERL_SER_NUM_L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_SERL_SER_NUM_L_SHIFT) +#define I40E_GLPCI_SPARE_BITS_0 0x0009C4F8 /* Reset: PCIR */ +#define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT 0 +#define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT) +#define I40E_GLPCI_SPARE_BITS_1 0x0009C4FC /* Reset: PCIR */ +#define I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_SHIFT 0 +#define I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_SHIFT) +#define I40E_GLPCI_SUBVENID 0x000BE48C /* Reset: PCIR */ +#define I40E_GLPCI_SUBVENID_SUB_VEN_ID_SHIFT 0 +#define I40E_GLPCI_SUBVENID_SUB_VEN_ID_MASK I40E_MASK(0xFFFF, I40E_GLPCI_SUBVENID_SUB_VEN_ID_SHIFT) +#define I40E_GLPCI_UPADD 0x000BE4F8 /* Reset: PCIR */ #define I40E_GLPCI_UPADD_ADDRESS_SHIFT 1 -#define I40E_GLPCI_UPADD_ADDRESS_MASK (0x7FFFFFFF << I40E_GLPCI_UPADD_ADDRESS_SHIFT) -#define I40E_GLPCI_VFSUP 0x000BE4B8 +#define I40E_GLPCI_UPADD_ADDRESS_MASK I40E_MASK(0x7FFFFFFF, I40E_GLPCI_UPADD_ADDRESS_SHIFT) +#define I40E_GLPCI_VENDORID 0x000BE518 /* Reset: PCIR */ +#define I40E_GLPCI_VENDORID_VENDORID_SHIFT 0 +#define I40E_GLPCI_VENDORID_VENDORID_MASK I40E_MASK(0xFFFF, I40E_GLPCI_VENDORID_VENDORID_SHIFT) +#define I40E_GLPCI_VFSUP 0x000BE4B8 /* Reset: PCIR */ #define I40E_GLPCI_VFSUP_VF_PREFETCH_SHIFT 0 -#define I40E_GLPCI_VFSUP_VF_PREFETCH_MASK (0x1 << I40E_GLPCI_VFSUP_VF_PREFETCH_SHIFT) +#define I40E_GLPCI_VFSUP_VF_PREFETCH_MASK I40E_MASK(0x1, I40E_GLPCI_VFSUP_VF_PREFETCH_SHIFT) #define I40E_GLPCI_VFSUP_VR_BAR_TYPE_SHIFT 1 -#define I40E_GLPCI_VFSUP_VR_BAR_TYPE_MASK (0x1 << I40E_GLPCI_VFSUP_VR_BAR_TYPE_SHIFT) -#define I40E_PF_FUNC_RID 0x0009C000 +#define I40E_GLPCI_VFSUP_VR_BAR_TYPE_MASK I40E_MASK(0x1, I40E_GLPCI_VFSUP_VR_BAR_TYPE_SHIFT) +#define I40E_PF_FUNC_RID 0x0009C000 /* Reset: PCIR */ #define I40E_PF_FUNC_RID_FUNCTION_NUMBER_SHIFT 0 -#define I40E_PF_FUNC_RID_FUNCTION_NUMBER_MASK (0x7 << I40E_PF_FUNC_RID_FUNCTION_NUMBER_SHIFT) +#define I40E_PF_FUNC_RID_FUNCTION_NUMBER_MASK I40E_MASK(0x7, I40E_PF_FUNC_RID_FUNCTION_NUMBER_SHIFT) #define I40E_PF_FUNC_RID_DEVICE_NUMBER_SHIFT 3 -#define I40E_PF_FUNC_RID_DEVICE_NUMBER_MASK (0x1F << I40E_PF_FUNC_RID_DEVICE_NUMBER_SHIFT) +#define I40E_PF_FUNC_RID_DEVICE_NUMBER_MASK I40E_MASK(0x1F, I40E_PF_FUNC_RID_DEVICE_NUMBER_SHIFT) #define I40E_PF_FUNC_RID_BUS_NUMBER_SHIFT 8 -#define I40E_PF_FUNC_RID_BUS_NUMBER_MASK (0xFF << I40E_PF_FUNC_RID_BUS_NUMBER_SHIFT) -#define I40E_PF_PCI_CIAA 0x0009C080 +#define I40E_PF_FUNC_RID_BUS_NUMBER_MASK I40E_MASK(0xFF, I40E_PF_FUNC_RID_BUS_NUMBER_SHIFT) +#define I40E_PF_PCI_CIAA 0x0009C080 /* Reset: FLR */ #define I40E_PF_PCI_CIAA_ADDRESS_SHIFT 0 -#define I40E_PF_PCI_CIAA_ADDRESS_MASK (0xFFF << I40E_PF_PCI_CIAA_ADDRESS_SHIFT) +#define I40E_PF_PCI_CIAA_ADDRESS_MASK I40E_MASK(0xFFF, I40E_PF_PCI_CIAA_ADDRESS_SHIFT) #define I40E_PF_PCI_CIAA_VF_NUM_SHIFT 12 -#define I40E_PF_PCI_CIAA_VF_NUM_MASK (0x7F << I40E_PF_PCI_CIAA_VF_NUM_SHIFT) -#define I40E_PF_PCI_CIAD 0x0009C100 +#define I40E_PF_PCI_CIAA_VF_NUM_MASK I40E_MASK(0x7F, I40E_PF_PCI_CIAA_VF_NUM_SHIFT) +#define I40E_PF_PCI_CIAD 0x0009C100 /* Reset: FLR */ #define I40E_PF_PCI_CIAD_DATA_SHIFT 0 -#define I40E_PF_PCI_CIAD_DATA_MASK (0xFFFFFFFF << I40E_PF_PCI_CIAD_DATA_SHIFT) -#define I40E_PFPCI_CLASS 0x000BE400 +#define I40E_PF_PCI_CIAD_DATA_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_PCI_CIAD_DATA_SHIFT) +#define I40E_PFPCI_CLASS 0x000BE400 /* Reset: PCIR */ #define I40E_PFPCI_CLASS_STORAGE_CLASS_SHIFT 0 -#define I40E_PFPCI_CLASS_STORAGE_CLASS_MASK (0x1 << I40E_PFPCI_CLASS_STORAGE_CLASS_SHIFT) -#define I40E_PFPCI_CNF 0x000BE000 +#define I40E_PFPCI_CLASS_STORAGE_CLASS_MASK I40E_MASK(0x1, I40E_PFPCI_CLASS_STORAGE_CLASS_SHIFT) +#define I40E_PFPCI_CLASS_RESERVED_1_SHIFT 1 +#define I40E_PFPCI_CLASS_RESERVED_1_MASK I40E_MASK(0x1, I40E_PFPCI_CLASS_RESERVED_1_SHIFT) +#define I40E_PFPCI_CLASS_PF_IS_LAN_SHIFT 2 +#define I40E_PFPCI_CLASS_PF_IS_LAN_MASK I40E_MASK(0x1, I40E_PFPCI_CLASS_PF_IS_LAN_SHIFT) +#define I40E_PFPCI_CNF 0x000BE000 /* Reset: PCIR */ #define I40E_PFPCI_CNF_MSI_EN_SHIFT 2 -#define I40E_PFPCI_CNF_MSI_EN_MASK (0x1 << I40E_PFPCI_CNF_MSI_EN_SHIFT) +#define I40E_PFPCI_CNF_MSI_EN_MASK I40E_MASK(0x1, I40E_PFPCI_CNF_MSI_EN_SHIFT) #define I40E_PFPCI_CNF_EXROM_DIS_SHIFT 3 -#define I40E_PFPCI_CNF_EXROM_DIS_MASK (0x1 << I40E_PFPCI_CNF_EXROM_DIS_SHIFT) +#define I40E_PFPCI_CNF_EXROM_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_CNF_EXROM_DIS_SHIFT) #define I40E_PFPCI_CNF_IO_BAR_SHIFT 4 -#define I40E_PFPCI_CNF_IO_BAR_MASK (0x1 << I40E_PFPCI_CNF_IO_BAR_SHIFT) +#define I40E_PFPCI_CNF_IO_BAR_MASK I40E_MASK(0x1, I40E_PFPCI_CNF_IO_BAR_SHIFT) #define I40E_PFPCI_CNF_INT_PIN_SHIFT 5 -#define I40E_PFPCI_CNF_INT_PIN_MASK (0x3 << I40E_PFPCI_CNF_INT_PIN_SHIFT) -#define I40E_PFPCI_FACTPS 0x0009C180 +#define I40E_PFPCI_CNF_INT_PIN_MASK I40E_MASK(0x3, I40E_PFPCI_CNF_INT_PIN_SHIFT) +#define I40E_PFPCI_DEVID 0x000BE080 /* Reset: PCIR */ +#define I40E_PFPCI_DEVID_PF_DEV_ID_SHIFT 0 +#define I40E_PFPCI_DEVID_PF_DEV_ID_MASK I40E_MASK(0xFFFF, I40E_PFPCI_DEVID_PF_DEV_ID_SHIFT) +#define I40E_PFPCI_DEVID_VF_DEV_ID_SHIFT 16 +#define I40E_PFPCI_DEVID_VF_DEV_ID_MASK I40E_MASK(0xFFFF, I40E_PFPCI_DEVID_VF_DEV_ID_SHIFT) +#define I40E_PFPCI_FACTPS 0x0009C180 /* Reset: FLR */ #define I40E_PFPCI_FACTPS_FUNC_POWER_STATE_SHIFT 0 -#define I40E_PFPCI_FACTPS_FUNC_POWER_STATE_MASK (0x3 << I40E_PFPCI_FACTPS_FUNC_POWER_STATE_SHIFT) +#define I40E_PFPCI_FACTPS_FUNC_POWER_STATE_MASK I40E_MASK(0x3, I40E_PFPCI_FACTPS_FUNC_POWER_STATE_SHIFT) #define I40E_PFPCI_FACTPS_FUNC_AUX_EN_SHIFT 3 -#define I40E_PFPCI_FACTPS_FUNC_AUX_EN_MASK (0x1 << I40E_PFPCI_FACTPS_FUNC_AUX_EN_SHIFT) -#define I40E_PFPCI_FUNC 0x000BE200 +#define I40E_PFPCI_FACTPS_FUNC_AUX_EN_MASK I40E_MASK(0x1, I40E_PFPCI_FACTPS_FUNC_AUX_EN_SHIFT) +#define I40E_PFPCI_FUNC 0x000BE200 /* Reset: POR */ #define I40E_PFPCI_FUNC_FUNC_DIS_SHIFT 0 -#define I40E_PFPCI_FUNC_FUNC_DIS_MASK (0x1 << I40E_PFPCI_FUNC_FUNC_DIS_SHIFT) +#define I40E_PFPCI_FUNC_FUNC_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_FUNC_FUNC_DIS_SHIFT) #define I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_SHIFT 1 -#define I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_MASK (0x1 << I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_SHIFT) +#define I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_SHIFT) #define I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_SHIFT 2 -#define I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_MASK (0x1 << I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_SHIFT) -#define I40E_PFPCI_FUNC2 0x000BE180 +#define I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_SHIFT) +#define I40E_PFPCI_FUNC2 0x000BE180 /* Reset: PCIR */ #define I40E_PFPCI_FUNC2_EMP_FUNC_DIS_SHIFT 0 -#define I40E_PFPCI_FUNC2_EMP_FUNC_DIS_MASK (0x1 << I40E_PFPCI_FUNC2_EMP_FUNC_DIS_SHIFT) -#define I40E_PFPCI_ICAUSE 0x0009C200 +#define I40E_PFPCI_FUNC2_EMP_FUNC_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_FUNC2_EMP_FUNC_DIS_SHIFT) +#define I40E_PFPCI_ICAUSE 0x0009C200 /* Reset: PFR */ #define I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_SHIFT 0 -#define I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_MASK (0xFFFFFFFF << I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_SHIFT) -#define I40E_PFPCI_IENA 0x0009C280 +#define I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_MASK I40E_MASK(0xFFFFFFFF, I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_SHIFT) +#define I40E_PFPCI_IENA 0x0009C280 /* Reset: PFR */ #define I40E_PFPCI_IENA_PCIE_ERR_EN_SHIFT 0 -#define I40E_PFPCI_IENA_PCIE_ERR_EN_MASK (0xFFFFFFFF << I40E_PFPCI_IENA_PCIE_ERR_EN_SHIFT) -#define I40E_PFPCI_PFDEVID 0x000BE080 -#define I40E_PFPCI_PFDEVID_PF_DEV_ID_LAN_SHIFT 0 -#define I40E_PFPCI_PFDEVID_PF_DEV_ID_LAN_MASK (0xFFFF << I40E_PFPCI_PFDEVID_PF_DEV_ID_LAN_SHIFT) -#define I40E_PFPCI_PFDEVID_PF_DEV_ID_SAN_SHIFT 16 -#define I40E_PFPCI_PFDEVID_PF_DEV_ID_SAN_MASK (0xFFFF << I40E_PFPCI_PFDEVID_PF_DEV_ID_SAN_SHIFT) -#define I40E_PFPCI_PM 0x000BE300 +#define I40E_PFPCI_IENA_PCIE_ERR_EN_MASK I40E_MASK(0xFFFFFFFF, I40E_PFPCI_IENA_PCIE_ERR_EN_SHIFT) +#define I40E_PFPCI_PF_FLUSH_DONE 0x0009C800 /* Reset: PCIR */ +#define I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_SHIFT 0 +#define I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_MASK I40E_MASK(0x1, I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_SHIFT) +#define I40E_PFPCI_PM 0x000BE300 /* Reset: POR */ #define I40E_PFPCI_PM_PME_EN_SHIFT 0 -#define I40E_PFPCI_PM_PME_EN_MASK (0x1 << I40E_PFPCI_PM_PME_EN_SHIFT) -#define I40E_PFPCI_STATUS1 0x000BE280 +#define I40E_PFPCI_PM_PME_EN_MASK I40E_MASK(0x1, I40E_PFPCI_PM_PME_EN_SHIFT) +#define I40E_PFPCI_STATUS1 0x000BE280 /* Reset: POR */ #define I40E_PFPCI_STATUS1_FUNC_VALID_SHIFT 0 -#define I40E_PFPCI_STATUS1_FUNC_VALID_MASK (0x1 << I40E_PFPCI_STATUS1_FUNC_VALID_SHIFT) -#define I40E_PFPCI_VFDEVID 0x000BE100 -#define I40E_PFPCI_VFDEVID_VF_DEV_ID_LAN_SHIFT 0 -#define I40E_PFPCI_VFDEVID_VF_DEV_ID_LAN_MASK (0xFFFF << I40E_PFPCI_VFDEVID_VF_DEV_ID_LAN_SHIFT) -#define I40E_PFPCI_VFDEVID_VF_DEV_ID_SAN_SHIFT 16 -#define I40E_PFPCI_VFDEVID_VF_DEV_ID_SAN_MASK (0xFFFF << I40E_PFPCI_VFDEVID_VF_DEV_ID_SAN_SHIFT) -#define I40E_PFPCI_VMINDEX 0x0009C300 +#define I40E_PFPCI_STATUS1_FUNC_VALID_MASK I40E_MASK(0x1, I40E_PFPCI_STATUS1_FUNC_VALID_SHIFT) +#define I40E_PFPCI_SUBSYSID 0x000BE100 /* Reset: PCIR */ +#define I40E_PFPCI_SUBSYSID_PF_SUBSYS_ID_SHIFT 0 +#define I40E_PFPCI_SUBSYSID_PF_SUBSYS_ID_MASK I40E_MASK(0xFFFF, I40E_PFPCI_SUBSYSID_PF_SUBSYS_ID_SHIFT) +#define I40E_PFPCI_SUBSYSID_VF_SUBSYS_ID_SHIFT 16 +#define I40E_PFPCI_SUBSYSID_VF_SUBSYS_ID_MASK I40E_MASK(0xFFFF, I40E_PFPCI_SUBSYSID_VF_SUBSYS_ID_SHIFT) +#define I40E_PFPCI_VF_FLUSH_DONE 0x0000E400 /* Reset: PCIR */ +#define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT 0 +#define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_MASK I40E_MASK(0x1, I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT) +#define I40E_PFPCI_VF_FLUSH_DONE1(_VF) (0x0009C600 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: PCIR */ +#define I40E_PFPCI_VF_FLUSH_DONE1_MAX_INDEX 127 +#define I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_SHIFT 0 +#define I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_MASK I40E_MASK(0x1, I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_SHIFT) +#define I40E_PFPCI_VM_FLUSH_DONE 0x0009C880 /* Reset: PCIR */ +#define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT 0 +#define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_MASK I40E_MASK(0x1, I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT) +#define I40E_PFPCI_VMINDEX 0x0009C300 /* Reset: PCIR */ #define I40E_PFPCI_VMINDEX_VMINDEX_SHIFT 0 -#define I40E_PFPCI_VMINDEX_VMINDEX_MASK (0x1FF << I40E_PFPCI_VMINDEX_VMINDEX_SHIFT) -#define I40E_PFPCI_VMPEND 0x0009C380 +#define I40E_PFPCI_VMINDEX_VMINDEX_MASK I40E_MASK(0x1FF, I40E_PFPCI_VMINDEX_VMINDEX_SHIFT) +#define I40E_PFPCI_VMPEND 0x0009C380 /* Reset: PCIR */ #define I40E_PFPCI_VMPEND_PENDING_SHIFT 0 -#define I40E_PFPCI_VMPEND_PENDING_MASK (0x1 << I40E_PFPCI_VMPEND_PENDING_SHIFT) -#define I40E_GLPE_CPUSTATUS0 0x0000D040 -#define I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_SHIFT 0 -#define I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_MASK (0xFFFFFFFF << I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_SHIFT) -#define I40E_GLPE_CPUSTATUS1 0x0000D044 -#define I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_SHIFT 0 -#define I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_MASK (0xFFFFFFFF << I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_SHIFT) -#define I40E_GLPE_CPUSTATUS2 0x0000D048 -#define I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_SHIFT 0 -#define I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_MASK (0xFFFFFFFF << I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_SHIFT) -#define I40E_GLPE_PFFLMOBJCTRL(_i) (0x0000D480 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPE_PFFLMOBJCTRL_MAX_INDEX 15 -#define I40E_GLPE_PFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT 0 -#define I40E_GLPE_PFFLMOBJCTRL_XMIT_BLOCKSIZE_MASK (0x7 << I40E_GLPE_PFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT) -#define I40E_GLPE_PFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT 8 -#define I40E_GLPE_PFFLMOBJCTRL_Q1_BLOCKSIZE_MASK (0x7 << I40E_GLPE_PFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT) -#define I40E_GLPE_VFFLMOBJCTRL(_i) (0x0000D400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPE_VFFLMOBJCTRL_MAX_INDEX 31 -#define I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT 0 -#define I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_MASK (0x7 << I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT) -#define I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT 8 -#define I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_MASK (0x7 << I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT) -#define I40E_GLPE_VFFLMQ1ALLOCERR(_i) (0x0000C700 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPE_VFFLMQ1ALLOCERR_MAX_INDEX 31 -#define I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_SHIFT 0 -#define I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_SHIFT) -#define I40E_GLPE_VFFLMXMITALLOCERR(_i) (0x0000C600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPE_VFFLMXMITALLOCERR_MAX_INDEX 31 -#define I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_SHIFT 0 -#define I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_SHIFT) -#define I40E_GLPE_VFUDACTRL(_i) (0x0000C000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPE_VFUDACTRL_MAX_INDEX 31 -#define I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_SHIFT 0 -#define I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_SHIFT) -#define I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_SHIFT 1 -#define I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_SHIFT) -#define I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_SHIFT 2 -#define I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_SHIFT) -#define I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_SHIFT 3 -#define I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_SHIFT) -#define I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_SHIFT 4 -#define I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_MASK (0x1 << I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_SHIFT) -#define I40E_GLPE_VFUDAUCFBQPN(_i) (0x0000C100 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPE_VFUDAUCFBQPN_MAX_INDEX 31 -#define I40E_GLPE_VFUDAUCFBQPN_QPN_SHIFT 0 -#define I40E_GLPE_VFUDAUCFBQPN_QPN_MASK (0x3FFFF << I40E_GLPE_VFUDAUCFBQPN_QPN_SHIFT) -#define I40E_GLPE_VFUDAUCFBQPN_VALID_SHIFT 31 -#define I40E_GLPE_VFUDAUCFBQPN_VALID_MASK (0x1 << I40E_GLPE_VFUDAUCFBQPN_VALID_SHIFT) -#define I40E_PFPE_AEQALLOC 0x00131180 -#define I40E_PFPE_AEQALLOC_AECOUNT_SHIFT 0 -#define I40E_PFPE_AEQALLOC_AECOUNT_MASK (0xFFFFFFFF << I40E_PFPE_AEQALLOC_AECOUNT_SHIFT) -#define I40E_PFPE_CCQPHIGH 0x00008200 -#define I40E_PFPE_CCQPHIGH_PECCQPHIGH_SHIFT 0 -#define I40E_PFPE_CCQPHIGH_PECCQPHIGH_MASK (0xFFFFFFFF << I40E_PFPE_CCQPHIGH_PECCQPHIGH_SHIFT) -#define I40E_PFPE_CCQPLOW 0x00008180 -#define I40E_PFPE_CCQPLOW_PECCQPLOW_SHIFT 0 -#define I40E_PFPE_CCQPLOW_PECCQPLOW_MASK (0xFFFFFFFF << I40E_PFPE_CCQPLOW_PECCQPLOW_SHIFT) -#define I40E_PFPE_CCQPSTATUS 0x00008100 -#define I40E_PFPE_CCQPSTATUS_CCQP_DONE_SHIFT 0 -#define I40E_PFPE_CCQPSTATUS_CCQP_DONE_MASK (0x1 << I40E_PFPE_CCQPSTATUS_CCQP_DONE_SHIFT) -#define I40E_PFPE_CCQPSTATUS_CCQP_ERR_SHIFT 31 -#define I40E_PFPE_CCQPSTATUS_CCQP_ERR_MASK (0x1 << I40E_PFPE_CCQPSTATUS_CCQP_ERR_SHIFT) -#define I40E_PFPE_CQACK 0x00131100 -#define I40E_PFPE_CQACK_PECQID_SHIFT 0 -#define I40E_PFPE_CQACK_PECQID_MASK (0x1FFFF << I40E_PFPE_CQACK_PECQID_SHIFT) -#define I40E_PFPE_CQARM 0x00131080 -#define I40E_PFPE_CQARM_PECQID_SHIFT 0 -#define I40E_PFPE_CQARM_PECQID_MASK (0x1FFFF << I40E_PFPE_CQARM_PECQID_SHIFT) -#define I40E_PFPE_CQPDB 0x00008000 -#define I40E_PFPE_CQPDB_WQHEAD_SHIFT 0 -#define I40E_PFPE_CQPDB_WQHEAD_MASK (0x7FF << I40E_PFPE_CQPDB_WQHEAD_SHIFT) -#define I40E_PFPE_CQPERRCODES 0x00008880 -#define I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT 0 -#define I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_MASK (0xFFFF << I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT) -#define I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT 16 -#define I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_MASK (0xFFFF << I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT) -#define I40E_PFPE_CQPTAIL 0x00008080 -#define I40E_PFPE_CQPTAIL_WQTAIL_SHIFT 0 -#define I40E_PFPE_CQPTAIL_WQTAIL_MASK (0x7FF << I40E_PFPE_CQPTAIL_WQTAIL_SHIFT) -#define I40E_PFPE_CQPTAIL_CQP_OP_ERR_SHIFT 31 -#define I40E_PFPE_CQPTAIL_CQP_OP_ERR_MASK (0x1 << I40E_PFPE_CQPTAIL_CQP_OP_ERR_SHIFT) -#define I40E_PFPE_FLMQ1ALLOCERR 0x00008980 -#define I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_SHIFT 0 -#define I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_SHIFT) -#define I40E_PFPE_FLMXMITALLOCERR 0x00008900 -#define I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_SHIFT 0 -#define I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_SHIFT) -#define I40E_PFPE_IPCONFIG0 0x00008280 -#define I40E_PFPE_IPCONFIG0_PEIPID_SHIFT 0 -#define I40E_PFPE_IPCONFIG0_PEIPID_MASK (0xFFFF << I40E_PFPE_IPCONFIG0_PEIPID_SHIFT) -#define I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT 16 -#define I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_MASK (0x1 << I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT) - -#define I40E_PFPE_MRTEIDXMASK 0x00008600 -#define I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT 0 -#define I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_MASK (0x1F << I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT) -#define I40E_PFPE_RCVUNEXPECTEDERROR 0x00008680 -#define I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT 0 -#define I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_MASK (0xFFFFFF << I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT) -#define I40E_PFPE_TCPNOWTIMER 0x00008580 -#define I40E_PFPE_TCPNOWTIMER_TCP_NOW_SHIFT 0 -#define I40E_PFPE_TCPNOWTIMER_TCP_NOW_MASK (0xFFFFFFFF << I40E_PFPE_TCPNOWTIMER_TCP_NOW_SHIFT) -#define I40E_PFPE_UDACTRL 0x00008700 -#define I40E_PFPE_UDACTRL_IPV4MCFRAGRESBP_SHIFT 0 -#define I40E_PFPE_UDACTRL_IPV4MCFRAGRESBP_MASK (0x1 << I40E_PFPE_UDACTRL_IPV4MCFRAGRESBP_SHIFT) -#define I40E_PFPE_UDACTRL_IPV4UCFRAGRESBP_SHIFT 1 -#define I40E_PFPE_UDACTRL_IPV4UCFRAGRESBP_MASK (0x1 << I40E_PFPE_UDACTRL_IPV4UCFRAGRESBP_SHIFT) -#define I40E_PFPE_UDACTRL_IPV6MCFRAGRESBP_SHIFT 2 -#define I40E_PFPE_UDACTRL_IPV6MCFRAGRESBP_MASK (0x1 << I40E_PFPE_UDACTRL_IPV6MCFRAGRESBP_SHIFT) -#define I40E_PFPE_UDACTRL_IPV6UCFRAGRESBP_SHIFT 3 -#define I40E_PFPE_UDACTRL_IPV6UCFRAGRESBP_MASK (0x1 << I40E_PFPE_UDACTRL_IPV6UCFRAGRESBP_SHIFT) -#define I40E_PFPE_UDACTRL_UDPMCFRAGRESFAIL_SHIFT 4 -#define I40E_PFPE_UDACTRL_UDPMCFRAGRESFAIL_MASK (0x1 << I40E_PFPE_UDACTRL_UDPMCFRAGRESFAIL_SHIFT) -#define I40E_PFPE_UDAUCFBQPN 0x00008780 -#define I40E_PFPE_UDAUCFBQPN_QPN_SHIFT 0 -#define I40E_PFPE_UDAUCFBQPN_QPN_MASK (0x3FFFF << I40E_PFPE_UDAUCFBQPN_QPN_SHIFT) -#define I40E_PFPE_UDAUCFBQPN_VALID_SHIFT 31 -#define I40E_PFPE_UDAUCFBQPN_VALID_MASK (0x1 << I40E_PFPE_UDAUCFBQPN_VALID_SHIFT) -#define I40E_PFPE_WQEALLOC 0x00138C00 -#define I40E_PFPE_WQEALLOC_PEQPID_SHIFT 0 -#define I40E_PFPE_WQEALLOC_PEQPID_MASK (0x3FFFF << I40E_PFPE_WQEALLOC_PEQPID_SHIFT) -#define I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT 20 -#define I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_MASK (0xFFF << I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT) -#define I40E_VFPE_AEQALLOC(_VF) (0x00130C00 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_AEQALLOC_MAX_INDEX 127 -#define I40E_VFPE_AEQALLOC_AECOUNT_SHIFT 0 -#define I40E_VFPE_AEQALLOC_AECOUNT_MASK (0xFFFFFFFF << I40E_VFPE_AEQALLOC_AECOUNT_SHIFT) -#define I40E_VFPE_CCQPHIGH(_VF) (0x00001000 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CCQPHIGH_MAX_INDEX 127 -#define I40E_VFPE_CCQPHIGH_PECCQPHIGH_SHIFT 0 -#define I40E_VFPE_CCQPHIGH_PECCQPHIGH_MASK (0xFFFFFFFF << I40E_VFPE_CCQPHIGH_PECCQPHIGH_SHIFT) -#define I40E_VFPE_CCQPLOW(_VF) (0x00000C00 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CCQPLOW_MAX_INDEX 127 -#define I40E_VFPE_CCQPLOW_PECCQPLOW_SHIFT 0 -#define I40E_VFPE_CCQPLOW_PECCQPLOW_MASK (0xFFFFFFFF << I40E_VFPE_CCQPLOW_PECCQPLOW_SHIFT) -#define I40E_VFPE_CCQPSTATUS(_VF) (0x00000800 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CCQPSTATUS_MAX_INDEX 127 -#define I40E_VFPE_CCQPSTATUS_CCQP_DONE_SHIFT 0 -#define I40E_VFPE_CCQPSTATUS_CCQP_DONE_MASK (0x1 << I40E_VFPE_CCQPSTATUS_CCQP_DONE_SHIFT) -#define I40E_VFPE_CCQPSTATUS_CCQP_ERR_SHIFT 31 -#define I40E_VFPE_CCQPSTATUS_CCQP_ERR_MASK (0x1 << I40E_VFPE_CCQPSTATUS_CCQP_ERR_SHIFT) -#define I40E_VFPE_CQACK(_VF) (0x00130800 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CQACK_MAX_INDEX 127 -#define I40E_VFPE_CQACK_PECQID_SHIFT 0 -#define I40E_VFPE_CQACK_PECQID_MASK (0x1FFFF << I40E_VFPE_CQACK_PECQID_SHIFT) -#define I40E_VFPE_CQARM(_VF) (0x00130400 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CQARM_MAX_INDEX 127 -#define I40E_VFPE_CQARM_PECQID_SHIFT 0 -#define I40E_VFPE_CQARM_PECQID_MASK (0x1FFFF << I40E_VFPE_CQARM_PECQID_SHIFT) -#define I40E_VFPE_CQPDB(_VF) (0x00000000 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CQPDB_MAX_INDEX 127 -#define I40E_VFPE_CQPDB_WQHEAD_SHIFT 0 -#define I40E_VFPE_CQPDB_WQHEAD_MASK (0x7FF << I40E_VFPE_CQPDB_WQHEAD_SHIFT) -#define I40E_VFPE_CQPERRCODES(_VF) (0x00001800 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CQPERRCODES_MAX_INDEX 127 -#define I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT 0 -#define I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT) -#define I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT 16 -#define I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT) -#define I40E_VFPE_CQPTAIL(_VF) (0x00000400 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_CQPTAIL_MAX_INDEX 127 -#define I40E_VFPE_CQPTAIL_WQTAIL_SHIFT 0 -#define I40E_VFPE_CQPTAIL_WQTAIL_MASK (0x7FF << I40E_VFPE_CQPTAIL_WQTAIL_SHIFT) -#define I40E_VFPE_CQPTAIL_CQP_OP_ERR_SHIFT 31 -#define I40E_VFPE_CQPTAIL_CQP_OP_ERR_MASK (0x1 << I40E_VFPE_CQPTAIL_CQP_OP_ERR_SHIFT) -#define I40E_VFPE_IPCONFIG0(_VF) (0x00001400 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_IPCONFIG0_MAX_INDEX 127 -#define I40E_VFPE_IPCONFIG0_PEIPID_SHIFT 0 -#define I40E_VFPE_IPCONFIG0_PEIPID_MASK (0xFFFF << I40E_VFPE_IPCONFIG0_PEIPID_SHIFT) -#define I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT 16 -#define I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT) -#define I40E_VFPE_MRTEIDXMASK(_VF) (0x00003000 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_MRTEIDXMASK_MAX_INDEX 127 -#define I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT 0 -#define I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_MASK (0x1F << I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT) -#define I40E_VFPE_RCVUNEXPECTEDERROR(_VF) (0x00003400 + ((_VF) * 4)) -#define I40E_VFPE_RCVUNEXPECTEDERROR_MAX_INDEX 127 -#define I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT 0 -#define I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_MASK (0xFFFFFF << I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT) -#define I40E_VFPE_TCPNOWTIMER(_VF) (0x00002C00 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_TCPNOWTIMER_MAX_INDEX 127 -#define I40E_VFPE_TCPNOWTIMER_TCP_NOW_SHIFT 0 -#define I40E_VFPE_TCPNOWTIMER_TCP_NOW_MASK (0xFFFFFFFF << I40E_VFPE_TCPNOWTIMER_TCP_NOW_SHIFT) -#define I40E_VFPE_WQEALLOC(_VF) (0x00138000 + ((_VF) * 4)) /* _i=0...127 */ -#define I40E_VFPE_WQEALLOC_MAX_INDEX 127 -#define I40E_VFPE_WQEALLOC_PEQPID_SHIFT 0 -#define I40E_VFPE_WQEALLOC_PEQPID_MASK (0x3FFFF << I40E_VFPE_WQEALLOC_PEQPID_SHIFT) -#define I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT 20 -#define I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_MASK (0xFFF << I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT) -#define I40E_GLPES_PFIP4RXDISCARD(_i) (0x00010600 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXDISCARD_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_SHIFT 0 -#define I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_SHIFT) -#define I40E_GLPES_PFIP4RXFRAGSHI(_i) (0x00010804 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXFRAGSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT 0 -#define I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT) -#define I40E_GLPES_PFIP4RXFRAGSLO(_i) (0x00010800 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXFRAGSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT 0 -#define I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT) -#define I40E_GLPES_PFIP4RXMCOCTSHI(_i) (0x00010A04 + ((_i) * 8)) -#define I40E_GLPES_PFIP4RXMCOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT) -#define I40E_GLPES_PFIP4RXMCOCTSLO(_i) (0x00010A00 + ((_i) * 8)) -#define I40E_GLPES_PFIP4RXMCOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT) -#define I40E_GLPES_PFIP4RXMCPKTSHI(_i) (0x00010C04 + ((_i) * 8)) -#define I40E_GLPES_PFIP4RXMCPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT) -#define I40E_GLPES_PFIP4RXMCPKTSLO(_i) (0x00010C00 + ((_i) * 8)) -#define I40E_GLPES_PFIP4RXMCPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT) -#define I40E_GLPES_PFIP4RXOCTSHI(_i) (0x00010204 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT) -#define I40E_GLPES_PFIP4RXOCTSLO(_i) (0x00010200 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT) -#define I40E_GLPES_PFIP4RXPKTSHI(_i) (0x00010404 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT) -#define I40E_GLPES_PFIP4RXPKTSLO(_i) (0x00010400 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT) -#define I40E_GLPES_PFIP4RXTRUNC(_i) (0x00010700 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4RXTRUNC_MAX_INDEX 15 -#define I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_SHIFT 0 -#define I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_SHIFT) -#define I40E_GLPES_PFIP4TXFRAGSHI(_i) (0x00011E04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXFRAGSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT 0 -#define I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT) -#define I40E_GLPES_PFIP4TXFRAGSLO(_i) (0x00011E00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXFRAGSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT 0 -#define I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT) -#define I40E_GLPES_PFIP4TXMCOCTSHI(_i) (0x00012004 + ((_i) * 8)) -#define I40E_GLPES_PFIP4TXMCOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT) -#define I40E_GLPES_PFIP4TXMCOCTSLO(_i) (0x00012000 + ((_i) * 8)) -#define I40E_GLPES_PFIP4TXMCOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT) -#define I40E_GLPES_PFIP4TXMCPKTSHI(_i) (0x00012204 + ((_i) * 8)) -#define I40E_GLPES_PFIP4TXMCPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT) -#define I40E_GLPES_PFIP4TXMCPKTSLO(_i) (0x00012200 + ((_i) * 8)) -#define I40E_GLPES_PFIP4TXMCPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT) -#define I40E_GLPES_PFIP4TXNOROUTE(_i) (0x00012E00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXNOROUTE_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT 0 -#define I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT) -#define I40E_GLPES_PFIP4TXOCTSHI(_i) (0x00011A04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT) -#define I40E_GLPES_PFIP4TXOCTSLO(_i) (0x00011A00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT) -#define I40E_GLPES_PFIP4TXPKTSHI(_i) (0x00011C04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT) -#define I40E_GLPES_PFIP4TXPKTSLO(_i) (0x00011C00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP4TXPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT) -#define I40E_GLPES_PFIP6RXDISCARD(_i) (0x00011200 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXDISCARD_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_SHIFT 0 -#define I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_SHIFT) -#define I40E_GLPES_PFIP6RXFRAGSHI(_i) (0x00011404 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXFRAGSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT 0 -#define I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT) -#define I40E_GLPES_PFIP6RXFRAGSLO(_i) (0x00011400 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXFRAGSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT 0 -#define I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT) -#define I40E_GLPES_PFIP6RXMCOCTSHI(_i) (0x00011604 + ((_i) * 8)) -#define I40E_GLPES_PFIP6RXMCOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT) -#define I40E_GLPES_PFIP6RXMCOCTSLO(_i) (0x00011600 + ((_i) * 8)) -#define I40E_GLPES_PFIP6RXMCOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT) -#define I40E_GLPES_PFIP6RXMCPKTSHI(_i) (0x00011804 + ((_i) * 8)) -#define I40E_GLPES_PFIP6RXMCPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT) -#define I40E_GLPES_PFIP6RXMCPKTSLO(_i) (0x00011800 + ((_i) * 8)) -#define I40E_GLPES_PFIP6RXMCPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT) -#define I40E_GLPES_PFIP6RXOCTSHI(_i) (0x00010E04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT) -#define I40E_GLPES_PFIP6RXOCTSLO(_i) (0x00010E00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT) -#define I40E_GLPES_PFIP6RXPKTSHI(_i) (0x00011004 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT) -#define I40E_GLPES_PFIP6RXPKTSLO(_i) (0x00011000 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT) -#define I40E_GLPES_PFIP6RXTRUNC(_i) (0x00011300 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6RXTRUNC_MAX_INDEX 15 -#define I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_SHIFT 0 -#define I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_SHIFT) -#define I40E_GLPES_PFIP6TXFRAGSHI(_i) (0x00012804 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXFRAGSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT 0 -#define I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT) -#define I40E_GLPES_PFIP6TXFRAGSLO(_i) (0x00012800 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXFRAGSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT 0 -#define I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT) -#define I40E_GLPES_PFIP6TXMCOCTSHI(_i) (0x00012A04 + ((_i) * 8)) -#define I40E_GLPES_PFIP6TXMCOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT) -#define I40E_GLPES_PFIP6TXMCOCTSLO(_i) (0x00012A00 + ((_i) * 8)) -#define I40E_GLPES_PFIP6TXMCOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT) -#define I40E_GLPES_PFIP6TXMCPKTSHI(_i) (0x00012C04 + ((_i) * 8)) -#define I40E_GLPES_PFIP6TXMCPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT) -#define I40E_GLPES_PFIP6TXMCPKTSLO(_i) (0x00012C00 + ((_i) * 8)) -#define I40E_GLPES_PFIP6TXMCPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT) -#define I40E_GLPES_PFIP6TXNOROUTE(_i) (0x00012F00 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXNOROUTE_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT 0 -#define I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT) -#define I40E_GLPES_PFIP6TXOCTSHI(_i) (0x00012404 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXOCTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT) -#define I40E_GLPES_PFIP6TXOCTSLO(_i) (0x00012400 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXOCTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT) -#define I40E_GLPES_PFIP6TXPKTSHI(_i) (0x00012604 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT 0 -#define I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT) -#define I40E_GLPES_PFIP6TXPKTSLO(_i) (0x00012600 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFIP6TXPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT 0 -#define I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT) -#define I40E_GLPES_PFRDMARXRDSHI(_i) (0x00013E04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMARXRDSHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_SHIFT 0 -#define I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_SHIFT) -#define I40E_GLPES_PFRDMARXRDSLO(_i) (0x00013E00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMARXRDSLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_SHIFT 0 -#define I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_SHIFT) -#define I40E_GLPES_PFRDMARXSNDSHI(_i) (0x00014004 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMARXSNDSHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT 0 -#define I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT) -#define I40E_GLPES_PFRDMARXSNDSLO(_i) (0x00014000 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMARXSNDSLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT 0 -#define I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT) -#define I40E_GLPES_PFRDMARXWRSHI(_i) (0x00013C04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMARXWRSHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_SHIFT 0 -#define I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_SHIFT) -#define I40E_GLPES_PFRDMARXWRSLO(_i) (0x00013C00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMARXWRSLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_SHIFT 0 -#define I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_SHIFT) -#define I40E_GLPES_PFRDMATXRDSHI(_i) (0x00014404 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMATXRDSHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_SHIFT 0 -#define I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_SHIFT) -#define I40E_GLPES_PFRDMATXRDSLO(_i) (0x00014400 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMATXRDSLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_SHIFT 0 -#define I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_SHIFT) -#define I40E_GLPES_PFRDMATXSNDSHI(_i) (0x00014604 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMATXSNDSHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT 0 -#define I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT) -#define I40E_GLPES_PFRDMATXSNDSLO(_i) (0x00014600 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMATXSNDSLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT 0 -#define I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT) -#define I40E_GLPES_PFRDMATXWRSHI(_i) (0x00014204 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMATXWRSHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_SHIFT 0 -#define I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_SHIFT) -#define I40E_GLPES_PFRDMATXWRSLO(_i) (0x00014200 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMATXWRSLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_SHIFT 0 -#define I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_SHIFT) -#define I40E_GLPES_PFRDMAVBNDHI(_i) (0x00014804 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMAVBNDHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_SHIFT 0 -#define I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_SHIFT) -#define I40E_GLPES_PFRDMAVBNDLO(_i) (0x00014800 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMAVBNDLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_SHIFT 0 -#define I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_SHIFT) -#define I40E_GLPES_PFRDMAVINVHI(_i) (0x00014A04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMAVINVHI_MAX_INDEX 15 -#define I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_SHIFT 0 -#define I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_SHIFT) -#define I40E_GLPES_PFRDMAVINVLO(_i) (0x00014A00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFRDMAVINVLO_MAX_INDEX 15 -#define I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_SHIFT 0 -#define I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_SHIFT) -#define I40E_GLPES_PFRXVLANERR(_i) (0x00010000 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFRXVLANERR_MAX_INDEX 15 -#define I40E_GLPES_PFRXVLANERR_RXVLANERR_SHIFT 0 -#define I40E_GLPES_PFRXVLANERR_RXVLANERR_MASK (0xFFFFFF << I40E_GLPES_PFRXVLANERR_RXVLANERR_SHIFT) -#define I40E_GLPES_PFTCPRTXSEG(_i) (0x00013600 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFTCPRTXSEG_MAX_INDEX 15 -#define I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_SHIFT 0 -#define I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_MASK (0xFFFFFFFF << I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_SHIFT) -#define I40E_GLPES_PFTCPRXOPTERR(_i) (0x00013200 + ((_i) * 4)) /* _i=0...15 */ -#define I40E_GLPES_PFTCPRXOPTERR_MAX_INDEX 15 -#define I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_SHIFT 0 -#define I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_MASK (0xFFFFFF << I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_SHIFT) -#define I40E_GLPES_PFTCPRXPROTOERR(_i) (0x00013300 + ((_i) * 4)) -#define I40E_GLPES_PFTCPRXPROTOERR_MAX_INDEX 15 -#define I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT 0 -#define I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_MASK (0xFFFFFF << I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT) -#define I40E_GLPES_PFTCPRXSEGSHI(_i) (0x00013004 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFTCPRXSEGSHI_MAX_INDEX 15 -#define I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT 0 -#define I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_MASK (0xFFFF << I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT) -#define I40E_GLPES_PFTCPRXSEGSLO(_i) (0x00013000 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFTCPRXSEGSLO_MAX_INDEX 15 -#define I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT 0 -#define I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT) -#define I40E_GLPES_PFTCPTXSEGHI(_i) (0x00013404 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFTCPTXSEGHI_MAX_INDEX 15 -#define I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_SHIFT 0 -#define I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_MASK (0xFFFF << I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_SHIFT) -#define I40E_GLPES_PFTCPTXSEGLO(_i) (0x00013400 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFTCPTXSEGLO_MAX_INDEX 15 -#define I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_SHIFT 0 -#define I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_MASK (0xFFFFFFFF << I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_SHIFT) -#define I40E_GLPES_PFUDPRXPKTSHI(_i) (0x00013804 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFUDPRXPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT 0 -#define I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT) -#define I40E_GLPES_PFUDPRXPKTSLO(_i) (0x00013800 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFUDPRXPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT 0 -#define I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT) -#define I40E_GLPES_PFUDPTXPKTSHI(_i) (0x00013A04 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFUDPTXPKTSHI_MAX_INDEX 15 -#define I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT 0 -#define I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT) -#define I40E_GLPES_PFUDPTXPKTSLO(_i) (0x00013A00 + ((_i) * 8)) /* _i=0...15 */ -#define I40E_GLPES_PFUDPTXPKTSLO_MAX_INDEX 15 -#define I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT 0 -#define I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT) -#define I40E_GLPES_RDMARXMULTFPDUSHI 0x0001E014 -#define I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_SHIFT 0 -#define I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_MASK (0xFFFFFF << I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_SHIFT) -#define I40E_GLPES_RDMARXMULTFPDUSLO 0x0001E010 -#define I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_SHIFT 0 -#define I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_SHIFT) -#define I40E_GLPES_RDMARXOOODDPHI 0x0001E01C -#define I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_SHIFT 0 -#define I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_MASK (0xFFFFFF << I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_SHIFT) -#define I40E_GLPES_RDMARXOOODDPLO 0x0001E018 -#define I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_SHIFT 0 -#define I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_SHIFT) -#define I40E_GLPES_RDMARXOOONOMARK 0x0001E004 -#define I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_SHIFT 0 -#define I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_SHIFT) -#define I40E_GLPES_RDMARXUNALIGN 0x0001E000 -#define I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_SHIFT 0 -#define I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_SHIFT) -#define I40E_GLPES_TCPRXFOURHOLEHI 0x0001E044 -#define I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_SHIFT 0 -#define I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_SHIFT) -#define I40E_GLPES_TCPRXFOURHOLELO 0x0001E040 -#define I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_SHIFT 0 -#define I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_SHIFT) -#define I40E_GLPES_TCPRXONEHOLEHI 0x0001E02C -#define I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_SHIFT 0 -#define I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_SHIFT) -#define I40E_GLPES_TCPRXONEHOLELO 0x0001E028 -#define I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_SHIFT 0 -#define I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_SHIFT) -#define I40E_GLPES_TCPRXPUREACKHI 0x0001E024 -#define I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_SHIFT 0 -#define I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_SHIFT) -#define I40E_GLPES_TCPRXPUREACKSLO 0x0001E020 -#define I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_SHIFT 0 -#define I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_SHIFT) -#define I40E_GLPES_TCPRXTHREEHOLEHI 0x0001E03C -#define I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_SHIFT 0 -#define I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_SHIFT) -#define I40E_GLPES_TCPRXTHREEHOLELO 0x0001E038 -#define I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_SHIFT 0 -#define I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_SHIFT) -#define I40E_GLPES_TCPRXTWOHOLEHI 0x0001E034 -#define I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_SHIFT 0 -#define I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_SHIFT) -#define I40E_GLPES_TCPRXTWOHOLELO 0x0001E030 -#define I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_SHIFT 0 -#define I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_SHIFT) -#define I40E_GLPES_TCPRXUNEXPERR 0x0001E008 -#define I40E_GLPES_TCPRXUNEXPERR_TCPRXUNEXPERR_SHIFT 0 -#define I40E_GLPES_TCPRXUNEXPERR_TCPRXUNEXPERR_MASK (0xFFFFFF << I40E_GLPES_TCPRXUNEXPERR_TCPRXUNEXPERR_SHIFT) -#define I40E_GLPES_TCPTXRETRANSFASTHI 0x0001E04C -#define I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_SHIFT 0 -#define I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_MASK (0xFFFFFF << I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_SHIFT) -#define I40E_GLPES_TCPTXRETRANSFASTLO 0x0001E048 -#define I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_SHIFT 0 -#define I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_SHIFT) -#define I40E_GLPES_TCPTXTOUTSFASTHI 0x0001E054 -#define I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_SHIFT 0 -#define I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_MASK (0xFFFFFF << I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_SHIFT) -#define I40E_GLPES_TCPTXTOUTSFASTLO 0x0001E050 -#define I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_SHIFT 0 -#define I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_SHIFT) -#define I40E_GLPES_TCPTXTOUTSHI 0x0001E05C -#define I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_SHIFT 0 -#define I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_MASK (0xFFFFFF << I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_SHIFT) -#define I40E_GLPES_TCPTXTOUTSLO 0x0001E058 -#define I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_SHIFT 0 -#define I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_SHIFT) -#define I40E_GLPES_VFIP4RXDISCARD(_i) (0x00018600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXDISCARD_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_SHIFT 0 -#define I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_SHIFT) -#define I40E_GLPES_VFIP4RXFRAGSHI(_i) (0x00018804 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXFRAGSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT 0 -#define I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT) -#define I40E_GLPES_VFIP4RXFRAGSLO(_i) (0x00018800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXFRAGSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT 0 -#define I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT) -#define I40E_GLPES_VFIP4RXMCOCTSHI(_i) (0x00018A04 + ((_i) * 4)) -#define I40E_GLPES_VFIP4RXMCOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT) -#define I40E_GLPES_VFIP4RXMCOCTSLO(_i) (0x00018A00 + ((_i) * 4)) -#define I40E_GLPES_VFIP4RXMCOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT) -#define I40E_GLPES_VFIP4RXMCPKTSHI(_i) (0x00018C04 + ((_i) * 4)) -#define I40E_GLPES_VFIP4RXMCPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT) -#define I40E_GLPES_VFIP4RXMCPKTSLO(_i) (0x00018C00 + ((_i) * 4)) -#define I40E_GLPES_VFIP4RXMCPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT) -#define I40E_GLPES_VFIP4RXOCTSHI(_i) (0x00018204 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT) -#define I40E_GLPES_VFIP4RXOCTSLO(_i) (0x00018200 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT) -#define I40E_GLPES_VFIP4RXPKTSHI(_i) (0x00018404 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT) -#define I40E_GLPES_VFIP4RXPKTSLO(_i) (0x00018400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT) -#define I40E_GLPES_VFIP4RXTRUNC(_i) (0x00018700 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4RXTRUNC_MAX_INDEX 31 -#define I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_SHIFT 0 -#define I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_SHIFT) -#define I40E_GLPES_VFIP4TXFRAGSHI(_i) (0x00019E04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXFRAGSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT 0 -#define I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT) -#define I40E_GLPES_VFIP4TXFRAGSLO(_i) (0x00019E00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXFRAGSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT 0 -#define I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT) -#define I40E_GLPES_VFIP4TXMCOCTSHI(_i) (0x0001A004 + ((_i) * 4)) -#define I40E_GLPES_VFIP4TXMCOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT) -#define I40E_GLPES_VFIP4TXMCOCTSLO(_i) (0x0001A000 + ((_i) * 4)) -#define I40E_GLPES_VFIP4TXMCOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT) -#define I40E_GLPES_VFIP4TXMCPKTSHI(_i) (0x0001A204 + ((_i) * 4)) -#define I40E_GLPES_VFIP4TXMCPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT) -#define I40E_GLPES_VFIP4TXMCPKTSLO(_i) (0x0001A200 + ((_i) * 4)) -#define I40E_GLPES_VFIP4TXMCPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT) -#define I40E_GLPES_VFIP4TXNOROUTE(_i) (0x0001AE00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXNOROUTE_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT 0 -#define I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT) -#define I40E_GLPES_VFIP4TXOCTSHI(_i) (0x00019A04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT) -#define I40E_GLPES_VFIP4TXOCTSLO(_i) (0x00019A00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT) -#define I40E_GLPES_VFIP4TXPKTSHI(_i) (0x00019C04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT) -#define I40E_GLPES_VFIP4TXPKTSLO(_i) (0x00019C00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP4TXPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT) -#define I40E_GLPES_VFIP6RXDISCARD(_i) (0x00019200 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXDISCARD_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_SHIFT 0 -#define I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_SHIFT) -#define I40E_GLPES_VFIP6RXFRAGSHI(_i) (0x00019404 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXFRAGSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT 0 -#define I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT) -#define I40E_GLPES_VFIP6RXFRAGSLO(_i) (0x00019400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXFRAGSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT 0 -#define I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT) -#define I40E_GLPES_VFIP6RXMCOCTSHI(_i) (0x00019604 + ((_i) * 4)) -#define I40E_GLPES_VFIP6RXMCOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT) -#define I40E_GLPES_VFIP6RXMCOCTSLO(_i) (0x00019600 + ((_i) * 4)) -#define I40E_GLPES_VFIP6RXMCOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT) -#define I40E_GLPES_VFIP6RXMCPKTSHI(_i) (0x00019804 + ((_i) * 4)) -#define I40E_GLPES_VFIP6RXMCPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT) -#define I40E_GLPES_VFIP6RXMCPKTSLO(_i) (0x00019800 + ((_i) * 4)) -#define I40E_GLPES_VFIP6RXMCPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT) -#define I40E_GLPES_VFIP6RXOCTSHI(_i) (0x00018E04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT) -#define I40E_GLPES_VFIP6RXOCTSLO(_i) (0x00018E00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT) -#define I40E_GLPES_VFIP6RXPKTSHI(_i) (0x00019004 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT) -#define I40E_GLPES_VFIP6RXPKTSLO(_i) (0x00019000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT) -#define I40E_GLPES_VFIP6RXTRUNC(_i) (0x00019300 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6RXTRUNC_MAX_INDEX 31 -#define I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_SHIFT 0 -#define I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_SHIFT) -#define I40E_GLPES_VFIP6TXFRAGSHI(_i) (0x0001A804 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXFRAGSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT 0 -#define I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT) -#define I40E_GLPES_VFIP6TXFRAGSLO(_i) (0x0001A800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXFRAGSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT 0 -#define I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT) -#define I40E_GLPES_VFIP6TXMCOCTSHI(_i) (0x0001AA04 + ((_i) * 4)) -#define I40E_GLPES_VFIP6TXMCOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT) -#define I40E_GLPES_VFIP6TXMCOCTSLO(_i) (0x0001AA00 + ((_i) * 4)) -#define I40E_GLPES_VFIP6TXMCOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT) -#define I40E_GLPES_VFIP6TXMCPKTSHI(_i) (0x0001AC04 + ((_i) * 4)) -#define I40E_GLPES_VFIP6TXMCPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT) -#define I40E_GLPES_VFIP6TXMCPKTSLO(_i) (0x0001AC00 + ((_i) * 4)) -#define I40E_GLPES_VFIP6TXMCPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT) -#define I40E_GLPES_VFIP6TXNOROUTE(_i) (0x0001AF00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXNOROUTE_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT 0 -#define I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT) -#define I40E_GLPES_VFIP6TXOCTSHI(_i) (0x0001A404 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXOCTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT) -#define I40E_GLPES_VFIP6TXOCTSLO(_i) (0x0001A400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXOCTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT) -#define I40E_GLPES_VFIP6TXPKTSHI(_i) (0x0001A604 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT 0 -#define I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT) -#define I40E_GLPES_VFIP6TXPKTSLO(_i) (0x0001A600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFIP6TXPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT 0 -#define I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT) -#define I40E_GLPES_VFRDMARXRDSHI(_i) (0x0001BE04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMARXRDSHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_SHIFT 0 -#define I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_SHIFT) -#define I40E_GLPES_VFRDMARXRDSLO(_i) (0x0001BE00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMARXRDSLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_SHIFT 0 -#define I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_SHIFT) -#define I40E_GLPES_VFRDMARXSNDSHI(_i) (0x0001C004 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMARXSNDSHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT 0 -#define I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT) -#define I40E_GLPES_VFRDMARXSNDSLO(_i) (0x0001C000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMARXSNDSLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT 0 -#define I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT) -#define I40E_GLPES_VFRDMARXWRSHI(_i) (0x0001BC04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMARXWRSHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_SHIFT 0 -#define I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_SHIFT) -#define I40E_GLPES_VFRDMARXWRSLO(_i) (0x0001BC00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMARXWRSLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_SHIFT 0 -#define I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_SHIFT) -#define I40E_GLPES_VFRDMATXRDSHI(_i) (0x0001C404 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMATXRDSHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_SHIFT 0 -#define I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_SHIFT) -#define I40E_GLPES_VFRDMATXRDSLO(_i) (0x0001C400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMATXRDSLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_SHIFT 0 -#define I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_SHIFT) -#define I40E_GLPES_VFRDMATXSNDSHI(_i) (0x0001C604 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMATXSNDSHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT 0 -#define I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT) -#define I40E_GLPES_VFRDMATXSNDSLO(_i) (0x0001C600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMATXSNDSLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT 0 -#define I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT) -#define I40E_GLPES_VFRDMATXWRSHI(_i) (0x0001C204 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMATXWRSHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_SHIFT 0 -#define I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_SHIFT) -#define I40E_GLPES_VFRDMATXWRSLO(_i) (0x0001C200 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMATXWRSLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_SHIFT 0 -#define I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_SHIFT) -#define I40E_GLPES_VFRDMAVBNDHI(_i) (0x0001C804 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMAVBNDHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_SHIFT 0 -#define I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_SHIFT) -#define I40E_GLPES_VFRDMAVBNDLO(_i) (0x0001C800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMAVBNDLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_SHIFT 0 -#define I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_SHIFT) -#define I40E_GLPES_VFRDMAVINVHI(_i) (0x0001CA04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMAVINVHI_MAX_INDEX 31 -#define I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_SHIFT 0 -#define I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_SHIFT) -#define I40E_GLPES_VFRDMAVINVLO(_i) (0x0001CA00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRDMAVINVLO_MAX_INDEX 31 -#define I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_SHIFT 0 -#define I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_SHIFT) -#define I40E_GLPES_VFRXVLANERR(_i) (0x00018000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFRXVLANERR_MAX_INDEX 31 -#define I40E_GLPES_VFRXVLANERR_RXVLANERR_SHIFT 0 -#define I40E_GLPES_VFRXVLANERR_RXVLANERR_MASK (0xFFFFFF << I40E_GLPES_VFRXVLANERR_RXVLANERR_SHIFT) -#define I40E_GLPES_VFTCPRTXSEG(_i) (0x0001B600 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFTCPRTXSEG_MAX_INDEX 31 -#define I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_SHIFT 0 -#define I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_MASK (0xFFFFFFFF << I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_SHIFT) -#define I40E_GLPES_VFTCPRXOPTERR(_i) (0x0001B200 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFTCPRXOPTERR_MAX_INDEX 31 -#define I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_SHIFT 0 -#define I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_MASK (0xFFFFFF << I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_SHIFT) -#define I40E_GLPES_VFTCPRXPROTOERR(_i) (0x0001B300 + ((_i) * 4)) -#define I40E_GLPES_VFTCPRXPROTOERR_MAX_INDEX 31 -#define I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT 0 -#define I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_MASK (0xFFFFFF << I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT) -#define I40E_GLPES_VFTCPRXSEGSHI(_i) (0x0001B004 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFTCPRXSEGSHI_MAX_INDEX 31 -#define I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT 0 -#define I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_MASK (0xFFFF << I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT) -#define I40E_GLPES_VFTCPRXSEGSLO(_i) (0x0001B000 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFTCPRXSEGSLO_MAX_INDEX 31 -#define I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT 0 -#define I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT) -#define I40E_GLPES_VFTCPTXSEGHI(_i) (0x0001B404 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFTCPTXSEGHI_MAX_INDEX 31 -#define I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_SHIFT 0 -#define I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_MASK (0xFFFF << I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_SHIFT) -#define I40E_GLPES_VFTCPTXSEGLO(_i) (0x0001B400 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFTCPTXSEGLO_MAX_INDEX 31 -#define I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_SHIFT 0 -#define I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_MASK (0xFFFFFFFF << I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_SHIFT) -#define I40E_GLPES_VFUDPRXPKTSHI(_i) (0x0001B804 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFUDPRXPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT 0 -#define I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT) -#define I40E_GLPES_VFUDPRXPKTSLO(_i) (0x0001B800 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFUDPRXPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT 0 -#define I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT) -#define I40E_GLPES_VFUDPTXPKTSHI(_i) (0x0001BA04 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFUDPTXPKTSHI_MAX_INDEX 31 -#define I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT 0 -#define I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT) -#define I40E_GLPES_VFUDPTXPKTSLO(_i) (0x0001BA00 + ((_i) * 4)) /* _i=0...31 */ -#define I40E_GLPES_VFUDPTXPKTSLO_MAX_INDEX 31 -#define I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT 0 -#define I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT) -#define I40E_PRTPM_EEE_STAT 0x001E4320 +#define I40E_PFPCI_VMPEND_PENDING_MASK I40E_MASK(0x1, I40E_PFPCI_VMPEND_PENDING_SHIFT) +#define I40E_PRTPM_EEE_STAT 0x001E4320 /* Reset: GLOBR */ #define I40E_PRTPM_EEE_STAT_EEE_NEG_SHIFT 29 -#define I40E_PRTPM_EEE_STAT_EEE_NEG_MASK (0x1 << I40E_PRTPM_EEE_STAT_EEE_NEG_SHIFT) +#define I40E_PRTPM_EEE_STAT_EEE_NEG_MASK I40E_MASK(0x1, I40E_PRTPM_EEE_STAT_EEE_NEG_SHIFT) #define I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT 30 -#define I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_MASK (0x1 << I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT) +#define I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_MASK I40E_MASK(0x1, I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT) #define I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT 31 -#define I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_MASK (0x1 << I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT) -#define I40E_PRTPM_EEEC 0x001E4380 +#define I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_MASK I40E_MASK(0x1, I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT) +#define I40E_PRTPM_EEEC 0x001E4380 /* Reset: GLOBR */ #define I40E_PRTPM_EEEC_TW_WAKE_MIN_SHIFT 16 -#define I40E_PRTPM_EEEC_TW_WAKE_MIN_MASK (0x3F << I40E_PRTPM_EEEC_TW_WAKE_MIN_SHIFT) +#define I40E_PRTPM_EEEC_TW_WAKE_MIN_MASK I40E_MASK(0x3F, I40E_PRTPM_EEEC_TW_WAKE_MIN_SHIFT) #define I40E_PRTPM_EEEC_TX_LU_LPI_DLY_SHIFT 24 -#define I40E_PRTPM_EEEC_TX_LU_LPI_DLY_MASK (0x3 << I40E_PRTPM_EEEC_TX_LU_LPI_DLY_SHIFT) +#define I40E_PRTPM_EEEC_TX_LU_LPI_DLY_MASK I40E_MASK(0x3, I40E_PRTPM_EEEC_TX_LU_LPI_DLY_SHIFT) #define I40E_PRTPM_EEEC_TEEE_DLY_SHIFT 26 -#define I40E_PRTPM_EEEC_TEEE_DLY_MASK (0x3F << I40E_PRTPM_EEEC_TEEE_DLY_SHIFT) -#define I40E_PRTPM_EEEFWD 0x001E4400 +#define I40E_PRTPM_EEEC_TEEE_DLY_MASK I40E_MASK(0x3F, I40E_PRTPM_EEEC_TEEE_DLY_SHIFT) +#define I40E_PRTPM_EEEFWD 0x001E4400 /* Reset: GLOBR */ #define I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_SHIFT 31 -#define I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_MASK (0x1 << I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_SHIFT) -#define I40E_PRTPM_EEER 0x001E4360 +#define I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_MASK I40E_MASK(0x1, I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_SHIFT) +#define I40E_PRTPM_EEER 0x001E4360 /* Reset: GLOBR */ #define I40E_PRTPM_EEER_TW_SYSTEM_SHIFT 0 -#define I40E_PRTPM_EEER_TW_SYSTEM_MASK (0xFFFF << I40E_PRTPM_EEER_TW_SYSTEM_SHIFT) +#define I40E_PRTPM_EEER_TW_SYSTEM_MASK I40E_MASK(0xFFFF, I40E_PRTPM_EEER_TW_SYSTEM_SHIFT) #define I40E_PRTPM_EEER_TX_LPI_EN_SHIFT 16 -#define I40E_PRTPM_EEER_TX_LPI_EN_MASK (0x1 << I40E_PRTPM_EEER_TX_LPI_EN_SHIFT) -#define I40E_PRTPM_EEETXC 0x001E43E0 +#define I40E_PRTPM_EEER_TX_LPI_EN_MASK I40E_MASK(0x1, I40E_PRTPM_EEER_TX_LPI_EN_SHIFT) +#define I40E_PRTPM_EEETXC 0x001E43E0 /* Reset: GLOBR */ #define I40E_PRTPM_EEETXC_TW_PHY_SHIFT 0 -#define I40E_PRTPM_EEETXC_TW_PHY_MASK (0xFFFF << I40E_PRTPM_EEETXC_TW_PHY_SHIFT) -#define I40E_PRTPM_GC 0x000B8140 +#define I40E_PRTPM_EEETXC_TW_PHY_MASK I40E_MASK(0xFFFF, I40E_PRTPM_EEETXC_TW_PHY_SHIFT) +#define I40E_PRTPM_GC 0x000B8140 /* Reset: POR */ #define I40E_PRTPM_GC_EMP_LINK_ON_SHIFT 0 -#define I40E_PRTPM_GC_EMP_LINK_ON_MASK (0x1 << I40E_PRTPM_GC_EMP_LINK_ON_SHIFT) +#define I40E_PRTPM_GC_EMP_LINK_ON_MASK I40E_MASK(0x1, I40E_PRTPM_GC_EMP_LINK_ON_SHIFT) #define I40E_PRTPM_GC_MNG_VETO_SHIFT 1 -#define I40E_PRTPM_GC_MNG_VETO_MASK (0x1 << I40E_PRTPM_GC_MNG_VETO_SHIFT) +#define I40E_PRTPM_GC_MNG_VETO_MASK I40E_MASK(0x1, I40E_PRTPM_GC_MNG_VETO_SHIFT) #define I40E_PRTPM_GC_RATD_SHIFT 2 -#define I40E_PRTPM_GC_RATD_MASK (0x1 << I40E_PRTPM_GC_RATD_SHIFT) +#define I40E_PRTPM_GC_RATD_MASK I40E_MASK(0x1, I40E_PRTPM_GC_RATD_SHIFT) #define I40E_PRTPM_GC_LCDMP_SHIFT 3 -#define I40E_PRTPM_GC_LCDMP_MASK (0x1 << I40E_PRTPM_GC_LCDMP_SHIFT) +#define I40E_PRTPM_GC_LCDMP_MASK I40E_MASK(0x1, I40E_PRTPM_GC_LCDMP_SHIFT) #define I40E_PRTPM_GC_LPLU_ASSERTED_SHIFT 31 -#define I40E_PRTPM_GC_LPLU_ASSERTED_MASK (0x1 << I40E_PRTPM_GC_LPLU_ASSERTED_SHIFT) -#define I40E_PRTPM_RLPIC 0x001E43A0 +#define I40E_PRTPM_GC_LPLU_ASSERTED_MASK I40E_MASK(0x1, I40E_PRTPM_GC_LPLU_ASSERTED_SHIFT) +#define I40E_PRTPM_RLPIC 0x001E43A0 /* Reset: GLOBR */ #define I40E_PRTPM_RLPIC_ERLPIC_SHIFT 0 -#define I40E_PRTPM_RLPIC_ERLPIC_MASK (0xFFFFFFFF << I40E_PRTPM_RLPIC_ERLPIC_SHIFT) -#define I40E_PRTPM_TLPIC 0x001E43C0 +#define I40E_PRTPM_RLPIC_ERLPIC_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTPM_RLPIC_ERLPIC_SHIFT) +#define I40E_PRTPM_TLPIC 0x001E43C0 /* Reset: GLOBR */ #define I40E_PRTPM_TLPIC_ETLPIC_SHIFT 0 -#define I40E_PRTPM_TLPIC_ETLPIC_MASK (0xFFFFFFFF << I40E_PRTPM_TLPIC_ETLPIC_SHIFT) -#define I40E_GLRPB_DPSS 0x000AC828 +#define I40E_PRTPM_TLPIC_ETLPIC_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTPM_TLPIC_ETLPIC_SHIFT) +#define I40E_GLRPB_DPSS 0x000AC828 /* Reset: CORER */ #define I40E_GLRPB_DPSS_DPS_TCN_SHIFT 0 -#define I40E_GLRPB_DPSS_DPS_TCN_MASK (0xFFFFF << I40E_GLRPB_DPSS_DPS_TCN_SHIFT) -#define I40E_GLRPB_GHW 0x000AC830 +#define I40E_GLRPB_DPSS_DPS_TCN_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_DPSS_DPS_TCN_SHIFT) +#define I40E_GLRPB_GHW 0x000AC830 /* Reset: CORER */ #define I40E_GLRPB_GHW_GHW_SHIFT 0 -#define I40E_GLRPB_GHW_GHW_MASK (0xFFFFF << I40E_GLRPB_GHW_GHW_SHIFT) -#define I40E_GLRPB_GLW 0x000AC834 +#define I40E_GLRPB_GHW_GHW_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_GHW_GHW_SHIFT) +#define I40E_GLRPB_GLW 0x000AC834 /* Reset: CORER */ #define I40E_GLRPB_GLW_GLW_SHIFT 0 -#define I40E_GLRPB_GLW_GLW_MASK (0xFFFFF << I40E_GLRPB_GLW_GLW_SHIFT) -#define I40E_GLRPB_PHW 0x000AC844 +#define I40E_GLRPB_GLW_GLW_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_GLW_GLW_SHIFT) +#define I40E_GLRPB_PHW 0x000AC844 /* Reset: CORER */ #define I40E_GLRPB_PHW_PHW_SHIFT 0 -#define I40E_GLRPB_PHW_PHW_MASK (0xFFFFF << I40E_GLRPB_PHW_PHW_SHIFT) -#define I40E_GLRPB_PLW 0x000AC848 +#define I40E_GLRPB_PHW_PHW_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_PHW_PHW_SHIFT) +#define I40E_GLRPB_PLW 0x000AC848 /* Reset: CORER */ #define I40E_GLRPB_PLW_PLW_SHIFT 0 -#define I40E_GLRPB_PLW_PLW_MASK (0xFFFFF << I40E_GLRPB_PLW_PLW_SHIFT) -#define I40E_PRTRPB_DHW(_i) (0x000AC100 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_GLRPB_PLW_PLW_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_PLW_PLW_SHIFT) +#define I40E_PRTRPB_DHW(_i) (0x000AC100 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTRPB_DHW_MAX_INDEX 7 #define I40E_PRTRPB_DHW_DHW_TCN_SHIFT 0 -#define I40E_PRTRPB_DHW_DHW_TCN_MASK (0xFFFFF << I40E_PRTRPB_DHW_DHW_TCN_SHIFT) -#define I40E_PRTRPB_DLW(_i) (0x000AC220 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTRPB_DHW_DHW_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_DHW_DHW_TCN_SHIFT) +#define I40E_PRTRPB_DLW(_i) (0x000AC220 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTRPB_DLW_MAX_INDEX 7 #define I40E_PRTRPB_DLW_DLW_TCN_SHIFT 0 -#define I40E_PRTRPB_DLW_DLW_TCN_MASK (0xFFFFF << I40E_PRTRPB_DLW_DLW_TCN_SHIFT) -#define I40E_PRTRPB_DPS(_i) (0x000AC320 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTRPB_DLW_DLW_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_DLW_DLW_TCN_SHIFT) +#define I40E_PRTRPB_DPS(_i) (0x000AC320 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTRPB_DPS_MAX_INDEX 7 #define I40E_PRTRPB_DPS_DPS_TCN_SHIFT 0 -#define I40E_PRTRPB_DPS_DPS_TCN_MASK (0xFFFFF << I40E_PRTRPB_DPS_DPS_TCN_SHIFT) -#define I40E_PRTRPB_SHT(_i) (0x000AC480 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTRPB_DPS_DPS_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_DPS_DPS_TCN_SHIFT) +#define I40E_PRTRPB_SHT(_i) (0x000AC480 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTRPB_SHT_MAX_INDEX 7 #define I40E_PRTRPB_SHT_SHT_TCN_SHIFT 0 -#define I40E_PRTRPB_SHT_SHT_TCN_MASK (0xFFFFF << I40E_PRTRPB_SHT_SHT_TCN_SHIFT) -#define I40E_PRTRPB_SHW 0x000AC580 +#define I40E_PRTRPB_SHT_SHT_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SHT_SHT_TCN_SHIFT) +#define I40E_PRTRPB_SHW 0x000AC580 /* Reset: CORER */ #define I40E_PRTRPB_SHW_SHW_SHIFT 0 -#define I40E_PRTRPB_SHW_SHW_MASK (0xFFFFF << I40E_PRTRPB_SHW_SHW_SHIFT) -#define I40E_PRTRPB_SLT(_i) (0x000AC5A0 + ((_i) * 32)) /* _i=0...7 */ +#define I40E_PRTRPB_SHW_SHW_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SHW_SHW_SHIFT) +#define I40E_PRTRPB_SLT(_i) (0x000AC5A0 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_PRTRPB_SLT_MAX_INDEX 7 #define I40E_PRTRPB_SLT_SLT_TCN_SHIFT 0 -#define I40E_PRTRPB_SLT_SLT_TCN_MASK (0xFFFFF << I40E_PRTRPB_SLT_SLT_TCN_SHIFT) -#define I40E_PRTRPB_SLW 0x000AC6A0 +#define I40E_PRTRPB_SLT_SLT_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SLT_SLT_TCN_SHIFT) +#define I40E_PRTRPB_SLW 0x000AC6A0 /* Reset: CORER */ #define I40E_PRTRPB_SLW_SLW_SHIFT 0 -#define I40E_PRTRPB_SLW_SLW_MASK (0xFFFFF << I40E_PRTRPB_SLW_SLW_SHIFT) -#define I40E_PRTRPB_SPS 0x000AC7C0 +#define I40E_PRTRPB_SLW_SLW_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SLW_SLW_SHIFT) +#define I40E_PRTRPB_SPS 0x000AC7C0 /* Reset: CORER */ #define I40E_PRTRPB_SPS_SPS_SHIFT 0 -#define I40E_PRTRPB_SPS_SPS_MASK (0xFFFFF << I40E_PRTRPB_SPS_SPS_SHIFT) -#define I40E_GLQF_APBVT(_i) (0x00260000 + ((_i) * 4)) /* _i=0...2047 */ -#define I40E_GLQF_APBVT_MAX_INDEX 2047 -#define I40E_GLQF_APBVT_APBVT_SHIFT 0 -#define I40E_GLQF_APBVT_APBVT_MASK (0xFFFFFFFF << I40E_GLQF_APBVT_APBVT_SHIFT) -#define I40E_GLQF_CTL 0x00269BA4 +#define I40E_PRTRPB_SPS_SPS_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SPS_SPS_SHIFT) +#define I40E_GLQF_CTL 0x00269BA4 /* Reset: CORER */ #define I40E_GLQF_CTL_HTOEP_SHIFT 1 -#define I40E_GLQF_CTL_HTOEP_MASK (0x1 << I40E_GLQF_CTL_HTOEP_SHIFT) +#define I40E_GLQF_CTL_HTOEP_MASK I40E_MASK(0x1, I40E_GLQF_CTL_HTOEP_SHIFT) #define I40E_GLQF_CTL_HTOEP_FCOE_SHIFT 2 -#define I40E_GLQF_CTL_HTOEP_FCOE_MASK (0x1 << I40E_GLQF_CTL_HTOEP_FCOE_SHIFT) +#define I40E_GLQF_CTL_HTOEP_FCOE_MASK I40E_MASK(0x1, I40E_GLQF_CTL_HTOEP_FCOE_SHIFT) #define I40E_GLQF_CTL_PCNT_ALLOC_SHIFT 3 -#define I40E_GLQF_CTL_PCNT_ALLOC_MASK (0x7 << I40E_GLQF_CTL_PCNT_ALLOC_SHIFT) +#define I40E_GLQF_CTL_PCNT_ALLOC_MASK I40E_MASK(0x7, I40E_GLQF_CTL_PCNT_ALLOC_SHIFT) +#define I40E_GLQF_CTL_FD_AUTO_PCTYPE_SHIFT 6 +#define I40E_GLQF_CTL_FD_AUTO_PCTYPE_MASK I40E_MASK(0x1, I40E_GLQF_CTL_FD_AUTO_PCTYPE_SHIFT) #define I40E_GLQF_CTL_RSVD_SHIFT 7 -#define I40E_GLQF_CTL_RSVD_MASK (0x1 << I40E_GLQF_CTL_RSVD_SHIFT) +#define I40E_GLQF_CTL_RSVD_MASK I40E_MASK(0x1, I40E_GLQF_CTL_RSVD_SHIFT) #define I40E_GLQF_CTL_MAXPEBLEN_SHIFT 8 -#define I40E_GLQF_CTL_MAXPEBLEN_MASK (0x7 << I40E_GLQF_CTL_MAXPEBLEN_SHIFT) +#define I40E_GLQF_CTL_MAXPEBLEN_MASK I40E_MASK(0x7, I40E_GLQF_CTL_MAXPEBLEN_SHIFT) #define I40E_GLQF_CTL_MAXFCBLEN_SHIFT 11 -#define I40E_GLQF_CTL_MAXFCBLEN_MASK (0x7 << I40E_GLQF_CTL_MAXFCBLEN_SHIFT) +#define I40E_GLQF_CTL_MAXFCBLEN_MASK I40E_MASK(0x7, I40E_GLQF_CTL_MAXFCBLEN_SHIFT) #define I40E_GLQF_CTL_MAXFDBLEN_SHIFT 14 -#define I40E_GLQF_CTL_MAXFDBLEN_MASK (0x7 << I40E_GLQF_CTL_MAXFDBLEN_SHIFT) +#define I40E_GLQF_CTL_MAXFDBLEN_MASK I40E_MASK(0x7, I40E_GLQF_CTL_MAXFDBLEN_SHIFT) #define I40E_GLQF_CTL_FDBEST_SHIFT 17 -#define I40E_GLQF_CTL_FDBEST_MASK (0xFF << I40E_GLQF_CTL_FDBEST_SHIFT) +#define I40E_GLQF_CTL_FDBEST_MASK I40E_MASK(0xFF, I40E_GLQF_CTL_FDBEST_SHIFT) #define I40E_GLQF_CTL_PROGPRIO_SHIFT 25 -#define I40E_GLQF_CTL_PROGPRIO_MASK (0x1 << I40E_GLQF_CTL_PROGPRIO_SHIFT) +#define I40E_GLQF_CTL_PROGPRIO_MASK I40E_MASK(0x1, I40E_GLQF_CTL_PROGPRIO_SHIFT) #define I40E_GLQF_CTL_INVALPRIO_SHIFT 26 -#define I40E_GLQF_CTL_INVALPRIO_MASK (0x1 << I40E_GLQF_CTL_INVALPRIO_SHIFT) +#define I40E_GLQF_CTL_INVALPRIO_MASK I40E_MASK(0x1, I40E_GLQF_CTL_INVALPRIO_SHIFT) #define I40E_GLQF_CTL_IGNORE_IP_SHIFT 27 -#define I40E_GLQF_CTL_IGNORE_IP_MASK (0x1 << I40E_GLQF_CTL_IGNORE_IP_SHIFT) -#define I40E_GLQF_FDCNT_0 0x00269BAC +#define I40E_GLQF_CTL_IGNORE_IP_MASK I40E_MASK(0x1, I40E_GLQF_CTL_IGNORE_IP_SHIFT) +#define I40E_GLQF_FDCNT_0 0x00269BAC /* Reset: CORER */ #define I40E_GLQF_FDCNT_0_GUARANT_CNT_SHIFT 0 -#define I40E_GLQF_FDCNT_0_GUARANT_CNT_MASK (0x1FFF << I40E_GLQF_FDCNT_0_GUARANT_CNT_SHIFT) +#define I40E_GLQF_FDCNT_0_GUARANT_CNT_MASK I40E_MASK(0x1FFF, I40E_GLQF_FDCNT_0_GUARANT_CNT_SHIFT) #define I40E_GLQF_FDCNT_0_BESTCNT_SHIFT 13 -#define I40E_GLQF_FDCNT_0_BESTCNT_MASK (0x1FFF << I40E_GLQF_FDCNT_0_BESTCNT_SHIFT) -#define I40E_GLQF_HSYM(_i) (0x00269D00 + ((_i) * 4)) /* _i=0...63 */ +#define I40E_GLQF_FDCNT_0_BESTCNT_MASK I40E_MASK(0x1FFF, I40E_GLQF_FDCNT_0_BESTCNT_SHIFT) +#define I40E_GLQF_HKEY(_i) (0x00270140 + ((_i) * 4)) /* _i=0...12 */ /* Reset: CORER */ +#define I40E_GLQF_HKEY_MAX_INDEX 12 +#define I40E_GLQF_HKEY_KEY_0_SHIFT 0 +#define I40E_GLQF_HKEY_KEY_0_MASK I40E_MASK(0xFF, I40E_GLQF_HKEY_KEY_0_SHIFT) +#define I40E_GLQF_HKEY_KEY_1_SHIFT 8 +#define I40E_GLQF_HKEY_KEY_1_MASK I40E_MASK(0xFF, I40E_GLQF_HKEY_KEY_1_SHIFT) +#define I40E_GLQF_HKEY_KEY_2_SHIFT 16 +#define I40E_GLQF_HKEY_KEY_2_MASK I40E_MASK(0xFF, I40E_GLQF_HKEY_KEY_2_SHIFT) +#define I40E_GLQF_HKEY_KEY_3_SHIFT 24 +#define I40E_GLQF_HKEY_KEY_3_MASK I40E_MASK(0xFF, I40E_GLQF_HKEY_KEY_3_SHIFT) +#define I40E_GLQF_HSYM(_i) (0x00269D00 + ((_i) * 4)) /* _i=0...63 */ /* Reset: CORER */ #define I40E_GLQF_HSYM_MAX_INDEX 63 #define I40E_GLQF_HSYM_SYMH_ENA_SHIFT 0 -#define I40E_GLQF_HSYM_SYMH_ENA_MASK (0x1 << I40E_GLQF_HSYM_SYMH_ENA_SHIFT) -#define I40E_GLQF_PCNT(_i) (0x00266800 + ((_i) * 4)) /* _i=0...511 */ +#define I40E_GLQF_HSYM_SYMH_ENA_MASK I40E_MASK(0x1, I40E_GLQF_HSYM_SYMH_ENA_SHIFT) +#define I40E_GLQF_PCNT(_i) (0x00266800 + ((_i) * 4)) /* _i=0...511 */ /* Reset: CORER */ #define I40E_GLQF_PCNT_MAX_INDEX 511 #define I40E_GLQF_PCNT_PCNT_SHIFT 0 -#define I40E_GLQF_PCNT_PCNT_MASK (0xFFFFFFFF << I40E_GLQF_PCNT_PCNT_SHIFT) -#define I40E_GLQF_SWAP(_i, _j) (0x00267E00 + ((_i) * 4 + (_j) * 8)) /* _i=0...1, _j=0...63 */ +#define I40E_GLQF_PCNT_PCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLQF_PCNT_PCNT_SHIFT) +#define I40E_GLQF_SWAP(_i, _j) (0x00267E00 + ((_i) * 4 + (_j) * 8)) /* _i=0...1, _j=0...63 */ /* Reset: CORER */ #define I40E_GLQF_SWAP_MAX_INDEX 1 #define I40E_GLQF_SWAP_OFF0_SRC0_SHIFT 0 -#define I40E_GLQF_SWAP_OFF0_SRC0_MASK (0x3F << I40E_GLQF_SWAP_OFF0_SRC0_SHIFT) +#define I40E_GLQF_SWAP_OFF0_SRC0_MASK I40E_MASK(0x3F, I40E_GLQF_SWAP_OFF0_SRC0_SHIFT) #define I40E_GLQF_SWAP_OFF0_SRC1_SHIFT 6 -#define I40E_GLQF_SWAP_OFF0_SRC1_MASK (0x3F << I40E_GLQF_SWAP_OFF0_SRC1_SHIFT) +#define I40E_GLQF_SWAP_OFF0_SRC1_MASK I40E_MASK(0x3F, I40E_GLQF_SWAP_OFF0_SRC1_SHIFT) #define I40E_GLQF_SWAP_FLEN0_SHIFT 12 -#define I40E_GLQF_SWAP_FLEN0_MASK (0xF << I40E_GLQF_SWAP_FLEN0_SHIFT) +#define I40E_GLQF_SWAP_FLEN0_MASK I40E_MASK(0xF, I40E_GLQF_SWAP_FLEN0_SHIFT) #define I40E_GLQF_SWAP_OFF1_SRC0_SHIFT 16 -#define I40E_GLQF_SWAP_OFF1_SRC0_MASK (0x3F << I40E_GLQF_SWAP_OFF1_SRC0_SHIFT) +#define I40E_GLQF_SWAP_OFF1_SRC0_MASK I40E_MASK(0x3F, I40E_GLQF_SWAP_OFF1_SRC0_SHIFT) #define I40E_GLQF_SWAP_OFF1_SRC1_SHIFT 22 -#define I40E_GLQF_SWAP_OFF1_SRC1_MASK (0x3F << I40E_GLQF_SWAP_OFF1_SRC1_SHIFT) +#define I40E_GLQF_SWAP_OFF1_SRC1_MASK I40E_MASK(0x3F, I40E_GLQF_SWAP_OFF1_SRC1_SHIFT) #define I40E_GLQF_SWAP_FLEN1_SHIFT 28 -#define I40E_GLQF_SWAP_FLEN1_MASK (0xF << I40E_GLQF_SWAP_FLEN1_SHIFT) -#define I40E_PFQF_CTL_0 0x001C0AC0 +#define I40E_GLQF_SWAP_FLEN1_MASK I40E_MASK(0xF, I40E_GLQF_SWAP_FLEN1_SHIFT) +#define I40E_PFQF_CTL_0 0x001C0AC0 /* Reset: CORER */ #define I40E_PFQF_CTL_0_PEHSIZE_SHIFT 0 -#define I40E_PFQF_CTL_0_PEHSIZE_MASK (0x1F << I40E_PFQF_CTL_0_PEHSIZE_SHIFT) +#define I40E_PFQF_CTL_0_PEHSIZE_MASK I40E_MASK(0x1F, I40E_PFQF_CTL_0_PEHSIZE_SHIFT) #define I40E_PFQF_CTL_0_PEDSIZE_SHIFT 5 -#define I40E_PFQF_CTL_0_PEDSIZE_MASK (0x1F << I40E_PFQF_CTL_0_PEDSIZE_SHIFT) +#define I40E_PFQF_CTL_0_PEDSIZE_MASK I40E_MASK(0x1F, I40E_PFQF_CTL_0_PEDSIZE_SHIFT) #define I40E_PFQF_CTL_0_PFFCHSIZE_SHIFT 10 -#define I40E_PFQF_CTL_0_PFFCHSIZE_MASK (0xF << I40E_PFQF_CTL_0_PFFCHSIZE_SHIFT) +#define I40E_PFQF_CTL_0_PFFCHSIZE_MASK I40E_MASK(0xF, I40E_PFQF_CTL_0_PFFCHSIZE_SHIFT) #define I40E_PFQF_CTL_0_PFFCDSIZE_SHIFT 14 -#define I40E_PFQF_CTL_0_PFFCDSIZE_MASK (0x3 << I40E_PFQF_CTL_0_PFFCDSIZE_SHIFT) +#define I40E_PFQF_CTL_0_PFFCDSIZE_MASK I40E_MASK(0x3, I40E_PFQF_CTL_0_PFFCDSIZE_SHIFT) #define I40E_PFQF_CTL_0_HASHLUTSIZE_SHIFT 16 -#define I40E_PFQF_CTL_0_HASHLUTSIZE_MASK (0x1 << I40E_PFQF_CTL_0_HASHLUTSIZE_SHIFT) +#define I40E_PFQF_CTL_0_HASHLUTSIZE_MASK I40E_MASK(0x1, I40E_PFQF_CTL_0_HASHLUTSIZE_SHIFT) #define I40E_PFQF_CTL_0_FD_ENA_SHIFT 17 -#define I40E_PFQF_CTL_0_FD_ENA_MASK (0x1 << I40E_PFQF_CTL_0_FD_ENA_SHIFT) +#define I40E_PFQF_CTL_0_FD_ENA_MASK I40E_MASK(0x1, I40E_PFQF_CTL_0_FD_ENA_SHIFT) #define I40E_PFQF_CTL_0_ETYPE_ENA_SHIFT 18 -#define I40E_PFQF_CTL_0_ETYPE_ENA_MASK (0x1 << I40E_PFQF_CTL_0_ETYPE_ENA_SHIFT) +#define I40E_PFQF_CTL_0_ETYPE_ENA_MASK I40E_MASK(0x1, I40E_PFQF_CTL_0_ETYPE_ENA_SHIFT) #define I40E_PFQF_CTL_0_MACVLAN_ENA_SHIFT 19 -#define I40E_PFQF_CTL_0_MACVLAN_ENA_MASK (0x1 << I40E_PFQF_CTL_0_MACVLAN_ENA_SHIFT) +#define I40E_PFQF_CTL_0_MACVLAN_ENA_MASK I40E_MASK(0x1, I40E_PFQF_CTL_0_MACVLAN_ENA_SHIFT) #define I40E_PFQF_CTL_0_VFFCHSIZE_SHIFT 20 -#define I40E_PFQF_CTL_0_VFFCHSIZE_MASK (0xF << I40E_PFQF_CTL_0_VFFCHSIZE_SHIFT) +#define I40E_PFQF_CTL_0_VFFCHSIZE_MASK I40E_MASK(0xF, I40E_PFQF_CTL_0_VFFCHSIZE_SHIFT) #define I40E_PFQF_CTL_0_VFFCDSIZE_SHIFT 24 -#define I40E_PFQF_CTL_0_VFFCDSIZE_MASK (0x3 << I40E_PFQF_CTL_0_VFFCDSIZE_SHIFT) -#define I40E_PFQF_CTL_1 0x00245D80 +#define I40E_PFQF_CTL_0_VFFCDSIZE_MASK I40E_MASK(0x3, I40E_PFQF_CTL_0_VFFCDSIZE_SHIFT) +#define I40E_PFQF_CTL_1 0x00245D80 /* Reset: CORER */ #define I40E_PFQF_CTL_1_CLEARFDTABLE_SHIFT 0 -#define I40E_PFQF_CTL_1_CLEARFDTABLE_MASK (0x1 << I40E_PFQF_CTL_1_CLEARFDTABLE_SHIFT) -#define I40E_PFQF_FDALLOC 0x00246280 +#define I40E_PFQF_CTL_1_CLEARFDTABLE_MASK I40E_MASK(0x1, I40E_PFQF_CTL_1_CLEARFDTABLE_SHIFT) +#define I40E_PFQF_FDALLOC 0x00246280 /* Reset: CORER */ #define I40E_PFQF_FDALLOC_FDALLOC_SHIFT 0 -#define I40E_PFQF_FDALLOC_FDALLOC_MASK (0xFF << I40E_PFQF_FDALLOC_FDALLOC_SHIFT) +#define I40E_PFQF_FDALLOC_FDALLOC_MASK I40E_MASK(0xFF, I40E_PFQF_FDALLOC_FDALLOC_SHIFT) #define I40E_PFQF_FDALLOC_FDBEST_SHIFT 8 -#define I40E_PFQF_FDALLOC_FDBEST_MASK (0xFF << I40E_PFQF_FDALLOC_FDBEST_SHIFT) -#define I40E_PFQF_FDSTAT 0x00246380 +#define I40E_PFQF_FDALLOC_FDBEST_MASK I40E_MASK(0xFF, I40E_PFQF_FDALLOC_FDBEST_SHIFT) +#define I40E_PFQF_FDSTAT 0x00246380 /* Reset: CORER */ #define I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT 0 -#define I40E_PFQF_FDSTAT_GUARANT_CNT_MASK (0x1FFF << I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT) +#define I40E_PFQF_FDSTAT_GUARANT_CNT_MASK I40E_MASK(0x1FFF, I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT) #define I40E_PFQF_FDSTAT_BEST_CNT_SHIFT 16 -#define I40E_PFQF_FDSTAT_BEST_CNT_MASK (0x1FFF << I40E_PFQF_FDSTAT_BEST_CNT_SHIFT) -#define I40E_PFQF_HENA(_i) (0x00245900 + ((_i) * 128)) /* _i=0...1 */ +#define I40E_PFQF_FDSTAT_BEST_CNT_MASK I40E_MASK(0x1FFF, I40E_PFQF_FDSTAT_BEST_CNT_SHIFT) +#define I40E_PFQF_HENA(_i) (0x00245900 + ((_i) * 128)) /* _i=0...1 */ /* Reset: CORER */ #define I40E_PFQF_HENA_MAX_INDEX 1 #define I40E_PFQF_HENA_PTYPE_ENA_SHIFT 0 -#define I40E_PFQF_HENA_PTYPE_ENA_MASK (0xFFFFFFFF << I40E_PFQF_HENA_PTYPE_ENA_SHIFT) -#define I40E_PFQF_HKEY(_i) (0x00244800 + ((_i) * 128)) /* _i=0...12 */ +#define I40E_PFQF_HENA_PTYPE_ENA_MASK I40E_MASK(0xFFFFFFFF, I40E_PFQF_HENA_PTYPE_ENA_SHIFT) +#define I40E_PFQF_HKEY(_i) (0x00244800 + ((_i) * 128)) /* _i=0...12 */ /* Reset: CORER */ #define I40E_PFQF_HKEY_MAX_INDEX 12 #define I40E_PFQF_HKEY_KEY_0_SHIFT 0 -#define I40E_PFQF_HKEY_KEY_0_MASK (0xFF << I40E_PFQF_HKEY_KEY_0_SHIFT) +#define I40E_PFQF_HKEY_KEY_0_MASK I40E_MASK(0xFF, I40E_PFQF_HKEY_KEY_0_SHIFT) #define I40E_PFQF_HKEY_KEY_1_SHIFT 8 -#define I40E_PFQF_HKEY_KEY_1_MASK (0xFF << I40E_PFQF_HKEY_KEY_1_SHIFT) +#define I40E_PFQF_HKEY_KEY_1_MASK I40E_MASK(0xFF, I40E_PFQF_HKEY_KEY_1_SHIFT) #define I40E_PFQF_HKEY_KEY_2_SHIFT 16 -#define I40E_PFQF_HKEY_KEY_2_MASK (0xFF << I40E_PFQF_HKEY_KEY_2_SHIFT) +#define I40E_PFQF_HKEY_KEY_2_MASK I40E_MASK(0xFF, I40E_PFQF_HKEY_KEY_2_SHIFT) #define I40E_PFQF_HKEY_KEY_3_SHIFT 24 -#define I40E_PFQF_HKEY_KEY_3_MASK (0xFF << I40E_PFQF_HKEY_KEY_3_SHIFT) -#define I40E_PFQF_HLUT(_i) (0x00240000 + ((_i) * 128)) /* _i=0...127 */ +#define I40E_PFQF_HKEY_KEY_3_MASK I40E_MASK(0xFF, I40E_PFQF_HKEY_KEY_3_SHIFT) +#define I40E_PFQF_HLUT(_i) (0x00240000 + ((_i) * 128)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_PFQF_HLUT_MAX_INDEX 127 #define I40E_PFQF_HLUT_LUT0_SHIFT 0 -#define I40E_PFQF_HLUT_LUT0_MASK (0x3F << I40E_PFQF_HLUT_LUT0_SHIFT) +#define I40E_PFQF_HLUT_LUT0_MASK I40E_MASK(0x3F, I40E_PFQF_HLUT_LUT0_SHIFT) #define I40E_PFQF_HLUT_LUT1_SHIFT 8 -#define I40E_PFQF_HLUT_LUT1_MASK (0x3F << I40E_PFQF_HLUT_LUT1_SHIFT) +#define I40E_PFQF_HLUT_LUT1_MASK I40E_MASK(0x3F, I40E_PFQF_HLUT_LUT1_SHIFT) #define I40E_PFQF_HLUT_LUT2_SHIFT 16 -#define I40E_PFQF_HLUT_LUT2_MASK (0x3F << I40E_PFQF_HLUT_LUT2_SHIFT) +#define I40E_PFQF_HLUT_LUT2_MASK I40E_MASK(0x3F, I40E_PFQF_HLUT_LUT2_SHIFT) #define I40E_PFQF_HLUT_LUT3_SHIFT 24 -#define I40E_PFQF_HLUT_LUT3_MASK (0x3F << I40E_PFQF_HLUT_LUT3_SHIFT) -#define I40E_PFQF_HREGION(_i) (0x00245400 + ((_i) * 128)) /* _i=0...7 */ -#define I40E_PFQF_HREGION_MAX_INDEX 7 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_0_SHIFT 0 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_0_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_0_SHIFT) -#define I40E_PFQF_HREGION_REGION_0_SHIFT 1 -#define I40E_PFQF_HREGION_REGION_0_MASK (0x7 << I40E_PFQF_HREGION_REGION_0_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_1_SHIFT 4 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_1_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_1_SHIFT) -#define I40E_PFQF_HREGION_REGION_1_SHIFT 5 -#define I40E_PFQF_HREGION_REGION_1_MASK (0x7 << I40E_PFQF_HREGION_REGION_1_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_2_SHIFT 8 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_2_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_2_SHIFT) -#define I40E_PFQF_HREGION_REGION_2_SHIFT 9 -#define I40E_PFQF_HREGION_REGION_2_MASK (0x7 << I40E_PFQF_HREGION_REGION_2_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_3_SHIFT 12 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_3_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_3_SHIFT) -#define I40E_PFQF_HREGION_REGION_3_SHIFT 13 -#define I40E_PFQF_HREGION_REGION_3_MASK (0x7 << I40E_PFQF_HREGION_REGION_3_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_4_SHIFT 16 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_4_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_4_SHIFT) -#define I40E_PFQF_HREGION_REGION_4_SHIFT 17 -#define I40E_PFQF_HREGION_REGION_4_MASK (0x7 << I40E_PFQF_HREGION_REGION_4_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_5_SHIFT 20 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_5_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_5_SHIFT) -#define I40E_PFQF_HREGION_REGION_5_SHIFT 21 -#define I40E_PFQF_HREGION_REGION_5_MASK (0x7 << I40E_PFQF_HREGION_REGION_5_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_6_SHIFT 24 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_6_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_6_SHIFT) -#define I40E_PFQF_HREGION_REGION_6_SHIFT 25 -#define I40E_PFQF_HREGION_REGION_6_MASK (0x7 << I40E_PFQF_HREGION_REGION_6_SHIFT) -#define I40E_PFQF_HREGION_OVERRIDE_ENA_7_SHIFT 28 -#define I40E_PFQF_HREGION_OVERRIDE_ENA_7_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_7_SHIFT) -#define I40E_PFQF_HREGION_REGION_7_SHIFT 29 -#define I40E_PFQF_HREGION_REGION_7_MASK (0x7 << I40E_PFQF_HREGION_REGION_7_SHIFT) -#define I40E_PRTQF_CTL_0 0x00256E60 +#define I40E_PFQF_HLUT_LUT3_MASK I40E_MASK(0x3F, I40E_PFQF_HLUT_LUT3_SHIFT) +#define I40E_PRTQF_CTL_0 0x00256E60 /* Reset: CORER */ #define I40E_PRTQF_CTL_0_HSYM_ENA_SHIFT 0 -#define I40E_PRTQF_CTL_0_HSYM_ENA_MASK (0x1 << I40E_PRTQF_CTL_0_HSYM_ENA_SHIFT) -#define I40E_PRTQF_FD_FLXINSET(_i) (0x00253800 + ((_i) * 32)) /* _i=0...63 */ +#define I40E_PRTQF_CTL_0_HSYM_ENA_MASK I40E_MASK(0x1, I40E_PRTQF_CTL_0_HSYM_ENA_SHIFT) +#define I40E_PRTQF_FD_FLXINSET(_i) (0x00253800 + ((_i) * 32)) /* _i=0...63 */ /* Reset: CORER */ #define I40E_PRTQF_FD_FLXINSET_MAX_INDEX 63 #define I40E_PRTQF_FD_FLXINSET_INSET_SHIFT 0 -#define I40E_PRTQF_FD_FLXINSET_INSET_MASK (0xFF << I40E_PRTQF_FD_FLXINSET_INSET_SHIFT) -#define I40E_PRTQF_FD_MSK(_i, _j) (0x00252000 + ((_i) * 64 + (_j) * 32)) /* _i=0...63, _j=0...1 */ +#define I40E_PRTQF_FD_FLXINSET_INSET_MASK I40E_MASK(0xFF, I40E_PRTQF_FD_FLXINSET_INSET_SHIFT) +#define I40E_PRTQF_FD_MSK(_i, _j) (0x00252000 + ((_i) * 64 + (_j) * 32)) /* _i=0...63, _j=0...1 */ /* Reset: CORER */ #define I40E_PRTQF_FD_MSK_MAX_INDEX 63 #define I40E_PRTQF_FD_MSK_MASK_SHIFT 0 -#define I40E_PRTQF_FD_MSK_MASK_MASK (0xFFFF << I40E_PRTQF_FD_MSK_MASK_SHIFT) +#define I40E_PRTQF_FD_MSK_MASK_MASK I40E_MASK(0xFFFF, I40E_PRTQF_FD_MSK_MASK_SHIFT) #define I40E_PRTQF_FD_MSK_OFFSET_SHIFT 16 -#define I40E_PRTQF_FD_MSK_OFFSET_MASK (0x3F << I40E_PRTQF_FD_MSK_OFFSET_SHIFT) -#define I40E_PRTQF_FLX_PIT(_i) (0x00255200 + ((_i) * 32)) /* _i=0...8 */ +#define I40E_PRTQF_FD_MSK_OFFSET_MASK I40E_MASK(0x3F, I40E_PRTQF_FD_MSK_OFFSET_SHIFT) +#define I40E_PRTQF_FLX_PIT(_i) (0x00255200 + ((_i) * 32)) /* _i=0...8 */ /* Reset: CORER */ #define I40E_PRTQF_FLX_PIT_MAX_INDEX 8 #define I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT 0 -#define I40E_PRTQF_FLX_PIT_SOURCE_OFF_MASK (0x1F << I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT) +#define I40E_PRTQF_FLX_PIT_SOURCE_OFF_MASK I40E_MASK(0x1F, I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT) #define I40E_PRTQF_FLX_PIT_FSIZE_SHIFT 5 -#define I40E_PRTQF_FLX_PIT_FSIZE_MASK (0x1F << I40E_PRTQF_FLX_PIT_FSIZE_SHIFT) +#define I40E_PRTQF_FLX_PIT_FSIZE_MASK I40E_MASK(0x1F, I40E_PRTQF_FLX_PIT_FSIZE_SHIFT) #define I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT 10 -#define I40E_PRTQF_FLX_PIT_DEST_OFF_MASK (0x3F << I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT) -#define I40E_VFQF_HENA1(_i, _VF) (0x00230800 + ((_i) * 1024 + (_VF) * 4)) +#define I40E_PRTQF_FLX_PIT_DEST_OFF_MASK I40E_MASK(0x3F, I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT) +#define I40E_VFQF_HENA1(_i, _VF) (0x00230800 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...1, _VF=0...127 */ /* Reset: CORER */ #define I40E_VFQF_HENA1_MAX_INDEX 1 #define I40E_VFQF_HENA1_PTYPE_ENA_SHIFT 0 -#define I40E_VFQF_HENA1_PTYPE_ENA_MASK (0xFFFFFFFF << I40E_VFQF_HENA1_PTYPE_ENA_SHIFT) -#define I40E_VFQF_HKEY1(_i, _VF) (0x00228000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...12, _VF=0...127 */ +#define I40E_VFQF_HENA1_PTYPE_ENA_MASK I40E_MASK(0xFFFFFFFF, I40E_VFQF_HENA1_PTYPE_ENA_SHIFT) +#define I40E_VFQF_HKEY1(_i, _VF) (0x00228000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...12, _VF=0...127 */ /* Reset: CORER */ #define I40E_VFQF_HKEY1_MAX_INDEX 12 #define I40E_VFQF_HKEY1_KEY_0_SHIFT 0 -#define I40E_VFQF_HKEY1_KEY_0_MASK (0xFF << I40E_VFQF_HKEY1_KEY_0_SHIFT) +#define I40E_VFQF_HKEY1_KEY_0_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY1_KEY_0_SHIFT) #define I40E_VFQF_HKEY1_KEY_1_SHIFT 8 -#define I40E_VFQF_HKEY1_KEY_1_MASK (0xFF << I40E_VFQF_HKEY1_KEY_1_SHIFT) +#define I40E_VFQF_HKEY1_KEY_1_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY1_KEY_1_SHIFT) #define I40E_VFQF_HKEY1_KEY_2_SHIFT 16 -#define I40E_VFQF_HKEY1_KEY_2_MASK (0xFF << I40E_VFQF_HKEY1_KEY_2_SHIFT) +#define I40E_VFQF_HKEY1_KEY_2_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY1_KEY_2_SHIFT) #define I40E_VFQF_HKEY1_KEY_3_SHIFT 24 -#define I40E_VFQF_HKEY1_KEY_3_MASK (0xFF << I40E_VFQF_HKEY1_KEY_3_SHIFT) -#define I40E_VFQF_HLUT1(_i, _VF) (0x00220000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ +#define I40E_VFQF_HKEY1_KEY_3_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY1_KEY_3_SHIFT) +#define I40E_VFQF_HLUT1(_i, _VF) (0x00220000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ /* Reset: CORER */ #define I40E_VFQF_HLUT1_MAX_INDEX 15 #define I40E_VFQF_HLUT1_LUT0_SHIFT 0 -#define I40E_VFQF_HLUT1_LUT0_MASK (0xF << I40E_VFQF_HLUT1_LUT0_SHIFT) +#define I40E_VFQF_HLUT1_LUT0_MASK I40E_MASK(0xF, I40E_VFQF_HLUT1_LUT0_SHIFT) #define I40E_VFQF_HLUT1_LUT1_SHIFT 8 -#define I40E_VFQF_HLUT1_LUT1_MASK (0xF << I40E_VFQF_HLUT1_LUT1_SHIFT) +#define I40E_VFQF_HLUT1_LUT1_MASK I40E_MASK(0xF, I40E_VFQF_HLUT1_LUT1_SHIFT) #define I40E_VFQF_HLUT1_LUT2_SHIFT 16 -#define I40E_VFQF_HLUT1_LUT2_MASK (0xF << I40E_VFQF_HLUT1_LUT2_SHIFT) +#define I40E_VFQF_HLUT1_LUT2_MASK I40E_MASK(0xF, I40E_VFQF_HLUT1_LUT2_SHIFT) #define I40E_VFQF_HLUT1_LUT3_SHIFT 24 -#define I40E_VFQF_HLUT1_LUT3_MASK (0xF << I40E_VFQF_HLUT1_LUT3_SHIFT) -#define I40E_VFQF_HREGION1(_i, _VF) (0x0022E000 + ((_i) * 1024 + (_VF) * 4)) +#define I40E_VFQF_HLUT1_LUT3_MASK I40E_MASK(0xF, I40E_VFQF_HLUT1_LUT3_SHIFT) +#define I40E_VFQF_HREGION1(_i, _VF) (0x0022E000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...7, _VF=0...127 */ /* Reset: CORER */ #define I40E_VFQF_HREGION1_MAX_INDEX 7 #define I40E_VFQF_HREGION1_OVERRIDE_ENA_0_SHIFT 0 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_0_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_0_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_0_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_0_SHIFT) #define I40E_VFQF_HREGION1_REGION_0_SHIFT 1 -#define I40E_VFQF_HREGION1_REGION_0_MASK (0x7 << I40E_VFQF_HREGION1_REGION_0_SHIFT) +#define I40E_VFQF_HREGION1_REGION_0_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_0_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_1_SHIFT 4 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_1_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_1_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_1_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_1_SHIFT) #define I40E_VFQF_HREGION1_REGION_1_SHIFT 5 -#define I40E_VFQF_HREGION1_REGION_1_MASK (0x7 << I40E_VFQF_HREGION1_REGION_1_SHIFT) +#define I40E_VFQF_HREGION1_REGION_1_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_1_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_2_SHIFT 8 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_2_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_2_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_2_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_2_SHIFT) #define I40E_VFQF_HREGION1_REGION_2_SHIFT 9 -#define I40E_VFQF_HREGION1_REGION_2_MASK (0x7 << I40E_VFQF_HREGION1_REGION_2_SHIFT) +#define I40E_VFQF_HREGION1_REGION_2_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_2_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_3_SHIFT 12 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_3_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_3_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_3_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_3_SHIFT) #define I40E_VFQF_HREGION1_REGION_3_SHIFT 13 -#define I40E_VFQF_HREGION1_REGION_3_MASK (0x7 << I40E_VFQF_HREGION1_REGION_3_SHIFT) +#define I40E_VFQF_HREGION1_REGION_3_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_3_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_4_SHIFT 16 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_4_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_4_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_4_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_4_SHIFT) #define I40E_VFQF_HREGION1_REGION_4_SHIFT 17 -#define I40E_VFQF_HREGION1_REGION_4_MASK (0x7 << I40E_VFQF_HREGION1_REGION_4_SHIFT) +#define I40E_VFQF_HREGION1_REGION_4_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_4_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_5_SHIFT 20 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_5_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_5_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_5_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_5_SHIFT) #define I40E_VFQF_HREGION1_REGION_5_SHIFT 21 -#define I40E_VFQF_HREGION1_REGION_5_MASK (0x7 << I40E_VFQF_HREGION1_REGION_5_SHIFT) +#define I40E_VFQF_HREGION1_REGION_5_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_5_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_6_SHIFT 24 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_6_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_6_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_6_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_6_SHIFT) #define I40E_VFQF_HREGION1_REGION_6_SHIFT 25 -#define I40E_VFQF_HREGION1_REGION_6_MASK (0x7 << I40E_VFQF_HREGION1_REGION_6_SHIFT) +#define I40E_VFQF_HREGION1_REGION_6_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_6_SHIFT) #define I40E_VFQF_HREGION1_OVERRIDE_ENA_7_SHIFT 28 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_7_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_7_SHIFT) +#define I40E_VFQF_HREGION1_OVERRIDE_ENA_7_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_7_SHIFT) #define I40E_VFQF_HREGION1_REGION_7_SHIFT 29 -#define I40E_VFQF_HREGION1_REGION_7_MASK (0x7 << I40E_VFQF_HREGION1_REGION_7_SHIFT) -#define I40E_VPQF_CTL(_VF) (0x001C0000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VFQF_HREGION1_REGION_7_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_7_SHIFT) +#define I40E_VPQF_CTL(_VF) (0x001C0000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ #define I40E_VPQF_CTL_MAX_INDEX 127 #define I40E_VPQF_CTL_PEHSIZE_SHIFT 0 -#define I40E_VPQF_CTL_PEHSIZE_MASK (0x1F << I40E_VPQF_CTL_PEHSIZE_SHIFT) +#define I40E_VPQF_CTL_PEHSIZE_MASK I40E_MASK(0x1F, I40E_VPQF_CTL_PEHSIZE_SHIFT) #define I40E_VPQF_CTL_PEDSIZE_SHIFT 5 -#define I40E_VPQF_CTL_PEDSIZE_MASK (0x1F << I40E_VPQF_CTL_PEDSIZE_SHIFT) +#define I40E_VPQF_CTL_PEDSIZE_MASK I40E_MASK(0x1F, I40E_VPQF_CTL_PEDSIZE_SHIFT) #define I40E_VPQF_CTL_FCHSIZE_SHIFT 10 -#define I40E_VPQF_CTL_FCHSIZE_MASK (0xF << I40E_VPQF_CTL_FCHSIZE_SHIFT) +#define I40E_VPQF_CTL_FCHSIZE_MASK I40E_MASK(0xF, I40E_VPQF_CTL_FCHSIZE_SHIFT) #define I40E_VPQF_CTL_FCDSIZE_SHIFT 14 -#define I40E_VPQF_CTL_FCDSIZE_MASK (0x3 << I40E_VPQF_CTL_FCDSIZE_SHIFT) -#define I40E_VSIQF_CTL(_VSI) (0x0020D800 + ((_VSI) * 4)) /* _i=0...383 */ +#define I40E_VPQF_CTL_FCDSIZE_MASK I40E_MASK(0x3, I40E_VPQF_CTL_FCDSIZE_SHIFT) +#define I40E_VSIQF_CTL(_VSI) (0x0020D800 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: PFR */ #define I40E_VSIQF_CTL_MAX_INDEX 383 #define I40E_VSIQF_CTL_FCOE_ENA_SHIFT 0 -#define I40E_VSIQF_CTL_FCOE_ENA_MASK (0x1 << I40E_VSIQF_CTL_FCOE_ENA_SHIFT) +#define I40E_VSIQF_CTL_FCOE_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_FCOE_ENA_SHIFT) #define I40E_VSIQF_CTL_PETCP_ENA_SHIFT 1 -#define I40E_VSIQF_CTL_PETCP_ENA_MASK (0x1 << I40E_VSIQF_CTL_PETCP_ENA_SHIFT) +#define I40E_VSIQF_CTL_PETCP_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PETCP_ENA_SHIFT) #define I40E_VSIQF_CTL_PEUUDP_ENA_SHIFT 2 -#define I40E_VSIQF_CTL_PEUUDP_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEUUDP_ENA_SHIFT) +#define I40E_VSIQF_CTL_PEUUDP_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PEUUDP_ENA_SHIFT) #define I40E_VSIQF_CTL_PEMUDP_ENA_SHIFT 3 -#define I40E_VSIQF_CTL_PEMUDP_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEMUDP_ENA_SHIFT) +#define I40E_VSIQF_CTL_PEMUDP_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PEMUDP_ENA_SHIFT) #define I40E_VSIQF_CTL_PEUFRAG_ENA_SHIFT 4 -#define I40E_VSIQF_CTL_PEUFRAG_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEUFRAG_ENA_SHIFT) +#define I40E_VSIQF_CTL_PEUFRAG_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PEUFRAG_ENA_SHIFT) #define I40E_VSIQF_CTL_PEMFRAG_ENA_SHIFT 5 -#define I40E_VSIQF_CTL_PEMFRAG_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEMFRAG_ENA_SHIFT) -#define I40E_VSIQF_TCREGION(_i, _VSI) (0x00206000 + ((_i) * 2048 + (_VSI) * 4)) +#define I40E_VSIQF_CTL_PEMFRAG_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PEMFRAG_ENA_SHIFT) +#define I40E_VSIQF_TCREGION(_i, _VSI) (0x00206000 + ((_i) * 2048 + (_VSI) * 4)) /* _i=0...3, _VSI=0...383 */ /* Reset: PFR */ #define I40E_VSIQF_TCREGION_MAX_INDEX 3 #define I40E_VSIQF_TCREGION_TC_OFFSET_SHIFT 0 -#define I40E_VSIQF_TCREGION_TC_OFFSET_MASK (0x1FF << I40E_VSIQF_TCREGION_TC_OFFSET_SHIFT) +#define I40E_VSIQF_TCREGION_TC_OFFSET_MASK I40E_MASK(0x1FF, I40E_VSIQF_TCREGION_TC_OFFSET_SHIFT) #define I40E_VSIQF_TCREGION_TC_SIZE_SHIFT 9 -#define I40E_VSIQF_TCREGION_TC_SIZE_MASK (0x7 << I40E_VSIQF_TCREGION_TC_SIZE_SHIFT) +#define I40E_VSIQF_TCREGION_TC_SIZE_MASK I40E_MASK(0x7, I40E_VSIQF_TCREGION_TC_SIZE_SHIFT) #define I40E_VSIQF_TCREGION_TC_OFFSET2_SHIFT 16 -#define I40E_VSIQF_TCREGION_TC_OFFSET2_MASK (0x1FF << I40E_VSIQF_TCREGION_TC_OFFSET2_SHIFT) +#define I40E_VSIQF_TCREGION_TC_OFFSET2_MASK I40E_MASK(0x1FF, I40E_VSIQF_TCREGION_TC_OFFSET2_SHIFT) #define I40E_VSIQF_TCREGION_TC_SIZE2_SHIFT 25 -#define I40E_VSIQF_TCREGION_TC_SIZE2_MASK (0x7 << I40E_VSIQF_TCREGION_TC_SIZE2_SHIFT) -#define I40E_GL_FCOECRC(_i) (0x00314d80 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_VSIQF_TCREGION_TC_SIZE2_MASK I40E_MASK(0x7, I40E_VSIQF_TCREGION_TC_SIZE2_SHIFT) +#define I40E_GL_FCOECRC(_i) (0x00314d80 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOECRC_MAX_INDEX 143 #define I40E_GL_FCOECRC_FCOECRC_SHIFT 0 -#define I40E_GL_FCOECRC_FCOECRC_MASK (0xFFFFFFFF << I40E_GL_FCOECRC_FCOECRC_SHIFT) -#define I40E_GL_FCOEDDPC(_i) (0x00314480 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOECRC_FCOECRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOECRC_FCOECRC_SHIFT) +#define I40E_GL_FCOEDDPC(_i) (0x00314480 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDDPC_MAX_INDEX 143 #define I40E_GL_FCOEDDPC_FCOEDDPC_SHIFT 0 -#define I40E_GL_FCOEDDPC_FCOEDDPC_MASK (0xFFFFFFFF << I40E_GL_FCOEDDPC_FCOEDDPC_SHIFT) -/* _i=0...143 */ -#define I40E_GL_FCOEDIFEC(_i) (0x00318480 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDDPC_FCOEDDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDDPC_FCOEDDPC_SHIFT) +#define I40E_GL_FCOEDIFEC(_i) (0x00318480 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDIFEC_MAX_INDEX 143 #define I40E_GL_FCOEDIFEC_FCOEDIFRC_SHIFT 0 -#define I40E_GL_FCOEDIFEC_FCOEDIFRC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIFEC_FCOEDIFRC_SHIFT) -#define I40E_GL_FCOEDIFRC(_i) (0x00318000 + ((_i) * 8)) /* _i=0...143 */ -#define I40E_GL_FCOEDIFRC_MAX_INDEX 143 -#define I40E_GL_FCOEDIFRC_FCOEDIFRC_SHIFT 0 -#define I40E_GL_FCOEDIFRC_FCOEDIFRC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIFRC_FCOEDIFRC_SHIFT) -#define I40E_GL_FCOEDIFTCL(_i) (0x00354000 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDIFEC_FCOEDIFRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDIFEC_FCOEDIFRC_SHIFT) +#define I40E_GL_FCOEDIFTCL(_i) (0x00354000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDIFTCL_MAX_INDEX 143 #define I40E_GL_FCOEDIFTCL_FCOEDIFTC_SHIFT 0 -#define I40E_GL_FCOEDIFTCL_FCOEDIFTC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIFTCL_FCOEDIFTC_SHIFT) -#define I40E_GL_FCOEDIXAC(_i) (0x0031c000 + ((_i) * 8)) /* _i=0...143 */ -#define I40E_GL_FCOEDIXAC_MAX_INDEX 143 -#define I40E_GL_FCOEDIXAC_FCOEDIXAC_SHIFT 0 -#define I40E_GL_FCOEDIXAC_FCOEDIXAC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIXAC_FCOEDIXAC_SHIFT) -#define I40E_GL_FCOEDIXEC(_i) (0x0034c000 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDIFTCL_FCOEDIFTC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDIFTCL_FCOEDIFTC_SHIFT) +#define I40E_GL_FCOEDIXEC(_i) (0x0034c000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDIXEC_MAX_INDEX 143 #define I40E_GL_FCOEDIXEC_FCOEDIXEC_SHIFT 0 -#define I40E_GL_FCOEDIXEC_FCOEDIXEC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIXEC_FCOEDIXEC_SHIFT) -#define I40E_GL_FCOEDIXVC(_i) (0x00350000 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDIXEC_FCOEDIXEC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDIXEC_FCOEDIXEC_SHIFT) +#define I40E_GL_FCOEDIXVC(_i) (0x00350000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDIXVC_MAX_INDEX 143 #define I40E_GL_FCOEDIXVC_FCOEDIXVC_SHIFT 0 -#define I40E_GL_FCOEDIXVC_FCOEDIXVC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIXVC_FCOEDIXVC_SHIFT) -#define I40E_GL_FCOEDWRCH(_i) (0x00320004 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDIXVC_FCOEDIXVC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDIXVC_FCOEDIXVC_SHIFT) +#define I40E_GL_FCOEDWRCH(_i) (0x00320004 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDWRCH_MAX_INDEX 143 #define I40E_GL_FCOEDWRCH_FCOEDWRCH_SHIFT 0 -#define I40E_GL_FCOEDWRCH_FCOEDWRCH_MASK (0xFFFF << I40E_GL_FCOEDWRCH_FCOEDWRCH_SHIFT) -#define I40E_GL_FCOEDWRCL(_i) (0x00320000 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDWRCH_FCOEDWRCH_MASK I40E_MASK(0xFFFF, I40E_GL_FCOEDWRCH_FCOEDWRCH_SHIFT) +#define I40E_GL_FCOEDWRCL(_i) (0x00320000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDWRCL_MAX_INDEX 143 #define I40E_GL_FCOEDWRCL_FCOEDWRCL_SHIFT 0 -#define I40E_GL_FCOEDWRCL_FCOEDWRCL_MASK (0xFFFFFFFF << I40E_GL_FCOEDWRCL_FCOEDWRCL_SHIFT) -#define I40E_GL_FCOEDWTCH(_i) (0x00348084 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDWRCL_FCOEDWRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDWRCL_FCOEDWRCL_SHIFT) +#define I40E_GL_FCOEDWTCH(_i) (0x00348084 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDWTCH_MAX_INDEX 143 #define I40E_GL_FCOEDWTCH_FCOEDWTCH_SHIFT 0 -#define I40E_GL_FCOEDWTCH_FCOEDWTCH_MASK (0xFFFF << I40E_GL_FCOEDWTCH_FCOEDWTCH_SHIFT) -#define I40E_GL_FCOEDWTCL(_i) (0x00348080 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDWTCH_FCOEDWTCH_MASK I40E_MASK(0xFFFF, I40E_GL_FCOEDWTCH_FCOEDWTCH_SHIFT) +#define I40E_GL_FCOEDWTCL(_i) (0x00348080 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEDWTCL_MAX_INDEX 143 #define I40E_GL_FCOEDWTCL_FCOEDWTCL_SHIFT 0 -#define I40E_GL_FCOEDWTCL_FCOEDWTCL_MASK (0xFFFFFFFF << I40E_GL_FCOEDWTCL_FCOEDWTCL_SHIFT) -#define I40E_GL_FCOELAST(_i) (0x00314000 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEDWTCL_FCOEDWTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDWTCL_FCOEDWTCL_SHIFT) +#define I40E_GL_FCOELAST(_i) (0x00314000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOELAST_MAX_INDEX 143 #define I40E_GL_FCOELAST_FCOELAST_SHIFT 0 -#define I40E_GL_FCOELAST_FCOELAST_MASK (0xFFFFFFFF << I40E_GL_FCOELAST_FCOELAST_SHIFT) -#define I40E_GL_FCOEPRC(_i) (0x00315200 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOELAST_FCOELAST_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOELAST_FCOELAST_SHIFT) +#define I40E_GL_FCOEPRC(_i) (0x00315200 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEPRC_MAX_INDEX 143 #define I40E_GL_FCOEPRC_FCOEPRC_SHIFT 0 -#define I40E_GL_FCOEPRC_FCOEPRC_MASK (0xFFFFFFFF << I40E_GL_FCOEPRC_FCOEPRC_SHIFT) -#define I40E_GL_FCOEPTC(_i) (0x00344C00 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEPRC_FCOEPRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEPRC_FCOEPRC_SHIFT) +#define I40E_GL_FCOEPTC(_i) (0x00344C00 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOEPTC_MAX_INDEX 143 #define I40E_GL_FCOEPTC_FCOEPTC_SHIFT 0 -#define I40E_GL_FCOEPTC_FCOEPTC_MASK (0xFFFFFFFF << I40E_GL_FCOEPTC_FCOEPTC_SHIFT) -#define I40E_GL_FCOERPDC(_i) (0x00324000 + ((_i) * 8)) /* _i=0...143 */ +#define I40E_GL_FCOEPTC_FCOEPTC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEPTC_FCOEPTC_SHIFT) +#define I40E_GL_FCOERPDC(_i) (0x00324000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ #define I40E_GL_FCOERPDC_MAX_INDEX 143 #define I40E_GL_FCOERPDC_FCOERPDC_SHIFT 0 -#define I40E_GL_FCOERPDC_FCOERPDC_MASK (0xFFFFFFFF << I40E_GL_FCOERPDC_FCOERPDC_SHIFT) -#define I40E_GLPRT_BPRCH(_i) (0x003005E4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GL_FCOERPDC_FCOERPDC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOERPDC_FCOERPDC_SHIFT) +#define I40E_GL_RXERR1_L(_i) (0x00318000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ +#define I40E_GL_RXERR1_L_MAX_INDEX 143 +#define I40E_GL_RXERR1_L_FCOEDIFRC_SHIFT 0 +#define I40E_GL_RXERR1_L_FCOEDIFRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR1_L_FCOEDIFRC_SHIFT) +#define I40E_GL_RXERR2_L(_i) (0x0031c000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ +#define I40E_GL_RXERR2_L_MAX_INDEX 143 +#define I40E_GL_RXERR2_L_FCOEDIXAC_SHIFT 0 +#define I40E_GL_RXERR2_L_FCOEDIXAC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR2_L_FCOEDIXAC_SHIFT) +#define I40E_GLPRT_BPRCH(_i) (0x003005E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_BPRCH_MAX_INDEX 3 #define I40E_GLPRT_BPRCH_UPRCH_SHIFT 0 -#define I40E_GLPRT_BPRCH_UPRCH_MASK (0xFFFF << I40E_GLPRT_BPRCH_UPRCH_SHIFT) -#define I40E_GLPRT_BPRCL(_i) (0x003005E0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_BPRCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_BPRCH_UPRCH_SHIFT) +#define I40E_GLPRT_BPRCL(_i) (0x003005E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_BPRCL_MAX_INDEX 3 #define I40E_GLPRT_BPRCL_UPRCH_SHIFT 0 -#define I40E_GLPRT_BPRCL_UPRCH_MASK (0xFFFFFFFF << I40E_GLPRT_BPRCL_UPRCH_SHIFT) -#define I40E_GLPRT_BPTCH(_i) (0x00300A04 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_BPRCL_UPRCH_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_BPRCL_UPRCH_SHIFT) +#define I40E_GLPRT_BPTCH(_i) (0x00300A04 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_BPTCH_MAX_INDEX 3 #define I40E_GLPRT_BPTCH_UPRCH_SHIFT 0 -#define I40E_GLPRT_BPTCH_UPRCH_MASK (0xFFFF << I40E_GLPRT_BPTCH_UPRCH_SHIFT) -#define I40E_GLPRT_BPTCL(_i) (0x00300A00 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_BPTCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_BPTCH_UPRCH_SHIFT) +#define I40E_GLPRT_BPTCL(_i) (0x00300A00 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_BPTCL_MAX_INDEX 3 #define I40E_GLPRT_BPTCL_UPRCH_SHIFT 0 -#define I40E_GLPRT_BPTCL_UPRCH_MASK (0xFFFFFFFF << I40E_GLPRT_BPTCL_UPRCH_SHIFT) -#define I40E_GLPRT_CRCERRS(_i) (0x00300080 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_BPTCL_UPRCH_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_BPTCL_UPRCH_SHIFT) +#define I40E_GLPRT_CRCERRS(_i) (0x00300080 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_CRCERRS_MAX_INDEX 3 #define I40E_GLPRT_CRCERRS_CRCERRS_SHIFT 0 -#define I40E_GLPRT_CRCERRS_CRCERRS_MASK (0xFFFFFFFF << I40E_GLPRT_CRCERRS_CRCERRS_SHIFT) -#define I40E_GLPRT_GORCH(_i) (0x00300004 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_CRCERRS_CRCERRS_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_CRCERRS_CRCERRS_SHIFT) +#define I40E_GLPRT_GORCH(_i) (0x00300004 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_GORCH_MAX_INDEX 3 #define I40E_GLPRT_GORCH_GORCH_SHIFT 0 -#define I40E_GLPRT_GORCH_GORCH_MASK (0xFFFF << I40E_GLPRT_GORCH_GORCH_SHIFT) -#define I40E_GLPRT_GORCL(_i) (0x00300000 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_GORCH_GORCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_GORCH_GORCH_SHIFT) +#define I40E_GLPRT_GORCL(_i) (0x00300000 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_GORCL_MAX_INDEX 3 #define I40E_GLPRT_GORCL_GORCL_SHIFT 0 -#define I40E_GLPRT_GORCL_GORCL_MASK (0xFFFFFFFF << I40E_GLPRT_GORCL_GORCL_SHIFT) -#define I40E_GLPRT_GOTCH(_i) (0x00300684 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_GORCL_GORCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_GORCL_GORCL_SHIFT) +#define I40E_GLPRT_GOTCH(_i) (0x00300684 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_GOTCH_MAX_INDEX 3 #define I40E_GLPRT_GOTCH_GOTCH_SHIFT 0 -#define I40E_GLPRT_GOTCH_GOTCH_MASK (0xFFFF << I40E_GLPRT_GOTCH_GOTCH_SHIFT) -#define I40E_GLPRT_GOTCL(_i) (0x00300680 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_GOTCH_GOTCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_GOTCH_GOTCH_SHIFT) +#define I40E_GLPRT_GOTCL(_i) (0x00300680 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_GOTCL_MAX_INDEX 3 #define I40E_GLPRT_GOTCL_GOTCL_SHIFT 0 -#define I40E_GLPRT_GOTCL_GOTCL_MASK (0xFFFFFFFF << I40E_GLPRT_GOTCL_GOTCL_SHIFT) -#define I40E_GLPRT_ILLERRC(_i) (0x003000E0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_GOTCL_GOTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_GOTCL_GOTCL_SHIFT) +#define I40E_GLPRT_ILLERRC(_i) (0x003000E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_ILLERRC_MAX_INDEX 3 #define I40E_GLPRT_ILLERRC_ILLERRC_SHIFT 0 -#define I40E_GLPRT_ILLERRC_ILLERRC_MASK (0xFFFFFFFF << I40E_GLPRT_ILLERRC_ILLERRC_SHIFT) -#define I40E_GLPRT_LDPC(_i) (0x00300620 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_ILLERRC_ILLERRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_ILLERRC_ILLERRC_SHIFT) +#define I40E_GLPRT_LDPC(_i) (0x00300620 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_LDPC_MAX_INDEX 3 #define I40E_GLPRT_LDPC_LDPC_SHIFT 0 -#define I40E_GLPRT_LDPC_LDPC_MASK (0xFFFFFFFF << I40E_GLPRT_LDPC_LDPC_SHIFT) -#define I40E_GLPRT_LXOFFRXC(_i) (0x00300160 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_LDPC_LDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LDPC_LDPC_SHIFT) +#define I40E_GLPRT_LXOFFRXC(_i) (0x00300160 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_LXOFFRXC_MAX_INDEX 3 #define I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_SHIFT 0 -#define I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_SHIFT) -#define I40E_GLPRT_LXOFFTXC(_i) (0x003009A0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_SHIFT) +#define I40E_GLPRT_LXOFFTXC(_i) (0x003009A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_LXOFFTXC_MAX_INDEX 3 #define I40E_GLPRT_LXOFFTXC_LXOFFTXC_SHIFT 0 -#define I40E_GLPRT_LXOFFTXC_LXOFFTXC_MASK (0xFFFFFFFF << I40E_GLPRT_LXOFFTXC_LXOFFTXC_SHIFT) -#define I40E_GLPRT_LXONRXC(_i) (0x00300140 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_LXOFFTXC_LXOFFTXC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LXOFFTXC_LXOFFTXC_SHIFT) +#define I40E_GLPRT_LXONRXC(_i) (0x00300140 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_LXONRXC_MAX_INDEX 3 #define I40E_GLPRT_LXONRXC_LXONRXCNT_SHIFT 0 -#define I40E_GLPRT_LXONRXC_LXONRXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_LXONRXC_LXONRXCNT_SHIFT) -#define I40E_GLPRT_LXONTXC(_i) (0x00300980 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_LXONRXC_LXONRXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LXONRXC_LXONRXCNT_SHIFT) +#define I40E_GLPRT_LXONTXC(_i) (0x00300980 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_LXONTXC_MAX_INDEX 3 #define I40E_GLPRT_LXONTXC_LXONTXC_SHIFT 0 -#define I40E_GLPRT_LXONTXC_LXONTXC_MASK (0xFFFFFFFF << I40E_GLPRT_LXONTXC_LXONTXC_SHIFT) -#define I40E_GLPRT_MLFC(_i) (0x00300020 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_LXONTXC_LXONTXC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LXONTXC_LXONTXC_SHIFT) +#define I40E_GLPRT_MLFC(_i) (0x00300020 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_MLFC_MAX_INDEX 3 #define I40E_GLPRT_MLFC_MLFC_SHIFT 0 -#define I40E_GLPRT_MLFC_MLFC_MASK (0xFFFFFFFF << I40E_GLPRT_MLFC_MLFC_SHIFT) -#define I40E_GLPRT_MPRCH(_i) (0x003005C4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_MLFC_MLFC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_MLFC_MLFC_SHIFT) +#define I40E_GLPRT_MPRCH(_i) (0x003005C4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_MPRCH_MAX_INDEX 3 #define I40E_GLPRT_MPRCH_MPRCH_SHIFT 0 -#define I40E_GLPRT_MPRCH_MPRCH_MASK (0xFFFF << I40E_GLPRT_MPRCH_MPRCH_SHIFT) -#define I40E_GLPRT_MPRCL(_i) (0x003005C0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_MPRCH_MPRCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_MPRCH_MPRCH_SHIFT) +#define I40E_GLPRT_MPRCL(_i) (0x003005C0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_MPRCL_MAX_INDEX 3 #define I40E_GLPRT_MPRCL_MPRCL_SHIFT 0 -#define I40E_GLPRT_MPRCL_MPRCL_MASK (0xFFFFFFFF << I40E_GLPRT_MPRCL_MPRCL_SHIFT) -#define I40E_GLPRT_MPTCH(_i) (0x003009E4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_MPRCL_MPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_MPRCL_MPRCL_SHIFT) +#define I40E_GLPRT_MPTCH(_i) (0x003009E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_MPTCH_MAX_INDEX 3 #define I40E_GLPRT_MPTCH_MPTCH_SHIFT 0 -#define I40E_GLPRT_MPTCH_MPTCH_MASK (0xFFFF << I40E_GLPRT_MPTCH_MPTCH_SHIFT) -#define I40E_GLPRT_MPTCL(_i) (0x003009E0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_MPTCH_MPTCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_MPTCH_MPTCH_SHIFT) +#define I40E_GLPRT_MPTCL(_i) (0x003009E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_MPTCL_MAX_INDEX 3 #define I40E_GLPRT_MPTCL_MPTCL_SHIFT 0 -#define I40E_GLPRT_MPTCL_MPTCL_MASK (0xFFFFFFFF << I40E_GLPRT_MPTCL_MPTCL_SHIFT) -#define I40E_GLPRT_MRFC(_i) (0x00300040 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_MPTCL_MPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_MPTCL_MPTCL_SHIFT) +#define I40E_GLPRT_MRFC(_i) (0x00300040 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_MRFC_MAX_INDEX 3 #define I40E_GLPRT_MRFC_MRFC_SHIFT 0 -#define I40E_GLPRT_MRFC_MRFC_MASK (0xFFFFFFFF << I40E_GLPRT_MRFC_MRFC_SHIFT) -#define I40E_GLPRT_PRC1023H(_i) (0x00300504 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_MRFC_MRFC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_MRFC_MRFC_SHIFT) +#define I40E_GLPRT_PRC1023H(_i) (0x00300504 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC1023H_MAX_INDEX 3 #define I40E_GLPRT_PRC1023H_PRC1023H_SHIFT 0 -#define I40E_GLPRT_PRC1023H_PRC1023H_MASK (0xFFFF << I40E_GLPRT_PRC1023H_PRC1023H_SHIFT) -#define I40E_GLPRT_PRC1023L(_i) (0x00300500 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC1023H_PRC1023H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC1023H_PRC1023H_SHIFT) +#define I40E_GLPRT_PRC1023L(_i) (0x00300500 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC1023L_MAX_INDEX 3 #define I40E_GLPRT_PRC1023L_PRC1023L_SHIFT 0 -#define I40E_GLPRT_PRC1023L_PRC1023L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC1023L_PRC1023L_SHIFT) -#define I40E_GLPRT_PRC127H(_i) (0x003004A4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC1023L_PRC1023L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC1023L_PRC1023L_SHIFT) +#define I40E_GLPRT_PRC127H(_i) (0x003004A4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC127H_MAX_INDEX 3 #define I40E_GLPRT_PRC127H_PRC127H_SHIFT 0 -#define I40E_GLPRT_PRC127H_PRC127H_MASK (0xFFFF << I40E_GLPRT_PRC127H_PRC127H_SHIFT) -#define I40E_GLPRT_PRC127L(_i) (0x003004A0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC127H_PRC127H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC127H_PRC127H_SHIFT) +#define I40E_GLPRT_PRC127L(_i) (0x003004A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC127L_MAX_INDEX 3 #define I40E_GLPRT_PRC127L_PRC127L_SHIFT 0 -#define I40E_GLPRT_PRC127L_PRC127L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC127L_PRC127L_SHIFT) -#define I40E_GLPRT_PRC1522H(_i) (0x00300524 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC127L_PRC127L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC127L_PRC127L_SHIFT) +#define I40E_GLPRT_PRC1522H(_i) (0x00300524 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC1522H_MAX_INDEX 3 #define I40E_GLPRT_PRC1522H_PRC1522H_SHIFT 0 -#define I40E_GLPRT_PRC1522H_PRC1522H_MASK (0xFFFF << I40E_GLPRT_PRC1522H_PRC1522H_SHIFT) -#define I40E_GLPRT_PRC1522L(_i) (0x00300520 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC1522H_PRC1522H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC1522H_PRC1522H_SHIFT) +#define I40E_GLPRT_PRC1522L(_i) (0x00300520 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC1522L_MAX_INDEX 3 #define I40E_GLPRT_PRC1522L_PRC1522L_SHIFT 0 -#define I40E_GLPRT_PRC1522L_PRC1522L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC1522L_PRC1522L_SHIFT) -#define I40E_GLPRT_PRC255H(_i) (0x003004C4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC1522L_PRC1522L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC1522L_PRC1522L_SHIFT) +#define I40E_GLPRT_PRC255H(_i) (0x003004C4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC255H_MAX_INDEX 3 #define I40E_GLPRT_PRC255H_PRTPRC255H_SHIFT 0 -#define I40E_GLPRT_PRC255H_PRTPRC255H_MASK (0xFFFF << I40E_GLPRT_PRC255H_PRTPRC255H_SHIFT) -#define I40E_GLPRT_PRC255L(_i) (0x003004C0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC255H_PRTPRC255H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC255H_PRTPRC255H_SHIFT) +#define I40E_GLPRT_PRC255L(_i) (0x003004C0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC255L_MAX_INDEX 3 #define I40E_GLPRT_PRC255L_PRC255L_SHIFT 0 -#define I40E_GLPRT_PRC255L_PRC255L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC255L_PRC255L_SHIFT) -#define I40E_GLPRT_PRC511H(_i) (0x003004E4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC255L_PRC255L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC255L_PRC255L_SHIFT) +#define I40E_GLPRT_PRC511H(_i) (0x003004E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC511H_MAX_INDEX 3 #define I40E_GLPRT_PRC511H_PRC511H_SHIFT 0 -#define I40E_GLPRT_PRC511H_PRC511H_MASK (0xFFFF << I40E_GLPRT_PRC511H_PRC511H_SHIFT) -#define I40E_GLPRT_PRC511L(_i) (0x003004E0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC511H_PRC511H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC511H_PRC511H_SHIFT) +#define I40E_GLPRT_PRC511L(_i) (0x003004E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC511L_MAX_INDEX 3 #define I40E_GLPRT_PRC511L_PRC511L_SHIFT 0 -#define I40E_GLPRT_PRC511L_PRC511L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC511L_PRC511L_SHIFT) -#define I40E_GLPRT_PRC64H(_i) (0x00300484 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC511L_PRC511L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC511L_PRC511L_SHIFT) +#define I40E_GLPRT_PRC64H(_i) (0x00300484 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC64H_MAX_INDEX 3 #define I40E_GLPRT_PRC64H_PRC64H_SHIFT 0 -#define I40E_GLPRT_PRC64H_PRC64H_MASK (0xFFFF << I40E_GLPRT_PRC64H_PRC64H_SHIFT) -#define I40E_GLPRT_PRC64L(_i) (0x00300480 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC64H_PRC64H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC64H_PRC64H_SHIFT) +#define I40E_GLPRT_PRC64L(_i) (0x00300480 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC64L_MAX_INDEX 3 #define I40E_GLPRT_PRC64L_PRC64L_SHIFT 0 -#define I40E_GLPRT_PRC64L_PRC64L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC64L_PRC64L_SHIFT) -#define I40E_GLPRT_PRC9522H(_i) (0x00300544 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC64L_PRC64L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC64L_PRC64L_SHIFT) +#define I40E_GLPRT_PRC9522H(_i) (0x00300544 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC9522H_MAX_INDEX 3 #define I40E_GLPRT_PRC9522H_PRC1522H_SHIFT 0 -#define I40E_GLPRT_PRC9522H_PRC1522H_MASK (0xFFFF << I40E_GLPRT_PRC9522H_PRC1522H_SHIFT) -#define I40E_GLPRT_PRC9522L(_i) (0x00300540 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC9522H_PRC1522H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC9522H_PRC1522H_SHIFT) +#define I40E_GLPRT_PRC9522L(_i) (0x00300540 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PRC9522L_MAX_INDEX 3 #define I40E_GLPRT_PRC9522L_PRC1522L_SHIFT 0 -#define I40E_GLPRT_PRC9522L_PRC1522L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC9522L_PRC1522L_SHIFT) -#define I40E_GLPRT_PTC1023H(_i) (0x00300724 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PRC9522L_PRC1522L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC9522L_PRC1522L_SHIFT) +#define I40E_GLPRT_PTC1023H(_i) (0x00300724 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC1023H_MAX_INDEX 3 #define I40E_GLPRT_PTC1023H_PTC1023H_SHIFT 0 -#define I40E_GLPRT_PTC1023H_PTC1023H_MASK (0xFFFF << I40E_GLPRT_PTC1023H_PTC1023H_SHIFT) -#define I40E_GLPRT_PTC1023L(_i) (0x00300720 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC1023H_PTC1023H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC1023H_PTC1023H_SHIFT) +#define I40E_GLPRT_PTC1023L(_i) (0x00300720 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC1023L_MAX_INDEX 3 #define I40E_GLPRT_PTC1023L_PTC1023L_SHIFT 0 -#define I40E_GLPRT_PTC1023L_PTC1023L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC1023L_PTC1023L_SHIFT) -#define I40E_GLPRT_PTC127H(_i) (0x003006C4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC1023L_PTC1023L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC1023L_PTC1023L_SHIFT) +#define I40E_GLPRT_PTC127H(_i) (0x003006C4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC127H_MAX_INDEX 3 #define I40E_GLPRT_PTC127H_PTC127H_SHIFT 0 -#define I40E_GLPRT_PTC127H_PTC127H_MASK (0xFFFF << I40E_GLPRT_PTC127H_PTC127H_SHIFT) -#define I40E_GLPRT_PTC127L(_i) (0x003006C0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC127H_PTC127H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC127H_PTC127H_SHIFT) +#define I40E_GLPRT_PTC127L(_i) (0x003006C0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC127L_MAX_INDEX 3 #define I40E_GLPRT_PTC127L_PTC127L_SHIFT 0 -#define I40E_GLPRT_PTC127L_PTC127L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC127L_PTC127L_SHIFT) -#define I40E_GLPRT_PTC1522H(_i) (0x00300744 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC127L_PTC127L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC127L_PTC127L_SHIFT) +#define I40E_GLPRT_PTC1522H(_i) (0x00300744 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC1522H_MAX_INDEX 3 #define I40E_GLPRT_PTC1522H_PTC1522H_SHIFT 0 -#define I40E_GLPRT_PTC1522H_PTC1522H_MASK (0xFFFF << I40E_GLPRT_PTC1522H_PTC1522H_SHIFT) -#define I40E_GLPRT_PTC1522L(_i) (0x00300740 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC1522H_PTC1522H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC1522H_PTC1522H_SHIFT) +#define I40E_GLPRT_PTC1522L(_i) (0x00300740 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC1522L_MAX_INDEX 3 #define I40E_GLPRT_PTC1522L_PTC1522L_SHIFT 0 -#define I40E_GLPRT_PTC1522L_PTC1522L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC1522L_PTC1522L_SHIFT) -#define I40E_GLPRT_PTC255H(_i) (0x003006E4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC1522L_PTC1522L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC1522L_PTC1522L_SHIFT) +#define I40E_GLPRT_PTC255H(_i) (0x003006E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC255H_MAX_INDEX 3 #define I40E_GLPRT_PTC255H_PTC255H_SHIFT 0 -#define I40E_GLPRT_PTC255H_PTC255H_MASK (0xFFFF << I40E_GLPRT_PTC255H_PTC255H_SHIFT) -#define I40E_GLPRT_PTC255L(_i) (0x003006E0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC255H_PTC255H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC255H_PTC255H_SHIFT) +#define I40E_GLPRT_PTC255L(_i) (0x003006E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC255L_MAX_INDEX 3 #define I40E_GLPRT_PTC255L_PTC255L_SHIFT 0 -#define I40E_GLPRT_PTC255L_PTC255L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC255L_PTC255L_SHIFT) -#define I40E_GLPRT_PTC511H(_i) (0x00300704 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC255L_PTC255L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC255L_PTC255L_SHIFT) +#define I40E_GLPRT_PTC511H(_i) (0x00300704 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC511H_MAX_INDEX 3 #define I40E_GLPRT_PTC511H_PTC511H_SHIFT 0 -#define I40E_GLPRT_PTC511H_PTC511H_MASK (0xFFFF << I40E_GLPRT_PTC511H_PTC511H_SHIFT) -#define I40E_GLPRT_PTC511L(_i) (0x00300700 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC511H_PTC511H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC511H_PTC511H_SHIFT) +#define I40E_GLPRT_PTC511L(_i) (0x00300700 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC511L_MAX_INDEX 3 #define I40E_GLPRT_PTC511L_PTC511L_SHIFT 0 -#define I40E_GLPRT_PTC511L_PTC511L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC511L_PTC511L_SHIFT) -#define I40E_GLPRT_PTC64H(_i) (0x003006A4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC511L_PTC511L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC511L_PTC511L_SHIFT) +#define I40E_GLPRT_PTC64H(_i) (0x003006A4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC64H_MAX_INDEX 3 #define I40E_GLPRT_PTC64H_PTC64H_SHIFT 0 -#define I40E_GLPRT_PTC64H_PTC64H_MASK (0xFFFF << I40E_GLPRT_PTC64H_PTC64H_SHIFT) -#define I40E_GLPRT_PTC64L(_i) (0x003006A0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC64H_PTC64H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC64H_PTC64H_SHIFT) +#define I40E_GLPRT_PTC64L(_i) (0x003006A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC64L_MAX_INDEX 3 #define I40E_GLPRT_PTC64L_PTC64L_SHIFT 0 -#define I40E_GLPRT_PTC64L_PTC64L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC64L_PTC64L_SHIFT) -#define I40E_GLPRT_PTC9522H(_i) (0x00300764 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC64L_PTC64L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC64L_PTC64L_SHIFT) +#define I40E_GLPRT_PTC9522H(_i) (0x00300764 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC9522H_MAX_INDEX 3 #define I40E_GLPRT_PTC9522H_PTC9522H_SHIFT 0 -#define I40E_GLPRT_PTC9522H_PTC9522H_MASK (0xFFFF << I40E_GLPRT_PTC9522H_PTC9522H_SHIFT) -#define I40E_GLPRT_PTC9522L(_i) (0x00300760 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PTC9522H_PTC9522H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC9522H_PTC9522H_SHIFT) +#define I40E_GLPRT_PTC9522L(_i) (0x00300760 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_PTC9522L_MAX_INDEX 3 #define I40E_GLPRT_PTC9522L_PTC9522L_SHIFT 0 -#define I40E_GLPRT_PTC9522L_PTC9522L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC9522L_PTC9522L_SHIFT) -#define I40E_GLPRT_PXOFFRXC(_i, _j) (0x00300280 + ((_i) * 8 + (_j) * 32)) +#define I40E_GLPRT_PTC9522L_PTC9522L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC9522L_PTC9522L_SHIFT) +#define I40E_GLPRT_PXOFFRXC(_i, _j) (0x00300280 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ #define I40E_GLPRT_PXOFFRXC_MAX_INDEX 3 #define I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_SHIFT 0 -#define I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_SHIFT) -#define I40E_GLPRT_PXOFFTXC(_i, _j) (0x00300880 + ((_i) * 8 + (_j) * 32)) +#define I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_SHIFT) +#define I40E_GLPRT_PXOFFTXC(_i, _j) (0x00300880 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ #define I40E_GLPRT_PXOFFTXC_MAX_INDEX 3 #define I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_SHIFT 0 -#define I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_SHIFT) -#define I40E_GLPRT_PXONRXC(_i, _j) (0x00300180 + ((_i) * 8 + (_j) * 32)) +#define I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_SHIFT) +#define I40E_GLPRT_PXONRXC(_i, _j) (0x00300180 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ #define I40E_GLPRT_PXONRXC_MAX_INDEX 3 #define I40E_GLPRT_PXONRXC_PRPXONRXCNT_SHIFT 0 -#define I40E_GLPRT_PXONRXC_PRPXONRXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_PXONRXC_PRPXONRXCNT_SHIFT) -#define I40E_GLPRT_PXONTXC(_i, _j) (0x00300780 + ((_i) * 8 + (_j) * 32)) +#define I40E_GLPRT_PXONRXC_PRPXONRXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PXONRXC_PRPXONRXCNT_SHIFT) +#define I40E_GLPRT_PXONTXC(_i, _j) (0x00300780 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ #define I40E_GLPRT_PXONTXC_MAX_INDEX 3 #define I40E_GLPRT_PXONTXC_PRPXONTXC_SHIFT 0 -#define I40E_GLPRT_PXONTXC_PRPXONTXC_MASK (0xFFFFFFFF << I40E_GLPRT_PXONTXC_PRPXONTXC_SHIFT) -#define I40E_GLPRT_RDPC(_i) (0x00300600 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_PXONTXC_PRPXONTXC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PXONTXC_PRPXONTXC_SHIFT) +#define I40E_GLPRT_RDPC(_i) (0x00300600 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_RDPC_MAX_INDEX 3 #define I40E_GLPRT_RDPC_RDPC_SHIFT 0 -#define I40E_GLPRT_RDPC_RDPC_MASK (0xFFFFFFFF << I40E_GLPRT_RDPC_RDPC_SHIFT) -#define I40E_GLPRT_RFC(_i) (0x00300560 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_RDPC_RDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RDPC_RDPC_SHIFT) +#define I40E_GLPRT_RFC(_i) (0x00300560 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_RFC_MAX_INDEX 3 #define I40E_GLPRT_RFC_RFC_SHIFT 0 -#define I40E_GLPRT_RFC_RFC_MASK (0xFFFFFFFF << I40E_GLPRT_RFC_RFC_SHIFT) -#define I40E_GLPRT_RJC(_i) (0x00300580 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_RFC_RFC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RFC_RFC_SHIFT) +#define I40E_GLPRT_RJC(_i) (0x00300580 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_RJC_MAX_INDEX 3 #define I40E_GLPRT_RJC_RJC_SHIFT 0 -#define I40E_GLPRT_RJC_RJC_MASK (0xFFFFFFFF << I40E_GLPRT_RJC_RJC_SHIFT) -#define I40E_GLPRT_RLEC(_i) (0x003000A0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_RJC_RJC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RJC_RJC_SHIFT) +#define I40E_GLPRT_RLEC(_i) (0x003000A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_RLEC_MAX_INDEX 3 #define I40E_GLPRT_RLEC_RLEC_SHIFT 0 -#define I40E_GLPRT_RLEC_RLEC_MASK (0xFFFFFFFF << I40E_GLPRT_RLEC_RLEC_SHIFT) -#define I40E_GLPRT_ROC(_i) (0x00300120 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_RLEC_RLEC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RLEC_RLEC_SHIFT) +#define I40E_GLPRT_ROC(_i) (0x00300120 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_ROC_MAX_INDEX 3 #define I40E_GLPRT_ROC_ROC_SHIFT 0 -#define I40E_GLPRT_ROC_ROC_MASK (0xFFFFFFFF << I40E_GLPRT_ROC_ROC_SHIFT) -#define I40E_GLPRT_RUC(_i) (0x00300100 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_ROC_ROC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_ROC_ROC_SHIFT) +#define I40E_GLPRT_RUC(_i) (0x00300100 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_RUC_MAX_INDEX 3 #define I40E_GLPRT_RUC_RUC_SHIFT 0 -#define I40E_GLPRT_RUC_RUC_MASK (0xFFFFFFFF << I40E_GLPRT_RUC_RUC_SHIFT) -#define I40E_GLPRT_RUPP(_i) (0x00300660 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_RUC_RUC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RUC_RUC_SHIFT) +#define I40E_GLPRT_RUPP(_i) (0x00300660 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_RUPP_MAX_INDEX 3 #define I40E_GLPRT_RUPP_RUPP_SHIFT 0 -#define I40E_GLPRT_RUPP_RUPP_MASK (0xFFFFFFFF << I40E_GLPRT_RUPP_RUPP_SHIFT) -#define I40E_GLPRT_RXON2OFFCNT(_i, _j) (0x00300380 + ((_i) * 8 + (_j) * 32)) +#define I40E_GLPRT_RUPP_RUPP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RUPP_RUPP_SHIFT) +#define I40E_GLPRT_RXON2OFFCNT(_i, _j) (0x00300380 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ #define I40E_GLPRT_RXON2OFFCNT_MAX_INDEX 3 #define I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_SHIFT 0 -#define I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_MASK (0xFFFFFFFF << I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_SHIFT) -#define I40E_GLPRT_STDC(_i) (0x00300640 + ((_i) * 8)) /* _i=0...3 */ -#define I40E_GLPRT_STDC_MAX_INDEX 3 -#define I40E_GLPRT_STDC_STDC_SHIFT 0 -#define I40E_GLPRT_STDC_STDC_MASK (0xFFFFFFFF << I40E_GLPRT_STDC_STDC_SHIFT) -#define I40E_GLPRT_TDOLD(_i) (0x00300A20 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_SHIFT) +#define I40E_GLPRT_TDOLD(_i) (0x00300A20 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_TDOLD_MAX_INDEX 3 #define I40E_GLPRT_TDOLD_GLPRT_TDOLD_SHIFT 0 -#define I40E_GLPRT_TDOLD_GLPRT_TDOLD_MASK (0xFFFFFFFF << I40E_GLPRT_TDOLD_GLPRT_TDOLD_SHIFT) -#define I40E_GLPRT_TDPC(_i) (0x00375400 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_TDOLD_GLPRT_TDOLD_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_TDOLD_GLPRT_TDOLD_SHIFT) +#define I40E_GLPRT_TDPC(_i) (0x00375400 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_TDPC_MAX_INDEX 3 #define I40E_GLPRT_TDPC_TDPC_SHIFT 0 -#define I40E_GLPRT_TDPC_TDPC_MASK (0xFFFFFFFF << I40E_GLPRT_TDPC_TDPC_SHIFT) -#define I40E_GLPRT_UPRCH(_i) (0x003005A4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_TDPC_TDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_TDPC_TDPC_SHIFT) +#define I40E_GLPRT_UPRCH(_i) (0x003005A4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_UPRCH_MAX_INDEX 3 #define I40E_GLPRT_UPRCH_UPRCH_SHIFT 0 -#define I40E_GLPRT_UPRCH_UPRCH_MASK (0xFFFF << I40E_GLPRT_UPRCH_UPRCH_SHIFT) -#define I40E_GLPRT_UPRCL(_i) (0x003005A0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_UPRCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_UPRCH_UPRCH_SHIFT) +#define I40E_GLPRT_UPRCL(_i) (0x003005A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_UPRCL_MAX_INDEX 3 #define I40E_GLPRT_UPRCL_UPRCL_SHIFT 0 -#define I40E_GLPRT_UPRCL_UPRCL_MASK (0xFFFFFFFF << I40E_GLPRT_UPRCL_UPRCL_SHIFT) -#define I40E_GLPRT_UPTCH(_i) (0x003009C4 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_UPRCL_UPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_UPRCL_UPRCL_SHIFT) +#define I40E_GLPRT_UPTCH(_i) (0x003009C4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_UPTCH_MAX_INDEX 3 #define I40E_GLPRT_UPTCH_UPTCH_SHIFT 0 -#define I40E_GLPRT_UPTCH_UPTCH_MASK (0xFFFF << I40E_GLPRT_UPTCH_UPTCH_SHIFT) -#define I40E_GLPRT_UPTCL(_i) (0x003009C0 + ((_i) * 8)) /* _i=0...3 */ +#define I40E_GLPRT_UPTCH_UPTCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_UPTCH_UPTCH_SHIFT) +#define I40E_GLPRT_UPTCL(_i) (0x003009C0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_GLPRT_UPTCL_MAX_INDEX 3 #define I40E_GLPRT_UPTCL_VUPTCH_SHIFT 0 -#define I40E_GLPRT_UPTCL_VUPTCH_MASK (0xFFFFFFFF << I40E_GLPRT_UPTCL_VUPTCH_SHIFT) -#define I40E_GLSW_BPRCH(_i) (0x00370104 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLPRT_UPTCL_VUPTCH_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_UPTCL_VUPTCH_SHIFT) +#define I40E_GLSW_BPRCH(_i) (0x00370104 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_BPRCH_MAX_INDEX 15 #define I40E_GLSW_BPRCH_BPRCH_SHIFT 0 -#define I40E_GLSW_BPRCH_BPRCH_MASK (0xFFFF << I40E_GLSW_BPRCH_BPRCH_SHIFT) -#define I40E_GLSW_BPRCL(_i) (0x00370100 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_BPRCH_BPRCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_BPRCH_BPRCH_SHIFT) +#define I40E_GLSW_BPRCL(_i) (0x00370100 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_BPRCL_MAX_INDEX 15 #define I40E_GLSW_BPRCL_BPRCL_SHIFT 0 -#define I40E_GLSW_BPRCL_BPRCL_MASK (0xFFFFFFFF << I40E_GLSW_BPRCL_BPRCL_SHIFT) -#define I40E_GLSW_BPTCH(_i) (0x00340104 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_BPRCL_BPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_BPRCL_BPRCL_SHIFT) +#define I40E_GLSW_BPTCH(_i) (0x00340104 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_BPTCH_MAX_INDEX 15 #define I40E_GLSW_BPTCH_BPTCH_SHIFT 0 -#define I40E_GLSW_BPTCH_BPTCH_MASK (0xFFFF << I40E_GLSW_BPTCH_BPTCH_SHIFT) -#define I40E_GLSW_BPTCL(_i) (0x00340100 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_BPTCH_BPTCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_BPTCH_BPTCH_SHIFT) +#define I40E_GLSW_BPTCL(_i) (0x00340100 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_BPTCL_MAX_INDEX 15 #define I40E_GLSW_BPTCL_BPTCL_SHIFT 0 -#define I40E_GLSW_BPTCL_BPTCL_MASK (0xFFFFFFFF << I40E_GLSW_BPTCL_BPTCL_SHIFT) -#define I40E_GLSW_GORCH(_i) (0x0035C004 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_BPTCL_BPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_BPTCL_BPTCL_SHIFT) +#define I40E_GLSW_GORCH(_i) (0x0035C004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_GORCH_MAX_INDEX 15 #define I40E_GLSW_GORCH_GORCH_SHIFT 0 -#define I40E_GLSW_GORCH_GORCH_MASK (0xFFFF << I40E_GLSW_GORCH_GORCH_SHIFT) -#define I40E_GLSW_GORCL(_i) (0x0035c000 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_GORCH_GORCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_GORCH_GORCH_SHIFT) +#define I40E_GLSW_GORCL(_i) (0x0035c000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_GORCL_MAX_INDEX 15 #define I40E_GLSW_GORCL_GORCL_SHIFT 0 -#define I40E_GLSW_GORCL_GORCL_MASK (0xFFFFFFFF << I40E_GLSW_GORCL_GORCL_SHIFT) -#define I40E_GLSW_GOTCH(_i) (0x0032C004 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_GORCL_GORCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_GORCL_GORCL_SHIFT) +#define I40E_GLSW_GOTCH(_i) (0x0032C004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_GOTCH_MAX_INDEX 15 #define I40E_GLSW_GOTCH_GOTCH_SHIFT 0 -#define I40E_GLSW_GOTCH_GOTCH_MASK (0xFFFF << I40E_GLSW_GOTCH_GOTCH_SHIFT) -#define I40E_GLSW_GOTCL(_i) (0x0032c000 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_GOTCH_GOTCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_GOTCH_GOTCH_SHIFT) +#define I40E_GLSW_GOTCL(_i) (0x0032c000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_GOTCL_MAX_INDEX 15 #define I40E_GLSW_GOTCL_GOTCL_SHIFT 0 -#define I40E_GLSW_GOTCL_GOTCL_MASK (0xFFFFFFFF << I40E_GLSW_GOTCL_GOTCL_SHIFT) -#define I40E_GLSW_MPRCH(_i) (0x00370084 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_GOTCL_GOTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_GOTCL_GOTCL_SHIFT) +#define I40E_GLSW_MPRCH(_i) (0x00370084 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_MPRCH_MAX_INDEX 15 #define I40E_GLSW_MPRCH_MPRCH_SHIFT 0 -#define I40E_GLSW_MPRCH_MPRCH_MASK (0xFFFF << I40E_GLSW_MPRCH_MPRCH_SHIFT) -#define I40E_GLSW_MPRCL(_i) (0x00370080 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_MPRCH_MPRCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_MPRCH_MPRCH_SHIFT) +#define I40E_GLSW_MPRCL(_i) (0x00370080 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_MPRCL_MAX_INDEX 15 #define I40E_GLSW_MPRCL_MPRCL_SHIFT 0 -#define I40E_GLSW_MPRCL_MPRCL_MASK (0xFFFFFFFF << I40E_GLSW_MPRCL_MPRCL_SHIFT) -#define I40E_GLSW_MPTCH(_i) (0x00340084 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_MPRCL_MPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_MPRCL_MPRCL_SHIFT) +#define I40E_GLSW_MPTCH(_i) (0x00340084 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_MPTCH_MAX_INDEX 15 #define I40E_GLSW_MPTCH_MPTCH_SHIFT 0 -#define I40E_GLSW_MPTCH_MPTCH_MASK (0xFFFF << I40E_GLSW_MPTCH_MPTCH_SHIFT) -#define I40E_GLSW_MPTCL(_i) (0x00340080 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_MPTCH_MPTCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_MPTCH_MPTCH_SHIFT) +#define I40E_GLSW_MPTCL(_i) (0x00340080 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_MPTCL_MAX_INDEX 15 #define I40E_GLSW_MPTCL_MPTCL_SHIFT 0 -#define I40E_GLSW_MPTCL_MPTCL_MASK (0xFFFFFFFF << I40E_GLSW_MPTCL_MPTCL_SHIFT) -#define I40E_GLSW_RUPP(_i) (0x00370180 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_MPTCL_MPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_MPTCL_MPTCL_SHIFT) +#define I40E_GLSW_RUPP(_i) (0x00370180 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_RUPP_MAX_INDEX 15 #define I40E_GLSW_RUPP_RUPP_SHIFT 0 -#define I40E_GLSW_RUPP_RUPP_MASK (0xFFFFFFFF << I40E_GLSW_RUPP_RUPP_SHIFT) -#define I40E_GLSW_TDPC(_i) (0x00348000 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_RUPP_RUPP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_RUPP_RUPP_SHIFT) +#define I40E_GLSW_TDPC(_i) (0x00348000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_TDPC_MAX_INDEX 15 #define I40E_GLSW_TDPC_TDPC_SHIFT 0 -#define I40E_GLSW_TDPC_TDPC_MASK (0xFFFFFFFF << I40E_GLSW_TDPC_TDPC_SHIFT) -#define I40E_GLSW_UPRCH(_i) (0x00370004 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_TDPC_TDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_TDPC_TDPC_SHIFT) +#define I40E_GLSW_UPRCH(_i) (0x00370004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_UPRCH_MAX_INDEX 15 #define I40E_GLSW_UPRCH_UPRCH_SHIFT 0 -#define I40E_GLSW_UPRCH_UPRCH_MASK (0xFFFF << I40E_GLSW_UPRCH_UPRCH_SHIFT) -#define I40E_GLSW_UPRCL(_i) (0x00370000 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_UPRCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_UPRCH_UPRCH_SHIFT) +#define I40E_GLSW_UPRCL(_i) (0x00370000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_UPRCL_MAX_INDEX 15 #define I40E_GLSW_UPRCL_UPRCL_SHIFT 0 -#define I40E_GLSW_UPRCL_UPRCL_MASK (0xFFFFFFFF << I40E_GLSW_UPRCL_UPRCL_SHIFT) -#define I40E_GLSW_UPTCH(_i) (0x00340004 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_UPRCL_UPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_UPRCL_UPRCL_SHIFT) +#define I40E_GLSW_UPTCH(_i) (0x00340004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_UPTCH_MAX_INDEX 15 #define I40E_GLSW_UPTCH_UPTCH_SHIFT 0 -#define I40E_GLSW_UPTCH_UPTCH_MASK (0xFFFF << I40E_GLSW_UPTCH_UPTCH_SHIFT) -#define I40E_GLSW_UPTCL(_i) (0x00340000 + ((_i) * 8)) /* _i=0...15 */ +#define I40E_GLSW_UPTCH_UPTCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_UPTCH_UPTCH_SHIFT) +#define I40E_GLSW_UPTCL(_i) (0x00340000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_GLSW_UPTCL_MAX_INDEX 15 #define I40E_GLSW_UPTCL_UPTCL_SHIFT 0 -#define I40E_GLSW_UPTCL_UPTCL_MASK (0xFFFFFFFF << I40E_GLSW_UPTCL_UPTCL_SHIFT) -#define I40E_GLV_BPRCH(_i) (0x0036D804 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLSW_UPTCL_UPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_UPTCL_UPTCL_SHIFT) +#define I40E_GLV_BPRCH(_i) (0x0036D804 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_BPRCH_MAX_INDEX 383 #define I40E_GLV_BPRCH_BPRCH_SHIFT 0 -#define I40E_GLV_BPRCH_BPRCH_MASK (0xFFFF << I40E_GLV_BPRCH_BPRCH_SHIFT) -#define I40E_GLV_BPRCL(_i) (0x0036d800 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_BPRCH_BPRCH_MASK I40E_MASK(0xFFFF, I40E_GLV_BPRCH_BPRCH_SHIFT) +#define I40E_GLV_BPRCL(_i) (0x0036d800 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_BPRCL_MAX_INDEX 383 #define I40E_GLV_BPRCL_BPRCL_SHIFT 0 -#define I40E_GLV_BPRCL_BPRCL_MASK (0xFFFFFFFF << I40E_GLV_BPRCL_BPRCL_SHIFT) -#define I40E_GLV_BPTCH(_i) (0x0033D804 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_BPRCL_BPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_BPRCL_BPRCL_SHIFT) +#define I40E_GLV_BPTCH(_i) (0x0033D804 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_BPTCH_MAX_INDEX 383 #define I40E_GLV_BPTCH_BPTCH_SHIFT 0 -#define I40E_GLV_BPTCH_BPTCH_MASK (0xFFFF << I40E_GLV_BPTCH_BPTCH_SHIFT) -#define I40E_GLV_BPTCL(_i) (0x0033d800 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_BPTCH_BPTCH_MASK I40E_MASK(0xFFFF, I40E_GLV_BPTCH_BPTCH_SHIFT) +#define I40E_GLV_BPTCL(_i) (0x0033d800 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_BPTCL_MAX_INDEX 383 #define I40E_GLV_BPTCL_BPTCL_SHIFT 0 -#define I40E_GLV_BPTCL_BPTCL_MASK (0xFFFFFFFF << I40E_GLV_BPTCL_BPTCL_SHIFT) -#define I40E_GLV_GORCH(_i) (0x00358004 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_BPTCL_BPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_BPTCL_BPTCL_SHIFT) +#define I40E_GLV_GORCH(_i) (0x00358004 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_GORCH_MAX_INDEX 383 #define I40E_GLV_GORCH_GORCH_SHIFT 0 -#define I40E_GLV_GORCH_GORCH_MASK (0xFFFF << I40E_GLV_GORCH_GORCH_SHIFT) -#define I40E_GLV_GORCL(_i) (0x00358000 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_GORCH_GORCH_MASK I40E_MASK(0xFFFF, I40E_GLV_GORCH_GORCH_SHIFT) +#define I40E_GLV_GORCL(_i) (0x00358000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_GORCL_MAX_INDEX 383 #define I40E_GLV_GORCL_GORCL_SHIFT 0 -#define I40E_GLV_GORCL_GORCL_MASK (0xFFFFFFFF << I40E_GLV_GORCL_GORCL_SHIFT) -#define I40E_GLV_GOTCH(_i) (0x00328004 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_GORCL_GORCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_GORCL_GORCL_SHIFT) +#define I40E_GLV_GOTCH(_i) (0x00328004 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_GOTCH_MAX_INDEX 383 #define I40E_GLV_GOTCH_GOTCH_SHIFT 0 -#define I40E_GLV_GOTCH_GOTCH_MASK (0xFFFF << I40E_GLV_GOTCH_GOTCH_SHIFT) -#define I40E_GLV_GOTCL(_i) (0x00328000 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_GOTCH_GOTCH_MASK I40E_MASK(0xFFFF, I40E_GLV_GOTCH_GOTCH_SHIFT) +#define I40E_GLV_GOTCL(_i) (0x00328000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_GOTCL_MAX_INDEX 383 #define I40E_GLV_GOTCL_GOTCL_SHIFT 0 -#define I40E_GLV_GOTCL_GOTCL_MASK (0xFFFFFFFF << I40E_GLV_GOTCL_GOTCL_SHIFT) -#define I40E_GLV_MPRCH(_i) (0x0036CC04 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_GOTCL_GOTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_GOTCL_GOTCL_SHIFT) +#define I40E_GLV_MPRCH(_i) (0x0036CC04 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_MPRCH_MAX_INDEX 383 #define I40E_GLV_MPRCH_MPRCH_SHIFT 0 -#define I40E_GLV_MPRCH_MPRCH_MASK (0xFFFF << I40E_GLV_MPRCH_MPRCH_SHIFT) -#define I40E_GLV_MPRCL(_i) (0x0036cc00 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_MPRCH_MPRCH_MASK I40E_MASK(0xFFFF, I40E_GLV_MPRCH_MPRCH_SHIFT) +#define I40E_GLV_MPRCL(_i) (0x0036cc00 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_MPRCL_MAX_INDEX 383 #define I40E_GLV_MPRCL_MPRCL_SHIFT 0 -#define I40E_GLV_MPRCL_MPRCL_MASK (0xFFFFFFFF << I40E_GLV_MPRCL_MPRCL_SHIFT) -#define I40E_GLV_MPTCH(_i) (0x0033CC04 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_MPRCL_MPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_MPRCL_MPRCL_SHIFT) +#define I40E_GLV_MPTCH(_i) (0x0033CC04 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_MPTCH_MAX_INDEX 383 #define I40E_GLV_MPTCH_MPTCH_SHIFT 0 -#define I40E_GLV_MPTCH_MPTCH_MASK (0xFFFF << I40E_GLV_MPTCH_MPTCH_SHIFT) -#define I40E_GLV_MPTCL(_i) (0x0033cc00 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_MPTCH_MPTCH_MASK I40E_MASK(0xFFFF, I40E_GLV_MPTCH_MPTCH_SHIFT) +#define I40E_GLV_MPTCL(_i) (0x0033cc00 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_MPTCL_MAX_INDEX 383 #define I40E_GLV_MPTCL_MPTCL_SHIFT 0 -#define I40E_GLV_MPTCL_MPTCL_MASK (0xFFFFFFFF << I40E_GLV_MPTCL_MPTCL_SHIFT) -#define I40E_GLV_RDPC(_i) (0x00310000 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_MPTCL_MPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_MPTCL_MPTCL_SHIFT) +#define I40E_GLV_RDPC(_i) (0x00310000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_RDPC_MAX_INDEX 383 #define I40E_GLV_RDPC_RDPC_SHIFT 0 -#define I40E_GLV_RDPC_RDPC_MASK (0xFFFFFFFF << I40E_GLV_RDPC_RDPC_SHIFT) -#define I40E_GLV_RUPP(_i) (0x0036E400 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_RDPC_RDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_RDPC_RDPC_SHIFT) +#define I40E_GLV_RUPP(_i) (0x0036E400 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_RUPP_MAX_INDEX 383 #define I40E_GLV_RUPP_RUPP_SHIFT 0 -#define I40E_GLV_RUPP_RUPP_MASK (0xFFFFFFFF << I40E_GLV_RUPP_RUPP_SHIFT) -#define I40E_GLV_TEPC(_VSI) (0x00344000 + ((_VSI) * 8)) /* _i=0...383 */ +#define I40E_GLV_RUPP_RUPP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_RUPP_RUPP_SHIFT) +#define I40E_GLV_TEPC(_VSI) (0x00344000 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_TEPC_MAX_INDEX 383 #define I40E_GLV_TEPC_TEPC_SHIFT 0 -#define I40E_GLV_TEPC_TEPC_MASK (0xFFFFFFFF << I40E_GLV_TEPC_TEPC_SHIFT) -#define I40E_GLV_UPRCH(_i) (0x0036C004 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_TEPC_TEPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_TEPC_TEPC_SHIFT) +#define I40E_GLV_UPRCH(_i) (0x0036C004 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_UPRCH_MAX_INDEX 383 #define I40E_GLV_UPRCH_UPRCH_SHIFT 0 -#define I40E_GLV_UPRCH_UPRCH_MASK (0xFFFF << I40E_GLV_UPRCH_UPRCH_SHIFT) -#define I40E_GLV_UPRCL(_i) (0x0036c000 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_UPRCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLV_UPRCH_UPRCH_SHIFT) +#define I40E_GLV_UPRCL(_i) (0x0036c000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_UPRCL_MAX_INDEX 383 #define I40E_GLV_UPRCL_UPRCL_SHIFT 0 -#define I40E_GLV_UPRCL_UPRCL_MASK (0xFFFFFFFF << I40E_GLV_UPRCL_UPRCL_SHIFT) -#define I40E_GLV_UPTCH(_i) (0x0033C004 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_UPRCL_UPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_UPRCL_UPRCL_SHIFT) +#define I40E_GLV_UPTCH(_i) (0x0033C004 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_UPTCH_MAX_INDEX 383 #define I40E_GLV_UPTCH_GLVUPTCH_SHIFT 0 -#define I40E_GLV_UPTCH_GLVUPTCH_MASK (0xFFFF << I40E_GLV_UPTCH_GLVUPTCH_SHIFT) -#define I40E_GLV_UPTCL(_i) (0x0033c000 + ((_i) * 8)) /* _i=0...383 */ +#define I40E_GLV_UPTCH_GLVUPTCH_MASK I40E_MASK(0xFFFF, I40E_GLV_UPTCH_GLVUPTCH_SHIFT) +#define I40E_GLV_UPTCL(_i) (0x0033c000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ #define I40E_GLV_UPTCL_MAX_INDEX 383 #define I40E_GLV_UPTCL_UPTCL_SHIFT 0 -#define I40E_GLV_UPTCL_UPTCL_MASK (0xFFFFFFFF << I40E_GLV_UPTCL_UPTCL_SHIFT) -#define I40E_GLVEBTC_RBCH(_i, _j) (0x00364004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLV_UPTCL_UPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_UPTCL_UPTCL_SHIFT) +#define I40E_GLVEBTC_RBCH(_i, _j) (0x00364004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_RBCH_MAX_INDEX 7 #define I40E_GLVEBTC_RBCH_TCBCH_SHIFT 0 -#define I40E_GLVEBTC_RBCH_TCBCH_MASK (0xFFFF << I40E_GLVEBTC_RBCH_TCBCH_SHIFT) -#define I40E_GLVEBTC_RBCL(_i, _j) (0x00364000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_RBCH_TCBCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBTC_RBCH_TCBCH_SHIFT) +#define I40E_GLVEBTC_RBCL(_i, _j) (0x00364000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_RBCL_MAX_INDEX 7 #define I40E_GLVEBTC_RBCL_TCBCL_SHIFT 0 -#define I40E_GLVEBTC_RBCL_TCBCL_MASK (0xFFFFFFFF << I40E_GLVEBTC_RBCL_TCBCL_SHIFT) -#define I40E_GLVEBTC_RPCH(_i, _j) (0x00368004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_RBCL_TCBCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBTC_RBCL_TCBCL_SHIFT) +#define I40E_GLVEBTC_RPCH(_i, _j) (0x00368004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_RPCH_MAX_INDEX 7 #define I40E_GLVEBTC_RPCH_TCPCH_SHIFT 0 -#define I40E_GLVEBTC_RPCH_TCPCH_MASK (0xFFFF << I40E_GLVEBTC_RPCH_TCPCH_SHIFT) -#define I40E_GLVEBTC_RPCL(_i, _j) (0x00368000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_RPCH_TCPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBTC_RPCH_TCPCH_SHIFT) +#define I40E_GLVEBTC_RPCL(_i, _j) (0x00368000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_RPCL_MAX_INDEX 7 #define I40E_GLVEBTC_RPCL_TCPCL_SHIFT 0 -#define I40E_GLVEBTC_RPCL_TCPCL_MASK (0xFFFFFFFF << I40E_GLVEBTC_RPCL_TCPCL_SHIFT) -#define I40E_GLVEBTC_TBCH(_i, _j) (0x00334004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_RPCL_TCPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBTC_RPCL_TCPCL_SHIFT) +#define I40E_GLVEBTC_TBCH(_i, _j) (0x00334004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_TBCH_MAX_INDEX 7 #define I40E_GLVEBTC_TBCH_TCBCH_SHIFT 0 -#define I40E_GLVEBTC_TBCH_TCBCH_MASK (0xFFFF << I40E_GLVEBTC_TBCH_TCBCH_SHIFT) -#define I40E_GLVEBTC_TBCL(_i, _j) (0x00334000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_TBCH_TCBCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBTC_TBCH_TCBCH_SHIFT) +#define I40E_GLVEBTC_TBCL(_i, _j) (0x00334000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_TBCL_MAX_INDEX 7 #define I40E_GLVEBTC_TBCL_TCBCL_SHIFT 0 -#define I40E_GLVEBTC_TBCL_TCBCL_MASK (0xFFFFFFFF << I40E_GLVEBTC_TBCL_TCBCL_SHIFT) -#define I40E_GLVEBTC_TPCH(_i, _j) (0x00338004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_TBCL_TCBCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBTC_TBCL_TCBCL_SHIFT) +#define I40E_GLVEBTC_TPCH(_i, _j) (0x00338004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_TPCH_MAX_INDEX 7 #define I40E_GLVEBTC_TPCH_TCPCH_SHIFT 0 -#define I40E_GLVEBTC_TPCH_TCPCH_MASK (0xFFFF << I40E_GLVEBTC_TPCH_TCPCH_SHIFT) -#define I40E_GLVEBTC_TPCL(_i, _j) (0x00338000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ +#define I40E_GLVEBTC_TPCH_TCPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBTC_TPCH_TCPCH_SHIFT) +#define I40E_GLVEBTC_TPCL(_i, _j) (0x00338000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ #define I40E_GLVEBTC_TPCL_MAX_INDEX 7 #define I40E_GLVEBTC_TPCL_TCPCL_SHIFT 0 -#define I40E_GLVEBTC_TPCL_TCPCL_MASK (0xFFFFFFFF << I40E_GLVEBTC_TPCL_TCPCL_SHIFT) -#define I40E_GLVEBVL_BPCH(_i) (0x00374804 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBTC_TPCL_TCPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBTC_TPCL_TCPCL_SHIFT) +#define I40E_GLVEBVL_BPCH(_i) (0x00374804 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_BPCH_MAX_INDEX 127 #define I40E_GLVEBVL_BPCH_VLBPCH_SHIFT 0 -#define I40E_GLVEBVL_BPCH_VLBPCH_MASK (0xFFFF << I40E_GLVEBVL_BPCH_VLBPCH_SHIFT) -#define I40E_GLVEBVL_BPCL(_i) (0x00374800 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_BPCH_VLBPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_BPCH_VLBPCH_SHIFT) +#define I40E_GLVEBVL_BPCL(_i) (0x00374800 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_BPCL_MAX_INDEX 127 #define I40E_GLVEBVL_BPCL_VLBPCL_SHIFT 0 -#define I40E_GLVEBVL_BPCL_VLBPCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_BPCL_VLBPCL_SHIFT) -#define I40E_GLVEBVL_GORCH(_i) (0x00360004 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_BPCL_VLBPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_BPCL_VLBPCL_SHIFT) +#define I40E_GLVEBVL_GORCH(_i) (0x00360004 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_GORCH_MAX_INDEX 127 #define I40E_GLVEBVL_GORCH_VLBCH_SHIFT 0 -#define I40E_GLVEBVL_GORCH_VLBCH_MASK (0xFFFF << I40E_GLVEBVL_GORCH_VLBCH_SHIFT) -#define I40E_GLVEBVL_GORCL(_i) (0x00360000 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_GORCH_VLBCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_GORCH_VLBCH_SHIFT) +#define I40E_GLVEBVL_GORCL(_i) (0x00360000 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_GORCL_MAX_INDEX 127 #define I40E_GLVEBVL_GORCL_VLBCL_SHIFT 0 -#define I40E_GLVEBVL_GORCL_VLBCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_GORCL_VLBCL_SHIFT) -#define I40E_GLVEBVL_GOTCH(_i) (0x00330004 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_GORCL_VLBCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_GORCL_VLBCL_SHIFT) +#define I40E_GLVEBVL_GOTCH(_i) (0x00330004 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_GOTCH_MAX_INDEX 127 #define I40E_GLVEBVL_GOTCH_VLBCH_SHIFT 0 -#define I40E_GLVEBVL_GOTCH_VLBCH_MASK (0xFFFF << I40E_GLVEBVL_GOTCH_VLBCH_SHIFT) -#define I40E_GLVEBVL_GOTCL(_i) (0x00330000 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_GOTCH_VLBCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_GOTCH_VLBCH_SHIFT) +#define I40E_GLVEBVL_GOTCL(_i) (0x00330000 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_GOTCL_MAX_INDEX 127 #define I40E_GLVEBVL_GOTCL_VLBCL_SHIFT 0 -#define I40E_GLVEBVL_GOTCL_VLBCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_GOTCL_VLBCL_SHIFT) -#define I40E_GLVEBVL_MPCH(_i) (0x00374404 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_GOTCL_VLBCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_GOTCL_VLBCL_SHIFT) +#define I40E_GLVEBVL_MPCH(_i) (0x00374404 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_MPCH_MAX_INDEX 127 #define I40E_GLVEBVL_MPCH_VLMPCH_SHIFT 0 -#define I40E_GLVEBVL_MPCH_VLMPCH_MASK (0xFFFF << I40E_GLVEBVL_MPCH_VLMPCH_SHIFT) -#define I40E_GLVEBVL_MPCL(_i) (0x00374400 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_MPCH_VLMPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_MPCH_VLMPCH_SHIFT) +#define I40E_GLVEBVL_MPCL(_i) (0x00374400 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_MPCL_MAX_INDEX 127 #define I40E_GLVEBVL_MPCL_VLMPCL_SHIFT 0 -#define I40E_GLVEBVL_MPCL_VLMPCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_MPCL_VLMPCL_SHIFT) -#define I40E_GLVEBVL_UPCH(_i) (0x00374004 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_MPCL_VLMPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_MPCL_VLMPCL_SHIFT) +#define I40E_GLVEBVL_UPCH(_i) (0x00374004 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_UPCH_MAX_INDEX 127 #define I40E_GLVEBVL_UPCH_VLUPCH_SHIFT 0 -#define I40E_GLVEBVL_UPCH_VLUPCH_MASK (0xFFFF << I40E_GLVEBVL_UPCH_VLUPCH_SHIFT) -#define I40E_GLVEBVL_UPCL(_i) (0x00374000 + ((_i) * 8)) /* _i=0...127 */ +#define I40E_GLVEBVL_UPCH_VLUPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_UPCH_VLUPCH_SHIFT) +#define I40E_GLVEBVL_UPCL(_i) (0x00374000 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_GLVEBVL_UPCL_MAX_INDEX 127 #define I40E_GLVEBVL_UPCL_VLUPCL_SHIFT 0 -#define I40E_GLVEBVL_UPCL_VLUPCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_UPCL_VLUPCL_SHIFT) -#define I40E_GL_MTG_FLU_MSK_H 0x00269F4C +#define I40E_GLVEBVL_UPCL_VLUPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_UPCL_VLUPCL_SHIFT) +#define I40E_GL_MTG_FLU_MSK_H 0x00269F4C /* Reset: CORER */ #define I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_SHIFT 0 -#define I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_MASK (0xFFFF << I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_SHIFT) -#define I40E_GL_MTG_FLU_MSK_L 0x00269F44 -#define I40E_GL_MTG_FLU_MSK_L_MASK_LOW_SHIFT 0 -#define I40E_GL_MTG_FLU_MSK_L_MASK_LOW_MASK (0xFFFFFFFF << I40E_GL_MTG_FLU_MSK_L_MASK_LOW_SHIFT) -#define I40E_GL_SWR_DEF_ACT(_i) (0x0026CF00 + ((_i) * 4)) /* _i=0...25 */ -#define I40E_GL_SWR_DEF_ACT_MAX_INDEX 25 +#define I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_MASK I40E_MASK(0xFFFF, I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_SHIFT) +#define I40E_GL_SWR_DEF_ACT(_i) (0x00270200 + ((_i) * 4)) /* _i=0...35 */ /* Reset: CORER */ +#define I40E_GL_SWR_DEF_ACT_MAX_INDEX 35 #define I40E_GL_SWR_DEF_ACT_DEF_ACTION_SHIFT 0 -#define I40E_GL_SWR_DEF_ACT_DEF_ACTION_MASK (0xFFFFFFFF << I40E_GL_SWR_DEF_ACT_DEF_ACTION_SHIFT) -#define I40E_GL_SWR_DEF_ACT_EN 0x0026CF84 +#define I40E_GL_SWR_DEF_ACT_DEF_ACTION_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_SWR_DEF_ACT_DEF_ACTION_SHIFT) +#define I40E_GL_SWR_DEF_ACT_EN(_i) (0x0026CFB8 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */ +#define I40E_GL_SWR_DEF_ACT_EN_MAX_INDEX 1 #define I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_SHIFT 0 -#define I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_MASK (0xFFFFFFFF << I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_SHIFT) -#define I40E_PRT_MSCCNT 0x00256BA0 -#define I40E_PRT_MSCCNT_CCOUNT_SHIFT 0 -#define I40E_PRT_MSCCNT_CCOUNT_MASK (0x1FFFFFF << I40E_PRT_MSCCNT_CCOUNT_SHIFT) -#define I40E_PRT_SCSTS 0x00256C20 -#define I40E_PRT_SCSTS_BSCA_SHIFT 0 -#define I40E_PRT_SCSTS_BSCA_MASK (0x1 << I40E_PRT_SCSTS_BSCA_SHIFT) -#define I40E_PRT_SCSTS_BSCAP_SHIFT 1 -#define I40E_PRT_SCSTS_BSCAP_MASK (0x1 << I40E_PRT_SCSTS_BSCAP_SHIFT) -#define I40E_PRT_SCSTS_MSCA_SHIFT 2 -#define I40E_PRT_SCSTS_MSCA_MASK (0x1 << I40E_PRT_SCSTS_MSCA_SHIFT) -#define I40E_PRT_SCSTS_MSCAP_SHIFT 3 -#define I40E_PRT_SCSTS_MSCAP_MASK (0x1 << I40E_PRT_SCSTS_MSCAP_SHIFT) -#define I40E_PRT_SWT_BSCCNT 0x00256C60 -#define I40E_PRT_SWT_BSCCNT_CCOUNT_SHIFT 0 -#define I40E_PRT_SWT_BSCCNT_CCOUNT_MASK (0x1FFFFFF << I40E_PRT_SWT_BSCCNT_CCOUNT_SHIFT) -#define I40E_PRTTSYN_ADJ 0x001E4280 +#define I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_SHIFT) +#define I40E_PRTTSYN_ADJ 0x001E4280 /* Reset: GLOBR */ #define I40E_PRTTSYN_ADJ_TSYNADJ_SHIFT 0 -#define I40E_PRTTSYN_ADJ_TSYNADJ_MASK (0x7FFFFFFF << I40E_PRTTSYN_ADJ_TSYNADJ_SHIFT) +#define I40E_PRTTSYN_ADJ_TSYNADJ_MASK I40E_MASK(0x7FFFFFFF, I40E_PRTTSYN_ADJ_TSYNADJ_SHIFT) #define I40E_PRTTSYN_ADJ_SIGN_SHIFT 31 -#define I40E_PRTTSYN_ADJ_SIGN_MASK (0x1 << I40E_PRTTSYN_ADJ_SIGN_SHIFT) -#define I40E_PRTTSYN_AUX_0(_i) (0x001E42A0 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_ADJ_SIGN_MASK I40E_MASK(0x1, I40E_PRTTSYN_ADJ_SIGN_SHIFT) +#define I40E_PRTTSYN_AUX_0(_i) (0x001E42A0 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_AUX_0_MAX_INDEX 1 #define I40E_PRTTSYN_AUX_0_OUT_ENA_SHIFT 0 -#define I40E_PRTTSYN_AUX_0_OUT_ENA_MASK (0x1 << I40E_PRTTSYN_AUX_0_OUT_ENA_SHIFT) +#define I40E_PRTTSYN_AUX_0_OUT_ENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_AUX_0_OUT_ENA_SHIFT) #define I40E_PRTTSYN_AUX_0_OUTMOD_SHIFT 1 -#define I40E_PRTTSYN_AUX_0_OUTMOD_MASK (0x3 << I40E_PRTTSYN_AUX_0_OUTMOD_SHIFT) +#define I40E_PRTTSYN_AUX_0_OUTMOD_MASK I40E_MASK(0x3, I40E_PRTTSYN_AUX_0_OUTMOD_SHIFT) #define I40E_PRTTSYN_AUX_0_OUTLVL_SHIFT 3 -#define I40E_PRTTSYN_AUX_0_OUTLVL_MASK (0x1 << I40E_PRTTSYN_AUX_0_OUTLVL_SHIFT) +#define I40E_PRTTSYN_AUX_0_OUTLVL_MASK I40E_MASK(0x1, I40E_PRTTSYN_AUX_0_OUTLVL_SHIFT) #define I40E_PRTTSYN_AUX_0_PULSEW_SHIFT 8 -#define I40E_PRTTSYN_AUX_0_PULSEW_MASK (0xF << I40E_PRTTSYN_AUX_0_PULSEW_SHIFT) +#define I40E_PRTTSYN_AUX_0_PULSEW_MASK I40E_MASK(0xF, I40E_PRTTSYN_AUX_0_PULSEW_SHIFT) #define I40E_PRTTSYN_AUX_0_EVNTLVL_SHIFT 16 -#define I40E_PRTTSYN_AUX_0_EVNTLVL_MASK (0x3 << I40E_PRTTSYN_AUX_0_EVNTLVL_SHIFT) -#define I40E_PRTTSYN_AUX_1(_i) (0x001E42E0 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_AUX_0_EVNTLVL_MASK I40E_MASK(0x3, I40E_PRTTSYN_AUX_0_EVNTLVL_SHIFT) +#define I40E_PRTTSYN_AUX_1(_i) (0x001E42E0 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_AUX_1_MAX_INDEX 1 #define I40E_PRTTSYN_AUX_1_INSTNT_SHIFT 0 -#define I40E_PRTTSYN_AUX_1_INSTNT_MASK (0x1 << I40E_PRTTSYN_AUX_1_INSTNT_SHIFT) +#define I40E_PRTTSYN_AUX_1_INSTNT_MASK I40E_MASK(0x1, I40E_PRTTSYN_AUX_1_INSTNT_SHIFT) #define I40E_PRTTSYN_AUX_1_SAMPLE_TIME_SHIFT 1 -#define I40E_PRTTSYN_AUX_1_SAMPLE_TIME_MASK (0x1 << I40E_PRTTSYN_AUX_1_SAMPLE_TIME_SHIFT) -#define I40E_PRTTSYN_CLKO(_i) (0x001E4240 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_AUX_1_SAMPLE_TIME_MASK I40E_MASK(0x1, I40E_PRTTSYN_AUX_1_SAMPLE_TIME_SHIFT) +#define I40E_PRTTSYN_CLKO(_i) (0x001E4240 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_CLKO_MAX_INDEX 1 #define I40E_PRTTSYN_CLKO_TSYNCLKO_SHIFT 0 -#define I40E_PRTTSYN_CLKO_TSYNCLKO_MASK (0xFFFFFFFF << I40E_PRTTSYN_CLKO_TSYNCLKO_SHIFT) -#define I40E_PRTTSYN_CTL0 0x001E4200 +#define I40E_PRTTSYN_CLKO_TSYNCLKO_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_CLKO_TSYNCLKO_SHIFT) +#define I40E_PRTTSYN_CTL0 0x001E4200 /* Reset: GLOBR */ #define I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_SHIFT 0 -#define I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_MASK (0x1 << I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_SHIFT) +#define I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_SHIFT) #define I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_SHIFT 1 -#define I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK (0x1 << I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_SHIFT) +#define I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_SHIFT) #define I40E_PRTTSYN_CTL0_EVENT_INT_ENA_SHIFT 2 -#define I40E_PRTTSYN_CTL0_EVENT_INT_ENA_MASK (0x1 << I40E_PRTTSYN_CTL0_EVENT_INT_ENA_SHIFT) +#define I40E_PRTTSYN_CTL0_EVENT_INT_ENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_EVENT_INT_ENA_SHIFT) #define I40E_PRTTSYN_CTL0_TGT_INT_ENA_SHIFT 3 -#define I40E_PRTTSYN_CTL0_TGT_INT_ENA_MASK (0x1 << I40E_PRTTSYN_CTL0_TGT_INT_ENA_SHIFT) +#define I40E_PRTTSYN_CTL0_TGT_INT_ENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_TGT_INT_ENA_SHIFT) #define I40E_PRTTSYN_CTL0_PF_ID_SHIFT 8 -#define I40E_PRTTSYN_CTL0_PF_ID_MASK (0xF << I40E_PRTTSYN_CTL0_PF_ID_SHIFT) +#define I40E_PRTTSYN_CTL0_PF_ID_MASK I40E_MASK(0xF, I40E_PRTTSYN_CTL0_PF_ID_SHIFT) #define I40E_PRTTSYN_CTL0_TSYNACT_SHIFT 12 -#define I40E_PRTTSYN_CTL0_TSYNACT_MASK (0x3 << I40E_PRTTSYN_CTL0_TSYNACT_SHIFT) +#define I40E_PRTTSYN_CTL0_TSYNACT_MASK I40E_MASK(0x3, I40E_PRTTSYN_CTL0_TSYNACT_SHIFT) #define I40E_PRTTSYN_CTL0_TSYNENA_SHIFT 31 -#define I40E_PRTTSYN_CTL0_TSYNENA_MASK (0x1 << I40E_PRTTSYN_CTL0_TSYNENA_SHIFT) -#define I40E_PRTTSYN_CTL1 0x00085020 +#define I40E_PRTTSYN_CTL0_TSYNENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_TSYNENA_SHIFT) +#define I40E_PRTTSYN_CTL1 0x00085020 /* Reset: CORER */ #define I40E_PRTTSYN_CTL1_V1MESSTYPE0_SHIFT 0 -#define I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK (0xFF << I40E_PRTTSYN_CTL1_V1MESSTYPE0_SHIFT) +#define I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK I40E_MASK(0xFF, I40E_PRTTSYN_CTL1_V1MESSTYPE0_SHIFT) #define I40E_PRTTSYN_CTL1_V1MESSTYPE1_SHIFT 8 -#define I40E_PRTTSYN_CTL1_V1MESSTYPE1_MASK (0xFF << I40E_PRTTSYN_CTL1_V1MESSTYPE1_SHIFT) +#define I40E_PRTTSYN_CTL1_V1MESSTYPE1_MASK I40E_MASK(0xFF, I40E_PRTTSYN_CTL1_V1MESSTYPE1_SHIFT) #define I40E_PRTTSYN_CTL1_V2MESSTYPE0_SHIFT 16 -#define I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK (0xF << I40E_PRTTSYN_CTL1_V2MESSTYPE0_SHIFT) +#define I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK I40E_MASK(0xF, I40E_PRTTSYN_CTL1_V2MESSTYPE0_SHIFT) #define I40E_PRTTSYN_CTL1_V2MESSTYPE1_SHIFT 20 -#define I40E_PRTTSYN_CTL1_V2MESSTYPE1_MASK (0xF << I40E_PRTTSYN_CTL1_V2MESSTYPE1_SHIFT) +#define I40E_PRTTSYN_CTL1_V2MESSTYPE1_MASK I40E_MASK(0xF, I40E_PRTTSYN_CTL1_V2MESSTYPE1_SHIFT) #define I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT 24 -#define I40E_PRTTSYN_CTL1_TSYNTYPE_MASK (0x3 << I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) +#define I40E_PRTTSYN_CTL1_TSYNTYPE_MASK I40E_MASK(0x3, I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) #define I40E_PRTTSYN_CTL1_UDP_ENA_SHIFT 26 -#define I40E_PRTTSYN_CTL1_UDP_ENA_MASK (0x3 << I40E_PRTTSYN_CTL1_UDP_ENA_SHIFT) +#define I40E_PRTTSYN_CTL1_UDP_ENA_MASK I40E_MASK(0x3, I40E_PRTTSYN_CTL1_UDP_ENA_SHIFT) #define I40E_PRTTSYN_CTL1_TSYNENA_SHIFT 31 -#define I40E_PRTTSYN_CTL1_TSYNENA_MASK (0x1 << I40E_PRTTSYN_CTL1_TSYNENA_SHIFT) -#define I40E_PRTTSYN_EVNT_H(_i) (0x001E40C0 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_CTL1_TSYNENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL1_TSYNENA_SHIFT) +#define I40E_PRTTSYN_EVNT_H(_i) (0x001E40C0 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_EVNT_H_MAX_INDEX 1 #define I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_SHIFT 0 -#define I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_SHIFT) -#define I40E_PRTTSYN_EVNT_L(_i) (0x001E4080 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_SHIFT) +#define I40E_PRTTSYN_EVNT_L(_i) (0x001E4080 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_EVNT_L_MAX_INDEX 1 #define I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_SHIFT 0 -#define I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_SHIFT) -#define I40E_PRTTSYN_INC_H 0x001E4060 +#define I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_SHIFT) +#define I40E_PRTTSYN_INC_H 0x001E4060 /* Reset: GLOBR */ #define I40E_PRTTSYN_INC_H_TSYNINC_H_SHIFT 0 -#define I40E_PRTTSYN_INC_H_TSYNINC_H_MASK (0x3F << I40E_PRTTSYN_INC_H_TSYNINC_H_SHIFT) -#define I40E_PRTTSYN_INC_L 0x001E4040 +#define I40E_PRTTSYN_INC_H_TSYNINC_H_MASK I40E_MASK(0x3F, I40E_PRTTSYN_INC_H_TSYNINC_H_SHIFT) +#define I40E_PRTTSYN_INC_L 0x001E4040 /* Reset: GLOBR */ #define I40E_PRTTSYN_INC_L_TSYNINC_L_SHIFT 0 -#define I40E_PRTTSYN_INC_L_TSYNINC_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_INC_L_TSYNINC_L_SHIFT) -#define I40E_PRTTSYN_RXTIME_H(_i) (0x00085040 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRTTSYN_INC_L_TSYNINC_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_INC_L_TSYNINC_L_SHIFT) +#define I40E_PRTTSYN_RXTIME_H(_i) (0x00085040 + ((_i) * 32)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_PRTTSYN_RXTIME_H_MAX_INDEX 3 #define I40E_PRTTSYN_RXTIME_H_RXTIEM_H_SHIFT 0 -#define I40E_PRTTSYN_RXTIME_H_RXTIEM_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_RXTIME_H_RXTIEM_H_SHIFT) -#define I40E_PRTTSYN_RXTIME_L(_i) (0x000850C0 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRTTSYN_RXTIME_H_RXTIEM_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_RXTIME_H_RXTIEM_H_SHIFT) +#define I40E_PRTTSYN_RXTIME_L(_i) (0x000850C0 + ((_i) * 32)) /* _i=0...3 */ /* Reset: CORER */ #define I40E_PRTTSYN_RXTIME_L_MAX_INDEX 3 #define I40E_PRTTSYN_RXTIME_L_RXTIEM_L_SHIFT 0 -#define I40E_PRTTSYN_RXTIME_L_RXTIEM_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_RXTIME_L_RXTIEM_L_SHIFT) -#define I40E_PRTTSYN_STAT_0 0x001E4220 +#define I40E_PRTTSYN_RXTIME_L_RXTIEM_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_RXTIME_L_RXTIEM_L_SHIFT) +#define I40E_PRTTSYN_STAT_0 0x001E4220 /* Reset: GLOBR */ #define I40E_PRTTSYN_STAT_0_EVENT0_SHIFT 0 -#define I40E_PRTTSYN_STAT_0_EVENT0_MASK (0x1 << I40E_PRTTSYN_STAT_0_EVENT0_SHIFT) +#define I40E_PRTTSYN_STAT_0_EVENT0_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_EVENT0_SHIFT) #define I40E_PRTTSYN_STAT_0_EVENT1_SHIFT 1 -#define I40E_PRTTSYN_STAT_0_EVENT1_MASK (0x1 << I40E_PRTTSYN_STAT_0_EVENT1_SHIFT) +#define I40E_PRTTSYN_STAT_0_EVENT1_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_EVENT1_SHIFT) #define I40E_PRTTSYN_STAT_0_TGT0_SHIFT 2 -#define I40E_PRTTSYN_STAT_0_TGT0_MASK (0x1 << I40E_PRTTSYN_STAT_0_TGT0_SHIFT) +#define I40E_PRTTSYN_STAT_0_TGT0_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_TGT0_SHIFT) #define I40E_PRTTSYN_STAT_0_TGT1_SHIFT 3 -#define I40E_PRTTSYN_STAT_0_TGT1_MASK (0x1 << I40E_PRTTSYN_STAT_0_TGT1_SHIFT) +#define I40E_PRTTSYN_STAT_0_TGT1_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_TGT1_SHIFT) #define I40E_PRTTSYN_STAT_0_TXTIME_SHIFT 4 -#define I40E_PRTTSYN_STAT_0_TXTIME_MASK (0x1 << I40E_PRTTSYN_STAT_0_TXTIME_SHIFT) -#define I40E_PRTTSYN_STAT_1 0x00085140 +#define I40E_PRTTSYN_STAT_0_TXTIME_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_TXTIME_SHIFT) +#define I40E_PRTTSYN_STAT_1 0x00085140 /* Reset: CORER */ #define I40E_PRTTSYN_STAT_1_RXT0_SHIFT 0 -#define I40E_PRTTSYN_STAT_1_RXT0_MASK (0x1 << I40E_PRTTSYN_STAT_1_RXT0_SHIFT) +#define I40E_PRTTSYN_STAT_1_RXT0_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_1_RXT0_SHIFT) #define I40E_PRTTSYN_STAT_1_RXT1_SHIFT 1 -#define I40E_PRTTSYN_STAT_1_RXT1_MASK (0x1 << I40E_PRTTSYN_STAT_1_RXT1_SHIFT) +#define I40E_PRTTSYN_STAT_1_RXT1_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_1_RXT1_SHIFT) #define I40E_PRTTSYN_STAT_1_RXT2_SHIFT 2 -#define I40E_PRTTSYN_STAT_1_RXT2_MASK (0x1 << I40E_PRTTSYN_STAT_1_RXT2_SHIFT) +#define I40E_PRTTSYN_STAT_1_RXT2_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_1_RXT2_SHIFT) #define I40E_PRTTSYN_STAT_1_RXT3_SHIFT 3 -#define I40E_PRTTSYN_STAT_1_RXT3_MASK (0x1 << I40E_PRTTSYN_STAT_1_RXT3_SHIFT) -#define I40E_PRTTSYN_TGT_H(_i) (0x001E4180 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_STAT_1_RXT3_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_1_RXT3_SHIFT) +#define I40E_PRTTSYN_TGT_H(_i) (0x001E4180 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_TGT_H_MAX_INDEX 1 #define I40E_PRTTSYN_TGT_H_TSYNTGTT_H_SHIFT 0 -#define I40E_PRTTSYN_TGT_H_TSYNTGTT_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_TGT_H_TSYNTGTT_H_SHIFT) -#define I40E_PRTTSYN_TGT_L(_i) (0x001E4140 + ((_i) * 32)) /* _i=0...1 */ +#define I40E_PRTTSYN_TGT_H_TSYNTGTT_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TGT_H_TSYNTGTT_H_SHIFT) +#define I40E_PRTTSYN_TGT_L(_i) (0x001E4140 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ #define I40E_PRTTSYN_TGT_L_MAX_INDEX 1 #define I40E_PRTTSYN_TGT_L_TSYNTGTT_L_SHIFT 0 -#define I40E_PRTTSYN_TGT_L_TSYNTGTT_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_TGT_L_TSYNTGTT_L_SHIFT) -#define I40E_PRTTSYN_TIME_H 0x001E4120 +#define I40E_PRTTSYN_TGT_L_TSYNTGTT_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TGT_L_TSYNTGTT_L_SHIFT) +#define I40E_PRTTSYN_TIME_H 0x001E4120 /* Reset: GLOBR */ #define I40E_PRTTSYN_TIME_H_TSYNTIME_H_SHIFT 0 -#define I40E_PRTTSYN_TIME_H_TSYNTIME_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_TIME_H_TSYNTIME_H_SHIFT) -#define I40E_PRTTSYN_TIME_L 0x001E4100 +#define I40E_PRTTSYN_TIME_H_TSYNTIME_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TIME_H_TSYNTIME_H_SHIFT) +#define I40E_PRTTSYN_TIME_L 0x001E4100 /* Reset: GLOBR */ #define I40E_PRTTSYN_TIME_L_TSYNTIME_L_SHIFT 0 -#define I40E_PRTTSYN_TIME_L_TSYNTIME_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_TIME_L_TSYNTIME_L_SHIFT) -#define I40E_PRTTSYN_TXTIME_H 0x001E41E0 +#define I40E_PRTTSYN_TIME_L_TSYNTIME_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TIME_L_TSYNTIME_L_SHIFT) +#define I40E_PRTTSYN_TXTIME_H 0x001E41E0 /* Reset: GLOBR */ #define I40E_PRTTSYN_TXTIME_H_TXTIEM_H_SHIFT 0 -#define I40E_PRTTSYN_TXTIME_H_TXTIEM_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_TXTIME_H_TXTIEM_H_SHIFT) -#define I40E_PRTTSYN_TXTIME_L 0x001E41C0 +#define I40E_PRTTSYN_TXTIME_H_TXTIEM_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TXTIME_H_TXTIEM_H_SHIFT) +#define I40E_PRTTSYN_TXTIME_L 0x001E41C0 /* Reset: GLOBR */ #define I40E_PRTTSYN_TXTIME_L_TXTIEM_L_SHIFT 0 -#define I40E_PRTTSYN_TXTIME_L_TXTIEM_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_TXTIME_L_TXTIEM_L_SHIFT) -#define I40E_GLSCD_QUANTA 0x000B2080 +#define I40E_PRTTSYN_TXTIME_L_TXTIEM_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TXTIME_L_TXTIEM_L_SHIFT) +#define I40E_GLSCD_QUANTA 0x000B2080 /* Reset: CORER */ #define I40E_GLSCD_QUANTA_TSCDQUANTA_SHIFT 0 -#define I40E_GLSCD_QUANTA_TSCDQUANTA_MASK (0x7 << I40E_GLSCD_QUANTA_TSCDQUANTA_SHIFT) -#define I40E_GL_MDET_RX 0x0012A510 +#define I40E_GLSCD_QUANTA_TSCDQUANTA_MASK I40E_MASK(0x7, I40E_GLSCD_QUANTA_TSCDQUANTA_SHIFT) +#define I40E_GL_MDET_RX 0x0012A510 /* Reset: CORER */ #define I40E_GL_MDET_RX_FUNCTION_SHIFT 0 -#define I40E_GL_MDET_RX_FUNCTION_MASK (0xFF << I40E_GL_MDET_RX_FUNCTION_SHIFT) +#define I40E_GL_MDET_RX_FUNCTION_MASK I40E_MASK(0xFF, I40E_GL_MDET_RX_FUNCTION_SHIFT) #define I40E_GL_MDET_RX_EVENT_SHIFT 8 -#define I40E_GL_MDET_RX_EVENT_MASK (0x1FF << I40E_GL_MDET_RX_EVENT_SHIFT) +#define I40E_GL_MDET_RX_EVENT_MASK I40E_MASK(0x1FF, I40E_GL_MDET_RX_EVENT_SHIFT) #define I40E_GL_MDET_RX_QUEUE_SHIFT 17 -#define I40E_GL_MDET_RX_QUEUE_MASK (0x3FFF << I40E_GL_MDET_RX_QUEUE_SHIFT) +#define I40E_GL_MDET_RX_QUEUE_MASK I40E_MASK(0x3FFF, I40E_GL_MDET_RX_QUEUE_SHIFT) #define I40E_GL_MDET_RX_VALID_SHIFT 31 -#define I40E_GL_MDET_RX_VALID_MASK (0x1 << I40E_GL_MDET_RX_VALID_SHIFT) -#define I40E_GL_MDET_TX 0x000E6480 -#define I40E_GL_MDET_TX_FUNCTION_SHIFT 0 -#define I40E_GL_MDET_TX_FUNCTION_MASK (0xFF << I40E_GL_MDET_TX_FUNCTION_SHIFT) -#define I40E_GL_MDET_TX_EVENT_SHIFT 8 -#define I40E_GL_MDET_TX_EVENT_MASK (0x1FF << I40E_GL_MDET_TX_EVENT_SHIFT) -#define I40E_GL_MDET_TX_QUEUE_SHIFT 17 -#define I40E_GL_MDET_TX_QUEUE_MASK (0x3FFF << I40E_GL_MDET_TX_QUEUE_SHIFT) +#define I40E_GL_MDET_RX_VALID_MASK I40E_MASK(0x1, I40E_GL_MDET_RX_VALID_SHIFT) +#define I40E_GL_MDET_TX 0x000E6480 /* Reset: CORER */ +#define I40E_GL_MDET_TX_QUEUE_SHIFT 0 +#define I40E_GL_MDET_TX_QUEUE_MASK I40E_MASK(0xFFF, I40E_GL_MDET_TX_QUEUE_SHIFT) +#define I40E_GL_MDET_TX_VF_NUM_SHIFT 12 +#define I40E_GL_MDET_TX_VF_NUM_MASK I40E_MASK(0x1FF, I40E_GL_MDET_TX_VF_NUM_SHIFT) +#define I40E_GL_MDET_TX_PF_NUM_SHIFT 21 +#define I40E_GL_MDET_TX_PF_NUM_MASK I40E_MASK(0xF, I40E_GL_MDET_TX_PF_NUM_SHIFT) +#define I40E_GL_MDET_TX_EVENT_SHIFT 25 +#define I40E_GL_MDET_TX_EVENT_MASK I40E_MASK(0x1F, I40E_GL_MDET_TX_EVENT_SHIFT) #define I40E_GL_MDET_TX_VALID_SHIFT 31 -#define I40E_GL_MDET_TX_VALID_MASK (0x1 << I40E_GL_MDET_TX_VALID_SHIFT) -#define I40E_PF_MDET_RX 0x0012A400 +#define I40E_GL_MDET_TX_VALID_MASK I40E_MASK(0x1, I40E_GL_MDET_TX_VALID_SHIFT) +#define I40E_PF_MDET_RX 0x0012A400 /* Reset: CORER */ #define I40E_PF_MDET_RX_VALID_SHIFT 0 -#define I40E_PF_MDET_RX_VALID_MASK (0x1 << I40E_PF_MDET_RX_VALID_SHIFT) -#define I40E_PF_MDET_TX 0x000E6400 +#define I40E_PF_MDET_RX_VALID_MASK I40E_MASK(0x1, I40E_PF_MDET_RX_VALID_SHIFT) +#define I40E_PF_MDET_TX 0x000E6400 /* Reset: CORER */ #define I40E_PF_MDET_TX_VALID_SHIFT 0 -#define I40E_PF_MDET_TX_VALID_MASK (0x1 << I40E_PF_MDET_TX_VALID_SHIFT) -#define I40E_PF_VT_PFALLOC 0x001C0500 +#define I40E_PF_MDET_TX_VALID_MASK I40E_MASK(0x1, I40E_PF_MDET_TX_VALID_SHIFT) +#define I40E_PF_VT_PFALLOC 0x001C0500 /* Reset: CORER */ #define I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT 0 -#define I40E_PF_VT_PFALLOC_FIRSTVF_MASK (0xFF << I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT) +#define I40E_PF_VT_PFALLOC_FIRSTVF_MASK I40E_MASK(0xFF, I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT) #define I40E_PF_VT_PFALLOC_LASTVF_SHIFT 8 -#define I40E_PF_VT_PFALLOC_LASTVF_MASK (0xFF << I40E_PF_VT_PFALLOC_LASTVF_SHIFT) +#define I40E_PF_VT_PFALLOC_LASTVF_MASK I40E_MASK(0xFF, I40E_PF_VT_PFALLOC_LASTVF_SHIFT) #define I40E_PF_VT_PFALLOC_VALID_SHIFT 31 -#define I40E_PF_VT_PFALLOC_VALID_MASK (0x1 << I40E_PF_VT_PFALLOC_VALID_SHIFT) -#define I40E_VP_MDET_RX(_VF) (0x0012A000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_PF_VT_PFALLOC_VALID_MASK I40E_MASK(0x1, I40E_PF_VT_PFALLOC_VALID_SHIFT) +#define I40E_VP_MDET_RX(_VF) (0x0012A000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VP_MDET_RX_MAX_INDEX 127 #define I40E_VP_MDET_RX_VALID_SHIFT 0 -#define I40E_VP_MDET_RX_VALID_MASK (0x1 << I40E_VP_MDET_RX_VALID_SHIFT) -#define I40E_VP_MDET_TX(_VF) (0x000E6000 + ((_VF) * 4)) /* _i=0...127 */ +#define I40E_VP_MDET_RX_VALID_MASK I40E_MASK(0x1, I40E_VP_MDET_RX_VALID_SHIFT) +#define I40E_VP_MDET_TX(_VF) (0x000E6000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ #define I40E_VP_MDET_TX_MAX_INDEX 127 #define I40E_VP_MDET_TX_VALID_SHIFT 0 -#define I40E_VP_MDET_TX_VALID_MASK (0x1 << I40E_VP_MDET_TX_VALID_SHIFT) -#define I40E_GLPM_WUMC 0x0006C800 +#define I40E_VP_MDET_TX_VALID_MASK I40E_MASK(0x1, I40E_VP_MDET_TX_VALID_SHIFT) +#define I40E_GLPM_WUMC 0x0006C800 /* Reset: POR */ #define I40E_GLPM_WUMC_NOTCO_SHIFT 0 -#define I40E_GLPM_WUMC_NOTCO_MASK (0x1 << I40E_GLPM_WUMC_NOTCO_SHIFT) +#define I40E_GLPM_WUMC_NOTCO_MASK I40E_MASK(0x1, I40E_GLPM_WUMC_NOTCO_SHIFT) #define I40E_GLPM_WUMC_SRST_PIN_VAL_SHIFT 1 -#define I40E_GLPM_WUMC_SRST_PIN_VAL_MASK (0x1 << I40E_GLPM_WUMC_SRST_PIN_VAL_SHIFT) +#define I40E_GLPM_WUMC_SRST_PIN_VAL_MASK I40E_MASK(0x1, I40E_GLPM_WUMC_SRST_PIN_VAL_SHIFT) #define I40E_GLPM_WUMC_ROL_MODE_SHIFT 2 -#define I40E_GLPM_WUMC_ROL_MODE_MASK (0x1 << I40E_GLPM_WUMC_ROL_MODE_SHIFT) +#define I40E_GLPM_WUMC_ROL_MODE_MASK I40E_MASK(0x1, I40E_GLPM_WUMC_ROL_MODE_SHIFT) #define I40E_GLPM_WUMC_RESERVED_4_SHIFT 3 -#define I40E_GLPM_WUMC_RESERVED_4_MASK (0x1FFF << I40E_GLPM_WUMC_RESERVED_4_SHIFT) +#define I40E_GLPM_WUMC_RESERVED_4_MASK I40E_MASK(0x1FFF, I40E_GLPM_WUMC_RESERVED_4_SHIFT) #define I40E_GLPM_WUMC_MNG_WU_PF_SHIFT 16 -#define I40E_GLPM_WUMC_MNG_WU_PF_MASK (0xFFFF << I40E_GLPM_WUMC_MNG_WU_PF_SHIFT) -#define I40E_PFPM_APM 0x000B8080 +#define I40E_GLPM_WUMC_MNG_WU_PF_MASK I40E_MASK(0xFFFF, I40E_GLPM_WUMC_MNG_WU_PF_SHIFT) +#define I40E_PFPM_APM 0x000B8080 /* Reset: POR */ #define I40E_PFPM_APM_APME_SHIFT 0 -#define I40E_PFPM_APM_APME_MASK (0x1 << I40E_PFPM_APM_APME_SHIFT) -#define I40E_PFPM_FHFT_LENGTH(_i) (0x0006A000 + ((_i) * 128)) /* _i=0...7 */ +#define I40E_PFPM_APM_APME_MASK I40E_MASK(0x1, I40E_PFPM_APM_APME_SHIFT) +#define I40E_PFPM_FHFT_LENGTH(_i) (0x0006A000 + ((_i) * 128)) /* _i=0...7 */ /* Reset: POR */ #define I40E_PFPM_FHFT_LENGTH_MAX_INDEX 7 #define I40E_PFPM_FHFT_LENGTH_LENGTH_SHIFT 0 -#define I40E_PFPM_FHFT_LENGTH_LENGTH_MASK (0xFF << I40E_PFPM_FHFT_LENGTH_LENGTH_SHIFT) -#define I40E_PFPM_WUC 0x0006B200 +#define I40E_PFPM_FHFT_LENGTH_LENGTH_MASK I40E_MASK(0xFF, I40E_PFPM_FHFT_LENGTH_LENGTH_SHIFT) +#define I40E_PFPM_WUC 0x0006B200 /* Reset: POR */ #define I40E_PFPM_WUC_EN_APM_D0_SHIFT 5 -#define I40E_PFPM_WUC_EN_APM_D0_MASK (0x1 << I40E_PFPM_WUC_EN_APM_D0_SHIFT) -#define I40E_PFPM_WUFC 0x0006B400 +#define I40E_PFPM_WUC_EN_APM_D0_MASK I40E_MASK(0x1, I40E_PFPM_WUC_EN_APM_D0_SHIFT) +#define I40E_PFPM_WUFC 0x0006B400 /* Reset: POR */ #define I40E_PFPM_WUFC_LNKC_SHIFT 0 -#define I40E_PFPM_WUFC_LNKC_MASK (0x1 << I40E_PFPM_WUFC_LNKC_SHIFT) +#define I40E_PFPM_WUFC_LNKC_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_LNKC_SHIFT) #define I40E_PFPM_WUFC_MAG_SHIFT 1 -#define I40E_PFPM_WUFC_MAG_MASK (0x1 << I40E_PFPM_WUFC_MAG_SHIFT) +#define I40E_PFPM_WUFC_MAG_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_MAG_SHIFT) #define I40E_PFPM_WUFC_MNG_SHIFT 3 -#define I40E_PFPM_WUFC_MNG_MASK (0x1 << I40E_PFPM_WUFC_MNG_SHIFT) +#define I40E_PFPM_WUFC_MNG_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_MNG_SHIFT) #define I40E_PFPM_WUFC_FLX0_ACT_SHIFT 4 -#define I40E_PFPM_WUFC_FLX0_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX0_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX0_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX0_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX1_ACT_SHIFT 5 -#define I40E_PFPM_WUFC_FLX1_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX1_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX1_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX1_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX2_ACT_SHIFT 6 -#define I40E_PFPM_WUFC_FLX2_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX2_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX2_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX2_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX3_ACT_SHIFT 7 -#define I40E_PFPM_WUFC_FLX3_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX3_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX3_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX3_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX4_ACT_SHIFT 8 -#define I40E_PFPM_WUFC_FLX4_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX4_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX4_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX4_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX5_ACT_SHIFT 9 -#define I40E_PFPM_WUFC_FLX5_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX5_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX5_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX5_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX6_ACT_SHIFT 10 -#define I40E_PFPM_WUFC_FLX6_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX6_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX6_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX6_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX7_ACT_SHIFT 11 -#define I40E_PFPM_WUFC_FLX7_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX7_ACT_SHIFT) +#define I40E_PFPM_WUFC_FLX7_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX7_ACT_SHIFT) #define I40E_PFPM_WUFC_FLX0_SHIFT 16 -#define I40E_PFPM_WUFC_FLX0_MASK (0x1 << I40E_PFPM_WUFC_FLX0_SHIFT) +#define I40E_PFPM_WUFC_FLX0_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX0_SHIFT) #define I40E_PFPM_WUFC_FLX1_SHIFT 17 -#define I40E_PFPM_WUFC_FLX1_MASK (0x1 << I40E_PFPM_WUFC_FLX1_SHIFT) +#define I40E_PFPM_WUFC_FLX1_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX1_SHIFT) #define I40E_PFPM_WUFC_FLX2_SHIFT 18 -#define I40E_PFPM_WUFC_FLX2_MASK (0x1 << I40E_PFPM_WUFC_FLX2_SHIFT) +#define I40E_PFPM_WUFC_FLX2_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX2_SHIFT) #define I40E_PFPM_WUFC_FLX3_SHIFT 19 -#define I40E_PFPM_WUFC_FLX3_MASK (0x1 << I40E_PFPM_WUFC_FLX3_SHIFT) +#define I40E_PFPM_WUFC_FLX3_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX3_SHIFT) #define I40E_PFPM_WUFC_FLX4_SHIFT 20 -#define I40E_PFPM_WUFC_FLX4_MASK (0x1 << I40E_PFPM_WUFC_FLX4_SHIFT) +#define I40E_PFPM_WUFC_FLX4_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX4_SHIFT) #define I40E_PFPM_WUFC_FLX5_SHIFT 21 -#define I40E_PFPM_WUFC_FLX5_MASK (0x1 << I40E_PFPM_WUFC_FLX5_SHIFT) +#define I40E_PFPM_WUFC_FLX5_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX5_SHIFT) #define I40E_PFPM_WUFC_FLX6_SHIFT 22 -#define I40E_PFPM_WUFC_FLX6_MASK (0x1 << I40E_PFPM_WUFC_FLX6_SHIFT) +#define I40E_PFPM_WUFC_FLX6_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX6_SHIFT) #define I40E_PFPM_WUFC_FLX7_SHIFT 23 -#define I40E_PFPM_WUFC_FLX7_MASK (0x1 << I40E_PFPM_WUFC_FLX7_SHIFT) +#define I40E_PFPM_WUFC_FLX7_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX7_SHIFT) #define I40E_PFPM_WUFC_FW_RST_WK_SHIFT 31 -#define I40E_PFPM_WUFC_FW_RST_WK_MASK (0x1 << I40E_PFPM_WUFC_FW_RST_WK_SHIFT) -#define I40E_PFPM_WUS 0x0006B600 +#define I40E_PFPM_WUFC_FW_RST_WK_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FW_RST_WK_SHIFT) +#define I40E_PFPM_WUS 0x0006B600 /* Reset: POR */ #define I40E_PFPM_WUS_LNKC_SHIFT 0 -#define I40E_PFPM_WUS_LNKC_MASK (0x1 << I40E_PFPM_WUS_LNKC_SHIFT) +#define I40E_PFPM_WUS_LNKC_MASK I40E_MASK(0x1, I40E_PFPM_WUS_LNKC_SHIFT) #define I40E_PFPM_WUS_MAG_SHIFT 1 -#define I40E_PFPM_WUS_MAG_MASK (0x1 << I40E_PFPM_WUS_MAG_SHIFT) +#define I40E_PFPM_WUS_MAG_MASK I40E_MASK(0x1, I40E_PFPM_WUS_MAG_SHIFT) #define I40E_PFPM_WUS_PME_STATUS_SHIFT 2 -#define I40E_PFPM_WUS_PME_STATUS_MASK (0x1 << I40E_PFPM_WUS_PME_STATUS_SHIFT) +#define I40E_PFPM_WUS_PME_STATUS_MASK I40E_MASK(0x1, I40E_PFPM_WUS_PME_STATUS_SHIFT) #define I40E_PFPM_WUS_MNG_SHIFT 3 -#define I40E_PFPM_WUS_MNG_MASK (0x1 << I40E_PFPM_WUS_MNG_SHIFT) +#define I40E_PFPM_WUS_MNG_MASK I40E_MASK(0x1, I40E_PFPM_WUS_MNG_SHIFT) #define I40E_PFPM_WUS_FLX0_SHIFT 16 -#define I40E_PFPM_WUS_FLX0_MASK (0x1 << I40E_PFPM_WUS_FLX0_SHIFT) +#define I40E_PFPM_WUS_FLX0_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX0_SHIFT) #define I40E_PFPM_WUS_FLX1_SHIFT 17 -#define I40E_PFPM_WUS_FLX1_MASK (0x1 << I40E_PFPM_WUS_FLX1_SHIFT) +#define I40E_PFPM_WUS_FLX1_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX1_SHIFT) #define I40E_PFPM_WUS_FLX2_SHIFT 18 -#define I40E_PFPM_WUS_FLX2_MASK (0x1 << I40E_PFPM_WUS_FLX2_SHIFT) +#define I40E_PFPM_WUS_FLX2_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX2_SHIFT) #define I40E_PFPM_WUS_FLX3_SHIFT 19 -#define I40E_PFPM_WUS_FLX3_MASK (0x1 << I40E_PFPM_WUS_FLX3_SHIFT) +#define I40E_PFPM_WUS_FLX3_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX3_SHIFT) #define I40E_PFPM_WUS_FLX4_SHIFT 20 -#define I40E_PFPM_WUS_FLX4_MASK (0x1 << I40E_PFPM_WUS_FLX4_SHIFT) +#define I40E_PFPM_WUS_FLX4_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX4_SHIFT) #define I40E_PFPM_WUS_FLX5_SHIFT 21 -#define I40E_PFPM_WUS_FLX5_MASK (0x1 << I40E_PFPM_WUS_FLX5_SHIFT) +#define I40E_PFPM_WUS_FLX5_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX5_SHIFT) #define I40E_PFPM_WUS_FLX6_SHIFT 22 -#define I40E_PFPM_WUS_FLX6_MASK (0x1 << I40E_PFPM_WUS_FLX6_SHIFT) +#define I40E_PFPM_WUS_FLX6_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX6_SHIFT) #define I40E_PFPM_WUS_FLX7_SHIFT 23 -#define I40E_PFPM_WUS_FLX7_MASK (0x1 << I40E_PFPM_WUS_FLX7_SHIFT) +#define I40E_PFPM_WUS_FLX7_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX7_SHIFT) #define I40E_PFPM_WUS_FW_RST_WK_SHIFT 31 -#define I40E_PFPM_WUS_FW_RST_WK_MASK (0x1 << I40E_PFPM_WUS_FW_RST_WK_SHIFT) -#define I40E_PRTPM_FHFHR 0x0006C000 +#define I40E_PFPM_WUS_FW_RST_WK_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FW_RST_WK_SHIFT) +#define I40E_PRTPM_FHFHR 0x0006C000 /* Reset: POR */ #define I40E_PRTPM_FHFHR_UNICAST_SHIFT 0 -#define I40E_PRTPM_FHFHR_UNICAST_MASK (0x1 << I40E_PRTPM_FHFHR_UNICAST_SHIFT) +#define I40E_PRTPM_FHFHR_UNICAST_MASK I40E_MASK(0x1, I40E_PRTPM_FHFHR_UNICAST_SHIFT) #define I40E_PRTPM_FHFHR_MULTICAST_SHIFT 1 -#define I40E_PRTPM_FHFHR_MULTICAST_MASK (0x1 << I40E_PRTPM_FHFHR_MULTICAST_SHIFT) -#define I40E_PRTPM_SAH(_i) (0x001E44C0 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRTPM_FHFHR_MULTICAST_MASK I40E_MASK(0x1, I40E_PRTPM_FHFHR_MULTICAST_SHIFT) +#define I40E_PRTPM_SAH(_i) (0x001E44C0 + ((_i) * 32)) /* _i=0...3 */ /* Reset: PFR */ #define I40E_PRTPM_SAH_MAX_INDEX 3 #define I40E_PRTPM_SAH_PFPM_SAH_SHIFT 0 -#define I40E_PRTPM_SAH_PFPM_SAH_MASK (0xFFFF << I40E_PRTPM_SAH_PFPM_SAH_SHIFT) +#define I40E_PRTPM_SAH_PFPM_SAH_MASK I40E_MASK(0xFFFF, I40E_PRTPM_SAH_PFPM_SAH_SHIFT) #define I40E_PRTPM_SAH_PF_NUM_SHIFT 26 -#define I40E_PRTPM_SAH_PF_NUM_MASK (0xF << I40E_PRTPM_SAH_PF_NUM_SHIFT) +#define I40E_PRTPM_SAH_PF_NUM_MASK I40E_MASK(0xF, I40E_PRTPM_SAH_PF_NUM_SHIFT) #define I40E_PRTPM_SAH_MC_MAG_EN_SHIFT 30 -#define I40E_PRTPM_SAH_MC_MAG_EN_MASK (0x1 << I40E_PRTPM_SAH_MC_MAG_EN_SHIFT) +#define I40E_PRTPM_SAH_MC_MAG_EN_MASK I40E_MASK(0x1, I40E_PRTPM_SAH_MC_MAG_EN_SHIFT) #define I40E_PRTPM_SAH_AV_SHIFT 31 -#define I40E_PRTPM_SAH_AV_MASK (0x1 << I40E_PRTPM_SAH_AV_SHIFT) -#define I40E_PRTPM_SAL(_i) (0x001E4440 + ((_i) * 32)) /* _i=0...3 */ +#define I40E_PRTPM_SAH_AV_MASK I40E_MASK(0x1, I40E_PRTPM_SAH_AV_SHIFT) +#define I40E_PRTPM_SAL(_i) (0x001E4440 + ((_i) * 32)) /* _i=0...3 */ /* Reset: PFR */ #define I40E_PRTPM_SAL_MAX_INDEX 3 #define I40E_PRTPM_SAL_PFPM_SAL_SHIFT 0 -#define I40E_PRTPM_SAL_PFPM_SAL_MASK (0xFFFFFFFF << I40E_PRTPM_SAL_PFPM_SAL_SHIFT) -#define I40E_VF_ARQBAH1 0x00006000 +#define I40E_PRTPM_SAL_PFPM_SAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTPM_SAL_PFPM_SAL_SHIFT) +#define I40E_VF_ARQBAH1 0x00006000 /* Reset: EMPR */ #define I40E_VF_ARQBAH1_ARQBAH_SHIFT 0 -#define I40E_VF_ARQBAH1_ARQBAH_MASK (0xFFFFFFFF << I40E_VF_ARQBAH1_ARQBAH_SHIFT) -#define I40E_VF_ARQBAL1 0x00006C00 +#define I40E_VF_ARQBAH1_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAH1_ARQBAH_SHIFT) +#define I40E_VF_ARQBAL1 0x00006C00 /* Reset: EMPR */ #define I40E_VF_ARQBAL1_ARQBAL_SHIFT 0 -#define I40E_VF_ARQBAL1_ARQBAL_MASK (0xFFFFFFFF << I40E_VF_ARQBAL1_ARQBAL_SHIFT) -#define I40E_VF_ARQH1 0x00007400 +#define I40E_VF_ARQBAL1_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAL1_ARQBAL_SHIFT) +#define I40E_VF_ARQH1 0x00007400 /* Reset: EMPR */ #define I40E_VF_ARQH1_ARQH_SHIFT 0 -#define I40E_VF_ARQH1_ARQH_MASK (0x3FF << I40E_VF_ARQH1_ARQH_SHIFT) -#define I40E_VF_ARQLEN1 0x00008000 +#define I40E_VF_ARQH1_ARQH_MASK I40E_MASK(0x3FF, I40E_VF_ARQH1_ARQH_SHIFT) +#define I40E_VF_ARQLEN1 0x00008000 /* Reset: EMPR */ #define I40E_VF_ARQLEN1_ARQLEN_SHIFT 0 -#define I40E_VF_ARQLEN1_ARQLEN_MASK (0x3FF << I40E_VF_ARQLEN1_ARQLEN_SHIFT) +#define I40E_VF_ARQLEN1_ARQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ARQLEN1_ARQLEN_SHIFT) #define I40E_VF_ARQLEN1_ARQVFE_SHIFT 28 -#define I40E_VF_ARQLEN1_ARQVFE_MASK (0x1 << I40E_VF_ARQLEN1_ARQVFE_SHIFT) +#define I40E_VF_ARQLEN1_ARQVFE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQVFE_SHIFT) #define I40E_VF_ARQLEN1_ARQOVFL_SHIFT 29 -#define I40E_VF_ARQLEN1_ARQOVFL_MASK (0x1 << I40E_VF_ARQLEN1_ARQOVFL_SHIFT) +#define I40E_VF_ARQLEN1_ARQOVFL_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQOVFL_SHIFT) #define I40E_VF_ARQLEN1_ARQCRIT_SHIFT 30 -#define I40E_VF_ARQLEN1_ARQCRIT_MASK (0x1 << I40E_VF_ARQLEN1_ARQCRIT_SHIFT) +#define I40E_VF_ARQLEN1_ARQCRIT_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQCRIT_SHIFT) #define I40E_VF_ARQLEN1_ARQENABLE_SHIFT 31 -#define I40E_VF_ARQLEN1_ARQENABLE_MASK (0x1 << I40E_VF_ARQLEN1_ARQENABLE_SHIFT) -#define I40E_VF_ARQT1 0x00007000 +#define I40E_VF_ARQLEN1_ARQENABLE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN1_ARQENABLE_SHIFT) +#define I40E_VF_ARQT1 0x00007000 /* Reset: EMPR */ #define I40E_VF_ARQT1_ARQT_SHIFT 0 -#define I40E_VF_ARQT1_ARQT_MASK (0x3FF << I40E_VF_ARQT1_ARQT_SHIFT) -#define I40E_VF_ATQBAH1 0x00007800 +#define I40E_VF_ARQT1_ARQT_MASK I40E_MASK(0x3FF, I40E_VF_ARQT1_ARQT_SHIFT) +#define I40E_VF_ATQBAH1 0x00007800 /* Reset: EMPR */ #define I40E_VF_ATQBAH1_ATQBAH_SHIFT 0 -#define I40E_VF_ATQBAH1_ATQBAH_MASK (0xFFFFFFFF << I40E_VF_ATQBAH1_ATQBAH_SHIFT) -#define I40E_VF_ATQBAL1 0x00007C00 +#define I40E_VF_ATQBAH1_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAH1_ATQBAH_SHIFT) +#define I40E_VF_ATQBAL1 0x00007C00 /* Reset: EMPR */ #define I40E_VF_ATQBAL1_ATQBAL_SHIFT 0 -#define I40E_VF_ATQBAL1_ATQBAL_MASK (0xFFFFFFFF << I40E_VF_ATQBAL1_ATQBAL_SHIFT) -#define I40E_VF_ATQH1 0x00006400 +#define I40E_VF_ATQBAL1_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAL1_ATQBAL_SHIFT) +#define I40E_VF_ATQH1 0x00006400 /* Reset: EMPR */ #define I40E_VF_ATQH1_ATQH_SHIFT 0 -#define I40E_VF_ATQH1_ATQH_MASK (0x3FF << I40E_VF_ATQH1_ATQH_SHIFT) -#define I40E_VF_ATQLEN1 0x00006800 +#define I40E_VF_ATQH1_ATQH_MASK I40E_MASK(0x3FF, I40E_VF_ATQH1_ATQH_SHIFT) +#define I40E_VF_ATQLEN1 0x00006800 /* Reset: EMPR */ #define I40E_VF_ATQLEN1_ATQLEN_SHIFT 0 -#define I40E_VF_ATQLEN1_ATQLEN_MASK (0x3FF << I40E_VF_ATQLEN1_ATQLEN_SHIFT) +#define I40E_VF_ATQLEN1_ATQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ATQLEN1_ATQLEN_SHIFT) #define I40E_VF_ATQLEN1_ATQVFE_SHIFT 28 -#define I40E_VF_ATQLEN1_ATQVFE_MASK (0x1 << I40E_VF_ATQLEN1_ATQVFE_SHIFT) +#define I40E_VF_ATQLEN1_ATQVFE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQVFE_SHIFT) #define I40E_VF_ATQLEN1_ATQOVFL_SHIFT 29 -#define I40E_VF_ATQLEN1_ATQOVFL_MASK (0x1 << I40E_VF_ATQLEN1_ATQOVFL_SHIFT) +#define I40E_VF_ATQLEN1_ATQOVFL_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQOVFL_SHIFT) #define I40E_VF_ATQLEN1_ATQCRIT_SHIFT 30 -#define I40E_VF_ATQLEN1_ATQCRIT_MASK (0x1 << I40E_VF_ATQLEN1_ATQCRIT_SHIFT) +#define I40E_VF_ATQLEN1_ATQCRIT_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQCRIT_SHIFT) #define I40E_VF_ATQLEN1_ATQENABLE_SHIFT 31 -#define I40E_VF_ATQLEN1_ATQENABLE_MASK (0x1 << I40E_VF_ATQLEN1_ATQENABLE_SHIFT) -#define I40E_VF_ATQT1 0x00008400 +#define I40E_VF_ATQLEN1_ATQENABLE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN1_ATQENABLE_SHIFT) +#define I40E_VF_ATQT1 0x00008400 /* Reset: EMPR */ #define I40E_VF_ATQT1_ATQT_SHIFT 0 -#define I40E_VF_ATQT1_ATQT_MASK (0x3FF << I40E_VF_ATQT1_ATQT_SHIFT) -#define I40E_VFGEN_RSTAT 0x00008800 +#define I40E_VF_ATQT1_ATQT_MASK I40E_MASK(0x3FF, I40E_VF_ATQT1_ATQT_SHIFT) +#define I40E_VFGEN_RSTAT 0x00008800 /* Reset: VFR */ #define I40E_VFGEN_RSTAT_VFR_STATE_SHIFT 0 -#define I40E_VFGEN_RSTAT_VFR_STATE_MASK (0x3 << I40E_VFGEN_RSTAT_VFR_STATE_SHIFT) -#define I40E_VFINT_DYN_CTL01 0x00005C00 +#define I40E_VFGEN_RSTAT_VFR_STATE_MASK I40E_MASK(0x3, I40E_VFGEN_RSTAT_VFR_STATE_SHIFT) +#define I40E_VFINT_DYN_CTL01 0x00005C00 /* Reset: VFR */ #define I40E_VFINT_DYN_CTL01_INTENA_SHIFT 0 -#define I40E_VFINT_DYN_CTL01_INTENA_MASK (0x1 << I40E_VFINT_DYN_CTL01_INTENA_SHIFT) +#define I40E_VFINT_DYN_CTL01_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_INTENA_SHIFT) #define I40E_VFINT_DYN_CTL01_CLEARPBA_SHIFT 1 -#define I40E_VFINT_DYN_CTL01_CLEARPBA_MASK (0x1 << I40E_VFINT_DYN_CTL01_CLEARPBA_SHIFT) +#define I40E_VFINT_DYN_CTL01_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_CLEARPBA_SHIFT) #define I40E_VFINT_DYN_CTL01_SWINT_TRIG_SHIFT 2 -#define I40E_VFINT_DYN_CTL01_SWINT_TRIG_MASK (0x1 << I40E_VFINT_DYN_CTL01_SWINT_TRIG_SHIFT) +#define I40E_VFINT_DYN_CTL01_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_SWINT_TRIG_SHIFT) #define I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT 3 -#define I40E_VFINT_DYN_CTL01_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTL01_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTL01_INTERVAL_MASK (0xFFF << I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT) +#define I40E_VFINT_DYN_CTL01_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT) #define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_MASK (0x1 << I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_SHIFT) +#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_SHIFT) #define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_SHIFT 25 -#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTL01_SW_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL01_SW_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTL01_INTENA_MSK_SHIFT 31 -#define I40E_VFINT_DYN_CTL01_INTENA_MSK_MASK (0x1 << I40E_VFINT_DYN_CTL01_INTENA_MSK_SHIFT) -#define I40E_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) +#define I40E_VFINT_DYN_CTL01_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_INTENA_MSK_SHIFT) +#define I40E_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...15 */ /* Reset: VFR */ #define I40E_VFINT_DYN_CTLN1_MAX_INDEX 15 #define I40E_VFINT_DYN_CTLN1_INTENA_SHIFT 0 -#define I40E_VFINT_DYN_CTLN1_INTENA_MASK (0x1 << I40E_VFINT_DYN_CTLN1_INTENA_SHIFT) +#define I40E_VFINT_DYN_CTLN1_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_INTENA_SHIFT) #define I40E_VFINT_DYN_CTLN1_CLEARPBA_SHIFT 1 -#define I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK (0x1 << I40E_VFINT_DYN_CTLN1_CLEARPBA_SHIFT) +#define I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_CLEARPBA_SHIFT) #define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT 2 -#define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK (0x1 << I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT) +#define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT) #define I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT 3 -#define I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTLN1_INTERVAL_MASK (0xFFF << I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT) +#define I40E_VFINT_DYN_CTLN1_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT) #define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK (0x1 << I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT) +#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT) #define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_SHIFT 25 -#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_SHIFT) +#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_SHIFT) #define I40E_VFINT_DYN_CTLN1_INTENA_MSK_SHIFT 31 -#define I40E_VFINT_DYN_CTLN1_INTENA_MSK_MASK (0x1 << I40E_VFINT_DYN_CTLN1_INTENA_MSK_SHIFT) -#define I40E_VFINT_ICR0_ENA1 0x00005000 +#define I40E_VFINT_DYN_CTLN1_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_INTENA_MSK_SHIFT) +#define I40E_VFINT_ICR0_ENA1 0x00005000 /* Reset: CORER */ #define I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_MASK (0x1 << I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_SHIFT) +#define I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_SHIFT) #define I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT 30 -#define I40E_VFINT_ICR0_ENA1_ADMINQ_MASK (0x1 << I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT) +#define I40E_VFINT_ICR0_ENA1_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT) #define I40E_VFINT_ICR0_ENA1_RSVD_SHIFT 31 -#define I40E_VFINT_ICR0_ENA1_RSVD_MASK (0x1 << I40E_VFINT_ICR0_ENA1_RSVD_SHIFT) -#define I40E_VFINT_ICR01 0x00004800 +#define I40E_VFINT_ICR0_ENA1_RSVD_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA1_RSVD_SHIFT) +#define I40E_VFINT_ICR01 0x00004800 /* Reset: CORER */ #define I40E_VFINT_ICR01_INTEVENT_SHIFT 0 -#define I40E_VFINT_ICR01_INTEVENT_MASK (0x1 << I40E_VFINT_ICR01_INTEVENT_SHIFT) +#define I40E_VFINT_ICR01_INTEVENT_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_INTEVENT_SHIFT) #define I40E_VFINT_ICR01_QUEUE_0_SHIFT 1 -#define I40E_VFINT_ICR01_QUEUE_0_MASK (0x1 << I40E_VFINT_ICR01_QUEUE_0_SHIFT) +#define I40E_VFINT_ICR01_QUEUE_0_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_0_SHIFT) #define I40E_VFINT_ICR01_QUEUE_1_SHIFT 2 -#define I40E_VFINT_ICR01_QUEUE_1_MASK (0x1 << I40E_VFINT_ICR01_QUEUE_1_SHIFT) +#define I40E_VFINT_ICR01_QUEUE_1_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_1_SHIFT) #define I40E_VFINT_ICR01_QUEUE_2_SHIFT 3 -#define I40E_VFINT_ICR01_QUEUE_2_MASK (0x1 << I40E_VFINT_ICR01_QUEUE_2_SHIFT) +#define I40E_VFINT_ICR01_QUEUE_2_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_2_SHIFT) #define I40E_VFINT_ICR01_QUEUE_3_SHIFT 4 -#define I40E_VFINT_ICR01_QUEUE_3_MASK (0x1 << I40E_VFINT_ICR01_QUEUE_3_SHIFT) +#define I40E_VFINT_ICR01_QUEUE_3_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_QUEUE_3_SHIFT) #define I40E_VFINT_ICR01_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_VFINT_ICR01_LINK_STAT_CHANGE_MASK (0x1 << I40E_VFINT_ICR01_LINK_STAT_CHANGE_SHIFT) +#define I40E_VFINT_ICR01_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_LINK_STAT_CHANGE_SHIFT) #define I40E_VFINT_ICR01_ADMINQ_SHIFT 30 -#define I40E_VFINT_ICR01_ADMINQ_MASK (0x1 << I40E_VFINT_ICR01_ADMINQ_SHIFT) +#define I40E_VFINT_ICR01_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_ADMINQ_SHIFT) #define I40E_VFINT_ICR01_SWINT_SHIFT 31 -#define I40E_VFINT_ICR01_SWINT_MASK (0x1 << I40E_VFINT_ICR01_SWINT_SHIFT) -#define I40E_VFINT_ITR01(_i) (0x00004C00 + ((_i) * 4)) /* _i=0...2 */ +#define I40E_VFINT_ICR01_SWINT_MASK I40E_MASK(0x1, I40E_VFINT_ICR01_SWINT_SHIFT) +#define I40E_VFINT_ITR01(_i) (0x00004C00 + ((_i) * 4)) /* _i=0...2 */ /* Reset: VFR */ #define I40E_VFINT_ITR01_MAX_INDEX 2 #define I40E_VFINT_ITR01_INTERVAL_SHIFT 0 -#define I40E_VFINT_ITR01_INTERVAL_MASK (0xFFF << I40E_VFINT_ITR01_INTERVAL_SHIFT) -#define I40E_VFINT_ITRN1(_i, _INTVF) (0x00002800 + ((_i) * 64 + (_INTVF) * 4)) +#define I40E_VFINT_ITR01_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITR01_INTERVAL_SHIFT) +#define I40E_VFINT_ITRN1(_i, _INTVF) (0x00002800 + ((_i) * 64 + (_INTVF) * 4)) /* _i=0...2, _INTVF=0...15 */ /* Reset: VFR */ #define I40E_VFINT_ITRN1_MAX_INDEX 2 #define I40E_VFINT_ITRN1_INTERVAL_SHIFT 0 -#define I40E_VFINT_ITRN1_INTERVAL_MASK (0xFFF << I40E_VFINT_ITRN1_INTERVAL_SHIFT) -#define I40E_VFINT_STAT_CTL01 0x00005400 +#define I40E_VFINT_ITRN1_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITRN1_INTERVAL_SHIFT) +#define I40E_VFINT_STAT_CTL01 0x00005400 /* Reset: VFR */ #define I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_SHIFT 2 -#define I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_MASK (0x3 << I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_SHIFT) -#define I40E_QRX_TAIL1(_Q) (0x00002000 + ((_Q) * 4)) /* _i=0...15 */ +#define I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_SHIFT) +#define I40E_QRX_TAIL1(_Q) (0x00002000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_QRX_TAIL1_MAX_INDEX 15 #define I40E_QRX_TAIL1_TAIL_SHIFT 0 -#define I40E_QRX_TAIL1_TAIL_MASK (0x1FFF << I40E_QRX_TAIL1_TAIL_SHIFT) -#define I40E_QTX_TAIL1(_Q) (0x00000000 + ((_Q) * 4)) /* _i=0...15 */ +#define I40E_QRX_TAIL1_TAIL_MASK I40E_MASK(0x1FFF, I40E_QRX_TAIL1_TAIL_SHIFT) +#define I40E_QTX_TAIL1(_Q) (0x00000000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: PFR */ #define I40E_QTX_TAIL1_MAX_INDEX 15 #define I40E_QTX_TAIL1_TAIL_SHIFT 0 -#define I40E_QTX_TAIL1_TAIL_MASK (0x1FFF << I40E_QTX_TAIL1_TAIL_SHIFT) -#define I40E_VFMSIX_PBA 0x00002000 +#define I40E_QTX_TAIL1_TAIL_MASK I40E_MASK(0x1FFF, I40E_QTX_TAIL1_TAIL_SHIFT) +#define I40E_VFMSIX_PBA 0x00002000 /* Reset: VFLR */ #define I40E_VFMSIX_PBA_PENBIT_SHIFT 0 -#define I40E_VFMSIX_PBA_PENBIT_MASK (0xFFFFFFFF << I40E_VFMSIX_PBA_PENBIT_SHIFT) -#define I40E_VFMSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...16 */ +#define I40E_VFMSIX_PBA_PENBIT_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_PBA_PENBIT_SHIFT) +#define I40E_VFMSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */ #define I40E_VFMSIX_TADD_MAX_INDEX 16 #define I40E_VFMSIX_TADD_MSIXTADD10_SHIFT 0 -#define I40E_VFMSIX_TADD_MSIXTADD10_MASK (0x3 << I40E_VFMSIX_TADD_MSIXTADD10_SHIFT) +#define I40E_VFMSIX_TADD_MSIXTADD10_MASK I40E_MASK(0x3, I40E_VFMSIX_TADD_MSIXTADD10_SHIFT) #define I40E_VFMSIX_TADD_MSIXTADD_SHIFT 2 -#define I40E_VFMSIX_TADD_MSIXTADD_MASK (0x3FFFFFFF << I40E_VFMSIX_TADD_MSIXTADD_SHIFT) -#define I40E_VFMSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...16 */ +#define I40E_VFMSIX_TADD_MSIXTADD_MASK I40E_MASK(0x3FFFFFFF, I40E_VFMSIX_TADD_MSIXTADD_SHIFT) +#define I40E_VFMSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */ #define I40E_VFMSIX_TMSG_MAX_INDEX 16 #define I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT 0 -#define I40E_VFMSIX_TMSG_MSIXTMSG_MASK (0xFFFFFFFF << I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT) -#define I40E_VFMSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...16 */ +#define I40E_VFMSIX_TMSG_MSIXTMSG_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT) +#define I40E_VFMSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */ #define I40E_VFMSIX_TUADD_MAX_INDEX 16 #define I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT 0 -#define I40E_VFMSIX_TUADD_MSIXTUADD_MASK (0xFFFFFFFF << I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT) -#define I40E_VFMSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...16 */ +#define I40E_VFMSIX_TUADD_MSIXTUADD_MASK I40E_MASK(0xFFFFFFFF, I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT) +#define I40E_VFMSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...16 */ /* Reset: VFLR */ #define I40E_VFMSIX_TVCTRL_MAX_INDEX 16 #define I40E_VFMSIX_TVCTRL_MASK_SHIFT 0 -#define I40E_VFMSIX_TVCTRL_MASK_MASK (0x1 << I40E_VFMSIX_TVCTRL_MASK_SHIFT) -#define I40E_VFCM_PE_ERRDATA 0x0000DC00 +#define I40E_VFMSIX_TVCTRL_MASK_MASK I40E_MASK(0x1, I40E_VFMSIX_TVCTRL_MASK_SHIFT) +#define I40E_VFCM_PE_ERRDATA 0x0000DC00 /* Reset: VFR */ #define I40E_VFCM_PE_ERRDATA_ERROR_CODE_SHIFT 0 -#define I40E_VFCM_PE_ERRDATA_ERROR_CODE_MASK (0xF << I40E_VFCM_PE_ERRDATA_ERROR_CODE_SHIFT) +#define I40E_VFCM_PE_ERRDATA_ERROR_CODE_MASK I40E_MASK(0xF, I40E_VFCM_PE_ERRDATA_ERROR_CODE_SHIFT) #define I40E_VFCM_PE_ERRDATA_Q_TYPE_SHIFT 4 -#define I40E_VFCM_PE_ERRDATA_Q_TYPE_MASK (0x7 << I40E_VFCM_PE_ERRDATA_Q_TYPE_SHIFT) +#define I40E_VFCM_PE_ERRDATA_Q_TYPE_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRDATA_Q_TYPE_SHIFT) #define I40E_VFCM_PE_ERRDATA_Q_NUM_SHIFT 8 -#define I40E_VFCM_PE_ERRDATA_Q_NUM_MASK (0x3FFFF << I40E_VFCM_PE_ERRDATA_Q_NUM_SHIFT) -#define I40E_VFCM_PE_ERRINFO 0x0000D800 +#define I40E_VFCM_PE_ERRDATA_Q_NUM_MASK I40E_MASK(0x3FFFF, I40E_VFCM_PE_ERRDATA_Q_NUM_SHIFT) +#define I40E_VFCM_PE_ERRINFO 0x0000D800 /* Reset: VFR */ #define I40E_VFCM_PE_ERRINFO_ERROR_VALID_SHIFT 0 -#define I40E_VFCM_PE_ERRINFO_ERROR_VALID_MASK (0x1 << I40E_VFCM_PE_ERRINFO_ERROR_VALID_SHIFT) +#define I40E_VFCM_PE_ERRINFO_ERROR_VALID_MASK I40E_MASK(0x1, I40E_VFCM_PE_ERRINFO_ERROR_VALID_SHIFT) #define I40E_VFCM_PE_ERRINFO_ERROR_INST_SHIFT 4 -#define I40E_VFCM_PE_ERRINFO_ERROR_INST_MASK (0x7 << I40E_VFCM_PE_ERRINFO_ERROR_INST_SHIFT) +#define I40E_VFCM_PE_ERRINFO_ERROR_INST_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRINFO_ERROR_INST_SHIFT) #define I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT 8 -#define I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT) +#define I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT) #define I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT 16 -#define I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT) +#define I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT) #define I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT 24 -#define I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT) -#define I40E_VFPE_AEQALLOC1 0x0000A400 -#define I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT 0 -#define I40E_VFPE_AEQALLOC1_AECOUNT_MASK (0xFFFFFFFF << I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT) -#define I40E_VFPE_CCQPHIGH1 0x00009800 -#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT 0 -#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_MASK (0xFFFFFFFF << I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT) -#define I40E_VFPE_CCQPLOW1 0x0000AC00 -#define I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT 0 -#define I40E_VFPE_CCQPLOW1_PECCQPLOW_MASK (0xFFFFFFFF << I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT) -#define I40E_VFPE_CCQPSTATUS1 0x0000B800 -#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT 0 -#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_MASK (0x1 << I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT) -#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT 31 -#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_MASK (0x1 << I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT) -#define I40E_VFPE_CQACK1 0x0000B000 -#define I40E_VFPE_CQACK1_PECQID_SHIFT 0 -#define I40E_VFPE_CQACK1_PECQID_MASK (0x1FFFF << I40E_VFPE_CQACK1_PECQID_SHIFT) -#define I40E_VFPE_CQARM1 0x0000B400 -#define I40E_VFPE_CQARM1_PECQID_SHIFT 0 -#define I40E_VFPE_CQARM1_PECQID_MASK (0x1FFFF << I40E_VFPE_CQARM1_PECQID_SHIFT) -#define I40E_VFPE_CQPDB1 0x0000BC00 -#define I40E_VFPE_CQPDB1_WQHEAD_SHIFT 0 -#define I40E_VFPE_CQPDB1_WQHEAD_MASK (0x7FF << I40E_VFPE_CQPDB1_WQHEAD_SHIFT) -#define I40E_VFPE_CQPERRCODES1 0x00009C00 -#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT 0 -#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT) -#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT 16 -#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT) -#define I40E_VFPE_CQPTAIL1 0x0000A000 -#define I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT 0 -#define I40E_VFPE_CQPTAIL1_WQTAIL_MASK (0x7FF << I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT) -#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT 31 -#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_MASK (0x1 << I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT) -#define I40E_VFPE_IPCONFIG01 0x00008C00 -#define I40E_VFPE_IPCONFIG01_PEIPID_SHIFT 0 -#define I40E_VFPE_IPCONFIG01_PEIPID_MASK (0xFFFF << I40E_VFPE_IPCONFIG01_PEIPID_SHIFT) -#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT 16 -#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT) -#define I40E_VFPE_MRTEIDXMASK1 0x00009000 -#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT 0 -#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_MASK (0x1F << I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT) -#define I40E_VFPE_RCVUNEXPECTEDERROR1 0x00009400 -#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT 0 -#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_MASK (0xFFFFFF << I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT) -#define I40E_VFPE_TCPNOWTIMER1 0x0000A800 -#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT 0 -#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_MASK (0xFFFFFFFF << I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT) -#define I40E_VFPE_WQEALLOC1 0x0000C000 -#define I40E_VFPE_WQEALLOC1_PEQPID_SHIFT 0 -#define I40E_VFPE_WQEALLOC1_PEQPID_MASK (0x3FFFF << I40E_VFPE_WQEALLOC1_PEQPID_SHIFT) -#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT 20 -#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_MASK (0xFFF << I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT) -#define I40E_VFQF_HENA(_i) (0x0000C400 + ((_i) * 4)) /* _i=0...1 */ +#define I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT) +#define I40E_VFQF_HENA(_i) (0x0000C400 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */ #define I40E_VFQF_HENA_MAX_INDEX 1 #define I40E_VFQF_HENA_PTYPE_ENA_SHIFT 0 -#define I40E_VFQF_HENA_PTYPE_ENA_MASK (0xFFFFFFFF << I40E_VFQF_HENA_PTYPE_ENA_SHIFT) -#define I40E_VFQF_HKEY(_i) (0x0000CC00 + ((_i) * 4)) /* _i=0...12 */ +#define I40E_VFQF_HENA_PTYPE_ENA_MASK I40E_MASK(0xFFFFFFFF, I40E_VFQF_HENA_PTYPE_ENA_SHIFT) +#define I40E_VFQF_HKEY(_i) (0x0000CC00 + ((_i) * 4)) /* _i=0...12 */ /* Reset: CORER */ #define I40E_VFQF_HKEY_MAX_INDEX 12 #define I40E_VFQF_HKEY_KEY_0_SHIFT 0 -#define I40E_VFQF_HKEY_KEY_0_MASK (0xFF << I40E_VFQF_HKEY_KEY_0_SHIFT) +#define I40E_VFQF_HKEY_KEY_0_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_0_SHIFT) #define I40E_VFQF_HKEY_KEY_1_SHIFT 8 -#define I40E_VFQF_HKEY_KEY_1_MASK (0xFF << I40E_VFQF_HKEY_KEY_1_SHIFT) +#define I40E_VFQF_HKEY_KEY_1_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_1_SHIFT) #define I40E_VFQF_HKEY_KEY_2_SHIFT 16 -#define I40E_VFQF_HKEY_KEY_2_MASK (0xFF << I40E_VFQF_HKEY_KEY_2_SHIFT) +#define I40E_VFQF_HKEY_KEY_2_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_2_SHIFT) #define I40E_VFQF_HKEY_KEY_3_SHIFT 24 -#define I40E_VFQF_HKEY_KEY_3_MASK (0xFF << I40E_VFQF_HKEY_KEY_3_SHIFT) -#define I40E_VFQF_HLUT(_i) (0x0000D000 + ((_i) * 4)) /* _i=0...15 */ +#define I40E_VFQF_HKEY_KEY_3_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY_KEY_3_SHIFT) +#define I40E_VFQF_HLUT(_i) (0x0000D000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ #define I40E_VFQF_HLUT_MAX_INDEX 15 #define I40E_VFQF_HLUT_LUT0_SHIFT 0 -#define I40E_VFQF_HLUT_LUT0_MASK (0xF << I40E_VFQF_HLUT_LUT0_SHIFT) +#define I40E_VFQF_HLUT_LUT0_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT0_SHIFT) #define I40E_VFQF_HLUT_LUT1_SHIFT 8 -#define I40E_VFQF_HLUT_LUT1_MASK (0xF << I40E_VFQF_HLUT_LUT1_SHIFT) +#define I40E_VFQF_HLUT_LUT1_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT1_SHIFT) #define I40E_VFQF_HLUT_LUT2_SHIFT 16 -#define I40E_VFQF_HLUT_LUT2_MASK (0xF << I40E_VFQF_HLUT_LUT2_SHIFT) +#define I40E_VFQF_HLUT_LUT2_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT2_SHIFT) #define I40E_VFQF_HLUT_LUT3_SHIFT 24 -#define I40E_VFQF_HLUT_LUT3_MASK (0xF << I40E_VFQF_HLUT_LUT3_SHIFT) -#define I40E_VFQF_HREGION(_i) (0x0000D400 + ((_i) * 4)) /* _i=0...7 */ +#define I40E_VFQF_HLUT_LUT3_MASK I40E_MASK(0xF, I40E_VFQF_HLUT_LUT3_SHIFT) +#define I40E_VFQF_HREGION(_i) (0x0000D400 + ((_i) * 4)) /* _i=0...7 */ /* Reset: CORER */ #define I40E_VFQF_HREGION_MAX_INDEX 7 #define I40E_VFQF_HREGION_OVERRIDE_ENA_0_SHIFT 0 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_0_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_0_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_0_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_0_SHIFT) #define I40E_VFQF_HREGION_REGION_0_SHIFT 1 -#define I40E_VFQF_HREGION_REGION_0_MASK (0x7 << I40E_VFQF_HREGION_REGION_0_SHIFT) +#define I40E_VFQF_HREGION_REGION_0_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_0_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_1_SHIFT 4 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_1_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_1_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_1_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_1_SHIFT) #define I40E_VFQF_HREGION_REGION_1_SHIFT 5 -#define I40E_VFQF_HREGION_REGION_1_MASK (0x7 << I40E_VFQF_HREGION_REGION_1_SHIFT) +#define I40E_VFQF_HREGION_REGION_1_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_1_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_2_SHIFT 8 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_2_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_2_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_2_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_2_SHIFT) #define I40E_VFQF_HREGION_REGION_2_SHIFT 9 -#define I40E_VFQF_HREGION_REGION_2_MASK (0x7 << I40E_VFQF_HREGION_REGION_2_SHIFT) +#define I40E_VFQF_HREGION_REGION_2_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_2_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_3_SHIFT 12 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_3_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_3_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_3_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_3_SHIFT) #define I40E_VFQF_HREGION_REGION_3_SHIFT 13 -#define I40E_VFQF_HREGION_REGION_3_MASK (0x7 << I40E_VFQF_HREGION_REGION_3_SHIFT) +#define I40E_VFQF_HREGION_REGION_3_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_3_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_4_SHIFT 16 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_4_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_4_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_4_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_4_SHIFT) #define I40E_VFQF_HREGION_REGION_4_SHIFT 17 -#define I40E_VFQF_HREGION_REGION_4_MASK (0x7 << I40E_VFQF_HREGION_REGION_4_SHIFT) +#define I40E_VFQF_HREGION_REGION_4_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_4_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_5_SHIFT 20 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_5_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_5_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_5_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_5_SHIFT) #define I40E_VFQF_HREGION_REGION_5_SHIFT 21 -#define I40E_VFQF_HREGION_REGION_5_MASK (0x7 << I40E_VFQF_HREGION_REGION_5_SHIFT) +#define I40E_VFQF_HREGION_REGION_5_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_5_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_6_SHIFT 24 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_6_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_6_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_6_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_6_SHIFT) #define I40E_VFQF_HREGION_REGION_6_SHIFT 25 -#define I40E_VFQF_HREGION_REGION_6_MASK (0x7 << I40E_VFQF_HREGION_REGION_6_SHIFT) +#define I40E_VFQF_HREGION_REGION_6_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_6_SHIFT) #define I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT 28 -#define I40E_VFQF_HREGION_OVERRIDE_ENA_7_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT) +#define I40E_VFQF_HREGION_OVERRIDE_ENA_7_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT) #define I40E_VFQF_HREGION_REGION_7_SHIFT 29 -#define I40E_VFQF_HREGION_REGION_7_MASK (0x7 << I40E_VFQF_HREGION_REGION_7_SHIFT) -#define I40E_RCU_PST_FOC_ACCESS_STATUS 0x00270110 -#define I40E_RCU_PST_FOC_ACCESS_STATUS_WR_ACCESS_CNT_SHIFT 0 -#define I40E_RCU_PST_FOC_ACCESS_STATUS_WR_ACCESS_CNT_MASK (0xFF << I40E_RCU_PST_FOC_ACCESS_STATUS_WR_ACCESS_CNT_SHIFT) -#define I40E_RCU_PST_FOC_ACCESS_STATUS_RD_ACCESS_CNT_SHIFT 8 -#define I40E_RCU_PST_FOC_ACCESS_STATUS_RD_ACCESS_CNT_MASK (0xFF << I40E_RCU_PST_FOC_ACCESS_STATUS_RD_ACCESS_CNT_SHIFT) -#define I40E_RCU_PST_FOC_ACCESS_STATUS_ERR_CNT_SHIFT 16 -#define I40E_RCU_PST_FOC_ACCESS_STATUS_ERR_CNT_MASK (0xFF << I40E_RCU_PST_FOC_ACCESS_STATUS_ERR_CNT_SHIFT) -#define I40E_RCU_PST_FOC_ACCESS_STATUS_LAST_ERR_CODE_SHIFT 24 -#define I40E_RCU_PST_FOC_ACCESS_STATUS_LAST_ERR_CODE_MASK (0x7 << I40E_RCU_PST_FOC_ACCESS_STATUS_LAST_ERR_CODE_SHIFT) +#define I40E_VFQF_HREGION_REGION_7_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_7_SHIFT) #endif diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index d3cf5a69de54..4a2e48af2887 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -50,6 +50,9 @@ (d) == I40E_DEV_ID_QSFP_B || \ (d) == I40E_DEV_ID_QSFP_C) +/* I40E_MASK is a macro used on 32 bit registers */ +#define I40E_MASK(mask, shift) (mask << shift) + #define I40E_MAX_VSI_QP 16 #define I40E_MAX_VF_VSI 3 #define I40E_MAX_CHAINED_RX_BUFFERS 5 -- cgit v1.2.3 From 407e063c92c51420c3e919203de47e144dec6934 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 3 Jun 2014 23:50:12 +0000 Subject: i40e: workaround NVM GLQF_HKEY The NVM wasn't filling in the GLQF_HKEY register on some old NVM versions. If this is the case, fill in some values so receive with flow rules works right. Change-ID: Ic737888ee68f96efb4cf8a1a49d2301615e09ed2 Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 374f36b84513..95c331abee43 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5463,6 +5463,20 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf) struct i40e_vsi *vsi; int i; + /* quick workaround for an NVM issue that leaves a critical register + * uninitialized + */ + if (!rd32(&pf->hw, I40E_GLQF_HKEY(0))) { + static const u32 hkey[] = { + 0xe640d33f, 0xcdfe98ab, 0x73fa7161, 0x0d7a7d36, + 0xeacb7d61, 0xaa4f05b6, 0x9c5c89ed, 0xfc425ddb, + 0xa4654832, 0xfc7461d4, 0x8f827619, 0xf5c63c21, + 0x95b3a76d}; + + for (i = 0; i <= I40E_GLQF_HKEY_MAX_INDEX; i++) + wr32(&pf->hw, I40E_GLQF_HKEY(i), hkey[i]); + } + if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED)) return; -- cgit v1.2.3 From 80a977e79373c8e46d88800a4e2c0cfeeb8d925b Mon Sep 17 00:00:00 2001 From: Michal Kosiarz Date: Tue, 3 Jun 2014 23:50:13 +0000 Subject: i40e/i40evf: Reset Head and Tail on AQ initialization Reset head and tail on admin queue initialization where H/T are not reset by HW. Change-ID: I6db8a2dd3f05ce66410a92cce016191add04760e Signed-off-by: Michal Kosiarz Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 21 +++++++++++++++++++++ drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 7a027499fc57..40381abb873b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -296,6 +296,10 @@ static i40e_status i40e_config_asq_regs(struct i40e_hw *hw) i40e_status ret_code = 0; u32 reg = 0; + /* Clear Head and Tail */ + wr32(hw, hw->aq.asq.head, 0); + wr32(hw, hw->aq.asq.tail, 0); + if (hw->mac.type == I40E_MAC_VF) { /* configure the transmit queue */ wr32(hw, I40E_VF_ATQBAH1, @@ -334,6 +338,10 @@ static i40e_status i40e_config_arq_regs(struct i40e_hw *hw) i40e_status ret_code = 0; u32 reg = 0; + /* Clear Head and Tail */ + wr32(hw, hw->aq.arq.head, 0); + wr32(hw, hw->aq.arq.tail, 0); + if (hw->mac.type == I40E_MAC_VF) { /* configure the receive queue */ wr32(hw, I40E_VF_ARQBAH1, @@ -677,6 +685,10 @@ static u16 i40e_clean_asq(struct i40e_hw *hw) desc = I40E_ADMINQ_DESC(*asq, ntc); details = I40E_ADMINQ_DETAILS(*asq, ntc); while (rd32(hw, hw->aq.asq.head) != ntc) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "%s: ntc %d head %d.\n", __func__, ntc, + rd32(hw, hw->aq.asq.head)); + if (details->callback) { I40E_ADMINQ_CALLBACK cb_func = (I40E_ADMINQ_CALLBACK)details->callback; @@ -736,6 +748,15 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, struct i40e_aq_desc *desc_on_ring; bool cmd_completed = false; u16 retval = 0; + u32 val = 0; + + val = rd32(hw, hw->aq.asq.head); + if (val >= hw->aq.num_asq_entries) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "AQTX: head overrun at %d\n", val); + status = I40E_ERR_QUEUE_EMPTY; + goto asq_send_command_exit; + } if (hw->aq.asq.count == 0) { i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index eb67cce3e8f9..4a90a85b0b53 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -294,6 +294,10 @@ static i40e_status i40e_config_asq_regs(struct i40e_hw *hw) i40e_status ret_code = 0; u32 reg = 0; + /* Clear Head and Tail */ + wr32(hw, hw->aq.asq.head, 0); + wr32(hw, hw->aq.asq.tail, 0); + if (hw->mac.type == I40E_MAC_VF) { /* configure the transmit queue */ wr32(hw, I40E_VF_ATQBAH1, @@ -332,6 +336,10 @@ static i40e_status i40e_config_arq_regs(struct i40e_hw *hw) i40e_status ret_code = 0; u32 reg = 0; + /* Clear Head and Tail */ + wr32(hw, hw->aq.arq.head, 0); + wr32(hw, hw->aq.arq.tail, 0); + if (hw->mac.type == I40E_MAC_VF) { /* configure the receive queue */ wr32(hw, I40E_VF_ARQBAH1, @@ -630,6 +638,10 @@ static u16 i40e_clean_asq(struct i40e_hw *hw) desc = I40E_ADMINQ_DESC(*asq, ntc); details = I40E_ADMINQ_DETAILS(*asq, ntc); while (rd32(hw, hw->aq.asq.head) != ntc) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "%s: ntc %d head %d.\n", __func__, ntc, + rd32(hw, hw->aq.asq.head)); + if (details->callback) { I40E_ADMINQ_CALLBACK cb_func = (I40E_ADMINQ_CALLBACK)details->callback; @@ -690,6 +702,15 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, struct i40e_aq_desc *desc_on_ring; bool cmd_completed = false; u16 retval = 0; + u32 val = 0; + + val = rd32(hw, hw->aq.asq.head); + if (val >= hw->aq.num_asq_entries) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "AQTX: head overrun at %d\n", val); + status = I40E_ERR_QUEUE_EMPTY; + goto asq_send_command_exit; + } if (hw->aq.asq.count == 0) { i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, -- cgit v1.2.3 From 70114ec4aa38096253eef8a9379a59d129e90902 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Tue, 3 Jun 2014 23:50:14 +0000 Subject: i40e: Fix dangling ring pointers upon driver removal When we resize the number of queues, the driver needs to disassociate any qvectors that are no longer in use from the original rings, this way we do not try to access the rings through these qvectors at the time of freeing the qvectors. Change-ID: Ie4eb9fc749f8e12348517fe1560f599c58f4a2a4 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 95c331abee43..7d2aeeb6318f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3151,8 +3151,12 @@ static void i40e_vsi_map_rings_to_vectors(struct i40e_vsi *vsi) /* If we don't have enough vectors for a 1-to-1 mapping, we'll have to * group them so there are multiple queues per vector. + * It is also important to go through all the vectors available to be + * sure that if we don't use all the vectors, that the remaining vectors + * are cleared. This is especially important when decreasing the + * number of queues in use. */ - for (; v_start < q_vectors && qp_remaining; v_start++) { + for (; v_start < q_vectors; v_start++) { struct i40e_q_vector *q_vector = vsi->q_vectors[v_start]; num_ringpairs = DIV_ROUND_UP(qp_remaining, q_vectors - v_start); -- cgit v1.2.3 From 23527308d6519c551c8296146f3edf3ad1cd123a Mon Sep 17 00:00:00 2001 From: Neerav Parikh Date: Tue, 3 Jun 2014 23:50:15 +0000 Subject: i40e: Helper routine for Rx/Tx queue enable/disable wait Introduce helper routines that would wait for the Rx/Tx queue to reach the enable or disable state as requested. Change-ID: I518d9d0e2afef3f45107af3b46e9af402ff587c3 Signed-off-by: Neerav Parikh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_main.c | 100 ++++++++++++++++++++-------- 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 65985846345d..fce7e4dfc173 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -84,6 +84,7 @@ #define I40E_AQ_WORK_LIMIT 16 #define I40E_MAX_USER_PRIORITY 8 #define I40E_DEFAULT_MSG_ENABLE 4 +#define I40E_QUEUE_WAIT_RETRY_LIMIT 10 #define I40E_NVM_VERSION_LO_SHIFT 0 #define I40E_NVM_VERSION_LO_MASK (0xff << I40E_NVM_VERSION_LO_SHIFT) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 7d2aeeb6318f..296b3d203ad9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3231,6 +3231,35 @@ static void i40e_netpoll(struct net_device *netdev) } #endif +/** + * i40e_pf_txq_wait - Wait for a PF's Tx queue to be enabled or disabled + * @pf: the PF being configured + * @pf_q: the PF queue + * @enable: enable or disable state of the queue + * + * This routine will wait for the given Tx queue of the PF to reach the + * enabled or disabled state. + * Returns -ETIMEDOUT in case of failing to reach the requested state after + * multiple retries; else will return 0 in case of success. + **/ +static int i40e_pf_txq_wait(struct i40e_pf *pf, int pf_q, bool enable) +{ + int i; + u32 tx_reg; + + for (i = 0; i < I40E_QUEUE_WAIT_RETRY_LIMIT; i++) { + tx_reg = rd32(&pf->hw, I40E_QTX_ENA(pf_q)); + if (enable == !!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) + break; + + udelay(10); + } + if (i >= I40E_QUEUE_WAIT_RETRY_LIMIT) + return -ETIMEDOUT; + + return 0; +} + /** * i40e_vsi_control_tx - Start or stop a VSI's rings * @vsi: the VSI being configured @@ -3240,7 +3269,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) { struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; - int i, j, pf_q; + int i, j, pf_q, ret = 0; u32 tx_reg; pf_q = vsi->base_queue; @@ -3273,22 +3302,46 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) wr32(hw, I40E_QTX_ENA(pf_q), tx_reg); /* wait for the change to finish */ - for (j = 0; j < 10; j++) { - tx_reg = rd32(hw, I40E_QTX_ENA(pf_q)); - if (enable == !!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) - break; - - udelay(10); - } - if (j >= 10) { - dev_info(&pf->pdev->dev, "Tx ring %d %sable timeout\n", - pf_q, (enable ? "en" : "dis")); - return -ETIMEDOUT; + ret = i40e_pf_txq_wait(pf, pf_q, enable); + if (ret) { + dev_info(&pf->pdev->dev, + "%s: VSI seid %d Tx ring %d %sable timeout\n", + __func__, vsi->seid, pf_q, + (enable ? "en" : "dis")); + break; } } if (hw->revision_id == 0) mdelay(50); + return ret; +} + +/** + * i40e_pf_rxq_wait - Wait for a PF's Rx queue to be enabled or disabled + * @pf: the PF being configured + * @pf_q: the PF queue + * @enable: enable or disable state of the queue + * + * This routine will wait for the given Rx queue of the PF to reach the + * enabled or disabled state. + * Returns -ETIMEDOUT in case of failing to reach the requested state after + * multiple retries; else will return 0 in case of success. + **/ +static int i40e_pf_rxq_wait(struct i40e_pf *pf, int pf_q, bool enable) +{ + int i; + u32 rx_reg; + + for (i = 0; i < I40E_QUEUE_WAIT_RETRY_LIMIT; i++) { + rx_reg = rd32(&pf->hw, I40E_QRX_ENA(pf_q)); + if (enable == !!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) + break; + + udelay(10); + } + if (i >= I40E_QUEUE_WAIT_RETRY_LIMIT) + return -ETIMEDOUT; return 0; } @@ -3302,7 +3355,7 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable) { struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; - int i, j, pf_q; + int i, j, pf_q, ret = 0; u32 rx_reg; pf_q = vsi->base_queue; @@ -3327,22 +3380,17 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable) wr32(hw, I40E_QRX_ENA(pf_q), rx_reg); /* wait for the change to finish */ - for (j = 0; j < 10; j++) { - rx_reg = rd32(hw, I40E_QRX_ENA(pf_q)); - - if (enable == !!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) - break; - - udelay(10); - } - if (j >= 10) { - dev_info(&pf->pdev->dev, "Rx ring %d %sable timeout\n", - pf_q, (enable ? "en" : "dis")); - return -ETIMEDOUT; + ret = i40e_pf_rxq_wait(pf, pf_q, enable); + if (ret) { + dev_info(&pf->pdev->dev, + "%s: VSI seid %d Rx ring %d %sable timeout\n", + __func__, vsi->seid, pf_q, + (enable ? "en" : "dis")); + break; } } - return 0; + return ret; } /** -- cgit v1.2.3 From c27936e7b2d57af2965a78973430383be98fe88a Mon Sep 17 00:00:00 2001 From: Neerav Parikh Date: Tue, 3 Jun 2014 23:50:16 +0000 Subject: i40e: debugfs fix to dump remote LLDPDU Fix the debugfs command "lldp get remote" that dumped the local LLDPDU instead of peer's LLDPDU. Change-ID: I0702eacdafd54478c18f20cab3a7fa5dc1b3182d Signed-off-by: Neerav Parikh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index cffdfc21290f..910b01b90cdc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1830,7 +1830,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, ret = i40e_aq_get_lldp_mib(&pf->hw, I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE, - I40E_AQ_LLDP_MIB_LOCAL, + I40E_AQ_LLDP_MIB_REMOTE, buff, I40E_LLDPDU_SIZE, &llen, &rlen, NULL); if (ret) { -- cgit v1.2.3 From b5d06f058b0bb52c39e4f1a32584dda712e0398f Mon Sep 17 00:00:00 2001 From: Neerav Parikh Date: Tue, 3 Jun 2014 23:50:17 +0000 Subject: i40e: Fix scheduling while atomic bug during NAPI The bug is encountered when all the Tx hang recovery mechanisms have failed and driver tries to bring down the interface in the interrupt context. The patch defers this and schedules it for next cycle. Change-ID: Id9cd1da15b0e5c018dce18da4d0eed5ef1e8a809 Signed-off-by: Neerav Parikh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_main.c | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index fce7e4dfc173..60f9a73303ba 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -135,6 +135,7 @@ enum i40e_state_t { __I40E_FILTER_OVERFLOW_PROMISC, __I40E_SUSPENDED, __I40E_BAD_EEPROM, + __I40E_DOWN_REQUESTED, }; enum i40e_interrupt_policy { diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 296b3d203ad9..14d7db60813e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -304,8 +304,8 @@ static void i40e_tx_timeout(struct net_device *netdev) break; default: netdev_err(netdev, "tx_timeout recovery unsuccessful\n"); - set_bit(__I40E_DOWN, &vsi->state); - i40e_down(vsi); + set_bit(__I40E_DOWN_REQUESTED, &pf->state); + set_bit(__I40E_DOWN_REQUESTED, &vsi->state); break; } i40e_service_event_schedule(pf); @@ -4690,6 +4690,23 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) } } + /* no further action needed, so return now */ + return; + } else if (reset_flags & (1 << __I40E_DOWN_REQUESTED)) { + int v; + + /* Find the VSI(s) that needs to be brought down */ + dev_info(&pf->pdev->dev, "VSI down requested\n"); + for (v = 0; v < pf->num_alloc_vsi; v++) { + struct i40e_vsi *vsi = pf->vsi[v]; + if (vsi != NULL && + test_bit(__I40E_DOWN_REQUESTED, &vsi->state)) { + set_bit(__I40E_DOWN, &vsi->state); + i40e_down(vsi); + clear_bit(__I40E_DOWN_REQUESTED, &vsi->state); + } + } + /* no further action needed, so return now */ return; } else { @@ -5162,6 +5179,10 @@ static void i40e_reset_subtask(struct i40e_pf *pf) reset_flags |= (1 << __I40E_GLOBAL_RESET_REQUESTED); clear_bit(__I40E_GLOBAL_RESET_REQUESTED, &pf->state); } + if (test_bit(__I40E_DOWN_REQUESTED, &pf->state)) { + reset_flags |= (1 << __I40E_DOWN_REQUESTED); + clear_bit(__I40E_DOWN_REQUESTED, &pf->state); + } /* If there's a recovery already waiting, it takes * precedence before starting a new reset sequence. -- cgit v1.2.3 From e91fdf7666fa4c6a5111f8b20304a990bc77e89e Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Tue, 3 Jun 2014 23:50:18 +0000 Subject: i40e: clear VEB stats when pf stats are cleared The VEB really is part of the whole PF and should be cleared at the same time. Change-ID: Ia1d4d1df5cf421f2578a22486650dd256cc4617a Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 14d7db60813e..394253e03e7a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -444,9 +444,21 @@ void i40e_vsi_reset_stats(struct i40e_vsi *vsi) **/ void i40e_pf_reset_stats(struct i40e_pf *pf) { + int i; + memset(&pf->stats, 0, sizeof(pf->stats)); memset(&pf->stats_offsets, 0, sizeof(pf->stats_offsets)); pf->stat_offsets_loaded = false; + + for (i = 0; i < I40E_MAX_VEB; i++) { + if (pf->veb[i]) { + memset(&pf->veb[i]->stats, 0, + sizeof(pf->veb[i]->stats)); + memset(&pf->veb[i]->stats_offsets, 0, + sizeof(pf->veb[i]->stats_offsets)); + pf->veb[i]->stat_offsets_loaded = false; + } + } } /** -- cgit v1.2.3 From e57a2fea8787dffcbdff3f7f0567a1e8555dd93a Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Tue, 3 Jun 2014 23:50:19 +0000 Subject: i40e: keep service tasks out of reset process Make sure the service tasks don't try to meddle with the device while a reset is in progress. Odd things can happen such as funky stats values. Change-ID: I6929cb9d6d96839c9279362ca7c0e3fe6c8fcc66 Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 394253e03e7a..ebbf37bc367e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5961,6 +5961,12 @@ static void i40e_service_task(struct work_struct *work) service_task); unsigned long start_time = jiffies; + /* don't bother with service tasks if a reset is in progress */ + if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state)) { + i40e_service_event_complete(pf); + return; + } + i40e_reset_subtask(pf); i40e_handle_mdd_event(pf); i40e_vc_process_vflr_event(pf); -- cgit v1.2.3 From cc70b080ea773d7aea4a0440316f30f5af6bb655 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Tue, 3 Jun 2014 23:50:20 +0000 Subject: i40evf: fix off-by-one The loop in i40evf_get_rxfh_indir was only reading fifteen registers, not all sixteen. Change the matching loop in i40evf_set_rxfh_indir at the same time to make the code more consistent. Change-ID: I6c182287698e742d1f6ca1a4bcc43cc08df6e1de Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c index 60407a9df0c1..e70e4cdb0eb2 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c @@ -632,7 +632,7 @@ static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key) u32 hlut_val; int i, j; - for (i = 0, j = 0; i < I40E_VFQF_HLUT_MAX_INDEX; i++) { + for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) { hlut_val = rd32(hw, I40E_VFQF_HLUT(i)); indir[j++] = hlut_val & 0xff; indir[j++] = (hlut_val >> 8) & 0xff; @@ -659,7 +659,7 @@ static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir, u32 hlut_val; int i, j; - for (i = 0, j = 0; i < I40E_VFQF_HLUT_MAX_INDEX + 1; i++) { + for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) { hlut_val = indir[j++]; hlut_val |= indir[j++] << 8; hlut_val |= indir[j++] << 16; -- cgit v1.2.3 From 3a494e710367c0a233d86bcde9853781859fc008 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Thu, 19 Jun 2014 18:34:36 -0700 Subject: hyperv: Add handler for RNDIS_STATUS_NETWORK_CHANGE event The RNDIS_STATUS_NETWORK_CHANGE event is received after the Hyper-V host sleep or hibernation. We refresh network at this time. MS-TFS: 135162 Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 3 ++- drivers/net/hyperv/netvsc_drv.c | 30 ++++++++++++++++++++++++++---- drivers/net/hyperv/rndis_filter.c | 21 +-------------------- include/linux/rndis.h | 1 + 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 6cc37c15e0bf..24441ae832d1 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -170,6 +170,7 @@ struct rndis_device { enum rndis_device_state state; bool link_state; + bool link_change; atomic_t new_req_id; spinlock_t request_lock; @@ -185,7 +186,7 @@ int netvsc_device_remove(struct hv_device *device); int netvsc_send(struct hv_device *device, struct hv_netvsc_packet *packet); void netvsc_linkstatus_callback(struct hv_device *device_obj, - unsigned int status); + struct rndis_message *resp); int netvsc_recv_callback(struct hv_device *device_obj, struct hv_netvsc_packet *packet, struct ndis_tcp_ip_checksum_info *csum_info); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 4fd71b75e666..9b27ca8c1d39 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -579,8 +579,9 @@ drop: * netvsc_linkstatus_callback - Link up/down notification */ void netvsc_linkstatus_callback(struct hv_device *device_obj, - unsigned int status) + struct rndis_message *resp) { + struct rndis_indicate_status *indicate = &resp->msg.indicate_status; struct net_device *net; struct net_device_context *ndev_ctx; struct netvsc_device *net_device; @@ -589,7 +590,19 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, net_device = hv_get_drvdata(device_obj); rdev = net_device->extension; - rdev->link_state = status != 1; + switch (indicate->status) { + case RNDIS_STATUS_MEDIA_CONNECT: + rdev->link_state = false; + break; + case RNDIS_STATUS_MEDIA_DISCONNECT: + rdev->link_state = true; + break; + case RNDIS_STATUS_NETWORK_CHANGE: + rdev->link_change = true; + break; + default: + return; + } net = net_device->ndev; @@ -597,7 +610,7 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, return; ndev_ctx = netdev_priv(net); - if (status == 1) { + if (!rdev->link_state) { schedule_delayed_work(&ndev_ctx->dwork, 0); schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20)); } else { @@ -767,7 +780,9 @@ static void netvsc_link_change(struct work_struct *w) struct net_device *net; struct netvsc_device *net_device; struct rndis_device *rdev; - bool notify; + bool notify, refresh = false; + char *argv[] = { "/etc/init.d/network", "restart", NULL }; + char *envp[] = { "HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; rtnl_lock(); @@ -782,10 +797,17 @@ static void netvsc_link_change(struct work_struct *w) } else { netif_carrier_on(net); notify = true; + if (rdev->link_change) { + rdev->link_change = false; + refresh = true; + } } rtnl_unlock(); + if (refresh) + call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); + if (notify) netdev_notify_peers(net); } diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 99c527adae5b..2b86f0b6f6d1 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -320,25 +320,6 @@ static void rndis_filter_receive_response(struct rndis_device *dev, } } -static void rndis_filter_receive_indicate_status(struct rndis_device *dev, - struct rndis_message *resp) -{ - struct rndis_indicate_status *indicate = - &resp->msg.indicate_status; - - if (indicate->status == RNDIS_STATUS_MEDIA_CONNECT) { - netvsc_linkstatus_callback( - dev->net_dev->dev, 1); - } else if (indicate->status == RNDIS_STATUS_MEDIA_DISCONNECT) { - netvsc_linkstatus_callback( - dev->net_dev->dev, 0); - } else { - /* - * TODO: - */ - } -} - /* * Get the Per-Packet-Info with the specified type * return NULL if not found. @@ -464,7 +445,7 @@ int rndis_filter_receive(struct hv_device *dev, case RNDIS_MSG_INDICATE: /* notification msgs */ - rndis_filter_receive_indicate_status(rndis_dev, rndis_msg); + netvsc_linkstatus_callback(dev, rndis_msg); break; default: netdev_err(ndev, diff --git a/include/linux/rndis.h b/include/linux/rndis.h index 0c8dc7195cdb..93c0a64aefa6 100644 --- a/include/linux/rndis.h +++ b/include/linux/rndis.h @@ -65,6 +65,7 @@ #define RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 #define RNDIS_STATUS_WW_INDICATION RDIA_SPECIFIC_INDICATION #define RNDIS_STATUS_LINK_SPEED_CHANGE 0x40010013L +#define RNDIS_STATUS_NETWORK_CHANGE 0x40010018 #define RNDIS_STATUS_NOT_RESETTABLE 0x80010001 #define RNDIS_STATUS_SOFT_ERRORS 0x80010003 -- cgit v1.2.3 From 44f71cef92eb65bc4382ef3fb04a8e1437bda2d7 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 17 Jun 2014 21:22:50 +0200 Subject: drivers/net/irda/kingsun-sir.c: remove null test before kfree Fix checkpatch warning: WARNING: kfree(NULL) is safe this check is probably not required Cc: Samuel Ortiz Cc: netdev@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/irda/kingsun-sir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index 96fe3659012d..e638893e98a9 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -553,8 +553,8 @@ static int kingsun_probe(struct usb_interface *intf, return 0; free_mem: - if (kingsun->out_buf) kfree(kingsun->out_buf); - if (kingsun->in_buf) kfree(kingsun->in_buf); + kfree(kingsun->out_buf); + kfree(kingsun->in_buf); free_netdev(net); err_out1: return ret; -- cgit v1.2.3 From 88729dd18995a87f0f8fe0423518b171a877d7b6 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 17 Jun 2014 21:32:53 +0200 Subject: drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c: remove null test before kfree Fix checkpatch warning: WARNING: kfree(NULL) is safe this check is probably not required Cc: Ariel Elior Cc: netdev@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index eda8583f6fc0..c9988e3bfe2b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -597,8 +597,7 @@ int bnx2x_vf_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf, rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_DEL); if (rc) { BNX2X_ERR("Failed to remove multicasts\n"); - if (mc) - kfree(mc); + kfree(mc); return rc; } -- cgit v1.2.3 From e157ea30606743f2bfa2ec445a0bb0839e17271b Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Tue, 3 Jun 2014 23:50:22 +0000 Subject: i40e/i40evf: Update RSS configuration This patch changes the RSS configuration to set table size and write to hardware to confirm RSS table size being used. Change-ID: I455a4c09c9dd479f5791ee1f09fdc83ff9908df5 Signed-off-by: Carolyn Wyborny Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_common.c | 7 +------ drivers/net/ethernet/intel/i40e/i40e_main.c | 14 +++++++++++++- drivers/net/ethernet/intel/i40e/i40e_type.h | 3 +++ drivers/net/ethernet/intel/i40evf/i40e_type.h | 3 +++ 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 60f9a73303ba..817e179dc3f9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -350,6 +350,7 @@ struct i40e_pf { u32 rx_hwtstamp_cleared; bool ptp_tx; bool ptp_rx; + u16 rss_table_size; }; struct i40e_mac_filter { diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 6e65f19dd6e5..a51bba634718 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1839,7 +1839,6 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, struct i40e_aqc_list_capabilities_element_resp *cap; u32 number, logical_id, phys_id; struct i40e_hw_capabilities *p; - u32 reg_val; u32 i = 0; u16 id; @@ -1910,11 +1909,7 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, break; case I40E_DEV_FUNC_CAP_RSS: p->rss = true; - reg_val = rd32(hw, I40E_PFQF_CTL_0); - if (reg_val & I40E_PFQF_CTL_0_HASHLUTSIZE_MASK) - p->rss_table_size = number; - else - p->rss_table_size = 128; + p->rss_table_size = number; p->rss_table_entry_width = logical_id; break; case I40E_DEV_FUNC_CAP_RX_QUEUES: diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index ebbf37bc367e..34310bd116b2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6599,6 +6599,7 @@ static int i40e_config_rss(struct i40e_pf *pf) u32 lut = 0; int i, j; u64 hena; + u32 reg_val; /* Fill out hash function seed */ for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++) @@ -6611,8 +6612,19 @@ static int i40e_config_rss(struct i40e_pf *pf) wr32(hw, I40E_PFQF_HENA(0), (u32)hena); wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); + /* Check capability and Set table size and register per hw expectation*/ + reg_val = rd32(hw, I40E_PFQF_CTL_0); + if (hw->func_caps.rss_table_size == 512) { + reg_val |= I40E_PFQF_CTL_0_HASHLUTSIZE_512; + pf->rss_table_size = 512; + } else { + pf->rss_table_size = 128; + reg_val &= ~I40E_PFQF_CTL_0_HASHLUTSIZE_512; + } + wr32(hw, I40E_PFQF_CTL_0, reg_val); + /* Populate the LUT with max no. of queues in round robin fashion */ - for (i = 0, j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) { + for (i = 0, j = 0; i < pf->rss_table_size; i++, j++) { /* The assumption is that lan qp count will be the highest * qp count for any PF VSI that needs RSS. diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index a688ab86f650..1c0d5a70b892 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -1165,4 +1165,7 @@ enum i40e_reset_type { I40E_RESET_GLOBR = 2, I40E_RESET_EMPR = 3, }; + +/* RSS Hash Table Size */ +#define I40E_PFQF_CTL_0_HASHLUTSIZE_512 0x00010000 #endif /* _I40E_TYPE_H_ */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 4a2e48af2887..9c835786e8a1 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -1165,4 +1165,7 @@ enum i40e_reset_type { I40E_RESET_GLOBR = 2, I40E_RESET_EMPR = 3, }; + +/* RSS Hash Table Size */ +#define I40E_PFQF_CTL_0_HASHLUTSIZE_512 0x00010000 #endif /* _I40E_TYPE_H_ */ -- cgit v1.2.3 From 66d90e7d1654f3ed2e66d90f82dbc9daa62f534c Mon Sep 17 00:00:00 2001 From: Kamil Krawczyk Date: Wed, 4 Jun 2014 00:57:12 +0000 Subject: i40e/i40evf: modify debug prints to avoid seg faults Some AQ debug prints needs be moved around or do additional checks so they will not cause our tool applications to cause segmentation faults. The tools run in user space and we need to correctly reference kernel space memory. Change-ID: Ia2ac4076f576b805f350453fd50ad69c2a91ab9a Signed-off-by: Kamil Krawczyk Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 15 +++++++++++---- drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 15 +++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 40381abb873b..95aab708a88d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -850,6 +850,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, } /* bump the tail */ + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n"); i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, buff); (hw->aq.asq.next_to_use)++; if (hw->aq.asq.next_to_use == hw->aq.asq.count) @@ -887,6 +888,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: Command completed with error 0x%X.\n", retval); + /* strip off FW internal code */ retval &= 0xff; } @@ -901,6 +903,12 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, if (i40e_is_nvm_update_op(desc)) hw->aq.nvm_busy = true; + if (le16_to_cpu(desc->datalen) == buff_size) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "AQTX: desc and buffer writeback:\n"); + i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff); + } + /* update the error if time out occurred */ if ((!cmd_completed) && (!details->async && !details->postpone)) { @@ -972,10 +980,6 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw, /* now clean the next descriptor */ desc = I40E_ADMINQ_DESC(hw->aq.arq, ntc); desc_idx = ntc; - i40e_debug_aq(hw, - I40E_DEBUG_AQ_COMMAND, - (void *)desc, - hw->aq.arq.r.arq_bi[desc_idx].va); flags = le16_to_cpu(desc->flags); if (flags & I40E_AQ_FLAG_ERR) { @@ -998,6 +1002,9 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw, if (i40e_is_nvm_update_op(&e->desc)) hw->aq.nvm_busy = false; + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); + i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf); + /* Restore the original datalen and buffer address in the desc, * FW updates datalen to indicate the event message * size diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index 4a90a85b0b53..15853fd699a4 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -804,6 +804,7 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, } /* bump the tail */ + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n"); i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, buff); (hw->aq.asq.next_to_use)++; if (hw->aq.asq.next_to_use == hw->aq.asq.count) @@ -841,6 +842,7 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: Command completed with error 0x%X.\n", retval); + /* strip off FW internal code */ retval &= 0xff; } @@ -855,6 +857,12 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, if (i40e_is_nvm_update_op(desc)) hw->aq.nvm_busy = true; + if (le16_to_cpu(desc->datalen) == buff_size) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "AQTX: desc and buffer writeback:\n"); + i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff); + } + /* update the error if time out occurred */ if ((!cmd_completed) && (!details->async && !details->postpone)) { @@ -926,10 +934,6 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw, /* now clean the next descriptor */ desc = I40E_ADMINQ_DESC(hw->aq.arq, ntc); desc_idx = ntc; - i40evf_debug_aq(hw, - I40E_DEBUG_AQ_COMMAND, - (void *)desc, - hw->aq.arq.r.arq_bi[desc_idx].va); flags = le16_to_cpu(desc->flags); if (flags & I40E_AQ_FLAG_ERR) { @@ -952,6 +956,9 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw, if (i40e_is_nvm_update_op(&e->desc)) hw->aq.nvm_busy = false; + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); + i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf); + /* Restore the original datalen and buffer address in the desc, * FW updates datalen to indicate the event message * size -- cgit v1.2.3 From 7974d5e5ed88f4214b0d931e96040e45d2db1e88 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Tue, 3 Jun 2014 23:50:25 +0000 Subject: i40e/i40evf: Bump i40e to 0.4.13 and i40evf to 0.9.35 Bump versions. Change-ID: Ifaed5404b9e953a11f4c88953ffe4bc8937705f1 Signed-off-by: Catherine Sullivan Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 34310bd116b2..b167fc2c4abe 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 4 -#define DRV_VERSION_BUILD 10 +#define DRV_VERSION_BUILD 13 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 7fc5f3b5d6bf..2fdccce1b872 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710 X710 Virtual Function Network Driver"; -#define DRV_VERSION "0.9.34" +#define DRV_VERSION "0.9.35" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; -- cgit v1.2.3 From 6451acdc4f716610043442016f76a0b849c06ea6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 19 Jun 2014 21:48:12 -0700 Subject: mwifiex: Use the proper interfaces Why is converting time formats so desired if there are proper interfaces for this? Signed-off-by: Thomas Gleixner Acked-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 4 +--- drivers/net/wireless/mwifiex/main.c | 4 +--- drivers/net/wireless/mwifiex/tdls.c | 8 ++------ drivers/net/wireless/mwifiex/uap_txrx.c | 4 +--- drivers/net/wireless/mwifiex/wmm.c | 9 +-------- 5 files changed, 6 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index e8981afb208b..8e7b9c9696f6 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -121,7 +121,6 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) u8 addr[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; u16 pkt_len; u32 tx_control = 0, pkt_type = PKT_TYPE_MGMT; - struct timeval tv; pkt_len = len + ETH_ALEN; @@ -143,8 +142,7 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) len - sizeof(struct ieee80211_hdr_3addr)); skb->priority = LOW_PRIO_TID; - do_gettimeofday(&tv); - skb->tstamp = timeval_to_ktime(tv); + __net_timestamp(skb); return 0; } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index cbabc12fbda3..40e4dbd5b89d 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -609,7 +609,6 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct sk_buff *new_skb; struct mwifiex_txinfo *tx_info; - struct timeval tv; dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n", jiffies, priv->bss_type, priv->bss_num); @@ -656,8 +655,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) * firmware for aggregate delay calculation for stats and * MSDU lifetime expiry. */ - do_gettimeofday(&tv); - skb->tstamp = timeval_to_ktime(tv); + __net_timestamp(skb); mwifiex_queue_tx_pkt(priv, skb); diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index e73034fbbde9..3efbcbe7e891 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -530,7 +530,6 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, { struct sk_buff *skb; struct mwifiex_txinfo *tx_info; - struct timeval tv; int ret; u16 skb_len; @@ -608,8 +607,7 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, tx_info->bss_num = priv->bss_num; tx_info->bss_type = priv->bss_type; - do_gettimeofday(&tv); - skb->tstamp = timeval_to_ktime(tv); + __net_timestamp(skb); mwifiex_queue_tx_pkt(priv, skb); return 0; @@ -702,7 +700,6 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer, { struct sk_buff *skb; struct mwifiex_txinfo *tx_info; - struct timeval tv; u8 *pos; u32 pkt_type, tx_control; u16 pkt_len, skb_len; @@ -767,8 +764,7 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer, pkt_len = skb->len - MWIFIEX_MGMT_FRAME_HEADER_SIZE - sizeof(pkt_len); memcpy(skb->data + MWIFIEX_MGMT_FRAME_HEADER_SIZE, &pkt_len, sizeof(pkt_len)); - do_gettimeofday(&tv); - skb->tstamp = timeval_to_ktime(tv); + __net_timestamp(skb); mwifiex_queue_tx_pkt(priv, skb); return 0; diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index 9a56bc61cb1d..0c87f8f9113a 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -96,7 +96,6 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, struct sk_buff *new_skb; struct mwifiex_txinfo *tx_info; int hdr_chop; - struct timeval tv; struct ethhdr *p_ethhdr; uap_rx_pd = (struct uap_rxpd *)(skb->data); @@ -192,8 +191,7 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, tx_info->pkt_len = skb->len; } - do_gettimeofday(&tv); - skb->tstamp = timeval_to_ktime(tv); + __net_timestamp(skb); mwifiex_wmm_add_buf_txqueue(priv, skb); atomic_inc(&adapter->tx_pending); atomic_inc(&adapter->pending_bridged_pkts); diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index d3671d009f6c..6e86d1e17d3e 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -878,15 +878,8 @@ u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, const struct sk_buff *skb) { + u32 queue_delay = ktime_to_ms(ktime_sub(ktime_get(), skb->tstamp)); u8 ret_val; - struct timeval out_tstamp, in_tstamp; - u32 queue_delay; - - do_gettimeofday(&out_tstamp); - in_tstamp = ktime_to_timeval(skb->tstamp); - - queue_delay = (out_tstamp.tv_sec - in_tstamp.tv_sec) * 1000; - queue_delay += (out_tstamp.tv_usec - in_tstamp.tv_usec) / 1000; /* * Queue delay is passed as a uint8 in units of 2ms (ms shifted -- cgit v1.2.3 From e48b1790907c960b9d4f28cf7da9e0c25c5d02df Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Fri, 20 Jun 2014 10:05:07 +0300 Subject: wil6210: fix for 64-bit integer division On some platforms, cycles_t is 64-bit, and gcc generates call to __udivdi3 for straight division of cycles_t/cycles_t. This leads to compilation failure, as this function is not exist in the kernel runtime. do_div() to rescue Original report: tree: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next.git master head: 2e91606f5e1ec7329557dfc0e298c4c021acbb80 commit: 7c0acf868d2e470c9d6a40091acf8d6444c01b57 [81/103] wil6210: Tx performance monitoring config: i386-randconfig-ha3-0620 (attached as .config) All error/warnings: drivers/built-in.o: In function `wil_vring_debugfs_show': >> debugfs.c:(.text+0x39b9be): undefined reference to `__udivdi3' Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 7d1ef4eea0d8..a868c5eebe37 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -83,9 +83,10 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) char name[10]; /* performance monitoring */ cycles_t now = get_cycles(); - cycles_t idle = txdata->idle; + cycles_t idle = txdata->idle * 100; cycles_t total = now - txdata->begin; + do_div(idle, total); txdata->begin = now; txdata->idle = 0ULL; @@ -93,7 +94,7 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d] idle %3d%%\n", wil->sta[cid].addr, cid, tid, used, avail, - (int)((idle*100)/total)); + (int)idle); wil_print_vring(s, wil, name, vring, '_', 'H'); } -- cgit v1.2.3 From bba4d409cbd322a0b78768a6dda013baed2b5a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 20 Jun 2014 17:22:00 +0200 Subject: b43: remove leftover code from old devices support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Old devices (A-PHY or B-PHY) are supposed to be supported by b43legacy. We keep phy_a.c as it's needed for G-PHY which shares some design. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 9 --------- drivers/net/wireless/b43/phy_a.h | 4 ---- drivers/net/wireless/b43/phy_common.c | 3 --- 3 files changed, 16 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 4b662d0abdd2..4164afa843e9 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4306,15 +4306,6 @@ static int b43_phy_versioning(struct b43_wldev *dev) phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT; phy_rev = (tmp & B43_PHYVER_VERSION); switch (phy_type) { - case B43_PHYTYPE_A: - if (phy_rev >= 4) - unsupported = 1; - break; - case B43_PHYTYPE_B: - if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 - && phy_rev != 7) - unsupported = 1; - break; case B43_PHYTYPE_G: if (phy_rev > 9) unsupported = 1; diff --git a/drivers/net/wireless/b43/phy_a.h b/drivers/net/wireless/b43/phy_a.h index 5cfaab7b16ee..f7d0d929a374 100644 --- a/drivers/net/wireless/b43/phy_a.h +++ b/drivers/net/wireless/b43/phy_a.h @@ -123,8 +123,4 @@ struct b43_phy_a { */ void b43_phy_inita(struct b43_wldev *dev); - -struct b43_phy_operations; -extern const struct b43_phy_operations b43_phyops_a; - #endif /* LINUX_B43_PHY_A_H_ */ diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 2d05b5987168..ce486eeaf8e1 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -45,9 +45,6 @@ int b43_phy_allocate(struct b43_wldev *dev) phy->ops = NULL; switch (phy->type) { - case B43_PHYTYPE_A: - phy->ops = &b43_phyops_a; - break; case B43_PHYTYPE_G: phy->ops = &b43_phyops_g; break; -- cgit v1.2.3 From 418378fed0506b5ec0b43c03bc11929ec1f88073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 20 Jun 2014 17:22:01 +0200 Subject: b43: add config for (en|dis)abling G-PHY support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows new devices users to save some space. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Kconfig | 9 +++++++++ drivers/net/wireless/b43/Makefile | 6 +----- drivers/net/wireless/b43/main.c | 2 ++ drivers/net/wireless/b43/phy_common.c | 2 ++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index e3f67b8d3f80..037a4e304d14 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -122,6 +122,15 @@ config B43_PIO select SSB_BLOCKIO default y +config B43_PHY_G + bool "Support for G-PHY (802.11g) devices" + depends on B43 && B43_SSB + default y + ---help--- + This PHY type can be found in the following chipsets: + PCI: BCM4306, BCM4311, BCM4318 + SoC: BCM4712, BCM5352E + config B43_PHY_N bool "Support for 802.11n (N-PHY) devices" depends on B43 diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 098fe9ee7096..6e00b8804ada 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -1,13 +1,11 @@ b43-y += main.o b43-y += bus.o -b43-y += tables.o +b43-$(CONFIG_B43_PHY_G) += phy_a.o phy_g.o tables.o lo.o wa.o b43-$(CONFIG_B43_PHY_N) += tables_nphy.o b43-$(CONFIG_B43_PHY_N) += radio_2055.o b43-$(CONFIG_B43_PHY_N) += radio_2056.o b43-$(CONFIG_B43_PHY_N) += radio_2057.o b43-y += phy_common.o -b43-y += phy_g.o -b43-y += phy_a.o b43-$(CONFIG_B43_PHY_N) += phy_n.o b43-$(CONFIG_B43_PHY_LP) += phy_lp.o b43-$(CONFIG_B43_PHY_LP) += tables_lpphy.o @@ -17,8 +15,6 @@ b43-$(CONFIG_B43_PHY_HT) += radio_2059.o b43-$(CONFIG_B43_PHY_LCN) += phy_lcn.o tables_phy_lcn.o b43-y += sysfs.o b43-y += xmit.o -b43-y += lo.o -b43-y += wa.o b43-y += dma.o b43-y += pio.o b43-y += rfkill.o diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 4164afa843e9..9cf07bb7adf8 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4306,10 +4306,12 @@ static int b43_phy_versioning(struct b43_wldev *dev) phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT; phy_rev = (tmp & B43_PHYVER_VERSION); switch (phy_type) { +#ifdef CONFIG_B43_PHY_G case B43_PHYTYPE_G: if (phy_rev > 9) unsupported = 1; break; +#endif #ifdef CONFIG_B43_PHY_N case B43_PHYTYPE_N: if (phy_rev > 9) diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index ce486eeaf8e1..3cbef21b4726 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -46,7 +46,9 @@ int b43_phy_allocate(struct b43_wldev *dev) switch (phy->type) { case B43_PHYTYPE_G: +#ifdef CONFIG_B43_PHY_G phy->ops = &b43_phyops_g; +#endif break; case B43_PHYTYPE_N: #ifdef CONFIG_B43_PHY_N -- cgit v1.2.3 From d6067f0e17eb1de7d9b1d792f67d17c6e894b770 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 20 Jun 2014 22:47:49 +0530 Subject: ath9k: Fix build error in ath_reset_internal drivers/net/wireless/ath/ath9k/main.c:299 ath_reset_internal() error: we previously assumed 'hchan' could be null (see line 293) Cc: Felix Fietkau Reported-by: Dan Carpenter Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cf21652835c1..83cb39efb636 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -314,11 +314,9 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) if (!ath_prepare_reset(sc)) fastcc = false; - if (hchan) { - spin_lock_bh(&sc->chan_lock); - sc->cur_chandef = sc->cur_chan->chandef; - spin_unlock_bh(&sc->chan_lock); - } + spin_lock_bh(&sc->chan_lock); + sc->cur_chandef = sc->cur_chan->chandef; + spin_unlock_bh(&sc->chan_lock); ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", hchan->channel, IS_CHAN_HT40(hchan), fastcc); -- cgit v1.2.3 From a3f5ee71cdec56543e0420a788dc7df335944dd5 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Wed, 18 Jun 2014 16:07:16 +0800 Subject: bridge: use list_for_each_entry_continue_reverse use list_for_each_entry_continue_reverse to rollback in fdb_add_hw when add address failed Signed-off-by: Li RongQing Signed-off-by: David S. Miller --- net/bridge/br_fdb.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index b524c36c1273..7be33667a839 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -93,7 +93,7 @@ static void fdb_rcu_free(struct rcu_head *head) static void fdb_add_hw(struct net_bridge *br, const unsigned char *addr) { int err; - struct net_bridge_port *p, *tmp; + struct net_bridge_port *p; ASSERT_RTNL(); @@ -107,11 +107,9 @@ static void fdb_add_hw(struct net_bridge *br, const unsigned char *addr) return; undo: - list_for_each_entry(tmp, &br->port_list, list) { - if (tmp == p) - break; - if (!br_promisc_port(tmp)) - dev_uc_del(tmp->dev, addr); + list_for_each_entry_continue_reverse(p, &br->port_list, list) { + if (!br_promisc_port(p)) + dev_uc_del(p->dev, addr); } } -- cgit v1.2.3 From 2b74e2caece67798195228775306aa97dbc51516 Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Wed, 18 Jun 2014 16:48:39 +0800 Subject: net: em_canid: remove useless statements from em_canid_change tcf_ematch is allocated by kzalloc in function tcf_em_tree_validate(), so cm_old is always NULL. Signed-off-by: Duan Jiong Signed-off-by: David S. Miller --- net/sched/em_canid.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/net/sched/em_canid.c b/net/sched/em_canid.c index bfd34e4c1afc..7c292d474f47 100644 --- a/net/sched/em_canid.c +++ b/net/sched/em_canid.c @@ -125,7 +125,6 @@ static int em_canid_change(struct tcf_proto *tp, void *data, int len, { struct can_filter *conf = data; /* Array with rules */ struct canid_match *cm; - struct canid_match *cm_old = (struct canid_match *)m->data; int i; if (!len) @@ -181,12 +180,6 @@ static int em_canid_change(struct tcf_proto *tp, void *data, int len, m->datalen = sizeof(struct canid_match) + len; m->data = (unsigned long)cm; - - if (cm_old != NULL) { - pr_err("canid: Configuring an existing ematch!\n"); - kfree(cm_old); - } - return 0; } -- cgit v1.2.3 From 9f8b93cb32e088d3377c86fabb666b884bac0f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Sch=C3=B6lling?= Date: Sun, 22 Jun 2014 13:24:54 +0200 Subject: xilinx: Fix compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The time comparsion functions require arguments of type unsigned long instead of (signed) long. Signed-off-by: Manuel Schölling Signed-off-by: David S. Miller --- drivers/net/ethernet/xilinx/ll_temac_main.c | 2 +- drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c | 2 +- drivers/net/ethernet/xilinx/xilinx_emaclite.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index 4ef818a7a6c6..8a6e5c2d6f95 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -72,7 +72,7 @@ void temac_iow(struct temac_local *lp, int offset, u32 value) int temac_indirect_busywait(struct temac_local *lp) { - long end = jiffies + 2; + unsigned long end = jiffies + 2; while (!(temac_ior(lp, XTE_RDY0_OFFSET) & XTE_RDY0_HARD_ACS_RDY_MASK)) { if (time_before_eq(end, jiffies)) { diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c index d4abf478e2bb..3b67d60d4378 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c @@ -19,7 +19,7 @@ /* Wait till MDIO interface is ready to accept a new transaction.*/ int axienet_mdio_wait_until_ready(struct axienet_local *lp) { - long end = jiffies + 2; + unsigned long end = jiffies + 2; while (!(axienet_ior(lp, XAE_MDIO_MCR_OFFSET) & XAE_MDIO_MCR_READY_MASK)) { if (time_before_eq(end, jiffies)) { diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c index 8c4aed3053eb..782bb9373cd8 100644 --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c @@ -695,7 +695,7 @@ static irqreturn_t xemaclite_interrupt(int irq, void *dev_id) static int xemaclite_mdio_wait(struct net_local *lp) { - long end = jiffies + 2; + unsigned long end = jiffies + 2; /* wait for the MDIO interface to not be busy or timeout after some time. -- cgit v1.2.3 From 989594e2f28df8ec83a41cd08c5ce5dc1072e251 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Thu, 19 Jun 2014 21:37:11 -0700 Subject: cxgb4 : Update fw interface file for DCBx support. Adds all the required fields to fw interface to communicate DCBx info Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 95 +++++++++++++++++++++------ 1 file changed, 76 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 9cc973fbcf26..e83c94bbac41 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -46,9 +46,11 @@ enum fw_retval { FW_EFAULT = 14, /* bad address; fw bad */ FW_EBUSY = 16, /* resource busy */ FW_EEXIST = 17, /* file exists */ + FW_ENODEV = 19, /* no such device */ FW_EINVAL = 22, /* invalid argument */ FW_ENOSPC = 28, /* no space left on device */ FW_ENOSYS = 38, /* functionality not implemented */ + FW_ENODATA = 61, /* no data available */ FW_EPROTO = 71, /* protocol error */ FW_EADDRINUSE = 98, /* address already in use */ FW_EADDRNOTAVAIL = 99, /* cannot assigned requested address */ @@ -989,6 +991,7 @@ enum fw_params_param_dmaq { FW_PARAMS_PARAM_DMAQ_EQ_CMPLIQID_MNGT = 0x10, FW_PARAMS_PARAM_DMAQ_EQ_CMPLIQID_CTRL = 0x11, FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH = 0x12, + FW_PARAMS_PARAM_DMAQ_EQ_DCBPRIO_ETH = 0x13, }; #define FW_PARAMS_MNEM(x) ((x) << 24) @@ -1422,6 +1425,7 @@ struct fw_vi_enable_cmd { #define FW_VI_ENABLE_CMD_VIID(x) ((x) << 0) #define FW_VI_ENABLE_CMD_IEN(x) ((x) << 31) #define FW_VI_ENABLE_CMD_EEN(x) ((x) << 30) +#define FW_VI_ENABLE_CMD_DCB_INFO(x) ((x) << 28) #define FW_VI_ENABLE_CMD_LED (1U << 29) /* VI VF stats offset definitions */ @@ -1594,6 +1598,9 @@ enum fw_port_action { FW_PORT_ACTION_GET_PORT_INFO = 0x0003, FW_PORT_ACTION_L2_PPP_CFG = 0x0004, FW_PORT_ACTION_L2_DCB_CFG = 0x0005, + FW_PORT_ACTION_DCB_READ_TRANS = 0x0006, + FW_PORT_ACTION_DCB_READ_RECV = 0x0007, + FW_PORT_ACTION_DCB_READ_DET = 0x0008, FW_PORT_ACTION_LOW_PWR_TO_NORMAL = 0x0010, FW_PORT_ACTION_L1_LOW_PWR_EN = 0x0011, FW_PORT_ACTION_L2_WOL_MODE_EN = 0x0012, @@ -1637,6 +1644,14 @@ enum fw_port_dcb_type { FW_PORT_DCB_TYPE_PRIORATE = 0x02, FW_PORT_DCB_TYPE_PFC = 0x03, FW_PORT_DCB_TYPE_APP_ID = 0x04, + FW_PORT_DCB_TYPE_CONTROL = 0x05, +}; + +enum fw_port_dcb_feature_state { + FW_PORT_DCB_FEATURE_STATE_PENDING = 0x0, + FW_PORT_DCB_FEATURE_STATE_SUCCESS = 0x1, + FW_PORT_DCB_FEATURE_STATE_ERROR = 0x2, + FW_PORT_DCB_FEATURE_STATE_TIMEOUT = 0x3, }; struct fw_port_cmd { @@ -1648,9 +1663,11 @@ struct fw_port_cmd { __be32 r; } l1cfg; struct fw_port_l2cfg { - __be16 ctlbf_to_ivlan0; + __u8 ctlbf; + __u8 ovlan3_to_ivlan0; __be16 ivlantype; - __be32 txipg_pkd; + __be16 txipg_force_pinfo; + __be16 mtu; __be16 ovlan0mask; __be16 ovlan0type; __be16 ovlan1mask; @@ -1666,24 +1683,60 @@ struct fw_port_cmd { __be16 acap; __be16 mtu; __u8 cbllen; - __u8 r9; - __be32 r10; - __be64 r11; + __u8 auxlinfo; + __u8 dcbxdis_pkd; + __u8 r8_lo[3]; + __be64 r9; } info; - struct fw_port_ppp { - __be32 pppen_to_ncsich; - __be32 r11; - } ppp; - struct fw_port_dcb { - __be16 cfg; - u8 up_map; - u8 sf_cfgrc; - __be16 prot_ix; - u8 pe7_to_pe0; - u8 numTCPFCs; - __be32 pgid0_to_pgid7; - __be32 numTCs_oui; - u8 pgpc[8]; + struct fw_port_diags { + __u8 diagop; + __u8 r[3]; + __be32 diagval; + } diags; + union fw_port_dcb { + struct fw_port_dcb_pgid { + __u8 type; + __u8 apply_pkd; + __u8 r10_lo[2]; + __be32 pgid; + __be64 r11; + } pgid; + struct fw_port_dcb_pgrate { + __u8 type; + __u8 apply_pkd; + __u8 r10_lo[5]; + __u8 num_tcs_supported; + __u8 pgrate[8]; + } pgrate; + struct fw_port_dcb_priorate { + __u8 type; + __u8 apply_pkd; + __u8 r10_lo[6]; + __u8 strict_priorate[8]; + } priorate; + struct fw_port_dcb_pfc { + __u8 type; + __u8 pfcen; + __u8 r10[5]; + __u8 max_pfc_tcs; + __be64 r11; + } pfc; + struct fw_port_app_priority { + __u8 type; + __u8 r10[2]; + __u8 idx; + __u8 user_prio_map; + __u8 sel_field; + __be16 protocolid; + __be64 r12; + } app_priority; + struct fw_port_dcb_control { + __u8 type; + __u8 all_syncd_pkd; + __be16 pfc_state_to_app_state; + __be32 r11; + __be64 r12; + } control; } dcb; } u; }; @@ -1720,6 +1773,10 @@ struct fw_port_cmd { #define FW_PORT_CMD_MODTYPE_MASK 0x1f #define FW_PORT_CMD_MODTYPE_GET(x) (((x) >> 0) & FW_PORT_CMD_MODTYPE_MASK) +#define FW_PORT_CMD_DCBXDIS (1U << 7) +#define FW_PORT_CMD_APPLY (1U << 7) +#define FW_PORT_CMD_ALL_SYNCD (1U << 7) + #define FW_PORT_CMD_PPPEN(x) ((x) << 31) #define FW_PORT_CMD_TPSRC(x) ((x) << 28) #define FW_PORT_CMD_NCSISRC(x) ((x) << 24) -- cgit v1.2.3 From 76bcb31efc0685574fb123f7aaa92f8a50c14fd9 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Thu, 19 Jun 2014 21:37:12 -0700 Subject: cxgb4 : Add DCBx support codebase and dcbnl_ops Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 980 +++++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h | 141 ++++ 2 files changed, 1121 insertions(+) create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c new file mode 100644 index 000000000000..39b4a85fceae --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -0,0 +1,980 @@ +/* + * Copyright (C) 2013-2014 Chelsio Communications. All rights reserved. + * + * Written by Anish Bhatt (anish@chelsio.com) + * Casey Leedom (leedom@chelsio.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + */ + +#include "cxgb4.h" + +/* Initialize a port's Data Center Bridging state. Typically used after a + * Link Down event. + */ +void cxgb4_dcb_state_init(struct net_device *dev) +{ + struct port_info *pi = netdev2pinfo(dev); + struct port_dcb_info *dcb = &pi->dcb; + + memset(dcb, 0, sizeof(struct port_dcb_info)); + dcb->state = CXGB4_DCB_STATE_START; +} + +/* Finite State machine for Data Center Bridging. + */ +void cxgb4_dcb_state_fsm(struct net_device *dev, + enum cxgb4_dcb_state_input input) +{ + struct port_info *pi = netdev2pinfo(dev); + struct port_dcb_info *dcb = &pi->dcb; + struct adapter *adap = pi->adapter; + + switch (input) { + case CXGB4_DCB_INPUT_FW_DISABLED: { + /* Firmware tells us it's not doing DCB */ + switch (dcb->state) { + case CXGB4_DCB_STATE_START: { + /* we're going to use Host DCB */ + dcb->state = CXGB4_DCB_STATE_HOST; + dcb->supported = CXGB4_DCBX_HOST_SUPPORT; + dcb->enabled = 1; + break; + } + + case CXGB4_DCB_STATE_HOST: { + /* we're alreaady in Host DCB mode */ + break; + } + + default: + goto bad_state_transition; + } + break; + } + + case CXGB4_DCB_INPUT_FW_ENABLED: { + /* Firmware tells us that it is doing DCB */ + switch (dcb->state) { + case CXGB4_DCB_STATE_START: { + /* we're going to use Firmware DCB */ + dcb->state = CXGB4_DCB_STATE_FW_INCOMPLETE; + dcb->supported = CXGB4_DCBX_FW_SUPPORT; + break; + } + + case CXGB4_DCB_STATE_FW_INCOMPLETE: + case CXGB4_DCB_STATE_FW_ALLSYNCED: { + /* we're alreaady in firmware DCB mode */ + break; + } + + default: + goto bad_state_transition; + } + break; + } + + case CXGB4_DCB_INPUT_FW_INCOMPLETE: { + /* Firmware tells us that its DCB state is incomplete */ + switch (dcb->state) { + case CXGB4_DCB_STATE_FW_INCOMPLETE: { + /* we're already incomplete */ + break; + } + + case CXGB4_DCB_STATE_FW_ALLSYNCED: { + /* We were successfully running with firmware DCB but + * now it's telling us that it's in an "incomplete + * state. We need to reset back to a ground state + * of incomplete. + */ + cxgb4_dcb_state_init(dev); + dcb->state = CXGB4_DCB_STATE_FW_INCOMPLETE; + dcb->supported = CXGB4_DCBX_FW_SUPPORT; + linkwatch_fire_event(dev); + break; + } + + default: + goto bad_state_transition; + } + break; + } + + case CXGB4_DCB_INPUT_FW_ALLSYNCED: { + /* Firmware tells us that its DCB state is complete */ + switch (dcb->state) { + case CXGB4_DCB_STATE_FW_INCOMPLETE: { + dcb->state = CXGB4_DCB_STATE_FW_ALLSYNCED; + dcb->enabled = 1; + linkwatch_fire_event(dev); + break; + } + + case CXGB4_DCB_STATE_FW_ALLSYNCED: { + /* we're already all sync'ed */ + break; + } + + default: + goto bad_state_transition; + } + break; + } + + default: + goto bad_state_input; + } + return; + +bad_state_input: + dev_err(adap->pdev_dev, "cxgb4_dcb_state_fsm: illegal input symbol %d\n", + input); + return; + +bad_state_transition: + dev_err(adap->pdev_dev, "cxgb4_dcb_state_fsm: bad state transition, state = %d, input = %d\n", + dcb->state, input); +} + +/* Handle a DCB/DCBX update message from the firmware. + */ +void cxgb4_dcb_handle_fw_update(struct adapter *adap, + const struct fw_port_cmd *pcmd) +{ + const union fw_port_dcb *fwdcb = &pcmd->u.dcb; + int port = FW_PORT_CMD_PORTID_GET(be32_to_cpu(pcmd->op_to_portid)); + struct net_device *dev = adap->port[port]; + struct port_info *pi = netdev_priv(dev); + struct port_dcb_info *dcb = &pi->dcb; + int dcb_type = pcmd->u.dcb.pgid.type; + + /* Handle Firmware DCB Control messages separately since they drive + * our state machine. + */ + if (dcb_type == FW_PORT_DCB_TYPE_CONTROL) { + enum cxgb4_dcb_state_input input = + ((pcmd->u.dcb.control.all_syncd_pkd & + FW_PORT_CMD_ALL_SYNCD) + ? CXGB4_DCB_STATE_FW_ALLSYNCED + : CXGB4_DCB_STATE_FW_INCOMPLETE); + + cxgb4_dcb_state_fsm(dev, input); + return; + } + + /* It's weird, and almost certainly an error, to get Firmware DCB + * messages when we either haven't been told whether we're going to be + * doing Host or Firmware DCB; and even worse when we've been told + * that we're doing Host DCB! + */ + if (dcb->state == CXGB4_DCB_STATE_START || + dcb->state == CXGB4_DCB_STATE_HOST) { + dev_err(adap->pdev_dev, "Receiving Firmware DCB messages in State %d\n", + dcb->state); + return; + } + + /* Now handle the general Firmware DCB update messages ... + */ + switch (dcb_type) { + case FW_PORT_DCB_TYPE_PGID: + dcb->pgid = be32_to_cpu(fwdcb->pgid.pgid); + dcb->msgs |= CXGB4_DCB_FW_PGID; + break; + + case FW_PORT_DCB_TYPE_PGRATE: + dcb->pg_num_tcs_supported = fwdcb->pgrate.num_tcs_supported; + memcpy(dcb->pgrate, &fwdcb->pgrate.pgrate, + sizeof(dcb->pgrate)); + dcb->msgs |= CXGB4_DCB_FW_PGRATE; + break; + + case FW_PORT_DCB_TYPE_PRIORATE: + memcpy(dcb->priorate, &fwdcb->priorate.strict_priorate, + sizeof(dcb->priorate)); + dcb->msgs |= CXGB4_DCB_FW_PRIORATE; + break; + + case FW_PORT_DCB_TYPE_PFC: + dcb->pfcen = fwdcb->pfc.pfcen; + dcb->pfc_num_tcs_supported = fwdcb->pfc.max_pfc_tcs; + dcb->msgs |= CXGB4_DCB_FW_PFC; + break; + + case FW_PORT_DCB_TYPE_APP_ID: { + const struct fw_port_app_priority *fwap = &fwdcb->app_priority; + int idx = fwap->idx; + struct app_priority *ap = &dcb->app_priority[idx]; + + struct dcb_app app = { + .selector = fwap->sel_field, + .protocol = be16_to_cpu(fwap->protocolid), + .priority = fwap->user_prio_map, + }; + int err; + + err = dcb_setapp(dev, &app); + if (err) + dev_err(adap->pdev_dev, + "Failed DCB Set Application Priority: sel=%d, prot=%d, prio=%d, err=%d\n", + app.selector, app.protocol, app.priority, -err); + + ap->user_prio_map = fwap->user_prio_map; + ap->sel_field = fwap->sel_field; + ap->protocolid = be16_to_cpu(fwap->protocolid); + dcb->msgs |= CXGB4_DCB_FW_APP_ID; + break; + } + + default: + dev_err(adap->pdev_dev, "Unknown DCB update type received %x\n", + dcb_type); + break; + } +} + +/* Data Center Bridging netlink operations. + */ + + +/* Get current DCB enabled/disabled state. + */ +static u8 cxgb4_getstate(struct net_device *dev) +{ + struct port_info *pi = netdev2pinfo(dev); + + return pi->dcb.enabled; +} + +/* Set DCB enabled/disabled. + */ +static u8 cxgb4_setstate(struct net_device *dev, u8 enabled) +{ + struct port_info *pi = netdev2pinfo(dev); + + /* Firmware doesn't provide any mechanism to control the DCB state. + */ + if (enabled != (pi->dcb.state == CXGB4_DCB_STATE_FW_ALLSYNCED)) + return 1; + + return 0; +} + +static void cxgb4_getpgtccfg(struct net_device *dev, int tc, + u8 *prio_type, u8 *pgid, u8 *bw_per, + u8 *up_tc_map, int local) +{ + struct fw_port_cmd pcmd; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = pi->adapter; + int err; + + *prio_type = *pgid = *bw_per = *up_tc_map = 0; + + if (local) + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + else + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + + pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID; + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err); + return; + } + *pgid = (be32_to_cpu(pcmd.u.dcb.pgid.pgid) >> (tc * 4)) & 0xf; + + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE; + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n", + -err); + return; + } + + *bw_per = pcmd.u.dcb.pgrate.pgrate[*pgid]; + *up_tc_map = (1 << tc); + + /* prio_type is link strict */ + *prio_type = 0x2; +} + +static void cxgb4_getpgtccfg_tx(struct net_device *dev, int tc, + u8 *prio_type, u8 *pgid, u8 *bw_per, + u8 *up_tc_map) +{ + return cxgb4_getpgtccfg(dev, tc, prio_type, pgid, bw_per, up_tc_map, 1); +} + + +static void cxgb4_getpgtccfg_rx(struct net_device *dev, int tc, + u8 *prio_type, u8 *pgid, u8 *bw_per, + u8 *up_tc_map) +{ + return cxgb4_getpgtccfg(dev, tc, prio_type, pgid, bw_per, up_tc_map, 0); +} + +static void cxgb4_setpgtccfg_tx(struct net_device *dev, int tc, + u8 prio_type, u8 pgid, u8 bw_per, + u8 up_tc_map) +{ + struct fw_port_cmd pcmd; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = pi->adapter; + u32 _pgid; + int err; + + if (pgid == DCB_ATTR_VALUE_UNDEFINED) + return; + if (bw_per == DCB_ATTR_VALUE_UNDEFINED) + return; + + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID; + + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err); + return; + } + + _pgid = be32_to_cpu(pcmd.u.dcb.pgid.pgid); + _pgid &= ~(0xF << (tc * 4)); + _pgid |= pgid << (tc * 4); + pcmd.u.dcb.pgid.pgid = cpu_to_be32(_pgid); + + INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id); + + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB write PGID failed with %d\n", + -err); + return; + } + + memset(&pcmd, 0, sizeof(struct fw_port_cmd)); + + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE; + + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n", + -err); + return; + } + + pcmd.u.dcb.pgrate.pgrate[pgid] = bw_per; + + INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id); + if (pi->dcb.state == CXGB4_DCB_STATE_HOST) + pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY); + + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) + dev_err(adap->pdev_dev, "DCB write PGRATE failed with %d\n", + -err); +} + +static void cxgb4_getpgbwgcfg(struct net_device *dev, int pgid, u8 *bw_per, + int local) +{ + struct fw_port_cmd pcmd; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = pi->adapter; + int err; + + if (local) + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + else + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + + pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE; + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n", + -err); + } else { + *bw_per = pcmd.u.dcb.pgrate.pgrate[pgid]; + } +} + +static void cxgb4_getpgbwgcfg_tx(struct net_device *dev, int pgid, u8 *bw_per) +{ + return cxgb4_getpgbwgcfg(dev, pgid, bw_per, 1); +} + +static void cxgb4_getpgbwgcfg_rx(struct net_device *dev, int pgid, u8 *bw_per) +{ + return cxgb4_getpgbwgcfg(dev, pgid, bw_per, 0); +} + +static void cxgb4_setpgbwgcfg_tx(struct net_device *dev, int pgid, + u8 bw_per) +{ + struct fw_port_cmd pcmd; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = pi->adapter; + int err; + + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE; + + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n", + -err); + return; + } + + pcmd.u.dcb.pgrate.pgrate[pgid] = bw_per; + + INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id); + if (pi->dcb.state == CXGB4_DCB_STATE_HOST) + pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY); + + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + + if (err != FW_PORT_DCB_CFG_SUCCESS) + dev_err(adap->pdev_dev, "DCB write PGRATE failed with %d\n", + -err); +} + +/* Return whether the specified Traffic Class Priority has Priority Pause + * Frames enabled. + */ +static void cxgb4_getpfccfg(struct net_device *dev, int priority, u8 *pfccfg) +{ + struct port_info *pi = netdev2pinfo(dev); + struct port_dcb_info *dcb = &pi->dcb; + + if (dcb->state != CXGB4_DCB_STATE_FW_ALLSYNCED || + priority >= CXGB4_MAX_PRIORITY) + *pfccfg = 0; + else + *pfccfg = (pi->dcb.pfcen >> priority) & 1; +} + +/* Enable/disable Priority Pause Frames for the specified Traffic Class + * Priority. + */ +static void cxgb4_setpfccfg(struct net_device *dev, int priority, u8 pfccfg) +{ + struct fw_port_cmd pcmd; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = pi->adapter; + int err; + + if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED || + priority >= CXGB4_MAX_PRIORITY) + return; + + INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id); + if (pi->dcb.state == CXGB4_DCB_STATE_HOST) + pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY); + + pcmd.u.dcb.pfc.type = FW_PORT_DCB_TYPE_PFC; + pcmd.u.dcb.pfc.pfcen = cpu_to_be16(pi->dcb.pfcen); + + if (pfccfg) + pcmd.u.dcb.pfc.pfcen |= cpu_to_be16(1 << priority); + else + pcmd.u.dcb.pfc.pfcen &= cpu_to_be16(~(1 << priority)); + + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB PFC write failed with %d\n", -err); + return; + } + + pi->dcb.pfcen = be16_to_cpu(pcmd.u.dcb.pfc.pfcen); +} + +static u8 cxgb4_setall(struct net_device *dev) +{ + return 0; +} + +/* Return DCB capabilities. + */ +static u8 cxgb4_getcap(struct net_device *dev, int cap_id, u8 *caps) +{ + struct port_info *pi = netdev2pinfo(dev); + + switch (cap_id) { + case DCB_CAP_ATTR_PG: + case DCB_CAP_ATTR_PFC: + *caps = true; + break; + + case DCB_CAP_ATTR_PG_TCS: + /* 8 priorities for PG represented by bitmap */ + *caps = 0x80; + break; + + case DCB_CAP_ATTR_PFC_TCS: + /* 8 priorities for PFC represented by bitmap */ + *caps = 0x80; + break; + + case DCB_CAP_ATTR_GSP: + *caps = true; + break; + + case DCB_CAP_ATTR_UP2TC: + case DCB_CAP_ATTR_BCN: + *caps = false; + break; + + case DCB_CAP_ATTR_DCBX: + *caps = pi->dcb.supported; + break; + + default: + *caps = false; + } + + return 0; +} + +/* Return the number of Traffic Classes for the indicated Traffic Class ID. + */ +static int cxgb4_getnumtcs(struct net_device *dev, int tcs_id, u8 *num) +{ + struct port_info *pi = netdev2pinfo(dev); + + switch (tcs_id) { + case DCB_NUMTCS_ATTR_PG: + if (pi->dcb.msgs & CXGB4_DCB_FW_PGRATE) + *num = pi->dcb.pg_num_tcs_supported; + else + *num = 0x8; + break; + + case DCB_NUMTCS_ATTR_PFC: + *num = 0x8; + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* Set the number of Traffic Classes supported for the indicated Traffic Class + * ID. + */ +static int cxgb4_setnumtcs(struct net_device *dev, int tcs_id, u8 num) +{ + /* Setting the number of Traffic Classes isn't supported. + */ + return -ENOSYS; +} + +/* Return whether Priority Flow Control is enabled. */ +static u8 cxgb4_getpfcstate(struct net_device *dev) +{ + struct port_info *pi = netdev2pinfo(dev); + + if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + return false; + + return pi->dcb.pfcen != 0; +} + +/* Enable/disable Priority Flow Control. */ +static void cxgb4_setpfcstate(struct net_device *dev, u8 state) +{ + /* We can't enable/disable Priority Flow Control but we also can't + * return an error ... + */ +} + +/* Return the Application User Priority Map associated with the specified + * Application ID. + */ +static int __cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id, + int peer) +{ + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = pi->adapter; + int i; + + if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + return 0; + + for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) { + struct fw_port_cmd pcmd; + int err; + + if (peer) + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + else + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + + pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID; + pcmd.u.dcb.app_priority.idx = i; + + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB APP read failed with %d\n", + -err); + return err; + } + if (be16_to_cpu(pcmd.u.dcb.app_priority.protocolid) == app_id) + return pcmd.u.dcb.app_priority.user_prio_map; + + /* exhausted app list */ + if (!pcmd.u.dcb.app_priority.protocolid) + break; + } + + return -EEXIST; +} + +/* Return the Application User Priority Map associated with the specified + * Application ID. Since this routine is prototyped to return "u8" we can't + * return errors ... + */ +static u8 cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id) +{ + int result = __cxgb4_getapp(dev, app_idtype, app_id, 0); + + if (result < 0) + result = 0; + + return result; +} + +/* Write a new Application User Priority Map for the specified Application ID. + * This routine is prototyped to return "u8" but other instantiations of the + * DCB NetLink Operations "setapp" routines return negative errnos for errors. + * We follow their lead. + */ +static u8 cxgb4_setapp(struct net_device *dev, u8 app_idtype, u16 app_id, + u8 app_prio) +{ + struct fw_port_cmd pcmd; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = pi->adapter; + int i, err; + + + if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + return -EINVAL; + + /* DCB info gets thrown away on link up */ + if (!netif_carrier_ok(dev)) + return -ENOLINK; + + if (app_idtype != DCB_APP_IDTYPE_ETHTYPE && + app_idtype != DCB_APP_IDTYPE_PORTNUM) + return -EINVAL; + + for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) { + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID; + pcmd.u.dcb.app_priority.idx = i; + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB app table read failed with %d\n", + -err); + return err; + } + if (be16_to_cpu(pcmd.u.dcb.app_priority.protocolid) == app_id) { + /* overwrite existing app table */ + pcmd.u.dcb.app_priority.protocolid = 0; + break; + } + /* find first empty slot */ + if (!pcmd.u.dcb.app_priority.protocolid) + break; + } + + if (i == CXGB4_MAX_DCBX_APP_SUPPORTED) { + /* no empty slots available */ + dev_err(adap->pdev_dev, "DCB app table full\n"); + return -EBUSY; + } + + /* write out new app table entry */ + INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id); + if (pi->dcb.state == CXGB4_DCB_STATE_HOST) + pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY); + + pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID; + pcmd.u.dcb.app_priority.protocolid = cpu_to_be16(app_id); + pcmd.u.dcb.app_priority.sel_field = app_idtype; + pcmd.u.dcb.app_priority.user_prio_map = app_prio; + pcmd.u.dcb.app_priority.idx = i; + + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB app table write failed with %d\n", + -err); + return err; + } + + return 0; +} + +/* Return whether IEEE Data Center Bridging has been negotiated. + */ +static inline int cxgb4_ieee_negotiation_complete(struct net_device *dev) +{ + struct port_info *pi = netdev2pinfo(dev); + struct port_dcb_info *dcb = &pi->dcb; + + return (dcb->state == CXGB4_DCB_STATE_FW_ALLSYNCED && + (dcb->supported & DCB_CAP_DCBX_VER_IEEE)); +} + +/* Fill in the Application User Priority Map associated with the + * specified Application. + */ +static int cxgb4_ieee_getapp(struct net_device *dev, struct dcb_app *app) +{ + int prio; + + if (!cxgb4_ieee_negotiation_complete(dev)) + return -EINVAL; + if (!(app->selector && app->protocol)) + return -EINVAL; + + prio = dcb_getapp(dev, app); + if (prio == 0) { + /* If app doesn't exist in dcb_app table, try firmware + * directly. + */ + prio = __cxgb4_getapp(dev, app->selector, app->protocol, 0); + } + + app->priority = prio; + return 0; +} + +/* Write a new Application User Priority Map for the specified App id. */ +static int cxgb4_ieee_setapp(struct net_device *dev, struct dcb_app *app) +{ + if (!cxgb4_ieee_negotiation_complete(dev)) + return -EINVAL; + if (!(app->selector && app->protocol && app->priority)) + return -EINVAL; + + cxgb4_setapp(dev, app->selector, app->protocol, app->priority); + return dcb_setapp(dev, app); +} + +/* Return our DCBX parameters. + */ +static u8 cxgb4_getdcbx(struct net_device *dev) +{ + struct port_info *pi = netdev2pinfo(dev); + + /* This is already set by cxgb4_set_dcb_caps, so just return it */ + return pi->dcb.supported; +} + +/* Set our DCBX parameters. + */ +static u8 cxgb4_setdcbx(struct net_device *dev, u8 dcb_request) +{ + struct port_info *pi = netdev2pinfo(dev); + + /* Filter out requests which exceed our capabilities. + */ + if ((dcb_request & (CXGB4_DCBX_FW_SUPPORT | CXGB4_DCBX_HOST_SUPPORT)) + != dcb_request) + return 1; + + /* Can't set DCBX capabilities if DCBX isn't enabled. */ + if (!pi->dcb.state) + return 1; + + /* There's currently no mechanism to allow for the firmware DCBX + * negotiation to be changed from the Host Driver. If the caller + * requests exactly the same parameters that we already have then + * we'll allow them to be successfully "set" ... + */ + if (dcb_request != pi->dcb.supported) + return 1; + + pi->dcb.supported = dcb_request; + return 0; +} + +static int cxgb4_getpeer_app(struct net_device *dev, + struct dcb_peer_app_info *info, u16 *app_count) +{ + struct fw_port_cmd pcmd; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = pi->adapter; + int i, err = 0; + + if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + return 1; + + info->willing = 0; + info->error = 0; + + *app_count = 0; + for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) { + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID; + pcmd.u.dcb.app_priority.idx = *app_count; + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB app table read failed with %d\n", + -err); + return err; + } + + /* find first empty slot */ + if (!pcmd.u.dcb.app_priority.protocolid) + break; + } + *app_count = i; + return err; +} + +static int cxgb4_getpeerapp_tbl(struct net_device *dev, struct dcb_app *table) +{ + struct fw_port_cmd pcmd; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = pi->adapter; + int i, err = 0; + + if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + return 1; + + for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) { + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID; + pcmd.u.dcb.app_priority.idx = i; + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB app table read failed with %d\n", + -err); + return err; + } + + /* find first empty slot */ + if (!pcmd.u.dcb.app_priority.protocolid) + break; + + table[i].selector = pcmd.u.dcb.app_priority.sel_field; + table[i].protocol = + be16_to_cpu(pcmd.u.dcb.app_priority.protocolid); + table[i].priority = pcmd.u.dcb.app_priority.user_prio_map; + } + return err; +} + +/* Return Priority Group information. + */ +static int cxgb4_cee_peer_getpg(struct net_device *dev, struct cee_pg *pg) +{ + struct fw_port_cmd pcmd; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = pi->adapter; + u32 pgid; + int i, err; + + /* We're always "willing" -- the Switch Fabric always dictates the + * DCBX parameters to us. + */ + pg->willing = true; + + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID; + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err); + return err; + } + pgid = be32_to_cpu(pcmd.u.dcb.pgid.pgid); + + for (i = 0; i < CXGB4_MAX_PRIORITY; i++) + pg->prio_pg[i] = (pgid >> (i * 4)) & 0xF; + + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE; + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n", + -err); + return err; + } + + for (i = 0; i < CXGB4_MAX_PRIORITY; i++) + pg->pg_bw[i] = pcmd.u.dcb.pgrate.pgrate[i]; + + return 0; +} + +/* Return Priority Flow Control information. + */ +static int cxgb4_cee_peer_getpfc(struct net_device *dev, struct cee_pfc *pfc) +{ + struct port_info *pi = netdev2pinfo(dev); + + cxgb4_getnumtcs(dev, DCB_NUMTCS_ATTR_PFC, &(pfc->tcs_supported)); + pfc->pfc_en = pi->dcb.pfcen; + + return 0; +} + +const struct dcbnl_rtnl_ops cxgb4_dcb_ops = { + .ieee_getapp = cxgb4_ieee_getapp, + .ieee_setapp = cxgb4_ieee_setapp, + + /* CEE std */ + .getstate = cxgb4_getstate, + .setstate = cxgb4_setstate, + .getpgtccfgtx = cxgb4_getpgtccfg_tx, + .getpgbwgcfgtx = cxgb4_getpgbwgcfg_tx, + .getpgtccfgrx = cxgb4_getpgtccfg_rx, + .getpgbwgcfgrx = cxgb4_getpgbwgcfg_rx, + .setpgtccfgtx = cxgb4_setpgtccfg_tx, + .setpgbwgcfgtx = cxgb4_setpgbwgcfg_tx, + .setpfccfg = cxgb4_setpfccfg, + .getpfccfg = cxgb4_getpfccfg, + .setall = cxgb4_setall, + .getcap = cxgb4_getcap, + .getnumtcs = cxgb4_getnumtcs, + .setnumtcs = cxgb4_setnumtcs, + .getpfcstate = cxgb4_getpfcstate, + .setpfcstate = cxgb4_setpfcstate, + .getapp = cxgb4_getapp, + .setapp = cxgb4_setapp, + + /* DCBX configuration */ + .getdcbx = cxgb4_getdcbx, + .setdcbx = cxgb4_setdcbx, + + /* peer apps */ + .peer_getappinfo = cxgb4_getpeer_app, + .peer_getapptable = cxgb4_getpeerapp_tbl, + + /* CEE peer */ + .cee_peer_getpg = cxgb4_cee_peer_getpg, + .cee_peer_getpfc = cxgb4_cee_peer_getpfc, +}; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h new file mode 100644 index 000000000000..1ec1d834e257 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2013-2014 Chelsio Communications. All rights reserved. + * + * Written by Anish Bhatt (anish@chelsio.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + */ + +#ifndef __CXGB4_DCB_H +#define __CXGB4_DCB_H + +#include +#include +#include + +#ifdef CONFIG_CHELSIO_T4_DCB + +#define CXGB4_DCBX_FW_SUPPORT \ + (DCB_CAP_DCBX_VER_CEE | \ + DCB_CAP_DCBX_VER_IEEE | \ + DCB_CAP_DCBX_LLD_MANAGED) +#define CXGB4_DCBX_HOST_SUPPORT \ + (DCB_CAP_DCBX_VER_CEE | \ + DCB_CAP_DCBX_VER_IEEE | \ + DCB_CAP_DCBX_HOST) + +#define CXGB4_MAX_PRIORITY CXGB4_MAX_DCBX_APP_SUPPORTED +#define CXGB4_MAX_TCS CXGB4_MAX_DCBX_APP_SUPPORTED + +#define INIT_PORT_DCB_CMD(__pcmd, __port, __op, __action) \ + do { \ + memset(&(__pcmd), 0, sizeof(__pcmd)); \ + (__pcmd).op_to_portid = \ + cpu_to_be32(FW_CMD_OP(FW_PORT_CMD) | \ + FW_CMD_REQUEST | \ + FW_CMD_##__op | \ + FW_PORT_CMD_PORTID(__port)); \ + (__pcmd).action_to_len16 = \ + cpu_to_be32(FW_PORT_CMD_ACTION(__action) | \ + FW_LEN16(pcmd)); \ + } while (0) + +#define INIT_PORT_DCB_READ_PEER_CMD(__pcmd, __port) \ + INIT_PORT_DCB_CMD(__pcmd, __port, READ, FW_PORT_ACTION_DCB_READ_RECV) + +#define INIT_PORT_DCB_READ_LOCAL_CMD(__pcmd, __port) \ + INIT_PORT_DCB_CMD(__pcmd, __port, READ, FW_PORT_ACTION_DCB_READ_TRANS) + +#define INIT_PORT_DCB_READ_SYNC_CMD(__pcmd, __port) \ + INIT_PORT_DCB_CMD(__pcmd, __port, READ, FW_PORT_ACTION_DCB_READ_DET) + +#define INIT_PORT_DCB_WRITE_CMD(__pcmd, __port) \ + INIT_PORT_DCB_CMD(__pcmd, __port, EXEC, FW_PORT_ACTION_L2_DCB_CFG) + +/* States we can be in for a port's Data Center Bridging. + */ +enum cxgb4_dcb_state { + CXGB4_DCB_STATE_START, /* initial unknown state */ + CXGB4_DCB_STATE_HOST, /* we're using Host DCB (if at all) */ + CXGB4_DCB_STATE_FW_INCOMPLETE, /* using firmware DCB, incomplete */ + CXGB4_DCB_STATE_FW_ALLSYNCED, /* using firmware DCB, all sync'ed */ +}; + +/* Data Center Bridging state input for the Finite State Machine. + */ +enum cxgb4_dcb_state_input { + /* Input from the firmware. + */ + CXGB4_DCB_INPUT_FW_DISABLED, /* firmware DCB disabled */ + CXGB4_DCB_INPUT_FW_ENABLED, /* firmware DCB enabled */ + CXGB4_DCB_INPUT_FW_INCOMPLETE, /* firmware reports incomplete DCB */ + CXGB4_DCB_INPUT_FW_ALLSYNCED, /* firmware reports all sync'ed */ + +}; + +/* Firmware DCB messages that we've received so far ... + */ +enum cxgb4_dcb_fw_msgs { + CXGB4_DCB_FW_PGID = 0x01, + CXGB4_DCB_FW_PGRATE = 0x02, + CXGB4_DCB_FW_PRIORATE = 0x04, + CXGB4_DCB_FW_PFC = 0x08, + CXGB4_DCB_FW_APP_ID = 0x10, +}; + +#define CXGB4_MAX_DCBX_APP_SUPPORTED 8 + +/* Data Center Bridging support; + */ +struct port_dcb_info { + enum cxgb4_dcb_state state; /* DCB State Machine */ + enum cxgb4_dcb_fw_msgs msgs; /* DCB Firmware messages received */ + unsigned int supported; /* OS DCB capabilities supported */ + bool enabled; /* OS Enabled state */ + + /* Cached copies of DCB information sent by the firmware (in Host + * Native Endian format). + */ + u32 pgid; /* Priority Group[0..7] */ + u8 pfcen; /* Priority Flow Control[0..7] */ + u8 pg_num_tcs_supported; /* max PG Traffic Classes */ + u8 pfc_num_tcs_supported; /* max PFC Traffic Classes */ + u8 pgrate[8]; /* Priority Group Rate[0..7] */ + u8 priorate[8]; /* Priority Rate[0..7] */ + struct app_priority { /* Application Information */ + u8 user_prio_map; /* Priority Map bitfield */ + u8 sel_field; /* Protocol ID interpretation */ + u16 protocolid; /* Protocol ID */ + } app_priority[CXGB4_MAX_DCBX_APP_SUPPORTED]; +}; + +void cxgb4_dcb_state_init(struct net_device *); +void cxgb4_dcb_state_fsm(struct net_device *, enum cxgb4_dcb_state_input); +void cxgb4_dcb_handle_fw_update(struct adapter *, const struct fw_port_cmd *); +void cxgb4_dcb_set_caps(struct adapter *, const struct fw_port_cmd *); +extern const struct dcbnl_rtnl_ops cxgb4_dcb_ops; + +#define CXGB4_DCB_ENABLED true + +#else /* !CONFIG_CHELSIO_T4_DCB */ + +static inline void cxgb4_dcb_state_init(struct net_device *dev) +{ +} + +#define CXGB4_DCB_ENABLED false + +#endif /* !CONFIG_CHELSIO_T4_DCB */ + +#endif /* __CXGB4_DCB_H */ -- cgit v1.2.3 From 688848b1493a0a55059041dcc1ea332dabd1c75d Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Thu, 19 Jun 2014 21:37:13 -0700 Subject: cxgb4 : Integrate DCBx support into cxgb4 module. Register dbcnl_ops to give access to DCBx functions Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 11 ++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 199 +++++++++++++++++++++++- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 76 ++++++++- 3 files changed, 272 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index f503dce4ab17..9d69c3ebbf00 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -373,6 +373,8 @@ enum { struct adapter; struct sge_rspq; +#include "cxgb4_dcb.h" + struct port_info { struct adapter *adapter; u16 viid; @@ -389,6 +391,9 @@ struct port_info { u8 rss_mode; struct link_config link_cfg; u16 *rss; +#ifdef CONFIG_CHELSIO_T4_DCB + struct port_dcb_info dcb; /* Data Center Bridging support */ +#endif }; struct dentry; @@ -1007,6 +1012,10 @@ int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int nparams, const u32 *params, const u32 *val); +int t4_set_params_nosleep(struct adapter *adap, unsigned int mbox, + unsigned int pf, unsigned int vf, + unsigned int nparams, const u32 *params, + const u32 *val); int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl, unsigned int rxqi, unsigned int rxq, unsigned int tc, @@ -1025,6 +1034,8 @@ int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, int idx, const u8 *addr, bool persist, bool add_smt); int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, bool ucast, u64 vec, bool sleep_ok); +int t4_enable_vi_params(struct adapter *adap, unsigned int mbox, + unsigned int viid, bool rx_en, bool tx_en, bool dcb_en); int t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid, bool rx_en, bool tx_en); int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 2f8d6b910383..74b0ce50a8ef 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -67,6 +67,7 @@ #include "t4_regs.h" #include "t4_msg.h" #include "t4fw_api.h" +#include "cxgb4_dcb.h" #include "l2t.h" #include <../drivers/net/bonding/bonding.h> @@ -391,6 +392,17 @@ module_param_array(num_vf, uint, NULL, 0644); MODULE_PARM_DESC(num_vf, "number of VFs for each of PFs 0-3"); #endif +/* TX Queue select used to determine what algorithm to use for selecting TX + * queue. Select between the kernel provided function (select_queue=0) or user + * cxgb_select_queue function (select_queue=1) + * + * Default: select_queue=0 + */ +static int select_queue; +module_param(select_queue, int, 0644); +MODULE_PARM_DESC(select_queue, + "Select between kernel provided method of selecting or driver method of selecting TX queue. Default is kernel method."); + /* * The filter TCAM has a fixed portion and a variable portion. The fixed * portion can match on source/destination IP IPv4/IPv6 addresses and TCP/UDP @@ -458,6 +470,42 @@ static void link_report(struct net_device *dev) } } +#ifdef CONFIG_CHELSIO_T4_DCB +/* Set up/tear down Data Center Bridging Priority mapping for a net device. */ +static void dcb_tx_queue_prio_enable(struct net_device *dev, int enable) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + struct sge_eth_txq *txq = &adap->sge.ethtxq[pi->first_qset]; + int i; + + /* We use a simple mapping of Port TX Queue Index to DCB + * Priority when we're enabling DCB. + */ + for (i = 0; i < pi->nqsets; i++, txq++) { + u32 name, value; + int err; + + name = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | + FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_DCBPRIO_ETH) | + FW_PARAMS_PARAM_YZ(txq->q.cntxt_id)); + value = enable ? i : 0xffffffff; + + /* Since we can be called while atomic (from "interrupt + * level") we need to issue the Set Parameters Commannd + * without sleeping (timeout < 0). + */ + err = t4_set_params_nosleep(adap, adap->mbox, adap->fn, 0, 1, + &name, &value); + + if (err) + dev_err(adap->pdev_dev, + "Can't %s DCB Priority on port %d, TX Queue %d: err=%d\n", + enable ? "set" : "unset", pi->port_id, i, -err); + } +} +#endif /* CONFIG_CHELSIO_T4_DCB */ + void t4_os_link_changed(struct adapter *adapter, int port_id, int link_stat) { struct net_device *dev = adapter->port[port_id]; @@ -466,8 +514,13 @@ void t4_os_link_changed(struct adapter *adapter, int port_id, int link_stat) if (netif_running(dev) && link_stat != netif_carrier_ok(dev)) { if (link_stat) netif_carrier_on(dev); - else + else { +#ifdef CONFIG_CHELSIO_T4_DCB + cxgb4_dcb_state_init(dev); + dcb_tx_queue_prio_enable(dev, false); +#endif /* CONFIG_CHELSIO_T4_DCB */ netif_carrier_off(dev); + } link_report(dev); } @@ -601,10 +654,45 @@ static int link_start(struct net_device *dev) ret = t4_link_start(pi->adapter, mb, pi->tx_chan, &pi->link_cfg); if (ret == 0) - ret = t4_enable_vi(pi->adapter, mb, pi->viid, true, true); + ret = t4_enable_vi_params(pi->adapter, mb, pi->viid, true, + true, CXGB4_DCB_ENABLED); + return ret; } +int cxgb4_dcb_enabled(const struct net_device *dev) +{ +#ifdef CONFIG_CHELSIO_T4_DCB + struct port_info *pi = netdev_priv(dev); + + return pi->dcb.state == CXGB4_DCB_STATE_FW_ALLSYNCED; +#else + return 0; +#endif +} +EXPORT_SYMBOL(cxgb4_dcb_enabled); + +#ifdef CONFIG_CHELSIO_T4_DCB +/* Handle a Data Center Bridging update message from the firmware. */ +static void dcb_rpl(struct adapter *adap, const struct fw_port_cmd *pcmd) +{ + int port = FW_PORT_CMD_PORTID_GET(ntohl(pcmd->op_to_portid)); + struct net_device *dev = adap->port[port]; + int old_dcb_enabled = cxgb4_dcb_enabled(dev); + int new_dcb_enabled; + + cxgb4_dcb_handle_fw_update(adap, pcmd); + new_dcb_enabled = cxgb4_dcb_enabled(dev); + + /* If the DCB has become enabled or disabled on the port then we're + * going to need to set up/tear down DCB Priority parameters for the + * TX Queues associated with the port. + */ + if (new_dcb_enabled != old_dcb_enabled) + dcb_tx_queue_prio_enable(dev, new_dcb_enabled); +} +#endif /* CONFIG_CHELSIO_T4_DCB */ + /* Clear a filter and release any of its resources that we own. This also * clears the filter's "pending" status. */ @@ -709,8 +797,32 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp, } else if (opcode == CPL_FW6_MSG || opcode == CPL_FW4_MSG) { const struct cpl_fw6_msg *p = (void *)rsp; - if (p->type == 0) - t4_handle_fw_rpl(q->adap, p->data); +#ifdef CONFIG_CHELSIO_T4_DCB + const struct fw_port_cmd *pcmd = (const void *)p->data; + unsigned int cmd = FW_CMD_OP_GET(ntohl(pcmd->op_to_portid)); + unsigned int action = + FW_PORT_CMD_ACTION_GET(ntohl(pcmd->action_to_len16)); + + if (cmd == FW_PORT_CMD && + action == FW_PORT_ACTION_GET_PORT_INFO) { + int port = FW_PORT_CMD_PORTID_GET( + be32_to_cpu(pcmd->op_to_portid)); + struct net_device *dev = q->adap->port[port]; + int state_input = ((pcmd->u.info.dcbxdis_pkd & + FW_PORT_CMD_DCBXDIS) + ? CXGB4_DCB_INPUT_FW_DISABLED + : CXGB4_DCB_INPUT_FW_ENABLED); + + cxgb4_dcb_state_fsm(dev, state_input); + } + + if (cmd == FW_PORT_CMD && + action == FW_PORT_ACTION_L2_DCB_CFG) + dcb_rpl(q->adap, pcmd); + else +#endif + if (p->type == 0) + t4_handle_fw_rpl(q->adap, p->data); } else if (opcode == CPL_L2T_WRITE_RPL) { const struct cpl_l2t_write_rpl *p = (void *)rsp; @@ -1290,6 +1402,48 @@ static int del_filter_wr(struct adapter *adapter, int fidx) return 0; } +static u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback) +{ + int txq; + +#ifdef CONFIG_CHELSIO_T4_DCB + /* If a Data Center Bridging has been successfully negotiated on this + * link then we'll use the skb's priority to map it to a TX Queue. + * The skb's priority is determined via the VLAN Tag Priority Code + * Point field. + */ + if (cxgb4_dcb_enabled(dev)) { + u16 vlan_tci; + int err; + + err = vlan_get_tag(skb, &vlan_tci); + if (unlikely(err)) { + if (net_ratelimit()) + netdev_warn(dev, + "TX Packet without VLAN Tag on DCB Link\n"); + txq = 0; + } else { + txq = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; + } + return txq; + } +#endif /* CONFIG_CHELSIO_T4_DCB */ + + if (select_queue) { + txq = (skb_rx_queue_recorded(skb) + ? skb_get_rx_queue(skb) + : smp_processor_id()); + + while (unlikely(txq >= dev->real_num_tx_queues)) + txq -= dev->real_num_tx_queues; + + return txq; + } + + return fallback(dev, skb) % dev->real_num_tx_queues; +} + static inline int is_offload(const struct adapter *adap) { return adap->params.offload; @@ -4601,6 +4755,7 @@ static const struct net_device_ops cxgb4_netdev_ops = { .ndo_open = cxgb_open, .ndo_stop = cxgb_close, .ndo_start_xmit = t4_eth_xmit, + .ndo_select_queue = cxgb_select_queue, .ndo_get_stats64 = cxgb_get_stats, .ndo_set_rx_mode = cxgb_set_rxmode, .ndo_set_mac_address = cxgb_set_mac_addr, @@ -5841,12 +5996,33 @@ static inline void init_rspq(struct adapter *adap, struct sge_rspq *q, static void cfg_queues(struct adapter *adap) { struct sge *s = &adap->sge; - int i, q10g = 0, n10g = 0, qidx = 0; + int i, n10g = 0, qidx = 0; +#ifndef CONFIG_CHELSIO_T4_DCB + int q10g = 0; +#endif int ciq_size; for_each_port(adap, i) n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg); +#ifdef CONFIG_CHELSIO_T4_DCB + /* For Data Center Bridging support we need to be able to support up + * to 8 Traffic Priorities; each of which will be assigned to its + * own TX Queue in order to prevent Head-Of-Line Blocking. + */ + if (adap->params.nports * 8 > MAX_ETH_QSETS) { + dev_err(adap->pdev_dev, "MAX_ETH_QSETS=%d < %d!\n", + MAX_ETH_QSETS, adap->params.nports * 8); + BUG_ON(1); + } + for_each_port(adap, i) { + struct port_info *pi = adap2pinfo(adap, i); + + pi->first_qset = qidx; + pi->nqsets = 8; + qidx += pi->nqsets; + } +#else /* !CONFIG_CHELSIO_T4_DCB */ /* * We default to 1 queue per non-10G port and up to # of cores queues * per 10G port. @@ -5863,6 +6039,7 @@ static void cfg_queues(struct adapter *adap) pi->nqsets = is_x_10g_port(&pi->link_cfg) ? q10g : 1; qidx += pi->nqsets; } +#endif /* !CONFIG_CHELSIO_T4_DCB */ s->ethqsets = qidx; s->max_ethqsets = qidx; /* MSI-X may lower it later */ @@ -5981,8 +6158,14 @@ static int enable_msix(struct adapter *adap) /* need nchan for each possible ULD */ ofld_need = 3 * nchan; } +#ifdef CONFIG_CHELSIO_T4_DCB + /* For Data Center Bridging we need 8 Ethernet TX Priority Queues for + * each port. + */ + need = 8 * adap->params.nports + EXTRA_VECS + ofld_need; +#else need = adap->params.nports + EXTRA_VECS + ofld_need; - +#endif want = pci_enable_msix_range(adap->pdev, entries, need, want); if (want < 0) return want; @@ -6245,6 +6428,10 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->priv_flags |= IFF_UNICAST_FLT; netdev->netdev_ops = &cxgb4_netdev_ops; +#ifdef CONFIG_CHELSIO_T4_DCB + netdev->dcbnl_ops = &cxgb4_dcb_ops; + cxgb4_dcb_state_init(netdev); +#endif netdev->ethtool_ops = &cxgb_ethtool_ops; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index bba67681aeaa..2a9da077c806 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3174,6 +3174,46 @@ int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, return ret; } +/** + * t4_set_params_nosleep - sets FW or device parameters + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @pf: the PF + * @vf: the VF + * @nparams: the number of parameters + * @params: the parameter names + * @val: the parameter values + * + * Does not ever sleep + * Sets the value of FW or device parameters. Up to 7 parameters can be + * specified at once. + */ +int t4_set_params_nosleep(struct adapter *adap, unsigned int mbox, + unsigned int pf, unsigned int vf, + unsigned int nparams, const u32 *params, + const u32 *val) +{ + struct fw_params_cmd c; + __be32 *p = &c.param[0].mnem; + + if (nparams > 7) + return -EINVAL; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) | + FW_CMD_REQUEST | FW_CMD_WRITE | + FW_PARAMS_CMD_PFN(pf) | + FW_PARAMS_CMD_VFN(vf)); + c.retval_len16 = cpu_to_be32(FW_LEN16(c)); + + while (nparams--) { + *p++ = cpu_to_be32(*params++); + *p++ = cpu_to_be32(*val++); + } + + return t4_wr_mbox_ns(adap, mbox, &c, sizeof(c), NULL); +} + /** * t4_set_params - sets FW or device parameters * @adap: the adapter @@ -3498,6 +3538,33 @@ int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); } +/** + * t4_enable_vi_params - enable/disable a virtual interface + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @viid: the VI id + * @rx_en: 1=enable Rx, 0=disable Rx + * @tx_en: 1=enable Tx, 0=disable Tx + * @dcb_en: 1=enable delivery of Data Center Bridging messages. + * + * Enables/disables a virtual interface. Note that setting DCB Enable + * only makes sense when enabling a Virtual Interface ... + */ +int t4_enable_vi_params(struct adapter *adap, unsigned int mbox, + unsigned int viid, bool rx_en, bool tx_en, bool dcb_en) +{ + struct fw_vi_enable_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST | + FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid)); + + c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_IEN(rx_en) | + FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c) | + FW_VI_ENABLE_CMD_DCB_INFO(dcb_en)); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + /** * t4_enable_vi - enable/disable a virtual interface * @adap: the adapter @@ -3511,14 +3578,7 @@ int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, int t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid, bool rx_en, bool tx_en) { - struct fw_vi_enable_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST | - FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid)); - c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_IEN(rx_en) | - FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c)); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); + return t4_enable_vi_params(adap, mbox, viid, rx_en, tx_en, 0); } /** -- cgit v1.2.3 From 19f43d1aa6c55eea7d0f67dd561fa992ac7e7894 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Thu, 19 Jun 2014 21:37:14 -0700 Subject: cxgb4 : Makefile & Kconfig changes for DCBx support Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/Kconfig | 11 +++++++++++ drivers/net/ethernet/chelsio/cxgb4/Makefile | 1 + 2 files changed, 12 insertions(+) diff --git a/drivers/net/ethernet/chelsio/Kconfig b/drivers/net/ethernet/chelsio/Kconfig index 570222c33410..c3ce9df0041a 100644 --- a/drivers/net/ethernet/chelsio/Kconfig +++ b/drivers/net/ethernet/chelsio/Kconfig @@ -86,6 +86,17 @@ config CHELSIO_T4 To compile this driver as a module choose M here; the module will be called cxgb4. +config CHELSIO_T4_DCB + bool "Data Center Bridging (DCB) Support for Chelsio T4/T5 cards" + default n + depends on CHELSIO_T4 && DCB + ---help--- + Enable DCB support through rtNetlink interface. + Say Y here if you want to enable Data Center Bridging (DCB) support + in the driver. + + If unsure, say N. + config CHELSIO_T4VF tristate "Chelsio Communications T4/T5 Virtual Function Ethernet support" depends on PCI diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile index 498667487f52..1df65c915b99 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/Makefile +++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o +cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o -- cgit v1.2.3 From ce100b8b813da05338ec15e40c195ee597be9dc9 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Thu, 19 Jun 2014 21:37:15 -0700 Subject: cxgb4 : Update copyright year on all cxgb4 files Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 2 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 2 +- drivers/net/ethernet/chelsio/cxgb4/l2t.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/l2t.h | 2 +- drivers/net/ethernet/chelsio/cxgb4/sge.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 2 +- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 2 +- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 2 +- drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 9d69c3ebbf00..7b5425c9c0fb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1,7 +1,7 @@ /* * This file is part of the Chelsio T4 Ethernet driver for Linux. * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 74b0ce50a8ef..02a0ebfa9c40 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -1,7 +1,7 @@ /* * This file is part of the Chelsio T4 Ethernet driver for Linux. * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index 55e9daf7f9d4..d719decbfb28 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -1,7 +1,7 @@ /* * This file is part of the Chelsio T4 Ethernet driver for Linux. * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index 8a96572fdde0..96041397ee15 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -1,7 +1,7 @@ /* * This file is part of the Chelsio T4 Ethernet driver for Linux. * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.h b/drivers/net/ethernet/chelsio/cxgb4/l2t.h index 85eb5c71358d..a30126ce90cb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.h +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.h @@ -1,7 +1,7 @@ /* * This file is part of the Chelsio T4 Ethernet driver for Linux. * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index dd4355d248e4..8bae1aa744a7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -1,7 +1,7 @@ /* * This file is part of the Chelsio T4 Ethernet driver for Linux. * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 2a9da077c806..6665cd410f2a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -1,7 +1,7 @@ /* * This file is part of the Chelsio T4 Ethernet driver for Linux. * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index 71b799b5b0f4..35e3d8e32881 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -1,7 +1,7 @@ /* * This file is part of the Chelsio T4 Ethernet driver for Linux. * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index 973eb11aa98a..abb45809c0c8 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -1,7 +1,7 @@ /* * This file is part of the Chelsio T4 Ethernet driver for Linux. * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 225ad8a5722d..3360025ad922 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -1,7 +1,7 @@ /* * This file is part of the Chelsio T4 Ethernet driver for Linux. * - * Copyright (c) 2010 Chelsio Communications, Inc. All rights reserved. + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index e83c94bbac41..4a6ae4db7397 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -1,7 +1,7 @@ /* * This file is part of the Chelsio T4 Ethernet driver for Linux. * - * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. + * Copyright (c) 2009-2014 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU -- cgit v1.2.3 From 0da6bc8cc3417a5e452efb886ff2c61e72b743d6 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 20 Jun 2014 17:47:15 +0530 Subject: ieee802154: cc2520: adds driver for TI CC2520 radio This patch adds the driver support for the cc2520 radio. Driver support: - Tx and Rx of IEEE-802.15.4 packets - Energy Detection on channel - Setting the Channel for the radio. [b/w 11 - 26 channels] - Start and Stop the radio - h/w address filtering Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ieee802154/cc2520.c | 1039 +++++++++++++++++++++++++++++++++++++++ include/linux/spi/cc2520.h | 26 + 2 files changed, 1065 insertions(+) create mode 100644 drivers/net/ieee802154/cc2520.c create mode 100644 include/linux/spi/cc2520.h diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c new file mode 100644 index 000000000000..8a5ac7ab2300 --- /dev/null +++ b/drivers/net/ieee802154/cc2520.c @@ -0,0 +1,1039 @@ +/* Driver for TI CC2520 802.15.4 Wireless-PAN Networking controller + * + * Copyright (C) 2014 Varka Bhadram + * Md.Jamal Mohiuddin + * P Sowjanya + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define SPI_COMMAND_BUFFER 3 +#define HIGH 1 +#define LOW 0 +#define STATE_IDLE 0 +#define RSSI_VALID 0 +#define RSSI_OFFSET 78 + +#define CC2520_RAM_SIZE 640 +#define CC2520_FIFO_SIZE 128 + +#define CC2520RAM_TXFIFO 0x100 +#define CC2520RAM_RXFIFO 0x180 +#define CC2520RAM_IEEEADDR 0x3EA +#define CC2520RAM_PANID 0x3F2 +#define CC2520RAM_SHORTADDR 0x3F4 + +#define CC2520_FREG_MASK 0x3F + +/* status byte values */ +#define CC2520_STATUS_XOSC32M_STABLE (1 << 7) +#define CC2520_STATUS_RSSI_VALID (1 << 6) +#define CC2520_STATUS_TX_UNDERFLOW (1 << 3) + +/* IEEE-802.15.4 defined constants (2.4 GHz logical channels) */ +#define CC2520_MINCHANNEL 11 +#define CC2520_MAXCHANNEL 26 +#define CC2520_CHANNEL_SPACING 5 + +/* command strobes */ +#define CC2520_CMD_SNOP 0x00 +#define CC2520_CMD_IBUFLD 0x02 +#define CC2520_CMD_SIBUFEX 0x03 +#define CC2520_CMD_SSAMPLECCA 0x04 +#define CC2520_CMD_SRES 0x0f +#define CC2520_CMD_MEMORY_MASK 0x0f +#define CC2520_CMD_MEMORY_READ 0x10 +#define CC2520_CMD_MEMORY_WRITE 0x20 +#define CC2520_CMD_RXBUF 0x30 +#define CC2520_CMD_RXBUFCP 0x38 +#define CC2520_CMD_RXBUFMOV 0x32 +#define CC2520_CMD_TXBUF 0x3A +#define CC2520_CMD_TXBUFCP 0x3E +#define CC2520_CMD_RANDOM 0x3C +#define CC2520_CMD_SXOSCON 0x40 +#define CC2520_CMD_STXCAL 0x41 +#define CC2520_CMD_SRXON 0x42 +#define CC2520_CMD_STXON 0x43 +#define CC2520_CMD_STXONCCA 0x44 +#define CC2520_CMD_SRFOFF 0x45 +#define CC2520_CMD_SXOSCOFF 0x46 +#define CC2520_CMD_SFLUSHRX 0x47 +#define CC2520_CMD_SFLUSHTX 0x48 +#define CC2520_CMD_SACK 0x49 +#define CC2520_CMD_SACKPEND 0x4A +#define CC2520_CMD_SNACK 0x4B +#define CC2520_CMD_SRXMASKBITSET 0x4C +#define CC2520_CMD_SRXMASKBITCLR 0x4D +#define CC2520_CMD_RXMASKAND 0x4E +#define CC2520_CMD_RXMASKOR 0x4F +#define CC2520_CMD_MEMCP 0x50 +#define CC2520_CMD_MEMCPR 0x52 +#define CC2520_CMD_MEMXCP 0x54 +#define CC2520_CMD_MEMXWR 0x56 +#define CC2520_CMD_BCLR 0x58 +#define CC2520_CMD_BSET 0x59 +#define CC2520_CMD_CTR_UCTR 0x60 +#define CC2520_CMD_CBCMAC 0x64 +#define CC2520_CMD_UCBCMAC 0x66 +#define CC2520_CMD_CCM 0x68 +#define CC2520_CMD_UCCM 0x6A +#define CC2520_CMD_ECB 0x70 +#define CC2520_CMD_ECBO 0x72 +#define CC2520_CMD_ECBX 0x74 +#define CC2520_CMD_INC 0x78 +#define CC2520_CMD_ABORT 0x7F +#define CC2520_CMD_REGISTER_READ 0x80 +#define CC2520_CMD_REGISTER_WRITE 0xC0 + +/* status registers */ +#define CC2520_CHIPID 0x40 +#define CC2520_VERSION 0x42 +#define CC2520_EXTCLOCK 0x44 +#define CC2520_MDMCTRL0 0x46 +#define CC2520_MDMCTRL1 0x47 +#define CC2520_FREQEST 0x48 +#define CC2520_RXCTRL 0x4A +#define CC2520_FSCTRL 0x4C +#define CC2520_FSCAL0 0x4E +#define CC2520_FSCAL1 0x4F +#define CC2520_FSCAL2 0x50 +#define CC2520_FSCAL3 0x51 +#define CC2520_AGCCTRL0 0x52 +#define CC2520_AGCCTRL1 0x53 +#define CC2520_AGCCTRL2 0x54 +#define CC2520_AGCCTRL3 0x55 +#define CC2520_ADCTEST0 0x56 +#define CC2520_ADCTEST1 0x57 +#define CC2520_ADCTEST2 0x58 +#define CC2520_MDMTEST0 0x5A +#define CC2520_MDMTEST1 0x5B +#define CC2520_DACTEST0 0x5C +#define CC2520_DACTEST1 0x5D +#define CC2520_ATEST 0x5E +#define CC2520_DACTEST2 0x5F +#define CC2520_PTEST0 0x60 +#define CC2520_PTEST1 0x61 +#define CC2520_RESERVED 0x62 +#define CC2520_DPUBIST 0x7A +#define CC2520_ACTBIST 0x7C +#define CC2520_RAMBIST 0x7E + +/* frame registers */ +#define CC2520_FRMFILT0 0x00 +#define CC2520_FRMFILT1 0x01 +#define CC2520_SRCMATCH 0x02 +#define CC2520_SRCSHORTEN0 0x04 +#define CC2520_SRCSHORTEN1 0x05 +#define CC2520_SRCSHORTEN2 0x06 +#define CC2520_SRCEXTEN0 0x08 +#define CC2520_SRCEXTEN1 0x09 +#define CC2520_SRCEXTEN2 0x0A +#define CC2520_FRMCTRL0 0x0C +#define CC2520_FRMCTRL1 0x0D +#define CC2520_RXENABLE0 0x0E +#define CC2520_RXENABLE1 0x0F +#define CC2520_EXCFLAG0 0x10 +#define CC2520_EXCFLAG1 0x11 +#define CC2520_EXCFLAG2 0x12 +#define CC2520_EXCMASKA0 0x14 +#define CC2520_EXCMASKA1 0x15 +#define CC2520_EXCMASKA2 0x16 +#define CC2520_EXCMASKB0 0x18 +#define CC2520_EXCMASKB1 0x19 +#define CC2520_EXCMASKB2 0x1A +#define CC2520_EXCBINDX0 0x1C +#define CC2520_EXCBINDX1 0x1D +#define CC2520_EXCBINDY0 0x1E +#define CC2520_EXCBINDY1 0x1F +#define CC2520_GPIOCTRL0 0x20 +#define CC2520_GPIOCTRL1 0x21 +#define CC2520_GPIOCTRL2 0x22 +#define CC2520_GPIOCTRL3 0x23 +#define CC2520_GPIOCTRL4 0x24 +#define CC2520_GPIOCTRL5 0x25 +#define CC2520_GPIOPOLARITY 0x26 +#define CC2520_GPIOCTRL 0x28 +#define CC2520_DPUCON 0x2A +#define CC2520_DPUSTAT 0x2C +#define CC2520_FREQCTRL 0x2E +#define CC2520_FREQTUNE 0x2F +#define CC2520_TXPOWER 0x30 +#define CC2520_TXCTRL 0x31 +#define CC2520_FSMSTAT0 0x32 +#define CC2520_FSMSTAT1 0x33 +#define CC2520_FIFOPCTRL 0x34 +#define CC2520_FSMCTRL 0x35 +#define CC2520_CCACTRL0 0x36 +#define CC2520_CCACTRL1 0x37 +#define CC2520_RSSI 0x38 +#define CC2520_RSSISTAT 0x39 +#define CC2520_RXFIRST 0x3C +#define CC2520_RXFIFOCNT 0x3E +#define CC2520_TXFIFOCNT 0x3F + +/* Driver private information */ +struct cc2520_private { + struct spi_device *spi; /* SPI device structure */ + struct ieee802154_dev *dev; /* IEEE-802.15.4 device */ + u8 *buf; /* SPI TX/Rx data buffer */ + struct mutex buffer_mutex; /* SPI buffer mutex */ + bool is_tx; /* Flag for sync b/w Tx and Rx */ + int fifo_pin; /* FIFO GPIO pin number */ + struct work_struct fifop_irqwork;/* Workqueue for FIFOP */ + spinlock_t lock; /* Lock for is_tx*/ + struct completion tx_complete; /* Work completion for Tx */ +}; + +/* Generic Functions */ +static int +cc2520_cmd_strobe(struct cc2520_private *priv, u8 cmd) +{ + int ret; + u8 status = 0xff; + struct spi_message msg; + struct spi_transfer xfer = { + .len = 0, + .tx_buf = priv->buf, + .rx_buf = priv->buf, + }; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + mutex_lock(&priv->buffer_mutex); + priv->buf[xfer.len++] = cmd; + dev_vdbg(&priv->spi->dev, + "command strobe buf[0] = %02x\n", + priv->buf[0]); + + ret = spi_sync(priv->spi, &msg); + if (!ret) + status = priv->buf[0]; + dev_vdbg(&priv->spi->dev, + "buf[0] = %02x\n", priv->buf[0]); + mutex_unlock(&priv->buffer_mutex); + + return ret; +} + +static int +cc2520_get_status(struct cc2520_private *priv, u8 *status) +{ + int ret; + struct spi_message msg; + struct spi_transfer xfer = { + .len = 0, + .tx_buf = priv->buf, + .rx_buf = priv->buf, + }; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + mutex_lock(&priv->buffer_mutex); + priv->buf[xfer.len++] = CC2520_CMD_SNOP; + dev_vdbg(&priv->spi->dev, + "get status command buf[0] = %02x\n", priv->buf[0]); + + ret = spi_sync(priv->spi, &msg); + if (!ret) + *status = priv->buf[0]; + dev_vdbg(&priv->spi->dev, + "buf[0] = %02x\n", priv->buf[0]); + mutex_unlock(&priv->buffer_mutex); + + return ret; +} + +static int +cc2520_write_register(struct cc2520_private *priv, u8 reg, u8 value) +{ + int status; + struct spi_message msg; + struct spi_transfer xfer = { + .len = 0, + .tx_buf = priv->buf, + .rx_buf = priv->buf, + }; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + mutex_lock(&priv->buffer_mutex); + + if (reg <= CC2520_FREG_MASK) { + priv->buf[xfer.len++] = CC2520_CMD_REGISTER_WRITE | reg; + priv->buf[xfer.len++] = value; + } else { + priv->buf[xfer.len++] = CC2520_CMD_MEMORY_WRITE; + priv->buf[xfer.len++] = reg; + priv->buf[xfer.len++] = value; + } + status = spi_sync(priv->spi, &msg); + if (msg.status) + status = msg.status; + + mutex_unlock(&priv->buffer_mutex); + + return status; +} + +static int +cc2520_write_ram(struct cc2520_private *priv, u16 reg, u8 len, u8 *data) +{ + int status; + struct spi_message msg; + struct spi_transfer xfer_head = { + .len = 0, + .tx_buf = priv->buf, + .rx_buf = priv->buf, + }; + + struct spi_transfer xfer_buf = { + .len = len, + .tx_buf = data, + }; + + mutex_lock(&priv->buffer_mutex); + priv->buf[xfer_head.len++] = (CC2520_CMD_MEMORY_WRITE | + ((reg >> 8) & 0xff)); + priv->buf[xfer_head.len++] = reg & 0xff; + + spi_message_init(&msg); + spi_message_add_tail(&xfer_head, &msg); + spi_message_add_tail(&xfer_buf, &msg); + + status = spi_sync(priv->spi, &msg); + dev_dbg(&priv->spi->dev, "spi status = %d\n", status); + if (msg.status) + status = msg.status; + + mutex_unlock(&priv->buffer_mutex); + return status; +} + +static int +cc2520_read_register(struct cc2520_private *priv, u8 reg, u8 *data) +{ + int status; + struct spi_message msg; + struct spi_transfer xfer1 = { + .len = 0, + .tx_buf = priv->buf, + .rx_buf = priv->buf, + }; + + struct spi_transfer xfer2 = { + .len = 1, + .rx_buf = data, + }; + + spi_message_init(&msg); + spi_message_add_tail(&xfer1, &msg); + spi_message_add_tail(&xfer2, &msg); + + mutex_lock(&priv->buffer_mutex); + priv->buf[xfer1.len++] = CC2520_CMD_MEMORY_READ; + priv->buf[xfer1.len++] = reg; + + status = spi_sync(priv->spi, &msg); + dev_dbg(&priv->spi->dev, + "spi status = %d\n", status); + if (msg.status) + status = msg.status; + + mutex_unlock(&priv->buffer_mutex); + + return status; +} + +static int +cc2520_write_txfifo(struct cc2520_private *priv, u8 *data, u8 len) +{ + int status; + + /* length byte must include FCS even + * if it is calculated in the hardware + */ + int len_byte = len + 2; + + struct spi_message msg; + + struct spi_transfer xfer_head = { + .len = 0, + .tx_buf = priv->buf, + .rx_buf = priv->buf, + }; + struct spi_transfer xfer_len = { + .len = 1, + .tx_buf = &len_byte, + }; + struct spi_transfer xfer_buf = { + .len = len, + .tx_buf = data, + }; + + spi_message_init(&msg); + spi_message_add_tail(&xfer_head, &msg); + spi_message_add_tail(&xfer_len, &msg); + spi_message_add_tail(&xfer_buf, &msg); + + mutex_lock(&priv->buffer_mutex); + priv->buf[xfer_head.len++] = CC2520_CMD_TXBUF; + dev_vdbg(&priv->spi->dev, + "TX_FIFO cmd buf[0] = %02x\n", priv->buf[0]); + + status = spi_sync(priv->spi, &msg); + dev_vdbg(&priv->spi->dev, "status = %d\n", status); + if (msg.status) + status = msg.status; + dev_vdbg(&priv->spi->dev, "status = %d\n", status); + dev_vdbg(&priv->spi->dev, "buf[0] = %02x\n", priv->buf[0]); + mutex_unlock(&priv->buffer_mutex); + + return status; +} + +static int +cc2520_read_rxfifo(struct cc2520_private *priv, u8 *data, u8 len, u8 *lqi) +{ + int status; + struct spi_message msg; + + struct spi_transfer xfer_head = { + .len = 0, + .tx_buf = priv->buf, + .rx_buf = priv->buf, + }; + struct spi_transfer xfer_buf = { + .len = len, + .rx_buf = data, + }; + + spi_message_init(&msg); + spi_message_add_tail(&xfer_head, &msg); + spi_message_add_tail(&xfer_buf, &msg); + + mutex_lock(&priv->buffer_mutex); + priv->buf[xfer_head.len++] = CC2520_CMD_RXBUF; + + dev_vdbg(&priv->spi->dev, "read rxfifo buf[0] = %02x\n", priv->buf[0]); + dev_vdbg(&priv->spi->dev, "buf[1] = %02x\n", priv->buf[1]); + + status = spi_sync(priv->spi, &msg); + dev_vdbg(&priv->spi->dev, "status = %d\n", status); + if (msg.status) + status = msg.status; + dev_vdbg(&priv->spi->dev, "status = %d\n", status); + dev_vdbg(&priv->spi->dev, + "return status buf[0] = %02x\n", priv->buf[0]); + dev_vdbg(&priv->spi->dev, "length buf[1] = %02x\n", priv->buf[1]); + + mutex_unlock(&priv->buffer_mutex); + + return status; +} + +static int cc2520_start(struct ieee802154_dev *dev) +{ + return cc2520_cmd_strobe(dev->priv, CC2520_CMD_SRXON); +} + +static void cc2520_stop(struct ieee802154_dev *dev) +{ + cc2520_cmd_strobe(dev->priv, CC2520_CMD_SRFOFF); +} + +static int +cc2520_tx(struct ieee802154_dev *dev, struct sk_buff *skb) +{ + struct cc2520_private *priv = dev->priv; + unsigned long flags; + int rc; + u8 status = 0; + + rc = cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHTX); + if (rc) + goto err_tx; + + rc = cc2520_write_txfifo(priv, skb->data, skb->len); + if (rc) + goto err_tx; + + rc = cc2520_get_status(priv, &status); + if (rc) + goto err_tx; + + if (status & CC2520_STATUS_TX_UNDERFLOW) { + dev_err(&priv->spi->dev, "cc2520 tx underflow exception\n"); + goto err_tx; + } + + spin_lock_irqsave(&priv->lock, flags); + BUG_ON(priv->is_tx); + priv->is_tx = 1; + spin_unlock_irqrestore(&priv->lock, flags); + + rc = cc2520_cmd_strobe(priv, CC2520_CMD_STXONCCA); + if (rc) + goto err; + + rc = wait_for_completion_interruptible(&priv->tx_complete); + if (rc < 0) + goto err; + + cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHTX); + cc2520_cmd_strobe(priv, CC2520_CMD_SRXON); + + return rc; +err: + spin_lock_irqsave(&priv->lock, flags); + priv->is_tx = 0; + spin_unlock_irqrestore(&priv->lock, flags); +err_tx: + return rc; +} + + +static int cc2520_rx(struct cc2520_private *priv) +{ + u8 len = 0, lqi = 0, bytes = 1; + struct sk_buff *skb; + + cc2520_read_rxfifo(priv, &len, bytes, &lqi); + + if (len < 2 || len > IEEE802154_MTU) + return -EINVAL; + + skb = alloc_skb(len, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + if (cc2520_read_rxfifo(priv, skb_put(skb, len), len, &lqi)) { + dev_dbg(&priv->spi->dev, "frame reception failed\n"); + kfree_skb(skb); + return -EINVAL; + } + + skb_trim(skb, skb->len - 2); + + ieee802154_rx_irqsafe(priv->dev, skb, lqi); + + dev_vdbg(&priv->spi->dev, "RXFIFO: %x %x\n", len, lqi); + + return 0; +} + +static int +cc2520_ed(struct ieee802154_dev *dev, u8 *level) +{ + struct cc2520_private *priv = dev->priv; + u8 status = 0xff; + u8 rssi; + int ret; + + ret = cc2520_read_register(priv , CC2520_RSSISTAT, &status); + if (ret) + return ret; + + if (status != RSSI_VALID) + return -EINVAL; + + ret = cc2520_read_register(priv , CC2520_RSSI, &rssi); + if (ret) + return ret; + + /* level = RSSI(rssi) - OFFSET [dBm] : offset is 76dBm */ + *level = rssi - RSSI_OFFSET; + + return 0; +} + +static int +cc2520_set_channel(struct ieee802154_dev *dev, int page, int channel) +{ + struct cc2520_private *priv = dev->priv; + int ret; + + might_sleep(); + dev_dbg(&priv->spi->dev, "trying to set channel\n"); + + BUG_ON(page != 0); + BUG_ON(channel < CC2520_MINCHANNEL); + BUG_ON(channel > CC2520_MAXCHANNEL); + + ret = cc2520_write_register(priv, CC2520_FREQCTRL, + 11 + 5*(channel - 11)); + + return ret; +} + +static int +cc2520_filter(struct ieee802154_dev *dev, + struct ieee802154_hw_addr_filt *filt, unsigned long changed) +{ + struct cc2520_private *priv = dev->priv; + + if (changed & IEEE802515_AFILT_PANID_CHANGED) { + u16 panid = le16_to_cpu(filt->pan_id); + + dev_vdbg(&priv->spi->dev, + "cc2520_filter called for pan id\n"); + cc2520_write_ram(priv, CC2520RAM_PANID, + sizeof(panid), (u8 *)&panid); + } + + if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) { + dev_vdbg(&priv->spi->dev, + "cc2520_filter called for IEEE addr\n"); + cc2520_write_ram(priv, CC2520RAM_IEEEADDR, + sizeof(filt->ieee_addr), + (u8 *)&filt->ieee_addr); + } + + if (changed & IEEE802515_AFILT_SADDR_CHANGED) { + u16 addr = le16_to_cpu(filt->short_addr); + + dev_vdbg(&priv->spi->dev, + "cc2520_filter called for saddr\n"); + cc2520_write_ram(priv, CC2520RAM_SHORTADDR, + sizeof(addr), (u8 *)&addr); + } + + if (changed & IEEE802515_AFILT_PANC_CHANGED) { + dev_vdbg(&priv->spi->dev, + "cc2520_filter called for panc change\n"); + if (filt->pan_coord) + cc2520_write_register(priv, CC2520_FRMFILT0, 0x02); + else + cc2520_write_register(priv, CC2520_FRMFILT0, 0x00); + } + + return 0; +} + +static struct ieee802154_ops cc2520_ops = { + .owner = THIS_MODULE, + .start = cc2520_start, + .stop = cc2520_stop, + .xmit = cc2520_tx, + .ed = cc2520_ed, + .set_channel = cc2520_set_channel, + .set_hw_addr_filt = cc2520_filter, +}; + +static int cc2520_register(struct cc2520_private *priv) +{ + int ret = -ENOMEM; + + priv->dev = ieee802154_alloc_device(sizeof(*priv), &cc2520_ops); + if (!priv->dev) + goto err_ret; + + priv->dev->priv = priv; + priv->dev->parent = &priv->spi->dev; + priv->dev->extra_tx_headroom = 0; + + /* We do support only 2.4 Ghz */ + priv->dev->phy->channels_supported[0] = 0x7FFF800; + priv->dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK; + + dev_vdbg(&priv->spi->dev, "registered cc2520\n"); + ret = ieee802154_register_device(priv->dev); + if (ret) + goto err_free_device; + + return 0; + +err_free_device: + ieee802154_free_device(priv->dev); +err_ret: + return ret; +} + +static void cc2520_fifop_irqwork(struct work_struct *work) +{ + struct cc2520_private *priv + = container_of(work, struct cc2520_private, fifop_irqwork); + + dev_dbg(&priv->spi->dev, "fifop interrupt received\n"); + + if (gpio_get_value(priv->fifo_pin)) + cc2520_rx(priv); + else + dev_dbg(&priv->spi->dev, "rxfifo overflow\n"); + + cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHRX); + cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHRX); +} + +static irqreturn_t cc2520_fifop_isr(int irq, void *data) +{ + struct cc2520_private *priv = data; + + schedule_work(&priv->fifop_irqwork); + + return IRQ_HANDLED; +} + +static irqreturn_t cc2520_sfd_isr(int irq, void *data) +{ + struct cc2520_private *priv = data; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (priv->is_tx) { + priv->is_tx = 0; + spin_unlock_irqrestore(&priv->lock, flags); + dev_dbg(&priv->spi->dev, "SFD for TX\n"); + complete(&priv->tx_complete); + } else { + spin_unlock_irqrestore(&priv->lock, flags); + dev_dbg(&priv->spi->dev, "SFD for RX\n"); + } + + return IRQ_HANDLED; +} + +static int cc2520_hw_init(struct cc2520_private *priv) +{ + u8 status = 0, state = 0xff; + int ret; + int timeout = 100; + + ret = cc2520_read_register(priv, CC2520_FSMSTAT1, &state); + if (ret) + goto err_ret; + + if (state != STATE_IDLE) + return -EINVAL; + + do { + ret = cc2520_get_status(priv, &status); + if (ret) + goto err_ret; + + if (timeout-- <= 0) { + dev_err(&priv->spi->dev, "oscillator start failed!\n"); + return ret; + } + udelay(1); + } while (!(status & CC2520_STATUS_XOSC32M_STABLE)); + + dev_vdbg(&priv->spi->dev, "oscillator brought up\n"); + + /* Registers default value: section 28.1 in Datasheet */ + ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF7); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_CCACTRL0, 0x1A); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_MDMCTRL0, 0x85); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_MDMCTRL1, 0x14); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_RXCTRL, 0x3f); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_FSCTRL, 0x5a); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_FSCAL1, 0x2b); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x11); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_ADCTEST0, 0x10); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_ADCTEST1, 0x0e); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_ADCTEST2, 0x03); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_FRMCTRL0, 0x60); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_FRMCTRL1, 0x03); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_FRMFILT0, 0x00); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_FIFOPCTRL, 127); + if (ret) + goto err_ret; + + return 0; + +err_ret: + return ret; +} + +static struct cc2520_platform_data * +cc2520_get_platform_data(struct spi_device *spi) +{ + struct cc2520_platform_data *pdata; + struct device_node *np = spi->dev.of_node; + struct cc2520_private *priv = spi_get_drvdata(spi); + + if (!np) + return spi->dev.platform_data; + + pdata = devm_kzalloc(&spi->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + goto done; + + pdata->fifo = of_get_named_gpio(np, "fifo-gpio", 0); + priv->fifo_pin = pdata->fifo; + + pdata->fifop = of_get_named_gpio(np, "fifop-gpio", 0); + + pdata->sfd = of_get_named_gpio(np, "sfd-gpio", 0); + pdata->cca = of_get_named_gpio(np, "cca-gpio", 0); + pdata->vreg = of_get_named_gpio(np, "vreg-gpio", 0); + pdata->reset = of_get_named_gpio(np, "reset-gpio", 0); + + spi->dev.platform_data = pdata; + +done: + return pdata; +} + +static int cc2520_probe(struct spi_device *spi) +{ + struct cc2520_private *priv; + struct pinctrl *pinctrl; + struct cc2520_platform_data *pdata; + int ret; + + priv = devm_kzalloc(&spi->dev, + sizeof(struct cc2520_private), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto err_ret; + } + + spi_set_drvdata(spi, priv); + + pinctrl = devm_pinctrl_get_select_default(&spi->dev); + if (IS_ERR(pinctrl)) + dev_warn(&spi->dev, + "pinctrl pins are not configured"); + + pdata = cc2520_get_platform_data(spi); + if (!pdata) { + dev_err(&spi->dev, "no platform data\n"); + return -EINVAL; + } + + priv->spi = spi; + + priv->buf = devm_kzalloc(&spi->dev, + SPI_COMMAND_BUFFER, GFP_KERNEL); + if (!priv->buf) { + ret = -ENOMEM; + goto err_ret; + } + + mutex_init(&priv->buffer_mutex); + INIT_WORK(&priv->fifop_irqwork, cc2520_fifop_irqwork); + spin_lock_init(&priv->lock); + init_completion(&priv->tx_complete); + + /* Request all the gpio's */ + if (!gpio_is_valid(pdata->fifo)) { + dev_err(&spi->dev, "fifo gpio is not valid\n"); + ret = -EINVAL; + goto err_hw_init; + } + + ret = devm_gpio_request_one(&spi->dev, pdata->fifo, + GPIOF_IN, "fifo"); + if (ret) + goto err_hw_init; + + if (!gpio_is_valid(pdata->cca)) { + dev_err(&spi->dev, "cca gpio is not valid\n"); + ret = -EINVAL; + goto err_hw_init; + } + + ret = devm_gpio_request_one(&spi->dev, pdata->cca, + GPIOF_IN, "cca"); + if (ret) + goto err_hw_init; + + if (!gpio_is_valid(pdata->fifop)) { + dev_err(&spi->dev, "fifop gpio is not valid\n"); + ret = -EINVAL; + goto err_hw_init; + } + + ret = devm_gpio_request_one(&spi->dev, pdata->fifop, + GPIOF_IN, "fifop"); + if (ret) + goto err_hw_init; + + if (!gpio_is_valid(pdata->sfd)) { + dev_err(&spi->dev, "sfd gpio is not valid\n"); + ret = -EINVAL; + goto err_hw_init; + } + + ret = devm_gpio_request_one(&spi->dev, pdata->sfd, + GPIOF_IN, "sfd"); + if (ret) + goto err_hw_init; + + if (!gpio_is_valid(pdata->reset)) { + dev_err(&spi->dev, "reset gpio is not valid\n"); + ret = -EINVAL; + goto err_hw_init; + } + + ret = devm_gpio_request_one(&spi->dev, pdata->reset, + GPIOF_OUT_INIT_LOW, "reset"); + if (ret) + goto err_hw_init; + + if (!gpio_is_valid(pdata->vreg)) { + dev_err(&spi->dev, "vreg gpio is not valid\n"); + ret = -EINVAL; + goto err_hw_init; + } + + ret = devm_gpio_request_one(&spi->dev, pdata->vreg, + GPIOF_OUT_INIT_LOW, "vreg"); + if (ret) + goto err_hw_init; + + + gpio_set_value(pdata->vreg, HIGH); + usleep_range(100, 150); + + gpio_set_value(pdata->reset, HIGH); + usleep_range(200, 250); + + ret = cc2520_hw_init(priv); + if (ret) + goto err_hw_init; + + /* Set up fifop interrupt */ + ret = devm_request_irq(&spi->dev, + gpio_to_irq(pdata->fifop), + cc2520_fifop_isr, + IRQF_TRIGGER_RISING, + dev_name(&spi->dev), + priv); + if (ret) { + dev_err(&spi->dev, "could not get fifop irq\n"); + goto err_hw_init; + } + + /* Set up sfd interrupt */ + ret = devm_request_irq(&spi->dev, + gpio_to_irq(pdata->sfd), + cc2520_sfd_isr, + IRQF_TRIGGER_FALLING, + dev_name(&spi->dev), + priv); + if (ret) { + dev_err(&spi->dev, "could not get sfd irq\n"); + goto err_hw_init; + } + + ret = cc2520_register(priv); + if (ret) + goto err_hw_init; + + return 0; + +err_hw_init: + mutex_destroy(&priv->buffer_mutex); + flush_work(&priv->fifop_irqwork); + +err_ret: + return ret; +} + +static int cc2520_remove(struct spi_device *spi) +{ + struct cc2520_private *priv = spi_get_drvdata(spi); + + mutex_destroy(&priv->buffer_mutex); + flush_work(&priv->fifop_irqwork); + + ieee802154_unregister_device(priv->dev); + ieee802154_free_device(priv->dev); + + return 0; +} + +static const struct spi_device_id cc2520_ids[] = { + {"cc2520", }, + {}, +}; +MODULE_DEVICE_TABLE(spi, cc2520_ids); + +static const struct of_device_id cc2520_of_ids[] = { + {.compatible = "ti,cc2520", }, + {}, +}; +MODULE_DEVICE_TABLE(of, cc2520_of_ids); + +/* SPI driver structure */ +static struct spi_driver cc2520_driver = { + .driver = { + .name = "cc2520", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(cc2520_of_ids), + }, + .id_table = cc2520_ids, + .probe = cc2520_probe, + .remove = cc2520_remove, +}; +module_spi_driver(cc2520_driver); + +MODULE_AUTHOR("Varka Bhadram "); +MODULE_DESCRIPTION("CC2520 Transceiver Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/spi/cc2520.h b/include/linux/spi/cc2520.h new file mode 100644 index 000000000000..85b8ee67e937 --- /dev/null +++ b/include/linux/spi/cc2520.h @@ -0,0 +1,26 @@ +/* Header file for cc2520 radio driver + * + * Copyright (C) 2014 Varka Bhadram + * Md.Jamal Mohiuddin + * P Sowjanya + * + * 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. + * + */ + +#ifndef __CC2520_H +#define __CC2520_H + +struct cc2520_platform_data { + int fifo; + int fifop; + int cca; + int sfd; + int reset; + int vreg; +}; + +#endif -- cgit v1.2.3 From b5bf62248a3f4983899498128233f4ffb8ba7630 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 20 Jun 2014 17:47:16 +0530 Subject: ieee802154: cc2520: add driver to kernel build system Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ieee802154/Kconfig | 11 +++++++++++ drivers/net/ieee802154/Makefile | 1 + 2 files changed, 12 insertions(+) diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig index 3e89beab64fd..8b7ae51f30f5 100644 --- a/drivers/net/ieee802154/Kconfig +++ b/drivers/net/ieee802154/Kconfig @@ -51,3 +51,14 @@ config IEEE802154_MRF24J40 This driver can also be built as a module. To do so, say M here. the module will be called 'mrf24j40'. + +config IEEE802154_CC2520 + depends on IEEE802154_DRIVERS && MAC802154 + tristate "CC2520 transceiver driver" + depends on SPI + ---help--- + Say Y here to enable the CC2520 SPI 802.15.4 wireless + controller. + + This driver can also be built as a module. To do so, say M here. + the module will be called 'cc2520'. diff --git a/drivers/net/ieee802154/Makefile b/drivers/net/ieee802154/Makefile index abb0c08decb0..655cb95e6e24 100644 --- a/drivers/net/ieee802154/Makefile +++ b/drivers/net/ieee802154/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o +obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o -- cgit v1.2.3 From 1952e8e0c5156615e344acbb9317e65f11aa9536 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 20 Jun 2014 17:47:17 +0530 Subject: devicetree: add device tree bindings for cc2520 driver DT bindings for cc2520 radio driver Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- .../devicetree/bindings/net/ieee802154/cc2520.txt | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/ieee802154/cc2520.txt diff --git a/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt b/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt new file mode 100644 index 000000000000..0071883c08d8 --- /dev/null +++ b/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt @@ -0,0 +1,29 @@ +*CC2520 IEEE 802.15.4 Compatible Radio* + +Required properties: + - compatible: should be "ti,cc2520" + - spi-max-frequency: maximal bus speed (8000000), should be set to 4000000 depends + sync or async operation mode + - reg: the chipselect index + - pinctrl-0: pin control group to be used for this controller. + - pinctrl-names: must contain a "default" entry. + - fifo-gpio: GPIO spec for the FIFO pin + - fifop-gpio: GPIO spec for the FIFOP pin + - sfd-gpio: GPIO spec for the SFD pin + - cca-gpio: GPIO spec for the CCA pin + - vreg-gpio: GPIO spec for the VREG pin + - reset-gpio: GPIO spec for the RESET pin +Example: + cc2520@0 { + compatible = "ti,cc2520"; + reg = <0>; + spi-max-frequency = <4000000>; + pinctrl-names = "default"; + pinctrl-0 = <&cc2520_cape_pins>; + fifo-gpio = <&gpio1 18 0>; + fifop-gpio = <&gpio1 19 0>; + sfd-gpio = <&gpio1 13 0>; + cca-gpio = <&gpio1 16 0>; + vreg-gpio = <&gpio0 31 0>; + reset-gpio = <&gpio1 12 0>; + }; -- cgit v1.2.3 From 20edb50e593dca7522b4f3a95b801dbf99f24c52 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 30 May 2014 10:47:28 -0400 Subject: mac80211: remove PID rate control Minstrel has long since proven its worth. Signed-off-by: John W. Linville Signed-off-by: Johannes Berg --- MAINTAINERS | 10 - net/mac80211/Kconfig | 17 -- net/mac80211/Makefile | 5 - net/mac80211/main.c | 7 - net/mac80211/rate.h | 13 - net/mac80211/rc80211_pid.h | 278 --------------------- net/mac80211/rc80211_pid_algo.c | 478 ------------------------------------- net/mac80211/rc80211_pid_debugfs.c | 228 ------------------ 8 files changed, 1036 deletions(-) delete mode 100644 net/mac80211/rc80211_pid.h delete mode 100644 net/mac80211/rc80211_pid_algo.c delete mode 100644 net/mac80211/rc80211_pid_debugfs.c diff --git a/MAINTAINERS b/MAINTAINERS index 134483f206e4..54ba0e643c39 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5629,16 +5629,6 @@ F: Documentation/networking/mac80211-injection.txt F: include/net/mac80211.h F: net/mac80211/ -MAC80211 PID RATE CONTROL -M: Stefano Brivio -M: Mattias Nissler -L: linux-wireless@vger.kernel.org -W: http://wireless.kernel.org/en/developers/Documentation/mac80211/RateControl/PID -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git -S: Maintained -F: net/mac80211/rc80211_pid* - MACVLAN DRIVER M: Patrick McHardy L: netdev@vger.kernel.org diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 97b5dcad5025..aeb6a483b3bc 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -19,14 +19,6 @@ if MAC80211 != n config MAC80211_HAS_RC bool -config MAC80211_RC_PID - bool "PID controller based rate control algorithm" if EXPERT - select MAC80211_HAS_RC - ---help--- - This option enables a TX rate control algorithm for - mac80211 that uses a PID controller to select the TX - rate. - config MAC80211_RC_MINSTREL bool "Minstrel" if EXPERT select MAC80211_HAS_RC @@ -51,14 +43,6 @@ choice overridden through the ieee80211_default_rc_algo module parameter if different algorithms are available. -config MAC80211_RC_DEFAULT_PID - bool "PID controller based rate control algorithm" - depends on MAC80211_RC_PID - ---help--- - Select the PID controller based rate control as the - default rate control algorithm. You should choose - this unless you know what you are doing. - config MAC80211_RC_DEFAULT_MINSTREL bool "Minstrel" depends on MAC80211_RC_MINSTREL @@ -72,7 +56,6 @@ config MAC80211_RC_DEFAULT string default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL - default "pid" if MAC80211_RC_DEFAULT_PID default "" endif diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 1e46ffa69167..4409bf506594 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -47,17 +47,12 @@ mac80211-$(CONFIG_PM) += pm.o CFLAGS_trace.o := -I$(src) -# objects for PID algorithm -rc80211_pid-y := rc80211_pid_algo.o -rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o - rc80211_minstrel-y := rc80211_minstrel.o rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o rc80211_minstrel_ht-y := rc80211_minstrel_ht.o rc80211_minstrel_ht-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o -mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y) mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d17c26d6e369..0512a5096f0f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1187,18 +1187,12 @@ static int __init ieee80211_init(void) if (ret) goto err_minstrel; - ret = rc80211_pid_init(); - if (ret) - goto err_pid; - ret = ieee80211_iface_init(); if (ret) goto err_netdev; return 0; err_netdev: - rc80211_pid_exit(); - err_pid: rc80211_minstrel_ht_exit(); err_minstrel: rc80211_minstrel_exit(); @@ -1208,7 +1202,6 @@ static int __init ieee80211_init(void) static void __exit ieee80211_exit(void) { - rc80211_pid_exit(); rc80211_minstrel_ht_exit(); rc80211_minstrel_exit(); diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 9aa2a1190a86..18babe302832 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -143,19 +143,6 @@ void rate_control_deinitialize(struct ieee80211_local *local); /* Rate control algorithms */ -#ifdef CONFIG_MAC80211_RC_PID -int rc80211_pid_init(void); -void rc80211_pid_exit(void); -#else -static inline int rc80211_pid_init(void) -{ - return 0; -} -static inline void rc80211_pid_exit(void) -{ -} -#endif - #ifdef CONFIG_MAC80211_RC_MINSTREL int rc80211_minstrel_init(void); void rc80211_minstrel_exit(void); diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h deleted file mode 100644 index 19111c7bf454..000000000000 --- a/net/mac80211/rc80211_pid.h +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright 2007, Mattias Nissler - * Copyright 2007, Stefano Brivio - * - * 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. - */ - -#ifndef RC80211_PID_H -#define RC80211_PID_H - -/* Sampling period for measuring percentage of failed frames in ms. */ -#define RC_PID_INTERVAL 125 - -/* Exponential averaging smoothness (used for I part of PID controller) */ -#define RC_PID_SMOOTHING_SHIFT 3 -#define RC_PID_SMOOTHING (1 << RC_PID_SMOOTHING_SHIFT) - -/* Sharpening factor (used for D part of PID controller) */ -#define RC_PID_SHARPENING_FACTOR 0 -#define RC_PID_SHARPENING_DURATION 0 - -/* Fixed point arithmetic shifting amount. */ -#define RC_PID_ARITH_SHIFT 8 - -/* Proportional PID component coefficient. */ -#define RC_PID_COEFF_P 15 -/* Integral PID component coefficient. */ -#define RC_PID_COEFF_I 9 -/* Derivative PID component coefficient. */ -#define RC_PID_COEFF_D 15 - -/* Target failed frames rate for the PID controller. NB: This effectively gives - * maximum failed frames percentage we're willing to accept. If the wireless - * link quality is good, the controller will fail to adjust failed frames - * percentage to the target. This is intentional. - */ -#define RC_PID_TARGET_PF 14 - -/* Rate behaviour normalization quantity over time. */ -#define RC_PID_NORM_OFFSET 3 - -/* Push high rates right after loading. */ -#define RC_PID_FAST_START 0 - -/* Arithmetic right shift for positive and negative values for ISO C. */ -#define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \ - ((x) < 0 ? -((-(x)) >> (y)) : (x) >> (y)) - -enum rc_pid_event_type { - RC_PID_EVENT_TYPE_TX_STATUS, - RC_PID_EVENT_TYPE_RATE_CHANGE, - RC_PID_EVENT_TYPE_TX_RATE, - RC_PID_EVENT_TYPE_PF_SAMPLE, -}; - -union rc_pid_event_data { - /* RC_PID_EVENT_TX_STATUS */ - struct { - u32 flags; - struct ieee80211_tx_info tx_status; - }; - /* RC_PID_EVENT_TYPE_RATE_CHANGE */ - /* RC_PID_EVENT_TYPE_TX_RATE */ - struct { - int index; - int rate; - }; - /* RC_PID_EVENT_TYPE_PF_SAMPLE */ - struct { - s32 pf_sample; - s32 prop_err; - s32 int_err; - s32 der_err; - }; -}; - -struct rc_pid_event { - /* The time when the event occurred */ - unsigned long timestamp; - - /* Event ID number */ - unsigned int id; - - /* Type of event */ - enum rc_pid_event_type type; - - /* type specific data */ - union rc_pid_event_data data; -}; - -/* Size of the event ring buffer. */ -#define RC_PID_EVENT_RING_SIZE 32 - -struct rc_pid_event_buffer { - /* Counter that generates event IDs */ - unsigned int ev_count; - - /* Ring buffer of events */ - struct rc_pid_event ring[RC_PID_EVENT_RING_SIZE]; - - /* Index to the entry in events_buf to be reused */ - unsigned int next_entry; - - /* Lock that guards against concurrent access to this buffer struct */ - spinlock_t lock; - - /* Wait queue for poll/select and blocking I/O */ - wait_queue_head_t waitqueue; -}; - -struct rc_pid_events_file_info { - /* The event buffer we read */ - struct rc_pid_event_buffer *events; - - /* The entry we have should read next */ - unsigned int next_entry; -}; - -/** - * struct rc_pid_debugfs_entries - tunable parameters - * - * Algorithm parameters, tunable via debugfs. - * @target: target percentage for failed frames - * @sampling_period: error sampling interval in milliseconds - * @coeff_p: absolute value of the proportional coefficient - * @coeff_i: absolute value of the integral coefficient - * @coeff_d: absolute value of the derivative coefficient - * @smoothing_shift: absolute value of the integral smoothing factor (i.e. - * amount of smoothing introduced by the exponential moving average) - * @sharpen_factor: absolute value of the derivative sharpening factor (i.e. - * amount of emphasis given to the derivative term after low activity - * events) - * @sharpen_duration: duration of the sharpening effect after the detected low - * activity event, relative to sampling_period - * @norm_offset: amount of normalization periodically performed on the learnt - * rate behaviour values (lower means we should trust more what we learnt - * about behaviour of rates, higher means we should trust more the natural - * ordering of rates) - */ -struct rc_pid_debugfs_entries { - struct dentry *target; - struct dentry *sampling_period; - struct dentry *coeff_p; - struct dentry *coeff_i; - struct dentry *coeff_d; - struct dentry *smoothing_shift; - struct dentry *sharpen_factor; - struct dentry *sharpen_duration; - struct dentry *norm_offset; -}; - -void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, - struct ieee80211_tx_info *stat); - -void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, - int index, int rate); - -void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf, - int index, int rate); - -void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf, - s32 pf_sample, s32 prop_err, - s32 int_err, s32 der_err); - -void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta, - struct dentry *dir); - -void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta); - -struct rc_pid_sta_info { - unsigned long last_change; - unsigned long last_sample; - - u32 tx_num_failed; - u32 tx_num_xmit; - - int txrate_idx; - - /* Average failed frames percentage error (i.e. actual vs. target - * percentage), scaled by RC_PID_SMOOTHING. This value is computed - * using using an exponential weighted average technique: - * - * (RC_PID_SMOOTHING - 1) * err_avg_old + err - * err_avg = ------------------------------------------ - * RC_PID_SMOOTHING - * - * where err_avg is the new approximation, err_avg_old the previous one - * and err is the error w.r.t. to the current failed frames percentage - * sample. Note that the bigger RC_PID_SMOOTHING the more weight is - * given to the previous estimate, resulting in smoother behavior (i.e. - * corresponding to a longer integration window). - * - * For computation, we actually don't use the above formula, but this - * one: - * - * err_avg_scaled = err_avg_old_scaled - err_avg_old + err - * - * where: - * err_avg_scaled = err * RC_PID_SMOOTHING - * err_avg_old_scaled = err_avg_old * RC_PID_SMOOTHING - * - * This avoids floating point numbers and the per_failed_old value can - * easily be obtained by shifting per_failed_old_scaled right by - * RC_PID_SMOOTHING_SHIFT. - */ - s32 err_avg_sc; - - /* Last framed failes percentage sample. */ - u32 last_pf; - - /* Sharpening needed. */ - u8 sharp_cnt; - -#ifdef CONFIG_MAC80211_DEBUGFS - /* Event buffer */ - struct rc_pid_event_buffer events; - - /* Events debugfs file entry */ - struct dentry *events_entry; -#endif -}; - -/* Algorithm parameters. We keep them on a per-algorithm approach, so they can - * be tuned individually for each interface. - */ -struct rc_pid_rateinfo { - - /* Map sorted rates to rates in ieee80211_hw_mode. */ - int index; - - /* Map rates in ieee80211_hw_mode to sorted rates. */ - int rev_index; - - /* Did we do any measurement on this rate? */ - bool valid; - - /* Comparison with the lowest rate. */ - int diff; -}; - -struct rc_pid_info { - - /* The failed frames percentage target. */ - unsigned int target; - - /* Rate at which failed frames percentage is sampled in 0.001s. */ - unsigned int sampling_period; - - /* P, I and D coefficients. */ - int coeff_p; - int coeff_i; - int coeff_d; - - /* Exponential averaging shift. */ - unsigned int smoothing_shift; - - /* Sharpening factor and duration. */ - unsigned int sharpen_factor; - unsigned int sharpen_duration; - - /* Normalization offset. */ - unsigned int norm_offset; - - /* Rates information. */ - struct rc_pid_rateinfo *rinfo; - - /* Index of the last used rate. */ - int oldrate; - -#ifdef CONFIG_MAC80211_DEBUGFS - /* Debugfs entries created for the parameters above. */ - struct rc_pid_debugfs_entries dentries; -#endif -}; - -#endif /* RC80211_PID_H */ diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c deleted file mode 100644 index d0da2a70fe68..000000000000 --- a/net/mac80211/rc80211_pid_algo.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005, Devicescape Software, Inc. - * Copyright 2007, Mattias Nissler - * Copyright 2007-2008, Stefano Brivio - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include "rate.h" -#include "mesh.h" -#include "rc80211_pid.h" - - -/* This is an implementation of a TX rate control algorithm that uses a PID - * controller. Given a target failed frames rate, the controller decides about - * TX rate changes to meet the target failed frames rate. - * - * The controller basically computes the following: - * - * adj = CP * err + CI * err_avg + CD * (err - last_err) * (1 + sharpening) - * - * where - * adj adjustment value that is used to switch TX rate (see below) - * err current error: target vs. current failed frames percentage - * last_err last error - * err_avg average (i.e. poor man's integral) of recent errors - * sharpening non-zero when fast response is needed (i.e. right after - * association or no frames sent for a long time), heading - * to zero over time - * CP Proportional coefficient - * CI Integral coefficient - * CD Derivative coefficient - * - * CP, CI, CD are subject to careful tuning. - * - * The integral component uses a exponential moving average approach instead of - * an actual sliding window. The advantage is that we don't need to keep an - * array of the last N error values and computation is easier. - * - * Once we have the adj value, we map it to a rate by means of a learning - * algorithm. This algorithm keeps the state of the percentual failed frames - * difference between rates. The behaviour of the lowest available rate is kept - * as a reference value, and every time we switch between two rates, we compute - * the difference between the failed frames each rate exhibited. By doing so, - * we compare behaviours which different rates exhibited in adjacent timeslices, - * thus the comparison is minimally affected by external conditions. This - * difference gets propagated to the whole set of measurements, so that the - * reference is always the same. Periodically, we normalize this set so that - * recent events weigh the most. By comparing the adj value with this set, we - * avoid pejorative switches to lower rates and allow for switches to higher - * rates if they behaved well. - * - * Note that for the computations we use a fixed-point representation to avoid - * floating point arithmetic. Hence, all values are shifted left by - * RC_PID_ARITH_SHIFT. - */ - - -/* Adjust the rate while ensuring that we won't switch to a lower rate if it - * exhibited a worse failed frames behaviour and we'll choose the highest rate - * whose failed frames behaviour is not worse than the one of the original rate - * target. While at it, check that the new rate is valid. */ -static void rate_control_pid_adjust_rate(struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, - struct rc_pid_sta_info *spinfo, int adj, - struct rc_pid_rateinfo *rinfo) -{ - int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; - int cur = spinfo->txrate_idx; - - band = sband->band; - n_bitrates = sband->n_bitrates; - - /* Map passed arguments to sorted values. */ - cur_sorted = rinfo[cur].rev_index; - new_sorted = cur_sorted + adj; - - /* Check limits. */ - if (new_sorted < 0) - new_sorted = rinfo[0].rev_index; - else if (new_sorted >= n_bitrates) - new_sorted = rinfo[n_bitrates - 1].rev_index; - - tmp = new_sorted; - - if (adj < 0) { - /* Ensure that the rate decrease isn't disadvantageous. */ - for (probe = cur_sorted; probe >= new_sorted; probe--) - if (rinfo[probe].diff <= rinfo[cur_sorted].diff && - rate_supported(sta, band, rinfo[probe].index)) - tmp = probe; - } else { - /* Look for rate increase with zero (or below) cost. */ - for (probe = new_sorted + 1; probe < n_bitrates; probe++) - if (rinfo[probe].diff <= rinfo[new_sorted].diff && - rate_supported(sta, band, rinfo[probe].index)) - tmp = probe; - } - - /* Fit the rate found to the nearest supported rate. */ - do { - if (rate_supported(sta, band, rinfo[tmp].index)) { - spinfo->txrate_idx = rinfo[tmp].index; - break; - } - if (adj < 0) - tmp--; - else - tmp++; - } while (tmp < n_bitrates && tmp >= 0); - -#ifdef CONFIG_MAC80211_DEBUGFS - rate_control_pid_event_rate_change(&spinfo->events, - spinfo->txrate_idx, - sband->bitrates[spinfo->txrate_idx].bitrate); -#endif -} - -/* Normalize the failed frames per-rate differences. */ -static void rate_control_pid_normalize(struct rc_pid_info *pinfo, int l) -{ - int i, norm_offset = pinfo->norm_offset; - struct rc_pid_rateinfo *r = pinfo->rinfo; - - if (r[0].diff > norm_offset) - r[0].diff -= norm_offset; - else if (r[0].diff < -norm_offset) - r[0].diff += norm_offset; - for (i = 0; i < l - 1; i++) - if (r[i + 1].diff > r[i].diff + norm_offset) - r[i + 1].diff -= norm_offset; - else if (r[i + 1].diff <= r[i].diff) - r[i + 1].diff += norm_offset; -} - -static void rate_control_pid_sample(struct rc_pid_info *pinfo, - struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, - struct rc_pid_sta_info *spinfo) -{ - struct rc_pid_rateinfo *rinfo = pinfo->rinfo; - u32 pf; - s32 err_avg; - u32 err_prop; - u32 err_int; - u32 err_der; - int adj, i, j, tmp; - unsigned long period; - - /* In case nothing happened during the previous control interval, turn - * the sharpening factor on. */ - period = msecs_to_jiffies(pinfo->sampling_period); - if (jiffies - spinfo->last_sample > 2 * period) - spinfo->sharp_cnt = pinfo->sharpen_duration; - - spinfo->last_sample = jiffies; - - /* This should never happen, but in case, we assume the old sample is - * still a good measurement and copy it. */ - if (unlikely(spinfo->tx_num_xmit == 0)) - pf = spinfo->last_pf; - else - pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; - - spinfo->tx_num_xmit = 0; - spinfo->tx_num_failed = 0; - - /* If we just switched rate, update the rate behaviour info. */ - if (pinfo->oldrate != spinfo->txrate_idx) { - - i = rinfo[pinfo->oldrate].rev_index; - j = rinfo[spinfo->txrate_idx].rev_index; - - tmp = (pf - spinfo->last_pf); - tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT); - - rinfo[j].diff = rinfo[i].diff + tmp; - pinfo->oldrate = spinfo->txrate_idx; - } - rate_control_pid_normalize(pinfo, sband->n_bitrates); - - /* Compute the proportional, integral and derivative errors. */ - err_prop = (pinfo->target - pf) << RC_PID_ARITH_SHIFT; - - err_avg = spinfo->err_avg_sc >> pinfo->smoothing_shift; - spinfo->err_avg_sc = spinfo->err_avg_sc - err_avg + err_prop; - err_int = spinfo->err_avg_sc >> pinfo->smoothing_shift; - - err_der = (pf - spinfo->last_pf) * - (1 + pinfo->sharpen_factor * spinfo->sharp_cnt); - spinfo->last_pf = pf; - if (spinfo->sharp_cnt) - spinfo->sharp_cnt--; - -#ifdef CONFIG_MAC80211_DEBUGFS - rate_control_pid_event_pf_sample(&spinfo->events, pf, err_prop, err_int, - err_der); -#endif - - /* Compute the controller output. */ - adj = (err_prop * pinfo->coeff_p + err_int * pinfo->coeff_i - + err_der * pinfo->coeff_d); - adj = RC_PID_DO_ARITH_RIGHT_SHIFT(adj, 2 * RC_PID_ARITH_SHIFT); - - /* Change rate. */ - if (adj) - rate_control_pid_adjust_rate(sband, sta, spinfo, adj, rinfo); -} - -static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb) -{ - struct rc_pid_info *pinfo = priv; - struct rc_pid_sta_info *spinfo = priv_sta; - unsigned long period; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - if (!spinfo) - return; - - /* Ignore all frames that were sent with a different rate than the rate - * we currently advise mac80211 to use. */ - if (info->status.rates[0].idx != spinfo->txrate_idx) - return; - - spinfo->tx_num_xmit++; - -#ifdef CONFIG_MAC80211_DEBUGFS - rate_control_pid_event_tx_status(&spinfo->events, info); -#endif - - /* We count frames that totally failed to be transmitted as two bad - * frames, those that made it out but had some retries as one good and - * one bad frame. */ - if (!(info->flags & IEEE80211_TX_STAT_ACK)) { - spinfo->tx_num_failed += 2; - spinfo->tx_num_xmit++; - } else if (info->status.rates[0].count > 1) { - spinfo->tx_num_failed++; - spinfo->tx_num_xmit++; - } - - /* Update PID controller state. */ - period = msecs_to_jiffies(pinfo->sampling_period); - if (time_after(jiffies, spinfo->last_sample + period)) - rate_control_pid_sample(pinfo, sband, sta, spinfo); -} - -static void -rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, - void *priv_sta, - struct ieee80211_tx_rate_control *txrc) -{ - struct sk_buff *skb = txrc->skb; - struct ieee80211_supported_band *sband = txrc->sband; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct rc_pid_sta_info *spinfo = priv_sta; - int rateidx; - - if (txrc->rts) - info->control.rates[0].count = - txrc->hw->conf.long_frame_max_tx_count; - else - info->control.rates[0].count = - txrc->hw->conf.short_frame_max_tx_count; - - /* Send management frames and NO_ACK data using lowest rate. */ - if (rate_control_send_low(sta, priv_sta, txrc)) - return; - - rateidx = spinfo->txrate_idx; - - if (rateidx >= sband->n_bitrates) - rateidx = sband->n_bitrates - 1; - - info->control.rates[0].idx = rateidx; - -#ifdef CONFIG_MAC80211_DEBUGFS - rate_control_pid_event_tx_rate(&spinfo->events, - rateidx, sband->bitrates[rateidx].bitrate); -#endif -} - -static void -rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, - struct cfg80211_chan_def *chandef, - struct ieee80211_sta *sta, void *priv_sta) -{ - struct rc_pid_sta_info *spinfo = priv_sta; - struct rc_pid_info *pinfo = priv; - struct rc_pid_rateinfo *rinfo = pinfo->rinfo; - int i, j, tmp; - bool s; - - /* TODO: This routine should consider using RSSI from previous packets - * as we need to have IEEE 802.1X auth succeed immediately after assoc.. - * Until that method is implemented, we will use the lowest supported - * rate as a workaround. */ - - /* Sort the rates. This is optimized for the most common case (i.e. - * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed - * mapping too. */ - for (i = 0; i < sband->n_bitrates; i++) { - rinfo[i].index = i; - rinfo[i].rev_index = i; - if (RC_PID_FAST_START) - rinfo[i].diff = 0; - else - rinfo[i].diff = i * pinfo->norm_offset; - } - for (i = 1; i < sband->n_bitrates; i++) { - s = false; - for (j = 0; j < sband->n_bitrates - i; j++) - if (unlikely(sband->bitrates[rinfo[j].index].bitrate > - sband->bitrates[rinfo[j + 1].index].bitrate)) { - tmp = rinfo[j].index; - rinfo[j].index = rinfo[j + 1].index; - rinfo[j + 1].index = tmp; - rinfo[rinfo[j].index].rev_index = j; - rinfo[rinfo[j + 1].index].rev_index = j + 1; - s = true; - } - if (!s) - break; - } - - spinfo->txrate_idx = rate_lowest_index(sband, sta); -} - -static void *rate_control_pid_alloc(struct ieee80211_hw *hw, - struct dentry *debugfsdir) -{ - struct rc_pid_info *pinfo; - struct rc_pid_rateinfo *rinfo; - struct ieee80211_supported_band *sband; - int i, max_rates = 0; -#ifdef CONFIG_MAC80211_DEBUGFS - struct rc_pid_debugfs_entries *de; -#endif - - pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC); - if (!pinfo) - return NULL; - - for (i = 0; i < IEEE80211_NUM_BANDS; i++) { - sband = hw->wiphy->bands[i]; - if (sband && sband->n_bitrates > max_rates) - max_rates = sband->n_bitrates; - } - - rinfo = kmalloc(sizeof(*rinfo) * max_rates, GFP_ATOMIC); - if (!rinfo) { - kfree(pinfo); - return NULL; - } - - pinfo->target = RC_PID_TARGET_PF; - pinfo->sampling_period = RC_PID_INTERVAL; - pinfo->coeff_p = RC_PID_COEFF_P; - pinfo->coeff_i = RC_PID_COEFF_I; - pinfo->coeff_d = RC_PID_COEFF_D; - pinfo->smoothing_shift = RC_PID_SMOOTHING_SHIFT; - pinfo->sharpen_factor = RC_PID_SHARPENING_FACTOR; - pinfo->sharpen_duration = RC_PID_SHARPENING_DURATION; - pinfo->norm_offset = RC_PID_NORM_OFFSET; - pinfo->rinfo = rinfo; - pinfo->oldrate = 0; - -#ifdef CONFIG_MAC80211_DEBUGFS - de = &pinfo->dentries; - de->target = debugfs_create_u32("target_pf", S_IRUSR | S_IWUSR, - debugfsdir, &pinfo->target); - de->sampling_period = debugfs_create_u32("sampling_period", - S_IRUSR | S_IWUSR, debugfsdir, - &pinfo->sampling_period); - de->coeff_p = debugfs_create_u32("coeff_p", S_IRUSR | S_IWUSR, - debugfsdir, (u32 *)&pinfo->coeff_p); - de->coeff_i = debugfs_create_u32("coeff_i", S_IRUSR | S_IWUSR, - debugfsdir, (u32 *)&pinfo->coeff_i); - de->coeff_d = debugfs_create_u32("coeff_d", S_IRUSR | S_IWUSR, - debugfsdir, (u32 *)&pinfo->coeff_d); - de->smoothing_shift = debugfs_create_u32("smoothing_shift", - S_IRUSR | S_IWUSR, debugfsdir, - &pinfo->smoothing_shift); - de->sharpen_factor = debugfs_create_u32("sharpen_factor", - S_IRUSR | S_IWUSR, debugfsdir, - &pinfo->sharpen_factor); - de->sharpen_duration = debugfs_create_u32("sharpen_duration", - S_IRUSR | S_IWUSR, debugfsdir, - &pinfo->sharpen_duration); - de->norm_offset = debugfs_create_u32("norm_offset", - S_IRUSR | S_IWUSR, debugfsdir, - &pinfo->norm_offset); -#endif - - return pinfo; -} - -static void rate_control_pid_free(void *priv) -{ - struct rc_pid_info *pinfo = priv; -#ifdef CONFIG_MAC80211_DEBUGFS - struct rc_pid_debugfs_entries *de = &pinfo->dentries; - - debugfs_remove(de->norm_offset); - debugfs_remove(de->sharpen_duration); - debugfs_remove(de->sharpen_factor); - debugfs_remove(de->smoothing_shift); - debugfs_remove(de->coeff_d); - debugfs_remove(de->coeff_i); - debugfs_remove(de->coeff_p); - debugfs_remove(de->sampling_period); - debugfs_remove(de->target); -#endif - - kfree(pinfo->rinfo); - kfree(pinfo); -} - -static void *rate_control_pid_alloc_sta(void *priv, struct ieee80211_sta *sta, - gfp_t gfp) -{ - struct rc_pid_sta_info *spinfo; - - spinfo = kzalloc(sizeof(*spinfo), gfp); - if (spinfo == NULL) - return NULL; - - spinfo->last_sample = jiffies; - -#ifdef CONFIG_MAC80211_DEBUGFS - spin_lock_init(&spinfo->events.lock); - init_waitqueue_head(&spinfo->events.waitqueue); -#endif - - return spinfo; -} - -static void rate_control_pid_free_sta(void *priv, struct ieee80211_sta *sta, - void *priv_sta) -{ - kfree(priv_sta); -} - -static const struct rate_control_ops mac80211_rcpid = { - .name = "pid", - .tx_status = rate_control_pid_tx_status, - .get_rate = rate_control_pid_get_rate, - .rate_init = rate_control_pid_rate_init, - .alloc = rate_control_pid_alloc, - .free = rate_control_pid_free, - .alloc_sta = rate_control_pid_alloc_sta, - .free_sta = rate_control_pid_free_sta, -#ifdef CONFIG_MAC80211_DEBUGFS - .add_sta_debugfs = rate_control_pid_add_sta_debugfs, - .remove_sta_debugfs = rate_control_pid_remove_sta_debugfs, -#endif -}; - -int __init rc80211_pid_init(void) -{ - return ieee80211_rate_control_register(&mac80211_rcpid); -} - -void rc80211_pid_exit(void) -{ - ieee80211_rate_control_unregister(&mac80211_rcpid); -} diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c deleted file mode 100644 index 6ff134650a84..000000000000 --- a/net/mac80211/rc80211_pid_debugfs.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2007, Mattias Nissler - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "rate.h" - -#include "rc80211_pid.h" - -static void rate_control_pid_event(struct rc_pid_event_buffer *buf, - enum rc_pid_event_type type, - union rc_pid_event_data *data) -{ - struct rc_pid_event *ev; - unsigned long status; - - spin_lock_irqsave(&buf->lock, status); - ev = &(buf->ring[buf->next_entry]); - buf->next_entry = (buf->next_entry + 1) % RC_PID_EVENT_RING_SIZE; - - ev->timestamp = jiffies; - ev->id = buf->ev_count++; - ev->type = type; - ev->data = *data; - - spin_unlock_irqrestore(&buf->lock, status); - - wake_up_all(&buf->waitqueue); -} - -void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, - struct ieee80211_tx_info *stat) -{ - union rc_pid_event_data evd; - - evd.flags = stat->flags; - memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info)); - rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd); -} - -void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, - int index, int rate) -{ - union rc_pid_event_data evd; - - evd.index = index; - evd.rate = rate; - rate_control_pid_event(buf, RC_PID_EVENT_TYPE_RATE_CHANGE, &evd); -} - -void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf, - int index, int rate) -{ - union rc_pid_event_data evd; - - evd.index = index; - evd.rate = rate; - rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_RATE, &evd); -} - -void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf, - s32 pf_sample, s32 prop_err, - s32 int_err, s32 der_err) -{ - union rc_pid_event_data evd; - - evd.pf_sample = pf_sample; - evd.prop_err = prop_err; - evd.int_err = int_err; - evd.der_err = der_err; - rate_control_pid_event(buf, RC_PID_EVENT_TYPE_PF_SAMPLE, &evd); -} - -static int rate_control_pid_events_open(struct inode *inode, struct file *file) -{ - struct rc_pid_sta_info *sinfo = inode->i_private; - struct rc_pid_event_buffer *events = &sinfo->events; - struct rc_pid_events_file_info *file_info; - unsigned long status; - - /* Allocate a state struct */ - file_info = kmalloc(sizeof(*file_info), GFP_KERNEL); - if (file_info == NULL) - return -ENOMEM; - - spin_lock_irqsave(&events->lock, status); - - file_info->next_entry = events->next_entry; - file_info->events = events; - - spin_unlock_irqrestore(&events->lock, status); - - file->private_data = file_info; - - return 0; -} - -static int rate_control_pid_events_release(struct inode *inode, - struct file *file) -{ - struct rc_pid_events_file_info *file_info = file->private_data; - - kfree(file_info); - - return 0; -} - -static unsigned int rate_control_pid_events_poll(struct file *file, - poll_table *wait) -{ - struct rc_pid_events_file_info *file_info = file->private_data; - - poll_wait(file, &file_info->events->waitqueue, wait); - - return POLLIN | POLLRDNORM; -} - -#define RC_PID_PRINT_BUF_SIZE 64 - -static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, - size_t length, loff_t *offset) -{ - struct rc_pid_events_file_info *file_info = file->private_data; - struct rc_pid_event_buffer *events = file_info->events; - struct rc_pid_event *ev; - char pb[RC_PID_PRINT_BUF_SIZE]; - int ret; - int p; - unsigned long status; - - /* Check if there is something to read. */ - if (events->next_entry == file_info->next_entry) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - /* Wait */ - ret = wait_event_interruptible(events->waitqueue, - events->next_entry != file_info->next_entry); - - if (ret) - return ret; - } - - /* Write out one event per call. I don't care whether it's a little - * inefficient, this is debugging code anyway. */ - spin_lock_irqsave(&events->lock, status); - - /* Get an event */ - ev = &(events->ring[file_info->next_entry]); - file_info->next_entry = (file_info->next_entry + 1) % - RC_PID_EVENT_RING_SIZE; - - /* Print information about the event. Note that userspace needs to - * provide large enough buffers. */ - length = length < RC_PID_PRINT_BUF_SIZE ? - length : RC_PID_PRINT_BUF_SIZE; - p = scnprintf(pb, length, "%u %lu ", ev->id, ev->timestamp); - switch (ev->type) { - case RC_PID_EVENT_TYPE_TX_STATUS: - p += scnprintf(pb + p, length - p, "tx_status %u %u", - !(ev->data.flags & IEEE80211_TX_STAT_ACK), - ev->data.tx_status.status.rates[0].idx); - break; - case RC_PID_EVENT_TYPE_RATE_CHANGE: - p += scnprintf(pb + p, length - p, "rate_change %d %d", - ev->data.index, ev->data.rate); - break; - case RC_PID_EVENT_TYPE_TX_RATE: - p += scnprintf(pb + p, length - p, "tx_rate %d %d", - ev->data.index, ev->data.rate); - break; - case RC_PID_EVENT_TYPE_PF_SAMPLE: - p += scnprintf(pb + p, length - p, - "pf_sample %d %d %d %d", - ev->data.pf_sample, ev->data.prop_err, - ev->data.int_err, ev->data.der_err); - break; - } - p += scnprintf(pb + p, length - p, "\n"); - - spin_unlock_irqrestore(&events->lock, status); - - if (copy_to_user(buf, pb, p)) - return -EFAULT; - - return p; -} - -#undef RC_PID_PRINT_BUF_SIZE - -static const struct file_operations rc_pid_fop_events = { - .owner = THIS_MODULE, - .read = rate_control_pid_events_read, - .poll = rate_control_pid_events_poll, - .open = rate_control_pid_events_open, - .release = rate_control_pid_events_release, - .llseek = noop_llseek, -}; - -void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta, - struct dentry *dir) -{ - struct rc_pid_sta_info *spinfo = priv_sta; - - spinfo->events_entry = debugfs_create_file("rc_pid_events", S_IRUGO, - dir, spinfo, - &rc_pid_fop_events); -} - -void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta) -{ - struct rc_pid_sta_info *spinfo = priv_sta; - - debugfs_remove(spinfo->events_entry); -} -- cgit v1.2.3 From 5ac2e35030113ed881ce9ad413d80f13ffe5b5a0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 27 May 2014 16:32:27 +0200 Subject: mac80211: fix station/driver powersave race It is currently possible to have a race due to the station PS unblock work like this: * station goes to sleep with frames buffered in the driver * driver blocks wakeup * station wakes up again * driver flushes/returns frames, and unblocks, which schedules the unblock work * unblock work starts to run, and checks that the station is awake (i.e. that the WLAN_STA_PS_STA flag isn't set) * we process a received frame with PM=1, setting the flag again * ieee80211_sta_ps_deliver_wakeup() runs, delivering all frames to the driver, and then clearing the WLAN_STA_PS_DRIVER and WLAN_STA_PS_STA flags In this scenario, mac80211 will think that the station is awake, while it really is asleep, and any TX'ed frames should be filtered by the device (it will know that the station is sleeping) but then passed to mac80211 again, which will not buffer it either as it thinks the station is awake, and eventually the packets will be dropped. Fix this by moving the clearing of the flags to exactly where we learn about the situation. This creates a problem of reordering, so introduce another flag indicating that delivery is being done, this new flag also queues frames and is cleared only while the spinlock is held (which the queuing code also holds) so that any concurrent delivery/TX is handled correctly. Reported-by: Andrei Otcheretianski Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 2 ++ net/mac80211/sta_info.c | 65 ++++++++++++++++++++++++++++++------------------- net/mac80211/sta_info.h | 7 ++++-- net/mac80211/tx.c | 6 +++-- 4 files changed, 51 insertions(+), 29 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 394e201cde6d..5f572bed1761 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1107,6 +1107,8 @@ static void sta_ps_end(struct sta_info *sta) return; } + set_sta_flag(sta, WLAN_STA_PS_DELIVER); + clear_sta_flag(sta, WLAN_STA_PS_STA); ieee80211_sta_ps_deliver_wakeup(sta); } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a9b46d8ea22f..ae7c16ad5f22 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -100,7 +100,8 @@ static void __cleanup_single_sta(struct sta_info *sta) struct ps_data *ps; if (test_sta_flag(sta, WLAN_STA_PS_STA) || - test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { + test_sta_flag(sta, WLAN_STA_PS_DRIVER) || + test_sta_flag(sta, WLAN_STA_PS_DELIVER)) { if (sta->sdata->vif.type == NL80211_IFTYPE_AP || sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) ps = &sdata->bss->ps; @@ -111,6 +112,7 @@ static void __cleanup_single_sta(struct sta_info *sta) clear_sta_flag(sta, WLAN_STA_PS_STA); clear_sta_flag(sta, WLAN_STA_PS_DRIVER); + clear_sta_flag(sta, WLAN_STA_PS_DELIVER); atomic_dec(&ps->num_sta_ps); sta_info_recalc_tim(sta); @@ -125,7 +127,7 @@ static void __cleanup_single_sta(struct sta_info *sta) if (ieee80211_vif_is_mesh(&sdata->vif)) mesh_sta_cleanup(sta); - cancel_work_sync(&sta->drv_unblock_wk); + cancel_work_sync(&sta->drv_deliver_wk); /* * Destroy aggregation state here. It would be nice to wait for the @@ -253,33 +255,23 @@ static void sta_info_hash_add(struct ieee80211_local *local, rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); } -static void sta_unblock(struct work_struct *wk) +static void sta_deliver_ps_frames(struct work_struct *wk) { struct sta_info *sta; - sta = container_of(wk, struct sta_info, drv_unblock_wk); + sta = container_of(wk, struct sta_info, drv_deliver_wk); if (sta->dead) return; - if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { - local_bh_disable(); + local_bh_disable(); + if (!test_sta_flag(sta, WLAN_STA_PS_STA)) ieee80211_sta_ps_deliver_wakeup(sta); - local_bh_enable(); - } else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) { - clear_sta_flag(sta, WLAN_STA_PS_DRIVER); - - local_bh_disable(); + else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) ieee80211_sta_ps_deliver_poll_response(sta); - local_bh_enable(); - } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) { - clear_sta_flag(sta, WLAN_STA_PS_DRIVER); - - local_bh_disable(); + else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) ieee80211_sta_ps_deliver_uapsd(sta); - local_bh_enable(); - } else - clear_sta_flag(sta, WLAN_STA_PS_DRIVER); + local_bh_enable(); } static int sta_prepare_rate_control(struct ieee80211_local *local, @@ -341,7 +333,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, spin_lock_init(&sta->lock); spin_lock_init(&sta->ps_lock); - INIT_WORK(&sta->drv_unblock_wk, sta_unblock); + INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); mutex_init(&sta->ampdu_mlme.mtx); #ifdef CONFIG_MAC80211_MESH @@ -1141,8 +1133,15 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) } ieee80211_add_pending_skbs(local, &pending); - clear_sta_flag(sta, WLAN_STA_PS_DRIVER); - clear_sta_flag(sta, WLAN_STA_PS_STA); + + /* now we're no longer in the deliver code */ + clear_sta_flag(sta, WLAN_STA_PS_DELIVER); + + /* The station might have polled and then woken up before we responded, + * so clear these flags now to avoid them sticking around. + */ + clear_sta_flag(sta, WLAN_STA_PSPOLL); + clear_sta_flag(sta, WLAN_STA_UAPSD); spin_unlock(&sta->ps_lock); atomic_dec(&ps->num_sta_ps); @@ -1543,10 +1542,26 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, trace_api_sta_block_awake(sta->local, pubsta, block); - if (block) + if (block) { set_sta_flag(sta, WLAN_STA_PS_DRIVER); - else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) - ieee80211_queue_work(hw, &sta->drv_unblock_wk); + return; + } + + if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) + return; + + if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { + set_sta_flag(sta, WLAN_STA_PS_DELIVER); + clear_sta_flag(sta, WLAN_STA_PS_DRIVER); + ieee80211_queue_work(hw, &sta->drv_deliver_wk); + } else if (test_sta_flag(sta, WLAN_STA_PSPOLL) || + test_sta_flag(sta, WLAN_STA_UAPSD)) { + /* must be asleep in this case */ + clear_sta_flag(sta, WLAN_STA_PS_DRIVER); + ieee80211_queue_work(hw, &sta->drv_deliver_wk); + } else { + clear_sta_flag(sta, WLAN_STA_PS_DRIVER); + } } EXPORT_SYMBOL(ieee80211_sta_block_awake); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4acc5fc402fa..dee0b645b34c 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -58,6 +58,8 @@ * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid. * @WLAN_STA_MPSP_OWNER: local STA is owner of a mesh Peer Service Period. * @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP. + * @WLAN_STA_PS_DELIVER: station woke up, but we're still blocking TX + * until pending frames are delivered */ enum ieee80211_sta_info_flags { WLAN_STA_AUTH, @@ -82,6 +84,7 @@ enum ieee80211_sta_info_flags { WLAN_STA_TOFFSET_KNOWN, WLAN_STA_MPSP_OWNER, WLAN_STA_MPSP_RECIPIENT, + WLAN_STA_PS_DELIVER, }; #define ADDBA_RESP_INTERVAL HZ @@ -265,7 +268,7 @@ struct ieee80211_tx_latency_stat { * @last_rx_rate_vht_nss: rx status nss of last data packet * @lock: used for locking all fields that require locking, see comments * in the header file. - * @drv_unblock_wk: used for driver PS unblocking + * @drv_deliver_wk: used for delivering frames after driver PS unblocking * @listen_interval: listen interval of this station, when we're acting as AP * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly * @ps_lock: used for powersave (when mac80211 is the AP) related locking @@ -345,7 +348,7 @@ struct sta_info { void *rate_ctrl_priv; spinlock_t lock; - struct work_struct drv_unblock_wk; + struct work_struct drv_deliver_wk; u16 listen_interval; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5214686d9fd1..8170d9945d6d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -469,7 +469,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) return TX_CONTINUE; if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) || - test_sta_flag(sta, WLAN_STA_PS_DRIVER)) && + test_sta_flag(sta, WLAN_STA_PS_DRIVER) || + test_sta_flag(sta, WLAN_STA_PS_DELIVER)) && !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) { int ac = skb_get_queue_mapping(tx->skb); @@ -486,7 +487,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) * ahead and Tx the packet. */ if (!test_sta_flag(sta, WLAN_STA_PS_STA) && - !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { + !test_sta_flag(sta, WLAN_STA_PS_DRIVER) && + !test_sta_flag(sta, WLAN_STA_PS_DELIVER)) { spin_unlock(&sta->ps_lock); return TX_CONTINUE; } -- cgit v1.2.3 From 2b470c39e895dfde5413b0a85fac928a353de48d Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 4 Jun 2014 09:27:31 -0400 Subject: mac80211: remove ignore_plink_timer flag The mesh_plink code is doing some interesting things with the ignore_plink_timer flag. It seems the original intent was to handle this race: cpu 0 cpu 1 ----- ----- start timer handler for state X acquire sta_lock change state from X to Y mod_timer() / del_timer() release sta_lock acquire sta_lock execute state Y timer too soon However, using the mod_timer()/del_timer() return values to detect these cases is broken. As a result, timers get ignored unnecessarily, and stations can get stuck in the peering state machine. Instead, we can detect the case by looking at the timer expiration. In the case of del_timer, just ignore the timers in the following (LISTEN/ESTAB) states since they won't have timers anyway. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 30 +++++++++++++++++++++++------- net/mac80211/sta_info.h | 2 -- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index e8f60aa2e848..63b874101b27 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -551,11 +551,30 @@ static void mesh_plink_timer(unsigned long data) return; spin_lock_bh(&sta->lock); - if (sta->ignore_plink_timer) { - sta->ignore_plink_timer = false; + + /* If a timer fires just before a state transition on another CPU, + * we may have already extended the timeout and changed state by the + * time we've acquired the lock and arrived here. In that case, + * skip this timer and wait for the new one. + */ + if (time_before(jiffies, sta->plink_timer.expires)) { + mpl_dbg(sta->sdata, + "Ignoring timer for %pM in state %s (timer adjusted)", + sta->sta.addr, mplstates[sta->plink_state]); spin_unlock_bh(&sta->lock); return; } + + /* del_timer() and handler may race when entering these states */ + if (sta->plink_state == NL80211_PLINK_LISTEN || + sta->plink_state == NL80211_PLINK_ESTAB) { + mpl_dbg(sta->sdata, + "Ignoring timer for %pM in state %s (timer deleted)", + sta->sta.addr, mplstates[sta->plink_state]); + spin_unlock_bh(&sta->lock); + return; + } + mpl_dbg(sta->sdata, "Mesh plink timer for %pM fired on state %s\n", sta->sta.addr, mplstates[sta->plink_state]); @@ -773,9 +792,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, break; case CNF_ACPT: sta->plink_state = NL80211_PLINK_CNF_RCVD; - if (!mod_plink_timer(sta, - mshcfg->dot11MeshConfirmTimeout)) - sta->ignore_plink_timer = true; + mod_plink_timer(sta, mshcfg->dot11MeshConfirmTimeout); break; default: break; @@ -834,8 +851,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, case NL80211_PLINK_HOLDING: switch (event) { case CLS_ACPT: - if (del_timer(&sta->plink_timer)) - sta->ignore_plink_timer = 1; + del_timer(&sta->plink_timer); mesh_plink_fsm_restart(sta); break; case OPN_ACPT: diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index dee0b645b34c..159cac903ce8 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -306,7 +306,6 @@ struct ieee80211_tx_latency_stat { * @plid: Peer link ID * @reason: Cancel reason on PLINK_HOLDING state * @plink_retries: Retries in establishment - * @ignore_plink_timer: ignore the peer-link timer (used internally) * @plink_state: peer link state * @plink_timeout: timeout of peer link * @plink_timer: peer link watch timer @@ -421,7 +420,6 @@ struct sta_info { u16 plid; u16 reason; u8 plink_retries; - bool ignore_plink_timer; enum nl80211_plink_state plink_state; u32 plink_timeout; struct timer_list plink_timer; -- cgit v1.2.3 From b314c669905cbef00fed33028c61c96efeea08f5 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Wed, 4 Jun 2014 14:03:49 +0200 Subject: trivial: net/mac80211/mesh.c: fix typo s/Substract/Subtract/ Signed-off-by: Antonio Ospite Cc: Luis Carlos Cobo Cc: Johannes Berg Cc: linux-wireless@vger.kernel.org Signed-off-by: Johannes Berg --- net/mac80211/mesh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 6495a3f0428d..da164685b524 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1122,7 +1122,7 @@ static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len); /* offset_ttl is based on whether the secondary channel - * offset is available or not. Substract 1 from the mesh TTL + * offset is available or not. Subtract 1 from the mesh TTL * and disable the initiator flag before forwarding. */ offset_ttl = (len < 42) ? 7 : 10; -- cgit v1.2.3 From ba9030c20a2def223d9b993cb3dfdd3aab3d2b31 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jun 2014 17:06:23 +0200 Subject: mac80211: remove weak WEP IV accounting Since WEP is practically dead, there seems very little point in keeping WEP weak IV accounting. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 3 +-- net/mac80211/debugfs_sta.c | 1 - net/mac80211/sta_info.h | 2 -- net/mac80211/wep.c | 20 -------------------- 4 files changed, 1 insertion(+), 25 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d7513a503be1..f8d065480ba9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -603,7 +603,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) } static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { - "rx_packets", "rx_bytes", "wep_weak_iv_count", + "rx_packets", "rx_bytes", "rx_duplicates", "rx_fragments", "rx_dropped", "tx_packets", "tx_bytes", "tx_fragments", "tx_filtered", "tx_retry_failed", "tx_retries", @@ -651,7 +651,6 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, do { \ data[i++] += sta->rx_packets; \ data[i++] += sta->rx_bytes; \ - data[i++] += sta->wep_weak_iv_count; \ data[i++] += sta->num_duplicates; \ data[i++] += sta->rx_fragments; \ data[i++] += sta->rx_dropped; \ diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 2ecb4deddb5d..ee82e1f0a9e7 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -587,7 +587,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count); DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed); DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); - DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count); if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) debugfs_create_x32("driver_buffered_tids", 0400, diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 159cac903ce8..fa7ce6f8593b 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -281,7 +281,6 @@ struct ieee80211_tx_latency_stat { * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on * @rx_packets: Number of MSDUs received from this STA * @rx_bytes: Number of bytes received from this STA - * @wep_weak_iv_count: number of weak WEP IVs received from this station * @last_rx: time (in jiffies) when last frame was received from this STA * @last_connected: time (in seconds) when a station got connected * @num_duplicates: number of duplicate frames received from this STA @@ -369,7 +368,6 @@ struct sta_info { /* Updated from RX path only, no locking requirements */ unsigned long rx_packets; u64 rx_bytes; - unsigned long wep_weak_iv_count; unsigned long last_rx; long last_connected; unsigned long num_duplicates; diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 6ee2b5863572..9181fb6d6437 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -271,22 +271,6 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local, return ret; } - -static bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, - struct ieee80211_key *key) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - unsigned int hdrlen; - u8 *ivpos; - u32 iv; - - hdrlen = ieee80211_hdrlen(hdr->frame_control); - ivpos = skb->data + hdrlen; - iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2]; - - return ieee80211_wep_weak_iv(iv, key->conf.keylen); -} - ieee80211_rx_result ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) { @@ -301,16 +285,12 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) if (!(status->flag & RX_FLAG_DECRYPTED)) { if (skb_linearize(rx->skb)) return RX_DROP_UNUSABLE; - if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) - rx->sta->wep_weak_iv_count++; if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) return RX_DROP_UNUSABLE; } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) + IEEE80211_WEP_IV_LEN)) return RX_DROP_UNUSABLE; - if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) - rx->sta->wep_weak_iv_count++; ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); /* remove ICV */ if (pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN)) -- cgit v1.2.3 From b7ffbd7ef6751f6cde73082346e365738daf00d2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jun 2014 17:31:56 +0200 Subject: cfg80211: make ethtool the driver's responsibility Currently, cfg80211 tries to implement ethtool, but that doesn't really scale well, with all the different operations. Make the lower-level driver responsible for it, which currently only has an effect on mac80211. It will similarly not scale well at that level though, since mac80211 also has many drivers. To cleanly implement this in mac80211, introduce a new file and move some code to appropriate places. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 29 +--- net/mac80211/Makefile | 1 + net/mac80211/cfg.c | 340 --------------------------------------------- net/mac80211/ethtool.c | 244 ++++++++++++++++++++++++++++++++ net/mac80211/ieee80211_i.h | 2 + net/mac80211/iface.c | 2 + net/mac80211/sta_info.c | 134 ++++++++++++++++++ net/mac80211/sta_info.h | 2 + net/wireless/core.c | 3 - net/wireless/ethtool.c | 86 +----------- net/wireless/ethtool.h | 6 - net/wireless/rdev-ops.h | 48 ------- net/wireless/trace.h | 49 ------- 13 files changed, 391 insertions(+), 555 deletions(-) create mode 100644 net/mac80211/ethtool.c delete mode 100644 net/wireless/ethtool.h diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e46c437944f7..29cb4b2bee5a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2266,10 +2266,6 @@ struct cfg80211_qos_map { * * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant). * - * @set_ringparam: Set tx and rx ring sizes. - * - * @get_ringparam: Get tx and rx ring current and maximum sizes. - * * @tdls_mgmt: Transmit a TDLS management frame. * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup). * @@ -2278,16 +2274,6 @@ struct cfg80211_qos_map { * * @set_noack_map: Set the NoAck Map for the TIDs. * - * @get_et_sset_count: Ethtool API to get string-set count. - * See @ethtool_ops.get_sset_count - * - * @get_et_stats: Ethtool API to get a set of u64 stats. - * See @ethtool_ops.get_ethtool_stats - * - * @get_et_strings: Ethtool API to get a set of strings to describe stats - * and perhaps other supported types of ethtool data-sets. - * See @ethtool_ops.get_strings - * * @get_channel: Get the current operating channel for the virtual interface. * For monitor interfaces, it should return %NULL unless there's a single * current monitoring channel. @@ -2503,10 +2489,6 @@ struct cfg80211_ops { int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant); int (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant); - int (*set_ringparam)(struct wiphy *wiphy, u32 tx, u32 rx); - void (*get_ringparam)(struct wiphy *wiphy, - u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); - int (*sched_scan_start)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_sched_scan_request *request); @@ -2529,13 +2511,6 @@ struct cfg80211_ops { struct net_device *dev, u16 noack_map); - int (*get_et_sset_count)(struct wiphy *wiphy, - struct net_device *dev, int sset); - void (*get_et_stats)(struct wiphy *wiphy, struct net_device *dev, - struct ethtool_stats *stats, u64 *data); - void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev, - u32 sset, u8 *data); - int (*get_channel)(struct wiphy *wiphy, struct wireless_dev *wdev, struct cfg80211_chan_def *chandef); @@ -4843,6 +4818,10 @@ void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev, */ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy); + +/* ethtool helper */ +void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info); + /* Logging, debugging and troubleshooting/diagnostic helpers. */ /* wiphy_printk helpers, similar to dev_printk */ diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 4409bf506594..7273d2796dd1 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -17,6 +17,7 @@ mac80211-y := \ aes_ccm.o \ aes_cmac.o \ cfg.o \ + ethtool.o \ rx.o \ spectmgmt.o \ tx.o \ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f8d065480ba9..b6d73c14e1ae 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -468,326 +468,6 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; } -static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) -{ - struct ieee80211_sub_if_data *sdata = sta->sdata; - struct ieee80211_local *local = sdata->local; - struct rate_control_ref *ref = local->rate_ctrl; - struct timespec uptime; - u64 packets = 0; - u32 thr = 0; - int i, ac; - - sinfo->generation = sdata->local->sta_generation; - - sinfo->filled = STATION_INFO_INACTIVE_TIME | - STATION_INFO_RX_BYTES64 | - STATION_INFO_TX_BYTES64 | - STATION_INFO_RX_PACKETS | - STATION_INFO_TX_PACKETS | - STATION_INFO_TX_RETRIES | - STATION_INFO_TX_FAILED | - STATION_INFO_TX_BITRATE | - STATION_INFO_RX_BITRATE | - STATION_INFO_RX_DROP_MISC | - STATION_INFO_BSS_PARAM | - STATION_INFO_CONNECTED_TIME | - STATION_INFO_STA_FLAGS | - STATION_INFO_BEACON_LOSS_COUNT; - - do_posix_clock_monotonic_gettime(&uptime); - sinfo->connected_time = uptime.tv_sec - sta->last_connected; - - sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); - sinfo->tx_bytes = 0; - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - sinfo->tx_bytes += sta->tx_bytes[ac]; - packets += sta->tx_packets[ac]; - } - sinfo->tx_packets = packets; - sinfo->rx_bytes = sta->rx_bytes; - sinfo->rx_packets = sta->rx_packets; - sinfo->tx_retries = sta->tx_retry_count; - sinfo->tx_failed = sta->tx_retry_failed; - sinfo->rx_dropped_misc = sta->rx_dropped; - sinfo->beacon_loss_count = sta->beacon_loss_count; - - if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || - (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { - sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; - if (!local->ops->get_rssi || - drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) - sinfo->signal = (s8)sta->last_signal; - sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); - } - if (sta->chains) { - sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | - STATION_INFO_CHAIN_SIGNAL_AVG; - - sinfo->chains = sta->chains; - for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { - sinfo->chain_signal[i] = sta->chain_signal_last[i]; - sinfo->chain_signal_avg[i] = - (s8) -ewma_read(&sta->chain_signal_avg[i]); - } - } - - sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); - sta_set_rate_info_rx(sta, &sinfo->rxrate); - - if (ieee80211_vif_is_mesh(&sdata->vif)) { -#ifdef CONFIG_MAC80211_MESH - sinfo->filled |= STATION_INFO_LLID | - STATION_INFO_PLID | - STATION_INFO_PLINK_STATE | - STATION_INFO_LOCAL_PM | - STATION_INFO_PEER_PM | - STATION_INFO_NONPEER_PM; - - sinfo->llid = sta->llid; - sinfo->plid = sta->plid; - sinfo->plink_state = sta->plink_state; - if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { - sinfo->filled |= STATION_INFO_T_OFFSET; - sinfo->t_offset = sta->t_offset; - } - sinfo->local_pm = sta->local_pm; - sinfo->peer_pm = sta->peer_pm; - sinfo->nonpeer_pm = sta->nonpeer_pm; -#endif - } - - sinfo->bss_param.flags = 0; - if (sdata->vif.bss_conf.use_cts_prot) - sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; - if (sdata->vif.bss_conf.use_short_preamble) - sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; - if (sdata->vif.bss_conf.use_short_slot) - sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; - sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; - sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; - - sinfo->sta_flags.set = 0; - sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) | - BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | - BIT(NL80211_STA_FLAG_WME) | - BIT(NL80211_STA_FLAG_MFP) | - BIT(NL80211_STA_FLAG_AUTHENTICATED) | - BIT(NL80211_STA_FLAG_ASSOCIATED) | - BIT(NL80211_STA_FLAG_TDLS_PEER); - if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) - sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); - if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) - sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); - if (test_sta_flag(sta, WLAN_STA_WME)) - sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME); - if (test_sta_flag(sta, WLAN_STA_MFP)) - sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); - if (test_sta_flag(sta, WLAN_STA_AUTH)) - sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); - if (test_sta_flag(sta, WLAN_STA_ASSOC)) - sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); - if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) - sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); - - /* check if the driver has a SW RC implementation */ - if (ref && ref->ops->get_expected_throughput) - thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv); - else - thr = drv_get_expected_throughput(local, &sta->sta); - - if (thr != 0) { - sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT; - sinfo->expected_throughput = thr; - } -} - -static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { - "rx_packets", "rx_bytes", - "rx_duplicates", "rx_fragments", "rx_dropped", - "tx_packets", "tx_bytes", "tx_fragments", - "tx_filtered", "tx_retry_failed", "tx_retries", - "beacon_loss", "sta_state", "txrate", "rxrate", "signal", - "channel", "noise", "ch_time", "ch_time_busy", - "ch_time_ext_busy", "ch_time_rx", "ch_time_tx" -}; -#define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats) - -static int ieee80211_get_et_sset_count(struct wiphy *wiphy, - struct net_device *dev, - int sset) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int rv = 0; - - if (sset == ETH_SS_STATS) - rv += STA_STATS_LEN; - - rv += drv_get_et_sset_count(sdata, sset); - - if (rv == 0) - return -EOPNOTSUPP; - return rv; -} - -static void ieee80211_get_et_stats(struct wiphy *wiphy, - struct net_device *dev, - struct ethtool_stats *stats, - u64 *data) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_channel *channel; - struct sta_info *sta; - struct ieee80211_local *local = sdata->local; - struct station_info sinfo; - struct survey_info survey; - int i, q; -#define STA_STATS_SURVEY_LEN 7 - - memset(data, 0, sizeof(u64) * STA_STATS_LEN); - -#define ADD_STA_STATS(sta) \ - do { \ - data[i++] += sta->rx_packets; \ - data[i++] += sta->rx_bytes; \ - data[i++] += sta->num_duplicates; \ - data[i++] += sta->rx_fragments; \ - data[i++] += sta->rx_dropped; \ - \ - data[i++] += sinfo.tx_packets; \ - data[i++] += sinfo.tx_bytes; \ - data[i++] += sta->tx_fragments; \ - data[i++] += sta->tx_filtered_count; \ - data[i++] += sta->tx_retry_failed; \ - data[i++] += sta->tx_retry_count; \ - data[i++] += sta->beacon_loss_count; \ - } while (0) - - /* For Managed stations, find the single station based on BSSID - * and use that. For interface types, iterate through all available - * stations and add stats for any station that is assigned to this - * network device. - */ - - mutex_lock(&local->sta_mtx); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); - - if (!(sta && !WARN_ON(sta->sdata->dev != dev))) - goto do_survey; - - sinfo.filled = 0; - sta_set_sinfo(sta, &sinfo); - - i = 0; - ADD_STA_STATS(sta); - - data[i++] = sta->sta_state; - - - if (sinfo.filled & STATION_INFO_TX_BITRATE) - data[i] = 100000 * - cfg80211_calculate_bitrate(&sinfo.txrate); - i++; - if (sinfo.filled & STATION_INFO_RX_BITRATE) - data[i] = 100000 * - cfg80211_calculate_bitrate(&sinfo.rxrate); - i++; - - if (sinfo.filled & STATION_INFO_SIGNAL_AVG) - data[i] = (u8)sinfo.signal_avg; - i++; - } else { - list_for_each_entry(sta, &local->sta_list, list) { - /* Make sure this station belongs to the proper dev */ - if (sta->sdata->dev != dev) - continue; - - sinfo.filled = 0; - sta_set_sinfo(sta, &sinfo); - i = 0; - ADD_STA_STATS(sta); - } - } - -do_survey: - i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; - /* Get survey stats for current channel */ - survey.filled = 0; - - rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); - if (chanctx_conf) - channel = chanctx_conf->def.chan; - else - channel = NULL; - rcu_read_unlock(); - - if (channel) { - q = 0; - do { - survey.filled = 0; - if (drv_get_survey(local, q, &survey) != 0) { - survey.filled = 0; - break; - } - q++; - } while (channel != survey.channel); - } - - if (survey.filled) - data[i++] = survey.channel->center_freq; - else - data[i++] = 0; - if (survey.filled & SURVEY_INFO_NOISE_DBM) - data[i++] = (u8)survey.noise; - else - data[i++] = -1LL; - if (survey.filled & SURVEY_INFO_CHANNEL_TIME) - data[i++] = survey.channel_time; - else - data[i++] = -1LL; - if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY) - data[i++] = survey.channel_time_busy; - else - data[i++] = -1LL; - if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) - data[i++] = survey.channel_time_ext_busy; - else - data[i++] = -1LL; - if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX) - data[i++] = survey.channel_time_rx; - else - data[i++] = -1LL; - if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX) - data[i++] = survey.channel_time_tx; - else - data[i++] = -1LL; - - mutex_unlock(&local->sta_mtx); - - if (WARN_ON(i != STA_STATS_LEN)) - return; - - drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN])); -} - -static void ieee80211_get_et_strings(struct wiphy *wiphy, - struct net_device *dev, - u32 sset, u8 *data) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int sz_sta_stats = 0; - - if (sset == ETH_SS_STATS) { - sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); - memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats); - } - drv_get_et_strings(sdata, sset, &(data[sz_sta_stats])); -} - static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { @@ -3597,21 +3277,6 @@ static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) return drv_get_antenna(local, tx_ant, rx_ant); } -static int ieee80211_set_ringparam(struct wiphy *wiphy, u32 tx, u32 rx) -{ - struct ieee80211_local *local = wiphy_priv(wiphy); - - return drv_set_ringparam(local, tx, rx); -} - -static void ieee80211_get_ringparam(struct wiphy *wiphy, - u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) -{ - struct ieee80211_local *local = wiphy_priv(wiphy); - - drv_get_ringparam(local, tx, tx_max, rx, rx_max); -} - static int ieee80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_gtk_rekey_data *data) @@ -3843,8 +3508,6 @@ const struct cfg80211_ops mac80211_config_ops = { .mgmt_frame_register = ieee80211_mgmt_frame_register, .set_antenna = ieee80211_set_antenna, .get_antenna = ieee80211_get_antenna, - .set_ringparam = ieee80211_set_ringparam, - .get_ringparam = ieee80211_get_ringparam, .set_rekey_data = ieee80211_set_rekey_data, .tdls_oper = ieee80211_tdls_oper, .tdls_mgmt = ieee80211_tdls_mgmt, @@ -3853,9 +3516,6 @@ const struct cfg80211_ops mac80211_config_ops = { #ifdef CONFIG_PM .set_wakeup = ieee80211_set_wakeup, #endif - .get_et_sset_count = ieee80211_get_et_sset_count, - .get_et_stats = ieee80211_get_et_stats, - .get_et_strings = ieee80211_get_et_strings, .get_channel = ieee80211_cfg_get_channel, .start_radar_detection = ieee80211_start_radar_detection, .channel_switch = ieee80211_channel_switch, diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c new file mode 100644 index 000000000000..ebfc8091557b --- /dev/null +++ b/net/mac80211/ethtool.c @@ -0,0 +1,244 @@ +/* + * mac80211 ethtool hooks for cfg80211 + * + * Copied from cfg.c - originally + * Copyright 2006-2010 Johannes Berg + * Copyright 2014 Intel Corporation (Author: Johannes Berg) + * + * This file is GPLv2 as found in COPYING. + */ +#include +#include +#include "ieee80211_i.h" +#include "sta_info.h" +#include "driver-ops.h" + +static int ieee80211_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *rp) +{ + struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy); + + if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0) + return -EINVAL; + + return drv_set_ringparam(local, rp->tx_pending, rp->rx_pending); +} + +static void ieee80211_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *rp) +{ + struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy); + + memset(rp, 0, sizeof(*rp)); + + drv_get_ringparam(local, &rp->tx_pending, &rp->tx_max_pending, + &rp->rx_pending, &rp->rx_max_pending); +} + +static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { + "rx_packets", "rx_bytes", + "rx_duplicates", "rx_fragments", "rx_dropped", + "tx_packets", "tx_bytes", "tx_fragments", + "tx_filtered", "tx_retry_failed", "tx_retries", + "beacon_loss", "sta_state", "txrate", "rxrate", "signal", + "channel", "noise", "ch_time", "ch_time_busy", + "ch_time_ext_busy", "ch_time_rx", "ch_time_tx" +}; +#define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats) + +static int ieee80211_get_sset_count(struct net_device *dev, int sset) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int rv = 0; + + if (sset == ETH_SS_STATS) + rv += STA_STATS_LEN; + + rv += drv_get_et_sset_count(sdata, sset); + + if (rv == 0) + return -EOPNOTSUPP; + return rv; +} + +static void ieee80211_get_stats(struct net_device *dev, + struct ethtool_stats *stats, + u64 *data) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *channel; + struct sta_info *sta; + struct ieee80211_local *local = sdata->local; + struct station_info sinfo; + struct survey_info survey; + int i, q; +#define STA_STATS_SURVEY_LEN 7 + + memset(data, 0, sizeof(u64) * STA_STATS_LEN); + +#define ADD_STA_STATS(sta) \ + do { \ + data[i++] += sta->rx_packets; \ + data[i++] += sta->rx_bytes; \ + data[i++] += sta->num_duplicates; \ + data[i++] += sta->rx_fragments; \ + data[i++] += sta->rx_dropped; \ + \ + data[i++] += sinfo.tx_packets; \ + data[i++] += sinfo.tx_bytes; \ + data[i++] += sta->tx_fragments; \ + data[i++] += sta->tx_filtered_count; \ + data[i++] += sta->tx_retry_failed; \ + data[i++] += sta->tx_retry_count; \ + data[i++] += sta->beacon_loss_count; \ + } while (0) + + /* For Managed stations, find the single station based on BSSID + * and use that. For interface types, iterate through all available + * stations and add stats for any station that is assigned to this + * network device. + */ + + mutex_lock(&local->sta_mtx); + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); + + if (!(sta && !WARN_ON(sta->sdata->dev != dev))) + goto do_survey; + + sinfo.filled = 0; + sta_set_sinfo(sta, &sinfo); + + i = 0; + ADD_STA_STATS(sta); + + data[i++] = sta->sta_state; + + + if (sinfo.filled & STATION_INFO_TX_BITRATE) + data[i] = 100000 * + cfg80211_calculate_bitrate(&sinfo.txrate); + i++; + if (sinfo.filled & STATION_INFO_RX_BITRATE) + data[i] = 100000 * + cfg80211_calculate_bitrate(&sinfo.rxrate); + i++; + + if (sinfo.filled & STATION_INFO_SIGNAL_AVG) + data[i] = (u8)sinfo.signal_avg; + i++; + } else { + list_for_each_entry(sta, &local->sta_list, list) { + /* Make sure this station belongs to the proper dev */ + if (sta->sdata->dev != dev) + continue; + + sinfo.filled = 0; + sta_set_sinfo(sta, &sinfo); + i = 0; + ADD_STA_STATS(sta); + } + } + +do_survey: + i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; + /* Get survey stats for current channel */ + survey.filled = 0; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (chanctx_conf) + channel = chanctx_conf->def.chan; + else + channel = NULL; + rcu_read_unlock(); + + if (channel) { + q = 0; + do { + survey.filled = 0; + if (drv_get_survey(local, q, &survey) != 0) { + survey.filled = 0; + break; + } + q++; + } while (channel != survey.channel); + } + + if (survey.filled) + data[i++] = survey.channel->center_freq; + else + data[i++] = 0; + if (survey.filled & SURVEY_INFO_NOISE_DBM) + data[i++] = (u8)survey.noise; + else + data[i++] = -1LL; + if (survey.filled & SURVEY_INFO_CHANNEL_TIME) + data[i++] = survey.channel_time; + else + data[i++] = -1LL; + if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY) + data[i++] = survey.channel_time_busy; + else + data[i++] = -1LL; + if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) + data[i++] = survey.channel_time_ext_busy; + else + data[i++] = -1LL; + if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX) + data[i++] = survey.channel_time_rx; + else + data[i++] = -1LL; + if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX) + data[i++] = survey.channel_time_tx; + else + data[i++] = -1LL; + + mutex_unlock(&local->sta_mtx); + + if (WARN_ON(i != STA_STATS_LEN)) + return; + + drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN])); +} + +static void ieee80211_get_strings(struct net_device *dev, u32 sset, u8 *data) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int sz_sta_stats = 0; + + if (sset == ETH_SS_STATS) { + sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); + memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats); + } + drv_get_et_strings(sdata, sset, &(data[sz_sta_stats])); +} + +static int ieee80211_get_regs_len(struct net_device *dev) +{ + return 0; +} + +static void ieee80211_get_regs(struct net_device *dev, + struct ethtool_regs *regs, + void *data) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + regs->version = wdev->wiphy->hw_version; + regs->len = 0; +} + +const struct ethtool_ops ieee80211_ethtool_ops = { + .get_drvinfo = cfg80211_get_drvinfo, + .get_regs_len = ieee80211_get_regs_len, + .get_regs = ieee80211_get_regs, + .get_link = ethtool_op_get_link, + .get_ringparam = ieee80211_get_ringparam, + .set_ringparam = ieee80211_set_ringparam, + .get_strings = ieee80211_get_strings, + .get_ethtool_stats = ieee80211_get_stats, + .get_sset_count = ieee80211_get_sset_count, +}; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ac9836e0aab3..4372d48b718f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1847,6 +1847,8 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, enum nl80211_tdls_operation oper); +extern const struct ethtool_ops ieee80211_ethtool_ops; + #ifdef CONFIG_MAC80211_NOINLINE #define debug_noinline noinline #else diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 388b863e821c..db5afc7faa22 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1705,6 +1705,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, ndev->features |= local->hw.netdev_features; + netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops); + ret = register_netdevice(ndev); if (ret) { free_netdev(ndev); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ae7c16ad5f22..6fe48f64d0e4 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1719,3 +1719,137 @@ u8 sta_info_tx_streams(struct sta_info *sta) return ((ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; } + +void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; + struct rate_control_ref *ref = local->rate_ctrl; + struct timespec uptime; + u64 packets = 0; + u32 thr = 0; + int i, ac; + + sinfo->generation = sdata->local->sta_generation; + + sinfo->filled = STATION_INFO_INACTIVE_TIME | + STATION_INFO_RX_BYTES64 | + STATION_INFO_TX_BYTES64 | + STATION_INFO_RX_PACKETS | + STATION_INFO_TX_PACKETS | + STATION_INFO_TX_RETRIES | + STATION_INFO_TX_FAILED | + STATION_INFO_TX_BITRATE | + STATION_INFO_RX_BITRATE | + STATION_INFO_RX_DROP_MISC | + STATION_INFO_BSS_PARAM | + STATION_INFO_CONNECTED_TIME | + STATION_INFO_STA_FLAGS | + STATION_INFO_BEACON_LOSS_COUNT; + + do_posix_clock_monotonic_gettime(&uptime); + sinfo->connected_time = uptime.tv_sec - sta->last_connected; + + sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); + sinfo->tx_bytes = 0; + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + sinfo->tx_bytes += sta->tx_bytes[ac]; + packets += sta->tx_packets[ac]; + } + sinfo->tx_packets = packets; + sinfo->rx_bytes = sta->rx_bytes; + sinfo->rx_packets = sta->rx_packets; + sinfo->tx_retries = sta->tx_retry_count; + sinfo->tx_failed = sta->tx_retry_failed; + sinfo->rx_dropped_misc = sta->rx_dropped; + sinfo->beacon_loss_count = sta->beacon_loss_count; + + if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || + (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { + sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; + if (!local->ops->get_rssi || + drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) + sinfo->signal = (s8)sta->last_signal; + sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); + } + if (sta->chains) { + sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | + STATION_INFO_CHAIN_SIGNAL_AVG; + + sinfo->chains = sta->chains; + for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { + sinfo->chain_signal[i] = sta->chain_signal_last[i]; + sinfo->chain_signal_avg[i] = + (s8) -ewma_read(&sta->chain_signal_avg[i]); + } + } + + sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); + sta_set_rate_info_rx(sta, &sinfo->rxrate); + + if (ieee80211_vif_is_mesh(&sdata->vif)) { +#ifdef CONFIG_MAC80211_MESH + sinfo->filled |= STATION_INFO_LLID | + STATION_INFO_PLID | + STATION_INFO_PLINK_STATE | + STATION_INFO_LOCAL_PM | + STATION_INFO_PEER_PM | + STATION_INFO_NONPEER_PM; + + sinfo->llid = sta->llid; + sinfo->plid = sta->plid; + sinfo->plink_state = sta->plink_state; + if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { + sinfo->filled |= STATION_INFO_T_OFFSET; + sinfo->t_offset = sta->t_offset; + } + sinfo->local_pm = sta->local_pm; + sinfo->peer_pm = sta->peer_pm; + sinfo->nonpeer_pm = sta->nonpeer_pm; +#endif + } + + sinfo->bss_param.flags = 0; + if (sdata->vif.bss_conf.use_cts_prot) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; + if (sdata->vif.bss_conf.use_short_preamble) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; + if (sdata->vif.bss_conf.use_short_slot) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; + sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; + sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; + + sinfo->sta_flags.set = 0; + sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) | + BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | + BIT(NL80211_STA_FLAG_WME) | + BIT(NL80211_STA_FLAG_MFP) | + BIT(NL80211_STA_FLAG_AUTHENTICATED) | + BIT(NL80211_STA_FLAG_ASSOCIATED) | + BIT(NL80211_STA_FLAG_TDLS_PEER); + if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) + sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); + if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) + sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); + if (test_sta_flag(sta, WLAN_STA_WME)) + sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME); + if (test_sta_flag(sta, WLAN_STA_MFP)) + sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); + if (test_sta_flag(sta, WLAN_STA_AUTH)) + sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); + if (test_sta_flag(sta, WLAN_STA_ASSOC)) + sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); + if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) + sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); + + /* check if the driver has a SW RC implementation */ + if (ref && ref->ops->get_expected_throughput) + thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv); + else + thr = drv_get_expected_throughput(local, &sta->sta); + + if (thr != 0) { + sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT; + sinfo->expected_throughput = thr; + } +} diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index fa7ce6f8593b..2a04361b2162 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -627,6 +627,8 @@ void sta_set_rate_info_tx(struct sta_info *sta, struct rate_info *rinfo); void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo); +void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo); + void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time); u8 sta_info_tx_streams(struct sta_info *sta); diff --git a/net/wireless/core.c b/net/wireless/core.c index a1c40654dd9b..afee5e0455ea 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -25,7 +25,6 @@ #include "sysfs.h" #include "debugfs.h" #include "wext-compat.h" -#include "ethtool.h" #include "rdev-ops.h" /* name for sysfs, %d is appended */ @@ -927,8 +926,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, /* allow mac80211 to determine the timeout */ wdev->ps_timeout = -1; - netdev_set_default_ethtool_ops(dev, &cfg80211_ethtool_ops); - if ((wdev->iftype == NL80211_IFTYPE_STATION || wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c index d4860bfc020e..e9e91298c70d 100644 --- a/net/wireless/ethtool.c +++ b/net/wireless/ethtool.c @@ -1,11 +1,9 @@ #include #include #include "core.h" -#include "ethtool.h" #include "rdev-ops.h" -static void cfg80211_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) +void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -23,84 +21,4 @@ static void cfg80211_get_drvinfo(struct net_device *dev, strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)), sizeof(info->bus_info)); } - -static int cfg80211_get_regs_len(struct net_device *dev) -{ - /* For now, return 0... */ - return 0; -} - -static void cfg80211_get_regs(struct net_device *dev, struct ethtool_regs *regs, - void *data) -{ - struct wireless_dev *wdev = dev->ieee80211_ptr; - - regs->version = wdev->wiphy->hw_version; - regs->len = 0; -} - -static void cfg80211_get_ringparam(struct net_device *dev, - struct ethtool_ringparam *rp) -{ - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); - - memset(rp, 0, sizeof(*rp)); - - if (rdev->ops->get_ringparam) - rdev_get_ringparam(rdev, &rp->tx_pending, &rp->tx_max_pending, - &rp->rx_pending, &rp->rx_max_pending); -} - -static int cfg80211_set_ringparam(struct net_device *dev, - struct ethtool_ringparam *rp) -{ - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); - - if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0) - return -EINVAL; - - if (rdev->ops->set_ringparam) - return rdev_set_ringparam(rdev, rp->tx_pending, rp->rx_pending); - - return -ENOTSUPP; -} - -static int cfg80211_get_sset_count(struct net_device *dev, int sset) -{ - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); - if (rdev->ops->get_et_sset_count) - return rdev_get_et_sset_count(rdev, dev, sset); - return -EOPNOTSUPP; -} - -static void cfg80211_get_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) -{ - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); - if (rdev->ops->get_et_stats) - rdev_get_et_stats(rdev, dev, stats, data); -} - -static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data) -{ - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); - if (rdev->ops->get_et_strings) - rdev_get_et_strings(rdev, dev, sset, data); -} - -const struct ethtool_ops cfg80211_ethtool_ops = { - .get_drvinfo = cfg80211_get_drvinfo, - .get_regs_len = cfg80211_get_regs_len, - .get_regs = cfg80211_get_regs, - .get_link = ethtool_op_get_link, - .get_ringparam = cfg80211_get_ringparam, - .set_ringparam = cfg80211_set_ringparam, - .get_strings = cfg80211_get_strings, - .get_ethtool_stats = cfg80211_get_stats, - .get_sset_count = cfg80211_get_sset_count, -}; +EXPORT_SYMBOL(cfg80211_get_drvinfo); diff --git a/net/wireless/ethtool.h b/net/wireless/ethtool.h deleted file mode 100644 index 695ecad20bd6..000000000000 --- a/net/wireless/ethtool.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __CFG80211_ETHTOOL__ -#define __CFG80211_ETHTOOL__ - -extern const struct ethtool_ops cfg80211_ethtool_ops; - -#endif /* __CFG80211_ETHTOOL__ */ diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index d95bbe348138..f552b0abbd70 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -714,25 +714,6 @@ static inline int rdev_get_antenna(struct cfg80211_registered_device *rdev, return ret; } -static inline int rdev_set_ringparam(struct cfg80211_registered_device *rdev, - u32 tx, u32 rx) -{ - int ret; - trace_rdev_set_ringparam(&rdev->wiphy, tx, rx); - ret = rdev->ops->set_ringparam(&rdev->wiphy, tx, rx); - trace_rdev_return_int(&rdev->wiphy, ret); - return ret; -} - -static inline void rdev_get_ringparam(struct cfg80211_registered_device *rdev, - u32 *tx, u32 *tx_max, u32 *rx, - u32 *rx_max) -{ - trace_rdev_get_ringparam(&rdev->wiphy); - rdev->ops->get_ringparam(&rdev->wiphy, tx, tx_max, rx, rx_max); - trace_rdev_return_void_tx_rx(&rdev->wiphy, *tx, *tx_max, *rx, *rx_max); -} - static inline int rdev_sched_scan_start(struct cfg80211_registered_device *rdev, struct net_device *dev, @@ -815,35 +796,6 @@ static inline int rdev_set_noack_map(struct cfg80211_registered_device *rdev, return ret; } -static inline int -rdev_get_et_sset_count(struct cfg80211_registered_device *rdev, - struct net_device *dev, int sset) -{ - int ret; - trace_rdev_get_et_sset_count(&rdev->wiphy, dev, sset); - ret = rdev->ops->get_et_sset_count(&rdev->wiphy, dev, sset); - trace_rdev_return_int(&rdev->wiphy, ret); - return ret; -} - -static inline void rdev_get_et_stats(struct cfg80211_registered_device *rdev, - struct net_device *dev, - struct ethtool_stats *stats, u64 *data) -{ - trace_rdev_get_et_stats(&rdev->wiphy, dev); - rdev->ops->get_et_stats(&rdev->wiphy, dev, stats, data); - trace_rdev_return_void(&rdev->wiphy); -} - -static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev, - struct net_device *dev, u32 sset, - u8 *data) -{ - trace_rdev_get_et_strings(&rdev->wiphy, dev, sset); - rdev->ops->get_et_strings(&rdev->wiphy, dev, sset, data); - trace_rdev_return_void(&rdev->wiphy); -} - static inline int rdev_get_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 560ed77084e9..174559aade57 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -298,11 +298,6 @@ DEFINE_EVENT(wiphy_only_evt, rdev_return_void, TP_ARGS(wiphy) ); -DEFINE_EVENT(wiphy_only_evt, rdev_get_ringparam, - TP_PROTO(struct wiphy *wiphy), - TP_ARGS(wiphy) -); - DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna, TP_PROTO(struct wiphy *wiphy), TP_ARGS(wiphy) @@ -580,11 +575,6 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_ap, TP_ARGS(wiphy, netdev) ); -DEFINE_EVENT(wiphy_netdev_evt, rdev_get_et_stats, - TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), - TP_ARGS(wiphy, netdev) -); - DEFINE_EVENT(wiphy_netdev_evt, rdev_sched_scan_stop, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), TP_ARGS(wiphy, netdev) @@ -1439,11 +1429,6 @@ DECLARE_EVENT_CLASS(tx_rx_evt, WIPHY_PR_ARG, __entry->tx, __entry->rx) ); -DEFINE_EVENT(tx_rx_evt, rdev_set_ringparam, - TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), - TP_ARGS(wiphy, rx, tx) -); - DEFINE_EVENT(tx_rx_evt, rdev_set_antenna, TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), TP_ARGS(wiphy, rx, tx) @@ -1725,40 +1710,6 @@ TRACE_EVENT(rdev_set_noack_map, WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) ); -TRACE_EVENT(rdev_get_et_sset_count, - TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int sset), - TP_ARGS(wiphy, netdev, sset), - TP_STRUCT__entry( - WIPHY_ENTRY - NETDEV_ENTRY - __field(int, sset) - ), - TP_fast_assign( - WIPHY_ASSIGN; - NETDEV_ASSIGN; - __entry->sset = sset; - ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %d", - WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) -); - -TRACE_EVENT(rdev_get_et_strings, - TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 sset), - TP_ARGS(wiphy, netdev, sset), - TP_STRUCT__entry( - WIPHY_ENTRY - NETDEV_ENTRY - __field(u32, sset) - ), - TP_fast_assign( - WIPHY_ASSIGN; - NETDEV_ASSIGN; - __entry->sset = sset; - ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %u", - WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset) -); - DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel, TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), TP_ARGS(wiphy, wdev) -- cgit v1.2.3 From b49328361bab10d786e321aeae79b4429fdff38c Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Thu, 5 Jun 2014 08:12:57 +0200 Subject: mac80211: allow tx via monitor iface when DFS Allow send frames using monitor interface when DFS chandef and we pass CAC (beaconing allowed). This fix problem when old kernel and new backports used, in such case hostapd create/use also monitor interface. Before this patch all frames hostapd send using monitor iface were dropped when AP was configured on DFS channel. Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 8170d9945d6d..3c80bf29b050 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1620,12 +1620,12 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_channel *chan; struct ieee80211_radiotap_header *prthdr = (struct ieee80211_radiotap_header *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr; struct ieee80211_sub_if_data *tmp_sdata, *sdata; + struct cfg80211_chan_def *chandef; u16 len_rthdr; int hdrlen; @@ -1723,9 +1723,9 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, } if (chanctx_conf) - chan = chanctx_conf->def.chan; + chandef = &chanctx_conf->def; else if (!local->use_chanctx) - chan = local->_oper_chandef.chan; + chandef = &local->_oper_chandef; else goto fail_rcu; @@ -1745,10 +1745,11 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, * radar detection by itself. We can do that later by adding a * monitor flag interfaces used for AP support. */ - if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))) + if (!cfg80211_reg_can_beacon(local->hw.wiphy, chandef, + sdata->vif.type)) goto fail_rcu; - ieee80211_xmit(sdata, skb, chan->band); + ieee80211_xmit(sdata, skb, chandef->chan->band); rcu_read_unlock(); return NETDEV_TX_OK; -- cgit v1.2.3 From af296bdb8da4d0a4284de10fc4a61497272ddf11 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 5 Jun 2014 14:21:36 +0200 Subject: mac80211: move csa counters from sdata to beacon/presp Having csa counters part of beacon and probe_resp structures makes it easier to get rid of possible races between setting a beacon and updating counters on SMP systems by guaranteeing counters are always consistent against given beacon struct. While at it relax WARN_ON into WARN_ON_ONCE to prevent spamming logs and racing. Signed-off-by: Michal Kazior [remove pointless array check] Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 67 +++++++++++++++++++---------- net/mac80211/ibss.c | 2 +- net/mac80211/ieee80211_i.h | 16 +++++-- net/mac80211/mesh.c | 2 +- net/mac80211/tx.c | 103 ++++++++++++++++++++++++--------------------- 5 files changed, 115 insertions(+), 75 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b6d73c14e1ae..af3eac482acd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -554,7 +554,8 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, } static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, - const u8 *resp, size_t resp_len) + const u8 *resp, size_t resp_len, + const struct ieee80211_csa_settings *csa) { struct probe_resp *new, *old; @@ -570,6 +571,11 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, new->len = resp_len; memcpy(new->data, resp, resp_len); + if (csa) + memcpy(new->csa_counter_offsets, csa->counter_offsets_presp, + csa->n_counter_offsets_presp * + sizeof(new->csa_counter_offsets[0])); + rcu_assign_pointer(sdata->u.ap.probe_resp, new); if (old) kfree_rcu(old, rcu_head); @@ -578,7 +584,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, } static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, - struct cfg80211_beacon_data *params) + struct cfg80211_beacon_data *params, + const struct ieee80211_csa_settings *csa) { struct beacon_data *new, *old; int new_head_len, new_tail_len; @@ -622,6 +629,13 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, new->head_len = new_head_len; new->tail_len = new_tail_len; + if (csa) { + new->csa_current_counter = csa->count; + memcpy(new->csa_counter_offsets, csa->counter_offsets_beacon, + csa->n_counter_offsets_beacon * + sizeof(new->csa_counter_offsets[0])); + } + /* copy in head */ if (params->head) memcpy(new->head, params->head, new_head_len); @@ -636,7 +650,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, memcpy(new->tail, old->tail, new_tail_len); err = ieee80211_set_probe_resp(sdata, params->probe_resp, - params->probe_resp_len); + params->probe_resp_len, csa); if (err < 0) return err; if (err == 0) @@ -721,7 +735,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT; - err = ieee80211_assign_beacon(sdata, ¶ms->beacon); + err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL); if (err < 0) { ieee80211_vif_release_channel(sdata); return err; @@ -769,7 +783,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, if (!old) return -ENOENT; - err = ieee80211_assign_beacon(sdata, params); + err = ieee80211_assign_beacon(sdata, params, NULL); if (err < 0) return err; ieee80211_bss_info_change_notify(sdata, err); @@ -2752,7 +2766,8 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata, switch (sdata->vif.type) { case NL80211_IFTYPE_AP: - err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); + err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, + NULL); kfree(sdata->u.ap.next_beacon); sdata->u.ap.next_beacon = NULL; @@ -2855,6 +2870,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, struct cfg80211_csa_settings *params, u32 *changed) { + struct ieee80211_csa_settings csa = {}; int err; switch (sdata->vif.type) { @@ -2889,20 +2905,13 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, IEEE80211_MAX_CSA_COUNTERS_NUM)) return -EINVAL; - /* make sure we don't have garbage in other counters */ - memset(sdata->csa_counter_offset_beacon, 0, - sizeof(sdata->csa_counter_offset_beacon)); - memset(sdata->csa_counter_offset_presp, 0, - sizeof(sdata->csa_counter_offset_presp)); - - memcpy(sdata->csa_counter_offset_beacon, - params->counter_offsets_beacon, - params->n_counter_offsets_beacon * sizeof(u16)); - memcpy(sdata->csa_counter_offset_presp, - params->counter_offsets_presp, - params->n_counter_offsets_presp * sizeof(u16)); + csa.counter_offsets_beacon = params->counter_offsets_beacon; + csa.counter_offsets_presp = params->counter_offsets_presp; + csa.n_counter_offsets_beacon = params->n_counter_offsets_beacon; + csa.n_counter_offsets_presp = params->n_counter_offsets_presp; + csa.count = params->count; - err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); + err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa); if (err < 0) { kfree(sdata->u.ap.next_beacon); return err; @@ -3046,7 +3055,6 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, sdata->csa_radar_required = params->radar_required; sdata->csa_chandef = params->chandef; sdata->csa_block_tx = params->block_tx; - sdata->csa_current_counter = params->count; sdata->vif.csa_active = true; if (sdata->csa_block_tx) @@ -3194,10 +3202,23 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, sdata->vif.type == NL80211_IFTYPE_ADHOC) && params->n_csa_offsets) { int i; - u8 c = sdata->csa_current_counter; + struct beacon_data *beacon = NULL; - for (i = 0; i < params->n_csa_offsets; i++) - data[params->csa_offsets[i]] = c; + rcu_read_lock(); + + if (sdata->vif.type == NL80211_IFTYPE_AP) + beacon = rcu_dereference(sdata->u.ap.beacon); + else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + beacon = rcu_dereference(sdata->u.ibss.presp); + else if (ieee80211_vif_is_mesh(&sdata->vif)) + beacon = rcu_dereference(sdata->u.mesh.beacon); + + if (beacon) + for (i = 0; i < params->n_csa_offsets; i++) + data[params->csa_offsets[i]] = + beacon->csa_current_counter; + + rcu_read_unlock(); } IEEE80211_SKB_CB(skb)->flags = flags; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 18ee0a256b1e..713485f9effc 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -143,7 +143,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, *pos++ = csa_settings->block_tx ? 1 : 0; *pos++ = ieee80211_frequency_to_channel( csa_settings->chandef.chan->center_freq); - sdata->csa_counter_offset_beacon[0] = (pos - presp->head); + presp->csa_counter_offsets[0] = (pos - presp->head); *pos++ = csa_settings->count; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4372d48b718f..d9af7ef3c11a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -229,16 +229,29 @@ struct ieee80211_rx_data { u16 tkip_iv16; }; +struct ieee80211_csa_settings { + const u16 *counter_offsets_beacon; + const u16 *counter_offsets_presp; + + int n_counter_offsets_beacon; + int n_counter_offsets_presp; + + u8 count; +}; + struct beacon_data { u8 *head, *tail; int head_len, tail_len; struct ieee80211_meshconf_ie *meshconf; + u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM]; + u8 csa_current_counter; struct rcu_head rcu_head; }; struct probe_resp { struct rcu_head rcu_head; int len; + u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM]; u8 data[0]; }; @@ -754,8 +767,6 @@ struct ieee80211_sub_if_data { struct mac80211_qos_map __rcu *qos_map; struct work_struct csa_finalize_work; - u16 csa_counter_offset_beacon[IEEE80211_MAX_CSA_COUNTERS_NUM]; - u16 csa_counter_offset_presp[IEEE80211_MAX_CSA_COUNTERS_NUM]; bool csa_radar_required; bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ struct cfg80211_chan_def csa_chandef; @@ -767,7 +778,6 @@ struct ieee80211_sub_if_data { struct ieee80211_chanctx *reserved_chanctx; struct cfg80211_chan_def reserved_chandef; bool reserved_radar_required; - u8 csa_current_counter; /* used to reconfigure hardware SM PS */ struct work_struct recalc_smps; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index da164685b524..e9f99c1e3fad 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -679,7 +679,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) *pos++ = 0x0; *pos++ = ieee80211_frequency_to_channel( csa->settings.chandef.chan->center_freq); - sdata->csa_counter_offset_beacon[0] = hdr_len + 6; + bcn->csa_counter_offsets[0] = hdr_len + 6; *pos++ = csa->settings.count; *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; *pos++ = 6; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3c80bf29b050..ed56f0091663 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2426,7 +2426,7 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata, u8 *beacon_data; size_t beacon_data_len; int i; - u8 count = sdata->csa_current_counter; + u8 count = beacon->csa_current_counter; switch (sdata->vif.type) { case NL80211_IFTYPE_AP: @@ -2445,46 +2445,53 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata, return; } + rcu_read_lock(); for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) { - u16 counter_offset_beacon = - sdata->csa_counter_offset_beacon[i]; - u16 counter_offset_presp = sdata->csa_counter_offset_presp[i]; - - if (counter_offset_beacon) { - if (WARN_ON(counter_offset_beacon >= beacon_data_len)) - return; - - beacon_data[counter_offset_beacon] = count; - } - - if (sdata->vif.type == NL80211_IFTYPE_AP && - counter_offset_presp) { - rcu_read_lock(); - resp = rcu_dereference(sdata->u.ap.probe_resp); + resp = rcu_dereference(sdata->u.ap.probe_resp); - /* If nl80211 accepted the offset, this should - * not happen. - */ - if (WARN_ON(!resp)) { + if (beacon->csa_counter_offsets[i]) { + if (WARN_ON_ONCE(beacon->csa_counter_offsets[i] >= + beacon_data_len)) { rcu_read_unlock(); return; } - resp->data[counter_offset_presp] = count; - rcu_read_unlock(); + + beacon_data[beacon->csa_counter_offsets[i]] = count; } + + if (sdata->vif.type == NL80211_IFTYPE_AP && resp) + resp->data[resp->csa_counter_offsets[i]] = count; } + rcu_read_unlock(); } u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct beacon_data *beacon = NULL; + u8 count = 0; - sdata->csa_current_counter--; + rcu_read_lock(); + + if (sdata->vif.type == NL80211_IFTYPE_AP) + beacon = rcu_dereference(sdata->u.ap.beacon); + else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + beacon = rcu_dereference(sdata->u.ibss.presp); + else if (ieee80211_vif_is_mesh(&sdata->vif)) + beacon = rcu_dereference(sdata->u.mesh.beacon); + + if (!beacon) + goto unlock; + + beacon->csa_current_counter--; /* the counter should never reach 0 */ - WARN_ON(!sdata->csa_current_counter); + WARN_ON_ONCE(!beacon->csa_current_counter); + count = beacon->csa_current_counter; - return sdata->csa_current_counter; +unlock: + rcu_read_unlock(); + return count; } EXPORT_SYMBOL(ieee80211_csa_update_counter); @@ -2494,7 +2501,6 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) struct beacon_data *beacon = NULL; u8 *beacon_data; size_t beacon_data_len; - int counter_beacon = sdata->csa_counter_offset_beacon[0]; int ret = false; if (!ieee80211_sdata_running(sdata)) @@ -2532,10 +2538,10 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) goto out; } - if (WARN_ON(counter_beacon > beacon_data_len)) + if (WARN_ON_ONCE(beacon->csa_counter_offsets[0] > beacon_data_len)) goto out; - if (beacon_data[counter_beacon] == 1) + if (beacon_data[beacon->csa_counter_offsets[0]] == 1) ret = true; out: rcu_read_unlock(); @@ -2551,6 +2557,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, bool is_template) { struct ieee80211_local *local = hw_to_local(hw); + struct beacon_data *beacon = NULL; struct sk_buff *skb = NULL; struct ieee80211_tx_info *info; struct ieee80211_sub_if_data *sdata = NULL; @@ -2572,8 +2579,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, if (sdata->vif.type == NL80211_IFTYPE_AP) { struct ieee80211_if_ap *ap = &sdata->u.ap; - struct beacon_data *beacon = rcu_dereference(ap->beacon); + beacon = rcu_dereference(ap->beacon); if (beacon) { if (sdata->vif.csa_active) { if (!is_template) @@ -2616,34 +2623,34 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_hdr *hdr; - struct beacon_data *presp = rcu_dereference(ifibss->presp); - if (!presp) + beacon = rcu_dereference(ifibss->presp); + if (!beacon) goto out; if (sdata->vif.csa_active) { if (!is_template) ieee80211_csa_update_counter(vif); - ieee80211_set_csa(sdata, presp); + ieee80211_set_csa(sdata, beacon); } - skb = dev_alloc_skb(local->tx_headroom + presp->head_len + + skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + local->hw.extra_beacon_tailroom); if (!skb) goto out; skb_reserve(skb, local->tx_headroom); - memcpy(skb_put(skb, presp->head_len), presp->head, - presp->head_len); + memcpy(skb_put(skb, beacon->head_len), beacon->head, + beacon->head_len); hdr = (struct ieee80211_hdr *) skb->data; hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); } else if (ieee80211_vif_is_mesh(&sdata->vif)) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - struct beacon_data *bcn = rcu_dereference(ifmsh->beacon); - if (!bcn) + beacon = rcu_dereference(ifmsh->beacon); + if (!beacon) goto out; if (sdata->vif.csa_active) { @@ -2655,40 +2662,42 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, */ ieee80211_csa_update_counter(vif); - ieee80211_set_csa(sdata, bcn); + ieee80211_set_csa(sdata, beacon); } if (ifmsh->sync_ops) - ifmsh->sync_ops->adjust_tbtt(sdata, bcn); + ifmsh->sync_ops->adjust_tbtt(sdata, beacon); skb = dev_alloc_skb(local->tx_headroom + - bcn->head_len + + beacon->head_len + 256 + /* TIM IE */ - bcn->tail_len + + beacon->tail_len + local->hw.extra_beacon_tailroom); if (!skb) goto out; skb_reserve(skb, local->tx_headroom); - memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len); + memcpy(skb_put(skb, beacon->head_len), beacon->head, + beacon->head_len); ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template); if (offs) { - offs->tim_offset = bcn->head_len; - offs->tim_length = skb->len - bcn->head_len; + offs->tim_offset = beacon->head_len; + offs->tim_length = skb->len - beacon->head_len; } - memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len); + memcpy(skb_put(skb, beacon->tail_len), beacon->tail, + beacon->tail_len); } else { WARN_ON(1); goto out; } /* CSA offsets */ - if (offs) { + if (offs && beacon) { int i; for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) { - u16 csa_off = sdata->csa_counter_offset_beacon[i]; + u16 csa_off = beacon->csa_counter_offsets[i]; if (!csa_off) continue; -- cgit v1.2.3 From 10d78f278214bd7c8a15d09ce2304728114786e7 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 5 Jun 2014 14:21:37 +0200 Subject: mac80211: use csa counter offsets instead of csa_active vif->csa_active is protected by mutexes only. This means it is unreliable to depend on it on codeflow in non-sleepable beacon and CSA code. There was no guarantee to have vif->csa_active update be visible before beacons are updated on SMP systems. Using csa counter offsets which are embedded in beacon struct (and thus are protected with single RCU assignment) is much safer. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ed56f0091663..d741b7369dc4 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2538,6 +2538,9 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) goto out; } + if (!beacon->csa_counter_offsets[0]) + goto out; + if (WARN_ON_ONCE(beacon->csa_counter_offsets[0] > beacon_data_len)) goto out; @@ -2582,7 +2585,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, beacon = rcu_dereference(ap->beacon); if (beacon) { - if (sdata->vif.csa_active) { + if (beacon->csa_counter_offsets[0]) { if (!is_template) ieee80211_csa_update_counter(vif); @@ -2628,7 +2631,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, if (!beacon) goto out; - if (sdata->vif.csa_active) { + if (beacon->csa_counter_offsets[0]) { if (!is_template) ieee80211_csa_update_counter(vif); @@ -2653,7 +2656,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, if (!beacon) goto out; - if (sdata->vif.csa_active) { + if (beacon->csa_counter_offsets[0]) { if (!is_template) /* TODO: For mesh csa_counter is in TU, so * decrementing it by one isn't correct, but -- cgit v1.2.3 From 181715203bc0e309b827f99baf44f5a97b19c90c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 11 Jun 2014 23:59:14 +0000 Subject: mac80211: Use ktime_get_ts() do_posix_clock_monotonic_gettime() is a leftover from the initial posix timer implementation which maps to ktime_get_ts(). Signed-off-by: Thomas Gleixner Signed-off-by: Johannes Berg --- net/mac80211/debugfs_sta.c | 2 +- net/mac80211/sta_info.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index ee82e1f0a9e7..3db96648b45a 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -124,7 +124,7 @@ static ssize_t sta_connected_time_read(struct file *file, char __user *userbuf, long connected_time_secs; char buf[100]; int res; - do_posix_clock_monotonic_gettime(&uptime); + ktime_get_ts(&uptime); connected_time_secs = uptime.tv_sec - sta->last_connected; time_to_tm(connected_time_secs, 0, &result); result.tm_year -= 70; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 6fe48f64d0e4..f41177f58b30 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -350,7 +350,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->sta_state = IEEE80211_STA_NONE; - do_posix_clock_monotonic_gettime(&uptime); + ktime_get_ts(&uptime); sta->last_connected = uptime.tv_sec; ewma_init(&sta->avg_signal, 1024, 8); for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) @@ -1747,7 +1747,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) STATION_INFO_STA_FLAGS | STATION_INFO_BEACON_LOSS_COUNT; - do_posix_clock_monotonic_gettime(&uptime); + ktime_get_ts(&uptime); sinfo->connected_time = uptime.tv_sec - sta->last_connected; sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); -- cgit v1.2.3 From 3283e286b859e9214867b2c855db065e41101b03 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 12 Jun 2014 22:34:49 +0200 Subject: mac80211_hwsim: clean up own address matching Using perm_addr is always wrong, it may be reassigned by anyone using standard netdev APIs. Remove that from the match function and also use the match function where only the perm_addr was used now. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 66 ++++++++++++++++------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index a312c653d116..06a0722164da 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -781,6 +781,36 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, netif_rx(skb); } +struct mac80211_hwsim_addr_match_data { + u8 addr[ETH_ALEN]; + bool ret; +}; + +static void mac80211_hwsim_addr_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_addr_match_data *md = data; + + if (memcmp(mac, md->addr, ETH_ALEN) == 0) + md->ret = true; +} + +static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, + const u8 *addr) +{ + struct mac80211_hwsim_addr_match_data md = { + .ret = false, + }; + + memcpy(md.addr, addr, ETH_ALEN); + + ieee80211_iterate_active_interfaces_atomic(data->hw, + IEEE80211_IFACE_ITER_NORMAL, + mac80211_hwsim_addr_iter, + &md); + + return md.ret; +} static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, struct sk_buff *skb) @@ -798,8 +828,7 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, /* Allow unicast frames to own address if there is a pending * PS-Poll */ if (data->ps_poll_pending && - memcmp(data->hw->wiphy->perm_addr, skb->data + 4, - ETH_ALEN) == 0) { + mac80211_hwsim_addr_match(data, skb->data + 4)) { data->ps_poll_pending = false; return true; } @@ -809,39 +838,6 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, return true; } - -struct mac80211_hwsim_addr_match_data { - bool ret; - const u8 *addr; -}; - -static void mac80211_hwsim_addr_iter(void *data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct mac80211_hwsim_addr_match_data *md = data; - if (memcmp(mac, md->addr, ETH_ALEN) == 0) - md->ret = true; -} - - -static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, - const u8 *addr) -{ - struct mac80211_hwsim_addr_match_data md; - - if (memcmp(addr, data->hw->wiphy->perm_addr, ETH_ALEN) == 0) - return true; - - md.ret = false; - md.addr = addr; - ieee80211_iterate_active_interfaces_atomic(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - mac80211_hwsim_addr_iter, - &md); - - return md.ret; -} - static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, struct sk_buff *my_skb, int dst_portid) -- cgit v1.2.3 From 8d7b70fb7bf8963634052f455db86074d48bab2c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 11 Jun 2014 23:59:18 +0000 Subject: net: Mac80211: Remove silly timespec dance Converting time from one format to another seems to give coders a warm and fuzzy feeling. Use the proper interfaces. Signed-off-by: Thomas Gleixner Cc: John Stultz Cc: Peter Zijlstra Cc: John W. Linville [fix compile error] Signed-off-by: Johannes Berg --- net/mac80211/status.c | 7 ++----- net/mac80211/tx.c | 5 +---- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/net/mac80211/status.c b/net/mac80211/status.c index ba29ebc86141..aa06dcad336e 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -473,8 +473,6 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, struct sta_info *sta, struct ieee80211_hdr *hdr) { - ktime_t skb_dprt; - struct timespec dprt_time; u32 msrmnt; u16 tid; u8 *qc; @@ -506,9 +504,8 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, tx_lat = &sta->tx_lat[tid]; - ktime_get_ts(&dprt_time); /* time stamp completion time */ - skb_dprt = ktime_set(dprt_time.tv_sec, dprt_time.tv_nsec); - msrmnt = ktime_to_ms(ktime_sub(skb_dprt, skb_arv)); + /* Calculate the latency */ + msrmnt = ktime_to_ms(ktime_sub(ktime_get(), skb_arv)); if (tx_lat->max < msrmnt) /* update stats */ tx_lat->max = msrmnt; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d741b7369dc4..9b3d94e7c4be 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1770,15 +1770,12 @@ fail: static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, struct sk_buff *skb) { - struct timespec skb_arv; struct ieee80211_tx_latency_bin_ranges *tx_latency; tx_latency = rcu_dereference(local->tx_latency); if (!tx_latency) return; - - ktime_get_ts(&skb_arv); - skb->tstamp = ktime_set(skb_arv.tv_sec, skb_arv.tv_nsec); + skb->tstamp = ktime_get(); } /** -- cgit v1.2.3 From 59f48fe22fe817df1ced42dee28b31de88b478b6 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 13 Jun 2014 16:30:04 +0300 Subject: mac80211: don't stop all queues when flushing There is no need to stop all queues when we want to flush specific queues, so stop only the queues that will be flushed. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 6886601afe1c..6d29e40538ad 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -551,12 +551,12 @@ void ieee80211_flush_queues(struct ieee80211_local *local, queues = BIT(local->hw.queues) - 1; } - ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, + ieee80211_stop_queues_by_reason(&local->hw, queues, IEEE80211_QUEUE_STOP_REASON_FLUSH); drv_flush(local, sdata, queues, false); - ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, + ieee80211_wake_queues_by_reason(&local->hw, queues, IEEE80211_QUEUE_STOP_REASON_FLUSH); } -- cgit v1.2.3 From cca07b00a56d6ddd339e457dfd1a229222b9acf5 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 13 Jun 2014 16:30:05 +0300 Subject: mac80211: introduce refcount for queue_stop_reasons Sometimes different vifs may be stopping the queues for the same reason (e.g. when several interfaces are performing a channel switch). Instead of using a bitmask for the reasons, use an integer that holds a refcount instead. In order to keep it backwards compatible, introduce a boolean in some functions that tell us whether the queue stopping should be refcounted or not. For now, use not refcounted for all calls to keep it functionally the same as before. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/agg-tx.c | 8 +++-- net/mac80211/cfg.c | 9 ++++-- net/mac80211/ieee80211_i.h | 15 ++++++--- net/mac80211/iface.c | 3 +- net/mac80211/main.c | 3 +- net/mac80211/mlme.c | 15 ++++++--- net/mac80211/offchannel.c | 6 ++-- net/mac80211/pm.c | 6 ++-- net/mac80211/tx.c | 3 +- net/mac80211/util.c | 76 +++++++++++++++++++++++++++++++--------------- 10 files changed, 98 insertions(+), 46 deletions(-) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index ce9633a3cfb0..d6986f3aa5c4 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -170,10 +170,13 @@ ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid) { int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)]; + /* we do refcounting here, so don't use the queue reason refcounting */ + if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1) ieee80211_stop_queue_by_reason( &sdata->local->hw, queue, - IEEE80211_QUEUE_STOP_REASON_AGGREGATION); + IEEE80211_QUEUE_STOP_REASON_AGGREGATION, + false); __acquire(agg_queue); } @@ -185,7 +188,8 @@ ieee80211_wake_queue_agg(struct ieee80211_sub_if_data *sdata, int tid) if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0) ieee80211_wake_queue_by_reason( &sdata->local->hw, queue, - IEEE80211_QUEUE_STOP_REASON_AGGREGATION); + IEEE80211_QUEUE_STOP_REASON_AGGREGATION, + false); __release(agg_queue); } diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index af3eac482acd..e920d48f0209 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -837,7 +837,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) if (!ieee80211_csa_needs_block_tx(local)) ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); + IEEE80211_QUEUE_STOP_REASON_CSA, + false); mutex_unlock(&local->mtx); kfree(sdata->u.ap.next_beacon); @@ -2828,7 +2829,8 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) if (!ieee80211_csa_needs_block_tx(local)) ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); + IEEE80211_QUEUE_STOP_REASON_CSA, + false); return 0; } @@ -3060,7 +3062,8 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (sdata->csa_block_tx) ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); + IEEE80211_QUEUE_STOP_REASON_CSA, + false); if (changed) { ieee80211_bss_info_change_notify(sdata, changed); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d9af7ef3c11a..a0c7da809744 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -922,6 +922,8 @@ enum queue_stop_reason { IEEE80211_QUEUE_STOP_REASON_SKB_ADD, IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, IEEE80211_QUEUE_STOP_REASON_FLUSH, + + IEEE80211_QUEUE_STOP_REASONS, }; #ifdef CONFIG_MAC80211_LEDS @@ -1018,6 +1020,7 @@ struct ieee80211_local { struct workqueue_struct *workqueue; unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; + int q_stop_reasons[IEEE80211_MAX_QUEUES][IEEE80211_QUEUE_STOP_REASONS]; /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ spinlock_t queue_stop_reason_lock; @@ -1715,14 +1718,18 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, unsigned long queues, - enum queue_stop_reason reason); + enum queue_stop_reason reason, + bool refcounted); void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, unsigned long queues, - enum queue_stop_reason reason); + enum queue_stop_reason reason, + bool refcounted); void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, - enum queue_stop_reason reason); + enum queue_stop_reason reason, + bool refcounted); void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, - enum queue_stop_reason reason); + enum queue_stop_reason reason, + bool refcounted); void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); void ieee80211_add_pending_skb(struct ieee80211_local *local, struct sk_buff *skb); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index db5afc7faa22..1971d2418d44 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -844,7 +844,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, if (!ieee80211_csa_needs_block_tx(local)) ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); + IEEE80211_QUEUE_STOP_REASON_CSA, + false); mutex_unlock(&local->mtx); sdata_unlock(sdata); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0512a5096f0f..e0ab4320a078 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -272,7 +272,8 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) /* use this reason, ieee80211_reconfig will unblock it */ ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_SUSPEND); + IEEE80211_QUEUE_STOP_REASON_SUSPEND, + false); /* * Stop all Rx during the reconfig. We don't want state changes diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3345401be1b3..1ab1884eddbf 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -983,7 +983,8 @@ static void ieee80211_chswitch_work(struct work_struct *work) if (!ieee80211_csa_needs_block_tx(local)) ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); + IEEE80211_QUEUE_STOP_REASON_CSA, + false); mutex_unlock(&local->mtx); ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; @@ -1115,7 +1116,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, if (sdata->csa_block_tx) ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); + IEEE80211_QUEUE_STOP_REASON_CSA, + false); mutex_unlock(&local->mtx); if (local->ops->channel_switch) { @@ -1385,7 +1387,8 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work) ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_PS); + IEEE80211_QUEUE_STOP_REASON_PS, + false); } void ieee80211_dynamic_ps_enable_work(struct work_struct *work) @@ -1833,7 +1836,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, if (!ieee80211_csa_needs_block_tx(local)) ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); + IEEE80211_QUEUE_STOP_REASON_CSA, + false); mutex_unlock(&local->mtx); sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; @@ -2082,7 +2086,8 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) if (!ieee80211_csa_needs_block_tx(local)) ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA); + IEEE80211_QUEUE_STOP_REASON_CSA, + false); mutex_unlock(&local->mtx); cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 7a17decd27f9..ff20b2ebdb30 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -119,7 +119,8 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local) * before sending nullfunc to enable powersave at the AP. */ ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL); + IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, + false); ieee80211_flush_queues(local, NULL); mutex_lock(&local->iflist_mtx); @@ -182,7 +183,8 @@ void ieee80211_offchannel_return(struct ieee80211_local *local) mutex_unlock(&local->iflist_mtx); ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL); + IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, + false); } void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index d478b880a0af..4c5192e0d66c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -35,7 +35,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_SUSPEND); + IEEE80211_QUEUE_STOP_REASON_SUSPEND, + false); /* flush out all packets */ synchronize_net(); @@ -74,7 +75,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) } ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_SUSPEND); + IEEE80211_QUEUE_STOP_REASON_SUSPEND, + false); return err; } else if (err > 0) { WARN_ON(err != 1); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9b3d94e7c4be..f6018178f33c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -250,7 +250,8 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_PS); + IEEE80211_QUEUE_STOP_REASON_PS, + false); ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; ieee80211_queue_work(&local->hw, &local->dynamic_ps_disable_work); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 6d29e40538ad..4e8513cfdae5 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -317,7 +317,8 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) } static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, - enum queue_stop_reason reason) + enum queue_stop_reason reason, + bool refcounted) { struct ieee80211_local *local = hw_to_local(hw); @@ -329,7 +330,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, if (!test_bit(reason, &local->queue_stop_reasons[queue])) return; - __clear_bit(reason, &local->queue_stop_reasons[queue]); + if (!refcounted) + local->q_stop_reasons[queue][reason] = 0; + else + local->q_stop_reasons[queue][reason]--; + + if (local->q_stop_reasons[queue][reason] == 0) + __clear_bit(reason, &local->queue_stop_reasons[queue]); if (local->queue_stop_reasons[queue] != 0) /* someone still has this queue stopped */ @@ -344,25 +351,28 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, } void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, - enum queue_stop_reason reason) + enum queue_stop_reason reason, + bool refcounted) { struct ieee80211_local *local = hw_to_local(hw); unsigned long flags; spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - __ieee80211_wake_queue(hw, queue, reason); + __ieee80211_wake_queue(hw, queue, reason, refcounted); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) { ieee80211_wake_queue_by_reason(hw, queue, - IEEE80211_QUEUE_STOP_REASON_DRIVER); + IEEE80211_QUEUE_STOP_REASON_DRIVER, + false); } EXPORT_SYMBOL(ieee80211_wake_queue); static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, - enum queue_stop_reason reason) + enum queue_stop_reason reason, + bool refcounted) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; @@ -373,10 +383,13 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, if (WARN_ON(queue >= hw->queues)) return; - if (test_bit(reason, &local->queue_stop_reasons[queue])) - return; + if (!refcounted) + local->q_stop_reasons[queue][reason] = 1; + else + local->q_stop_reasons[queue][reason]++; - __set_bit(reason, &local->queue_stop_reasons[queue]); + if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue])) + return; if (local->hw.queues < IEEE80211_NUM_ACS) n_acs = 1; @@ -398,20 +411,22 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, } void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, - enum queue_stop_reason reason) + enum queue_stop_reason reason, + bool refcounted) { struct ieee80211_local *local = hw_to_local(hw); unsigned long flags; spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - __ieee80211_stop_queue(hw, queue, reason); + __ieee80211_stop_queue(hw, queue, reason, refcounted); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) { ieee80211_stop_queue_by_reason(hw, queue, - IEEE80211_QUEUE_STOP_REASON_DRIVER); + IEEE80211_QUEUE_STOP_REASON_DRIVER, + false); } EXPORT_SYMBOL(ieee80211_stop_queue); @@ -429,9 +444,11 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, } spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD, + false); __skb_queue_tail(&local->pending[queue], skb); - __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD, + false); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } @@ -455,20 +472,23 @@ void ieee80211_add_pending_skbs(struct ieee80211_local *local, queue = info->hw_queue; __ieee80211_stop_queue(hw, queue, - IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + IEEE80211_QUEUE_STOP_REASON_SKB_ADD, + false); __skb_queue_tail(&local->pending[queue], skb); } for (i = 0; i < hw->queues; i++) __ieee80211_wake_queue(hw, i, - IEEE80211_QUEUE_STOP_REASON_SKB_ADD); + IEEE80211_QUEUE_STOP_REASON_SKB_ADD, + false); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, unsigned long queues, - enum queue_stop_reason reason) + enum queue_stop_reason reason, + bool refcounted) { struct ieee80211_local *local = hw_to_local(hw); unsigned long flags; @@ -477,7 +497,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, spin_lock_irqsave(&local->queue_stop_reason_lock, flags); for_each_set_bit(i, &queues, hw->queues) - __ieee80211_stop_queue(hw, i, reason); + __ieee80211_stop_queue(hw, i, reason, refcounted); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } @@ -485,7 +505,8 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, void ieee80211_stop_queues(struct ieee80211_hw *hw) { ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_DRIVER); + IEEE80211_QUEUE_STOP_REASON_DRIVER, + false); } EXPORT_SYMBOL(ieee80211_stop_queues); @@ -508,7 +529,8 @@ EXPORT_SYMBOL(ieee80211_queue_stopped); void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, unsigned long queues, - enum queue_stop_reason reason) + enum queue_stop_reason reason, + bool refcounted) { struct ieee80211_local *local = hw_to_local(hw); unsigned long flags; @@ -517,7 +539,7 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, spin_lock_irqsave(&local->queue_stop_reason_lock, flags); for_each_set_bit(i, &queues, hw->queues) - __ieee80211_wake_queue(hw, i, reason); + __ieee80211_wake_queue(hw, i, reason, refcounted); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } @@ -525,7 +547,8 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, void ieee80211_wake_queues(struct ieee80211_hw *hw) { ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_DRIVER); + IEEE80211_QUEUE_STOP_REASON_DRIVER, + false); } EXPORT_SYMBOL(ieee80211_wake_queues); @@ -552,12 +575,14 @@ void ieee80211_flush_queues(struct ieee80211_local *local, } ieee80211_stop_queues_by_reason(&local->hw, queues, - IEEE80211_QUEUE_STOP_REASON_FLUSH); + IEEE80211_QUEUE_STOP_REASON_FLUSH, + false); drv_flush(local, sdata, queues, false); ieee80211_wake_queues_by_reason(&local->hw, queues, - IEEE80211_QUEUE_STOP_REASON_FLUSH); + IEEE80211_QUEUE_STOP_REASON_FLUSH, + false); } static void __iterate_active_interfaces(struct ieee80211_local *local, @@ -1797,7 +1822,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) } ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_SUSPEND); + IEEE80211_QUEUE_STOP_REASON_SUSPEND, + false); /* * Reconfigure sched scan if it was interrupted by FW restart or -- cgit v1.2.3 From 26da23b6950cd1aaae86caa541eb4befc9e96e1d Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 13 Jun 2014 16:30:06 +0300 Subject: mac80211: add functions to stop and wake all queues assigned to a vif In some cases we may want to stop the queues of a single vif (for instance during a channel-switch). Add a function that stops all the queues that are assigned to a vif. If a queue is assigned to more than one vif, the corresponding netdev subqueue of the other vif(s) will also be stopped. If the HW doesn't set the IEEE80211_HW_QUEUE_CONTROL flag, then all queues are stopped. Also add a corresponding function to wake the queues of a vif back. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 6 ++++++ net/mac80211/util.c | 41 +++++++++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a0c7da809744..b202df2aebe8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1720,6 +1720,12 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, unsigned long queues, enum queue_stop_reason reason, bool refcounted); +void ieee80211_stop_vif_queues(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + enum queue_stop_reason reason); +void ieee80211_wake_vif_queues(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + enum queue_stop_reason reason); void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, unsigned long queues, enum queue_stop_reason reason, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 4e8513cfdae5..42d448d765b4 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -552,13 +552,11 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_wake_queues); -void ieee80211_flush_queues(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) +static unsigned int +ieee80211_get_vif_queues(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) { - u32 queues; - - if (!local->ops->flush) - return; + unsigned int queues; if (sdata && local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) { int ac; @@ -574,6 +572,19 @@ void ieee80211_flush_queues(struct ieee80211_local *local, queues = BIT(local->hw.queues) - 1; } + return queues; +} + +void ieee80211_flush_queues(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + unsigned int queues; + + if (!local->ops->flush) + return; + + queues = ieee80211_get_vif_queues(local, sdata); + ieee80211_stop_queues_by_reason(&local->hw, queues, IEEE80211_QUEUE_STOP_REASON_FLUSH, false); @@ -585,6 +596,24 @@ void ieee80211_flush_queues(struct ieee80211_local *local, false); } +void ieee80211_stop_vif_queues(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + enum queue_stop_reason reason) +{ + ieee80211_stop_queues_by_reason(&local->hw, + ieee80211_get_vif_queues(local, sdata), + reason, true); +} + +void ieee80211_wake_vif_queues(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + enum queue_stop_reason reason) +{ + ieee80211_wake_queues_by_reason(&local->hw, + ieee80211_get_vif_queues(local, sdata), + reason, true); +} + static void __iterate_active_interfaces(struct ieee80211_local *local, u32 iter_flags, void (*iterator)(void *data, u8 *mac, -- cgit v1.2.3 From a46992b441f097a971cca39f49d07a0d16a1c0d8 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 13 Jun 2014 16:30:07 +0300 Subject: mac80211: stop only the queues assigned to the vif during channel switch Instead of stopping all the hardware queues during channel switch, which is especially bad when we have large CSA counts, stop only the queues that are assigned to the vif that is performing the channel switch. Additionally, check for (sdata->csa_block_tx) instead of calling ieee80211_csa_needs_block_tx(), which can now be removed. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 52 ++++++++++++---------------------------------- net/mac80211/ieee80211_i.h | 1 - net/mac80211/iface.c | 10 ++++----- net/mac80211/mlme.c | 36 +++++++++++++++----------------- 4 files changed, 35 insertions(+), 64 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e920d48f0209..a0d7a0362f1f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -790,31 +790,6 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, return 0; } -bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local) -{ - struct ieee80211_sub_if_data *sdata; - - lockdep_assert_held(&local->mtx); - - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) - continue; - - if (!sdata->vif.csa_active) - continue; - - if (!sdata->csa_block_tx) - continue; - - rcu_read_unlock(); - return true; - } - rcu_read_unlock(); - - return false; -} - static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -834,11 +809,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) /* abort any running channel switch */ mutex_lock(&local->mtx); sdata->vif.csa_active = false; - if (!ieee80211_csa_needs_block_tx(local)) - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + if (sdata->csa_block_tx) { + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_block_tx = false; + } + mutex_unlock(&local->mtx); kfree(sdata->u.ap.next_beacon); @@ -2826,11 +2802,11 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) ieee80211_bss_info_change_notify(sdata, changed); cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); - if (!ieee80211_csa_needs_block_tx(local)) - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + if (sdata->csa_block_tx) { + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_block_tx = false; + } return 0; } @@ -3060,10 +3036,8 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, sdata->vif.csa_active = true; if (sdata->csa_block_tx) - ieee80211_stop_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + ieee80211_stop_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); if (changed) { ieee80211_bss_info_change_notify(sdata, changed); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b202df2aebe8..1fd50f173653 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1489,7 +1489,6 @@ void ieee80211_sw_roc_work(struct work_struct *work); void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); /* channel switch handling */ -bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local); void ieee80211_csa_finalize_work(struct work_struct *work); int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_csa_settings *params); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 1971d2418d44..2a12b8aa6aad 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -841,11 +841,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, sdata_lock(sdata); mutex_lock(&local->mtx); sdata->vif.csa_active = false; - if (!ieee80211_csa_needs_block_tx(local)) - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + if (sdata->csa_block_tx) { + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_block_tx = false; + } mutex_unlock(&local->mtx); sdata_unlock(sdata); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1ab1884eddbf..eccc8492a59c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -980,11 +980,11 @@ static void ieee80211_chswitch_work(struct work_struct *work) mutex_lock(&local->mtx); sdata->vif.csa_active = false; /* XXX: wait for a beacon first? */ - if (!ieee80211_csa_needs_block_tx(local)) - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + if (sdata->csa_block_tx) { + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_block_tx = false; + } mutex_unlock(&local->mtx); ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; @@ -1114,10 +1114,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, sdata->csa_block_tx = csa_ie.mode; if (sdata->csa_block_tx) - ieee80211_stop_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + ieee80211_stop_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); mutex_unlock(&local->mtx); if (local->ops->channel_switch) { @@ -1833,11 +1831,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ieee80211_vif_release_channel(sdata); sdata->vif.csa_active = false; - if (!ieee80211_csa_needs_block_tx(local)) - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + if (sdata->csa_block_tx) { + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_block_tx = false; + } mutex_unlock(&local->mtx); sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; @@ -2083,11 +2081,11 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->mtx); sdata->vif.csa_active = false; - if (!ieee80211_csa_needs_block_tx(local)) - ieee80211_wake_queues_by_reason(&local->hw, - IEEE80211_MAX_QUEUE_MAP, - IEEE80211_QUEUE_STOP_REASON_CSA, - false); + if (sdata->csa_block_tx) { + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_CSA); + sdata->csa_block_tx = false; + } mutex_unlock(&local->mtx); cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, -- cgit v1.2.3 From 9deba04d0f0b43ca60a867f006e06625ad85f8c2 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 11 Jun 2014 17:18:18 +0300 Subject: mac80211: clarify TDLS Tx handling Rename the flags used in the Tx path and add an explanation for the reasons to drop, send directly or through the AP. Signed-off-by: Arik Nemtsov Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f6018178f33c..865bdaf06ff1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1811,7 +1811,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, int nh_pos, h_pos; struct sta_info *sta = NULL; bool wme_sta = false, authorized = false, tdls_auth = false; - bool tdls_direct = false; + bool tdls_peer = false, tdls_setup_frame = false; bool multicast; u32 info_flags = 0; u16 info_id = 0; @@ -1953,34 +1953,35 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, #endif case NL80211_IFTYPE_STATION: if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { - bool tdls_peer = false; - sta = sta_info_get(sdata, skb->data); if (sta) { authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); wme_sta = test_sta_flag(sta, WLAN_STA_WME); tdls_peer = test_sta_flag(sta, - WLAN_STA_TDLS_PEER); + WLAN_STA_TDLS_PEER); tdls_auth = test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); } - /* - * If the TDLS link is enabled, send everything - * directly. Otherwise, allow TDLS setup frames - * to be transmitted indirectly. - */ - tdls_direct = tdls_peer && (tdls_auth || - !(ethertype == ETH_P_TDLS && skb->len > 14 && - skb->data[14] == WLAN_TDLS_SNAP_RFTYPE)); + if (tdls_peer) + tdls_setup_frame = + ethertype == ETH_P_TDLS && + skb->len > 14 && + skb->data[14] == WLAN_TDLS_SNAP_RFTYPE; } - if (tdls_direct) { - /* link during setup - throw out frames to peer */ - if (!tdls_auth) - goto fail_rcu; + /* + * TDLS link during setup - throw out frames to peer. We allow + * TDLS-setup frames to unauthorized peers for the special case + * of a link teardown after a TDLS sta is removed due to being + * unreachable. + */ + if (tdls_peer && !tdls_auth && !tdls_setup_frame) + goto fail_rcu; + /* send direct packets to authorized TDLS peers */ + if (tdls_peer && tdls_auth) { /* DA SA BSSID */ memcpy(hdr.addr1, skb->data, ETH_ALEN); memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); -- cgit v1.2.3 From 68885a54cd04742a2e6e10e9d3ff5976d046832e Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 11 Jun 2014 17:18:19 +0300 Subject: mac80211: set auth flags after other station info For TDLS, the AUTHORIZED flag arrives with all other important station info (supported rates, HT/VHT caps, ...). Make sure to set the station state in the low-level driver after transferring this information to the mac80211 STA entry. This aligns the STA information during sta_state callbacks with the non-TDLS case. Signed-off-by: Arik Nemtsov Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a0d7a0362f1f..73c9e1003e25 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -997,9 +997,12 @@ static int sta_apply_parameters(struct ieee80211_local *local, } } - ret = sta_apply_auth_flags(local, sta, mask, set); - if (ret) - return ret; + /* auth flags will be set later for TDLS stations */ + if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { + ret = sta_apply_auth_flags(local, sta, mask, set); + if (ret) + return ret; + } if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) @@ -1136,6 +1139,13 @@ static int sta_apply_parameters(struct ieee80211_local *local, #endif } + /* set the STA state after all sta info from usermode has been set */ + if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { + ret = sta_apply_auth_flags(local, sta, mask, set); + if (ret) + return ret; + } + return 0; } -- cgit v1.2.3 From 17e6a59a365ac993c18f762d3a259635957f1026 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 11 Jun 2014 17:18:20 +0300 Subject: mac80211: cleanup TDLS state during failed setup When setting up a TDLS session, register a delayed work to remove the peer if setup times out. Prevent concurrent setups to support this capacity. Signed-off-by: Arik Nemtsov Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 4 ++ net/mac80211/iface.c | 2 + net/mac80211/tdls.c | 133 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 115 insertions(+), 24 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1fd50f173653..fc687d2a7518 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -794,6 +794,9 @@ struct ieee80211_sub_if_data { bool radar_required; struct delayed_work dfs_cac_timer_work; + u8 tdls_peer[ETH_ALEN] __aligned(2); + struct delayed_work tdls_peer_del_work; + /* * AP this belongs to: self in AP mode and * corresponding AP in VLAN mode, NULL for @@ -1878,3 +1881,4 @@ extern const struct ethtool_ops ieee80211_ethtool_ops; #endif #endif /* IEEE80211_I_H */ +void ieee80211_tdls_peer_del_work(struct work_struct *wk); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2a12b8aa6aad..bbf51b2f0651 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1672,6 +1672,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, ieee80211_dfs_cac_timer_work); INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, ieee80211_delayed_tailroom_dec); + INIT_DELAYED_WORK(&sdata->tdls_peer_del_work, + ieee80211_tdls_peer_del_work); for (i = 0; i < IEEE80211_NUM_BANDS; i++) { struct ieee80211_supported_band *sband; diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 652813b2d3df..cafcbde70018 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -10,6 +10,27 @@ #include #include "ieee80211_i.h" +/* give usermode some time for retries in setting up the TDLS session */ +#define TDLS_PEER_SETUP_TIMEOUT (15 * HZ) + +void ieee80211_tdls_peer_del_work(struct work_struct *wk) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local; + + sdata = container_of(wk, struct ieee80211_sub_if_data, + tdls_peer_del_work.work); + local = sdata->local; + + mutex_lock(&local->mtx); + if (!is_zero_ether_addr(sdata->tdls_peer)) { + tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->tdls_peer); + sta_info_destroy_addr(sdata, sdata->tdls_peer); + eth_zero_addr(sdata->tdls_peer); + } + mutex_unlock(&local->mtx); +} + static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) { u8 *pos = (void *)skb_put(skb, 7); @@ -168,10 +189,12 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, return 0; } -int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - const u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, u32 peer_capability, - const u8 *extra_ies, size_t extra_ies_len) +static int +ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, u8 action_code, + u8 dialog_token, u16 status_code, + u32 peer_capability, const u8 *extra_ies, + size_t extra_ies_len) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; @@ -179,17 +202,6 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, bool send_direct; int ret; - if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) - return -ENOTSUPP; - - /* make sure we are in managed mode, and associated */ - if (sdata->vif.type != NL80211_IFTYPE_STATION || - !sdata->u.mgd.associated) - return -EINVAL; - - tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n", - action_code, peer); - skb = dev_alloc_skb(local->hw.extra_tx_headroom + max(sizeof(struct ieee80211_mgmt), sizeof(struct ieee80211_tdls_data)) + @@ -284,11 +296,64 @@ fail: return ret; } +int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, + const u8 *extra_ies, size_t extra_ies_len) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + int ret; + + if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) + return -ENOTSUPP; + + /* make sure we are in managed mode, and associated */ + if (sdata->vif.type != NL80211_IFTYPE_STATION || + !sdata->u.mgd.associated) + return -EINVAL; + + mutex_lock(&local->mtx); + + /* we don't support concurrent TDLS peer setups */ + if (!is_zero_ether_addr(sdata->tdls_peer) && + !ether_addr_equal(sdata->tdls_peer, peer) && + (action_code == WLAN_TDLS_SETUP_REQUEST || + action_code == WLAN_TDLS_SETUP_RESPONSE)) { + ret = -EBUSY; + goto exit; + } + + ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, extra_ies, + extra_ies_len); + if (ret < 0) + goto exit; + + if (action_code == WLAN_TDLS_SETUP_REQUEST || + action_code == WLAN_TDLS_SETUP_RESPONSE) { + memcpy(sdata->tdls_peer, peer, ETH_ALEN); + ieee80211_queue_delayed_work(&sdata->local->hw, + &sdata->tdls_peer_del_work, + TDLS_PEER_SETUP_TIMEOUT); + } + +exit: + mutex_unlock(&local->mtx); + + tdls_dbg(sdata, "TDLS mgmt action %d peer %pM status %d\n", + action_code, peer, ret); + return ret; +} + int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, enum nl80211_tdls_operation oper) { struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + int ret; if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) return -ENOTSUPP; @@ -296,6 +361,18 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, if (sdata->vif.type != NL80211_IFTYPE_STATION) return -EINVAL; + switch (oper) { + case NL80211_TDLS_ENABLE_LINK: + case NL80211_TDLS_DISABLE_LINK: + break; + case NL80211_TDLS_TEARDOWN: + case NL80211_TDLS_SETUP: + case NL80211_TDLS_DISCOVERY_REQ: + /* We don't support in-driver setup/teardown/discovery */ + return -ENOTSUPP; + } + + mutex_lock(&local->mtx); tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer); switch (oper) { @@ -304,22 +381,30 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, sta = sta_info_get(sdata, peer); if (!sta) { rcu_read_unlock(); - return -ENOLINK; + ret = -ENOLINK; + break; } set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); rcu_read_unlock(); + + WARN_ON_ONCE(is_zero_ether_addr(sdata->tdls_peer) || + !ether_addr_equal(sdata->tdls_peer, peer)); + ret = 0; break; case NL80211_TDLS_DISABLE_LINK: - return sta_info_destroy_addr(sdata, peer); - case NL80211_TDLS_TEARDOWN: - case NL80211_TDLS_SETUP: - case NL80211_TDLS_DISCOVERY_REQ: - /* We don't support in-driver setup/teardown/discovery */ - return -ENOTSUPP; + ret = sta_info_destroy_addr(sdata, peer); + break; default: - return -ENOTSUPP; + ret = -ENOTSUPP; + break; } - return 0; + if (ret == 0 && ether_addr_equal(sdata->tdls_peer, peer)) { + cancel_delayed_work(&sdata->tdls_peer_del_work); + eth_zero_addr(sdata->tdls_peer); + } + + mutex_unlock(&local->mtx); + return ret; } -- cgit v1.2.3 From 31fa97c5defca3895dc6c823096d7ba59df76125 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 11 Jun 2014 17:18:21 +0300 Subject: cfg80211: pass TDLS initiator in tdls_mgmt operations The TDLS initiator is set once during link setup. If determines the address ordering in the link identifier IE. Fix dependent drivers - mwifiex and mac80211. Signed-off-by: Arik Nemtsov Signed-off-by: Johannes Berg --- drivers/net/wireless/mwifiex/cfg80211.c | 3 ++- include/net/cfg80211.h | 2 +- include/uapi/linux/nl80211.h | 5 +++++ net/mac80211/ieee80211_i.h | 3 ++- net/mac80211/tdls.c | 3 ++- net/wireless/nl80211.c | 4 ++++ net/wireless/rdev-ops.h | 6 +++--- net/wireless/trace.h | 10 +++++++--- 8 files changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index e95dec91a561..149d2e693bdd 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2631,7 +2631,8 @@ static int mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, - const u8 *extra_ies, size_t extra_ies_len) + bool initiator, const u8 *extra_ies, + size_t extra_ies_len) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int ret; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 29cb4b2bee5a..b9eeae3990cf 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2500,7 +2500,7 @@ struct cfg80211_ops { int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, - const u8 *buf, size_t len); + bool initiator, const u8 *buf, size_t len); int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, enum nl80211_tdls_operation oper); diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index be9519b52bb1..f1db15b9c041 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1591,6 +1591,9 @@ enum nl80211_commands { * creation then the new interface will be owned by the netlink socket * that created it and will be destroyed when the socket is closed * + * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is + * the TDLS link initiator. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1931,6 +1934,8 @@ enum nl80211_attrs { NL80211_ATTR_CSA_C_OFFSETS_TX, NL80211_ATTR_MAX_CSA_COUNTERS, + NL80211_ATTR_TDLS_INITIATOR, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index fc687d2a7518..75f79c168e90 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1867,7 +1867,8 @@ int ieee80211_max_num_channels(struct ieee80211_local *local); int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, - const u8 *extra_ies, size_t extra_ies_len); + bool initiator, const u8 *extra_ies, + size_t extra_ies_len); int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, enum nl80211_tdls_operation oper); diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index cafcbde70018..0b3ca2ce7ea4 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -299,7 +299,8 @@ fail: int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, - const u8 *extra_ies, size_t extra_ies_len) + bool initiator, const u8 *extra_ies, + size_t extra_ies_len) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ba4f1723c83a..8f46b8ffbcf6 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -337,6 +337,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 }, [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG }, [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG }, + [NL80211_ATTR_TDLS_INITIATOR] = { .type = NLA_FLAG }, [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, @@ -7365,6 +7366,7 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) u32 peer_capability = 0; u16 status_code; u8 *peer; + bool initiator; if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || !rdev->ops->tdls_mgmt) @@ -7381,12 +7383,14 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]); status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]); + initiator = nla_get_flag(info->attrs[NL80211_ATTR_TDLS_INITIATOR]); if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]) peer_capability = nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]); return rdev_tdls_mgmt(rdev, dev, peer, action_code, dialog_token, status_code, peer_capability, + initiator, nla_data(info->attrs[NL80211_ATTR_IE]), nla_len(info->attrs[NL80211_ATTR_IE])); } diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index f552b0abbd70..56c2240c30ce 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -751,15 +751,15 @@ static inline int rdev_tdls_mgmt(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, - const u8 *buf, size_t len) + bool initiator, const u8 *buf, size_t len) { int ret; trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, action_code, dialog_token, status_code, peer_capability, - buf, len); + initiator, buf, len); ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, dialog_token, status_code, peer_capability, - buf, len); + initiator, buf, len); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 174559aade57..85474ee501eb 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1454,9 +1454,9 @@ TRACE_EVENT(rdev_tdls_mgmt, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, - const u8 *buf, size_t len), + bool initiator, const u8 *buf, size_t len), TP_ARGS(wiphy, netdev, peer, action_code, dialog_token, status_code, - peer_capability, buf, len), + peer_capability, initiator, buf, len), TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY @@ -1465,6 +1465,7 @@ TRACE_EVENT(rdev_tdls_mgmt, __field(u8, dialog_token) __field(u16, status_code) __field(u32, peer_capability) + __field(bool, initiator) __dynamic_array(u8, buf, len) ), TP_fast_assign( @@ -1475,13 +1476,16 @@ TRACE_EVENT(rdev_tdls_mgmt, __entry->dialog_token = dialog_token; __entry->status_code = status_code; __entry->peer_capability = peer_capability; + __entry->initiator = initiator; memcpy(__get_dynamic_array(buf), buf, len); ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", action_code: %u, " - "dialog_token: %u, status_code: %u, peer_capability: %u buf: %#.2x ", + "dialog_token: %u, status_code: %u, peer_capability: %u " + "initiator: %s buf: %#.2x ", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->action_code, __entry->dialog_token, __entry->status_code, __entry->peer_capability, + BOOL_TO_STR(__entry->initiator), ((u8 *)__get_dynamic_array(buf))[0]) ); -- cgit v1.2.3 From 2fb6b9b8e5f08df31bc4081b4d9f38701c59cfd3 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 11 Jun 2014 17:18:22 +0300 Subject: mac80211: use TDLS initiator in tdls_mgmt operations The TDLS initiator is set once during link setup. If determines the address ordering in the link identifier IE. Use the value from userspace in order to have a correct teardown packet. With the current code, a teardown from the responder side fails the TDLS MIC check because of a bad link identifier IE. Signed-off-by: Arik Nemtsov Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 0b3ca2ce7ea4..c4a9af3b75e5 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -193,13 +193,14 @@ static int ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, - u32 peer_capability, const u8 *extra_ies, - size_t extra_ies_len) + u32 peer_capability, bool initiator, + const u8 *extra_ies, size_t extra_ies_len) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; struct sk_buff *skb = NULL; bool send_direct; + const u8 *init_addr, *rsp_addr; int ret; skb = dev_alloc_skb(local->hw.extra_tx_headroom + @@ -242,27 +243,42 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, if (extra_ies_len) memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); - /* the TDLS link IE is always added last */ + /* sanity check for initiator */ switch (action_code) { case WLAN_TDLS_SETUP_REQUEST: case WLAN_TDLS_SETUP_CONFIRM: - case WLAN_TDLS_TEARDOWN: case WLAN_TDLS_DISCOVERY_REQUEST: - /* we are the initiator */ - ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer, - sdata->u.mgd.bssid); + if (!initiator) { + ret = -EINVAL; + goto fail; + } break; case WLAN_TDLS_SETUP_RESPONSE: case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: - /* we are the responder */ - ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr, - sdata->u.mgd.bssid); + if (initiator) { + ret = -EINVAL; + goto fail; + } + break; + case WLAN_TDLS_TEARDOWN: + /* any value is ok */ break; default: ret = -ENOTSUPP; goto fail; } + if (initiator) { + init_addr = sdata->vif.addr; + rsp_addr = peer; + } else { + init_addr = peer; + rsp_addr = sdata->vif.addr; + } + + ieee80211_tdls_add_link_ie(skb, init_addr, rsp_addr, + sdata->u.mgd.bssid); + if (send_direct) { ieee80211_tx_skb(sdata, skb); return 0; @@ -327,8 +343,8 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, dialog_token, status_code, - peer_capability, extra_ies, - extra_ies_len); + peer_capability, initiator, + extra_ies, extra_ies_len); if (ret < 0) goto exit; -- cgit v1.2.3 From 191dd46905ce9a25174dd9eea4ff3029802ac37c Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 11 Jun 2014 17:18:23 +0300 Subject: mac80211: split tdls_mgmt function There are setup/teardown specific actions to be done that accompany the sending of a TDLS management packet. Split the main function to simplify future additions. Signed-off-by: Arik Nemtsov Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 78 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index c4a9af3b75e5..92d203a3be07 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -312,31 +312,21 @@ fail: return ret; } -int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - const u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, u32 peer_capability, - bool initiator, const u8 *extra_ies, - size_t extra_ies_len) +static int +ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, bool initiator, + const u8 *extra_ies, size_t extra_ies_len) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; int ret; - if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) - return -ENOTSUPP; - - /* make sure we are in managed mode, and associated */ - if (sdata->vif.type != NL80211_IFTYPE_STATION || - !sdata->u.mgd.associated) - return -EINVAL; - mutex_lock(&local->mtx); /* we don't support concurrent TDLS peer setups */ if (!is_zero_ether_addr(sdata->tdls_peer) && - !ether_addr_equal(sdata->tdls_peer, peer) && - (action_code == WLAN_TDLS_SETUP_REQUEST || - action_code == WLAN_TDLS_SETUP_RESPONSE)) { + !ether_addr_equal(sdata->tdls_peer, peer)) { ret = -EBUSY; goto exit; } @@ -348,16 +338,58 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, if (ret < 0) goto exit; - if (action_code == WLAN_TDLS_SETUP_REQUEST || - action_code == WLAN_TDLS_SETUP_RESPONSE) { - memcpy(sdata->tdls_peer, peer, ETH_ALEN); - ieee80211_queue_delayed_work(&sdata->local->hw, - &sdata->tdls_peer_del_work, - TDLS_PEER_SETUP_TIMEOUT); - } + memcpy(sdata->tdls_peer, peer, ETH_ALEN); + ieee80211_queue_delayed_work(&sdata->local->hw, + &sdata->tdls_peer_del_work, + TDLS_PEER_SETUP_TIMEOUT); exit: mutex_unlock(&local->mtx); + return ret; +} + +int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, + bool initiator, const u8 *extra_ies, + size_t extra_ies_len) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int ret; + + if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) + return -ENOTSUPP; + + /* make sure we are in managed mode, and associated */ + if (sdata->vif.type != NL80211_IFTYPE_STATION || + !sdata->u.mgd.associated) + return -EINVAL; + + switch (action_code) { + case WLAN_TDLS_SETUP_REQUEST: + case WLAN_TDLS_SETUP_RESPONSE: + ret = ieee80211_tdls_mgmt_setup(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, initiator, + extra_ies, extra_ies_len); + break; + case WLAN_TDLS_TEARDOWN: + case WLAN_TDLS_SETUP_CONFIRM: + case WLAN_TDLS_DISCOVERY_REQUEST: + case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: + /* no special handling */ + ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, + action_code, + dialog_token, + status_code, + peer_capability, + initiator, extra_ies, + extra_ies_len); + break; + default: + ret = -EOPNOTSUPP; + break; + } tdls_dbg(sdata, "TDLS mgmt action %d peer %pM status %d\n", action_code, peer, ret); -- cgit v1.2.3 From db67d661e82da22f751585a7f284a9251e8a2a51 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 11 Jun 2014 17:18:24 +0300 Subject: mac80211: implement proper Tx path flushing for TDLS As the spec mandates, flush data in the AP path before transmitting the first setup frame. Data packets transmitted during setup are already dropped in the Tx path. For the teardown flow, flush all packets in the direct path before transmitting the teardown frame. Un-authorize the peer sta after teardown is sent, forcing all subsequent Tx to the peer through the AP. Make sure to flush the queues when disabling the link to get the teardown packet out. Signed-off-by: Arik Nemtsov [adjust to Luca's new quuee API and stop only vif queues] Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/tdls.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 75f79c168e90..6c8089429892 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -925,6 +925,7 @@ enum queue_stop_reason { IEEE80211_QUEUE_STOP_REASON_SKB_ADD, IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, IEEE80211_QUEUE_STOP_REASON_FLUSH, + IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN, IEEE80211_QUEUE_STOP_REASONS, }; diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 92d203a3be07..0ba7e4c029c8 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -331,6 +331,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, goto exit; } + ieee80211_flush_queues(local, sdata); + ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, dialog_token, status_code, peer_capability, initiator, @@ -348,6 +350,52 @@ exit: return ret; } +static int +ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, + bool initiator, const u8 *extra_ies, + size_t extra_ies_len) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + struct sta_info *sta; + int ret; + + /* + * No packets can be transmitted to the peer via the AP during setup - + * the STA is set as a TDLS peer, but is not authorized. + * During teardown, we prevent direct transmissions by stopping the + * queues and flushing all direct packets. + */ + ieee80211_stop_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN); + ieee80211_flush_queues(local, sdata); + + ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, initiator, + extra_ies, extra_ies_len); + if (ret < 0) + sdata_err(sdata, "Failed sending TDLS teardown packet %d\n", + ret); + + /* + * Remove the STA AUTH flag to force further traffic through the AP. If + * the STA was unreachable, it was already removed. + */ + rcu_read_lock(); + sta = sta_info_get(sdata, peer); + if (sta) + clear_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); + rcu_read_unlock(); + + ieee80211_wake_vif_queues(local, sdata, + IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN); + + return 0; +} + int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, @@ -374,6 +422,12 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, extra_ies, extra_ies_len); break; case WLAN_TDLS_TEARDOWN: + ret = ieee80211_tdls_mgmt_teardown(wiphy, dev, peer, + action_code, dialog_token, + status_code, + peer_capability, initiator, + extra_ies, extra_ies_len); + break; case WLAN_TDLS_SETUP_CONFIRM: case WLAN_TDLS_DISCOVERY_REQUEST: case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: @@ -442,6 +496,9 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, ret = 0; break; case NL80211_TDLS_DISABLE_LINK: + /* flush a potentially queued teardown packet */ + ieee80211_flush_queues(local, sdata); + ret = sta_info_destroy_addr(sdata, peer); break; default: -- cgit v1.2.3 From c887f0d3a03283cb6fe2c32aae62229bebd3fa32 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 11 Jun 2014 17:18:25 +0300 Subject: mac80211: add API to request TDLS operation from userspace Write a mac80211 to the cfg80211 API for requesting a userspace TDLS operation. Define TDLS specific reason codes that can be used here. Signed-off-by: Arik Nemtsov Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 3 +++ include/net/mac80211.h | 13 +++++++++++++ net/mac80211/tdls.c | 17 +++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 6bff13f74050..75d17e15da33 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1621,6 +1621,9 @@ enum ieee80211_reasoncode { WLAN_REASON_INVALID_RSN_IE_CAP = 22, WLAN_REASON_IEEE8021X_FAILED = 23, WLAN_REASON_CIPHER_SUITE_REJECTED = 24, + /* TDLS (802.11z) */ + WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE = 25, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED = 26, /* 802.11e */ WLAN_REASON_DISASSOC_UNSPECIFIED_QOS = 32, WLAN_REASON_DISASSOC_QAP_NO_BANDWIDTH = 33, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 421b6ecb4b2c..8d876dc8b299 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4815,4 +4815,17 @@ int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr, */ void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf); +/** + * ieee80211_tdls_oper - request userspace to perform a TDLS operation + * @vif: virtual interface + * @peer: the peer's destination address + * @oper: the requested TDLS operation + * @reason_code: reason code for the operation, valid for TDLS teardown + * @gfp: allocation flags + * + * See cfg80211_tdls_oper_request(). + */ +void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, + enum nl80211_tdls_operation oper, + u16 reason_code, gfp_t gfp); #endif /* MAC80211_H */ diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 0ba7e4c029c8..6f3a3ad0cb7c 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -8,6 +8,7 @@ */ #include +#include #include "ieee80211_i.h" /* give usermode some time for retries in setting up the TDLS session */ @@ -514,3 +515,19 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, mutex_unlock(&local->mtx); return ret; } + +void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, + enum nl80211_tdls_operation oper, + u16 reason_code, gfp_t gfp) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + + if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) { + sdata_err(sdata, "Discarding TDLS oper %d - not STA or disconnected\n", + oper); + return; + } + + cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp); +} +EXPORT_SYMBOL(ieee80211_tdls_oper_request); -- cgit v1.2.3 From 7adc3e4664bc5bd382fa181e6a4506f5b5b583d8 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 11 Jun 2014 17:18:26 +0300 Subject: mac80211: make sure TDLS peer STA exists during setup Make sure userspace added a TDLS peer station before invoking the transmission of the first setup frame. This ensures packets to the peer won't go through the AP path. Signed-off-by: Arik Nemtsov Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 6f3a3ad0cb7c..b87e369561f4 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -332,6 +332,19 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, goto exit; } + /* + * make sure we have a STA representing the peer so we drop or buffer + * non-TDLS-setup frames to the peer. We can't send other packets + * during setup through the AP path + */ + rcu_read_lock(); + if (!sta_info_get(sdata, peer)) { + rcu_read_unlock(); + ret = -ENOLINK; + goto exit; + } + rcu_read_unlock(); + ieee80211_flush_queues(local, sdata); ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, -- cgit v1.2.3 From ee10f2c779b28c1d6e87ac3e1bbb1aa8b62fa891 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 11 Jun 2014 17:18:27 +0300 Subject: mac80211: protect TDLS discovery session After sending a TDLS discovery-request, we expect a reply to arrive on the AP's channel. We must stay on the channel (no PSM, scan, etc.), since a TDLS setup-response is a direct packet not buffered by the AP. Add a new mac80211 driver callback to allow discovery session protection. Signed-off-by: Arik Nemtsov Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- include/net/mac80211.h | 12 ++++++++++++ net/mac80211/driver-ops.h | 16 ++++++++++++++++ net/mac80211/tdls.c | 10 +++++++++- net/mac80211/trace.h | 7 +++++++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8d876dc8b299..18c2bdbaf988 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2764,6 +2764,15 @@ enum ieee80211_roc_type { * mac80211 will transmit the frame right away. * The callback is optional and can (should!) sleep. * + * @mgd_protect_tdls_discover: Protect a TDLS discovery session. After sending + * a TDLS discovery-request, we expect a reply to arrive on the AP's + * channel. We must stay on the channel (no PSM, scan, etc.), since a TDLS + * setup-response is a direct packet not buffered by the AP. + * mac80211 will call this function just before the transmission of a TDLS + * discovery-request. The recommended period of protection is at least + * 2 * (DTIM period). + * The callback is optional and can sleep. + * * @add_chanctx: Notifies device driver about new channel context creation. * @remove_chanctx: Notifies device driver about channel context destruction. * @change_chanctx: Notifies device driver about channel context changes that @@ -2981,6 +2990,9 @@ struct ieee80211_ops { void (*mgd_prepare_tx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + void (*mgd_protect_tdls_discover)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + int (*add_chanctx)(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx); void (*remove_chanctx)(struct ieee80211_hw *hw, diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index bd782dcffcc7..2265bd7a44ba 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -970,6 +970,22 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, trace_drv_return_void(local); } +static inline void +drv_mgd_protect_tdls_discover(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + might_sleep(); + + if (!check_sdata_in_driver(sdata)) + return; + WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION); + + trace_drv_mgd_protect_tdls_discover(local, sdata); + if (local->ops->mgd_protect_tdls_discover) + local->ops->mgd_protect_tdls_discover(&local->hw, &sdata->vif); + trace_drv_return_void(local); +} + static inline int drv_add_chanctx(struct ieee80211_local *local, struct ieee80211_chanctx *ctx) { diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index b87e369561f4..f7185338a0fa 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -10,6 +10,7 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" /* give usermode some time for retries in setting up the TDLS session */ #define TDLS_PEER_SETUP_TIMEOUT (15 * HZ) @@ -442,8 +443,15 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, peer_capability, initiator, extra_ies, extra_ies_len); break; - case WLAN_TDLS_SETUP_CONFIRM: case WLAN_TDLS_DISCOVERY_REQUEST: + /* + * Protect the discovery so we can hear the TDLS discovery + * response frame. It is transmitted directly and not buffered + * by the AP. + */ + drv_mgd_protect_tdls_discover(sdata->local, sdata); + /* fall-through */ + case WLAN_TDLS_SETUP_CONFIRM: case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: /* no special handling */ ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index cfe1a0688b5c..02ac535d1274 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1330,6 +1330,13 @@ DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, TP_ARGS(local, sdata) ); +DEFINE_EVENT(local_sdata_evt, drv_mgd_protect_tdls_discover, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + + TP_ARGS(local, sdata) +); + DECLARE_EVENT_CLASS(local_chanctx, TP_PROTO(struct ieee80211_local *local, struct ieee80211_chanctx *ctx), -- cgit v1.2.3 From e0f31d8498676fda36289603a054d0d490aa2679 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Mon, 23 Jun 2014 16:07:58 +0530 Subject: flow_keys: Record IP layer protocol in skb_flow_dissect() skb_flow_dissect() dissects only transport header type in ip_proto. It dose not give any information about IPv4 or IPv6. This patch adds new member, n_proto, to struct flow_keys. Which records the IP layer type. i.e IPv4 or IPv6. This can be used in netdev->ndo_rx_flow_steer driver function to dissect flow. Adding new member to flow_keys increases the struct size by around 4 bytes. This causes BUILD_BUG_ON(sizeof(qcb->data) < sz); to fail in qdisc_cb_private_validate() So increase data size by 4 Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- include/net/flow_keys.h | 14 ++++++++++++++ include/net/sch_generic.h | 2 +- net/core/flow_dissector.c | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h index 7e64bd8bbda9..fbefdca5e283 100644 --- a/include/net/flow_keys.h +++ b/include/net/flow_keys.h @@ -1,6 +1,19 @@ #ifndef _NET_FLOW_KEYS_H #define _NET_FLOW_KEYS_H +/* struct flow_keys: + * @src: source ip address in case of IPv4 + * For IPv6 it contains 32bit hash of src address + * @dst: destination ip address in case of IPv4 + * For IPv6 it contains 32bit hash of dst address + * @ports: port numbers of Transport header + * port16[0]: src port number + * port16[1]: dst port number + * @thoff: Transport header offset + * @n_proto: Network header protocol (eg. IPv4/IPv6) + * @ip_proto: Transport header protocol (eg. TCP/UDP) + * All the members, except thoff, are in network byte order. + */ struct flow_keys { /* (src,dst) must be grouped, in the same way than in IP header */ __be32 src; @@ -10,6 +23,7 @@ struct flow_keys { __be16 port16[2]; }; u16 thoff; + u16 n_proto; u8 ip_proto; }; diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 624f9857c83e..a3cfb8ebeb53 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -231,7 +231,7 @@ struct qdisc_skb_cb { unsigned int pkt_len; u16 slave_dev_queue_mapping; u16 _pad; - unsigned char data[20]; + unsigned char data[24]; }; static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 107ed12a5323..c2b53c1b21d2 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -175,6 +175,7 @@ ipv6: break; } + flow->n_proto = proto; flow->ip_proto = ip_proto; flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto); flow->thoff = (u16) nhoff; -- cgit v1.2.3 From 10cc88446cec4eee8e2efab24ad387d52ef1f4fb Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Mon, 23 Jun 2014 16:07:59 +0530 Subject: enic: fix return value in _vnic_dev_cmd Hardware (in readq(&devcmd->args[0])) returns positive number in case of error. But _vnic_dev_cmd should return a negative value in case of error. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/vnic_dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.c b/drivers/net/ethernet/cisco/enic/vnic_dev.c index e86a45cb9e68..263081b8e636 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_dev.c +++ b/drivers/net/ethernet/cisco/enic/vnic_dev.c @@ -312,12 +312,12 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, err = (int)readq(&devcmd->args[0]); if (err == ERR_EINVAL && cmd == CMD_CAPABILITY) - return err; + return -err; if (err != ERR_ECMDUNKNOWN || cmd != CMD_CAPABILITY) pr_err("Error %d devcmd %d\n", err, _CMD_N(cmd)); - return err; + return -err; } if (_CMD_DIR(cmd) & _CMD_DIR_READ) { -- cgit v1.2.3 From 631185273b6e1f8e0b5a00c1aca08650b2d18a57 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Mon, 23 Jun 2014 16:08:00 +0530 Subject: enic: devcmd for adding IP 5 tuple hardware filters This patch adds interface to add and delete IP 5 tuple filter. This interface is used by Accelerated RFS code to steer a flow to corresponding receive queue. As of now adaptor supports only ipv4 + tcp/udp packet steering. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/Makefile | 2 +- drivers/net/ethernet/cisco/enic/enic_clsf.c | 66 +++++++++++++++++++++++++++ drivers/net/ethernet/cisco/enic/enic_clsf.h | 10 ++++ drivers/net/ethernet/cisco/enic/vnic_dev.c | 61 +++++++++++++++++++++++++ drivers/net/ethernet/cisco/enic/vnic_dev.h | 2 + drivers/net/ethernet/cisco/enic/vnic_devcmd.h | 5 ++ 6 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/cisco/enic/enic_clsf.c create mode 100644 drivers/net/ethernet/cisco/enic/enic_clsf.h diff --git a/drivers/net/ethernet/cisco/enic/Makefile b/drivers/net/ethernet/cisco/enic/Makefile index 239e1e46545d..aadcaf7876ce 100644 --- a/drivers/net/ethernet/cisco/enic/Makefile +++ b/drivers/net/ethernet/cisco/enic/Makefile @@ -2,5 +2,5 @@ obj-$(CONFIG_ENIC) := enic.o enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \ enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o \ - enic_ethtool.o enic_api.o + enic_ethtool.o enic_api.o enic_clsf.o diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c new file mode 100644 index 000000000000..f6703c4f76a9 --- /dev/null +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "enic_res.h" +#include "enic_clsf.h" + +/* enic_addfltr_5t - Add ipv4 5tuple filter + * @enic: enic struct of vnic + * @keys: flow_keys of ipv4 5tuple + * @rq: rq number to steer to + * + * This function returns filter_id(hardware_id) of the filter + * added. In case of error it returns an negative number. + */ +int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq) +{ + int res; + struct filter data; + + switch (keys->ip_proto) { + case IPPROTO_TCP: + data.u.ipv4.protocol = PROTO_TCP; + break; + case IPPROTO_UDP: + data.u.ipv4.protocol = PROTO_UDP; + break; + default: + return -EPROTONOSUPPORT; + }; + data.type = FILTER_IPV4_5TUPLE; + data.u.ipv4.src_addr = ntohl(keys->src); + data.u.ipv4.dst_addr = ntohl(keys->dst); + data.u.ipv4.src_port = ntohs(keys->port16[0]); + data.u.ipv4.dst_port = ntohs(keys->port16[1]); + data.u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE; + + spin_lock_bh(&enic->devcmd_lock); + res = vnic_dev_classifier(enic->vdev, CLSF_ADD, &rq, &data); + spin_unlock_bh(&enic->devcmd_lock); + res = (res == 0) ? rq : res; + + return res; +} + +/* enic_delfltr - Delete clsf filter + * @enic: enic struct of vnic + * @filter_id: filter_is(hardware_id) of filter to be deleted + * + * This function returns zero in case of success, negative number incase of + * error. + */ +int enic_delfltr(struct enic *enic, u16 filter_id) +{ + int ret; + + spin_lock_bh(&enic->devcmd_lock); + ret = vnic_dev_classifier(enic->vdev, CLSF_DEL, &filter_id, NULL); + spin_unlock_bh(&enic->devcmd_lock); + + return ret; +} diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.h b/drivers/net/ethernet/cisco/enic/enic_clsf.h new file mode 100644 index 000000000000..b6925b368b77 --- /dev/null +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.h @@ -0,0 +1,10 @@ +#ifndef _ENIC_CLSF_H_ +#define _ENIC_CLSF_H_ + +#include "vnic_dev.h" +#include "enic.h" + +int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq); +int enic_delfltr(struct enic *enic, u16 filter_id); + +#endif /* _ENIC_CLSF_H_ */ diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.c b/drivers/net/ethernet/cisco/enic/vnic_dev.c index 263081b8e636..5abc496bcf29 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_dev.c +++ b/drivers/net/ethernet/cisco/enic/vnic_dev.c @@ -1048,3 +1048,64 @@ int vnic_dev_set_mac_addr(struct vnic_dev *vdev, u8 *mac_addr) return vnic_dev_cmd(vdev, CMD_SET_MAC_ADDR, &a0, &a1, wait); } + +/* vnic_dev_classifier: Add/Delete classifier entries + * @vdev: vdev of the device + * @cmd: CLSF_ADD for Add filter + * CLSF_DEL for Delete filter + * @entry: In case of ADD filter, the caller passes the RQ number in this + * variable. + * + * This function stores the filter_id returned by the firmware in the + * same variable before return; + * + * In case of DEL filter, the caller passes the RQ number. Return + * value is irrelevant. + * @data: filter data + */ +int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry, + struct filter *data) +{ + u64 a0, a1; + int wait = 1000; + dma_addr_t tlv_pa; + int ret = -EINVAL; + struct filter_tlv *tlv, *tlv_va; + struct filter_action *action; + u64 tlv_size; + + if (cmd == CLSF_ADD) { + tlv_size = sizeof(struct filter) + + sizeof(struct filter_action) + + 2 * sizeof(struct filter_tlv); + tlv_va = pci_alloc_consistent(vdev->pdev, tlv_size, &tlv_pa); + if (!tlv_va) + return -ENOMEM; + tlv = tlv_va; + a0 = tlv_pa; + a1 = tlv_size; + memset(tlv, 0, tlv_size); + tlv->type = CLSF_TLV_FILTER; + tlv->length = sizeof(struct filter); + *(struct filter *)&tlv->val = *data; + + tlv = (struct filter_tlv *)((char *)tlv + + sizeof(struct filter_tlv) + + sizeof(struct filter)); + + tlv->type = CLSF_TLV_ACTION; + tlv->length = sizeof(struct filter_action); + action = (struct filter_action *)&tlv->val; + action->type = FILTER_ACTION_RQ_STEERING; + action->u.rq_idx = *entry; + + ret = vnic_dev_cmd(vdev, CMD_ADD_FILTER, &a0, &a1, wait); + *entry = (u16)a0; + pci_free_consistent(vdev->pdev, tlv_size, tlv_va, tlv_pa); + } else if (cmd == CLSF_DEL) { + a0 = *entry; + ret = vnic_dev_cmd(vdev, CMD_DEL_FILTER, &a0, &a1, wait); + } + + return ret; +} diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.h b/drivers/net/ethernet/cisco/enic/vnic_dev.h index 1f3b301f8225..1fb214efceba 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_dev.h +++ b/drivers/net/ethernet/cisco/enic/vnic_dev.h @@ -133,5 +133,7 @@ int vnic_dev_enable2(struct vnic_dev *vdev, int active); int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status); int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status); int vnic_dev_set_mac_addr(struct vnic_dev *vdev, u8 *mac_addr); +int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry, + struct filter *data); #endif /* _VNIC_DEV_H_ */ diff --git a/drivers/net/ethernet/cisco/enic/vnic_devcmd.h b/drivers/net/ethernet/cisco/enic/vnic_devcmd.h index b9a0d78fd639..435d0cd96c22 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_devcmd.h +++ b/drivers/net/ethernet/cisco/enic/vnic_devcmd.h @@ -603,6 +603,11 @@ struct filter_tlv { u_int32_t val[0]; }; +enum { + CLSF_ADD = 0, + CLSF_DEL = 1, +}; + /* * Writing cmd register causes STAT_BUSY to get set in status register. * When cmd completes, STAT_BUSY will be cleared. -- cgit v1.2.3 From b6e97c132bbca469d57634622dd7bdacb21f018f Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Mon, 23 Jun 2014 16:08:01 +0530 Subject: enic: alloc/free rx_cpu_rmap rx_cpu_rmap provides the reverse irq cpu affinity. This patch allocates and sets drivers netdev->rx_cpu_rmap accordingly. rx_cpu_rmap is set in enic_request_intr() which is called by enic_open and rx_cpu_rmap is freed in enic_free_intr() which is called by enic_stop. This is used by Accelerated RFS. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_main.c | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index f32f828b7f3d..151b375337a9 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -39,6 +39,9 @@ #include #include #include +#ifdef CONFIG_RFS_ACCEL +#include +#endif #include "cq_enet_desc.h" #include "vnic_dev.h" @@ -1192,6 +1195,44 @@ static void enic_calc_int_moderation(struct enic *enic, struct vnic_rq *rq) pkt_size_counter->small_pkt_bytes_cnt = 0; } +#ifdef CONFIG_RFS_ACCEL +static void enic_free_rx_cpu_rmap(struct enic *enic) +{ + free_irq_cpu_rmap(enic->netdev->rx_cpu_rmap); + enic->netdev->rx_cpu_rmap = NULL; +} + +static void enic_set_rx_cpu_rmap(struct enic *enic) +{ + int i, res; + + if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) { + enic->netdev->rx_cpu_rmap = alloc_irq_cpu_rmap(enic->rq_count); + if (unlikely(!enic->netdev->rx_cpu_rmap)) + return; + for (i = 0; i < enic->rq_count; i++) { + res = irq_cpu_rmap_add(enic->netdev->rx_cpu_rmap, + enic->msix_entry[i].vector); + if (unlikely(res)) { + enic_free_rx_cpu_rmap(enic); + return; + } + } + } +} + +#else + +static void enic_free_rx_cpu_rmap(struct enic *enic) +{ +} + +static void enic_set_rx_cpu_rmap(struct enic *enic) +{ +} + +#endif /* CONFIG_RFS_ACCEL */ + static int enic_poll_msix(struct napi_struct *napi, int budget) { struct net_device *netdev = napi->dev; @@ -1267,6 +1308,7 @@ static void enic_free_intr(struct enic *enic) struct net_device *netdev = enic->netdev; unsigned int i; + enic_free_rx_cpu_rmap(enic); switch (vnic_dev_get_intr_mode(enic->vdev)) { case VNIC_DEV_INTR_MODE_INTX: free_irq(enic->pdev->irq, netdev); @@ -1291,6 +1333,7 @@ static int enic_request_intr(struct enic *enic) unsigned int i, intr; int err = 0; + enic_set_rx_cpu_rmap(enic); switch (vnic_dev_get_intr_mode(enic->vdev)) { case VNIC_DEV_INTR_MODE_INTX: -- cgit v1.2.3 From a145df23ef32c7b933875f334ba28791ee75766e Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Mon, 23 Jun 2014 16:08:02 +0530 Subject: enic: Add Accelerated RFS support This patch adds supports for Accelerated Receive Flow Steering. When the desired rx is different from current rq, for a flow, kernel calls the driver function enic_rx_flow_steer(). enic_rx_flow_steer adds a IP-TCP/UDP hardware filter. Driver registers a timer function enic_flow_may_expire. This function is called every HZ/4 seconds. In this function we check if the added filter has expired by calling rps_may_expire_flow(). If the flow has expired, it removes the hw filter. As of now adaptor supports only IPv4 - TCP/UDP filters. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic.h | 41 ++++++ drivers/net/ethernet/cisco/enic/enic_clsf.c | 213 ++++++++++++++++++++++++++++ drivers/net/ethernet/cisco/enic/enic_clsf.h | 9 ++ drivers/net/ethernet/cisco/enic/enic_main.c | 13 ++ drivers/net/ethernet/cisco/enic/enic_res.c | 1 + drivers/net/ethernet/cisco/enic/vnic_enet.h | 2 + 6 files changed, 279 insertions(+) diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index 14f465f239d6..b9b9178e174e 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -99,6 +99,44 @@ struct enic_port_profile { u8 mac_addr[ETH_ALEN]; }; +#ifdef CONFIG_RFS_ACCEL +/* enic_rfs_fltr_node - rfs filter node in hash table + * @@keys: IPv4 5 tuple + * @flow_id: flow_id of clsf filter provided by kernel + * @fltr_id: filter id of clsf filter returned by adaptor + * @rq_id: desired rq index + * @node: hlist_node + */ +struct enic_rfs_fltr_node { + struct flow_keys keys; + u32 flow_id; + u16 fltr_id; + u16 rq_id; + struct hlist_node node; +}; + +/* enic_rfs_flw_tbl - rfs flow table + * @max: Maximum number of filters vNIC supports + * @free: Number of free filters available + * @toclean: hash table index to clean next + * @ht_head: hash table list head + * @lock: spin lock + * @rfs_may_expire: timer function for enic_rps_may_expire_flow + */ +struct enic_rfs_flw_tbl { + u16 max; + int free; + +#define ENIC_RFS_FLW_BITSHIFT (10) +#define ENIC_RFS_FLW_MASK ((1 << ENIC_RFS_FLW_BITSHIFT) - 1) + u16 toclean:ENIC_RFS_FLW_BITSHIFT; + struct hlist_head ht_head[1 << ENIC_RFS_FLW_BITSHIFT]; + spinlock_t lock; + struct timer_list rfs_may_expire; +}; + +#endif /* CONFIG_RFS_ACCEL */ + /* Per-instance private data structure */ struct enic { struct net_device *netdev; @@ -150,6 +188,9 @@ struct enic { /* completion queue cache line section */ ____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX]; unsigned int cq_count; +#ifdef CONFIG_RFS_ACCEL + struct enic_rfs_flw_tbl rfs_h; +#endif }; static inline struct device *enic_get_dev(struct enic *enic) diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index f6703c4f76a9..7f27a4c7fbfd 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -64,3 +64,216 @@ int enic_delfltr(struct enic *enic, u16 filter_id) return ret; } + +#ifdef CONFIG_RFS_ACCEL +void enic_flow_may_expire(unsigned long data) +{ + struct enic *enic = (struct enic *)data; + bool res; + int j; + + spin_lock(&enic->rfs_h.lock); + for (j = 0; j < ENIC_CLSF_EXPIRE_COUNT; j++) { + struct hlist_head *hhead; + struct hlist_node *tmp; + struct enic_rfs_fltr_node *n; + + hhead = &enic->rfs_h.ht_head[enic->rfs_h.toclean++]; + hlist_for_each_entry_safe(n, tmp, hhead, node) { + res = rps_may_expire_flow(enic->netdev, n->rq_id, + n->flow_id, n->fltr_id); + if (res) { + res = enic_delfltr(enic, n->fltr_id); + if (unlikely(res)) + continue; + hlist_del(&n->node); + kfree(n); + enic->rfs_h.free++; + } + } + } + spin_unlock(&enic->rfs_h.lock); + mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4); +} + +/* enic_rfs_flw_tbl_init - initialize enic->rfs_h members + * @enic: enic data + */ +void enic_rfs_flw_tbl_init(struct enic *enic) +{ + int i; + + spin_lock_init(&enic->rfs_h.lock); + for (i = 0; i <= ENIC_RFS_FLW_MASK; i++) + INIT_HLIST_HEAD(&enic->rfs_h.ht_head[i]); + enic->rfs_h.max = enic->config.num_arfs; + enic->rfs_h.free = enic->rfs_h.max; + enic->rfs_h.toclean = 0; + init_timer(&enic->rfs_h.rfs_may_expire); + enic->rfs_h.rfs_may_expire.function = enic_flow_may_expire; + enic->rfs_h.rfs_may_expire.data = (unsigned long)enic; + mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4); +} + +void enic_rfs_flw_tbl_free(struct enic *enic) +{ + int i, res; + + del_timer_sync(&enic->rfs_h.rfs_may_expire); + spin_lock(&enic->rfs_h.lock); + enic->rfs_h.free = 0; + for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) { + struct hlist_head *hhead; + struct hlist_node *tmp; + struct enic_rfs_fltr_node *n; + + hhead = &enic->rfs_h.ht_head[i]; + hlist_for_each_entry_safe(n, tmp, hhead, node) { + enic_delfltr(enic, n->fltr_id); + hlist_del(&n->node); + kfree(n); + } + } + spin_unlock(&enic->rfs_h.lock); +} + +static struct enic_rfs_fltr_node *htbl_key_search(struct hlist_head *h, + struct flow_keys *k) +{ + struct enic_rfs_fltr_node *tpos; + + hlist_for_each_entry(tpos, h, node) + if (tpos->keys.src == k->src && + tpos->keys.dst == k->dst && + tpos->keys.ports == k->ports && + tpos->keys.ip_proto == k->ip_proto && + tpos->keys.n_proto == k->n_proto) + return tpos; + return NULL; +} + +int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, + u16 rxq_index, u32 flow_id) +{ + struct flow_keys keys; + struct enic_rfs_fltr_node *n; + struct enic *enic; + u16 tbl_idx; + int res, i; + + enic = netdev_priv(dev); + res = skb_flow_dissect(skb, &keys); + if (!res || keys.n_proto != htons(ETH_P_IP) || + (keys.ip_proto != IPPROTO_TCP && keys.ip_proto != IPPROTO_UDP)) + return -EPROTONOSUPPORT; + + tbl_idx = skb_get_hash_raw(skb) & ENIC_RFS_FLW_MASK; + spin_lock(&enic->rfs_h.lock); + n = htbl_key_search(&enic->rfs_h.ht_head[tbl_idx], &keys); + + if (n) { /* entry already present */ + if (rxq_index == n->rq_id) { + res = -EEXIST; + goto ret_unlock; + } + + /* desired rq changed for the flow, we need to delete + * old fltr and add new one + * + * The moment we delete the fltr, the upcoming pkts + * are put it default rq based on rss. When we add + * new filter, upcoming pkts are put in desired queue. + * This could cause ooo pkts. + * + * Lets 1st try adding new fltr and then del old one. + */ + i = --enic->rfs_h.free; + /* clsf tbl is full, we have to del old fltr first*/ + if (unlikely(i < 0)) { + enic->rfs_h.free++; + res = enic_delfltr(enic, n->fltr_id); + if (unlikely(res < 0)) + goto ret_unlock; + res = enic_addfltr_5t(enic, &keys, rxq_index); + if (res < 0) { + hlist_del(&n->node); + enic->rfs_h.free++; + goto ret_unlock; + } + /* add new fltr 1st then del old fltr */ + } else { + int ret; + + res = enic_addfltr_5t(enic, &keys, rxq_index); + if (res < 0) { + enic->rfs_h.free++; + goto ret_unlock; + } + ret = enic_delfltr(enic, n->fltr_id); + /* deleting old fltr failed. Add old fltr to list. + * enic_flow_may_expire() will try to delete it later. + */ + if (unlikely(ret < 0)) { + struct enic_rfs_fltr_node *d; + struct hlist_head *head; + + head = &enic->rfs_h.ht_head[tbl_idx]; + d = kmalloc(sizeof(*d), GFP_ATOMIC); + if (d) { + d->fltr_id = n->fltr_id; + INIT_HLIST_NODE(&d->node); + hlist_add_head(&d->node, head); + } + } else { + enic->rfs_h.free++; + } + } + n->rq_id = rxq_index; + n->fltr_id = res; + n->flow_id = flow_id; + /* entry not present */ + } else { + i = --enic->rfs_h.free; + if (i <= 0) { + enic->rfs_h.free++; + res = -EBUSY; + goto ret_unlock; + } + + n = kmalloc(sizeof(*n), GFP_ATOMIC); + if (!n) { + res = -ENOMEM; + enic->rfs_h.free++; + goto ret_unlock; + } + + res = enic_addfltr_5t(enic, &keys, rxq_index); + if (res < 0) { + kfree(n); + enic->rfs_h.free++; + goto ret_unlock; + } + n->rq_id = rxq_index; + n->fltr_id = res; + n->flow_id = flow_id; + n->keys = keys; + INIT_HLIST_NODE(&n->node); + hlist_add_head(&n->node, &enic->rfs_h.ht_head[tbl_idx]); + } + +ret_unlock: + spin_unlock(&enic->rfs_h.lock); + return res; +} + +#else + +void enic_rfs_flw_tbl_init(struct enic *enic) +{ +} + +void enic_rfs_flw_tbl_free(struct enic *enic) +{ +} + +#endif /* CONFIG_RFS_ACCEL */ diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.h b/drivers/net/ethernet/cisco/enic/enic_clsf.h index b6925b368b77..76a85bb0bb73 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.h +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.h @@ -4,7 +4,16 @@ #include "vnic_dev.h" #include "enic.h" +#define ENIC_CLSF_EXPIRE_COUNT 128 + int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq); int enic_delfltr(struct enic *enic, u16 filter_id); +#ifdef CONFIG_RFS_ACCEL +void enic_rfs_flw_tbl_init(struct enic *enic); +void enic_rfs_flw_tbl_free(struct enic *enic); +int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, + u16 rxq_index, u32 flow_id); +#endif /* CONFIG_RFS_ACCEL */ + #endif /* _ENIC_CLSF_H_ */ diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 151b375337a9..a302f1b3e8ff 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -52,6 +52,7 @@ #include "enic.h" #include "enic_dev.h" #include "enic_pp.h" +#include "enic_clsf.h" #define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ) #define WQ_ENET_MAX_DESC_LEN (1 << WQ_ENET_LEN_BITS) @@ -1546,6 +1547,7 @@ static int enic_open(struct net_device *netdev) vnic_intr_unmask(&enic->intr[i]); enic_notify_timer_start(enic); + enic_rfs_flw_tbl_init(enic); return 0; @@ -1572,6 +1574,7 @@ static int enic_stop(struct net_device *netdev) enic_synchronize_irqs(enic); del_timer_sync(&enic->notify_timer); + enic_rfs_flw_tbl_free(enic); enic_dev_disable(enic); @@ -2064,6 +2067,9 @@ static const struct net_device_ops enic_netdev_dynamic_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = enic_poll_controller, #endif +#ifdef CONFIG_RFS_ACCEL + .ndo_rx_flow_steer = enic_rx_flow_steer, +#endif }; static const struct net_device_ops enic_netdev_ops = { @@ -2084,6 +2090,9 @@ static const struct net_device_ops enic_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = enic_poll_controller, #endif +#ifdef CONFIG_RFS_ACCEL + .ndo_rx_flow_steer = enic_rx_flow_steer, +#endif }; static void enic_dev_deinit(struct enic *enic) @@ -2429,6 +2438,10 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->features |= netdev->hw_features; +#ifdef CONFIG_RFS_ACCEL + netdev->hw_features |= NETIF_F_NTUPLE; +#endif + if (using_dac) netdev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/ethernet/cisco/enic/enic_res.c b/drivers/net/ethernet/cisco/enic/enic_res.c index 31d658880c3c..9c96911fb2c8 100644 --- a/drivers/net/ethernet/cisco/enic/enic_res.c +++ b/drivers/net/ethernet/cisco/enic/enic_res.c @@ -71,6 +71,7 @@ int enic_get_vnic_config(struct enic *enic) GET_CONFIG(intr_mode); GET_CONFIG(intr_timer_usec); GET_CONFIG(loop_tag); + GET_CONFIG(num_arfs); c->wq_desc_count = min_t(u32, ENIC_MAX_WQ_DESCS, diff --git a/drivers/net/ethernet/cisco/enic/vnic_enet.h b/drivers/net/ethernet/cisco/enic/vnic_enet.h index 609542848e02..75aced2de869 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_enet.h +++ b/drivers/net/ethernet/cisco/enic/vnic_enet.h @@ -32,6 +32,8 @@ struct vnic_enet_config { char devname[16]; u32 intr_timer_usec; u16 loop_tag; + u16 vf_rq_count; + u16 num_arfs; }; #define VENETF_TSO 0x1 /* TSO enabled */ -- cgit v1.2.3 From 8e091340cfcd6f96ca0dddb078ce28c407a6d44c Mon Sep 17 00:00:00 2001 From: Tony Camuso Date: Mon, 23 Jun 2014 16:08:03 +0530 Subject: enic: fix lockdep around devcmd_lock We were experiencing occasional "BUG: scheduling while atomic" splats in our testing. Enabling DEBUG_SPINLOCK and DEBUG_LOCKDEP in the kernel exposed a lockdep in the enic driver. enic 0000:0b:00.0 eth2: Link UP ====================================================== [ INFO: SOFTIRQ-safe -> SOFTIRQ-unsafe lock order detected ] 3.12.0-rc1.x86_64-dbg+ #2 Tainted: GF W ------------------------------------------------------ NetworkManager/4209 [HC0[0]:SC0[2]:HE1:SE0] is trying to acquire: (&(&enic->devcmd_lock)->rlock){+.+...}, at: [] enic_dev_packet_filter+0x44/0x90 [enic] The fix was to replace spin_lock with spin_lock_bh for the enic devcmd_lock, so that soft irqs would be disabled while the lock is held. Signed-off-by: Sujith Sankar Signed-off-by: Tony Camuso Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_api.c | 4 +- drivers/net/ethernet/cisco/enic/enic_dev.c | 80 ++++++++++++++--------------- drivers/net/ethernet/cisco/enic/enic_dev.h | 4 +- drivers/net/ethernet/cisco/enic/enic_main.c | 16 +++--- 4 files changed, 52 insertions(+), 52 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_api.c b/drivers/net/ethernet/cisco/enic/enic_api.c index e13efbdaa2ed..b161f24522b8 100644 --- a/drivers/net/ethernet/cisco/enic/enic_api.c +++ b/drivers/net/ethernet/cisco/enic/enic_api.c @@ -34,13 +34,13 @@ int enic_api_devcmd_proxy_by_index(struct net_device *netdev, int vf, struct vnic_dev *vdev = enic->vdev; spin_lock(&enic->enic_api_lock); - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); vnic_dev_cmd_proxy_by_index_start(vdev, vf); err = vnic_dev_cmd(vdev, cmd, a0, a1, wait); vnic_dev_cmd_proxy_end(vdev); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); spin_unlock(&enic->enic_api_lock); return err; diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.c b/drivers/net/ethernet/cisco/enic/enic_dev.c index 3e27df522847..87ddc44b590e 100644 --- a/drivers/net/ethernet/cisco/enic/enic_dev.c +++ b/drivers/net/ethernet/cisco/enic/enic_dev.c @@ -29,9 +29,9 @@ int enic_dev_fw_info(struct enic *enic, struct vnic_devcmd_fw_info **fw_info) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_fw_info(enic->vdev, fw_info); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -40,9 +40,9 @@ int enic_dev_stats_dump(struct enic *enic, struct vnic_stats **vstats) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_stats_dump(enic->vdev, vstats); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -54,9 +54,9 @@ int enic_dev_add_station_addr(struct enic *enic) if (!is_valid_ether_addr(enic->netdev->dev_addr)) return -EADDRNOTAVAIL; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_add_addr(enic->vdev, enic->netdev->dev_addr); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -68,9 +68,9 @@ int enic_dev_del_station_addr(struct enic *enic) if (!is_valid_ether_addr(enic->netdev->dev_addr)) return -EADDRNOTAVAIL; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_del_addr(enic->vdev, enic->netdev->dev_addr); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -80,10 +80,10 @@ int enic_dev_packet_filter(struct enic *enic, int directed, int multicast, { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_packet_filter(enic->vdev, directed, multicast, broadcast, promisc, allmulti); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -92,9 +92,9 @@ int enic_dev_add_addr(struct enic *enic, const u8 *addr) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_add_addr(enic->vdev, addr); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -103,9 +103,9 @@ int enic_dev_del_addr(struct enic *enic, const u8 *addr) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_del_addr(enic->vdev, addr); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -114,9 +114,9 @@ int enic_dev_notify_unset(struct enic *enic) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_notify_unset(enic->vdev); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -125,9 +125,9 @@ int enic_dev_hang_notify(struct enic *enic) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_hang_notify(enic->vdev); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -136,10 +136,10 @@ int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_set_ig_vlan_rewrite_mode(enic->vdev, IG_VLAN_REWRITE_MODE_PRIORITY_TAG_DEFAULT_VLAN); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -148,9 +148,9 @@ int enic_dev_enable(struct enic *enic) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_enable_wait(enic->vdev); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -159,9 +159,9 @@ int enic_dev_disable(struct enic *enic) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_disable(enic->vdev); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -170,9 +170,9 @@ int enic_dev_intr_coal_timer_info(struct enic *enic) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_intr_coal_timer_info(enic->vdev); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -181,9 +181,9 @@ int enic_vnic_dev_deinit(struct enic *enic) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_deinit(enic->vdev); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -192,10 +192,10 @@ int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_init_prov2(enic->vdev, (u8 *)vp, vic_provinfo_size(vp)); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -204,9 +204,9 @@ int enic_dev_deinit_done(struct enic *enic, int *status) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_deinit_done(enic->vdev, status); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -217,9 +217,9 @@ int enic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid) struct enic *enic = netdev_priv(netdev); int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = enic_add_vlan(enic, vid); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -230,9 +230,9 @@ int enic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) struct enic *enic = netdev_priv(netdev); int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = enic_del_vlan(enic, vid); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -241,9 +241,9 @@ int enic_dev_enable2(struct enic *enic, int active) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_enable2(enic->vdev, active); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -252,9 +252,9 @@ int enic_dev_enable2_done(struct enic *enic, int *status) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = vnic_dev_enable2_done(enic->vdev, status); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.h b/drivers/net/ethernet/cisco/enic/enic_dev.h index 36ea1ab25f6a..10bb970b2f35 100644 --- a/drivers/net/ethernet/cisco/enic/enic_dev.h +++ b/drivers/net/ethernet/cisco/enic/enic_dev.h @@ -28,7 +28,7 @@ */ #define ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnicdevcmdfn, ...) \ do { \ - spin_lock(&enic->devcmd_lock); \ + spin_lock_bh(&enic->devcmd_lock); \ if (enic_is_valid_vf(enic, vf)) { \ vnic_dev_cmd_proxy_by_index_start(enic->vdev, vf); \ err = vnicdevcmdfn(enic->vdev, ##__VA_ARGS__); \ @@ -36,7 +36,7 @@ } else { \ err = vnicdevcmdfn(enic->vdev, ##__VA_ARGS__); \ } \ - spin_unlock(&enic->devcmd_lock); \ + spin_unlock_bh(&enic->devcmd_lock); \ } while (0) int enic_dev_fw_info(struct enic *enic, struct vnic_devcmd_fw_info **fw_info); diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index a302f1b3e8ff..5448df2d78c2 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1465,7 +1465,7 @@ static int enic_dev_notify_set(struct enic *enic) { int err; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); switch (vnic_dev_get_intr_mode(enic->vdev)) { case VNIC_DEV_INTR_MODE_INTX: err = vnic_dev_notify_set(enic->vdev, @@ -1479,7 +1479,7 @@ static int enic_dev_notify_set(struct enic *enic) err = vnic_dev_notify_set(enic->vdev, -1 /* no intr */); break; } - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } @@ -1804,11 +1804,11 @@ static int enic_set_rsskey(struct enic *enic) memcpy(rss_key_buf_va, &rss_key, sizeof(union vnic_rss_key)); - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = enic_set_rss_key(enic, rss_key_buf_pa, sizeof(union vnic_rss_key)); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); pci_free_consistent(enic->pdev, sizeof(union vnic_rss_key), rss_key_buf_va, rss_key_buf_pa); @@ -1831,11 +1831,11 @@ static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits) for (i = 0; i < (1 << rss_hash_bits); i++) (*rss_cpu_buf_va).cpu[i/4].b[i%4] = i % enic->rq_count; - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = enic_set_rss_cpu(enic, rss_cpu_buf_pa, sizeof(union vnic_rss_cpu)); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); pci_free_consistent(enic->pdev, sizeof(union vnic_rss_cpu), rss_cpu_buf_va, rss_cpu_buf_pa); @@ -1853,13 +1853,13 @@ static int enic_set_niccfg(struct enic *enic, u8 rss_default_cpu, /* Enable VLAN tag stripping. */ - spin_lock(&enic->devcmd_lock); + spin_lock_bh(&enic->devcmd_lock); err = enic_set_nic_cfg(enic, rss_default_cpu, rss_hash_type, rss_hash_bits, rss_base_cpu, rss_enable, tso_ipid_split_en, ig_vlan_strip_en); - spin_unlock(&enic->devcmd_lock); + spin_unlock_bh(&enic->devcmd_lock); return err; } -- cgit v1.2.3 From 14747cd977195a8aae13d0b1ad021e33c8786afe Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Mon, 23 Jun 2014 16:08:04 +0530 Subject: enic: add low latency socket busy_poll support This patch adds support for low latency busy_poll. * Introduce drivers ndo_busy_poll function enic_busy_poll, which is called by socket waiting for data. * Introduce locking between napi_poll nad busy_poll * enic_busy_poll cleans up all the rx pkts possible. While in busy_poll, rq holds the state ENIC_POLL_STATE_POLL. While in napi_poll, rq holds the state ENIC_POLL_STATE_NAPI. * in napi_poll we return if we are in busy_poll. Incase of INTx & msix, we just service wq and return if busy_poll is going on. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_main.c | 85 ++++++++++++++++--- drivers/net/ethernet/cisco/enic/vnic_rq.h | 122 ++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 5448df2d78c2..d4918eef5050 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -42,6 +42,9 @@ #ifdef CONFIG_RFS_ACCEL #include #endif +#ifdef CONFIG_NET_RX_BUSY_POLL +#include +#endif #include "cq_enet_desc.h" #include "vnic_dev.h" @@ -1053,10 +1056,12 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, if (vlan_stripped) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); - if (netdev->features & NETIF_F_GRO) - napi_gro_receive(&enic->napi[q_number], skb); - else + skb_mark_napi_id(skb, &enic->napi[rq->index]); + if (enic_poll_busy_polling(rq) || + !(netdev->features & NETIF_F_GRO)) netif_receive_skb(skb); + else + napi_gro_receive(&enic->napi[q_number], skb); if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) enic_intr_update_pkt_size(&cq->pkt_size_counter, bytes_written); @@ -1093,16 +1098,22 @@ static int enic_poll(struct napi_struct *napi, int budget) unsigned int work_done, rq_work_done = 0, wq_work_done; int err; - /* Service RQ (first) and WQ - */ + wq_work_done = vnic_cq_service(&enic->cq[cq_wq], wq_work_to_do, + enic_wq_service, NULL); + + if (!enic_poll_lock_napi(&enic->rq[cq_rq])) { + if (wq_work_done > 0) + vnic_intr_return_credits(&enic->intr[intr], + wq_work_done, + 0 /* dont unmask intr */, + 0 /* dont reset intr timer */); + return rq_work_done; + } if (budget > 0) rq_work_done = vnic_cq_service(&enic->cq[cq_rq], rq_work_to_do, enic_rq_service, NULL); - wq_work_done = vnic_cq_service(&enic->cq[cq_wq], - wq_work_to_do, enic_wq_service, NULL); - /* Accumulate intr event credits for this polling * cycle. An intr event is the completion of a * a WQ or RQ packet. @@ -1134,6 +1145,7 @@ static int enic_poll(struct napi_struct *napi, int budget) napi_complete(napi); vnic_intr_unmask(&enic->intr[intr]); } + enic_poll_unlock_napi(&enic->rq[cq_rq]); return rq_work_done; } @@ -1234,6 +1246,34 @@ static void enic_set_rx_cpu_rmap(struct enic *enic) #endif /* CONFIG_RFS_ACCEL */ +#ifdef CONFIG_NET_RX_BUSY_POLL +int enic_busy_poll(struct napi_struct *napi) +{ + struct net_device *netdev = napi->dev; + struct enic *enic = netdev_priv(netdev); + unsigned int rq = (napi - &enic->napi[0]); + unsigned int cq = enic_cq_rq(enic, rq); + unsigned int intr = enic_msix_rq_intr(enic, rq); + unsigned int work_to_do = -1; /* clean all pkts possible */ + unsigned int work_done; + + if (!enic_poll_lock_poll(&enic->rq[rq])) + return LL_FLUSH_BUSY; + work_done = vnic_cq_service(&enic->cq[cq], work_to_do, + enic_rq_service, NULL); + + if (work_done > 0) + vnic_intr_return_credits(&enic->intr[intr], + work_done, 0, 0); + vnic_rq_fill(&enic->rq[rq], enic_rq_alloc_buf); + if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) + enic_calc_int_moderation(enic, &enic->rq[rq]); + enic_poll_unlock_poll(&enic->rq[rq]); + + return work_done; +} +#endif /* CONFIG_NET_RX_BUSY_POLL */ + static int enic_poll_msix(struct napi_struct *napi, int budget) { struct net_device *netdev = napi->dev; @@ -1245,6 +1285,8 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) unsigned int work_done = 0; int err; + if (!enic_poll_lock_napi(&enic->rq[rq])) + return work_done; /* Service RQ */ @@ -1290,6 +1332,7 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) enic_set_int_moderation(enic, &enic->rq[rq]); vnic_intr_unmask(&enic->intr[intr]); } + enic_poll_unlock_napi(&enic->rq[rq]); return work_done; } @@ -1538,8 +1581,10 @@ static int enic_open(struct net_device *netdev) netif_tx_wake_all_queues(netdev); - for (i = 0; i < enic->rq_count; i++) + for (i = 0; i < enic->rq_count; i++) { + enic_busy_poll_init_lock(&enic->rq[i]); napi_enable(&enic->napi[i]); + } enic_dev_enable(enic); @@ -1578,8 +1623,13 @@ static int enic_stop(struct net_device *netdev) enic_dev_disable(enic); - for (i = 0; i < enic->rq_count; i++) + local_bh_disable(); + for (i = 0; i < enic->rq_count; i++) { napi_disable(&enic->napi[i]); + while (!enic_poll_lock_napi(&enic->rq[i])) + mdelay(1); + } + local_bh_enable(); netif_carrier_off(netdev); netif_tx_disable(netdev); @@ -2070,6 +2120,9 @@ static const struct net_device_ops enic_netdev_dynamic_ops = { #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = enic_rx_flow_steer, #endif +#ifdef CONFIG_NET_RX_BUSY_POLL + .ndo_busy_poll = enic_busy_poll, +#endif }; static const struct net_device_ops enic_netdev_ops = { @@ -2093,14 +2146,19 @@ static const struct net_device_ops enic_netdev_ops = { #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = enic_rx_flow_steer, #endif +#ifdef CONFIG_NET_RX_BUSY_POLL + .ndo_busy_poll = enic_busy_poll, +#endif }; static void enic_dev_deinit(struct enic *enic) { unsigned int i; - for (i = 0; i < enic->rq_count; i++) + for (i = 0; i < enic->rq_count; i++) { + napi_hash_del(&enic->napi[i]); netif_napi_del(&enic->napi[i]); + } enic_free_vnic_resources(enic); enic_clear_intr_mode(enic); @@ -2166,11 +2224,14 @@ static int enic_dev_init(struct enic *enic) switch (vnic_dev_get_intr_mode(enic->vdev)) { default: netif_napi_add(netdev, &enic->napi[0], enic_poll, 64); + napi_hash_add(&enic->napi[0]); break; case VNIC_DEV_INTR_MODE_MSIX: - for (i = 0; i < enic->rq_count; i++) + for (i = 0; i < enic->rq_count; i++) { netif_napi_add(netdev, &enic->napi[i], enic_poll_msix, 64); + napi_hash_add(&enic->napi[i]); + } break; } diff --git a/drivers/net/ethernet/cisco/enic/vnic_rq.h b/drivers/net/ethernet/cisco/enic/vnic_rq.h index ee7bc95af278..8111d5202df2 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_rq.h +++ b/drivers/net/ethernet/cisco/enic/vnic_rq.h @@ -85,6 +85,21 @@ struct vnic_rq { struct vnic_rq_buf *to_clean; void *os_buf_head; unsigned int pkts_outstanding; +#ifdef CONFIG_NET_RX_BUSY_POLL +#define ENIC_POLL_STATE_IDLE 0 +#define ENIC_POLL_STATE_NAPI (1 << 0) /* NAPI owns this poll */ +#define ENIC_POLL_STATE_POLL (1 << 1) /* poll owns this poll */ +#define ENIC_POLL_STATE_NAPI_YIELD (1 << 2) /* NAPI yielded this poll */ +#define ENIC_POLL_STATE_POLL_YIELD (1 << 3) /* poll yielded this poll */ +#define ENIC_POLL_YIELD (ENIC_POLL_STATE_NAPI_YIELD | \ + ENIC_POLL_STATE_POLL_YIELD) +#define ENIC_POLL_LOCKED (ENIC_POLL_STATE_NAPI | \ + ENIC_POLL_STATE_POLL) +#define ENIC_POLL_USER_PEND (ENIC_POLL_STATE_POLL | \ + ENIC_POLL_STATE_POLL_YIELD) + unsigned int bpoll_state; + spinlock_t bpoll_lock; +#endif /* CONFIG_NET_RX_BUSY_POLL */ }; static inline unsigned int vnic_rq_desc_avail(struct vnic_rq *rq) @@ -197,6 +212,113 @@ static inline int vnic_rq_fill(struct vnic_rq *rq, return 0; } +#ifdef CONFIG_NET_RX_BUSY_POLL +static inline void enic_busy_poll_init_lock(struct vnic_rq *rq) +{ + spin_lock_init(&rq->bpoll_lock); + rq->bpoll_state = ENIC_POLL_STATE_IDLE; +} + +static inline bool enic_poll_lock_napi(struct vnic_rq *rq) +{ + bool rc = true; + + spin_lock(&rq->bpoll_lock); + if (rq->bpoll_state & ENIC_POLL_LOCKED) { + WARN_ON(rq->bpoll_state & ENIC_POLL_STATE_NAPI); + rq->bpoll_state |= ENIC_POLL_STATE_NAPI_YIELD; + rc = false; + } else { + rq->bpoll_state = ENIC_POLL_STATE_NAPI; + } + spin_unlock(&rq->bpoll_lock); + + return rc; +} + +static inline bool enic_poll_unlock_napi(struct vnic_rq *rq) +{ + bool rc = false; + + spin_lock(&rq->bpoll_lock); + WARN_ON(rq->bpoll_state & + (ENIC_POLL_STATE_POLL | ENIC_POLL_STATE_NAPI_YIELD)); + if (rq->bpoll_state & ENIC_POLL_STATE_POLL_YIELD) + rc = true; + rq->bpoll_state = ENIC_POLL_STATE_IDLE; + spin_unlock(&rq->bpoll_lock); + + return rc; +} + +static inline bool enic_poll_lock_poll(struct vnic_rq *rq) +{ + bool rc = true; + + spin_lock_bh(&rq->bpoll_lock); + if (rq->bpoll_state & ENIC_POLL_LOCKED) { + rq->bpoll_state |= ENIC_POLL_STATE_POLL_YIELD; + rc = false; + } else { + rq->bpoll_state |= ENIC_POLL_STATE_POLL; + } + spin_unlock_bh(&rq->bpoll_lock); + + return rc; +} + +static inline bool enic_poll_unlock_poll(struct vnic_rq *rq) +{ + bool rc = false; + + spin_lock_bh(&rq->bpoll_lock); + WARN_ON(rq->bpoll_state & ENIC_POLL_STATE_NAPI); + if (rq->bpoll_state & ENIC_POLL_STATE_POLL_YIELD) + rc = true; + rq->bpoll_state = ENIC_POLL_STATE_IDLE; + spin_unlock_bh(&rq->bpoll_lock); + + return rc; +} + +static inline bool enic_poll_busy_polling(struct vnic_rq *rq) +{ + WARN_ON(!(rq->bpoll_state & ENIC_POLL_LOCKED)); + return rq->bpoll_state & ENIC_POLL_USER_PEND; +} + +#else + +static inline void enic_busy_poll_init_lock(struct vnic_rq *rq) +{ +} + +static inline bool enic_poll_lock_napi(struct vnic_rq *rq) +{ + return true; +} + +static inline bool enic_poll_unlock_napi(struct vnic_rq *rq) +{ + return false; +} + +static inline bool enic_poll_lock_poll(struct vnic_rq *rq) +{ + return false; +} + +static inline bool enic_poll_unlock_poll(struct vnic_rq *rq) +{ + return false; +} + +static inline bool enic_poll_ll_polling(struct vnic_rq *rq) +{ + return false; +} +#endif /* CONFIG_NET_RX_BUSY_POLL */ + void vnic_rq_free(struct vnic_rq *rq); int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index, unsigned int desc_count, unsigned int desc_size); -- cgit v1.2.3 From 4cfe878537cec0e9c0f84b93cc6aa9526f6942b5 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Mon, 23 Jun 2014 16:08:05 +0530 Subject: enic: do tx cleanup in napi poll Till now enic had been doing tx clean in isr. Using napi infrastructure to move the tx clean up out of isr to softirq. Now, wq isr schedules napi poll. In enic_poll_msix_wq we clean up the tx queus. This is applicable only on MSIX. In INTx and MSI we use single napi to clean both rx & tx queues. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic.h | 2 +- drivers/net/ethernet/cisco/enic/enic_main.c | 88 +++++++++++++++++------------ 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index b9b9178e174e..c8aa9fb81d3c 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -178,7 +178,7 @@ struct enic { unsigned int rq_count; u64 rq_truncated_pkts; u64 rq_bad_fcs; - struct napi_struct napi[ENIC_RQ_MAX]; + struct napi_struct napi[ENIC_RQ_MAX + ENIC_WQ_MAX]; /* interrupt resource cache line section */ ____cacheline_aligned struct vnic_intr intr[ENIC_INTR_MAX]; diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index d4918eef5050..9348febc0743 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -316,40 +316,15 @@ static irqreturn_t enic_isr_msi(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t enic_isr_msix_rq(int irq, void *data) +static irqreturn_t enic_isr_msix(int irq, void *data) { struct napi_struct *napi = data; - /* schedule NAPI polling for RQ cleanup */ napi_schedule(napi); return IRQ_HANDLED; } -static irqreturn_t enic_isr_msix_wq(int irq, void *data) -{ - struct enic *enic = data; - unsigned int cq; - unsigned int intr; - unsigned int wq_work_to_do = -1; /* no limit */ - unsigned int wq_work_done; - unsigned int wq_irq; - - wq_irq = (u32)irq - enic->msix_entry[enic_msix_wq_intr(enic, 0)].vector; - cq = enic_cq_wq(enic, wq_irq); - intr = enic_msix_wq_intr(enic, wq_irq); - - wq_work_done = vnic_cq_service(&enic->cq[cq], - wq_work_to_do, enic_wq_service, NULL); - - vnic_intr_return_credits(&enic->intr[intr], - wq_work_done, - 1 /* unmask intr */, - 1 /* reset intr timer */); - - return IRQ_HANDLED; -} - static irqreturn_t enic_isr_msix_err(int irq, void *data) { struct enic *enic = data; @@ -1274,7 +1249,36 @@ int enic_busy_poll(struct napi_struct *napi) } #endif /* CONFIG_NET_RX_BUSY_POLL */ -static int enic_poll_msix(struct napi_struct *napi, int budget) +static int enic_poll_msix_wq(struct napi_struct *napi, int budget) +{ + struct net_device *netdev = napi->dev; + struct enic *enic = netdev_priv(netdev); + unsigned int wq_index = (napi - &enic->napi[0]) - enic->rq_count; + struct vnic_wq *wq = &enic->wq[wq_index]; + unsigned int cq; + unsigned int intr; + unsigned int wq_work_to_do = -1; /* clean all desc possible */ + unsigned int wq_work_done; + unsigned int wq_irq; + + wq_irq = wq->index; + cq = enic_cq_wq(enic, wq_irq); + intr = enic_msix_wq_intr(enic, wq_irq); + wq_work_done = vnic_cq_service(&enic->cq[cq], wq_work_to_do, + enic_wq_service, NULL); + + vnic_intr_return_credits(&enic->intr[intr], wq_work_done, + 0 /* don't unmask intr */, + 1 /* reset intr timer */); + if (!wq_work_done) { + napi_complete(napi); + vnic_intr_unmask(&enic->intr[intr]); + } + + return 0; +} + +static int enic_poll_msix_rq(struct napi_struct *napi, int budget) { struct net_device *netdev = napi->dev; struct enic *enic = netdev_priv(netdev); @@ -1399,17 +1403,19 @@ static int enic_request_intr(struct enic *enic) snprintf(enic->msix[intr].devname, sizeof(enic->msix[intr].devname), "%.11s-rx-%d", netdev->name, i); - enic->msix[intr].isr = enic_isr_msix_rq; + enic->msix[intr].isr = enic_isr_msix; enic->msix[intr].devid = &enic->napi[i]; } for (i = 0; i < enic->wq_count; i++) { + int wq = enic_cq_wq(enic, i); + intr = enic_msix_wq_intr(enic, i); snprintf(enic->msix[intr].devname, sizeof(enic->msix[intr].devname), "%.11s-tx-%d", netdev->name, i); - enic->msix[intr].isr = enic_isr_msix_wq; - enic->msix[intr].devid = enic; + enic->msix[intr].isr = enic_isr_msix; + enic->msix[intr].devid = &enic->napi[wq]; } intr = enic_msix_err_intr(enic); @@ -1585,7 +1591,9 @@ static int enic_open(struct net_device *netdev) enic_busy_poll_init_lock(&enic->rq[i]); napi_enable(&enic->napi[i]); } - + if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) + for (i = 0; i < enic->wq_count; i++) + napi_enable(&enic->napi[enic_cq_wq(enic, i)]); enic_dev_enable(enic); for (i = 0; i < enic->intr_count; i++) @@ -1633,6 +1641,9 @@ static int enic_stop(struct net_device *netdev) netif_carrier_off(netdev); netif_tx_disable(netdev); + if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) + for (i = 0; i < enic->wq_count; i++) + napi_disable(&enic->napi[enic_cq_wq(enic, i)]); if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic)) enic_dev_del_station_addr(enic); @@ -1752,13 +1763,14 @@ static void enic_poll_controller(struct net_device *netdev) case VNIC_DEV_INTR_MODE_MSIX: for (i = 0; i < enic->rq_count; i++) { intr = enic_msix_rq_intr(enic, i); - enic_isr_msix_rq(enic->msix_entry[intr].vector, - &enic->napi[i]); + enic_isr_msix(enic->msix_entry[intr].vector, + &enic->napi[i]); } for (i = 0; i < enic->wq_count; i++) { intr = enic_msix_wq_intr(enic, i); - enic_isr_msix_wq(enic->msix_entry[intr].vector, enic); + enic_isr_msix(enic->msix_entry[intr].vector, + &enic->napi[enic_cq_wq(enic, i)]); } break; @@ -2159,6 +2171,9 @@ static void enic_dev_deinit(struct enic *enic) napi_hash_del(&enic->napi[i]); netif_napi_del(&enic->napi[i]); } + if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) + for (i = 0; i < enic->wq_count; i++) + netif_napi_del(&enic->napi[enic_cq_wq(enic, i)]); enic_free_vnic_resources(enic); enic_clear_intr_mode(enic); @@ -2229,9 +2244,12 @@ static int enic_dev_init(struct enic *enic) case VNIC_DEV_INTR_MODE_MSIX: for (i = 0; i < enic->rq_count; i++) { netif_napi_add(netdev, &enic->napi[i], - enic_poll_msix, 64); + enic_poll_msix_rq, NAPI_POLL_WEIGHT); napi_hash_add(&enic->napi[i]); } + for (i = 0; i < enic->wq_count; i++) + netif_napi_add(netdev, &enic->napi[enic_cq_wq(enic, i)], + enic_poll_msix_wq, NAPI_POLL_WEIGHT); break; } -- cgit v1.2.3 From f2769af94c908c6eae9a6dc5810e2fa6a5ac151e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 23 Jun 2014 14:46:29 -0700 Subject: enic: Kill unused variable in enic_rfs_flw_tbl_init(). Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_clsf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index 7f27a4c7fbfd..c2322adfccdc 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -117,7 +117,7 @@ void enic_rfs_flw_tbl_init(struct enic *enic) void enic_rfs_flw_tbl_free(struct enic *enic) { - int i, res; + int i; del_timer_sync(&enic->rfs_h.rfs_may_expire); spin_lock(&enic->rfs_h.lock); -- cgit v1.2.3 From 79631c89ed70643fd0579a65834b227795b251ee Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 20 Jun 2014 21:48:00 +0200 Subject: trivial: net/irda/irlmp.c: Fix closing brace followed by if Signed-off-by: Rasmus Villemoes Signed-off-by: David S. Miller --- net/irda/irlmp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c index 98ad6ec4bd3c..a5f28d421ea8 100644 --- a/net/irda/irlmp.c +++ b/net/irda/irlmp.c @@ -1426,7 +1426,8 @@ __u8 *irlmp_hint_to_service(__u8 *hint) if (hint[1] & HINT_TELEPHONY) { IRDA_DEBUG(1, "Telephony "); service[i++] = S_TELEPHONY; - } if (hint[1] & HINT_FILE_SERVER) + } + if (hint[1] & HINT_FILE_SERVER) IRDA_DEBUG(1, "File Server "); if (hint[1] & HINT_COMM) { -- cgit v1.2.3 From 14ca0f389c11f9e845a3e10a834c6412af279ccd Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 24 Jun 2014 14:12:43 +0300 Subject: iwlwifi: bump API version for 8000 devices Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 51c41531d81d..0a1bb5f564ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -67,7 +67,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 8 +#define IWL8000_UCODE_API_MAX 9 /* Oldest version we won't warn about */ #define IWL8000_UCODE_API_OK 8 -- cgit v1.2.3 From 0564679bb6e750dc6d441f6d67e95c0590fa3f80 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Mon, 2 Jun 2014 09:59:49 +0300 Subject: iwlwifi: mvm: use ksize to memset scan_command Use ksize to get scan command size instead of calculating it, to avoid nasty bugs. Signed-off-by: David Spinadel Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 4b6c7d4bd199..df8f3ebea84a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -325,9 +325,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, IWL_DEBUG_SCAN(mvm, "Handling mac80211 scan request\n"); mvm->scan_status = IWL_MVM_SCAN_OS; - memset(cmd, 0, sizeof(struct iwl_scan_cmd) + - mvm->fw->ucode_capa.max_probe_length + - (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel))); + memset(cmd, 0, ksize(cmd)); cmd->channel_count = (u8)req->n_channels; cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME); -- cgit v1.2.3 From ab4800303299e9a3b844e8256bf3c8fd9f095060 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jun 2014 10:13:50 +0200 Subject: iwlwifi: mvm: add back support for low-priority scan The low-priority scan feature can be useful, e.g. for OBSS scans (if those are required by the AP); add back support for it, restoring the maximum out time to the value it was for low-priority scan before that was removed. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 1 + drivers/net/wireless/iwlwifi/mvm/scan.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 7215f5980186..41c0aace3e84 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -374,6 +374,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->max_sched_scan_ie_len = SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2; hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | + NL80211_FEATURE_LOW_PRIORITY_SCAN | NL80211_FEATURE_P2P_GO_OPPPS; mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index df8f3ebea84a..896c21d4fc7c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -267,7 +267,7 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - int n_ssids, + int n_ssids, u32 flags, struct iwl_mvm_scan_params *params) { bool global_bound = false; @@ -289,6 +289,9 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, params->max_out_time = 250; } + if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY) + params->max_out_time = 200; + not_bound: for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { @@ -332,7 +335,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH); cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm); - iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, ¶ms); + iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, req->flags, ¶ms); cmd->max_out_time = cpu_to_le32(params.max_out_time); cmd->suspend_time = cpu_to_le32(params.suspend_time); if (params.passive_fragmented) @@ -758,7 +761,7 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, if (!scan_cfg) return -ENOMEM; - iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, ¶ms); + iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, ¶ms); iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, ¶ms); scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len); -- cgit v1.2.3 From 762533ba9c0306b97e8587fdcafc500a3d7115ae Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Thu, 5 Jun 2014 11:20:43 +0300 Subject: iwlwifi: mvm: don't use hardcoded num of scan channels Use num of scan channels as advertised by fw TLV. Signed-off-by: David Spinadel Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 9 +++++ drivers/net/wireless/iwlwifi/iwl-fw-file.h | 1 + drivers/net/wireless/iwlwifi/iwl-fw.h | 1 + drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 47 ++++++++------------------ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 +- drivers/net/wireless/iwlwifi/mvm/ops.c | 3 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 43 ++++++++++++++--------- 7 files changed, 56 insertions(+), 51 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index f2a5c12269a3..bf584d3fe8ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -155,6 +155,8 @@ static struct iwlwifi_opmode_table { [MVM_OP_MODE] = { .name = "iwlmvm", .ops = NULL }, }; +#define IWL_DEFAULT_SCAN_CHANNELS 40 + /* * struct fw_sec: Just for the image parsing proccess. * For the fw storage we are using struct fw_desc. @@ -819,6 +821,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, if (iwl_store_cscheme(&drv->fw, tlv_data, tlv_len)) goto invalid_tlv_len; break; + case IWL_UCODE_TLV_N_SCAN_CHANNELS: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + capa->n_scan_channels = + le32_to_cpup((__le32 *)tlv_data); + break; default: IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); break; @@ -973,6 +981,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH; fw->ucode_capa.standard_phy_calibration_size = IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; + fw->ucode_capa.n_scan_channels = IWL_DEFAULT_SCAN_CHANNELS; if (!api_ok) api_ok = api_max; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index b45e576a4b57..9e6ba1e7fd21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -128,6 +128,7 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_CSCHEME = 28, IWL_UCODE_TLV_API_CHANGES_SET = 29, IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, + IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, }; struct iwl_ucode_tlv { diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 0aa7c0085c9f..de975cd4d73a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -178,6 +178,7 @@ enum iwl_ucode_sec { struct iwl_ucode_capabilities { u32 max_probe_length; + u32 n_scan_channels; u32 standard_phy_calibration_size; u32 flags; u32 api[IWL_API_ARRAY_SIZE]; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 6959fda3fe09..1d586923d5b7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -169,19 +169,13 @@ enum iwl_scan_type { SCAN_TYPE_DISCOVERY_FORCED = 6, }; /* SCAN_ACTIVITY_TYPE_E_VER_1 */ -/** - * Maximal number of channels to scan - * it should be equal to: - * max(IWL_NUM_CHANNELS, IWL_NUM_CHANNELS_FAMILY_8000) - */ -#define MAX_NUM_SCAN_CHANNELS 50 - /** * struct iwl_scan_cmd - scan request command * ( SCAN_REQUEST_CMD = 0x80 ) * @len: command length in bytes * @scan_flags: scan flags from SCAN_FLAGS_* - * @channel_count: num of channels in channel list (1 - MAX_NUM_SCAN_CHANNELS) + * @channel_count: num of channels in channel list + * (1 - ucode_capa.n_scan_channels) * @quiet_time: in msecs, dwell this time for active scan on quiet channels * @quiet_plcp_th: quiet PLCP threshold (channel is quiet if less than * this number of packets were received (typically 1) @@ -345,7 +339,7 @@ struct iwl_scan_results_notif { * @last_channel: last channel that was scanned * @tsf_low: TSF timer (lower half) in usecs * @tsf_high: TSF timer (higher half) in usecs - * @results: all scan results, only "scanned_channels" of them are valid + * @results: array of scan results, only "scanned_channels" of them are valid */ struct iwl_scan_complete_notif { u8 scanned_channels; @@ -354,11 +348,10 @@ struct iwl_scan_complete_notif { u8 last_channel; __le32 tsf_low; __le32 tsf_high; - struct iwl_scan_results_notif results[MAX_NUM_SCAN_CHANNELS]; + struct iwl_scan_results_notif results[]; } __packed; /* SCAN_COMPLETE_NTF_API_S_VER_2 */ /* scan offload */ -#define IWL_MAX_SCAN_CHANNELS 40 #define IWL_SCAN_MAX_BLACKLIST_LEN 64 #define IWL_SCAN_SHORT_BLACKLIST_LEN 16 #define IWL_SCAN_MAX_PROFILES 11 @@ -423,36 +416,24 @@ enum iwl_scan_offload_channel_flags { IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL = BIT(25), }; -/** - * iwl_scan_channel_cfg - SCAN_CHANNEL_CFG_S - * @type: bitmap - see enum iwl_scan_offload_channel_flags. - * 0: passive (0) or active (1) scan. - * 1-20: directed scan to i'th ssid. - * 22: channel width configuation - 1 for narrow. - * 24: full scan. - * 25: partial scan. - * @channel_number: channel number 1-13 etc. - * @iter_count: repetition count for the channel. - * @iter_interval: interval between two innteration on one channel. - * @dwell_time: entry 0 - active scan, entry 1 - passive scan. +/* channel configuration for struct iwl_scan_offload_cfg. Each channels needs: + * __le32 type: bitmap; bits 1-20 are for directed scan to i'th ssid and + * see enum iwl_scan_offload_channel_flags. + * __le16 channel_number: channel number 1-13 etc. + * __le16 iter_count: repetition count for the channel. + * __le32 iter_interval: interval between two innteration on one channel. + * u8 active_dwell. + * u8 passive_dwell. */ -struct iwl_scan_channel_cfg { - __le32 type[IWL_MAX_SCAN_CHANNELS]; - __le16 channel_number[IWL_MAX_SCAN_CHANNELS]; - __le16 iter_count[IWL_MAX_SCAN_CHANNELS]; - __le32 iter_interval[IWL_MAX_SCAN_CHANNELS]; - u8 dwell_time[IWL_MAX_SCAN_CHANNELS][2]; -} __packed; +#define IWL_SCAN_CHAN_SIZE 14 /** * iwl_scan_offload_cfg - SCAN_OFFLOAD_CONFIG_API_S * @scan_cmd: scan command fixed part - * @channel_cfg: scan channel configuration - * @data: probe request frames (one per band) + * @data: scan channel configuration and probe request frames */ struct iwl_scan_offload_cfg { struct iwl_scan_offload_cmd scan_cmd; - struct iwl_scan_channel_cfg channel_cfg; u8 data[0]; } __packed; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 41c0aace3e84..f22be88c0387 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1543,7 +1543,8 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; - if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS) + if (req->n_channels == 0 || + req->n_channels > mvm->fw->ucode_capa.n_scan_channels) return -EINVAL; mutex_lock(&mvm->mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index cc2f7de396de..a46f0289a3c1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -504,7 +504,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, scan_size = sizeof(struct iwl_scan_cmd) + mvm->fw->ucode_capa.max_probe_length + - (MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel)); + (mvm->fw->ucode_capa.n_scan_channels * + sizeof(struct iwl_scan_channel)); mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); if (!mvm->scan_cmd) goto out_free; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 40c112f136dc..349d8e67118b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -666,12 +666,19 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req, static void iwl_build_channel_cfg(struct iwl_mvm *mvm, struct cfg80211_sched_scan_request *req, - struct iwl_scan_channel_cfg *channels, + u8 *channels_buffer, enum ieee80211_band band, int *head, u32 ssid_bitmap, struct iwl_mvm_scan_params *params) { + u32 n_channels = mvm->fw->ucode_capa.n_scan_channels; + __le32 *type = (__le32 *)channels_buffer; + __le16 *channel_number = (__le16 *)(type + n_channels); + __le16 *iter_count = channel_number + n_channels; + __le32 *iter_interval = (__le32 *)(iter_count + n_channels); + u8 *active_dwell = (u8 *)(iter_interval + n_channels); + u8 *passive_dwell = active_dwell + n_channels; int i, index = 0; for (i = 0; i < req->n_channels; i++) { @@ -683,27 +690,26 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm, index = *head; (*head)++; - channels->channel_number[index] = cpu_to_le16(chan->hw_value); - channels->dwell_time[index][0] = params->dwell[band].active; - channels->dwell_time[index][1] = params->dwell[band].passive; + channel_number[index] = cpu_to_le16(chan->hw_value); + active_dwell[index] = params->dwell[band].active; + passive_dwell[index] = params->dwell[band].passive; - channels->iter_count[index] = cpu_to_le16(1); - channels->iter_interval[index] = 0; + iter_count[index] = cpu_to_le16(1); + iter_interval[index] = 0; if (!(chan->flags & IEEE80211_CHAN_NO_IR)) - channels->type[index] |= + type[index] |= cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE); - channels->type[index] |= - cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_FULL | - IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL); + type[index] |= cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_FULL | + IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL); if (chan->flags & IEEE80211_CHAN_NO_HT40) - channels->type[index] |= + type[index] |= cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_NARROW); /* scan for all SSIDs from req->ssids */ - channels->type[index] |= cpu_to_le32(ssid_bitmap); + type[index] |= cpu_to_le32(ssid_bitmap); } } @@ -718,6 +724,7 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, u32 ssid_bitmap; int cmd_len; int ret; + u8 *probes; struct iwl_scan_offload_cfg *scan_cfg; struct iwl_host_cmd cmd = { @@ -728,12 +735,16 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); cmd_len = sizeof(struct iwl_scan_offload_cfg) + + mvm->fw->ucode_capa.n_scan_channels * IWL_SCAN_CHAN_SIZE + 2 * SCAN_OFFLOAD_PROBE_REQ_SIZE; scan_cfg = kzalloc(cmd_len, GFP_KERNEL); if (!scan_cfg) return -ENOMEM; + probes = scan_cfg->data + + mvm->fw->ucode_capa.n_scan_channels * IWL_SCAN_CHAN_SIZE; + iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, ¶ms); iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, ¶ms); scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len); @@ -744,8 +755,8 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, iwl_scan_offload_build_tx_cmd(mvm, vif, ies, IEEE80211_BAND_2GHZ, &scan_cfg->scan_cmd.tx_cmd[0], - scan_cfg->data); - iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg, + probes); + iwl_build_channel_cfg(mvm, req, scan_cfg->data, IEEE80211_BAND_2GHZ, &head, ssid_bitmap, ¶ms); } @@ -753,9 +764,9 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, iwl_scan_offload_build_tx_cmd(mvm, vif, ies, IEEE80211_BAND_5GHZ, &scan_cfg->scan_cmd.tx_cmd[1], - scan_cfg->data + + probes + SCAN_OFFLOAD_PROBE_REQ_SIZE); - iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg, + iwl_build_channel_cfg(mvm, req, scan_cfg->data, IEEE80211_BAND_5GHZ, &head, ssid_bitmap, ¶ms); } -- cgit v1.2.3 From 5788ab75eccd5783889ad848282a160e5dd365cb Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 15 Jun 2014 10:40:48 +0300 Subject: iwlwifi: remove MCS32 support declaration MCS32 is currently not supported, so don't declare support for it. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index c44cf1149648..07ff7e0028ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c @@ -779,7 +779,6 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, if (cfg->ht_params->ht40_bands & BIT(band)) { ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; ht_info->cap |= IEEE80211_HT_CAP_SGI_40; - ht_info->mcs.rx_mask[4] = 0x01; max_bit_rate = MAX_BIT_RATE_40_MHZ; } -- cgit v1.2.3 From 06ddbf5adac1fd2a031eade8a92239abfa6db93a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 2 Jun 2014 08:34:53 +0300 Subject: iwlwifi: add device / firmware to fw-error-dump file This can be useful later for parsing since the parsing may differ based on the device's family / bus. Also add the human readable version of the firmware. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 24 ++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-fw-file.h | 5 +++-- drivers/net/wireless/iwlwifi/iwl-fw.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/ops.c | 24 +++++++++++++++++++++--- 5 files changed, 53 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index bf584d3fe8ec..01a426871ffb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -567,6 +567,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, } drv->fw.ucode_ver = le32_to_cpu(ucode->ver); + memcpy(drv->fw.human_readable, ucode->human_readable, + sizeof(drv->fw.human_readable)); build = le32_to_cpu(ucode->build); if (build) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index 2953ffceda38..aa0f85ee65b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -74,12 +74,15 @@ * @IWL_FW_ERROR_DUMP_RXF: * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as * &struct iwl_fw_error_dump_txcmd packets + * @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info + * info on the device / firmware. */ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_SRAM = 0, IWL_FW_ERROR_DUMP_REG = 1, IWL_FW_ERROR_DUMP_RXF = 2, IWL_FW_ERROR_DUMP_TXCMD = 3, + IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, IWL_FW_ERROR_DUMP_MAX, }; @@ -120,6 +123,27 @@ struct iwl_fw_error_dump_txcmd { u8 data[]; } __packed; +enum iwl_fw_error_dump_family { + IWL_FW_ERROR_DUMP_FAMILY_7 = 7, + IWL_FW_ERROR_DUMP_FAMILY_8 = 8, +}; + +/** + * struct iwl_fw_error_dump_info - info on the device / firmware + * @device_family: the family of the device (7 / 8) + * @hw_step: the step of the device + * @fw_human_readable: human readable FW version + * @dev_human_readable: name of the device + * @bus_human_readable: name of the bus used + */ +struct iwl_fw_error_dump_info { + __le32 device_family; + __le32 hw_step; + u8 fw_human_readable[FW_VER_HUMAN_READABLE_SZ]; + u8 dev_human_readable[64]; + u8 bus_human_readable[8]; +} __packed; + /** * iwl_mvm_fw_error_next_data - advance fw error dump data pointer * @data: previous data block diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 9e6ba1e7fd21..929a8063354c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -137,7 +137,8 @@ struct iwl_ucode_tlv { u8 data[0]; }; -#define IWL_TLV_UCODE_MAGIC 0x0a4c5749 +#define IWL_TLV_UCODE_MAGIC 0x0a4c5749 +#define FW_VER_HUMAN_READABLE_SZ 64 struct iwl_tlv_ucode_header { /* @@ -148,7 +149,7 @@ struct iwl_tlv_ucode_header { */ __le32 zero; __le32 magic; - u8 human_readable[64]; + u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; __le32 ver; /* major/minor/API/serial */ __le32 build; __le64 ignore; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index de975cd4d73a..287b949c95f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -65,6 +65,8 @@ #include #include +#include "iwl-fw-file.h" + /** * enum iwl_ucode_tlv_flag - ucode API flags * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously @@ -312,6 +314,7 @@ struct iwl_fw { bool mvm_fw; struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; + u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; }; #endif /* __iwl_fw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index a46f0289a3c1..3ab33e296686 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -827,6 +827,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) { struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; + struct iwl_fw_error_dump_info *dump_info; u32 file_len; u32 trans_len; @@ -835,10 +836,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) if (mvm->fw_error_dump) return; - file_len = mvm->fw_error_sram_len + + file_len = sizeof(*dump_file) + + sizeof(*dump_data) * 3 + + mvm->fw_error_sram_len + mvm->fw_error_rxf_len + - sizeof(*dump_file) + - sizeof(*dump_data) * 2; + sizeof(*dump_info); trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0); if (trans_len) @@ -853,6 +855,22 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); dump_file->file_len = cpu_to_le32(file_len); dump_data = (void *)dump_file->data; + + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); + dump_data->len = cpu_to_le32(sizeof(*dump_info)); + dump_info = (void *) dump_data->data; + dump_info->device_family = + mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? + cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) : + cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8); + memcpy(dump_info->fw_human_readable, mvm->fw->human_readable, + sizeof(dump_info->fw_human_readable)); + strncpy(dump_info->dev_human_readable, mvm->cfg->name, + sizeof(dump_info->dev_human_readable)); + strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, + sizeof(dump_info->bus_human_readable)); + + dump_data = iwl_mvm_fw_error_next_data(dump_data); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len); memcpy(dump_data->data, mvm->fw_error_rxf, mvm->fw_error_rxf_len); -- cgit v1.2.3 From 1fa1605648d15d42f350807279b6c6e8d33b6382 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 5 Jun 2014 13:50:31 +0300 Subject: iwlwifi: rename iwl_mvm_fw_error_next_data This is not related to mvm. Rename to iwl_fw_error_next_data. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 4 ++-- drivers/net/wireless/iwlwifi/mvm/ops.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index aa0f85ee65b5..3584a75833fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -145,12 +145,12 @@ struct iwl_fw_error_dump_info { } __packed; /** - * iwl_mvm_fw_error_next_data - advance fw error dump data pointer + * iwl_fw_error_next_data - advance fw error dump data pointer * @data: previous data block * Returns: next data block */ static inline struct iwl_fw_error_dump_data * -iwl_mvm_fw_error_next_data(struct iwl_fw_error_dump_data *data) +iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data) { return (void *)(data->data + le32_to_cpu(data->len)); } diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 3ab33e296686..7bb763f3052b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -870,12 +870,12 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, sizeof(dump_info->bus_human_readable)); - dump_data = iwl_mvm_fw_error_next_data(dump_data); + dump_data = iwl_fw_error_next_data(dump_data); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len); memcpy(dump_data->data, mvm->fw_error_rxf, mvm->fw_error_rxf_len); - dump_data = iwl_mvm_fw_error_next_data(dump_data); + dump_data = iwl_fw_error_next_data(dump_data); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); dump_data->len = cpu_to_le32(mvm->fw_error_sram_len); @@ -895,7 +895,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) mvm->fw_error_sram_len = 0; if (trans_len) { - void *buf = iwl_mvm_fw_error_next_data(dump_data); + void *buf = iwl_fw_error_next_data(dump_data); u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, trans_len); dump_data = (void *)((u8 *)buf + real_trans_len); -- cgit v1.2.3 From c2d202017da18ebd6567862bd9a50392970f048f Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 1 Jun 2014 08:05:52 +0300 Subject: iwlwifi: pcie: add firmware monitor capabilities This allows to use the firmware monitor. This capability uses a lot of contiguous memory (up to 64MB), so make its usage module parameter dependent. The driver will try to allocate as much contiguous memory as possible downgrading its requirements until the allocation succeeds. Dump this data into the fw-error dump file when an error happens. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 4 + drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 18 ++++ drivers/net/wireless/iwlwifi/iwl-modparams.h | 2 + drivers/net/wireless/iwlwifi/iwl-prph.h | 6 ++ drivers/net/wireless/iwlwifi/pcie/internal.h | 7 ++ drivers/net/wireless/iwlwifi/pcie/trans.c | 125 ++++++++++++++++++++++- 6 files changed, 158 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 01a426871ffb..bb842f4732dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1405,3 +1405,7 @@ module_param_named(power_level, iwlwifi_mod_params.power_level, int, S_IRUGO); MODULE_PARM_DESC(power_level, "default power save level (range from 1 - 5, default: 1)"); + +module_param_named(fw_monitor, iwlwifi_mod_params.fw_monitor, bool, S_IRUGO); +MODULE_PARM_DESC(dbgm, + "firmware monitor - to debug FW (default: false - needs lots of memory)"); diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index 3584a75833fe..ced5ba95c23d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -76,6 +76,7 @@ * &struct iwl_fw_error_dump_txcmd packets * @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info * info on the device / firmware. + * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor */ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_SRAM = 0, @@ -83,6 +84,7 @@ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_RXF = 2, IWL_FW_ERROR_DUMP_TXCMD = 3, IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, + IWL_FW_ERROR_DUMP_FW_MONITOR = 5, IWL_FW_ERROR_DUMP_MAX, }; @@ -144,6 +146,22 @@ struct iwl_fw_error_dump_info { u8 bus_human_readable[8]; } __packed; +/** + * struct iwl_fw_error_fw_mon - FW monitor data + * @fw_mon_wr_ptr: the position of the write pointer in the cyclic buffer + * @fw_mon_base_ptr: base pointer of the data + * @fw_mon_cycle_cnt: number of wrap arounds + * @reserved: for future use + * @data: captured data + */ +struct iwl_fw_error_fw_mon { + __le32 fw_mon_wr_ptr; + __le32 fw_mon_base_ptr; + __le32 fw_mon_cycle_cnt; + __le32 reserved[3]; + u8 data[]; +} __packed; + /** * iwl_fw_error_next_data - advance fw error dump data pointer * @data: previous data block diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index d051857729ab..f2d39cb011fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -103,6 +103,7 @@ enum iwl_disable_11n { * @power_level: power level, default = 1 * @debug_level: levels are IWL_DL_* * @ant_coupling: antenna coupling in dB, default = 0 + * @fw_monitor: allow to use firmware monitor */ struct iwl_mod_params { int sw_crypto; @@ -120,6 +121,7 @@ struct iwl_mod_params { int ant_coupling; char *nvm_file; bool uapsd_disable; + bool fw_monitor; }; #endif /* #__iwl_modparams_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 4997e27672b3..47033a35a402 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -359,4 +359,10 @@ enum secure_load_status_reg { #define RXF_LD_FENCE_OFFSET_ADDR (0xa00c10) #define RXF_FIFO_RD_FENCE_ADDR (0xa00c0c) +/* FW monitor */ +#define MON_BUFF_BASE_ADDR (0xa03c3c) +#define MON_BUFF_END_ADDR (0xa03c40) +#define MON_BUFF_WRPTR (0xa03c44) +#define MON_BUFF_CYCLE_CNT (0xa03c48) + #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 6c22b23a2845..78f72c34438a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -260,6 +260,9 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @wd_timeout: queue watchdog timeout (jiffies) * @reg_lock: protect hw register access * @cmd_in_flight: true when we have a host command in flight + * @fw_mon_phys: physical address of the buffer for the firmware monitor + * @fw_mon_page: points to the first page of the buffer for the firmware monitor + * @fw_mon_size: size of the buffer for the firmware monitor */ struct iwl_trans_pcie { struct iwl_rxq rxq; @@ -312,6 +315,10 @@ struct iwl_trans_pcie { /*protect hw register */ spinlock_t reg_lock; bool cmd_in_flight; + + dma_addr_t fw_mon_phys; + struct page *fw_mon_page; + u32 fw_mon_size; }; #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 788085bc65d7..3ffac4888c12 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -76,6 +76,68 @@ #include "iwl-fw-error-dump.h" #include "internal.h" +static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + if (!trans_pcie->fw_mon_page) + return; + + dma_unmap_page(trans->dev, trans_pcie->fw_mon_phys, + trans_pcie->fw_mon_size, DMA_FROM_DEVICE); + __free_pages(trans_pcie->fw_mon_page, + get_order(trans_pcie->fw_mon_size)); + trans_pcie->fw_mon_page = NULL; + trans_pcie->fw_mon_phys = 0; + trans_pcie->fw_mon_size = 0; +} + +static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct page *page; + dma_addr_t phys; + u32 size; + u8 power; + + if (trans_pcie->fw_mon_page) { + dma_sync_single_for_device(trans->dev, trans_pcie->fw_mon_phys, + trans_pcie->fw_mon_size, + DMA_FROM_DEVICE); + return; + } + + phys = 0; + for (power = 26; power >= 11; power--) { + int order; + + size = BIT(power); + order = get_order(size); + page = alloc_pages(__GFP_COMP | __GFP_NOWARN | __GFP_ZERO, + order); + if (!page) + continue; + + phys = dma_map_page(trans->dev, page, 0, PAGE_SIZE << order, + DMA_FROM_DEVICE); + if (dma_mapping_error(trans->dev, phys)) { + __free_pages(page, order); + continue; + } + IWL_INFO(trans, + "Allocated 0x%08x bytes (order %d) for firmware monitor.\n", + size, order); + break; + } + + if (!page) + return; + + trans_pcie->fw_mon_page = page; + trans_pcie->fw_mon_phys = phys; + trans_pcie->fw_mon_size = size; +} + static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg) { iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, @@ -675,6 +737,7 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, const struct fw_img *image) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret = 0; int first_ucode_section; @@ -733,6 +796,20 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, return ret; } + /* supported for 7000 only for the moment */ + if (iwlwifi_mod_params.fw_monitor && + trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { + iwl_pcie_alloc_fw_monitor(trans); + + if (trans_pcie->fw_mon_size) { + iwl_write_prph(trans, MON_BUFF_BASE_ADDR, + trans_pcie->fw_mon_phys >> 4); + iwl_write_prph(trans, MON_BUFF_END_ADDR, + (trans_pcie->fw_mon_phys + + trans_pcie->fw_mon_size) >> 4); + } + } + /* release CPU reset */ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); @@ -1126,6 +1203,8 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) if (trans_pcie->napi.poll) netif_napi_del(&trans_pcie->napi); + iwl_pcie_free_fw_monitor(trans); + kfree(trans); } @@ -1698,10 +1777,15 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, u32 len; int i, ptr; + len = sizeof(*data) + + cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); + + if (trans_pcie->fw_mon_page) + len += sizeof(*data) + sizeof(struct iwl_fw_error_fw_mon) + + trans_pcie->fw_mon_size; + if (!buf) - return sizeof(*data) + - cmdq->q.n_window * (sizeof(*txcmd) + - TFD_MAX_PAYLOAD_SIZE); + return len; len = 0; data = buf; @@ -1729,7 +1813,40 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, spin_unlock_bh(&cmdq->lock); data->len = cpu_to_le32(len); - return sizeof(*data) + len; + len += sizeof(*data); + + if (trans_pcie->fw_mon_page) { + struct iwl_fw_error_fw_mon *fw_mon_data; + + data = iwl_fw_error_next_data(data); + data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); + data->len = cpu_to_le32(trans_pcie->fw_mon_size + + sizeof(*fw_mon_data)); + fw_mon_data = (void *)data->data; + fw_mon_data->fw_mon_wr_ptr = + cpu_to_le32(iwl_read_prph(trans, MON_BUFF_WRPTR)); + fw_mon_data->fw_mon_cycle_cnt = + cpu_to_le32(iwl_read_prph(trans, MON_BUFF_CYCLE_CNT)); + fw_mon_data->fw_mon_base_ptr = + cpu_to_le32(iwl_read_prph(trans, MON_BUFF_BASE_ADDR)); + + /* + * The firmware is now asserted, it won't write anything to + * the buffer. CPU can take ownership to fetch the data. + * The buffer will be handed back to the device before the + * firmware will be restarted. + */ + dma_sync_single_for_cpu(trans->dev, trans_pcie->fw_mon_phys, + trans_pcie->fw_mon_size, + DMA_FROM_DEVICE); + memcpy(fw_mon_data->data, page_address(trans_pcie->fw_mon_page), + trans_pcie->fw_mon_size); + + len += sizeof(*data) + sizeof(*fw_mon_data) + + trans_pcie->fw_mon_size; + } + + return len; } #else static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, -- cgit v1.2.3 From 52ab4c86a7ebbdce4e1f227acfc7b39352ad2967 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Sun, 1 Jun 2014 14:55:21 +0300 Subject: iwlwifi: mvm: fixes for 8000 NVM flow The nvm_file should be loaded by default for SDIO procucts only. Change the configuration accordingly. While at it, fix a typo in the device name. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 3 +-- drivers/net/wireless/iwlwifi/iwl-config.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 0a1bb5f564ba..51486cc9d943 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -119,10 +119,9 @@ const struct iwl_cfg iwl8260_2ac_cfg = { .ht_params = &iwl8000_ht_params, .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, - .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, }; -const struct iwl_cfg iwl8260_n_cfg = { +const struct iwl_cfg iwl8260_2ac_sdio_cfg = { .name = "Intel(R) Dual Band Wireless-AC 8260", .fw_name_pre = IWL8000_FW_PRE, IWL_DEVICE_8000, diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index b7047905f41a..034c2fc4b69f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -337,7 +337,7 @@ extern const struct iwl_cfg iwl7265_2ac_cfg; extern const struct iwl_cfg iwl7265_2n_cfg; extern const struct iwl_cfg iwl7265_n_cfg; extern const struct iwl_cfg iwl8260_2ac_cfg; -extern const struct iwl_cfg iwl8260_n_cfg; +extern const struct iwl_cfg iwl8260_2ac_sdio_cfg; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ -- cgit v1.2.3 From 9ee6dace73029fc88767f33b13d52b60d5861f21 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Wed, 29 May 2013 11:37:28 +0300 Subject: iwlwifi: fix NVM channel attribute map. Fix NVM channel attributes. Add indoor-only and GO Concurrent bits. Remove DFS channel bit which is overlapped with radar. Signed-off-by: David Spinadel Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 85eee79c495c..0e3322a136c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -174,7 +174,9 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = { * @NVM_CHANNEL_IBSS: usable as an IBSS channel * @NVM_CHANNEL_ACTIVE: active scanning allowed * @NVM_CHANNEL_RADAR: radar detection required - * @NVM_CHANNEL_DFS: dynamic freq selection candidate + * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed + * @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS + * on same channel on 2.4 or same UNII band on 5.2 * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?) * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?) * @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?) @@ -185,7 +187,8 @@ enum iwl_nvm_channel_flags { NVM_CHANNEL_IBSS = BIT(1), NVM_CHANNEL_ACTIVE = BIT(3), NVM_CHANNEL_RADAR = BIT(4), - NVM_CHANNEL_DFS = BIT(7), + NVM_CHANNEL_INDOOR_ONLY = BIT(5), + NVM_CHANNEL_GO_CONCURRENT = BIT(6), NVM_CHANNEL_WIDE = BIT(8), NVM_CHANNEL_40MHZ = BIT(9), NVM_CHANNEL_80MHZ = BIT(10), @@ -273,6 +276,16 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, if (ch_flags & NVM_CHANNEL_RADAR) channel->flags |= IEEE80211_CHAN_RADAR; + if (ch_flags & NVM_CHANNEL_INDOOR_ONLY) + channel->flags |= IEEE80211_CHAN_INDOOR_ONLY; + + /* Set the GO concurrent flag only in case that NO_IR is set. + * Otherwise it is meaningless + */ + if ((ch_flags & NVM_CHANNEL_GO_CONCURRENT) && + (channel->flags & IEEE80211_CHAN_NO_IR)) + channel->flags |= IEEE80211_CHAN_GO_CONCURRENT; + /* Initialize regulatory-based run-time data */ /* @@ -282,7 +295,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, channel->max_power = DEFAULT_MAX_TX_POWER; is_5ghz = channel->band == IEEE80211_BAND_5GHZ; IWL_DEBUG_EEPROM(dev, - "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", + "Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", channel->hw_value, is_5ghz ? "5.2" : "2.4", CHECK_AND_PRINT_I(VALID), @@ -290,7 +303,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, CHECK_AND_PRINT_I(ACTIVE), CHECK_AND_PRINT_I(RADAR), CHECK_AND_PRINT_I(WIDE), - CHECK_AND_PRINT_I(DFS), + CHECK_AND_PRINT_I(INDOOR_ONLY), + CHECK_AND_PRINT_I(GO_CONCURRENT), ch_flags, channel->max_power, ((ch_flags & NVM_CHANNEL_IBSS) && -- cgit v1.2.3 From d536c32b45d2f86c9e9e7780bd94d28d1d7c4660 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Sat, 7 Jun 2014 09:00:11 -0700 Subject: iwlwifi: pcie: log when waking the NIC for hcmd submission fails I've never seen this happen, but it's useful to rule it out. Signed-off-by: Andy Lutomirski Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/tx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 038940afbdc5..6acccb19c4f3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1438,6 +1438,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); trans_pcie->cmd_in_flight = false; + IWL_ERR(trans, "Failed to wake NIC for hcmd\n"); idx = -EIO; goto out; } -- cgit v1.2.3 From f40faf623712153a64f39d2bddad2fc5a4f5e12d Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Sat, 7 Jun 2014 09:13:44 -0700 Subject: iwlwifi: pcie: improve debugfs queue info This adds need_update and write_actual to rx_queue and need_update and an HCMD indicator to tx_queue. On my card, rx_queue now looks like: read: 181 write: 180 write_actual: 176 need_update: 0 free_count: 40 closed_rb_num: 181 tx_queue now looks like: hwq 00: read=29 write=30 use=1 stop=0 need_update=0 hwq 01: read=0 write=0 use=1 stop=0 need_update=0 hwq 02: read=128 write=128 use=1 stop=0 need_update=0 hwq 03: read=0 write=0 use=1 stop=0 need_update=0 hwq 04: read=94 write=94 use=1 stop=0 need_update=0 HCMD hwq 05: read=0 write=0 use=0 stop=0 need_update=0 hwq 06: read=0 write=0 use=0 stop=0 need_update=0 hwq 07: read=0 write=0 use=0 stop=0 need_update=0 hwq 08: read=0 write=0 use=0 stop=0 need_update=0 hwq 09: read=0 write=0 use=0 stop=0 need_update=0 hwq 10: read=0 write=0 use=0 stop=0 need_update=0 hwq 11: read=0 write=0 use=0 stop=0 need_update=0 hwq 12: read=0 write=0 use=0 stop=0 need_update=0 hwq 13: read=0 write=0 use=0 stop=0 need_update=0 hwq 14: read=0 write=0 use=0 stop=0 need_update=0 hwq 15: read=0 write=0 use=0 stop=0 need_update=0 hwq 16: read=0 write=0 use=0 stop=0 need_update=0 hwq 17: read=0 write=0 use=0 stop=0 need_update=0 hwq 18: read=0 write=0 use=0 stop=0 need_update=0 hwq 19: read=0 write=0 use=0 stop=0 need_update=0 This may help with debugging queue stalls. Signed-off-by: Andy Lutomirski Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 3ffac4888c12..0480857ee6e2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1573,10 +1573,12 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, txq = &trans_pcie->txq[cnt]; q = &txq->q; pos += scnprintf(buf + pos, bufsz - pos, - "hwq %.2d: read=%u write=%u use=%d stop=%d\n", + "hwq %.2d: read=%u write=%u use=%d stop=%d need_update=%d%s\n", cnt, q->read_ptr, q->write_ptr, !!test_bit(cnt, trans_pcie->queue_used), - !!test_bit(cnt, trans_pcie->queue_stopped)); + !!test_bit(cnt, trans_pcie->queue_stopped), + txq->need_update, + (cnt == trans_pcie->cmd_queue ? " HCMD" : "")); } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -1598,6 +1600,10 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, rxq->read); pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n", rxq->write); + pos += scnprintf(buf + pos, bufsz - pos, "write_actual: %u\n", + rxq->write_actual); + pos += scnprintf(buf + pos, bufsz - pos, "need_update: %d\n", + rxq->need_update); pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n", rxq->free_count); if (rxq->rb_stts) { -- cgit v1.2.3 From c9e38e770981ff25d203f0f5c1423a863c484446 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Sat, 7 Jun 2014 09:21:15 -0700 Subject: iwlwifi: dvm: add a force_cam module parameter to fully disable power saving iwldvm stalls are often blamed on power management. Add an option to force it all the way off. Signed-off-by: Andy Lutomirski Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/power.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/dvm/power.c b/drivers/net/wireless/iwlwifi/dvm/power.c index f2c1439566b5..760c45c34ef3 100644 --- a/drivers/net/wireless/iwlwifi/dvm/power.c +++ b/drivers/net/wireless/iwlwifi/dvm/power.c @@ -40,6 +40,10 @@ #include "commands.h" #include "power.h" +static bool force_cam; +module_param(force_cam, bool, 0644); +MODULE_PARM_DESC(force_cam, "force continuously aware mode (no power saving at all)"); + /* * Setting power level allows the card to go to sleep when not busy. * @@ -288,6 +292,11 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS; int dtimper; + if (force_cam) { + iwl_power_sleep_cam_cmd(priv, cmd); + return; + } + dtimper = priv->hw->conf.ps_dtim_period ?: 1; if (priv->wowlan) -- cgit v1.2.3 From 6a68a39fcd3af3f8ae3d185a8a2c8a82cf0363ef Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Wed, 7 May 2014 11:09:11 +0300 Subject: iwlwifi: mvm: fix bug in set_hw_address function Don't use nvm_hw pointer if it is NULL. Print an error message if the MAC address isn't valid. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 34 ++++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 0e3322a136c5..f0ae038f3339 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -476,7 +476,8 @@ static void iwl_set_hw_address(const struct iwl_cfg *cfg, data->hw_addr[5] = hw_addr[4]; } -static void iwl_set_hw_address_family_8000(const struct iwl_cfg *cfg, +static void iwl_set_hw_address_family_8000(struct device *dev, + const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const __le16 *mac_override, const __le16 *nvm_hw) @@ -495,20 +496,28 @@ static void iwl_set_hw_address_family_8000(const struct iwl_cfg *cfg, data->hw_addr[4] = hw_addr[5]; data->hw_addr[5] = hw_addr[4]; - if (is_valid_ether_addr(hw_addr)) + if (is_valid_ether_addr(data->hw_addr)) return; + + IWL_ERR_DEV(dev, + "mac address from nvm override section is not valid\n"); } - /* take the MAC address from the OTP */ - hw_addr = (const u8 *)(nvm_hw + HW_ADDR0_FAMILY_8000); - data->hw_addr[0] = hw_addr[3]; - data->hw_addr[1] = hw_addr[2]; - data->hw_addr[2] = hw_addr[1]; - data->hw_addr[3] = hw_addr[0]; + if (nvm_hw) { + /* take the MAC address from the OTP */ + hw_addr = (const u8 *)(nvm_hw + HW_ADDR0_FAMILY_8000); + data->hw_addr[0] = hw_addr[3]; + data->hw_addr[1] = hw_addr[2]; + data->hw_addr[2] = hw_addr[1]; + data->hw_addr[3] = hw_addr[0]; + + hw_addr = (const u8 *)(nvm_hw + HW_ADDR1_FAMILY_8000); + data->hw_addr[4] = hw_addr[1]; + data->hw_addr[5] = hw_addr[0]; + return; + } - hw_addr = (const u8 *)(nvm_hw + HW_ADDR1_FAMILY_8000); - data->hw_addr[4] = hw_addr[1]; - data->hw_addr[5] = hw_addr[0]; + IWL_ERR_DEV(dev, "mac address is not found\n"); } struct iwl_nvm_data * @@ -570,7 +579,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, rx_chains); } else { /* MAC address in family 8000 */ - iwl_set_hw_address_family_8000(cfg, data, mac_override, nvm_hw); + iwl_set_hw_address_family_8000(dev, cfg, data, mac_override, + nvm_hw); iwl_init_sbands(dev, cfg, data, regulatory, sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, -- cgit v1.2.3 From b513ee7fd6dd5ca6498eee99fa46c0d6c0f21c9d Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 1 Jun 2014 17:21:33 +0300 Subject: iwlwifi: update trans->hw_rev 8000 hw family format The format of the CSR_HW_REV register has changed in 8000 HW family. To keep backwards compatibility, we store the value of this register as usual in trans->hw_rev, only we store it in the old format in this variable. Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 0480857ee6e2..5703a3d7799b 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1993,6 +1993,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } trans->hw_rev = iwl_read32(trans, CSR_HW_REV); + /* + * In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have + * changed, and now the revision step also includes bit 0-1 (no more + * "dash" value). To keep hw_rev backwards compatible - we'll store it + * in the old format. + */ + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + trans->hw_rev = (trans->hw_rev & 0xfff0) | + ((trans->hw_rev << 2) & 0xc); + trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device); -- cgit v1.2.3 From f251c07c88513c02d9f815e16bcbace0e95a5fe0 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Mon, 28 Apr 2014 14:42:04 +0300 Subject: iwlwifi: nvm: update maximal parsed values in external nvm Some of the maximum values of the parsed external NVM file in the B-step of the 8000 HW family were updated, so this updates these values. Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/nvm.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 808f78f6fbf9..26ba27e3992d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -69,7 +69,9 @@ /* Default NVM size to read */ #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) -#define IWL_MAX_NVM_SECTION_SIZE 7000 +#define IWL_MAX_NVM_SECTION_SIZE 0x1b58 +#define IWL_MAX_NVM_8000A_SECTION_SIZE 0xffc +#define IWL_MAX_NVM_8000B_SECTION_SIZE 0x1ffc #define NVM_WRITE_OPCODE 1 #define NVM_READ_OPCODE 0 @@ -326,6 +328,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) u8 data[]; } *file_sec; const u8 *eof, *temp; + int max_section_size; #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) #define NVM_WORD2_ID(x) (x >> 12) @@ -334,6 +337,14 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); + /* Maximal size depends on HW family and step */ + if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + max_section_size = IWL_MAX_NVM_SECTION_SIZE; + else if ((mvm->trans->hw_rev & 0xc) == 0) /* Family 8000 A-step */ + max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE; + else /* Family 8000 B-step */ + max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE; + /* * Obtain NVM image via request_firmware. Since we already used * request_firmware_nowait() for the firmware binary load and only @@ -392,7 +403,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) le16_to_cpu(file_sec->word1)); } - if (section_size > IWL_MAX_NVM_SECTION_SIZE) { + if (section_size > max_section_size) { IWL_ERR(mvm, "ERROR - section too large (%d)\n", section_size); ret = -EINVAL; -- cgit v1.2.3 From 5daddc99024b952bb4e66452febd2175fff8d26e Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Wed, 21 May 2014 14:37:00 +0300 Subject: iwlwifi: mvm: assure no overflows occur while reading otp Just in case sizes change in the OTP without proper SW updating, an additional check is inserted when reading OTP sections to assure no overflows occur. Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/nvm.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 26ba27e3992d..1f1a550828fa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -221,7 +221,7 @@ static int iwl_nvm_write_section(struct iwl_mvm *mvm, u16 section, * without overflowing, so no check is needed. */ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section, - u8 *data) + u8 *data, u32 size_read) { u16 length, offset = 0; int ret; @@ -233,6 +233,13 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section, /* Read the NVM until exhausted (reading less than requested) */ while (ret == length) { + /* Check no memory assumptions fail and cause an overflow */ + if ((size_read + offset + length) > + mvm->cfg->base_params->eeprom_size) { + IWL_ERR(mvm, "EEPROM size is too small for NVM\n"); + return -ENOBUFS; + } + ret = iwl_nvm_read_chunk(mvm, section, offset, length, data); if (ret < 0) { IWL_DEBUG_EEPROM(mvm->trans->dev, @@ -470,6 +477,7 @@ int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm) int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) { int ret, section; + u32 size_read = 0; u8 *nvm_buffer, *temp; if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS)) @@ -486,9 +494,11 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) return -ENOMEM; for (section = 0; section < NVM_MAX_NUM_SECTIONS; section++) { /* we override the constness for initial read */ - ret = iwl_nvm_read_section(mvm, section, nvm_buffer); + ret = iwl_nvm_read_section(mvm, section, nvm_buffer, + size_read); if (ret < 0) continue; + size_read += ret; temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); if (!temp) { ret = -ENOMEM; -- cgit v1.2.3 From a39979a8c3e71eac72f43568b2535da60099b8e4 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 28 May 2014 12:06:41 +0300 Subject: iwlwifi: mvm: BT Coex - allow to force the antenna allocation This can be used for testing. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 39 ++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 39 ++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | 6 ++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 10 +++++++ 4 files changed, 94 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index c8c3b38228f0..b2003d82260a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -106,6 +106,9 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) { + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) + return 0; + return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, 0, sizeof(struct iwl_bt_coex_prio_tbl_cmd), &iwl_bt_prio_tbl); @@ -578,6 +581,29 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) return -ENOMEM; cmd.data[0] = bt_cmd; + lockdep_assert_held(&mvm->mutex); + + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) { + switch (mvm->bt_force_ant_mode) { + case BT_FORCE_ANT_AUTO: + flags = BT_COEX_AUTO; + break; + case BT_FORCE_ANT_BT: + flags = BT_COEX_BT; + break; + case BT_FORCE_ANT_WIFI: + flags = BT_COEX_WIFI; + break; + default: + WARN_ON(1); + flags = 0; + } + + bt_cmd->flags = cpu_to_le32(flags); + bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE); + goto send_cmd; + } + bt_cmd->max_kill = 5; bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD; bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling; @@ -642,6 +668,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); +send_cmd: memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); @@ -955,6 +982,10 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) struct iwl_bt_coex_ci_cmd cmd = {}; u8 ci_bw_idx; + /* Ignore updates if we are in force mode */ + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) + return; + rcu_read_lock(); ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, @@ -1121,6 +1152,10 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); + /* Ignore updates if we are in force mode */ + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) + return; + /* * Rssi update while not associated - can happen since the statistics * are handled asynchronously @@ -1274,6 +1309,10 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); + /* Ignore updates if we are in force mode */ + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) + return 0; + if (ant_isolation == mvm->last_ant_isol) return 0; diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 29ca72695eaa..602bbd29ec5a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -455,6 +455,43 @@ iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf, return count; } +static ssize_t +iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) +{ + static const char * const modes_str[BT_FORCE_ANT_MAX] = { + [BT_FORCE_ANT_DIS] = "dis", + [BT_FORCE_ANT_AUTO] = "auto", + [BT_FORCE_ANT_BT] = "bt", + [BT_FORCE_ANT_WIFI] = "wifi", + }; + int ret, bt_force_ant_mode; + + for (bt_force_ant_mode = 0; + bt_force_ant_mode < ARRAY_SIZE(modes_str); + bt_force_ant_mode++) { + if (!strcmp(buf, modes_str[bt_force_ant_mode])) + break; + } + + if (bt_force_ant_mode >= ARRAY_SIZE(modes_str)) + return -EINVAL; + + ret = 0; + mutex_lock(&mvm->mutex); + if (mvm->bt_force_ant_mode == bt_force_ant_mode) + goto out; + + mvm->bt_force_ant_mode = bt_force_ant_mode; + IWL_DEBUG_COEX(mvm, "Force mode: %s\n", + modes_str[mvm->bt_force_ant_mode]); + ret = iwl_send_bt_init_conf(mvm); + +out: + mutex_unlock(&mvm->mutex); + return ret ?: count; +} + #define PRINT_STATS_LE32(_str, _val) \ pos += scnprintf(buf + pos, bufsz - pos, \ fmt_table, _str, \ @@ -1101,6 +1138,7 @@ MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats); MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10); +MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); @@ -1142,6 +1180,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR); + MVM_DEBUGFS_ADD_FILE(bt_force_ant, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index 5fe82c29c8ad..98175ca05e9d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h @@ -76,6 +76,9 @@ * @BT_COEX_2W: * @BT_COEX_3W: * @BT_COEX_NW: + * @BT_COEX_AUTO: + * @BT_COEX_BT: Antenna is for BT (manufacuring tests) + * @BT_COEX_WIFI: Antenna is for BT (manufacuring tests) * @BT_COEX_SYNC2SCO: * @BT_COEX_CORUNNING: * @BT_COEX_MPLUT: @@ -89,6 +92,9 @@ enum iwl_bt_coex_flags { BT_COEX_2W = 0x1 << BT_COEX_MODE_POS, BT_COEX_3W = 0x2 << BT_COEX_MODE_POS, BT_COEX_NW = 0x3 << BT_COEX_MODE_POS, + BT_COEX_AUTO = 0x5 << BT_COEX_MODE_POS, + BT_COEX_BT = 0x6 << BT_COEX_MODE_POS, + BT_COEX_WIFI = 0x7 << BT_COEX_MODE_POS, BT_COEX_SYNC2SCO = BIT(7), BT_COEX_CORUNNING = BIT(8), BT_COEX_MPLUT = BIT(9), diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fcc6c29482d0..472ef09c1f5f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -235,6 +235,15 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_COUNT, }; +enum iwl_bt_force_ant_mode { + BT_FORCE_ANT_DIS = 0, + BT_FORCE_ANT_AUTO, + BT_FORCE_ANT_BT, + BT_FORCE_ANT_WIFI, + + BT_FORCE_ANT_MAX, +}; + /** * struct iwl_mvm_vif_bf_data - beacon filtering related data * @bf_enabled: indicates if beacon filtering is enabled @@ -629,6 +638,7 @@ struct iwl_mvm { u32 last_ant_isol; u8 last_corun_lut; u8 bt_tx_prio; + enum iwl_bt_force_ant_mode bt_force_ant_mode; /* Thermal Throttling and CTkill */ struct iwl_mvm_tt_mgmt thermal_throttle; -- cgit v1.2.3 From 7fa4fa0c441835ebe78aa25496ae952177e8bb84 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 25 May 2014 13:58:31 +0300 Subject: iwlwifi: mvm: BT Coex - allow MIMO in more cases We can Tx in MIMO rates when we are in TxTx Disallow mode just like we can when we are in Tight mode. Same if we are in 5Ghz regardless of the mode we are. Change the code to allow MIMO in these cases. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index b2003d82260a..aab92a6b2f35 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -538,7 +538,7 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) if (!chanctx_conf || chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) { rcu_read_unlock(); - return BT_COEX_LOOSE_LUT; + return BT_COEX_INVALID_LUT; } ret = BT_COEX_TX_DIS_LUT; @@ -1214,7 +1214,7 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, lut_type = iwl_get_coex_type(mvm, mvmsta->vif); - if (lut_type == BT_COEX_LOOSE_LUT) + if (lut_type == BT_COEX_LOOSE_LUT || lut_type == BT_COEX_INVALID_LUT) return LINK_QUAL_AGG_TIME_LIMIT_DEF; /* tight coex, high bt traffic, reduce AGG time limit */ @@ -1225,18 +1225,21 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + enum iwl_bt_coex_lut_type lut_type; if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC) return true; /* - * In Tight, BT can't Rx while we Tx, so use both antennas since BT is - * already killed. - * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while we - * Tx. + * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas + * since BT is already killed. + * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while + * we Tx. + * When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO. */ - return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT; + lut_type = iwl_get_coex_type(mvm, mvmsta->vif); + return lut_type != BT_COEX_LOOSE_LUT; } bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, -- cgit v1.2.3 From 35fbf5d08e57cb4e7bd516781ba9499ff83688f6 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 2 Jun 2014 16:18:42 +0300 Subject: iwlwifi: mvm: BT Coex - don't limit rate control if TTC is on When the firmware enables TxTxCorunning, we can lift the constaints on the rate control. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 6 ++++++ drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index aab92a6b2f35..8d7146e54269 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -1212,6 +1212,9 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, BT_HIGH_TRAFFIC) return LINK_QUAL_AGG_TIME_LIMIT_DEF; + if (mvm->last_bt_notif.ttc_enabled) + return LINK_QUAL_AGG_TIME_LIMIT_DEF; + lut_type = iwl_get_coex_type(mvm, mvmsta->vif); if (lut_type == BT_COEX_LOOSE_LUT || lut_type == BT_COEX_INVALID_LUT) @@ -1227,6 +1230,9 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); enum iwl_bt_coex_lut_type lut_type; + if (mvm->last_bt_notif.ttc_enabled) + return true; + if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC) return true; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index 98175ca05e9d..39cb33a19862 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h @@ -305,6 +305,7 @@ enum iwl_bt_activity_grading { * @bt_traffic_load: load of BT traffic * @bt_agg_traffic_load: aggregated load of BT traffic * @bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant + * @ttc_enabled: true if ttc has been enabled by the firmware * @primary_ch_lut: LUT used for primary channel * @secondary_ch_lut: LUT used for secondary channel * @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading @@ -317,7 +318,8 @@ struct iwl_bt_coex_profile_notif { u8 bt_traffic_load; u8 bt_agg_traffic_load; u8 bt_ci_compliance; - u8 reserved[3]; + u8 ttc_enabled; + __le16 reserved; __le32 primary_ch_lut; __le32 secondary_ch_lut; -- cgit v1.2.3 From 8286d9f50af6f2c97946c6026482ee607a070c99 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 27 May 2014 22:54:18 +0300 Subject: iwlwifi: mvm: BT Coex - add reduced Tx power thresholds to constants This really belongs to the constants file. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 10 ++++------ drivers/net/wireless/iwlwifi/mvm/constants.h | 2 ++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 8d7146e54269..cae44edbeef8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -100,8 +100,6 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { #undef EVENT_PRIO_ANT -#define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD (-62) -#define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65) #define BT_ANTENNA_COUPLING_THRESHOLD (30) static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) @@ -807,9 +805,9 @@ void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm, mvmvif->bf_data.last_bt_coex_event = rssi; mvmvif->bf_data.bt_coex_max_thold = - enable ? BT_ENABLE_REDUCED_TXPOWER_THRESHOLD : 0; + enable ? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH : 0; mvmvif->bf_data.bt_coex_min_thold = - enable ? BT_DISABLE_REDUCED_TXPOWER_THRESHOLD : 0; + enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0; } /* must be called under rcu_read_lock */ @@ -946,7 +944,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, /* if the RSSI isn't valid, fake it is very low */ if (!ave_rssi) ave_rssi = -100; - if (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) { + if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) { if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); @@ -957,7 +955,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, * the iteration, if one interface's rssi isn't good enough, * bt_kill_msk will be set to default values. */ - } else if (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) { + } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) { if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 51685693af2e..ca79f7160573 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -79,6 +79,8 @@ #define IWL_MVM_PS_SNOOZE_WINDOW 50 #define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25 #define IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT 64 +#define IWL_MVM_BT_COEX_EN_RED_TXP_THRESH 62 +#define IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH 65 #define IWL_MVM_BT_COEX_SYNC2SCO 1 #define IWL_MVM_BT_COEX_CORUNNING 1 #define IWL_MVM_BT_COEX_MPLUT 1 -- cgit v1.2.3 From 34c8b24ff284d78f7db17d34125e2395120c471a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 28 May 2014 21:53:39 +0300 Subject: iwlwifi: mvm: BT Coex - avoid the shared antenna for management frames If BT is active, we need to refrain from using the shared antenna. This logic is done in the firmware when we use the link quality tables. But for management frames, the rate is written in the Tx command by the driver. Hence the driver needs to make sure not use the shared antenna when BT is active for any frames that don't use the rate scale table such as management frames or multicast. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 5 +++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/tx.c | 8 +++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index cae44edbeef8..7e0388a32912 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -1246,6 +1246,11 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, return lut_type != BT_COEX_LOOSE_LUT; } +bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) +{ + return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF; +} + bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, enum ieee80211_band band) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 472ef09c1f5f..8419840d4701 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -973,6 +973,7 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, struct ieee80211_sta *sta); bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct ieee80211_sta *sta); +bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm); bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, enum ieee80211_band band); u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 3846a6c41eb1..4f7cff506ee7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -205,7 +205,13 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, mvm->mgmt_last_antenna_idx = iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, mvm->mgmt_last_antenna_idx); - rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; + + if (info->band == IEEE80211_BAND_2GHZ && + !iwl_mvm_bt_coex_is_shared_ant_avail(mvm)) + rate_flags = BIT(ANT_A) << RATE_MCS_ANT_POS; + else + rate_flags = + BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; /* Set CCK flag as needed */ if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) -- cgit v1.2.3 From 50675360a8b0190d23350d42cc12a4e31c056c4f Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 15 Jun 2014 11:12:38 +0300 Subject: iwlwifi: mvm: disable beacon filtering escape timer in d0i3 The beacon filtering configuration in d0i3 currently uses the max value defined as 1024. However, with beacon interval of 100ms we end up with too-frequent wakeups. Instead, configure the escape timer to 0, asking the fw to disable it altogether. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index cbbcd8e284e4..c3a8c86b550d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -336,7 +336,7 @@ struct iwl_beacon_filter_cmd { #define IWL_BF_DEBUG_FLAG_D0I3 0 #define IWL_BF_ESCAPE_TIMER_DEFAULT 50 -#define IWL_BF_ESCAPE_TIMER_D0I3 1024 +#define IWL_BF_ESCAPE_TIMER_D0I3 0 #define IWL_BF_ESCAPE_TIMER_MAX 1024 #define IWL_BF_ESCAPE_TIMER_MIN 0 -- cgit v1.2.3 From 09b0ce1a874a644fb5799ebf5e54563632714115 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Sun, 25 May 2014 17:07:38 +0300 Subject: iwlwifi: mvm: Introduce an API to set STA_FLG_DISABLE_TX flag Introduce new station flag STA_FLG_DISABLE_TX, which is modified with ADD_STA command. This flag, when set, disables tx to the STA. Provide an API (iwl_mvm_sta_modify_disable_tx) to modify this flag, which should be used in channel switch and immediate quiet flows. Signed-off-by: Andrei Otcheretianski Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h | 7 ++----- drivers/net/wireless/iwlwifi/mvm/sta.c | 20 ++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/sta.h | 2 ++ 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 287b949c95f6..c71331034e9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -120,10 +120,12 @@ enum iwl_ucode_tlv_flag { * enum iwl_ucode_tlv_api - ucode api * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. + * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), + IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), }; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h index 39cebee8016f..47bd0406355d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h @@ -67,7 +67,7 @@ * enum iwl_sta_flags - flags for the ADD_STA host command * @STA_FLG_REDUCED_TX_PWR_CTRL: * @STA_FLG_REDUCED_TX_PWR_DATA: - * @STA_FLG_FLG_ANT_MSK: Antenna selection + * @STA_FLG_DISABLE_TX: set if TX should be disabled * @STA_FLG_PS: set if STA is in Power Save * @STA_FLG_INVALID: set if STA is invalid * @STA_FLG_DLP_EN: Direct Link Protocol is enabled @@ -91,10 +91,7 @@ enum iwl_sta_flags { STA_FLG_REDUCED_TX_PWR_CTRL = BIT(3), STA_FLG_REDUCED_TX_PWR_DATA = BIT(6), - STA_FLG_FLG_ANT_A = (1 << 4), - STA_FLG_FLG_ANT_B = (2 << 4), - STA_FLG_FLG_ANT_MSK = (STA_FLG_FLG_ANT_A | - STA_FLG_FLG_ANT_B), + STA_FLG_DISABLE_TX = BIT(4), STA_FLG_PS = BIT(8), STA_FLG_DRAIN_FLOW = BIT(12), diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 1fb01ea2e704..d3a6cf7558eb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1448,3 +1448,23 @@ int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, return 0; } + +void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvmsta, bool disable) +{ + struct iwl_mvm_add_sta_cmd cmd = { + .add_modify = STA_MODE_MODIFY, + .sta_id = mvmsta->sta_id, + .station_flags = disable ? cpu_to_le32(STA_FLG_DISABLE_TX) : 0, + .station_flags_msk = cpu_to_le32(STA_FLG_DISABLE_TX), + .mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color), + }; + int ret; + + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_DISABLE_STA_TX)) + return; + + ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); + if (ret) + IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); +} diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index d98e8a2142b8..10c1a5352651 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -404,5 +404,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, bool agg); int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool drain); +void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvmsta, bool disable); #endif /* __sta_h__ */ -- cgit v1.2.3 From 1c87bbad439d818f94f2e8bff98f73d6fb568dfc Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Thu, 27 Feb 2014 16:41:52 +0200 Subject: iwlwifi: mvm: support extended beacon notification Use extended beacon notification when supported by FW. Set last beacon system time to AP or GO interface. System time of last beacon can be used to avoid TBTT overlapping between two interfaces, CSA and other uses. Signed-off-by: David Spinadel Signed-off-by: Andrei Otcheretianski Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | 14 ++++++++++++ drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 32 +++++++++++++++++++--------- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 1 + drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 +++ 5 files changed, 42 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index c71331034e9b..13e5d69845e9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -119,11 +119,13 @@ enum iwl_ucode_tlv_flag { /** * enum iwl_ucode_tlv_api - ucode api * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. + * @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), + IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1), IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), }; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index 6cc5f52b807f..bdd6ff648626 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h @@ -548,6 +548,20 @@ struct iwl_beacon_notif { __le32 ibss_mgr_status; } __packed; +/** + * struct iwl_extended_beacon_notif - notifies about beacon transmission + * @beacon_notify_hdr: tx response command associated with the beacon + * @tsf: last beacon tsf + * @ibss_mgr_status: whether IBSS is manager + * @gp2: last beacon time in gp2 + */ +struct iwl_extended_beacon_notif { + struct iwl_mvm_tx_resp beacon_notify_hdr; + __le64 tsf; + __le32 ibss_mgr_status; + __le32 gp2; +} __packed; /* BEACON_NTFY_API_S_VER_5 */ + /** * enum iwl_dump_control - dump (flush) control flags * @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 8b5302777632..3b0390b8639c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -1205,19 +1205,31 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_beacon_notif *beacon = (void *)pkt->data; - u16 status __maybe_unused = - le16_to_cpu(beacon->beacon_notify_hdr.status.status); - u32 rate __maybe_unused = - le32_to_cpu(beacon->beacon_notify_hdr.initial_rate); + struct iwl_mvm_tx_resp *beacon_notify_hdr; + u64 tsf; lockdep_assert_held(&mvm->mutex); - IWL_DEBUG_RX(mvm, "beacon status %#x retries:%d tsf:0x%16llX rate:%d\n", - status & TX_STATUS_MSK, - beacon->beacon_notify_hdr.failure_frame, - le64_to_cpu(beacon->tsf), - rate); + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_CAPA_EXTENDED_BEACON) { + struct iwl_extended_beacon_notif *beacon = (void *)pkt->data; + + beacon_notify_hdr = &beacon->beacon_notify_hdr; + tsf = le64_to_cpu(beacon->tsf); + mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2); + } else { + struct iwl_beacon_notif *beacon = (void *)pkt->data; + + beacon_notify_hdr = &beacon->beacon_notify_hdr; + tsf = le64_to_cpu(beacon->tsf); + } + + IWL_DEBUG_RX(mvm, + "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n", + le16_to_cpu(beacon_notify_hdr->status.status) & + TX_STATUS_MSK, + beacon_notify_hdr->failure_frame, tsf, + mvm->ap_last_beacon_gp2, + le32_to_cpu(beacon_notify_hdr->initial_rate)); if (unlikely(mvm->csa_vif && mvm->csa_vif->csa_active)) { if (!ieee80211_csa_is_complete(mvm->csa_vif)) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index f22be88c0387..f2fde3649139 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1465,6 +1465,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); mvmvif->ap_ibss_active = false; + mvm->ap_last_beacon_gp2 = 0; iwl_mvm_bt_coex_vif_change(mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 8419840d4701..da692582d502 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -658,6 +658,9 @@ struct iwl_mvm { bool ps_disabled; struct ieee80211_vif *csa_vif; + + /* system time of last beacon (for AP/GO interface) */ + u32 ap_last_beacon_gp2; }; /* Extract MVM priv from op_mode and _hw */ -- cgit v1.2.3 From 75f6b9b64eeead2a7726f342b89a0c74c985e584 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 2 Jun 2014 10:03:33 +0300 Subject: iwlwivi: mvm: BT Coex - properly set the priority of beacons Since the new API allows multiple priorities, we need to properly set the beacon's prorities in the TX cmd associated to it. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 3b0390b8639c..aad36212c4d7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -904,7 +904,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, struct iwl_mac_beacon_cmd beacon_cmd = {}; struct ieee80211_tx_info *info; u32 beacon_skb_len; - u32 rate; + u32 rate, tx_flags; if (WARN_ON(!beacon)) return -EINVAL; @@ -914,14 +914,17 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, /* TODO: for now the beacon template id is set to be the mac context id. * Might be better to handle it as another resource ... */ beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id); + info = IEEE80211_SKB_CB(beacon); /* Set up TX command fields */ beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len); beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id; beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); - beacon_cmd.tx.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | - TX_CMD_FLG_BT_DIS | - TX_CMD_FLG_TSF); + tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF; + tx_flags |= + iwl_mvm_bt_coex_tx_prio(mvm, (void *)beacon->data, info, 0) << + TX_CMD_FLG_BT_PRIO_POS; + beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags); mvm->mgmt_last_antenna_idx = iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, @@ -931,8 +934,6 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS); - info = IEEE80211_SKB_CB(beacon); - if (info->band == IEEE80211_BAND_5GHZ || vif->p2p) { rate = IWL_FIRST_OFDM_RATE; } else { -- cgit v1.2.3 From c47af22ad630e03053f3eeefd19bd8274989ffbb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 30 Apr 2014 16:34:45 +0200 Subject: iwlwifi: mvm: handle device start failures during restart If the device fails during a restart, mac80211 now handles the situation better but we still have a little bit of cleanup to do in the driver - add the required code. Signed-off-by: Johannes Berg Reviewed-by: ArikX Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index f2fde3649139..3c2c9b99b59e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -689,6 +689,16 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw) iwl_mvm_restart_cleanup(mvm); ret = iwl_mvm_up(mvm); + + if (ret && test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + /* Something went wrong - we need to finish some cleanup + * that normally iwl_mvm_mac_restart_complete() below + * would do. + */ + clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); + iwl_mvm_d0i3_enable_tx(mvm, NULL); + } + mutex_unlock(&mvm->mutex); return ret; -- cgit v1.2.3 From 5433ba365f6dd9f30899188755eb4b093314732c Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Mon, 23 Jun 2014 23:11:09 -0700 Subject: cxgb4: Fix endian bug introduced in cxgb4 dcb patchset Hi, This patch fixes warnings generated by sparse as pointed out by kbuild test robot, please apply to net-next. Applies on top of commit 79631c89ed70643fd0579a65834b227795b251ee ("trivial: net/irda/irlmp.c: Fix closing brace followed by if") -Anish v2: cleanup submission as per davem's feedback Fixes: 76bcb31efc06 ("cxgb4 : Add DCBx support codebase and dcbnl_ops") Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index 39b4a85fceae..a8b1073e6373 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -488,12 +488,12 @@ static void cxgb4_setpfccfg(struct net_device *dev, int priority, u8 pfccfg) pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY); pcmd.u.dcb.pfc.type = FW_PORT_DCB_TYPE_PFC; - pcmd.u.dcb.pfc.pfcen = cpu_to_be16(pi->dcb.pfcen); + pcmd.u.dcb.pfc.pfcen = pi->dcb.pfcen; if (pfccfg) - pcmd.u.dcb.pfc.pfcen |= cpu_to_be16(1 << priority); + pcmd.u.dcb.pfc.pfcen |= (1 << priority); else - pcmd.u.dcb.pfc.pfcen &= cpu_to_be16(~(1 << priority)); + pcmd.u.dcb.pfc.pfcen &= (~(1 << priority)); err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); if (err != FW_PORT_DCB_CFG_SUCCESS) { @@ -501,7 +501,7 @@ static void cxgb4_setpfccfg(struct net_device *dev, int priority, u8 pfccfg) return; } - pi->dcb.pfcen = be16_to_cpu(pcmd.u.dcb.pfc.pfcen); + pi->dcb.pfcen = pcmd.u.dcb.pfc.pfcen; } static u8 cxgb4_setall(struct net_device *dev) -- cgit v1.2.3 From 17413a80bcff78ceb371fb6a34d888780ad7b7fa Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Wed, 4 Jun 2014 01:23:13 +0000 Subject: i40e: Stop the VF device after setting its MAC address If the host VMM administrator has changed the VF device's MAC address then the i40e driver needs to halt the VF device so that the administrator will be forced to reload the VF driver. This will cause the VF driver to start using the newly assigned MAC address. This brings the i40e driver into conformance with operational characteristics of other Intel SR-IOV featured drivers. Change-ID: Ic7242cceb8287dd2cb72fb1f3166a032a28bf88a Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index f5b9d2062573..d2dabae5b40c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -2077,6 +2077,8 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) } ether_addr_copy(vf->default_lan_addr.addr, mac); vf->pf_set_mac = true; + /* Force the VF driver stop so it has to reload with new MAC address */ + i40e_vc_disable_vf(pf, vf); dev_info(&pf->pdev->dev, "Reload the VF driver to make this change effective.\n"); ret = 0; -- cgit v1.2.3 From 23cfbe074da66305d992c663b778d12476eeefce Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 4 Jun 2014 01:23:14 +0000 Subject: i40e: make prep_for_reset void The return from i40e_prep_for_reset() was being ignored by almost all its callers. The one place it wasn't ignored could have caused a silent and confusing failure of the driver to finish a reset. Since we really are doing a rebuild anyway, ignore this last case as well and simply make the function a void type. Change-ID: Ia4fed7f903d39a6c47c5722625a53e59c3f7ed53 Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b167fc2c4abe..3f60976a0805 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5611,7 +5611,7 @@ static void i40e_fdir_teardown(struct i40e_pf *pf) * * Close up the VFs and other things in prep for pf Reset. **/ -static int i40e_prep_for_reset(struct i40e_pf *pf) +static void i40e_prep_for_reset(struct i40e_pf *pf) { struct i40e_hw *hw = &pf->hw; i40e_status ret = 0; @@ -5619,7 +5619,7 @@ static int i40e_prep_for_reset(struct i40e_pf *pf) clear_bit(__I40E_RESET_INTR_RECEIVED, &pf->state); if (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state)) - return 0; + return; dev_dbg(&pf->pdev->dev, "Tearing down internal switch for reset\n"); @@ -5636,13 +5636,10 @@ static int i40e_prep_for_reset(struct i40e_pf *pf) /* call shutdown HMC */ if (hw->hmc.hmc_obj) { ret = i40e_shutdown_lan_hmc(hw); - if (ret) { + if (ret) dev_warn(&pf->pdev->dev, "shutdown_lan_hmc failed: %d\n", ret); - clear_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state); - } } - return ret; } /** @@ -5816,11 +5813,8 @@ end_core_reset: **/ static void i40e_handle_reset_warning(struct i40e_pf *pf) { - i40e_status ret; - - ret = i40e_prep_for_reset(pf); - if (!ret) - i40e_reset_and_rebuild(pf, false); + i40e_prep_for_reset(pf); + i40e_reset_and_rebuild(pf, false); } /** -- cgit v1.2.3 From df430b1240d3375d053230d1f943383d59f9267a Mon Sep 17 00:00:00 2001 From: Neerav Parikh Date: Wed, 4 Jun 2014 01:23:15 +0000 Subject: i40e: Add PF reset when Malicious driver event for PF As per the spec when the PF driver receives a Malicious driver event the queue that caused the event is already stopped and it is expected that the function that owns the queue will reset the queue. In some cases it may not be possible to determine the queue and it is suggested to reset the whole function. This patch takes the later approach when the event is owned by the PF that owns it. Change-ID: I40f9764a6a5e068c0ef8438db00c5aa9c2c6c1c8 Signed-off-by: Neerav Parikh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 3f60976a0805..80c5d55cf50b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5827,6 +5827,7 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf) { struct i40e_hw *hw = &pf->hw; bool mdd_detected = false; + bool pf_mdd_detected = false; struct i40e_vf *vf; u32 reg; int i; @@ -5866,6 +5867,30 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf) mdd_detected = true; } + if (mdd_detected) { + reg = rd32(hw, I40E_PF_MDET_TX); + if (reg & I40E_PF_MDET_TX_VALID_MASK) { + wr32(hw, I40E_PF_MDET_TX, 0xFFFF); + dev_info(&pf->pdev->dev, + "MDD TX event is for this function 0x%08x, requesting PF reset.\n", + reg); + pf_mdd_detected = true; + } + reg = rd32(hw, I40E_PF_MDET_RX); + if (reg & I40E_PF_MDET_RX_VALID_MASK) { + wr32(hw, I40E_PF_MDET_RX, 0xFFFF); + dev_info(&pf->pdev->dev, + "MDD RX event is for this function 0x%08x, requesting PF reset.\n", + reg); + pf_mdd_detected = true; + } + /* Queue belongs to the PF, initiate a reset */ + if (pf_mdd_detected) { + set_bit(__I40E_PF_RESET_REQUESTED, &pf->state); + i40e_service_event_schedule(pf); + } + } + /* see if one of the VFs needs its hand slapped */ for (i = 0; i < pf->num_alloc_vfs && mdd_detected; i++) { vf = &(pf->vf[i]); -- cgit v1.2.3 From 278b6f629c8221b06850f43c748d0888d5d15a24 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 4 Jun 2014 01:41:03 +0000 Subject: i40e: warn on newer/older firmware API rev If the firmware's API minor number is larger than the one expected, log a warning and recommend driver SW update. If the firmware's API major or minor number is smaller then the one expected (n for major, n or n-1 for minor), log a warning and recommend NVM update. Change-ID: If0b887e055478f8e435ba7fa28113b63a6f1bb35 Signed-off-by: Shannon Nelson Signed-off-by: Catherine Sullivan Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 80c5d55cf50b..4289ff1e84ef 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -8633,6 +8633,20 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_pf_reset; } + if (hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) + dev_info(&pdev->dev, + "Note: FW API version %02x.%02x newer than expected %02x.%02x, recommend driver update.\n", + hw->aq.api_maj_ver, hw->aq.api_min_ver, + I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR); + + if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || + hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR-1)) + dev_info(&pdev->dev, + "Note: FW API version %02x.%02x older than expected %02x.%02x, recommend nvm update.\n", + hw->aq.api_maj_ver, hw->aq.api_min_ver, + I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR); + + i40e_verify_eeprom(pf); /* Rev 0 hardware was never productized */ -- cgit v1.2.3 From cde4cbc7800469c9b8424261b69c45a71a89caf4 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 4 Jun 2014 01:23:17 +0000 Subject: i40e: fix a stray print message This log print message will probably never be seen, but it needs to match the "attempting to rebuild switch\n" log message a few lines above. Change-ID: Ic3f5b4f67568d721cb02e826cf2cb33847f51c11 Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 4289ff1e84ef..b4278a22382c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5775,7 +5775,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) } if (pf->vsi[pf->lan_vsi]->uplink_seid == pf->mac_seid) { - dev_info(&pf->pdev->dev, "attempting to rebuild PF VSI\n"); + dev_dbg(&pf->pdev->dev, "attempting to rebuild PF VSI\n"); /* no VEB, so rebuild only the Main VSI */ ret = i40e_add_vsi(pf->vsi[pf->lan_vsi]); if (ret) { -- cgit v1.2.3 From 5c2cebda438b888147f6dfd6d1423432d837c0ea Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Wed, 4 Jun 2014 01:23:18 +0000 Subject: i40e: Fix ethtool coalesce settings This patch fixes the i40e_set_coalesce function to allow 0 as a disable value. Also, added message to user about invalid value and provides valid range. Change-ID: I6c9ff11a9861f2045bd543745a3d132999ffbbd8 Signed-off-by: Carolyn Wyborny Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 28 +++++++++++++++++++++----- drivers/net/ethernet/intel/i40e/i40e_main.c | 16 +++++++++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 817e179dc3f9..07811dd6eb89 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -617,6 +617,7 @@ static inline void i40e_dbg_init(void) {} static inline void i40e_dbg_exit(void) {} #endif /* CONFIG_DEBUG_FS*/ void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector); +void i40e_irq_dynamic_disable(struct i40e_vsi *vsi, int vector); void i40e_irq_dynamic_disable_icr0(struct i40e_pf *pf); void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf); int i40e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 4a488ffcd6b0..7da37581bc02 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1105,17 +1105,36 @@ static int i40e_set_coalesce(struct net_device *netdev, if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq) vsi->work_limit = ec->tx_max_coalesced_frames_irq; + vector = vsi->base_vector; if ((ec->rx_coalesce_usecs >= (I40E_MIN_ITR << 1)) && - (ec->rx_coalesce_usecs <= (I40E_MAX_ITR << 1))) + (ec->rx_coalesce_usecs <= (I40E_MAX_ITR << 1))) { vsi->rx_itr_setting = ec->rx_coalesce_usecs; - else + } else if (ec->rx_coalesce_usecs == 0) { + vsi->rx_itr_setting = ec->rx_coalesce_usecs; + i40e_irq_dynamic_disable(vsi, vector); + if (ec->use_adaptive_rx_coalesce) + netif_info(pf, drv, netdev, + "Rx-secs=0, need to disable adaptive-Rx for a complete disable\n"); + } else { + netif_info(pf, drv, netdev, + "Invalid value, Rx-usecs range is 0, 8-8160\n"); return -EINVAL; + } if ((ec->tx_coalesce_usecs >= (I40E_MIN_ITR << 1)) && - (ec->tx_coalesce_usecs <= (I40E_MAX_ITR << 1))) + (ec->tx_coalesce_usecs <= (I40E_MAX_ITR << 1))) { vsi->tx_itr_setting = ec->tx_coalesce_usecs; - else + } else if (ec->tx_coalesce_usecs == 0) { + vsi->tx_itr_setting = ec->tx_coalesce_usecs; + i40e_irq_dynamic_disable(vsi, vector); + if (ec->use_adaptive_tx_coalesce) + netif_info(pf, drv, netdev, + "Tx-secs=0, need to disable adaptive-Tx for a complete disable\n"); + } else { + netif_info(pf, drv, netdev, + "Invalid value, Tx-usecs range is 0, 8-8160\n"); return -EINVAL; + } if (ec->use_adaptive_rx_coalesce) vsi->rx_itr_setting |= I40E_ITR_DYNAMIC; @@ -1127,7 +1146,6 @@ static int i40e_set_coalesce(struct net_device *netdev, else vsi->tx_itr_setting &= ~I40E_ITR_DYNAMIC; - vector = vsi->base_vector; for (i = 0; i < vsi->num_q_vectors; i++, vector++) { q_vector = vsi->q_vectors[i]; q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b4278a22382c..71efc68c5d99 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2767,6 +2767,22 @@ void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector) /* skip the flush */ } +/** + * i40e_irq_dynamic_disable - Disable default interrupt generation settings + * @vsi: pointer to a vsi + * @vector: enable a particular Hw Interrupt vector + **/ +void i40e_irq_dynamic_disable(struct i40e_vsi *vsi, int vector) +{ + struct i40e_pf *pf = vsi->back; + struct i40e_hw *hw = &pf->hw; + u32 val; + + val = I40E_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; + wr32(hw, I40E_PFINT_DYN_CTLN(vector - 1), val); + i40e_flush(hw); +} + /** * i40e_msix_clean_rings - MSIX mode Interrupt Handler * @irq: interrupt number -- cgit v1.2.3 From c571ea05a03da856b1e9f8c0355128a7044d6a91 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 4 Jun 2014 01:23:19 +0000 Subject: i40e/i40evf: remove reserved type One of the PCTYPES that was moved to a reserved value wasn't removed from the code. Change-ID: I31fafe6d79c5f5128179979af5eaafa8c0cd62fe Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 1 - drivers/net/ethernet/intel/i40e/i40e_type.h | 1 - drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 1 - drivers/net/ethernet/intel/i40evf/i40e_type.h | 1 - 4 files changed, 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 0277894fe1c4..f09fb3ef691d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -75,7 +75,6 @@ enum i40e_dyn_idx_t { ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | \ ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN) | \ ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 1c0d5a70b892..11dd2dcfb592 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -878,7 +878,6 @@ enum i40e_filter_pctype { I40E_FILTER_PCTYPE_FRAG_IPV4 = 36, /* Note: Values 37-40 are reserved for future use */ I40E_FILTER_PCTYPE_NONF_IPV6_UDP = 41, - I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN = 42, I40E_FILTER_PCTYPE_NONF_IPV6_TCP = 43, I40E_FILTER_PCTYPE_NONF_IPV6_SCTP = 44, I40E_FILTER_PCTYPE_NONF_IPV6_OTHER = 45, diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h index 30d248bc5d19..acd3c12b8f6a 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h @@ -75,7 +75,6 @@ enum i40e_dyn_idx_t { ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | \ ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN) | \ ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 9c835786e8a1..23cd18b66b71 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -878,7 +878,6 @@ enum i40e_filter_pctype { I40E_FILTER_PCTYPE_FRAG_IPV4 = 36, /* Note: Values 37-40 are reserved for future use */ I40E_FILTER_PCTYPE_NONF_IPV6_UDP = 41, - I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN = 42, I40E_FILTER_PCTYPE_NONF_IPV6_TCP = 43, I40E_FILTER_PCTYPE_NONF_IPV6_SCTP = 44, I40E_FILTER_PCTYPE_NONF_IPV6_OTHER = 45, -- cgit v1.2.3 From 1ac978af7caca1aa857802822602520a58a50018 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 01:23:20 +0000 Subject: i40e: Add ablitity to enable/disable link from set_link_restart_an The ability is already there in the fw and this will make it easy to toggle link without calling set_phy_config when no other link settings need to change. Change-ID: I185567ae81776382ac145247e4eb1ee95f22382c Signed-off-by: Catherine Sullivan Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 8 +++++++- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 3 ++- drivers/net/ethernet/intel/i40e/i40e_prototype.h | 3 ++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index a51bba634718..bbace40bd114 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -971,12 +971,14 @@ i40e_status i40e_aq_clear_pxe_mode(struct i40e_hw *hw, /** * i40e_aq_set_link_restart_an * @hw: pointer to the hw struct + * @enable_link: if true: enable link, if false: disable link * @cmd_details: pointer to command details structure or NULL * * Sets up the link and restarts the Auto-Negotiation over the link. **/ i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw, - struct i40e_asq_cmd_details *cmd_details) + bool enable_link, + struct i40e_asq_cmd_details *cmd_details) { struct i40e_aq_desc desc; struct i40e_aqc_set_link_restart_an *cmd = @@ -987,6 +989,10 @@ i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw, i40e_aqc_opc_set_link_restart_an); cmd->command = I40E_AQ_PHY_RESTART_AN; + if (enable_link) + cmd->command |= I40E_AQ_PHY_LINK_ENABLE; + else + cmd->command &= ~I40E_AQ_PHY_LINK_ENABLE; status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 7da37581bc02..df89b6c3db41 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1027,9 +1027,10 @@ static int i40e_nway_reset(struct net_device *netdev) struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; struct i40e_hw *hw = &pf->hw; + bool link_up = hw->phy.link_info.link_info & I40E_AQ_LINK_UP; i40e_status ret = 0; - ret = i40e_aq_set_link_restart_an(hw, NULL); + ret = i40e_aq_set_link_restart_an(hw, link_up, NULL); if (ret) { netdev_info(netdev, "link restart failed, aq_err=%d\n", pf->hw.aq.asq_last_status); diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index a430699c41d5..3300b996a467 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -77,7 +77,8 @@ i40e_status i40e_aq_set_default_vsi(struct i40e_hw *hw, u16 vsi_id, i40e_status i40e_aq_clear_pxe_mode(struct i40e_hw *hw, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw, - struct i40e_asq_cmd_details *cmd_details); + bool enable_link, + struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, bool enable_lse, struct i40e_link_status *link, struct i40e_asq_cmd_details *cmd_details); -- cgit v1.2.3 From cc41222c55e9ec44d148dee67e6ad407e3b79e46 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 4 Jun 2014 01:23:21 +0000 Subject: i40e: use WoL flag when setting LAA Make sure the Firmware sets up the LAA as a Wake-On-LAN address. Change-ID: I57b9acd8c288424fcfed0911053eb725c400b41c Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 71efc68c5d99..44789c2e3f50 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1337,7 +1337,7 @@ static int i40e_set_mac(struct net_device *netdev, void *p) if (vsi->type == I40E_VSI_MAIN) { i40e_status ret; ret = i40e_aq_mac_address_write(&vsi->back->hw, - I40E_AQC_WRITE_TYPE_LAA_ONLY, + I40E_AQC_WRITE_TYPE_LAA_WOL, addr->sa_data, NULL); if (ret) { netdev_info(netdev, -- cgit v1.2.3 From 6c8ad1ba1650e6c22dcaa5fe288c6236c3b25ae5 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 4 Jun 2014 01:23:22 +0000 Subject: i40e: allow user to set LAA again Don't short-circuit the LAA assignment when the driver thinks it has already been done - it is possible that the user might want to force the address setting again. At the same time, this requires a little re-ordering of the filter management. Change-ID: Ia0d71e3bc04edd7b68cf67edecc00abe7b9f6639 Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 31 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 44789c2e3f50..81cbea72722e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1327,9 +1327,6 @@ static int i40e_set_mac(struct net_device *netdev, void *p) netdev_info(netdev, "set mac address=%pM\n", addr->sa_data); - if (ether_addr_equal(netdev->dev_addr, addr->sa_data)) - return 0; - if (test_bit(__I40E_DOWN, &vsi->back->state) || test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state)) return -EADDRNOTAVAIL; @@ -1345,22 +1342,26 @@ static int i40e_set_mac(struct net_device *netdev, void *p) ret); return -EADDRNOTAVAIL; } - - ether_addr_copy(vsi->back->hw.mac.addr, addr->sa_data); } - /* In order to be sure to not drop any packets, add the new address - * then delete the old one. - */ - f = i40e_add_filter(vsi, addr->sa_data, I40E_VLAN_ANY, false, false); - if (!f) - return -ENOMEM; + if (!i40e_find_mac(vsi, addr->sa_data, false, true)) { - i40e_sync_vsi_filters(vsi); - i40e_del_filter(vsi, netdev->dev_addr, I40E_VLAN_ANY, false, false); - i40e_sync_vsi_filters(vsi); + /* In order to be sure to not drop any packets, add the + * new address first then delete the old one. + */ + f = i40e_add_filter(vsi, addr->sa_data, I40E_VLAN_ANY, + false, false); + if (!f) + return -ENOMEM; + + i40e_sync_vsi_filters(vsi); + i40e_del_filter(vsi, netdev->dev_addr, I40E_VLAN_ANY, + false, false); + i40e_sync_vsi_filters(vsi); + } - ether_addr_copy(netdev->dev_addr, addr->sa_data); + if (!ether_addr_equal(netdev->dev_addr, addr->sa_data)) + ether_addr_copy(netdev->dev_addr, addr->sa_data); return 0; } -- cgit v1.2.3 From 6252c7e4ee48f016dd075168df9fabc7197f38e5 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 4 Jun 2014 01:23:23 +0000 Subject: i40e: reapply LAA after reset The LAA is lost on a reset, so be sure to replay it when rebuilding the switch after any reset. Change-ID: I6e643f9a59dfd899b6cbdf84d93b4bc9c37bb949 Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_main.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 07811dd6eb89..2ec6e8a11ee1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -362,6 +362,7 @@ struct i40e_mac_filter { bool is_vf; /* filter belongs to a VF */ bool is_netdev; /* filter belongs to a netdev */ bool changed; /* filter needs to be sync'd to the HW */ + bool is_laa; /* filter is a Locally Administered Address */ }; struct i40e_veb { diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 81cbea72722e..9276ca3f43f2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1344,8 +1344,8 @@ static int i40e_set_mac(struct net_device *netdev, void *p) } } - if (!i40e_find_mac(vsi, addr->sa_data, false, true)) { - + f = i40e_find_mac(vsi, addr->sa_data, false, true); + if (!f) { /* In order to be sure to not drop any packets, add the * new address first then delete the old one. */ @@ -1360,6 +1360,7 @@ static int i40e_set_mac(struct net_device *netdev, void *p) i40e_sync_vsi_filters(vsi); } + f->is_laa = true; if (!ether_addr_equal(netdev->dev_addr, addr->sa_data)) ether_addr_copy(netdev->dev_addr, addr->sa_data); @@ -7378,6 +7379,12 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { f->changed = true; f_count++; + + if (f->is_laa && vsi->type == I40E_VSI_MAIN) { + i40e_aq_mac_address_write(&vsi->back->hw, + I40E_AQC_WRITE_TYPE_LAA_WOL, + f->macaddr, NULL); + } } if (f_count) { vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; -- cgit v1.2.3 From 264ccc93b23ae654d3db37c3ebde1da6a2866e31 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 4 Jun 2014 01:23:24 +0000 Subject: i40e: no pf reset at pci remove The PF reset to clean up at the end of the remove is a nice thing to do, but it also removes any LAA setting that Wake On LAN wants for future wake up. Change-ID: Ic090ec714df2d722281d11735cf75f2aa4432e2c Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 9276ca3f43f2..e2dbe0427cdf 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -8898,7 +8898,6 @@ static void i40e_remove(struct pci_dev *pdev) { struct i40e_pf *pf = pci_get_drvdata(pdev); i40e_status ret_code; - u32 reg; int i; i40e_dbg_pf_exit(pf); @@ -8976,11 +8975,6 @@ static void i40e_remove(struct pci_dev *pdev) kfree(pf->irq_pile); kfree(pf->vsi); - /* force a PF reset to clean anything leftover */ - reg = rd32(&pf->hw, I40E_PFGEN_CTRL); - wr32(&pf->hw, I40E_PFGEN_CTRL, (reg | I40E_PFGEN_CTRL_PFSWR_MASK)); - i40e_flush(&pf->hw); - iounmap(pf->hw.hw_addr); kfree(pf); pci_release_selected_regions(pdev, -- cgit v1.2.3 From 327fe04bfb32642eee237e1cc1eaef16d6a4a0f5 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 4 Jun 2014 01:23:26 +0000 Subject: i40e: Bypass timeout recovery level 0 so as to not cause MDD When a Tx hang happens, usually the Tx queue disable fails. At this point if we try to recover by a VSI reinit the HW gets unhappy and we get a Malicious Driver Detect (MDD) event. HW expects a PF reset if a queue disable fails, if we don't do a PF reset and restart the queue we get an MDD. This patch makes sure we do a PF reset on Tx hang and that way we avoid any MDD because of Tx queue disable failure. Change-ID: I665ab6223577c788da857ee2132e733dc9a451e4 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index e2dbe0427cdf..50f9ab72c95f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -278,7 +278,7 @@ static void i40e_tx_timeout(struct net_device *netdev) pf->tx_timeout_count++; if (time_after(jiffies, (pf->tx_timeout_last_recovery + HZ*20))) - pf->tx_timeout_recovery_level = 0; + pf->tx_timeout_recovery_level = 1; pf->tx_timeout_last_recovery = jiffies; netdev_info(netdev, "tx_timeout recovery level %d\n", pf->tx_timeout_recovery_level); @@ -6826,6 +6826,8 @@ static int i40e_sw_init(struct i40e_pf *pf) pf->irq_pile->num_entries = pf->hw.func_caps.num_msix_vectors; pf->irq_pile->search_hint = 0; + pf->tx_timeout_recovery_level = 1; + mutex_init(&pf->switch_mutex); sw_init_done: -- cgit v1.2.3 From 25941f94ba2dbb0b8e451a917aa12a547994c738 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 01:23:27 +0000 Subject: i40e/i40evf: Bump i40e to 0.4.17 and i40evf to 0.9.36 Bump versions. Change-ID: I47fc3433240800cd823ff512f3015822277b0d20 Signed-off-by: Catherine Sullivan Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 50f9ab72c95f..5980d6b3fb1a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 4 -#define DRV_VERSION_BUILD 13 +#define DRV_VERSION_BUILD 17 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 2fdccce1b872..b473172708f5 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710 X710 Virtual Function Network Driver"; -#define DRV_VERSION "0.9.35" +#define DRV_VERSION "0.9.36" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; -- cgit v1.2.3 From c56ef6725068c0ce499e517409c0da226ef51b08 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Wed, 5 Feb 2014 15:21:13 +0200 Subject: mac80211: support more than one band in scan request Some drivers (such as iwlmvm) can handle multiple bands in a single HW scan request. Add a HW flag to indicate that the driver support this. To hold the required data, create a separate structure for HW scan request that holds cfg scan request and data about different parts of the scan IEs. As this changes the mac80211 API, update all drivers using it to use the correct new function type/argument. Signed-off-by: David Spinadel Signed-off-by: Johannes Berg --- drivers/net/wireless/at76c50x-usb.c | 3 +- drivers/net/wireless/ath/ath10k/mac.c | 3 +- drivers/net/wireless/cw1200/scan.c | 3 +- drivers/net/wireless/cw1200/scan.h | 2 +- drivers/net/wireless/iwlegacy/common.c | 3 +- drivers/net/wireless/iwlegacy/common.h | 2 +- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 3 +- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 +- drivers/net/wireless/mac80211_hwsim.c | 3 +- drivers/net/wireless/ti/wl1251/main.c | 3 +- drivers/net/wireless/ti/wlcore/main.c | 3 +- include/net/mac80211.h | 39 ++++++++++- net/mac80211/driver-ops.h | 2 +- net/mac80211/ieee80211_i.h | 9 ++- net/mac80211/scan.c | 85 +++++++++++++++------- net/mac80211/util.c | 105 +++++++++++++++++++--------- 16 files changed, 198 insertions(+), 73 deletions(-) diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index d48776e4f343..334c2ece855a 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1955,8 +1955,9 @@ static void at76_dwork_hw_scan(struct work_struct *work) static int at76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) + struct ieee80211_scan_request *hw_req) { + struct cfg80211_scan_request *req = &hw_req->req; struct at76_priv *priv = hw->priv; struct at76_req_scan scan; u8 *ssid = NULL; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a21080028c54..b8314a534972 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3137,10 +3137,11 @@ exit: static int ath10k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) + struct ieee80211_scan_request *hw_req) { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + struct cfg80211_scan_request *req = &hw_req->req; struct wmi_start_scan_arg arg; int ret = 0; int i; diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c index 9afcd4ce3368..b2fb6c632092 100644 --- a/drivers/net/wireless/cw1200/scan.c +++ b/drivers/net/wireless/cw1200/scan.c @@ -53,9 +53,10 @@ static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan) int cw1200_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) + struct ieee80211_scan_request *hw_req) { struct cw1200_common *priv = hw->priv; + struct cfg80211_scan_request *req = &hw_req->req; struct wsm_template_frame frame = { .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, }; diff --git a/drivers/net/wireless/cw1200/scan.h b/drivers/net/wireless/cw1200/scan.h index 5a8296ccfa82..cc75459e5784 100644 --- a/drivers/net/wireless/cw1200/scan.h +++ b/drivers/net/wireless/cw1200/scan.h @@ -41,7 +41,7 @@ struct cw1200_scan { int cw1200_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_scan_request *req); + struct ieee80211_scan_request *hw_req); void cw1200_scan_work(struct work_struct *work); void cw1200_scan_timeout(struct work_struct *work); void cw1200_clear_recent_scan_work(struct work_struct *work); diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index ecc674627e6e..03de7467aecf 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -1572,8 +1572,9 @@ il_scan_initiate(struct il_priv *il, struct ieee80211_vif *vif) int il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) + struct ieee80211_scan_request *hw_req) { + struct cfg80211_scan_request *req = &hw_req->req; struct il_priv *il = hw->priv; int ret; diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h index ea5c0f863c4e..5b972798bdff 100644 --- a/drivers/net/wireless/iwlegacy/common.h +++ b/drivers/net/wireless/iwlegacy/common.h @@ -1787,7 +1787,7 @@ int il_scan_cancel(struct il_priv *il); int il_scan_cancel_timeout(struct il_priv *il, unsigned long ms); void il_force_scan_end(struct il_priv *il); int il_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_scan_request *req); + struct ieee80211_scan_request *hw_req); void il_internal_short_hw_scan(struct il_priv *il); int il_force_reset(struct il_priv *il, bool external); u16 il_fill_probe_req(struct il_priv *il, struct ieee80211_mgmt *frame, diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 29af7b51e370..afb98f4fdaf3 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -1495,9 +1495,10 @@ static int iwlagn_mac_change_interface(struct ieee80211_hw *hw, static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) + struct ieee80211_scan_request *hw_req) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); + struct cfg80211_scan_request *req = &hw_req->req; int ret; IWL_DEBUG_MAC80211(priv, "enter\n"); diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 7215f5980186..4dc2e05f49ce 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1537,9 +1537,10 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) + struct ieee80211_scan_request *hw_req) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct cfg80211_scan_request *req = &hw_req->req; int ret; if (req->n_channels == 0 || req->n_channels > MAX_NUM_SCAN_CHANNELS) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 06a0722164da..eba51460a5de 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1736,9 +1736,10 @@ static void hw_scan_work(struct work_struct *work) static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) + struct ieee80211_scan_request *hw_req) { struct mac80211_hwsim_data *hwsim = hw->priv; + struct cfg80211_scan_request *req = &hw_req->req; mutex_lock(&hwsim->mutex); if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 4e782f18ae34..38234851457e 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -991,8 +991,9 @@ out: static int wl1251_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) + struct ieee80211_scan_request *hw_req) { + struct cfg80211_scan_request *req = &hw_req->req; struct wl1251 *wl = hw->priv; struct sk_buff *skb; size_t ssid_len = 0; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 3d6028e62750..e5ffb8b91dd4 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -3540,8 +3540,9 @@ out: static int wl1271_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) + struct ieee80211_scan_request *hw_req) { + struct cfg80211_scan_request *req = &hw_req->req; struct wl1271 *wl = hw->priv; int ret; u8 *ssid = NULL; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 18c2bdbaf988..9536ee3e22a9 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -768,6 +768,26 @@ struct ieee80211_sched_scan_ies { size_t len[IEEE80211_NUM_BANDS]; }; +/** + * struct ieee80211_scan_ies - descriptors for different blocks of IEs + * + * This structure is used to point to different blocks of IEs in HW scan. + * These blocks contain the IEs passed by userspace and the ones generated + * by mac80211. + * + * @ies: pointers to band specific IEs. + * @len: lengths of band_specific IEs. + * @common_ies: IEs for all bands (especially vendor specific ones) + * @common_ie_len: length of the common_ies + */ +struct ieee80211_scan_ies { + const u8 *ies[IEEE80211_NUM_BANDS]; + size_t len[IEEE80211_NUM_BANDS]; + const u8 *common_ies; + size_t common_ie_len; +}; + + static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) { return (struct ieee80211_tx_info *)skb->cb; @@ -1606,6 +1626,9 @@ struct ieee80211_tx_control { * on single-channel hardware. It can also be used as an * optimization in certain channel switch cases with * multi-channel. + * + * @IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS: The HW supports scanning on all bands + * in one command, mac80211 doesn't have to run separate scans per band. */ enum ieee80211_hw_flags { IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, @@ -1638,6 +1661,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27, IEEE80211_HW_CHANCTX_STA_CSA = 1<<28, IEEE80211_HW_CHANGE_RUNNING_CHANCTX = 1<<29, + IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS = 1<<30, }; /** @@ -1763,6 +1787,19 @@ struct ieee80211_hw { const struct ieee80211_cipher_scheme *cipher_schemes; }; +/** + * struct ieee80211_scan_request - hw scan request + * + * @ies: pointers different parts of IEs (in req.ie) + * @req: cfg80211 request. + */ +struct ieee80211_scan_request { + struct ieee80211_scan_ies ies; + + /* Keep last */ + struct cfg80211_scan_request req; +}; + /** * wiphy_to_ieee80211_hw - return a mac80211 driver hw struct from a wiphy * @@ -2874,7 +2911,7 @@ struct ieee80211_ops { void (*set_default_unicast_key)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int idx); int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_scan_request *req); + struct ieee80211_scan_request *req); void (*cancel_hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int (*sched_scan_start)(struct ieee80211_hw *hw, diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 2265bd7a44ba..faa0d90f6e80 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -314,7 +314,7 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, static inline int drv_hw_scan(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - struct cfg80211_scan_request *req) + struct ieee80211_scan_request *req) { int ret; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6c8089429892..f88bd1659cde 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1152,7 +1152,8 @@ struct ieee80211_local { unsigned long scanning; struct cfg80211_ssid scan_ssid; struct cfg80211_scan_request *int_scan_req; - struct cfg80211_scan_request *scan_req, *hw_scan_req; + struct cfg80211_scan_request *scan_req; + struct ieee80211_scan_request *hw_scan_req; struct cfg80211_chan_def scan_chandef; enum ieee80211_band hw_scan_band; int scan_channel_idx; @@ -1756,8 +1757,10 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, const u8 *bssid, u16 stype, u16 reason, bool send_frame, u8 *frame_buf); int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, - size_t buffer_len, const u8 *ie, size_t ie_len, - enum ieee80211_band band, u32 rate_mask, + size_t buffer_len, + struct ieee80211_scan_ies *ie_desc, + const u8 *ie, size_t ie_len, + u8 bands_used, u32 *rate_masks, struct cfg80211_chan_def *chandef); struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, u32 ratemask, diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index f40661eb75b5..116959e070d0 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -235,38 +235,51 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) { struct cfg80211_scan_request *req = local->scan_req; struct cfg80211_chan_def chandef; - enum ieee80211_band band; + u8 bands_used = 0; int i, ielen, n_chans; if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) return false; - do { - if (local->hw_scan_band == IEEE80211_NUM_BANDS) - return false; - - band = local->hw_scan_band; - n_chans = 0; + if (local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) { for (i = 0; i < req->n_channels; i++) { - if (req->channels[i]->band == band) { - local->hw_scan_req->channels[n_chans] = + local->hw_scan_req->req.channels[i] = req->channels[i]; + bands_used |= BIT(req->channels[i]->band); + } + + n_chans = req->n_channels; + } else { + do { + if (local->hw_scan_band == IEEE80211_NUM_BANDS) + return false; + + n_chans = 0; + + for (i = 0; i < req->n_channels; i++) { + if (req->channels[i]->band != + local->hw_scan_band) + continue; + local->hw_scan_req->req.channels[n_chans] = req->channels[i]; n_chans++; + bands_used |= BIT(req->channels[i]->band); } - } - local->hw_scan_band++; - } while (!n_chans); + local->hw_scan_band++; + } while (!n_chans); + } - local->hw_scan_req->n_channels = n_chans; + local->hw_scan_req->req.n_channels = n_chans; ieee80211_prepare_scan_chandef(&chandef, req->scan_width); - ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, + ielen = ieee80211_build_preq_ies(local, + (u8 *)local->hw_scan_req->req.ie, local->hw_scan_ies_bufsize, - req->ie, req->ie_len, band, - req->rates[band], &chandef); - local->hw_scan_req->ie_len = ielen; - local->hw_scan_req->no_cck = req->no_cck; + &local->hw_scan_req->ies, + req->ie, req->ie_len, + bands_used, req->rates, &chandef); + local->hw_scan_req->req.ie_len = ielen; + local->hw_scan_req->req.no_cck = req->no_cck; return true; } @@ -291,7 +304,9 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (WARN_ON(!local->scan_req)) return; - if (hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { + if (hw_scan && !aborted && + !(local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) && + ieee80211_prep_hw_scan(local)) { int rc; rc = drv_hw_scan(local, @@ -473,6 +488,21 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, u8 *ies; local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len; + + if (local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) { + int i, n_bands = 0; + u8 bands_counted = 0; + + for (i = 0; i < req->n_channels; i++) { + if (bands_counted & BIT(req->channels[i]->band)) + continue; + bands_counted |= BIT(req->channels[i]->band); + n_bands++; + } + + local->hw_scan_ies_bufsize *= n_bands; + } + local->hw_scan_req = kmalloc( sizeof(*local->hw_scan_req) + req->n_channels * sizeof(req->channels[0]) + @@ -480,13 +510,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (!local->hw_scan_req) return -ENOMEM; - local->hw_scan_req->ssids = req->ssids; - local->hw_scan_req->n_ssids = req->n_ssids; + local->hw_scan_req->req.ssids = req->ssids; + local->hw_scan_req->req.n_ssids = req->n_ssids; ies = (u8 *)local->hw_scan_req + sizeof(*local->hw_scan_req) + req->n_channels * sizeof(req->channels[0]); - local->hw_scan_req->ie = ies; - local->hw_scan_req->flags = req->flags; + local->hw_scan_req->req.ie = ies; + local->hw_scan_req->req.flags = req->flags; local->hw_scan_band = 0; @@ -976,6 +1006,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, struct ieee80211_sched_scan_ies sched_scan_ies = {}; struct cfg80211_chan_def chandef; int ret, i, iebufsz; + struct ieee80211_scan_ies dummy_ie_desc; iebufsz = local->scan_ies_len + req->ie_len; @@ -985,6 +1016,8 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, return -ENOTSUPP; for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + u32 rate_masks[IEEE80211_NUM_BANDS] = {}; + if (!local->hw.wiphy->bands[i]) continue; @@ -995,11 +1028,13 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, } ieee80211_prepare_scan_chandef(&chandef, req->scan_width); + rate_masks[i] = (u32) -1; sched_scan_ies.len[i] = ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], - iebufsz, req->ie, req->ie_len, - i, (u32) -1, &chandef); + iebufsz, &dummy_ie_desc, + req->ie, req->ie_len, BIT(i), + rate_masks, &chandef); } ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 42d448d765b4..e31458201278 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1219,14 +1219,17 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, } } -int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, - size_t buffer_len, const u8 *ie, size_t ie_len, - enum ieee80211_band band, u32 rate_mask, - struct cfg80211_chan_def *chandef) +static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, + u8 *buffer, size_t buffer_len, + const u8 *ie, size_t ie_len, + enum ieee80211_band band, + u32 rate_mask, + struct cfg80211_chan_def *chandef, + size_t *offset) { struct ieee80211_supported_band *sband; u8 *pos = buffer, *end = buffer + buffer_len; - size_t offset = 0, noffset; + size_t noffset; int supp_rates_len, i; u8 rates[32]; int num_rates; @@ -1234,6 +1237,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, int shift; u32 rate_flags; + *offset = 0; + sband = local->hw.wiphy->bands[band]; if (WARN_ON_ONCE(!sband)) return 0; @@ -1272,12 +1277,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, noffset = ieee80211_ie_split(ie, ie_len, before_extrates, ARRAY_SIZE(before_extrates), - offset); - if (end - pos < noffset - offset) + *offset); + if (end - pos < noffset - *offset) goto out_err; - memcpy(pos, ie + offset, noffset - offset); - pos += noffset - offset; - offset = noffset; + memcpy(pos, ie + *offset, noffset - *offset); + pos += noffset - *offset; + *offset = noffset; } ext_rates_len = num_rates - supp_rates_len; @@ -1311,12 +1316,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, }; noffset = ieee80211_ie_split(ie, ie_len, before_ht, ARRAY_SIZE(before_ht), - offset); - if (end - pos < noffset - offset) + *offset); + if (end - pos < noffset - *offset) goto out_err; - memcpy(pos, ie + offset, noffset - offset); - pos += noffset - offset; - offset = noffset; + memcpy(pos, ie + *offset, noffset - *offset); + pos += noffset - *offset; + *offset = noffset; } if (sband->ht_cap.ht_supported) { @@ -1351,12 +1356,12 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, }; noffset = ieee80211_ie_split(ie, ie_len, before_vht, ARRAY_SIZE(before_vht), - offset); - if (end - pos < noffset - offset) + *offset); + if (end - pos < noffset - *offset) goto out_err; - memcpy(pos, ie + offset, noffset - offset); - pos += noffset - offset; - offset = noffset; + memcpy(pos, ie + *offset, noffset - *offset); + pos += noffset - *offset; + *offset = noffset; } if (sband->vht_cap.vht_supported) { @@ -1366,21 +1371,54 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, sband->vht_cap.cap); } - /* add any remaining custom IEs */ - if (ie && ie_len) { - noffset = ie_len; - if (end - pos < noffset - offset) - goto out_err; - memcpy(pos, ie + offset, noffset - offset); - pos += noffset - offset; - } - return pos - buffer; out_err: WARN_ONCE(1, "not enough space for preq IEs\n"); return pos - buffer; } +int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, + size_t buffer_len, + struct ieee80211_scan_ies *ie_desc, + const u8 *ie, size_t ie_len, + u8 bands_used, u32 *rate_masks, + struct cfg80211_chan_def *chandef) +{ + size_t pos = 0, old_pos = 0, custom_ie_offset = 0; + int i; + + memset(ie_desc, 0, sizeof(*ie_desc)); + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + if (bands_used & BIT(i)) { + pos += ieee80211_build_preq_ies_band(local, + buffer + pos, + buffer_len - pos, + ie, ie_len, i, + rate_masks[i], + chandef, + &custom_ie_offset); + ie_desc->ies[i] = buffer + old_pos; + ie_desc->len[i] = pos - old_pos; + old_pos = pos; + } + } + + /* add any remaining custom IEs */ + if (ie && ie_len) { + if (WARN_ONCE(buffer_len - pos < ie_len - custom_ie_offset, + "not enough space for preq custom IEs\n")) + return pos; + memcpy(buffer + pos, ie + custom_ie_offset, + ie_len - custom_ie_offset); + ie_desc->common_ies = buffer + pos; + ie_desc->common_ie_len = ie_len - custom_ie_offset; + pos += ie_len - custom_ie_offset; + } + + return pos; +}; + struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, u32 ratemask, struct ieee80211_channel *chan, @@ -1393,6 +1431,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb; struct ieee80211_mgmt *mgmt; int ies_len; + u32 rate_masks[IEEE80211_NUM_BANDS] = {}; + struct ieee80211_scan_ies dummy_ie_desc; /* * Do not send DS Channel parameter for directed probe requests @@ -1410,10 +1450,11 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, if (!skb) return NULL; + rate_masks[chan->band] = ratemask; ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), - skb_tailroom(skb), - ie, ie_len, chan->band, - ratemask, &chandef); + skb_tailroom(skb), &dummy_ie_desc, + ie, ie_len, BIT(chan->band), + rate_masks, &chandef); skb_put(skb, ies_len); if (dst) { -- cgit v1.2.3 From 633e27132625a0692440c4db58b901fb3cb67c55 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Thu, 6 Feb 2014 16:15:23 +0200 Subject: mac80211: split sched scan IEs Split sched scan IEs to band specific and not band specific blocks. Common IEs blocks may be sent to the FW once per command, instead of per band. This allows optimization of size of the command, which may be required by some drivers (eg. iwlmvm with newer firmware version). As this changes the mac80211 API, update all drivers to use the new version correctly, even if they don't (yet) make use of the split data. Signed-off-by: David Spinadel Reviewed-by: Alexander Bondar Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 27 +++++++++++------ drivers/net/wireless/ti/wl12xx/scan.c | 20 +++++++----- drivers/net/wireless/ti/wl12xx/scan.h | 2 +- drivers/net/wireless/ti/wl18xx/scan.c | 16 +++++++--- drivers/net/wireless/ti/wl18xx/scan.h | 2 +- drivers/net/wireless/ti/wlcore/cmd.c | 11 ++++--- drivers/net/wireless/ti/wlcore/cmd.h | 3 +- drivers/net/wireless/ti/wlcore/main.c | 2 +- drivers/net/wireless/ti/wlcore/scan.h | 2 +- drivers/net/wireless/ti/wlcore/wlcore.h | 2 +- include/net/mac80211.h | 23 +++----------- net/mac80211/driver-ops.h | 2 +- net/mac80211/scan.c | 47 +++++++++++++++-------------- 15 files changed, 88 insertions(+), 75 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 4dc2e05f49ce..7dd363dd3ad3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1828,7 +1828,7 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) + struct ieee80211_scan_ies *ies) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fcc6c29482d0..97630f9a7cb9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -854,7 +854,7 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies); + struct ieee80211_scan_ies *ies); int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, struct cfg80211_sched_scan_request *req); int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 4b6c7d4bd199..3206fa097255 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -204,7 +204,8 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, */ static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, int n_ssids, const u8 *ssid, int ssid_len, - const u8 *ie, int ie_len, + const u8 *band_ie, int band_ie_len, + const u8 *common_ie, int common_ie_len, int left) { int len = 0; @@ -244,12 +245,19 @@ static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, len += ssid_len + 2; - if (WARN_ON(left < ie_len)) + if (WARN_ON(left < band_ie_len + common_ie_len)) return len; - if (ie && ie_len) { - memcpy(pos, ie, ie_len); - len += ie_len; + if (band_ie && band_ie_len) { + memcpy(pos, band_ie, band_ie_len); + pos += band_ie_len; + len += band_ie_len; + } + + if (common_ie && common_ie_len) { + memcpy(pos, common_ie, common_ie_len); + pos += common_ie_len; + len += common_ie_len; } return (u16)len; @@ -382,7 +390,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, (struct ieee80211_mgmt *)cmd->data, vif->addr, req->n_ssids, ssid, ssid_len, - req->ie, req->ie_len, + req->ie, req->ie_len, NULL, 0, mvm->fw->ucode_capa.max_probe_length)); iwl_mvm_scan_fill_channels(cmd, req, basic_ssid, ¶ms); @@ -561,7 +569,7 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_sched_scan_ies *ies, + struct ieee80211_scan_ies *ies, enum ieee80211_band band, struct iwl_tx_cmd *cmd, u8 *data) @@ -577,7 +585,8 @@ static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm, cmd_len = iwl_mvm_fill_probe_req((struct ieee80211_mgmt *)data, vif->addr, 1, NULL, 0, - ies->ie[band], ies->len[band], + ies->ies[band], ies->len[band], + ies->common_ies, ies->common_ie_len, SCAN_OFFLOAD_PROBE_REQ_SIZE); cmd->len = cpu_to_le16(cmd_len); } @@ -735,7 +744,7 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm, int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) + struct ieee80211_scan_ies *ies) { int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels; int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c index 7541bd1a4a4b..0c0d5cd98514 100644 --- a/drivers/net/wireless/ti/wl12xx/scan.c +++ b/drivers/net/wireless/ti/wl12xx/scan.c @@ -156,7 +156,7 @@ static int wl1271_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, cmd->params.role_id, band, wl->scan.ssid, wl->scan.ssid_len, wl->scan.req->ie, - wl->scan.req->ie_len, false); + wl->scan.req->ie_len, NULL, 0, false); if (ret < 0) { wl1271_error("PROBE request template failed"); goto out; @@ -317,7 +317,7 @@ static void wl12xx_adjust_channels(struct wl1271_cmd_sched_scan_config *cmd, int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) + struct ieee80211_scan_ies *ies) { struct wl1271_cmd_sched_scan_config *cfg = NULL; struct wlcore_scan_channels *cfg_channels = NULL; @@ -378,8 +378,11 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, wlvif->role_id, band, req->ssids[0].ssid, req->ssids[0].ssid_len, - ies->ie[band], - ies->len[band], true); + ies->ies[band], + ies->len[band], + ies->common_ies, + ies->common_ie_len, + true); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); goto out; @@ -392,8 +395,11 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, wlvif->role_id, band, req->ssids[0].ssid, req->ssids[0].ssid_len, - ies->ie[band], - ies->len[band], true); + ies->ies[band], + ies->len[band], + ies->common_ies, + ies->common_ie_len, + true); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); goto out; @@ -449,7 +455,7 @@ out_free: int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) + struct ieee80211_scan_ies *ies) { int ret; diff --git a/drivers/net/wireless/ti/wl12xx/scan.h b/drivers/net/wireless/ti/wl12xx/scan.h index 264af7ac2785..427f9af85a00 100644 --- a/drivers/net/wireless/ti/wl12xx/scan.h +++ b/drivers/net/wireless/ti/wl12xx/scan.h @@ -135,6 +135,6 @@ int wl12xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wl12xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl12xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies); + struct ieee80211_scan_ies *ies); void wl12xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); #endif diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c index 2b642f8c9266..98666f235a12 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.c +++ b/drivers/net/wireless/ti/wl18xx/scan.c @@ -113,6 +113,8 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, req->ssids ? req->ssids[0].ssid_len : 0, req->ie, req->ie_len, + NULL, + 0, false); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); @@ -128,6 +130,8 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, req->ssids ? req->ssids[0].ssid_len : 0, req->ie, req->ie_len, + NULL, + 0, false); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); @@ -161,7 +165,7 @@ static int wl18xx_scan_sched_scan_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) + struct ieee80211_scan_ies *ies) { struct wl18xx_cmd_scan_params *cmd; struct wlcore_scan_channels *cmd_channels = NULL; @@ -237,8 +241,10 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl, cmd->role_id, band, req->ssids ? req->ssids[0].ssid : NULL, req->ssids ? req->ssids[0].ssid_len : 0, - ies->ie[band], + ies->ies[band], ies->len[band], + ies->common_ies, + ies->common_ie_len, true); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); @@ -252,8 +258,10 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl, cmd->role_id, band, req->ssids ? req->ssids[0].ssid : NULL, req->ssids ? req->ssids[0].ssid_len : 0, - ies->ie[band], + ies->ies[band], ies->len[band], + ies->common_ies, + ies->common_ie_len, true); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); @@ -277,7 +285,7 @@ out: int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) + struct ieee80211_scan_ies *ies) { return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies); } diff --git a/drivers/net/wireless/ti/wl18xx/scan.h b/drivers/net/wireless/ti/wl18xx/scan.h index eadee42689d1..2e636aa5dba9 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.h +++ b/drivers/net/wireless/ti/wl18xx/scan.h @@ -122,6 +122,6 @@ int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies); + struct ieee80211_scan_ies *ies); void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif); #endif diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 40dc30f4faaa..e269c0a57017 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -1124,7 +1124,8 @@ out: int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, u8 band, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len, bool sched_scan) + const u8 *ie0, size_t ie0_len, const u8 *ie1, + size_t ie1_len, bool sched_scan) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb; @@ -1136,13 +1137,15 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, wl1271_debug(DEBUG_SCAN, "build probe request band %d", band); skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, - ie_len); + ie0_len + ie1_len); if (!skb) { ret = -ENOMEM; goto out; } - if (ie_len) - memcpy(skb_put(skb, ie_len), ie, ie_len); + if (ie0_len) + memcpy(skb_put(skb, ie0_len), ie0, ie0_len); + if (ie1_len) + memcpy(skb_put(skb, ie1_len), ie1, ie1_len); if (sched_scan && (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index b084830a61cf..6788d7356ca5 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -64,7 +64,8 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, u8 band, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len, bool sched_scan); + const u8 *ie, size_t ie_len, const u8 *common_ie, + size_t common_ie_len, bool sched_scan); struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct sk_buff *skb); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index e5ffb8b91dd4..48f83868f9cb 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -3637,7 +3637,7 @@ out: static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) + struct ieee80211_scan_ies *ies) { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); diff --git a/drivers/net/wireless/ti/wlcore/scan.h b/drivers/net/wireless/ti/wlcore/scan.h index a6ab24b5c0f9..4dadd0c62cde 100644 --- a/drivers/net/wireless/ti/wlcore/scan.h +++ b/drivers/net/wireless/ti/wlcore/scan.h @@ -37,7 +37,7 @@ void wl1271_scan_complete_work(struct work_struct *work); int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies); + struct ieee80211_scan_ies *ies); int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wlcore_scan_sched_scan_results(struct wl1271 *wl); diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 95a54504f0cc..71320509b56d 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -95,7 +95,7 @@ struct wlcore_ops { int (*scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif); int (*sched_scan_start)(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies); + struct ieee80211_scan_ies *ies); void (*sched_scan_stop)(struct wl1271 *wl, struct wl12xx_vif *wlvif); int (*get_spare_blocks)(struct wl1271 *wl, bool is_gem); int (*set_key)(struct wl1271 *wl, enum set_key_cmd cmd, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9536ee3e22a9..545d2fa179c4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -753,27 +753,12 @@ struct ieee80211_tx_info { }; }; -/** - * struct ieee80211_sched_scan_ies - scheduled scan IEs - * - * This structure is used to pass the appropriate IEs to be used in scheduled - * scans for all bands. It contains both the IEs passed from the userspace - * and the ones generated by mac80211. - * - * @ie: array with the IEs for each supported band - * @len: array with the total length of the IEs for each band - */ -struct ieee80211_sched_scan_ies { - u8 *ie[IEEE80211_NUM_BANDS]; - size_t len[IEEE80211_NUM_BANDS]; -}; - /** * struct ieee80211_scan_ies - descriptors for different blocks of IEs * - * This structure is used to point to different blocks of IEs in HW scan. - * These blocks contain the IEs passed by userspace and the ones generated - * by mac80211. + * This structure is used to point to different blocks of IEs in HW scan + * and scheduled scan. These blocks contain the IEs passed by userspace + * and the ones generated by mac80211. * * @ies: pointers to band specific IEs. * @len: lengths of band_specific IEs. @@ -2917,7 +2902,7 @@ struct ieee80211_ops { int (*sched_scan_start)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies); + struct ieee80211_scan_ies *ies); int (*sched_scan_stop)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*sw_scan_start)(struct ieee80211_hw *hw); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index faa0d90f6e80..11423958116a 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -346,7 +346,7 @@ static inline int drv_sched_scan_start(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) + struct ieee80211_scan_ies *ies) { int ret; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 116959e070d0..a0a938145dcc 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -1003,10 +1003,13 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, struct cfg80211_sched_scan_request *req) { struct ieee80211_local *local = sdata->local; - struct ieee80211_sched_scan_ies sched_scan_ies = {}; + struct ieee80211_scan_ies sched_scan_ies = {}; struct cfg80211_chan_def chandef; - int ret, i, iebufsz; - struct ieee80211_scan_ies dummy_ie_desc; + int ret, i, iebufsz, num_bands = 0; + u32 rate_masks[IEEE80211_NUM_BANDS] = {}; + u8 bands_used = 0; + u8 *ie; + size_t len; iebufsz = local->scan_ies_len + req->ie_len; @@ -1016,37 +1019,35 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, return -ENOTSUPP; for (i = 0; i < IEEE80211_NUM_BANDS; i++) { - u32 rate_masks[IEEE80211_NUM_BANDS] = {}; - - if (!local->hw.wiphy->bands[i]) - continue; - - sched_scan_ies.ie[i] = kzalloc(iebufsz, GFP_KERNEL); - if (!sched_scan_ies.ie[i]) { - ret = -ENOMEM; - goto out_free; + if (local->hw.wiphy->bands[i]) { + bands_used |= BIT(i); + rate_masks[i] = (u32) -1; + num_bands++; } + } - ieee80211_prepare_scan_chandef(&chandef, req->scan_width); - rate_masks[i] = (u32) -1; - - sched_scan_ies.len[i] = - ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], - iebufsz, &dummy_ie_desc, - req->ie, req->ie_len, BIT(i), - rate_masks, &chandef); + ie = kzalloc(num_bands * iebufsz, GFP_KERNEL); + if (!ie) { + ret = -ENOMEM; + goto out; } + ieee80211_prepare_scan_chandef(&chandef, req->scan_width); + + len = ieee80211_build_preq_ies(local, ie, num_bands * iebufsz, + &sched_scan_ies, req->ie, + req->ie_len, bands_used, + rate_masks, &chandef); + ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); if (ret == 0) { rcu_assign_pointer(local->sched_scan_sdata, sdata); local->sched_scan_req = req; } -out_free: - while (i > 0) - kfree(sched_scan_ies.ie[--i]); + kfree(ie); +out: if (ret) { /* Clean in case of failure after HW restart or upon resume. */ RCU_INIT_POINTER(local->sched_scan_sdata, NULL); -- cgit v1.2.3 From 397304b52d9b726a4aed0bf9086612bba429d420 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 20 Jun 2014 22:38:58 +0200 Subject: netfilter: ctnetlink: remove null test before kfree Fix checkpatch warning: WARNING: kfree(NULL) is safe this check is probably not required Signed-off-by: Fabian Frederick Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_netlink.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 58579634427d..aee017f625d9 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -742,8 +742,7 @@ static int ctnetlink_done(struct netlink_callback *cb) { if (cb->args[1]) nf_ct_put((struct nf_conn *)cb->args[1]); - if (cb->data) - kfree(cb->data); + kfree(cb->data); return 0; } -- cgit v1.2.3 From f6b50824f7d85f72285c17fec66076a36907089f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 24 Jun 2014 02:15:35 -0700 Subject: netfilter: x_tables: xt_free_table_info() cleanup kvfree() helper can make xt_free_table_info() much cleaner. Signed-off-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso --- net/netfilter/x_tables.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 227aa11e8409..47b978bc3100 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -711,28 +711,15 @@ void xt_free_table_info(struct xt_table_info *info) { int cpu; - for_each_possible_cpu(cpu) { - if (info->size <= PAGE_SIZE) - kfree(info->entries[cpu]); - else - vfree(info->entries[cpu]); - } + for_each_possible_cpu(cpu) + kvfree(info->entries[cpu]); if (info->jumpstack != NULL) { - if (sizeof(void *) * info->stacksize > PAGE_SIZE) { - for_each_possible_cpu(cpu) - vfree(info->jumpstack[cpu]); - } else { - for_each_possible_cpu(cpu) - kfree(info->jumpstack[cpu]); - } + for_each_possible_cpu(cpu) + kvfree(info->jumpstack[cpu]); + kvfree(info->jumpstack); } - if (sizeof(void **) * nr_cpu_ids > PAGE_SIZE) - vfree(info->jumpstack); - else - kfree(info->jumpstack); - free_percpu(info->stackptr); kfree(info); -- cgit v1.2.3 From 5bcae31d9cb1ebfad3ad5a3eea04c8cdc329a04f Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 25 Jun 2014 12:35:06 +0200 Subject: mac80211: implement multi-vif in-place reservations Multi-vif in-place reservations happen when it is impossible to allocate more channel contexts as indicated by interface combinations. Such reservations are not finalized until all assigned interfaces are ready. This still doesn't handle all possible cases (i.e. degradation of number of channels) properly. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- include/net/mac80211.h | 8 +- net/mac80211/chan.c | 765 ++++++++++++++++++++++++++++++++++++++++----- net/mac80211/ieee80211_i.h | 26 +- net/mac80211/util.c | 9 +- 4 files changed, 716 insertions(+), 92 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 545d2fa179c4..9ce5cb17ed82 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1606,12 +1606,6 @@ struct ieee80211_tx_control { * is not enabled the default action is to disconnect when getting the * CSA frame. * - * @IEEE80211_HW_CHANGE_RUNNING_CHANCTX: The hardware can change a - * channel context on-the-fly. This is needed for channel switch - * on single-channel hardware. It can also be used as an - * optimization in certain channel switch cases with - * multi-channel. - * * @IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS: The HW supports scanning on all bands * in one command, mac80211 doesn't have to run separate scans per band. */ @@ -1645,7 +1639,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26, IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27, IEEE80211_HW_CHANCTX_STA_CSA = 1<<28, - IEEE80211_HW_CHANGE_RUNNING_CHANCTX = 1<<29, + /* bit 29 unused */ IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS = 1<<30, }; diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index a310e33972de..0e4302bb5b34 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -63,6 +63,20 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local) return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local); } +static struct ieee80211_chanctx * +ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *conf; + + conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (!conf) + return NULL; + + return container_of(conf, struct ieee80211_chanctx, conf); +} + static const struct cfg80211_chan_def * ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, @@ -160,6 +174,9 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local, return NULL; list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) + continue; + if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) continue; @@ -347,6 +364,9 @@ ieee80211_find_chanctx(struct ieee80211_local *local, list_for_each_entry(ctx, &local->chanctx_list, list) { const struct cfg80211_chan_def *compat; + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACE_NONE) + continue; + if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) continue; @@ -622,6 +642,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; + bool use_reserved_switch = false; lockdep_assert_held(&local->chanctx_mtx); @@ -632,12 +653,23 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) ctx = container_of(conf, struct ieee80211_chanctx, conf); - if (sdata->reserved_chanctx) + if (sdata->reserved_chanctx) { + if (sdata->reserved_chanctx->replace_state == + IEEE80211_CHANCTX_REPLACES_OTHER && + ieee80211_chanctx_num_reserved(local, + sdata->reserved_chanctx) > 1) + use_reserved_switch = true; + ieee80211_vif_unreserve_chanctx(sdata); + } ieee80211_assign_vif_chanctx(sdata, NULL); if (ieee80211_chanctx_refcount(local, ctx) == 0) ieee80211_free_chanctx(local, ctx); + + /* Unreserving may ready an in-place reservation. */ + if (use_reserved_switch) + ieee80211_vif_use_reserved_switch(local); } void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, @@ -905,8 +937,25 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata) list_del(&sdata->reserved_chanctx_list); sdata->reserved_chanctx = NULL; - if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) - ieee80211_free_chanctx(sdata->local, ctx); + if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) { + if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) { + if (WARN_ON(!ctx->replace_ctx)) + return -EINVAL; + + WARN_ON(ctx->replace_ctx->replace_state != + IEEE80211_CHANCTX_WILL_BE_REPLACED); + WARN_ON(ctx->replace_ctx->replace_ctx != ctx); + + ctx->replace_ctx->replace_ctx = NULL; + ctx->replace_ctx->replace_state = + IEEE80211_CHANCTX_REPLACE_NONE; + + list_del_rcu(&ctx->list); + kfree_rcu(ctx, rcu_head); + } else { + ieee80211_free_chanctx(sdata->local, ctx); + } + } return 0; } @@ -917,40 +966,84 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, bool radar_required) { struct ieee80211_local *local = sdata->local; - struct ieee80211_chanctx_conf *conf; - struct ieee80211_chanctx *new_ctx, *curr_ctx; - int ret = 0; + struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx; - mutex_lock(&local->chanctx_mtx); - - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, - lockdep_is_held(&local->chanctx_mtx)); - if (!conf) { - ret = -EINVAL; - goto out; - } + lockdep_assert_held(&local->chanctx_mtx); - curr_ctx = container_of(conf, struct ieee80211_chanctx, conf); + curr_ctx = ieee80211_vif_get_chanctx(sdata); + if (curr_ctx && local->use_chanctx && !local->ops->switch_vif_chanctx) + return -ENOTSUPP; new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode); if (!new_ctx) { - if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 && - (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) { - /* if we're the only users of the chanctx and - * the driver supports changing a running - * context, reserve our current context - */ - new_ctx = curr_ctx; - } else if (ieee80211_can_create_new_chanctx(local)) { - /* create a new context and reserve it */ + if (ieee80211_can_create_new_chanctx(local)) { new_ctx = ieee80211_new_chanctx(local, chandef, mode); - if (IS_ERR(new_ctx)) { - ret = PTR_ERR(new_ctx); - goto out; - } + if (IS_ERR(new_ctx)) + return PTR_ERR(new_ctx); } else { - ret = -EBUSY; - goto out; + if (!curr_ctx || + (curr_ctx->replace_state == + IEEE80211_CHANCTX_WILL_BE_REPLACED) || + !list_empty(&curr_ctx->reserved_vifs)) { + /* + * Another vif already requested this context + * for a reservation. Find another one hoping + * all vifs assigned to it will also switch + * soon enough. + * + * TODO: This needs a little more work as some + * cases (more than 2 chanctx capable devices) + * may fail which could otherwise succeed + * provided some channel context juggling was + * performed. + * + * Consider ctx1..3, vif1..6, each ctx has 2 + * vifs. vif1 and vif2 from ctx1 request new + * different chandefs starting 2 in-place + * reserations with ctx4 and ctx5 replacing + * ctx1 and ctx2 respectively. Next vif5 and + * vif6 from ctx3 reserve ctx4. If vif3 and + * vif4 remain on ctx2 as they are then this + * fails unless `replace_ctx` from ctx5 is + * replaced with ctx3. + */ + list_for_each_entry(ctx, &local->chanctx_list, + list) { + if (ctx->replace_state != + IEEE80211_CHANCTX_REPLACE_NONE) + continue; + + if (!list_empty(&ctx->reserved_vifs)) + continue; + + curr_ctx = ctx; + break; + } + } + + /* + * If that's true then all available contexts already + * have reservations and cannot be used. + */ + if (!curr_ctx || + (curr_ctx->replace_state == + IEEE80211_CHANCTX_WILL_BE_REPLACED) || + !list_empty(&curr_ctx->reserved_vifs)) + return -EBUSY; + + new_ctx = ieee80211_alloc_chanctx(local, chandef, mode); + if (!new_ctx) + return -ENOMEM; + + new_ctx->replace_ctx = curr_ctx; + new_ctx->replace_state = + IEEE80211_CHANCTX_REPLACES_OTHER; + + curr_ctx->replace_ctx = new_ctx; + curr_ctx->replace_state = + IEEE80211_CHANCTX_WILL_BE_REPLACED; + + list_add_rcu(&new_ctx->list, &local->chanctx_list); } } @@ -958,82 +1051,567 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, sdata->reserved_chanctx = new_ctx; sdata->reserved_chandef = *chandef; sdata->reserved_radar_required = radar_required; -out: - mutex_unlock(&local->chanctx_mtx); - return ret; + sdata->reserved_ready = false; + + return 0; } -int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata, - u32 *changed) +static int +ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; - struct ieee80211_chanctx *ctx; - struct ieee80211_chanctx *old_ctx; - struct ieee80211_chanctx_conf *conf; - int ret; - u32 tmp_changed = *changed; - - /* TODO: need to recheck if the chandef is usable etc.? */ + struct ieee80211_vif_chanctx_switch vif_chsw[1] = {}; + struct ieee80211_chanctx *old_ctx, *new_ctx; + const struct cfg80211_chan_def *chandef; + u32 changed = 0; + int err; lockdep_assert_held(&local->mtx); + lockdep_assert_held(&local->chanctx_mtx); - mutex_lock(&local->chanctx_mtx); + new_ctx = sdata->reserved_chanctx; + old_ctx = ieee80211_vif_get_chanctx(sdata); - ctx = sdata->reserved_chanctx; - if (WARN_ON(!ctx)) { - ret = -EINVAL; - goto out; - } + if (WARN_ON(!sdata->reserved_ready)) + return -EBUSY; - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, - lockdep_is_held(&local->chanctx_mtx)); - if (!conf) { - ret = -EINVAL; - goto out; + if (WARN_ON(!new_ctx)) + return -EINVAL; + + if (WARN_ON(!old_ctx)) + return -EINVAL; + + if (WARN_ON(new_ctx->replace_state == + IEEE80211_CHANCTX_REPLACES_OTHER)) + return -EINVAL; + + chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, + &sdata->reserved_chandef); + if (WARN_ON(!chandef)) + return -EINVAL; + + vif_chsw[0].vif = &sdata->vif; + vif_chsw[0].old_ctx = &old_ctx->conf; + vif_chsw[0].new_ctx = &new_ctx->conf; + + list_del(&sdata->reserved_chanctx_list); + sdata->reserved_chanctx = NULL; + + err = drv_switch_vif_chanctx(local, vif_chsw, 1, + CHANCTX_SWMODE_REASSIGN_VIF); + if (err) { + if (ieee80211_chanctx_refcount(local, new_ctx) == 0) + ieee80211_free_chanctx(local, new_ctx); + + return err; } - old_ctx = container_of(conf, struct ieee80211_chanctx, conf); + list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs); + rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf); + + if (sdata->vif.type == NL80211_IFTYPE_AP) + __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); + + if (ieee80211_chanctx_refcount(local, old_ctx) == 0) + ieee80211_free_chanctx(local, old_ctx); if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width) - tmp_changed |= BSS_CHANGED_BANDWIDTH; + changed = BSS_CHANGED_BANDWIDTH; sdata->vif.bss_conf.chandef = sdata->reserved_chandef; - /* unref our reservation */ - sdata->reserved_chanctx = NULL; - sdata->radar_required = sdata->reserved_radar_required; + if (changed) + ieee80211_bss_info_change_notify(sdata, changed); + + return err; +} + +static int +ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx *old_ctx, *new_ctx; + const struct cfg80211_chan_def *chandef; + int err; + + old_ctx = ieee80211_vif_get_chanctx(sdata); + new_ctx = sdata->reserved_chanctx; + + if (WARN_ON(!sdata->reserved_ready)) + return -EINVAL; + + if (WARN_ON(old_ctx)) + return -EINVAL; + + if (WARN_ON(!new_ctx)) + return -EINVAL; + + if (WARN_ON(new_ctx->replace_state == + IEEE80211_CHANCTX_REPLACES_OTHER)) + return -EINVAL; + + chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, + &sdata->reserved_chandef); + if (WARN_ON(!chandef)) + return -EINVAL; + list_del(&sdata->reserved_chanctx_list); + sdata->reserved_chanctx = NULL; - if (old_ctx == ctx) { - /* This is our own context, just change it */ - ret = __ieee80211_vif_change_channel(sdata, old_ctx, - &tmp_changed); - if (ret) - goto out; - } else { - ret = ieee80211_assign_vif_chanctx(sdata, ctx); - if (ieee80211_chanctx_refcount(local, old_ctx) == 0) - ieee80211_free_chanctx(local, old_ctx); - if (ret) { - /* if assign fails refcount stays the same */ - if (ieee80211_chanctx_refcount(local, ctx) == 0) - ieee80211_free_chanctx(local, ctx); + err = ieee80211_assign_vif_chanctx(sdata, new_ctx); + if (err) { + if (ieee80211_chanctx_refcount(local, new_ctx) == 0) + ieee80211_free_chanctx(local, new_ctx); + + goto out; + } + +out: + return err; +} + +static bool +ieee80211_vif_has_in_place_reservation(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_chanctx *old_ctx, *new_ctx; + + lockdep_assert_held(&sdata->local->chanctx_mtx); + + new_ctx = sdata->reserved_chanctx; + old_ctx = ieee80211_vif_get_chanctx(sdata); + + if (!old_ctx) + return false; + + if (WARN_ON(!new_ctx)) + return false; + + if (old_ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED) + return false; + + if (new_ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) + return false; + + return true; +} + +static int ieee80211_chsw_switch_hwconf(struct ieee80211_local *local, + struct ieee80211_chanctx *new_ctx) +{ + const struct cfg80211_chan_def *chandef; + + lockdep_assert_held(&local->mtx); + lockdep_assert_held(&local->chanctx_mtx); + + chandef = ieee80211_chanctx_reserved_chandef(local, new_ctx, NULL); + if (WARN_ON(!chandef)) + return -EINVAL; + + local->hw.conf.radar_enabled = new_ctx->conf.radar_enabled; + local->_oper_chandef = *chandef; + ieee80211_hw_config(local, 0); + + return 0; +} + +static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local, + int n_vifs) +{ + struct ieee80211_vif_chanctx_switch *vif_chsw; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_chanctx *ctx, *old_ctx; + int i, err; + + lockdep_assert_held(&local->mtx); + lockdep_assert_held(&local->chanctx_mtx); + + vif_chsw = kzalloc(sizeof(vif_chsw[0]) * n_vifs, GFP_KERNEL); + if (!vif_chsw) + return -ENOMEM; + + i = 0; + list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) + continue; + + if (WARN_ON(!ctx->replace_ctx)) { + err = -EINVAL; goto out; } - if (sdata->vif.type == NL80211_IFTYPE_AP) - __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); + list_for_each_entry(sdata, &ctx->reserved_vifs, + reserved_chanctx_list) { + if (!ieee80211_vif_has_in_place_reservation( + sdata)) + continue; + + old_ctx = ieee80211_vif_get_chanctx(sdata); + vif_chsw[i].vif = &sdata->vif; + vif_chsw[i].old_ctx = &old_ctx->conf; + vif_chsw[i].new_ctx = &ctx->conf; + + i++; + } } - *changed = tmp_changed; + err = drv_switch_vif_chanctx(local, vif_chsw, n_vifs, + CHANCTX_SWMODE_SWAP_CONTEXTS); - ieee80211_recalc_chanctx_chantype(local, ctx); - ieee80211_recalc_smps_chanctx(local, ctx); - ieee80211_recalc_radar_chanctx(local, ctx); - ieee80211_recalc_chanctx_min_def(local, ctx); out: - mutex_unlock(&local->chanctx_mtx); - return ret; + kfree(vif_chsw); + return err; +} + +static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local) +{ + struct ieee80211_chanctx *ctx; + int err; + + lockdep_assert_held(&local->mtx); + lockdep_assert_held(&local->chanctx_mtx); + + list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) + continue; + + if (!list_empty(&ctx->replace_ctx->assigned_vifs)) + continue; + + ieee80211_del_chanctx(local, ctx->replace_ctx); + err = ieee80211_add_chanctx(local, ctx); + if (err) + goto err; + } + + return 0; + +err: + WARN_ON(ieee80211_add_chanctx(local, ctx)); + list_for_each_entry_continue_reverse(ctx, &local->chanctx_list, list) { + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) + continue; + + if (!list_empty(&ctx->replace_ctx->assigned_vifs)) + continue; + + ieee80211_del_chanctx(local, ctx); + WARN_ON(ieee80211_add_chanctx(local, ctx->replace_ctx)); + } + + return err; +} + +int +ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) +{ + struct ieee80211_sub_if_data *sdata, *sdata_tmp; + struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx; + struct ieee80211_chanctx *new_ctx = NULL; + int i, err, n_assigned, n_reserved, n_ready; + int n_ctx = 0, n_vifs_switch = 0, n_vifs_assign = 0, n_vifs_ctxless = 0; + + lockdep_assert_held(&local->mtx); + lockdep_assert_held(&local->chanctx_mtx); + + /* + * If there are 2 independent pairs of channel contexts performing + * cross-switch of their vifs this code will still wait until both are + * ready even though it could be possible to switch one before the + * other is ready. + * + * For practical reasons and code simplicity just do a single huge + * switch. + */ + + /* + * Verify if the reservation is still feasible. + * - if it's not then disconnect + * - if it is but not all vifs necessary are ready then defer + */ + + list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) + continue; + + if (WARN_ON(!ctx->replace_ctx)) { + err = -EINVAL; + goto err; + } + + if (!local->use_chanctx) + new_ctx = ctx; + + n_ctx++; + + n_assigned = 0; + n_reserved = 0; + n_ready = 0; + + list_for_each_entry(sdata, &ctx->replace_ctx->assigned_vifs, + assigned_chanctx_list) { + n_assigned++; + if (sdata->reserved_chanctx) { + n_reserved++; + if (sdata->reserved_ready) + n_ready++; + } + } + + if (n_assigned != n_reserved) { + if (n_ready == n_reserved) { + wiphy_info(local->hw.wiphy, + "channel context reservation cannot be finalized because some interfaces aren't switching\n"); + err = -EBUSY; + goto err; + } + + return -EAGAIN; + } + + ctx->conf.radar_enabled = false; + list_for_each_entry(sdata, &ctx->reserved_vifs, + reserved_chanctx_list) { + if (ieee80211_vif_has_in_place_reservation(sdata) && + !sdata->reserved_ready) + return -EAGAIN; + + old_ctx = ieee80211_vif_get_chanctx(sdata); + if (old_ctx) { + if (old_ctx->replace_state == + IEEE80211_CHANCTX_WILL_BE_REPLACED) + n_vifs_switch++; + else + n_vifs_assign++; + } else { + n_vifs_ctxless++; + } + + if (sdata->reserved_radar_required) + ctx->conf.radar_enabled = true; + } + } + + if (WARN_ON(n_ctx == 0) || + WARN_ON(n_vifs_switch == 0 && + n_vifs_assign == 0 && + n_vifs_ctxless == 0) || + WARN_ON(n_ctx > 1 && !local->use_chanctx) || + WARN_ON(!new_ctx && !local->use_chanctx)) { + err = -EINVAL; + goto err; + } + + /* + * All necessary vifs are ready. Perform the switch now depending on + * reservations and driver capabilities. + */ + + if (local->use_chanctx) { + if (n_vifs_switch > 0) { + err = ieee80211_chsw_switch_vifs(local, n_vifs_switch); + if (err) + goto err; + } + + if (n_vifs_assign > 0 || n_vifs_ctxless > 0) { + err = ieee80211_chsw_switch_ctxs(local); + if (err) + goto err; + } + } else { + err = ieee80211_chsw_switch_hwconf(local, new_ctx); + if (err) + goto err; + } + + /* + * Update all structures, values and pointers to point to new channel + * context(s). + */ + + i = 0; + list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) + continue; + + if (WARN_ON(!ctx->replace_ctx)) { + err = -EINVAL; + goto err; + } + + list_for_each_entry(sdata, &ctx->reserved_vifs, + reserved_chanctx_list) { + u32 changed = 0; + + if (!ieee80211_vif_has_in_place_reservation(sdata)) + continue; + + rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); + + if (sdata->vif.type == NL80211_IFTYPE_AP) + __ieee80211_vif_copy_chanctx_to_vlans(sdata, + false); + + sdata->radar_required = sdata->reserved_radar_required; + + if (sdata->vif.bss_conf.chandef.width != + sdata->reserved_chandef.width) + changed = BSS_CHANGED_BANDWIDTH; + + sdata->vif.bss_conf.chandef = sdata->reserved_chandef; + if (changed) + ieee80211_bss_info_change_notify(sdata, + changed); + + ieee80211_recalc_txpower(sdata); + } + + ieee80211_recalc_chanctx_chantype(local, ctx); + ieee80211_recalc_smps_chanctx(local, ctx); + ieee80211_recalc_radar_chanctx(local, ctx); + ieee80211_recalc_chanctx_min_def(local, ctx); + + list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, + reserved_chanctx_list) { + if (ieee80211_vif_get_chanctx(sdata) != ctx) + continue; + + list_del(&sdata->reserved_chanctx_list); + list_move(&sdata->assigned_chanctx_list, + &new_ctx->assigned_vifs); + sdata->reserved_chanctx = NULL; + } + + /* + * This context might have been a dependency for an already + * ready re-assign reservation interface that was deferred. Do + * not propagate error to the caller though. The in-place + * reservation for originally requested interface has already + * succeeded at this point. + */ + list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, + reserved_chanctx_list) { + if (WARN_ON(ieee80211_vif_has_in_place_reservation( + sdata))) + continue; + + if (WARN_ON(sdata->reserved_chanctx != ctx)) + continue; + + if (!sdata->reserved_ready) + continue; + + if (ieee80211_vif_get_chanctx(sdata)) + err = ieee80211_vif_use_reserved_reassign( + sdata); + else + err = ieee80211_vif_use_reserved_assign(sdata); + + if (err) { + sdata_info(sdata, + "failed to finalize (re-)assign reservation (err=%d)\n", + err); + ieee80211_vif_unreserve_chanctx(sdata); + cfg80211_stop_iface(local->hw.wiphy, + &sdata->wdev, + GFP_KERNEL); + } + } + } + + /* + * Finally free old contexts + */ + + list_for_each_entry_safe(ctx, ctx_tmp, &local->chanctx_list, list) { + if (ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED) + continue; + + ctx->replace_ctx->replace_ctx = NULL; + ctx->replace_ctx->replace_state = + IEEE80211_CHANCTX_REPLACE_NONE; + + list_del_rcu(&ctx->list); + kfree_rcu(ctx, rcu_head); + } + + return 0; + +err: + list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) + continue; + + list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, + reserved_chanctx_list) + ieee80211_vif_unreserve_chanctx(sdata); + } + + return err; +} + +int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx *new_ctx; + struct ieee80211_chanctx *old_ctx; + int err; + + lockdep_assert_held(&local->mtx); + lockdep_assert_held(&local->chanctx_mtx); + + new_ctx = sdata->reserved_chanctx; + old_ctx = ieee80211_vif_get_chanctx(sdata); + + if (WARN_ON(!new_ctx)) + return -EINVAL; + + if (WARN_ON(new_ctx->replace_state == + IEEE80211_CHANCTX_WILL_BE_REPLACED)) + return -EINVAL; + + if (WARN_ON(sdata->reserved_ready)) + return -EINVAL; + + sdata->reserved_ready = true; + + if (new_ctx->replace_state == IEEE80211_CHANCTX_REPLACE_NONE) { + if (old_ctx) + err = ieee80211_vif_use_reserved_reassign(sdata); + else + err = ieee80211_vif_use_reserved_assign(sdata); + + if (err) + return err; + } + + /* + * In-place reservation may need to be finalized now either if: + * a) sdata is taking part in the swapping itself and is the last one + * b) sdata has switched with a re-assign reservation to an existing + * context readying in-place switching of old_ctx + * + * In case of (b) do not propagate the error up because the requested + * sdata already switched successfully. Just spill an extra warning. + * The ieee80211_vif_use_reserved_switch() already stops all necessary + * interfaces upon failure. + */ + if ((old_ctx && + old_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) || + new_ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) { + err = ieee80211_vif_use_reserved_switch(local); + if (err && err != -EAGAIN) { + if (new_ctx->replace_state == + IEEE80211_CHANCTX_REPLACES_OTHER) + return err; + + wiphy_info(local->hw.wiphy, + "depending in-place reservation failed (err=%d)\n", + err); + } + } + + return 0; } int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, @@ -1043,6 +1621,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; + const struct cfg80211_chan_def *compat; int ret; if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, @@ -1069,11 +1648,33 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, } ctx = container_of(conf, struct ieee80211_chanctx, conf); - if (!cfg80211_chandef_compatible(&conf->def, chandef)) { + + compat = cfg80211_chandef_compatible(&conf->def, chandef); + if (!compat) { ret = -EINVAL; goto out; } + switch (ctx->replace_state) { + case IEEE80211_CHANCTX_REPLACE_NONE: + if (!ieee80211_chanctx_reserved_chandef(local, ctx, compat)) { + ret = -EBUSY; + goto out; + } + break; + case IEEE80211_CHANCTX_WILL_BE_REPLACED: + /* TODO: Perhaps the bandwith change could be treated as a + * reservation itself? */ + ret = -EBUSY; + goto out; + case IEEE80211_CHANCTX_REPLACES_OTHER: + /* channel context that is going to replace another channel + * context doesn't really exist and shouldn't be assigned + * anywhere yet */ + WARN_ON(1); + break; + } + sdata->vif.bss_conf.chandef = *chandef; ieee80211_recalc_chanctx_chantype(local, ctx); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f88bd1659cde..c26955f6c14d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -701,6 +701,24 @@ enum ieee80211_chanctx_mode { IEEE80211_CHANCTX_EXCLUSIVE }; +/** + * enum ieee80211_chanctx_replace_state - channel context replacement state + * + * This is used for channel context in-place reservations that require channel + * context switch/swap. + * + * @IEEE80211_CHANCTX_REPLACE_NONE: no replacement is taking place + * @IEEE80211_CHANCTX_WILL_BE_REPLACED: this channel context will be replaced + * by a (not yet registered) channel context pointed by %replace_ctx. + * @IEEE80211_CHANCTX_REPLACES_OTHER: this (not yet registered) channel context + * replaces an existing channel context pointed to by %replace_ctx. + */ +enum ieee80211_chanctx_replace_state { + IEEE80211_CHANCTX_REPLACE_NONE, + IEEE80211_CHANCTX_WILL_BE_REPLACED, + IEEE80211_CHANCTX_REPLACES_OTHER, +}; + struct ieee80211_chanctx { struct list_head list; struct rcu_head rcu_head; @@ -708,6 +726,9 @@ struct ieee80211_chanctx { struct list_head assigned_vifs; struct list_head reserved_vifs; + enum ieee80211_chanctx_replace_state replace_state; + struct ieee80211_chanctx *replace_ctx; + enum ieee80211_chanctx_mode mode; bool driver_present; @@ -778,6 +799,7 @@ struct ieee80211_sub_if_data { struct ieee80211_chanctx *reserved_chanctx; struct cfg80211_chan_def reserved_chandef; bool reserved_radar_required; + bool reserved_ready; /* used to reconfigure hardware SM PS */ struct work_struct recalc_smps; @@ -1820,9 +1842,9 @@ ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, enum ieee80211_chanctx_mode mode, bool radar_required); int __must_check -ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata, - u32 *changed); +ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata); int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata); +int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local); int __must_check ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e31458201278..1b42aa16ec03 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1698,7 +1698,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) if (local->use_chanctx) { mutex_lock(&local->chanctx_mtx); list_for_each_entry(ctx, &local->chanctx_list, list) - WARN_ON(drv_add_chanctx(local, ctx)); + if (ctx->replace_state != + IEEE80211_CHANCTX_REPLACES_OTHER) + WARN_ON(drv_add_chanctx(local, ctx)); mutex_unlock(&local->chanctx_mtx); list_for_each_entry(sdata, &local->interfaces, list) { @@ -2972,6 +2974,8 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, num[iftype] = 1; list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) + continue; if (ctx->conf.radar_enabled) radar_detect |= BIT(ctx->conf.def.width); if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { @@ -3030,6 +3034,9 @@ int ieee80211_max_num_channels(struct ieee80211_local *local) lockdep_assert_held(&local->chanctx_mtx); list_for_each_entry(ctx, &local->chanctx_list, list) { + if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) + continue; + num_different_channels++; if (ctx->conf.radar_enabled) -- cgit v1.2.3 From 71e6195ed2541d764fb0d7ef39cdb2236817116b Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 25 Jun 2014 12:35:07 +0200 Subject: mac80211: make check_combinations() aware of chanctx reservation The ieee80211_check_combinations() computes radar_detect accordingly depending on chanctx reservation status. This makes it possible to use the function for channel_switch validation. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/util.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 1b42aa16ec03..ea79668c2e5f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2933,6 +2933,35 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local, ps->dtim_count = dtim_count; } +static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) +{ + struct ieee80211_sub_if_data *sdata; + u8 radar_detect = 0; + + lockdep_assert_held(&local->chanctx_mtx); + + if (WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)) + return 0; + + list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) + if (sdata->reserved_radar_required) + radar_detect |= BIT(sdata->reserved_chandef.width); + + /* + * An in-place reservation context should not have any assigned vifs + * until it replaces the other context. + */ + WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER && + !list_empty(&ctx->assigned_vifs)); + + list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list) + if (sdata->radar_required) + radar_detect |= BIT(sdata->vif.bss_conf.chandef.width); + + return radar_detect; +} + int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode chanmode, @@ -2976,8 +3005,7 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, list_for_each_entry(ctx, &local->chanctx_list, list) { if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) continue; - if (ctx->conf.radar_enabled) - radar_detect |= BIT(ctx->conf.def.width); + radar_detect |= ieee80211_chanctx_radar_detect(local, ctx); if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { num_different_channels++; continue; @@ -3039,8 +3067,7 @@ int ieee80211_max_num_channels(struct ieee80211_local *local) num_different_channels++; - if (ctx->conf.radar_enabled) - radar_detect |= BIT(ctx->conf.def.width); + radar_detect |= ieee80211_chanctx_radar_detect(local, ctx); } list_for_each_entry_rcu(sdata, &local->interfaces, list) -- cgit v1.2.3 From 03078de4f928ffcbe629a914dea8bdf66a9d6a48 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 25 Jun 2014 12:35:08 +0200 Subject: mac80211: use chanctx reservation for AP CSA Channel switch finalization is now 2-step. First step is when driver calls csa_finish(), the other is when reservation is actually finalized (which can be deferred for in-place reservation). It is now safe to call ieee80211_csa_finish() more than once. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 82 +++++++++++++++++++++++++++++++++++------------------ net/mac80211/chan.c | 35 +++++++++++++++++++++-- 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 73c9e1003e25..927b4ea0128b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2792,17 +2792,35 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) sdata_assert_lock(sdata); lockdep_assert_held(&local->mtx); + lockdep_assert_held(&local->chanctx_mtx); - sdata->radar_required = sdata->csa_radar_required; - err = ieee80211_vif_change_channel(sdata, &changed); - if (err < 0) - return err; + /* + * using reservation isn't immediate as it may be deferred until later + * with multi-vif. once reservation is complete it will re-schedule the + * work with no reserved_chanctx so verify chandef to check if it + * completed successfully + */ - if (!local->use_chanctx) { - local->_oper_chandef = sdata->csa_chandef; - ieee80211_hw_config(local, 0); + if (sdata->reserved_chanctx) { + /* + * with multi-vif csa driver may call ieee80211_csa_finish() + * many times while waiting for other interfaces to use their + * reservations + */ + if (sdata->reserved_ready) + return 0; + + err = ieee80211_vif_use_reserved_context(sdata); + if (err) + return err; + + return 0; } + if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, + &sdata->csa_chandef)) + return -EINVAL; + sdata->vif.csa_active = false; err = ieee80211_set_after_csa_beacon(sdata, &changed); @@ -2839,6 +2857,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work) sdata_lock(sdata); mutex_lock(&local->mtx); + mutex_lock(&local->chanctx_mtx); /* AP might have been stopped while waiting for the lock. */ if (!sdata->vif.csa_active) @@ -2850,6 +2869,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work) ieee80211_csa_finalize(sdata); unlock: + mutex_unlock(&local->chanctx_mtx); mutex_unlock(&local->mtx); sdata_unlock(sdata); } @@ -2995,7 +3015,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *chanctx; - int err, num_chanctx, changed = 0; + int err, changed = 0; sdata_assert_lock(sdata); lockdep_assert_held(&local->mtx); @@ -3010,37 +3030,43 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, &sdata->vif.bss_conf.chandef)) return -EINVAL; + /* don't allow another channel switch if one is already active. */ + if (sdata->vif.csa_active) + return -EBUSY; + mutex_lock(&local->chanctx_mtx); conf = rcu_dereference_protected(sdata->vif.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) { - mutex_unlock(&local->chanctx_mtx); - return -EBUSY; + err = -EBUSY; + goto out; } - /* don't handle for multi-VIF cases */ chanctx = container_of(conf, struct ieee80211_chanctx, conf); - if (ieee80211_chanctx_refcount(local, chanctx) > 1) { - mutex_unlock(&local->chanctx_mtx); - return -EBUSY; + if (!chanctx) { + err = -EBUSY; + goto out; } - num_chanctx = 0; - list_for_each_entry_rcu(chanctx, &local->chanctx_list, list) - num_chanctx++; - mutex_unlock(&local->chanctx_mtx); - if (num_chanctx > 1) - return -EBUSY; + err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef, + chanctx->mode, + params->radar_required); + if (err) + goto out; - /* don't allow another channel switch if one is already active. */ - if (sdata->vif.csa_active) - return -EBUSY; + /* if reservation is invalid then this will fail */ + err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0); + if (err) { + ieee80211_vif_unreserve_chanctx(sdata); + goto out; + } err = ieee80211_set_csa_beacon(sdata, params, &changed); - if (err) - return err; + if (err) { + ieee80211_vif_unreserve_chanctx(sdata); + goto out; + } - sdata->csa_radar_required = params->radar_required; sdata->csa_chandef = params->chandef; sdata->csa_block_tx = params->block_tx; sdata->vif.csa_active = true; @@ -3057,7 +3083,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, ieee80211_csa_finalize(sdata); } - return 0; +out: + mutex_unlock(&local->chanctx_mtx); + return err; } int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 0e4302bb5b34..ea4db2f0db87 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -1056,6 +1056,30 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, return 0; } +static void +ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) +{ + switch (sdata->vif.type) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: + ieee80211_queue_work(&sdata->local->hw, + &sdata->csa_finalize_work); + break; + case NL80211_IFTYPE_UNSPECIFIED: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_P2P_DEVICE: + case NUM_NL80211_IFTYPES: + WARN_ON(1); + break; + } +} + static int ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) { @@ -1103,7 +1127,7 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) if (ieee80211_chanctx_refcount(local, new_ctx) == 0) ieee80211_free_chanctx(local, new_ctx); - return err; + goto out; } list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs); @@ -1123,6 +1147,8 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) if (changed) ieee80211_bss_info_change_notify(sdata, changed); +out: + ieee80211_vif_chanctx_reservation_complete(sdata); return err; } @@ -1167,6 +1193,7 @@ ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata) } out: + ieee80211_vif_chanctx_reservation_complete(sdata); return err; } @@ -1480,6 +1507,8 @@ ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs); sdata->reserved_chanctx = NULL; + + ieee80211_vif_chanctx_reservation_complete(sdata); } /* @@ -1543,8 +1572,10 @@ err: continue; list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, - reserved_chanctx_list) + reserved_chanctx_list) { ieee80211_vif_unreserve_chanctx(sdata); + ieee80211_vif_chanctx_reservation_complete(sdata); + } } return err; -- cgit v1.2.3 From 4c3ebc56d7561526524ec62c61aa3e2040b71f6e Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 25 Jun 2014 12:35:09 +0200 Subject: mac80211: use chanctx reservation for STA CSA Channel switch finalization is now 2-step. First step is when driver calls chswitch_done(), the other is when reservation is actually finalized (which be defered for in-place reservation). It is now safe to call ieee80211_chswitch_done() more than once. Also remove the ieee80211_vif_change_channel() because it is no longer used. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 69 ++------------------------------ net/mac80211/ieee80211_i.h | 5 --- net/mac80211/mlme.c | 99 ++++++++++++++++++++++++++++++---------------- 3 files changed, 69 insertions(+), 104 deletions(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index ea4db2f0db87..c3fd4d275bf4 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -819,70 +819,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, return ret; } -static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, - struct ieee80211_chanctx *ctx, - u32 *changed) -{ - struct ieee80211_local *local = sdata->local; - const struct cfg80211_chan_def *chandef = &sdata->csa_chandef; - u32 chanctx_changed = 0; - - if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, - IEEE80211_CHAN_DISABLED)) - return -EINVAL; - - if (ieee80211_chanctx_refcount(local, ctx) != 1) - return -EINVAL; - - if (sdata->vif.bss_conf.chandef.width != chandef->width) { - chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH; - *changed |= BSS_CHANGED_BANDWIDTH; - } - - sdata->vif.bss_conf.chandef = *chandef; - ctx->conf.def = *chandef; - - chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; - drv_change_chanctx(local, ctx, chanctx_changed); - - ieee80211_recalc_chanctx_chantype(local, ctx); - ieee80211_recalc_smps_chanctx(local, ctx); - ieee80211_recalc_radar_chanctx(local, ctx); - ieee80211_recalc_chanctx_min_def(local, ctx); - - return 0; -} - -int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, - u32 *changed) -{ - struct ieee80211_local *local = sdata->local; - struct ieee80211_chanctx_conf *conf; - struct ieee80211_chanctx *ctx; - int ret; - - lockdep_assert_held(&local->mtx); - - /* should never be called if not performing a channel switch. */ - if (WARN_ON(!sdata->vif.csa_active)) - return -EINVAL; - - mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, - lockdep_is_held(&local->chanctx_mtx)); - if (!conf) { - ret = -EINVAL; - goto out; - } - - ctx = container_of(conf, struct ieee80211_chanctx, conf); - - ret = __ieee80211_vif_change_channel(sdata, ctx, changed); - out: - mutex_unlock(&local->chanctx_mtx); - return ret; -} - static void __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, bool clear) @@ -1066,8 +1002,11 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) ieee80211_queue_work(&sdata->local->hw, &sdata->csa_finalize_work); break; - case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: + ieee80211_queue_work(&sdata->local->hw, + &sdata->u.mgd.chswitch_work); + break; + case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_MONITOR: diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c26955f6c14d..9e025e1184cc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -788,7 +788,6 @@ struct ieee80211_sub_if_data { struct mac80211_qos_map __rcu *qos_map; struct work_struct csa_finalize_work; - bool csa_radar_required; bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ struct cfg80211_chan_def csa_chandef; @@ -1850,10 +1849,6 @@ int __must_check ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, const struct cfg80211_chan_def *chandef, u32 *changed); -/* NOTE: only use ieee80211_vif_change_channel() for channel switch */ -int __must_check -ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, - u32 *changed); void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index eccc8492a59c..931330bbe00c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -940,52 +940,70 @@ static void ieee80211_chswitch_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - u32 changed = 0; int ret; if (!ieee80211_sdata_running(sdata)) return; sdata_lock(sdata); + mutex_lock(&local->mtx); + mutex_lock(&local->chanctx_mtx); + if (!ifmgd->associated) goto out; - mutex_lock(&local->mtx); - ret = ieee80211_vif_change_channel(sdata, &changed); - mutex_unlock(&local->mtx); - if (ret) { + if (!sdata->vif.csa_active) + goto out; + + /* + * using reservation isn't immediate as it may be deferred until later + * with multi-vif. once reservation is complete it will re-schedule the + * work with no reserved_chanctx so verify chandef to check if it + * completed successfully + */ + + if (sdata->reserved_chanctx) { + /* + * with multi-vif csa driver may call ieee80211_csa_finish() + * many times while waiting for other interfaces to use their + * reservations + */ + if (sdata->reserved_ready) + goto out; + + ret = ieee80211_vif_use_reserved_context(sdata); + if (ret) { + sdata_info(sdata, + "failed to use reserved channel context, disconnecting (err=%d)\n", + ret); + ieee80211_queue_work(&sdata->local->hw, + &ifmgd->csa_connection_drop_work); + goto out; + } + + goto out; + } + + if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, + &sdata->csa_chandef)) { sdata_info(sdata, - "vif channel switch failed, disconnecting\n"); + "failed to finalize channel switch, disconnecting\n"); ieee80211_queue_work(&sdata->local->hw, &ifmgd->csa_connection_drop_work); goto out; } - if (!local->use_chanctx) { - local->_oper_chandef = sdata->csa_chandef; - /* Call "hw_config" only if doing sw channel switch. - * Otherwise update the channel directly - */ - if (!local->ops->channel_switch) - ieee80211_hw_config(local, 0); - else - local->hw.conf.chandef = local->_oper_chandef; - } - /* XXX: shouldn't really modify cfg80211-owned data! */ ifmgd->associated->channel = sdata->csa_chandef.chan; - ieee80211_bss_info_change_notify(sdata, changed); - - mutex_lock(&local->mtx); sdata->vif.csa_active = false; + /* XXX: wait for a beacon first? */ if (sdata->csa_block_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); sdata->csa_block_tx = false; } - mutex_unlock(&local->mtx); ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; @@ -993,6 +1011,8 @@ static void ieee80211_chswitch_work(struct work_struct *work) ieee80211_sta_reset_conn_monitor(sdata); out: + mutex_unlock(&local->chanctx_mtx); + mutex_unlock(&local->mtx); sdata_unlock(sdata); } @@ -1029,6 +1049,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct cfg80211_bss *cbss = ifmgd->associated; + struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *chanctx; enum ieee80211_band current_band; struct ieee80211_csa_ie csa_ie; @@ -1072,7 +1093,22 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; + mutex_lock(&local->mtx); mutex_lock(&local->chanctx_mtx); + conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (!conf) { + sdata_info(sdata, + "no channel context assigned to vif?, disconnecting\n"); + ieee80211_queue_work(&local->hw, + &ifmgd->csa_connection_drop_work); + mutex_unlock(&local->chanctx_mtx); + mutex_unlock(&local->mtx); + return; + } + + chanctx = container_of(conf, struct ieee80211_chanctx, conf); + if (local->use_chanctx) { u32 num_chanctx = 0; list_for_each_entry(chanctx, &local->chanctx_list, list) @@ -1085,32 +1121,27 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); mutex_unlock(&local->chanctx_mtx); + mutex_unlock(&local->mtx); return; } } - if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { - ieee80211_queue_work(&local->hw, - &ifmgd->csa_connection_drop_work); - mutex_unlock(&local->chanctx_mtx); - return; - } - chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), - struct ieee80211_chanctx, conf); - if (ieee80211_chanctx_refcount(local, chanctx) > 1) { + res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, + chanctx->mode, false); + if (res) { sdata_info(sdata, - "channel switch with multiple interfaces on the same channel, disconnecting\n"); + "failed to reserve channel context for channel switch, disconnecting (err=%d)\n", + res); ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); mutex_unlock(&local->chanctx_mtx); + mutex_unlock(&local->mtx); return; } mutex_unlock(&local->chanctx_mtx); - sdata->csa_chandef = csa_ie.chandef; - - mutex_lock(&local->mtx); sdata->vif.csa_active = true; + sdata->csa_chandef = csa_ie.chandef; sdata->csa_block_tx = csa_ie.mode; if (sdata->csa_block_tx) -- cgit v1.2.3 From 97dc94f1d933c9df2c0b327066ea130c0e92083f Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 25 Jun 2014 12:35:10 +0200 Subject: cfg80211: remove channel_switch combination check Driver is now responsible for veryfing if the switch is possible. Since this is inherently tricky driver may decide to disconnect an interface later with cfg80211_stop_iface(). This doesn't mean driver can accept everything. It should do it's best to verify requests and reject them as soon as possible. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 7 ++++++- net/wireless/nl80211.c | 11 ----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b9eeae3990cf..0a080c4de275 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2301,7 +2301,12 @@ struct cfg80211_qos_map { * reliability. This operation can not fail. * @set_coalesce: Set coalesce parameters. * - * @channel_switch: initiate channel-switch procedure (with CSA) + * @channel_switch: initiate channel-switch procedure (with CSA). Driver is + * responsible for veryfing if the switch is possible. Since this is + * inherently tricky driver may decide to disconnect an interface later + * with cfg80211_stop_iface(). This doesn't mean driver can accept + * everything. It should do it's best to verify requests and reject them + * as soon as possible. * * @set_qos_map: Set QoS mapping information to the driver * diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8f46b8ffbcf6..c10295138eb5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6013,17 +6013,6 @@ skip_beacons: params.radar_required = true; } - /* TODO: I left this here for now. With channel switch, the - * verification is a bit more complicated, because we only do - * it later when the channel switch really happens. - */ - err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, - params.chandef.chan, - CHAN_MODE_SHARED, - radar_detect_width); - if (err) - return err; - if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) params.block_tx = true; -- cgit v1.2.3 From 9500507c61381ceda4edbefa7361a4d26f54eb17 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 10 Jun 2014 23:12:56 +0200 Subject: netfilter: conntrack: remove timer from ecache extension This brings the (per-conntrack) ecache extension back to 24 bytes in size (was 152 byte on x86_64 with lockdep on). When event delivery fails, re-delivery is attempted via work queue. Redelivery is attempted at least every 0.1 seconds, but can happen more frequently if userspace is not congested. The nf_ct_release_dying_list() function is removed. With this patch, ownership of the to-be-redelivered conntracks (on-dying-list-with-DYING-bit not yet set) is with the work queue, which will release the references once event is out. Joint work with Pablo Neira Ayuso. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_ecache.h | 26 +++++++- include/net/netns/conntrack.h | 6 +- net/netfilter/nf_conntrack_core.c | 68 +++----------------- net/netfilter/nf_conntrack_ecache.c | 96 ++++++++++++++++++++++++++--- 4 files changed, 124 insertions(+), 72 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index 0e3d08e4b1d3..57c880378443 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -18,7 +18,6 @@ struct nf_conntrack_ecache { u16 ctmask; /* bitmask of ct events to be delivered */ u16 expmask; /* bitmask of expect events to be delivered */ u32 portid; /* netlink portid of destroyer */ - struct timer_list timeout; }; static inline struct nf_conntrack_ecache * @@ -216,8 +215,23 @@ void nf_conntrack_ecache_pernet_fini(struct net *net); int nf_conntrack_ecache_init(void); void nf_conntrack_ecache_fini(void); -#else /* CONFIG_NF_CONNTRACK_EVENTS */ +static inline void nf_conntrack_ecache_delayed_work(struct net *net) +{ + if (!delayed_work_pending(&net->ct.ecache_dwork)) { + schedule_delayed_work(&net->ct.ecache_dwork, HZ); + net->ct.ecache_dwork_pending = true; + } +} + +static inline void nf_conntrack_ecache_work(struct net *net) +{ + if (net->ct.ecache_dwork_pending) { + net->ct.ecache_dwork_pending = false; + mod_delayed_work(system_wq, &net->ct.ecache_dwork, 0); + } +} +#else /* CONFIG_NF_CONNTRACK_EVENTS */ static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) {} static inline int nf_conntrack_eventmask_report(unsigned int eventmask, @@ -255,6 +269,14 @@ static inline int nf_conntrack_ecache_init(void) static inline void nf_conntrack_ecache_fini(void) { } + +static inline void nf_conntrack_ecache_delayed_work(struct net *net) +{ +} + +static inline void nf_conntrack_ecache_work(struct net *net) +{ +} #endif /* CONFIG_NF_CONNTRACK_EVENTS */ #endif /*_NF_CONNTRACK_ECACHE_H*/ diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h index 773cce308bc6..29d6a94db54d 100644 --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -73,6 +74,10 @@ struct ct_pcpu { struct netns_ct { atomic_t count; unsigned int expect_count; +#ifdef CONFIG_NF_CONNTRACK_EVENTS + struct delayed_work ecache_dwork; + bool ecache_dwork_pending; +#endif #ifdef CONFIG_SYSCTL struct ctl_table_header *sysctl_header; struct ctl_table_header *acct_sysctl_header; @@ -82,7 +87,6 @@ struct netns_ct { #endif char *slabname; unsigned int sysctl_log_invalid; /* Log invalid packets */ - unsigned int sysctl_events_retry_timeout; int sysctl_events; int sysctl_acct; int sysctl_auto_assign_helper; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 1f4f954c4b47..de88c4ab5146 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -352,40 +352,6 @@ static void nf_ct_delete_from_lists(struct nf_conn *ct) local_bh_enable(); } -static void death_by_event(unsigned long ul_conntrack) -{ - struct nf_conn *ct = (void *)ul_conntrack; - struct net *net = nf_ct_net(ct); - struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct); - - BUG_ON(ecache == NULL); - - if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) { - /* bad luck, let's retry again */ - ecache->timeout.expires = jiffies + - (prandom_u32() % net->ct.sysctl_events_retry_timeout); - add_timer(&ecache->timeout); - return; - } - /* we've got the event delivered, now it's dying */ - set_bit(IPS_DYING_BIT, &ct->status); - nf_ct_put(ct); -} - -static void nf_ct_dying_timeout(struct nf_conn *ct) -{ - struct net *net = nf_ct_net(ct); - struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct); - - BUG_ON(ecache == NULL); - - /* set a new timer to retry event delivery */ - setup_timer(&ecache->timeout, death_by_event, (unsigned long)ct); - ecache->timeout.expires = jiffies + - (prandom_u32() % net->ct.sysctl_events_retry_timeout); - add_timer(&ecache->timeout); -} - bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report) { struct nf_conn_tstamp *tstamp; @@ -394,15 +360,20 @@ bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report) if (tstamp && tstamp->stop == 0) tstamp->stop = ktime_to_ns(ktime_get_real()); - if (!nf_ct_is_dying(ct) && - unlikely(nf_conntrack_event_report(IPCT_DESTROY, ct, - portid, report) < 0)) { + if (nf_ct_is_dying(ct)) + goto delete; + + if (nf_conntrack_event_report(IPCT_DESTROY, ct, + portid, report) < 0) { /* destroy event was not delivered */ nf_ct_delete_from_lists(ct); - nf_ct_dying_timeout(ct); + nf_conntrack_ecache_delayed_work(nf_ct_net(ct)); return false; } + + nf_conntrack_ecache_work(nf_ct_net(ct)); set_bit(IPS_DYING_BIT, &ct->status); + delete: nf_ct_delete_from_lists(ct); nf_ct_put(ct); return true; @@ -1464,26 +1435,6 @@ void nf_conntrack_flush_report(struct net *net, u32 portid, int report) } EXPORT_SYMBOL_GPL(nf_conntrack_flush_report); -static void nf_ct_release_dying_list(struct net *net) -{ - struct nf_conntrack_tuple_hash *h; - struct nf_conn *ct; - struct hlist_nulls_node *n; - int cpu; - - for_each_possible_cpu(cpu) { - struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); - - spin_lock_bh(&pcpu->lock); - hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) { - ct = nf_ct_tuplehash_to_ctrack(h); - /* never fails to remove them, no listeners at this point */ - nf_ct_kill(ct); - } - spin_unlock_bh(&pcpu->lock); - } -} - static int untrack_refs(void) { int cnt = 0, cpu; @@ -1548,7 +1499,6 @@ i_see_dead_people: busy = 0; list_for_each_entry(net, net_exit_list, exit_list) { nf_ct_iterate_cleanup(net, kill_all, NULL, 0, 0); - nf_ct_release_dying_list(net); if (atomic_read(&net->ct.count) != 0) busy = 1; } diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index 1df176146567..4e78c57b818f 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -29,6 +29,90 @@ static DEFINE_MUTEX(nf_ct_ecache_mutex); +#define ECACHE_RETRY_WAIT (HZ/10) + +enum retry_state { + STATE_CONGESTED, + STATE_RESTART, + STATE_DONE, +}; + +static enum retry_state ecache_work_evict_list(struct ct_pcpu *pcpu) +{ + struct nf_conn *refs[16]; + struct nf_conntrack_tuple_hash *h; + struct hlist_nulls_node *n; + unsigned int evicted = 0; + enum retry_state ret = STATE_DONE; + + spin_lock(&pcpu->lock); + + hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) { + struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); + + if (nf_ct_is_dying(ct)) + continue; + + if (nf_conntrack_event(IPCT_DESTROY, ct)) { + ret = STATE_CONGESTED; + break; + } + + /* we've got the event delivered, now it's dying */ + set_bit(IPS_DYING_BIT, &ct->status); + refs[evicted] = ct; + + if (++evicted >= ARRAY_SIZE(refs)) { + ret = STATE_RESTART; + break; + } + } + + spin_unlock(&pcpu->lock); + + /* can't _put while holding lock */ + while (evicted) + nf_ct_put(refs[--evicted]); + + return ret; +} + +static void ecache_work(struct work_struct *work) +{ + struct netns_ct *ctnet = + container_of(work, struct netns_ct, ecache_dwork.work); + int cpu, delay = -1; + struct ct_pcpu *pcpu; + + local_bh_disable(); + + for_each_possible_cpu(cpu) { + enum retry_state ret; + + pcpu = per_cpu_ptr(ctnet->pcpu_lists, cpu); + + ret = ecache_work_evict_list(pcpu); + + switch (ret) { + case STATE_CONGESTED: + delay = ECACHE_RETRY_WAIT; + goto out; + case STATE_RESTART: + delay = 0; + break; + case STATE_DONE: + break; + } + } + + out: + local_bh_enable(); + + ctnet->ecache_dwork_pending = delay > 0; + if (delay >= 0) + schedule_delayed_work(&ctnet->ecache_dwork, delay); +} + /* deliver cached events and clear cache entry - must be called with locally * disabled softirqs */ void nf_ct_deliver_cached_events(struct nf_conn *ct) @@ -157,7 +241,6 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); #define NF_CT_EVENTS_DEFAULT 1 static int nf_ct_events __read_mostly = NF_CT_EVENTS_DEFAULT; -static int nf_ct_events_retry_timeout __read_mostly = 15*HZ; #ifdef CONFIG_SYSCTL static struct ctl_table event_sysctl_table[] = { @@ -168,13 +251,6 @@ static struct ctl_table event_sysctl_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, - { - .procname = "nf_conntrack_events_retry_timeout", - .data = &init_net.ct.sysctl_events_retry_timeout, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, {} }; #endif /* CONFIG_SYSCTL */ @@ -196,7 +272,6 @@ static int nf_conntrack_event_init_sysctl(struct net *net) goto out; table[0].data = &net->ct.sysctl_events; - table[1].data = &net->ct.sysctl_events_retry_timeout; /* Don't export sysctls to unprivileged users */ if (net->user_ns != &init_user_ns) @@ -238,12 +313,13 @@ static void nf_conntrack_event_fini_sysctl(struct net *net) int nf_conntrack_ecache_pernet_init(struct net *net) { net->ct.sysctl_events = nf_ct_events; - net->ct.sysctl_events_retry_timeout = nf_ct_events_retry_timeout; + INIT_DELAYED_WORK(&net->ct.ecache_dwork, ecache_work); return nf_conntrack_event_init_sysctl(net); } void nf_conntrack_ecache_pernet_fini(struct net *net) { + cancel_delayed_work_sync(&net->ct.ecache_dwork); nf_conntrack_event_fini_sysctl(net); } -- cgit v1.2.3 From 7200135bc1e61f1437dc326ae2ef2f310c50b4eb Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 16 Jun 2014 13:01:52 +0200 Subject: netfilter: kill ulog targets This has been marked as deprecated for quite some time and the NFLOG target replacement has been also available since 2006. Signed-off-by: Pablo Neira Ayuso --- include/uapi/linux/netfilter_bridge/Kbuild | 1 - include/uapi/linux/netfilter_bridge/ebt_ulog.h | 38 -- include/uapi/linux/netfilter_ipv4/Kbuild | 1 - include/uapi/linux/netfilter_ipv4/ipt_ULOG.h | 49 --- net/bridge/netfilter/Kconfig | 16 - net/bridge/netfilter/ebt_ulog.c | 393 ------------------- net/ipv4/netfilter/Kconfig | 19 - net/ipv4/netfilter/ipt_ULOG.c | 498 ------------------------- 8 files changed, 1015 deletions(-) delete mode 100644 include/uapi/linux/netfilter_bridge/ebt_ulog.h delete mode 100644 include/uapi/linux/netfilter_ipv4/ipt_ULOG.h delete mode 100644 net/bridge/netfilter/ebt_ulog.c delete mode 100644 net/ipv4/netfilter/ipt_ULOG.c diff --git a/include/uapi/linux/netfilter_bridge/Kbuild b/include/uapi/linux/netfilter_bridge/Kbuild index 348717c3a22f..0fbad8ef96de 100644 --- a/include/uapi/linux/netfilter_bridge/Kbuild +++ b/include/uapi/linux/netfilter_bridge/Kbuild @@ -14,6 +14,5 @@ header-y += ebt_nflog.h header-y += ebt_pkttype.h header-y += ebt_redirect.h header-y += ebt_stp.h -header-y += ebt_ulog.h header-y += ebt_vlan.h header-y += ebtables.h diff --git a/include/uapi/linux/netfilter_bridge/ebt_ulog.h b/include/uapi/linux/netfilter_bridge/ebt_ulog.h deleted file mode 100644 index 89a6becb5269..000000000000 --- a/include/uapi/linux/netfilter_bridge/ebt_ulog.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef _EBT_ULOG_H -#define _EBT_ULOG_H - -#include - -#define EBT_ULOG_DEFAULT_NLGROUP 0 -#define EBT_ULOG_DEFAULT_QTHRESHOLD 1 -#define EBT_ULOG_MAXNLGROUPS 32 /* hardcoded netlink max */ -#define EBT_ULOG_PREFIX_LEN 32 -#define EBT_ULOG_MAX_QLEN 50 -#define EBT_ULOG_WATCHER "ulog" -#define EBT_ULOG_VERSION 1 - -struct ebt_ulog_info { - __u32 nlgroup; - unsigned int cprange; - unsigned int qthreshold; - char prefix[EBT_ULOG_PREFIX_LEN]; -}; - -typedef struct ebt_ulog_packet_msg { - int version; - char indev[IFNAMSIZ]; - char outdev[IFNAMSIZ]; - char physindev[IFNAMSIZ]; - char physoutdev[IFNAMSIZ]; - char prefix[EBT_ULOG_PREFIX_LEN]; - struct timeval stamp; - unsigned long mark; - unsigned int hook; - size_t data_len; - /* The complete packet, including Ethernet header and perhaps - * the VLAN header is appended */ - unsigned char data[0] __attribute__ - ((aligned (__alignof__(struct ebt_ulog_info)))); -} ebt_ulog_packet_msg_t; - -#endif /* _EBT_ULOG_H */ diff --git a/include/uapi/linux/netfilter_ipv4/Kbuild b/include/uapi/linux/netfilter_ipv4/Kbuild index fb008437dde1..ecb291df390e 100644 --- a/include/uapi/linux/netfilter_ipv4/Kbuild +++ b/include/uapi/linux/netfilter_ipv4/Kbuild @@ -5,7 +5,6 @@ header-y += ipt_ECN.h header-y += ipt_LOG.h header-y += ipt_REJECT.h header-y += ipt_TTL.h -header-y += ipt_ULOG.h header-y += ipt_ah.h header-y += ipt_ecn.h header-y += ipt_ttl.h diff --git a/include/uapi/linux/netfilter_ipv4/ipt_ULOG.h b/include/uapi/linux/netfilter_ipv4/ipt_ULOG.h deleted file mode 100644 index 417aad280bcc..000000000000 --- a/include/uapi/linux/netfilter_ipv4/ipt_ULOG.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Header file for IP tables userspace logging, Version 1.8 - * - * (C) 2000-2002 by Harald Welte - * - * Distributed under the terms of GNU GPL */ - -#ifndef _IPT_ULOG_H -#define _IPT_ULOG_H - -#ifndef NETLINK_NFLOG -#define NETLINK_NFLOG 5 -#endif - -#define ULOG_DEFAULT_NLGROUP 1 -#define ULOG_DEFAULT_QTHRESHOLD 1 - -#define ULOG_MAC_LEN 80 -#define ULOG_PREFIX_LEN 32 - -#define ULOG_MAX_QLEN 50 -/* Why 50? Well... there is a limit imposed by the slab cache 131000 - * bytes. So the multipart netlink-message has to be < 131000 bytes. - * Assuming a standard ethernet-mtu of 1500, we could define this up - * to 80... but even 50 seems to be big enough. */ - -/* private data structure for each rule with a ULOG target */ -struct ipt_ulog_info { - unsigned int nl_group; - size_t copy_range; - size_t qthreshold; - char prefix[ULOG_PREFIX_LEN]; -}; - -/* Format of the ULOG packets passed through netlink */ -typedef struct ulog_packet_msg { - unsigned long mark; - long timestamp_sec; - long timestamp_usec; - unsigned int hook; - char indev_name[IFNAMSIZ]; - char outdev_name[IFNAMSIZ]; - size_t data_len; - char prefix[ULOG_PREFIX_LEN]; - unsigned char mac_len; - unsigned char mac[ULOG_MAC_LEN]; - unsigned char payload[0]; -} ulog_packet_msg_t; - -#endif /*_IPT_ULOG_H*/ diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig index 629dc77874a9..3a76ac7b7141 100644 --- a/net/bridge/netfilter/Kconfig +++ b/net/bridge/netfilter/Kconfig @@ -202,22 +202,6 @@ config BRIDGE_EBT_LOG To compile it as a module, choose M here. If unsure, say N. -config BRIDGE_EBT_ULOG - tristate "ebt: ulog support (OBSOLETE)" - help - This option enables the old bridge-specific "ebt_ulog" implementation - which has been obsoleted by the new "nfnetlink_log" code (see - CONFIG_NETFILTER_NETLINK_LOG). - - This option adds the ulog watcher, that you can use in any rule - in any ebtables table. The packet is passed to a userspace - logging daemon using netlink multicast sockets. This differs - from the log watcher in the sense that the complete packet is - sent to userspace instead of a descriptive text and that - netlink multicast sockets are used instead of the syslog. - - To compile it as a module, choose M here. If unsure, say N. - config BRIDGE_EBT_NFLOG tristate "ebt: nflog support" help diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c deleted file mode 100644 index 7c470c371e14..000000000000 --- a/net/bridge/netfilter/ebt_ulog.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * netfilter module for userspace bridged Ethernet frames logging daemons - * - * Authors: - * Bart De Schuymer - * Harald Welte - * - * November, 2004 - * - * Based on ipt_ULOG.c, which is - * (C) 2000-2002 by Harald Welte - * - * This module accepts two parameters: - * - * nlbufsiz: - * The parameter specifies how big the buffer for each netlink multicast - * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will - * get accumulated in the kernel until they are sent to userspace. It is - * NOT possible to allocate more than 128kB, and it is strongly discouraged, - * because atomically allocating 128kB inside the network rx softirq is not - * reliable. Please also keep in mind that this buffer size is allocated for - * each nlgroup you are using, so the total kernel memory usage increases - * by that factor. - * - * flushtimeout: - * Specify, after how many hundredths of a second the queue should be - * flushed even if it is not full yet. - * - */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../br_private.h" - -static unsigned int nlbufsiz = NLMSG_GOODSIZE; -module_param(nlbufsiz, uint, 0600); -MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) " - "(defaults to 4096)"); - -static unsigned int flushtimeout = 10; -module_param(flushtimeout, uint, 0600); -MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths ofa second) " - "(defaults to 10)"); - -typedef struct { - unsigned int qlen; /* number of nlmsgs' in the skb */ - struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */ - struct sk_buff *skb; /* the pre-allocated skb */ - struct timer_list timer; /* the timer function */ - spinlock_t lock; /* the per-queue lock */ -} ebt_ulog_buff_t; - -static int ebt_ulog_net_id __read_mostly; -struct ebt_ulog_net { - unsigned int nlgroup[EBT_ULOG_MAXNLGROUPS]; - ebt_ulog_buff_t ulog_buffers[EBT_ULOG_MAXNLGROUPS]; - struct sock *ebtulognl; -}; - -static struct ebt_ulog_net *ebt_ulog_pernet(struct net *net) -{ - return net_generic(net, ebt_ulog_net_id); -} - -/* send one ulog_buff_t to userspace */ -static void ulog_send(struct ebt_ulog_net *ebt, unsigned int nlgroup) -{ - ebt_ulog_buff_t *ub = &ebt->ulog_buffers[nlgroup]; - - del_timer(&ub->timer); - - if (!ub->skb) - return; - - /* last nlmsg needs NLMSG_DONE */ - if (ub->qlen > 1) - ub->lastnlh->nlmsg_type = NLMSG_DONE; - - NETLINK_CB(ub->skb).dst_group = nlgroup + 1; - netlink_broadcast(ebt->ebtulognl, ub->skb, 0, nlgroup + 1, GFP_ATOMIC); - - ub->qlen = 0; - ub->skb = NULL; -} - -/* timer function to flush queue in flushtimeout time */ -static void ulog_timer(unsigned long data) -{ - struct ebt_ulog_net *ebt = container_of((void *)data, - struct ebt_ulog_net, - nlgroup[*(unsigned int *)data]); - - ebt_ulog_buff_t *ub = &ebt->ulog_buffers[*(unsigned int *)data]; - spin_lock_bh(&ub->lock); - if (ub->skb) - ulog_send(ebt, *(unsigned int *)data); - spin_unlock_bh(&ub->lock); -} - -static struct sk_buff *ulog_alloc_skb(unsigned int size) -{ - struct sk_buff *skb; - unsigned int n; - - n = max(size, nlbufsiz); - skb = alloc_skb(n, GFP_ATOMIC | __GFP_NOWARN); - if (!skb) { - if (n > size) { - /* try to allocate only as much as we need for - * current packet */ - skb = alloc_skb(size, GFP_ATOMIC); - if (!skb) - pr_debug("cannot even allocate buffer of size %ub\n", - size); - } - } - - return skb; -} - -static void ebt_ulog_packet(struct net *net, unsigned int hooknr, - const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct ebt_ulog_info *uloginfo, - const char *prefix) -{ - ebt_ulog_packet_msg_t *pm; - size_t size, copy_len; - struct nlmsghdr *nlh; - struct ebt_ulog_net *ebt = ebt_ulog_pernet(net); - unsigned int group = uloginfo->nlgroup; - ebt_ulog_buff_t *ub = &ebt->ulog_buffers[group]; - spinlock_t *lock = &ub->lock; - ktime_t kt; - - if ((uloginfo->cprange == 0) || - (uloginfo->cprange > skb->len + ETH_HLEN)) - copy_len = skb->len + ETH_HLEN; - else - copy_len = uloginfo->cprange; - - size = nlmsg_total_size(sizeof(*pm) + copy_len); - if (size > nlbufsiz) { - pr_debug("Size %Zd needed, but nlbufsiz=%d\n", size, nlbufsiz); - return; - } - - spin_lock_bh(lock); - - if (!ub->skb) { - if (!(ub->skb = ulog_alloc_skb(size))) - goto unlock; - } else if (size > skb_tailroom(ub->skb)) { - ulog_send(ebt, group); - - if (!(ub->skb = ulog_alloc_skb(size))) - goto unlock; - } - - nlh = nlmsg_put(ub->skb, 0, ub->qlen, 0, - size - NLMSG_ALIGN(sizeof(*nlh)), 0); - if (!nlh) { - kfree_skb(ub->skb); - ub->skb = NULL; - goto unlock; - } - ub->qlen++; - - pm = nlmsg_data(nlh); - memset(pm, 0, sizeof(*pm)); - - /* Fill in the ulog data */ - pm->version = EBT_ULOG_VERSION; - kt = ktime_get_real(); - pm->stamp = ktime_to_timeval(kt); - if (ub->qlen == 1) - ub->skb->tstamp = kt; - pm->data_len = copy_len; - pm->mark = skb->mark; - pm->hook = hooknr; - if (uloginfo->prefix != NULL) - strcpy(pm->prefix, uloginfo->prefix); - - if (in) { - strcpy(pm->physindev, in->name); - /* If in isn't a bridge, then physindev==indev */ - if (br_port_exists(in)) - /* rcu_read_lock()ed by nf_hook_slow */ - strcpy(pm->indev, br_port_get_rcu(in)->br->dev->name); - else - strcpy(pm->indev, in->name); - } - - if (out) { - /* If out exists, then out is a bridge port */ - strcpy(pm->physoutdev, out->name); - /* rcu_read_lock()ed by nf_hook_slow */ - strcpy(pm->outdev, br_port_get_rcu(out)->br->dev->name); - } - - if (skb_copy_bits(skb, -ETH_HLEN, pm->data, copy_len) < 0) - BUG(); - - if (ub->qlen > 1) - ub->lastnlh->nlmsg_flags |= NLM_F_MULTI; - - ub->lastnlh = nlh; - - if (ub->qlen >= uloginfo->qthreshold) - ulog_send(ebt, group); - else if (!timer_pending(&ub->timer)) { - ub->timer.expires = jiffies + flushtimeout * HZ / 100; - add_timer(&ub->timer); - } - -unlock: - spin_unlock_bh(lock); -} - -/* this function is registered with the netfilter core */ -static void ebt_log_packet(struct net *net, u_int8_t pf, unsigned int hooknum, - const struct sk_buff *skb, const struct net_device *in, - const struct net_device *out, const struct nf_loginfo *li, - const char *prefix) -{ - struct ebt_ulog_info loginfo; - - if (!li || li->type != NF_LOG_TYPE_ULOG) { - loginfo.nlgroup = EBT_ULOG_DEFAULT_NLGROUP; - loginfo.cprange = 0; - loginfo.qthreshold = EBT_ULOG_DEFAULT_QTHRESHOLD; - loginfo.prefix[0] = '\0'; - } else { - loginfo.nlgroup = li->u.ulog.group; - loginfo.cprange = li->u.ulog.copy_len; - loginfo.qthreshold = li->u.ulog.qthreshold; - strlcpy(loginfo.prefix, prefix, sizeof(loginfo.prefix)); - } - - ebt_ulog_packet(net, hooknum, skb, in, out, &loginfo, prefix); -} - -static unsigned int -ebt_ulog_tg(struct sk_buff *skb, const struct xt_action_param *par) -{ - struct net *net = dev_net(par->in ? par->in : par->out); - - ebt_ulog_packet(net, par->hooknum, skb, par->in, par->out, - par->targinfo, NULL); - return EBT_CONTINUE; -} - -static int ebt_ulog_tg_check(const struct xt_tgchk_param *par) -{ - struct ebt_ulog_info *uloginfo = par->targinfo; - - if (!par->net->xt.ebt_ulog_warn_deprecated) { - pr_info("ebt_ulog is deprecated and it will be removed soon, " - "use ebt_nflog instead\n"); - par->net->xt.ebt_ulog_warn_deprecated = true; - } - - if (uloginfo->nlgroup > 31) - return -EINVAL; - - uloginfo->prefix[EBT_ULOG_PREFIX_LEN - 1] = '\0'; - - if (uloginfo->qthreshold > EBT_ULOG_MAX_QLEN) - uloginfo->qthreshold = EBT_ULOG_MAX_QLEN; - - return 0; -} - -static struct xt_target ebt_ulog_tg_reg __read_mostly = { - .name = "ulog", - .revision = 0, - .family = NFPROTO_BRIDGE, - .target = ebt_ulog_tg, - .checkentry = ebt_ulog_tg_check, - .targetsize = sizeof(struct ebt_ulog_info), - .me = THIS_MODULE, -}; - -static struct nf_logger ebt_ulog_logger __read_mostly = { - .name = "ebt_ulog", - .logfn = &ebt_log_packet, - .me = THIS_MODULE, -}; - -static int __net_init ebt_ulog_net_init(struct net *net) -{ - int i; - struct ebt_ulog_net *ebt = ebt_ulog_pernet(net); - - struct netlink_kernel_cfg cfg = { - .groups = EBT_ULOG_MAXNLGROUPS, - }; - - /* initialize ulog_buffers */ - for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { - ebt->nlgroup[i] = i; - setup_timer(&ebt->ulog_buffers[i].timer, ulog_timer, - (unsigned long)&ebt->nlgroup[i]); - spin_lock_init(&ebt->ulog_buffers[i].lock); - } - - ebt->ebtulognl = netlink_kernel_create(net, NETLINK_NFLOG, &cfg); - if (!ebt->ebtulognl) - return -ENOMEM; - - nf_log_set(net, NFPROTO_BRIDGE, &ebt_ulog_logger); - return 0; -} - -static void __net_exit ebt_ulog_net_fini(struct net *net) -{ - int i; - struct ebt_ulog_net *ebt = ebt_ulog_pernet(net); - - nf_log_unset(net, &ebt_ulog_logger); - for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { - ebt_ulog_buff_t *ub = &ebt->ulog_buffers[i]; - del_timer(&ub->timer); - - if (ub->skb) { - kfree_skb(ub->skb); - ub->skb = NULL; - } - } - netlink_kernel_release(ebt->ebtulognl); -} - -static struct pernet_operations ebt_ulog_net_ops = { - .init = ebt_ulog_net_init, - .exit = ebt_ulog_net_fini, - .id = &ebt_ulog_net_id, - .size = sizeof(struct ebt_ulog_net), -}; - -static int __init ebt_ulog_init(void) -{ - int ret; - - if (nlbufsiz >= 128*1024) { - pr_warn("Netlink buffer has to be <= 128kB," - "please try a smaller nlbufsiz parameter.\n"); - return -EINVAL; - } - - ret = register_pernet_subsys(&ebt_ulog_net_ops); - if (ret) - goto out_pernet; - - ret = xt_register_target(&ebt_ulog_tg_reg); - if (ret) - goto out_target; - - nf_log_register(NFPROTO_BRIDGE, &ebt_ulog_logger); - - return 0; - -out_target: - unregister_pernet_subsys(&ebt_ulog_net_ops); -out_pernet: - return ret; -} - -static void __exit ebt_ulog_fini(void) -{ - nf_log_unregister(&ebt_ulog_logger); - xt_unregister_target(&ebt_ulog_tg_reg); - unregister_pernet_subsys(&ebt_ulog_net_ops); -} - -module_init(ebt_ulog_init); -module_exit(ebt_ulog_fini); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Bart De Schuymer "); -MODULE_DESCRIPTION("Ebtables: Packet logging to netlink using ULOG"); diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index a26ce035e3fa..730faacbc5f8 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -159,25 +159,6 @@ config IP_NF_TARGET_SYNPROXY To compile it as a module, choose M here. If unsure, say N. -config IP_NF_TARGET_ULOG - tristate "ULOG target support (obsolete)" - default m if NETFILTER_ADVANCED=n - ---help--- - - This option enables the old IPv4-only "ipt_ULOG" implementation - which has been obsoleted by the new "nfnetlink_log" code (see - CONFIG_NETFILTER_NETLINK_LOG). - - This option adds a `ULOG' target, which allows you to create rules in - any iptables table. The packet is passed to a userspace logging - daemon using netlink multicast sockets; unlike the LOG target - which can only be viewed through syslog. - - The appropriate userspace logging daemon (ulogd) may be obtained from - - - To compile it as a module, choose M here. If unsure, say N. - # NAT + specific targets: nf_conntrack config NF_NAT_IPV4 tristate "IPv4 NAT" diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c deleted file mode 100644 index 9cb993cd224b..000000000000 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * netfilter module for userspace packet logging daemons - * - * (C) 2000-2004 by Harald Welte - * (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team - * (C) 2005-2007 Patrick McHardy - * - * 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. - * - * This module accepts two parameters: - * - * nlbufsiz: - * The parameter specifies how big the buffer for each netlink multicast - * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will - * get accumulated in the kernel until they are sent to userspace. It is - * NOT possible to allocate more than 128kB, and it is strongly discouraged, - * because atomically allocating 128kB inside the network rx softirq is not - * reliable. Please also keep in mind that this buffer size is allocated for - * each nlgroup you are using, so the total kernel memory usage increases - * by that factor. - * - * Actually you should use nlbufsiz a bit smaller than PAGE_SIZE, since - * nlbufsiz is used with alloc_skb, which adds another - * sizeof(struct skb_shared_info). Use NLMSG_GOODSIZE instead. - * - * flushtimeout: - * Specify, after how many hundredths of a second the queue should be - * flushed even if it is not full yet. - */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Harald Welte "); -MODULE_DESCRIPTION("Xtables: packet logging to netlink using ULOG"); -MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NFLOG); - -#define ULOG_NL_EVENT 111 /* Harald's favorite number */ -#define ULOG_MAXNLGROUPS 32 /* numer of nlgroups */ - -static unsigned int nlbufsiz = NLMSG_GOODSIZE; -module_param(nlbufsiz, uint, 0400); -MODULE_PARM_DESC(nlbufsiz, "netlink buffer size"); - -static unsigned int flushtimeout = 10; -module_param(flushtimeout, uint, 0600); -MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths of a second)"); - -static bool nflog = true; -module_param(nflog, bool, 0400); -MODULE_PARM_DESC(nflog, "register as internal netfilter logging module"); - -/* global data structures */ - -typedef struct { - unsigned int qlen; /* number of nlmsgs' in the skb */ - struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */ - struct sk_buff *skb; /* the pre-allocated skb */ - struct timer_list timer; /* the timer function */ -} ulog_buff_t; - -static int ulog_net_id __read_mostly; -struct ulog_net { - unsigned int nlgroup[ULOG_MAXNLGROUPS]; - ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS]; - struct sock *nflognl; - spinlock_t lock; -}; - -static struct ulog_net *ulog_pernet(struct net *net) -{ - return net_generic(net, ulog_net_id); -} - -/* send one ulog_buff_t to userspace */ -static void ulog_send(struct ulog_net *ulog, unsigned int nlgroupnum) -{ - ulog_buff_t *ub = &ulog->ulog_buffers[nlgroupnum]; - - pr_debug("ulog_send: timer is deleting\n"); - del_timer(&ub->timer); - - if (!ub->skb) { - pr_debug("ulog_send: nothing to send\n"); - return; - } - - /* last nlmsg needs NLMSG_DONE */ - if (ub->qlen > 1) - ub->lastnlh->nlmsg_type = NLMSG_DONE; - - NETLINK_CB(ub->skb).dst_group = nlgroupnum + 1; - pr_debug("throwing %d packets to netlink group %u\n", - ub->qlen, nlgroupnum + 1); - netlink_broadcast(ulog->nflognl, ub->skb, 0, nlgroupnum + 1, - GFP_ATOMIC); - - ub->qlen = 0; - ub->skb = NULL; - ub->lastnlh = NULL; -} - - -/* timer function to flush queue in flushtimeout time */ -static void ulog_timer(unsigned long data) -{ - unsigned int groupnum = *((unsigned int *)data); - struct ulog_net *ulog = container_of((void *)data, - struct ulog_net, - nlgroup[groupnum]); - pr_debug("timer function called, calling ulog_send\n"); - - /* lock to protect against somebody modifying our structure - * from ipt_ulog_target at the same time */ - spin_lock_bh(&ulog->lock); - ulog_send(ulog, groupnum); - spin_unlock_bh(&ulog->lock); -} - -static struct sk_buff *ulog_alloc_skb(unsigned int size) -{ - struct sk_buff *skb; - unsigned int n; - - /* alloc skb which should be big enough for a whole - * multipart message. WARNING: has to be <= 131000 - * due to slab allocator restrictions */ - - n = max(size, nlbufsiz); - skb = alloc_skb(n, GFP_ATOMIC | __GFP_NOWARN); - if (!skb) { - if (n > size) { - /* try to allocate only as much as we need for - * current packet */ - - skb = alloc_skb(size, GFP_ATOMIC); - if (!skb) - pr_debug("cannot even allocate %ub\n", size); - } - } - - return skb; -} - -static void ipt_ulog_packet(struct net *net, - unsigned int hooknum, - const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct ipt_ulog_info *loginfo, - const char *prefix) -{ - ulog_buff_t *ub; - ulog_packet_msg_t *pm; - size_t size, copy_len; - struct nlmsghdr *nlh; - struct timeval tv; - struct ulog_net *ulog = ulog_pernet(net); - - /* ffs == find first bit set, necessary because userspace - * is already shifting groupnumber, but we need unshifted. - * ffs() returns [1..32], we need [0..31] */ - unsigned int groupnum = ffs(loginfo->nl_group) - 1; - - /* calculate the size of the skb needed */ - if (loginfo->copy_range == 0 || loginfo->copy_range > skb->len) - copy_len = skb->len; - else - copy_len = loginfo->copy_range; - - size = nlmsg_total_size(sizeof(*pm) + copy_len); - - ub = &ulog->ulog_buffers[groupnum]; - - spin_lock_bh(&ulog->lock); - - if (!ub->skb) { - if (!(ub->skb = ulog_alloc_skb(size))) - goto alloc_failure; - } else if (ub->qlen >= loginfo->qthreshold || - size > skb_tailroom(ub->skb)) { - /* either the queue len is too high or we don't have - * enough room in nlskb left. send it to userspace. */ - - ulog_send(ulog, groupnum); - - if (!(ub->skb = ulog_alloc_skb(size))) - goto alloc_failure; - } - - pr_debug("qlen %d, qthreshold %Zu\n", ub->qlen, loginfo->qthreshold); - - nlh = nlmsg_put(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, - sizeof(*pm)+copy_len, 0); - if (!nlh) { - pr_debug("error during nlmsg_put\n"); - goto out_unlock; - } - ub->qlen++; - - pm = nlmsg_data(nlh); - memset(pm, 0, sizeof(*pm)); - - /* We might not have a timestamp, get one */ - if (skb->tstamp.tv64 == 0) - __net_timestamp((struct sk_buff *)skb); - - /* copy hook, prefix, timestamp, payload, etc. */ - pm->data_len = copy_len; - tv = ktime_to_timeval(skb->tstamp); - put_unaligned(tv.tv_sec, &pm->timestamp_sec); - put_unaligned(tv.tv_usec, &pm->timestamp_usec); - put_unaligned(skb->mark, &pm->mark); - pm->hook = hooknum; - if (prefix != NULL) { - strncpy(pm->prefix, prefix, sizeof(pm->prefix) - 1); - pm->prefix[sizeof(pm->prefix) - 1] = '\0'; - } - else if (loginfo->prefix[0] != '\0') - strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix)); - - if (in && in->hard_header_len > 0 && - skb->mac_header != skb->network_header && - in->hard_header_len <= ULOG_MAC_LEN) { - memcpy(pm->mac, skb_mac_header(skb), in->hard_header_len); - pm->mac_len = in->hard_header_len; - } else - pm->mac_len = 0; - - if (in) - strncpy(pm->indev_name, in->name, sizeof(pm->indev_name)); - - if (out) - strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name)); - - /* copy_len <= skb->len, so can't fail. */ - if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0) - BUG(); - - /* check if we are building multi-part messages */ - if (ub->qlen > 1) - ub->lastnlh->nlmsg_flags |= NLM_F_MULTI; - - ub->lastnlh = nlh; - - /* if timer isn't already running, start it */ - if (!timer_pending(&ub->timer)) { - ub->timer.expires = jiffies + flushtimeout * HZ / 100; - add_timer(&ub->timer); - } - - /* if threshold is reached, send message to userspace */ - if (ub->qlen >= loginfo->qthreshold) { - if (loginfo->qthreshold > 1) - nlh->nlmsg_type = NLMSG_DONE; - ulog_send(ulog, groupnum); - } -out_unlock: - spin_unlock_bh(&ulog->lock); - - return; - -alloc_failure: - pr_debug("Error building netlink message\n"); - spin_unlock_bh(&ulog->lock); -} - -static unsigned int -ulog_tg(struct sk_buff *skb, const struct xt_action_param *par) -{ - struct net *net = dev_net(par->in ? par->in : par->out); - - ipt_ulog_packet(net, par->hooknum, skb, par->in, par->out, - par->targinfo, NULL); - return XT_CONTINUE; -} - -static void ipt_logfn(struct net *net, - u_int8_t pf, - unsigned int hooknum, - const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct nf_loginfo *li, - const char *prefix) -{ - struct ipt_ulog_info loginfo; - - if (!li || li->type != NF_LOG_TYPE_ULOG) { - loginfo.nl_group = ULOG_DEFAULT_NLGROUP; - loginfo.copy_range = 0; - loginfo.qthreshold = ULOG_DEFAULT_QTHRESHOLD; - loginfo.prefix[0] = '\0'; - } else { - loginfo.nl_group = li->u.ulog.group; - loginfo.copy_range = li->u.ulog.copy_len; - loginfo.qthreshold = li->u.ulog.qthreshold; - strlcpy(loginfo.prefix, prefix, sizeof(loginfo.prefix)); - } - - ipt_ulog_packet(net, hooknum, skb, in, out, &loginfo, prefix); -} - -static int ulog_tg_check(const struct xt_tgchk_param *par) -{ - const struct ipt_ulog_info *loginfo = par->targinfo; - - if (!par->net->xt.ulog_warn_deprecated) { - pr_info("ULOG is deprecated and it will be removed soon, " - "use NFLOG instead\n"); - par->net->xt.ulog_warn_deprecated = true; - } - - if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') { - pr_debug("prefix not null-terminated\n"); - return -EINVAL; - } - if (loginfo->qthreshold > ULOG_MAX_QLEN) { - pr_debug("queue threshold %Zu > MAX_QLEN\n", - loginfo->qthreshold); - return -EINVAL; - } - return 0; -} - -#ifdef CONFIG_COMPAT -struct compat_ipt_ulog_info { - compat_uint_t nl_group; - compat_size_t copy_range; - compat_size_t qthreshold; - char prefix[ULOG_PREFIX_LEN]; -}; - -static void ulog_tg_compat_from_user(void *dst, const void *src) -{ - const struct compat_ipt_ulog_info *cl = src; - struct ipt_ulog_info l = { - .nl_group = cl->nl_group, - .copy_range = cl->copy_range, - .qthreshold = cl->qthreshold, - }; - - memcpy(l.prefix, cl->prefix, sizeof(l.prefix)); - memcpy(dst, &l, sizeof(l)); -} - -static int ulog_tg_compat_to_user(void __user *dst, const void *src) -{ - const struct ipt_ulog_info *l = src; - struct compat_ipt_ulog_info cl = { - .nl_group = l->nl_group, - .copy_range = l->copy_range, - .qthreshold = l->qthreshold, - }; - - memcpy(cl.prefix, l->prefix, sizeof(cl.prefix)); - return copy_to_user(dst, &cl, sizeof(cl)) ? -EFAULT : 0; -} -#endif /* CONFIG_COMPAT */ - -static struct xt_target ulog_tg_reg __read_mostly = { - .name = "ULOG", - .family = NFPROTO_IPV4, - .target = ulog_tg, - .targetsize = sizeof(struct ipt_ulog_info), - .checkentry = ulog_tg_check, -#ifdef CONFIG_COMPAT - .compatsize = sizeof(struct compat_ipt_ulog_info), - .compat_from_user = ulog_tg_compat_from_user, - .compat_to_user = ulog_tg_compat_to_user, -#endif - .me = THIS_MODULE, -}; - -static struct nf_logger ipt_ulog_logger __read_mostly = { - .name = "ipt_ULOG", - .logfn = ipt_logfn, - .me = THIS_MODULE, -}; - -static int __net_init ulog_tg_net_init(struct net *net) -{ - int i; - struct ulog_net *ulog = ulog_pernet(net); - struct netlink_kernel_cfg cfg = { - .groups = ULOG_MAXNLGROUPS, - }; - - spin_lock_init(&ulog->lock); - /* initialize ulog_buffers */ - for (i = 0; i < ULOG_MAXNLGROUPS; i++) { - ulog->nlgroup[i] = i; - setup_timer(&ulog->ulog_buffers[i].timer, ulog_timer, - (unsigned long)&ulog->nlgroup[i]); - } - - ulog->nflognl = netlink_kernel_create(net, NETLINK_NFLOG, &cfg); - if (!ulog->nflognl) - return -ENOMEM; - - if (nflog) - nf_log_set(net, NFPROTO_IPV4, &ipt_ulog_logger); - - return 0; -} - -static void __net_exit ulog_tg_net_exit(struct net *net) -{ - ulog_buff_t *ub; - int i; - struct ulog_net *ulog = ulog_pernet(net); - - if (nflog) - nf_log_unset(net, &ipt_ulog_logger); - - netlink_kernel_release(ulog->nflognl); - - /* remove pending timers and free allocated skb's */ - for (i = 0; i < ULOG_MAXNLGROUPS; i++) { - ub = &ulog->ulog_buffers[i]; - pr_debug("timer is deleting\n"); - del_timer(&ub->timer); - - if (ub->skb) { - kfree_skb(ub->skb); - ub->skb = NULL; - } - } -} - -static struct pernet_operations ulog_tg_net_ops = { - .init = ulog_tg_net_init, - .exit = ulog_tg_net_exit, - .id = &ulog_net_id, - .size = sizeof(struct ulog_net), -}; - -static int __init ulog_tg_init(void) -{ - int ret; - pr_debug("init module\n"); - - if (nlbufsiz > 128*1024) { - pr_warn("Netlink buffer has to be <= 128kB\n"); - return -EINVAL; - } - - ret = register_pernet_subsys(&ulog_tg_net_ops); - if (ret) - goto out_pernet; - - ret = xt_register_target(&ulog_tg_reg); - if (ret < 0) - goto out_target; - - if (nflog) - nf_log_register(NFPROTO_IPV4, &ipt_ulog_logger); - - return 0; - -out_target: - unregister_pernet_subsys(&ulog_tg_net_ops); -out_pernet: - return ret; -} - -static void __exit ulog_tg_exit(void) -{ - pr_debug("cleanup_module\n"); - if (nflog) - nf_log_unregister(&ipt_ulog_logger); - xt_unregister_target(&ulog_tg_reg); - unregister_pernet_subsys(&ulog_tg_net_ops); -} - -module_init(ulog_tg_init); -module_exit(ulog_tg_exit); -- cgit v1.2.3 From 5962815a6a56566318a60dc53ff8789b7e6ec71f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 18 Jun 2014 19:24:30 +0200 Subject: netfilter: nf_log: use an array of loggers instead of list Now that legacy ulog targets are not available anymore in the tree, we can have up to two possible loggers: 1) The plain text logging via kernel logging ring. 2) The nfnetlink_log infrastructure which delivers log messages to userspace. This patch replaces the list of loggers by an array of two pointers per family for each possible logger and it also introduces a new field to the nf_logger structure which indicates the position in the logger array (based on the logger type). This prepares a follow up patch that consolidates the nf_log_packet() interface by allowing to specify the logger as parameter. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_log.h | 15 ++++++++----- net/bridge/netfilter/ebt_log.c | 1 + net/netfilter/nf_log.c | 50 ++++++++++++++++++++---------------------- net/netfilter/nfnetlink_log.c | 1 + net/netfilter/xt_LOG.c | 2 ++ 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/include/net/netfilter/nf_log.h b/include/net/netfilter/nf_log.h index 99eac12d040b..06b4c6b07f52 100644 --- a/include/net/netfilter/nf_log.h +++ b/include/net/netfilter/nf_log.h @@ -12,8 +12,11 @@ #define NF_LOG_UID 0x08 /* Log UID owning local socket */ #define NF_LOG_MASK 0x0f -#define NF_LOG_TYPE_LOG 0x01 -#define NF_LOG_TYPE_ULOG 0x02 +enum nf_log_type { + NF_LOG_TYPE_LOG = 0, + NF_LOG_TYPE_ULOG, + NF_LOG_TYPE_MAX +}; struct nf_loginfo { u_int8_t type; @@ -40,10 +43,10 @@ typedef void nf_logfn(struct net *net, const char *prefix); struct nf_logger { - struct module *me; - nf_logfn *logfn; - char *name; - struct list_head list[NFPROTO_NUMPROTO]; + char *name; + enum nf_log_type type; + nf_logfn *logfn; + struct module *me; }; /* Function to register/unregister log function. */ diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index 5322a36867a3..0577477aacd8 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c @@ -207,6 +207,7 @@ static struct xt_target ebt_log_tg_reg __read_mostly = { static struct nf_logger ebt_log_logger __read_mostly = { .name = "ebt_log", + .type = NF_LOG_TYPE_LOG, .logfn = &ebt_log_packet, .me = THIS_MODULE, }; diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index 85296d4eac0e..7a29a3a46172 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -16,16 +16,22 @@ #define NF_LOG_PREFIXLEN 128 #define NFLOGGER_NAME_LEN 64 -static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly; +static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly; static DEFINE_MUTEX(nf_log_mutex); static struct nf_logger *__find_logger(int pf, const char *str_logger) { - struct nf_logger *t; + struct nf_logger *log; + int i; + + for (i = 0; i < NF_LOG_TYPE_MAX; i++) { + if (loggers[pf][i] == NULL) + continue; - list_for_each_entry(t, &nf_loggers_l[pf], list[pf]) { - if (!strnicmp(str_logger, t->name, strlen(t->name))) - return t; + log = rcu_dereference_protected(loggers[pf][i], + lockdep_is_held(&nf_log_mutex)); + if (!strnicmp(str_logger, log->name, strlen(log->name))) + return log; } return NULL; @@ -73,17 +79,14 @@ int nf_log_register(u_int8_t pf, struct nf_logger *logger) if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers)) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(logger->list); i++) - INIT_LIST_HEAD(&logger->list[i]); - mutex_lock(&nf_log_mutex); if (pf == NFPROTO_UNSPEC) { for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) - list_add_tail(&(logger->list[i]), &(nf_loggers_l[i])); + rcu_assign_pointer(loggers[i][logger->type], logger); } else { /* register at end of list to honor first register win */ - list_add_tail(&logger->list[pf], &nf_loggers_l[pf]); + rcu_assign_pointer(loggers[pf][logger->type], logger); } mutex_unlock(&nf_log_mutex); @@ -98,7 +101,7 @@ void nf_log_unregister(struct nf_logger *logger) mutex_lock(&nf_log_mutex); for (i = 0; i < NFPROTO_NUMPROTO; i++) - list_del(&logger->list[i]); + RCU_INIT_POINTER(loggers[i][logger->type], NULL); mutex_unlock(&nf_log_mutex); } EXPORT_SYMBOL(nf_log_unregister); @@ -188,8 +191,7 @@ static int seq_show(struct seq_file *s, void *v) { loff_t *pos = v; const struct nf_logger *logger; - struct nf_logger *t; - int ret; + int i, ret; struct net *net = seq_file_net(s); logger = rcu_dereference_protected(net->nf.nf_loggers[*pos], @@ -203,11 +205,16 @@ static int seq_show(struct seq_file *s, void *v) if (ret < 0) return ret; - list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) { - ret = seq_printf(s, "%s", t->name); + for (i = 0; i < NF_LOG_TYPE_MAX; i++) { + if (loggers[*pos][i] == NULL) + continue; + + logger = rcu_dereference_protected(loggers[*pos][i], + lockdep_is_held(&nf_log_mutex)); + ret = seq_printf(s, "%s", logger->name); if (ret < 0) return ret; - if (&t->list[*pos] != nf_loggers_l[*pos].prev) { + if (i == 0 && loggers[*pos][i + 1] != NULL) { ret = seq_printf(s, ","); if (ret < 0) return ret; @@ -389,14 +396,5 @@ static struct pernet_operations nf_log_net_ops = { int __init netfilter_log_init(void) { - int i, ret; - - ret = register_pernet_subsys(&nf_log_net_ops); - if (ret < 0) - return ret; - - for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) - INIT_LIST_HEAD(&(nf_loggers_l[i])); - - return 0; + return register_pernet_subsys(&nf_log_net_ops); } diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index d292c8d286eb..160bb8ea9923 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -773,6 +773,7 @@ nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, static struct nf_logger nfulnl_logger __read_mostly = { .name = "nfnetlink_log", + .type = NF_LOG_TYPE_ULOG, .logfn = &nfulnl_log_packet, .me = THIS_MODULE, }; diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c index 5ab24843370a..e668d9797cf3 100644 --- a/net/netfilter/xt_LOG.c +++ b/net/netfilter/xt_LOG.c @@ -896,6 +896,7 @@ static struct xt_target log_tg_regs[] __read_mostly = { static struct nf_logger ipt_log_logger __read_mostly = { .name = "ipt_LOG", + .type = NF_LOG_TYPE_LOG, .logfn = &ipt_log_packet, .me = THIS_MODULE, }; @@ -903,6 +904,7 @@ static struct nf_logger ipt_log_logger __read_mostly = { #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) static struct nf_logger ip6t_log_logger __read_mostly = { .name = "ip6t_LOG", + .type = NF_LOG_TYPE_LOG, .logfn = &ip6t_log_packet, .me = THIS_MODULE, }; -- cgit v1.2.3 From 27fd8d90c996caa480ed6777eaaf21d9e5166cc3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 19 Jun 2014 12:37:58 +0200 Subject: netfilter: nf_log: move log buffering to core logging This patch moves Eric Dumazet's log buffer implementation from the xt_log.h header file to the core net/netfilter/nf_log.c. This also includes the renaming of the structure and functions to avoid possible undesired namespace clashes. This change allows us to use it from the arp and bridge packet logging implementation in follow up patches. --- include/net/netfilter/nf_log.h | 6 + include/net/netfilter/xt_log.h | 54 -------- net/netfilter/nf_log.c | 57 ++++++++ net/netfilter/xt_LOG.c | 301 +++++++++++++++++++++-------------------- 4 files changed, 217 insertions(+), 201 deletions(-) delete mode 100644 include/net/netfilter/xt_log.h diff --git a/include/net/netfilter/nf_log.h b/include/net/netfilter/nf_log.h index 06b4c6b07f52..aaec845de106 100644 --- a/include/net/netfilter/nf_log.h +++ b/include/net/netfilter/nf_log.h @@ -72,4 +72,10 @@ void nf_log_packet(struct net *net, const struct nf_loginfo *li, const char *fmt, ...); +struct nf_log_buf; + +struct nf_log_buf *nf_log_buf_open(void); +__printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...); +void nf_log_buf_close(struct nf_log_buf *m); + #endif /* _NF_LOG_H */ diff --git a/include/net/netfilter/xt_log.h b/include/net/netfilter/xt_log.h deleted file mode 100644 index 9d9756cca013..000000000000 --- a/include/net/netfilter/xt_log.h +++ /dev/null @@ -1,54 +0,0 @@ -#define S_SIZE (1024 - (sizeof(unsigned int) + 1)) - -struct sbuff { - unsigned int count; - char buf[S_SIZE + 1]; -}; -static struct sbuff emergency, *emergency_ptr = &emergency; - -static __printf(2, 3) int sb_add(struct sbuff *m, const char *f, ...) -{ - va_list args; - int len; - - if (likely(m->count < S_SIZE)) { - va_start(args, f); - len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args); - va_end(args); - if (likely(m->count + len < S_SIZE)) { - m->count += len; - return 0; - } - } - m->count = S_SIZE; - printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n"); - return -1; -} - -static struct sbuff *sb_open(void) -{ - struct sbuff *m = kmalloc(sizeof(*m), GFP_ATOMIC); - - if (unlikely(!m)) { - local_bh_disable(); - do { - m = xchg(&emergency_ptr, NULL); - } while (!m); - } - m->count = 0; - return m; -} - -static void sb_close(struct sbuff *m) -{ - m->buf[m->count] = 0; - printk("%s\n", m->buf); - - if (likely(m != &emergency)) - kfree(m); - else { - emergency_ptr = m; - local_bh_enable(); - } -} - diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index 7a29a3a46172..0b6b2c874199 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -157,6 +157,63 @@ void nf_log_packet(struct net *net, } EXPORT_SYMBOL(nf_log_packet); +#define S_SIZE (1024 - (sizeof(unsigned int) + 1)) + +struct nf_log_buf { + unsigned int count; + char buf[S_SIZE + 1]; +}; +static struct nf_log_buf emergency, *emergency_ptr = &emergency; + +__printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...) +{ + va_list args; + int len; + + if (likely(m->count < S_SIZE)) { + va_start(args, f); + len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args); + va_end(args); + if (likely(m->count + len < S_SIZE)) { + m->count += len; + return 0; + } + } + m->count = S_SIZE; + printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n"); + return -1; +} +EXPORT_SYMBOL_GPL(nf_log_buf_add); + +struct nf_log_buf *nf_log_buf_open(void) +{ + struct nf_log_buf *m = kmalloc(sizeof(*m), GFP_ATOMIC); + + if (unlikely(!m)) { + local_bh_disable(); + do { + m = xchg(&emergency_ptr, NULL); + } while (!m); + } + m->count = 0; + return m; +} +EXPORT_SYMBOL_GPL(nf_log_buf_open); + +void nf_log_buf_close(struct nf_log_buf *m) +{ + m->buf[m->count] = 0; + printk("%s\n", m->buf); + + if (likely(m != &emergency)) + kfree(m); + else { + emergency_ptr = m; + local_bh_enable(); + } +} +EXPORT_SYMBOL_GPL(nf_log_buf_close); + #ifdef CONFIG_PROC_FS static void *seq_start(struct seq_file *seq, loff_t *pos) { diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c index e668d9797cf3..649b85fc5463 100644 --- a/net/netfilter/xt_LOG.c +++ b/net/netfilter/xt_LOG.c @@ -27,7 +27,6 @@ #include #include #include -#include static struct nf_loginfo default_loginfo = { .type = NF_LOG_TYPE_LOG, @@ -39,7 +38,7 @@ static struct nf_loginfo default_loginfo = { }, }; -static int dump_udp_header(struct sbuff *m, const struct sk_buff *skb, +static int dump_udp_header(struct nf_log_buf *m, const struct sk_buff *skb, u8 proto, int fragment, unsigned int offset) { struct udphdr _udph; @@ -47,9 +46,9 @@ static int dump_udp_header(struct sbuff *m, const struct sk_buff *skb, if (proto == IPPROTO_UDP) /* Max length: 10 "PROTO=UDP " */ - sb_add(m, "PROTO=UDP "); + nf_log_buf_add(m, "PROTO=UDP "); else /* Max length: 14 "PROTO=UDPLITE " */ - sb_add(m, "PROTO=UDPLITE "); + nf_log_buf_add(m, "PROTO=UDPLITE "); if (fragment) goto out; @@ -57,20 +56,20 @@ static int dump_udp_header(struct sbuff *m, const struct sk_buff *skb, /* Max length: 25 "INCOMPLETE [65535 bytes] " */ uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); if (uh == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); return 1; } /* Max length: 20 "SPT=65535 DPT=65535 " */ - sb_add(m, "SPT=%u DPT=%u LEN=%u ", ntohs(uh->source), ntohs(uh->dest), - ntohs(uh->len)); + nf_log_buf_add(m, "SPT=%u DPT=%u LEN=%u ", + ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); out: return 0; } -static int dump_tcp_header(struct sbuff *m, const struct sk_buff *skb, +static int dump_tcp_header(struct nf_log_buf *m, const struct sk_buff *skb, u8 proto, int fragment, unsigned int offset, unsigned int logflags) { @@ -78,7 +77,7 @@ static int dump_tcp_header(struct sbuff *m, const struct sk_buff *skb, const struct tcphdr *th; /* Max length: 10 "PROTO=TCP " */ - sb_add(m, "PROTO=TCP "); + nf_log_buf_add(m, "PROTO=TCP "); if (fragment) return 0; @@ -86,40 +85,43 @@ static int dump_tcp_header(struct sbuff *m, const struct sk_buff *skb, /* Max length: 25 "INCOMPLETE [65535 bytes] " */ th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); if (th == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); return 1; } /* Max length: 20 "SPT=65535 DPT=65535 " */ - sb_add(m, "SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest)); + nf_log_buf_add(m, "SPT=%u DPT=%u ", + ntohs(th->source), ntohs(th->dest)); /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ - if (logflags & XT_LOG_TCPSEQ) - sb_add(m, "SEQ=%u ACK=%u ", ntohl(th->seq), ntohl(th->ack_seq)); + if (logflags & XT_LOG_TCPSEQ) { + nf_log_buf_add(m, "SEQ=%u ACK=%u ", + ntohl(th->seq), ntohl(th->ack_seq)); + } /* Max length: 13 "WINDOW=65535 " */ - sb_add(m, "WINDOW=%u ", ntohs(th->window)); + nf_log_buf_add(m, "WINDOW=%u ", ntohs(th->window)); /* Max length: 9 "RES=0x3C " */ - sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & + nf_log_buf_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ if (th->cwr) - sb_add(m, "CWR "); + nf_log_buf_add(m, "CWR "); if (th->ece) - sb_add(m, "ECE "); + nf_log_buf_add(m, "ECE "); if (th->urg) - sb_add(m, "URG "); + nf_log_buf_add(m, "URG "); if (th->ack) - sb_add(m, "ACK "); + nf_log_buf_add(m, "ACK "); if (th->psh) - sb_add(m, "PSH "); + nf_log_buf_add(m, "PSH "); if (th->rst) - sb_add(m, "RST "); + nf_log_buf_add(m, "RST "); if (th->syn) - sb_add(m, "SYN "); + nf_log_buf_add(m, "SYN "); if (th->fin) - sb_add(m, "FIN "); + nf_log_buf_add(m, "FIN "); /* Max length: 11 "URGP=65535 " */ - sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); + nf_log_buf_add(m, "URGP=%u ", ntohs(th->urg_ptr)); if ((logflags & XT_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) { u_int8_t _opt[60 - sizeof(struct tcphdr)]; @@ -130,22 +132,22 @@ static int dump_tcp_header(struct sbuff *m, const struct sk_buff *skb, op = skb_header_pointer(skb, offset + sizeof(struct tcphdr), optsize, _opt); if (op == NULL) { - sb_add(m, "OPT (TRUNCATED)"); + nf_log_buf_add(m, "OPT (TRUNCATED)"); return 1; } /* Max length: 127 "OPT (" 15*4*2chars ") " */ - sb_add(m, "OPT ("); + nf_log_buf_add(m, "OPT ("); for (i = 0; i < optsize; i++) - sb_add(m, "%02X", op[i]); + nf_log_buf_add(m, "%02X", op[i]); - sb_add(m, ") "); + nf_log_buf_add(m, ") "); } return 0; } -static void dump_sk_uid_gid(struct sbuff *m, struct sock *sk) +static void dump_sk_uid_gid(struct nf_log_buf *m, struct sock *sk) { if (!sk || sk->sk_state == TCP_TIME_WAIT) return; @@ -153,7 +155,7 @@ static void dump_sk_uid_gid(struct sbuff *m, struct sock *sk) read_lock_bh(&sk->sk_callback_lock); if (sk->sk_socket && sk->sk_socket->file) { const struct cred *cred = sk->sk_socket->file->f_cred; - sb_add(m, "UID=%u GID=%u ", + nf_log_buf_add(m, "UID=%u GID=%u ", from_kuid_munged(&init_user_ns, cred->fsuid), from_kgid_munged(&init_user_ns, cred->fsgid)); } @@ -161,10 +163,9 @@ static void dump_sk_uid_gid(struct sbuff *m, struct sock *sk) } /* One level of recursion won't kill us */ -static void dump_ipv4_packet(struct sbuff *m, - const struct nf_loginfo *info, - const struct sk_buff *skb, - unsigned int iphoff) +static void dump_ipv4_packet(struct nf_log_buf *m, + const struct nf_loginfo *info, + const struct sk_buff *skb, unsigned int iphoff) { struct iphdr _iph; const struct iphdr *ih; @@ -177,32 +178,32 @@ static void dump_ipv4_packet(struct sbuff *m, ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); if (ih == NULL) { - sb_add(m, "TRUNCATED"); + nf_log_buf_add(m, "TRUNCATED"); return; } /* Important fields: * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ - sb_add(m, "SRC=%pI4 DST=%pI4 ", + nf_log_buf_add(m, "SRC=%pI4 DST=%pI4 ", &ih->saddr, &ih->daddr); /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ - sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", + nf_log_buf_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); /* Max length: 6 "CE DF MF " */ if (ntohs(ih->frag_off) & IP_CE) - sb_add(m, "CE "); + nf_log_buf_add(m, "CE "); if (ntohs(ih->frag_off) & IP_DF) - sb_add(m, "DF "); + nf_log_buf_add(m, "DF "); if (ntohs(ih->frag_off) & IP_MF) - sb_add(m, "MF "); + nf_log_buf_add(m, "MF "); /* Max length: 11 "FRAG:65535 " */ if (ntohs(ih->frag_off) & IP_OFFSET) - sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); + nf_log_buf_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); if ((logflags & XT_LOG_IPOPT) && ih->ihl * 4 > sizeof(struct iphdr)) { @@ -214,15 +215,15 @@ static void dump_ipv4_packet(struct sbuff *m, op = skb_header_pointer(skb, iphoff+sizeof(_iph), optsize, _opt); if (op == NULL) { - sb_add(m, "TRUNCATED"); + nf_log_buf_add(m, "TRUNCATED"); return; } /* Max length: 127 "OPT (" 15*4*2chars ") " */ - sb_add(m, "OPT ("); + nf_log_buf_add(m, "OPT ("); for (i = 0; i < optsize; i++) - sb_add(m, "%02X", op[i]); - sb_add(m, ") "); + nf_log_buf_add(m, "%02X", op[i]); + nf_log_buf_add(m, ") "); } switch (ih->protocol) { @@ -261,7 +262,7 @@ static void dump_ipv4_packet(struct sbuff *m, [ICMP_ADDRESSREPLY] = 12 }; /* Max length: 11 "PROTO=ICMP " */ - sb_add(m, "PROTO=ICMP "); + nf_log_buf_add(m, "PROTO=ICMP "); if (ntohs(ih->frag_off) & IP_OFFSET) break; @@ -270,19 +271,19 @@ static void dump_ipv4_packet(struct sbuff *m, ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, sizeof(_icmph), &_icmph); if (ich == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); break; } /* Max length: 18 "TYPE=255 CODE=255 " */ - sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); + nf_log_buf_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); /* Max length: 25 "INCOMPLETE [65535 bytes] " */ if (ich->type <= NR_ICMP_TYPES && required_len[ich->type] && skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { - sb_add(m, "INCOMPLETE [%u bytes] ", + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); break; } @@ -291,35 +292,37 @@ static void dump_ipv4_packet(struct sbuff *m, case ICMP_ECHOREPLY: case ICMP_ECHO: /* Max length: 19 "ID=65535 SEQ=65535 " */ - sb_add(m, "ID=%u SEQ=%u ", + nf_log_buf_add(m, "ID=%u SEQ=%u ", ntohs(ich->un.echo.id), ntohs(ich->un.echo.sequence)); break; case ICMP_PARAMETERPROB: /* Max length: 14 "PARAMETER=255 " */ - sb_add(m, "PARAMETER=%u ", + nf_log_buf_add(m, "PARAMETER=%u ", ntohl(ich->un.gateway) >> 24); break; case ICMP_REDIRECT: /* Max length: 24 "GATEWAY=255.255.255.255 " */ - sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); + nf_log_buf_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); /* Fall through */ case ICMP_DEST_UNREACH: case ICMP_SOURCE_QUENCH: case ICMP_TIME_EXCEEDED: /* Max length: 3+maxlen */ if (!iphoff) { /* Only recurse once. */ - sb_add(m, "["); + nf_log_buf_add(m, "["); dump_ipv4_packet(m, info, skb, iphoff + ih->ihl*4+sizeof(_icmph)); - sb_add(m, "] "); + nf_log_buf_add(m, "] "); } /* Max length: 10 "MTU=65535 " */ if (ich->type == ICMP_DEST_UNREACH && - ich->code == ICMP_FRAG_NEEDED) - sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu)); + ich->code == ICMP_FRAG_NEEDED) { + nf_log_buf_add(m, "MTU=%u ", + ntohs(ich->un.frag.mtu)); + } } break; } @@ -332,19 +335,19 @@ static void dump_ipv4_packet(struct sbuff *m, break; /* Max length: 9 "PROTO=AH " */ - sb_add(m, "PROTO=AH "); + nf_log_buf_add(m, "PROTO=AH "); /* Max length: 25 "INCOMPLETE [65535 bytes] " */ ah = skb_header_pointer(skb, iphoff+ih->ihl*4, sizeof(_ahdr), &_ahdr); if (ah == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); break; } /* Length: 15 "SPI=0xF1234567 " */ - sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); + nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi)); break; } case IPPROTO_ESP: { @@ -352,7 +355,7 @@ static void dump_ipv4_packet(struct sbuff *m, const struct ip_esp_hdr *eh; /* Max length: 10 "PROTO=ESP " */ - sb_add(m, "PROTO=ESP "); + nf_log_buf_add(m, "PROTO=ESP "); if (ntohs(ih->frag_off) & IP_OFFSET) break; @@ -361,18 +364,18 @@ static void dump_ipv4_packet(struct sbuff *m, eh = skb_header_pointer(skb, iphoff+ih->ihl*4, sizeof(_esph), &_esph); if (eh == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); break; } /* Length: 15 "SPI=0xF1234567 " */ - sb_add(m, "SPI=0x%x ", ntohl(eh->spi)); + nf_log_buf_add(m, "SPI=0x%x ", ntohl(eh->spi)); break; } /* Max length: 10 "PROTO 255 " */ default: - sb_add(m, "PROTO=%u ", ih->protocol); + nf_log_buf_add(m, "PROTO=%u ", ih->protocol); } /* Max length: 15 "UID=4294967295 " */ @@ -381,7 +384,7 @@ static void dump_ipv4_packet(struct sbuff *m, /* Max length: 16 "MARK=0xFFFFFFFF " */ if (!iphoff && skb->mark) - sb_add(m, "MARK=0x%x ", skb->mark); + nf_log_buf_add(m, "MARK=0x%x ", skb->mark); /* Proto Max log string length */ /* IP: 40+46+6+11+127 = 230 */ @@ -398,9 +401,9 @@ static void dump_ipv4_packet(struct sbuff *m, /* maxlen = 230+ 91 + 230 + 252 = 803 */ } -static void dump_ipv4_mac_header(struct sbuff *m, - const struct nf_loginfo *info, - const struct sk_buff *skb) +static void dump_ipv4_mac_header(struct nf_log_buf *m, + const struct nf_loginfo *info, + const struct sk_buff *skb) { struct net_device *dev = skb->dev; unsigned int logflags = 0; @@ -413,30 +416,30 @@ static void dump_ipv4_mac_header(struct sbuff *m, switch (dev->type) { case ARPHRD_ETHER: - sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", - eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, - ntohs(eth_hdr(skb)->h_proto)); + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, + ntohs(eth_hdr(skb)->h_proto)); return; default: break; } fallback: - sb_add(m, "MAC="); + nf_log_buf_add(m, "MAC="); if (dev->hard_header_len && skb->mac_header != skb->network_header) { const unsigned char *p = skb_mac_header(skb); unsigned int i; - sb_add(m, "%02x", *p++); + nf_log_buf_add(m, "%02x", *p++); for (i = 1; i < dev->hard_header_len; i++, p++) - sb_add(m, ":%02x", *p); + nf_log_buf_add(m, ":%02x", *p); } - sb_add(m, " "); + nf_log_buf_add(m, " "); } static void -log_packet_common(struct sbuff *m, +log_packet_common(struct nf_log_buf *m, u_int8_t pf, unsigned int hooknum, const struct sk_buff *skb, @@ -445,10 +448,10 @@ log_packet_common(struct sbuff *m, const struct nf_loginfo *loginfo, const char *prefix) { - sb_add(m, KERN_SOH "%c%sIN=%s OUT=%s ", - '0' + loginfo->u.log.level, prefix, - in ? in->name : "", - out ? out->name : ""); + nf_log_buf_add(m, KERN_SOH "%c%sIN=%s OUT=%s ", + '0' + loginfo->u.log.level, prefix, + in ? in->name : "", + out ? out->name : ""); #ifdef CONFIG_BRIDGE_NETFILTER if (skb->nf_bridge) { const struct net_device *physindev; @@ -456,10 +459,10 @@ log_packet_common(struct sbuff *m, physindev = skb->nf_bridge->physindev; if (physindev && in != physindev) - sb_add(m, "PHYSIN=%s ", physindev->name); + nf_log_buf_add(m, "PHYSIN=%s ", physindev->name); physoutdev = skb->nf_bridge->physoutdev; if (physoutdev && out != physoutdev) - sb_add(m, "PHYSOUT=%s ", physoutdev->name); + nf_log_buf_add(m, "PHYSOUT=%s ", physoutdev->name); } #endif } @@ -475,13 +478,13 @@ ipt_log_packet(struct net *net, const struct nf_loginfo *loginfo, const char *prefix) { - struct sbuff *m; + struct nf_log_buf *m; /* FIXME: Disabled from containers until syslog ns is supported */ if (!net_eq(net, &init_net)) return; - m = sb_open(); + m = nf_log_buf_open(); if (!loginfo) loginfo = &default_loginfo; @@ -493,15 +496,15 @@ ipt_log_packet(struct net *net, dump_ipv4_packet(m, loginfo, skb, 0); - sb_close(m); + nf_log_buf_close(m); } #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) /* One level of recursion won't kill us */ -static void dump_ipv6_packet(struct sbuff *m, - const struct nf_loginfo *info, - const struct sk_buff *skb, unsigned int ip6hoff, - int recurse) +static void dump_ipv6_packet(struct nf_log_buf *m, + const struct nf_loginfo *info, + const struct sk_buff *skb, unsigned int ip6hoff, + int recurse) { u_int8_t currenthdr; int fragment; @@ -518,19 +521,18 @@ static void dump_ipv6_packet(struct sbuff *m, ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); if (ih == NULL) { - sb_add(m, "TRUNCATED"); + nf_log_buf_add(m, "TRUNCATED"); return; } /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ - sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); + nf_log_buf_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ - sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", - ntohs(ih->payload_len) + sizeof(struct ipv6hdr), - (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, - ih->hop_limit, - (ntohl(*(__be32 *)ih) & 0x000fffff)); + nf_log_buf_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", + ntohs(ih->payload_len) + sizeof(struct ipv6hdr), + (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, + ih->hop_limit, (ntohl(*(__be32 *)ih) & 0x000fffff)); fragment = 0; ptr = ip6hoff + sizeof(struct ipv6hdr); @@ -541,35 +543,35 @@ static void dump_ipv6_packet(struct sbuff *m, hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); if (hp == NULL) { - sb_add(m, "TRUNCATED"); + nf_log_buf_add(m, "TRUNCATED"); return; } /* Max length: 48 "OPT (...) " */ if (logflags & XT_LOG_IPOPT) - sb_add(m, "OPT ( "); + nf_log_buf_add(m, "OPT ( "); switch (currenthdr) { case IPPROTO_FRAGMENT: { struct frag_hdr _fhdr; const struct frag_hdr *fh; - sb_add(m, "FRAG:"); + nf_log_buf_add(m, "FRAG:"); fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), &_fhdr); if (fh == NULL) { - sb_add(m, "TRUNCATED "); + nf_log_buf_add(m, "TRUNCATED "); return; } /* Max length: 6 "65535 " */ - sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); + nf_log_buf_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); /* Max length: 11 "INCOMPLETE " */ if (fh->frag_off & htons(0x0001)) - sb_add(m, "INCOMPLETE "); + nf_log_buf_add(m, "INCOMPLETE "); - sb_add(m, "ID:%08x ", ntohl(fh->identification)); + nf_log_buf_add(m, "ID:%08x ", ntohl(fh->identification)); if (ntohs(fh->frag_off) & 0xFFF8) fragment = 1; @@ -583,7 +585,7 @@ static void dump_ipv6_packet(struct sbuff *m, case IPPROTO_HOPOPTS: if (fragment) { if (logflags & XT_LOG_IPOPT) - sb_add(m, ")"); + nf_log_buf_add(m, ")"); return; } hdrlen = ipv6_optlen(hp); @@ -595,10 +597,10 @@ static void dump_ipv6_packet(struct sbuff *m, const struct ip_auth_hdr *ah; /* Max length: 3 "AH " */ - sb_add(m, "AH "); + nf_log_buf_add(m, "AH "); if (fragment) { - sb_add(m, ")"); + nf_log_buf_add(m, ")"); return; } @@ -609,13 +611,13 @@ static void dump_ipv6_packet(struct sbuff *m, * Max length: 26 "INCOMPLETE [65535 * bytes] )" */ - sb_add(m, "INCOMPLETE [%u bytes] )", - skb->len - ptr); + nf_log_buf_add(m, "INCOMPLETE [%u bytes] )", + skb->len - ptr); return; } /* Length: 15 "SPI=0xF1234567 */ - sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); + nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi)); } @@ -627,10 +629,10 @@ static void dump_ipv6_packet(struct sbuff *m, const struct ip_esp_hdr *eh; /* Max length: 4 "ESP " */ - sb_add(m, "ESP "); + nf_log_buf_add(m, "ESP "); if (fragment) { - sb_add(m, ")"); + nf_log_buf_add(m, ")"); return; } @@ -640,23 +642,23 @@ static void dump_ipv6_packet(struct sbuff *m, eh = skb_header_pointer(skb, ptr, sizeof(_esph), &_esph); if (eh == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] )", - skb->len - ptr); + nf_log_buf_add(m, "INCOMPLETE [%u bytes] )", + skb->len - ptr); return; } /* Length: 16 "SPI=0xF1234567 )" */ - sb_add(m, "SPI=0x%x )", ntohl(eh->spi)); + nf_log_buf_add(m, "SPI=0x%x )", ntohl(eh->spi)); } return; default: /* Max length: 20 "Unknown Ext Hdr 255" */ - sb_add(m, "Unknown Ext Hdr %u", currenthdr); + nf_log_buf_add(m, "Unknown Ext Hdr %u", currenthdr); return; } if (logflags & XT_LOG_IPOPT) - sb_add(m, ") "); + nf_log_buf_add(m, ") "); currenthdr = hp->nexthdr; ptr += hdrlen; @@ -678,7 +680,7 @@ static void dump_ipv6_packet(struct sbuff *m, const struct icmp6hdr *ic; /* Max length: 13 "PROTO=ICMPv6 " */ - sb_add(m, "PROTO=ICMPv6 "); + nf_log_buf_add(m, "PROTO=ICMPv6 "); if (fragment) break; @@ -686,20 +688,22 @@ static void dump_ipv6_packet(struct sbuff *m, /* Max length: 25 "INCOMPLETE [65535 bytes] " */ ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); if (ic == NULL) { - sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", + skb->len - ptr); return; } /* Max length: 18 "TYPE=255 CODE=255 " */ - sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); + nf_log_buf_add(m, "TYPE=%u CODE=%u ", + ic->icmp6_type, ic->icmp6_code); switch (ic->icmp6_type) { case ICMPV6_ECHO_REQUEST: case ICMPV6_ECHO_REPLY: /* Max length: 19 "ID=65535 SEQ=65535 " */ - sb_add(m, "ID=%u SEQ=%u ", - ntohs(ic->icmp6_identifier), - ntohs(ic->icmp6_sequence)); + nf_log_buf_add(m, "ID=%u SEQ=%u ", + ntohs(ic->icmp6_identifier), + ntohs(ic->icmp6_sequence)); break; case ICMPV6_MGM_QUERY: case ICMPV6_MGM_REPORT: @@ -708,28 +712,30 @@ static void dump_ipv6_packet(struct sbuff *m, case ICMPV6_PARAMPROB: /* Max length: 17 "POINTER=ffffffff " */ - sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer)); + nf_log_buf_add(m, "POINTER=%08x ", + ntohl(ic->icmp6_pointer)); /* Fall through */ case ICMPV6_DEST_UNREACH: case ICMPV6_PKT_TOOBIG: case ICMPV6_TIME_EXCEED: /* Max length: 3+maxlen */ if (recurse) { - sb_add(m, "["); + nf_log_buf_add(m, "["); dump_ipv6_packet(m, info, skb, ptr + sizeof(_icmp6h), 0); - sb_add(m, "] "); + nf_log_buf_add(m, "] "); } /* Max length: 10 "MTU=65535 " */ if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) - sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu)); + nf_log_buf_add(m, "MTU=%u ", + ntohl(ic->icmp6_mtu)); } break; } /* Max length: 10 "PROTO=255 " */ default: - sb_add(m, "PROTO=%u ", currenthdr); + nf_log_buf_add(m, "PROTO=%u ", currenthdr); } /* Max length: 15 "UID=4294967295 " */ @@ -738,12 +744,12 @@ static void dump_ipv6_packet(struct sbuff *m, /* Max length: 16 "MARK=0xFFFFFFFF " */ if (recurse && skb->mark) - sb_add(m, "MARK=0x%x ", skb->mark); + nf_log_buf_add(m, "MARK=0x%x ", skb->mark); } -static void dump_ipv6_mac_header(struct sbuff *m, - const struct nf_loginfo *info, - const struct sk_buff *skb) +static void dump_ipv6_mac_header(struct nf_log_buf *m, + const struct nf_loginfo *info, + const struct sk_buff *skb) { struct net_device *dev = skb->dev; unsigned int logflags = 0; @@ -756,16 +762,16 @@ static void dump_ipv6_mac_header(struct sbuff *m, switch (dev->type) { case ARPHRD_ETHER: - sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", - eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, - ntohs(eth_hdr(skb)->h_proto)); + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, + ntohs(eth_hdr(skb)->h_proto)); return; default: break; } fallback: - sb_add(m, "MAC="); + nf_log_buf_add(m, "MAC="); if (dev->hard_header_len && skb->mac_header != skb->network_header) { const unsigned char *p = skb_mac_header(skb); @@ -780,20 +786,21 @@ fallback: } if (p != NULL) { - sb_add(m, "%02x", *p++); + nf_log_buf_add(m, "%02x", *p++); for (i = 1; i < len; i++) - sb_add(m, ":%02x", *p++); + nf_log_buf_add(m, ":%02x", *p++); } - sb_add(m, " "); + nf_log_buf_add(m, " "); if (dev->type == ARPHRD_SIT) { const struct iphdr *iph = (struct iphdr *)skb_mac_header(skb); - sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, - &iph->daddr); + nf_log_buf_add(m, "TUNNEL=%pI4->%pI4 ", + &iph->saddr, &iph->daddr); } - } else - sb_add(m, " "); + } else { + nf_log_buf_add(m, " "); + } } static void @@ -806,13 +813,13 @@ ip6t_log_packet(struct net *net, const struct nf_loginfo *loginfo, const char *prefix) { - struct sbuff *m; + struct nf_log_buf *m; /* FIXME: Disabled from containers until syslog ns is supported */ if (!net_eq(net, &init_net)) return; - m = sb_open(); + m = nf_log_buf_open(); if (!loginfo) loginfo = &default_loginfo; @@ -824,7 +831,7 @@ ip6t_log_packet(struct net *net, dump_ipv6_packet(m, loginfo, skb, skb_network_offset(skb), 1); - sb_close(m); + nf_log_buf_close(m); } #endif -- cgit v1.2.3 From 92c2538f55132d8e0e53945204cfb137e7d64b6b Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 19 Jun 2014 21:38:52 -0700 Subject: mwifiex: add firmware dump feature for PCIe Firmware dump feature is added for PCIe based chipsets which can be used with the help of ethtool commands. 1) Trigger firmware dump operation: ethtool --set-dump mlan0 0xff When the operation is completed, udev event will be sent to trigger external application. 2) Following udev rule can be used to get the data from ethtool: DRIVER=="mwifiex_pcie", ACTION=="change", RUN+="/sbin/mwifiex_pcie_fw_dump.sh" mwifiex_pcie_fw_dump.sh: #!/bin/bash ethtool --set-dump mlan0 0 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/ITCM.log ethtool --set-dump mlan0 1 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/DTCM.log ethtool --set-dump mlan0 2 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/SQRAM.log ethtool --set-dump mlan0 3 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/IRAM.log Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 3 + drivers/net/wireless/mwifiex/ethtool.c | 83 ++++++++++++++ drivers/net/wireless/mwifiex/init.c | 13 ++- drivers/net/wireless/mwifiex/main.c | 2 + drivers/net/wireless/mwifiex/main.h | 29 +++++ drivers/net/wireless/mwifiex/pcie.c | 193 +++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/pcie.h | 10 ++ 7 files changed, 332 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 8dee6c86f4f1..421322f5e5fb 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -960,6 +960,9 @@ mwifiex_cmd_timeout_func(unsigned long function_context) if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) mwifiex_init_fw_complete(adapter); + if (adapter->if_ops.fw_dump) + adapter->if_ops.fw_dump(adapter); + if (adapter->if_ops.card_reset) adapter->if_ops.card_reset(adapter); } diff --git a/drivers/net/wireless/mwifiex/ethtool.c b/drivers/net/wireless/mwifiex/ethtool.c index bfb39908b2c6..528bdfa6c60c 100644 --- a/drivers/net/wireless/mwifiex/ethtool.c +++ b/drivers/net/wireless/mwifiex/ethtool.c @@ -64,7 +64,90 @@ static int mwifiex_ethtool_set_wol(struct net_device *dev, return 0; } +static int +mwifiex_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_adapter *adapter = priv->adapter; + struct memory_type_mapping *entry; + + if (!adapter->if_ops.fw_dump) + return -ENOTSUPP; + + dump->flag = adapter->curr_mem_idx; + dump->version = 1; + if (adapter->curr_mem_idx != MWIFIEX_FW_DUMP_IDX) { + entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx]; + dump->len = entry->mem_size; + } else { + dump->len = 0; + } + + return 0; +} + +static int +mwifiex_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, + void *buffer) +{ + u8 *p = buffer; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_adapter *adapter = priv->adapter; + struct memory_type_mapping *entry; + + if (!adapter->if_ops.fw_dump) + return -ENOTSUPP; + + if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) { + dev_err(adapter->dev, "firmware dump in progress!!\n"); + return -EBUSY; + } + + entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx]; + + if (!entry->mem_ptr) + return -EFAULT; + + memcpy(p, entry->mem_ptr, entry->mem_size); + + entry->mem_size = 0; + vfree(entry->mem_ptr); + entry->mem_ptr = NULL; + + return 0; +} + +static int mwifiex_set_dump(struct net_device *dev, struct ethtool_dump *val) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_adapter *adapter = priv->adapter; + + if (!adapter->if_ops.fw_dump) + return -ENOTSUPP; + + if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) { + dev_err(adapter->dev, "firmware dump in progress!!\n"); + return -EBUSY; + } + + if (val->flag == MWIFIEX_FW_DUMP_IDX) { + adapter->curr_mem_idx = val->flag; + adapter->if_ops.fw_dump(adapter); + return 0; + } + + if (val->flag < 0 || val->flag >= adapter->num_mem_types) + return -EINVAL; + + adapter->curr_mem_idx = val->flag; + + return 0; +} + const struct ethtool_ops mwifiex_ethtool_ops = { .get_wol = mwifiex_ethtool_get_wol, .set_wol = mwifiex_ethtool_set_wol, + .get_dump_flag = mwifiex_get_dump_flag, + .get_dump_data = mwifiex_get_dump_data, + .set_dump = mwifiex_set_dump, }; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 4ecd0b208ac6..2b68cf3aa336 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -382,6 +382,8 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) static void mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) { + int idx; + if (!adapter) { pr_err("%s: adapter is NULL\n", __func__); return; @@ -396,7 +398,16 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) dev_dbg(adapter->dev, "info: free cmd buffer\n"); mwifiex_free_cmd_buffer(adapter); - dev_dbg(adapter->dev, "info: free scan table\n"); + for (idx = 0; idx < adapter->num_mem_types; idx++) { + struct memory_type_mapping *entry = + &adapter->mem_type_mapping_tbl[idx]; + + if (entry->mem_ptr) { + vfree(entry->mem_ptr); + entry->mem_ptr = NULL; + } + entry->mem_size = 0; + } if (adapter->sleep_cfm) dev_kfree_skb_any(adapter->sleep_cfm); diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 40e4dbd5b89d..31bd34d0f79b 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -879,6 +879,8 @@ mwifiex_add_card(void *card, struct semaphore *sem, goto err_kmalloc; INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); + if (adapter->if_ops.iface_work) + INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work); /* Register the device. Fill up the private data structure with relevant information from the card. */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 1398afa84064..24791e2acf24 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -410,6 +411,28 @@ struct mwifiex_roc_cfg { struct ieee80211_channel chan; }; +#define MWIFIEX_FW_DUMP_IDX 0xff +#define FW_DUMP_MAX_NAME_LEN 8 +#define FW_DUMP_HOST_READY 0xEE +#define FW_DUMP_DONE 0xFF + +struct memory_type_mapping { + u8 mem_name[FW_DUMP_MAX_NAME_LEN]; + u8 *mem_ptr; + u32 mem_size; + u8 done_flag; +}; + +enum rdwr_status { + RDWR_STATUS_SUCCESS = 0, + RDWR_STATUS_FAILURE = 1, + RDWR_STATUS_DONE = 2 +}; + +enum mwifiex_iface_work_flags { + MWIFIEX_IFACE_WORK_FW_DUMP, +}; + struct mwifiex_adapter; struct mwifiex_private; @@ -674,6 +697,7 @@ struct mwifiex_if_ops { void (*card_reset) (struct mwifiex_adapter *); void (*fw_dump)(struct mwifiex_adapter *); int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); + void (*iface_work)(struct work_struct *work); }; struct mwifiex_adapter { @@ -809,6 +833,11 @@ struct mwifiex_adapter { bool ext_scan; u8 fw_api_ver; u8 fw_key_api_major_ver, fw_key_api_minor_ver; + struct work_struct iface_work; + unsigned long iface_work_flags; + struct memory_type_mapping *mem_type_mapping_tbl; + u8 num_mem_types; + u8 curr_mem_idx; }; int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 574d4b597468..6ea8e9d314b7 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -37,6 +37,13 @@ static struct mwifiex_if_ops pcie_ops; static struct semaphore add_remove_card_sem; +static struct memory_type_mapping mem_type_mapping_tbl[] = { + {"ITCM", NULL, 0, 0xF0}, + {"DTCM", NULL, 0, 0xF1}, + {"SQRAM", NULL, 0, 0xF2}, + {"IRAM", NULL, 0, 0xF3}, +}; + static int mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb, size_t size, int flags) @@ -192,6 +199,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, card->pcie.reg = data->reg; card->pcie.blksz_fw_dl = data->blksz_fw_dl; card->pcie.tx_buf_size = data->tx_buf_size; + card->pcie.supports_fw_dump = data->supports_fw_dump; } if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops, @@ -221,6 +229,8 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev) if (!adapter || !adapter->priv_num) return; + cancel_work_sync(&adapter->iface_work); + if (user_rmmod) { #ifdef CONFIG_PM_SLEEP if (adapter->is_suspended) @@ -307,6 +317,17 @@ static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data) return 0; } +/* This function reads u8 data from PCIE card register. */ +static int mwifiex_read_reg_byte(struct mwifiex_adapter *adapter, + int reg, u8 *data) +{ + struct pcie_service_card *card = adapter->card; + + *data = ioread8(card->pci_mmap1 + reg); + + return 0; +} + /* * This function adds delay loop to ensure FW is awake before proceeding. */ @@ -2173,6 +2194,174 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type, return 0; } +/* This function read/write firmware */ +static enum rdwr_status +mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag) +{ + int ret, tries; + u8 ctrl_data; + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + + ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl, FW_DUMP_HOST_READY); + if (ret) { + dev_err(adapter->dev, "PCIE write err\n"); + return RDWR_STATUS_FAILURE; + } + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + mwifiex_read_reg_byte(adapter, reg->fw_dump_ctrl, &ctrl_data); + if (ctrl_data == FW_DUMP_DONE) + return RDWR_STATUS_SUCCESS; + if (doneflag && ctrl_data == doneflag) + return RDWR_STATUS_DONE; + if (ctrl_data != FW_DUMP_HOST_READY) { + dev_info(adapter->dev, + "The ctrl reg was changed, re-try again!\n"); + mwifiex_write_reg(adapter, reg->fw_dump_ctrl, + FW_DUMP_HOST_READY); + if (ret) { + dev_err(adapter->dev, "PCIE write err\n"); + return RDWR_STATUS_FAILURE; + } + } + usleep_range(100, 200); + } + + dev_err(adapter->dev, "Fail to pull ctrl_data\n"); + return RDWR_STATUS_FAILURE; +} + +/* This function dump firmware memory to file */ +static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *creg = card->pcie.reg; + unsigned int reg, reg_start, reg_end; + struct timeval t; + u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0; + enum rdwr_status stat; + u32 memory_size; + static char *env[] = { "DRIVER=mwifiex_pcie", "EVENT=fw_dump", NULL }; + + if (!card->pcie.supports_fw_dump) + return; + + for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) { + struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; + + if (entry->mem_ptr) { + vfree(entry->mem_ptr); + entry->mem_ptr = NULL; + } + entry->mem_size = 0; + } + + do_gettimeofday(&t); + dev_info(adapter->dev, "== mwifiex firmware dump start: %u.%06u ==\n", + (u32)t.tv_sec, (u32)t.tv_usec); + + /* Read the number of the memories which will dump */ + stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + + reg = creg->fw_dump_start; + mwifiex_read_reg_byte(adapter, reg, &dump_num); + + /* Read the length of every memory which will dump */ + for (idx = 0; idx < dump_num; idx++) { + struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; + + stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + + memory_size = 0; + reg = creg->fw_dump_start; + for (i = 0; i < 4; i++) { + mwifiex_read_reg_byte(adapter, reg, &read_reg); + memory_size |= (read_reg << (i * 8)); + reg++; + } + + if (memory_size == 0) { + dev_info(adapter->dev, "Firmware dump Finished!\n"); + break; + } + + dev_info(adapter->dev, + "%s_SIZE=0x%x\n", entry->mem_name, memory_size); + entry->mem_ptr = vmalloc(memory_size + 1); + entry->mem_size = memory_size; + if (!entry->mem_ptr) { + dev_err(adapter->dev, + "Vmalloc %s failed\n", entry->mem_name); + goto done; + } + dbg_ptr = entry->mem_ptr; + end_ptr = dbg_ptr + memory_size; + + doneflag = entry->done_flag; + do_gettimeofday(&t); + dev_info(adapter->dev, "Start %s output %u.%06u, please wait...\n", + entry->mem_name, (u32)t.tv_sec, (u32)t.tv_usec); + + do { + stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag); + if (RDWR_STATUS_FAILURE == stat) + goto done; + + reg_start = creg->fw_dump_start; + reg_end = creg->fw_dump_end; + for (reg = reg_start; reg <= reg_end; reg++) { + mwifiex_read_reg_byte(adapter, reg, dbg_ptr); + if (dbg_ptr < end_ptr) + dbg_ptr++; + else + dev_err(adapter->dev, + "Allocated buf not enough\n"); + } + + if (stat != RDWR_STATUS_DONE) + continue; + + dev_info(adapter->dev, "%s done: size=0x%tx\n", + entry->mem_name, dbg_ptr - entry->mem_ptr); + break; + } while (true); + } + do_gettimeofday(&t); + dev_info(adapter->dev, "== mwifiex firmware dump end: %u.%06u ==\n", + (u32)t.tv_sec, (u32)t.tv_usec); + + kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env); + +done: + adapter->curr_mem_idx = 0; +} + +static void mwifiex_pcie_work(struct work_struct *work) +{ + struct mwifiex_adapter *adapter = + container_of(work, struct mwifiex_adapter, iface_work); + + if (test_and_clear_bit(MWIFIEX_IFACE_WORK_FW_DUMP, + &adapter->iface_work_flags)) + mwifiex_pcie_fw_dump_work(adapter); +} + +/* This function dumps FW information */ +static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) +{ + if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags)) + return; + + set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags); + + schedule_work(&adapter->iface_work); +} + /* * This function initializes the PCI-E host memory space, WCB rings, etc. * @@ -2342,6 +2531,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) adapter->dev = &pdev->dev; adapter->tx_buf_size = card->pcie.tx_buf_size; + adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; + adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); strcpy(adapter->fw_name, card->pcie.firmware); return 0; @@ -2394,6 +2585,8 @@ static struct mwifiex_if_ops pcie_ops = { .cleanup_mpa_buf = NULL, .init_fw_port = mwifiex_pcie_init_fw_port, .clean_pcie_ring = mwifiex_clean_pcie_ring_buf, + .fw_dump = mwifiex_pcie_fw_dump, + .iface_work = mwifiex_pcie_work, }; /* diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index e8ec561f8a64..ee073f5c9f0d 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -129,6 +129,9 @@ struct mwifiex_pcie_card_reg { u32 ring_tx_start_ptr; u8 pfu_enabled; u8 sleep_cookie; + u16 fw_dump_ctrl; + u16 fw_dump_start; + u16 fw_dump_end; }; static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = { @@ -191,6 +194,9 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, .pfu_enabled = 1, .sleep_cookie = 0, + .fw_dump_ctrl = 0xcf4, + .fw_dump_start = 0xcf8, + .fw_dump_end = 0xcff }; struct mwifiex_pcie_device { @@ -198,6 +204,7 @@ struct mwifiex_pcie_device { const struct mwifiex_pcie_card_reg *reg; u16 blksz_fw_dl; u16 tx_buf_size; + bool supports_fw_dump; }; static const struct mwifiex_pcie_device mwifiex_pcie8766 = { @@ -205,6 +212,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8766 = { .reg = &mwifiex_reg_8766, .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, + .supports_fw_dump = false, }; static const struct mwifiex_pcie_device mwifiex_pcie8897 = { @@ -212,6 +220,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8897 = { .reg = &mwifiex_reg_8897, .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, + .supports_fw_dump = true, }; struct mwifiex_evt_buf_desc { @@ -322,4 +331,5 @@ mwifiex_pcie_txbd_not_full(struct pcie_service_card *card) return 0; } + #endif /* _MWIFIEX_PCIE_H */ -- cgit v1.2.3 From 8915d73870a62c65fd7825f0ca2eb58c8bcdfb61 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 19 Jun 2014 21:38:53 -0700 Subject: mwifiex: use generic 'iface_work' workqueue for SDIO interface Existing dedicated card_reset work queue is replaced with the interface specific workqueue pointer provided by mwifiex module. Also new work flag is added for card reset task. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/sdio.c | 24 ++++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 24791e2acf24..582a9f9fee93 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -431,6 +431,7 @@ enum rdwr_status { enum mwifiex_iface_work_flags { MWIFIEX_IFACE_WORK_FW_DUMP, + MWIFIEX_IFACE_WORK_CARD_RESET, }; struct mwifiex_adapter; diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 4ce3d7b33991..2ae4dd754226 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -179,6 +179,8 @@ mwifiex_sdio_remove(struct sdio_func *func) if (!adapter || !adapter->priv_num) return; + cancel_work_sync(&adapter->iface_work); + if (user_rmmod) { if (adapter->is_suspended) mwifiex_sdio_resume(adapter->dev); @@ -1915,7 +1917,7 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) } static struct mmc_host *reset_host; -static void sdio_card_reset_worker(struct work_struct *work) +static void mwifiex_sdio_card_reset_work(struct work_struct *work) { struct mmc_host *target = reset_host; @@ -1933,15 +1935,29 @@ static void sdio_card_reset_worker(struct work_struct *work) mdelay(20); mmc_add_host(target); } -static DECLARE_WORK(card_reset_work, sdio_card_reset_worker); + +static void mwifiex_sdio_work(struct work_struct *work) +{ + struct mwifiex_adapter *adapter = + container_of(work, struct mwifiex_adapter, iface_work); + + if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, + &adapter->iface_work_flags)) + mwifiex_sdio_card_reset_work(work); +} /* This function resets the card */ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; + if (test_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &adapter->iface_work_flags)) + return; + + set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &adapter->iface_work_flags); + reset_host = card->func->card->host; - schedule_work(&card_reset_work); + schedule_work(&adapter->iface_work); } static struct mwifiex_if_ops sdio_ops = { @@ -1964,6 +1980,7 @@ static struct mwifiex_if_ops sdio_ops = { .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete, .event_complete = mwifiex_sdio_event_complete, .card_reset = mwifiex_sdio_card_reset, + .iface_work = mwifiex_sdio_work, }; /* @@ -2001,7 +2018,6 @@ mwifiex_sdio_cleanup_module(void) /* Set the flag as user is removing this module. */ user_rmmod = 1; - cancel_work_sync(&card_reset_work); sdio_unregister_driver(&mwifiex_sdio); } -- cgit v1.2.3 From 088df424be7fe5706ea7c385638d23f6a68c6dd1 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 19 Jun 2014 21:38:54 -0700 Subject: mwifiex: get rid of global pointer reset_host As we can derive host pointer from adapter, maintaining a global variable doesn't make sense. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sdio.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 2ae4dd754226..b34270d425f4 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1916,10 +1916,10 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) port, card->mp_data_port_mask); } -static struct mmc_host *reset_host; -static void mwifiex_sdio_card_reset_work(struct work_struct *work) +static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) { - struct mmc_host *target = reset_host; + struct sdio_mmc_card *card = adapter->card; + struct mmc_host *target = card->func->card->host; /* The actual reset operation must be run outside of driver thread. * This is because mmc_remove_host() will cause the device to be @@ -1943,20 +1943,17 @@ static void mwifiex_sdio_work(struct work_struct *work) if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &adapter->iface_work_flags)) - mwifiex_sdio_card_reset_work(work); + mwifiex_sdio_card_reset_work(adapter); } /* This function resets the card */ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) { - struct sdio_mmc_card *card = adapter->card; - if (test_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &adapter->iface_work_flags)) return; set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &adapter->iface_work_flags); - reset_host = card->func->card->host; schedule_work(&adapter->iface_work); } -- cgit v1.2.3 From 54881c6b37c8d6127fa67c6baf0dc887f1920ae6 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 19 Jun 2014 21:38:55 -0700 Subject: mwifiex: add firmware dump feature for SDIO Firmware dump feature is added for SDIO based chipsets which can be used with the help of ethtool commands. 1) Trigger firmware dump operation: ethtool --set-dump mlan0 0xff When the operation is completed, udev event will be sent to trigger external application. 2) Following udev rule can be used to get the data from ethtool: DRIVER=="mwifiex_sdio", ACTION=="change", RUN+="/sbin/mwifiex_sdio_fw_dump.sh" mwifiex_sdio_fw_dump.sh: #!/bin/bash ethtool --set-dump mlan0 0 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/ITCM.log ethtool --set-dump mlan0 1 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/DTCM.log ethtool --set-dump mlan0 2 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/SQRAM.log ethtool --set-dump mlan0 3 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/APU.log ethtool --set-dump mlan0 4 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/CIU.log ethtool --set-dump mlan0 5 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/ICU.log ethtool --set-dump mlan0 6 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/MAC.log Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sdio.c | 209 ++++++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/sdio.h | 12 +++ 2 files changed, 221 insertions(+) diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index b34270d425f4..95a1d1face95 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -50,6 +50,24 @@ static struct mwifiex_if_ops sdio_ops; static struct semaphore add_remove_card_sem; +static struct memory_type_mapping mem_type_mapping_tbl[] = { + {"ITCM", NULL, 0, 0xF0}, + {"DTCM", NULL, 0, 0xF1}, + {"SQRAM", NULL, 0, 0xF2}, + {"APU", NULL, 0, 0xF3}, + {"CIU", NULL, 0, 0xF4}, + {"ICU", NULL, 0, 0xF5}, + {"MAC", NULL, 0, 0xF6}, + {"EXT7", NULL, 0, 0xF7}, + {"EXT8", NULL, 0, 0xF8}, + {"EXT9", NULL, 0, 0xF9}, + {"EXT10", NULL, 0, 0xFA}, + {"EXT11", NULL, 0, 0xFB}, + {"EXT12", NULL, 0, 0xFC}, + {"EXT13", NULL, 0, 0xFD}, + {"EXTLAST", NULL, 0, 0xFE}, +}; + /* * SDIO probe. * @@ -87,6 +105,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) card->tx_buf_size = data->tx_buf_size; card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size; card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; + card->supports_fw_dump = data->supports_fw_dump; } sdio_claim_host(func); @@ -1779,6 +1798,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) adapter->dev = &func->dev; strcpy(adapter->fw_name, card->firmware); + adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; + adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); return 0; } @@ -1936,6 +1957,180 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) mmc_add_host(target); } +/* This function read/write firmware */ +static enum +rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter, + u8 doneflag) +{ + struct sdio_mmc_card *card = adapter->card; + int ret, tries; + u8 ctrl_data = 0; + + sdio_writeb(card->func, FW_DUMP_HOST_READY, card->reg->fw_dump_ctrl, + &ret); + if (ret) { + dev_err(adapter->dev, "SDIO Write ERR\n"); + return RDWR_STATUS_FAILURE; + } + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + ctrl_data = sdio_readb(card->func, card->reg->fw_dump_ctrl, + &ret); + if (ret) { + dev_err(adapter->dev, "SDIO read err\n"); + return RDWR_STATUS_FAILURE; + } + if (ctrl_data == FW_DUMP_DONE) + break; + if (doneflag && ctrl_data == doneflag) + return RDWR_STATUS_DONE; + if (ctrl_data != FW_DUMP_HOST_READY) { + dev_info(adapter->dev, + "The ctrl reg was changed, re-try again!\n"); + sdio_writeb(card->func, FW_DUMP_HOST_READY, + card->reg->fw_dump_ctrl, &ret); + if (ret) { + dev_err(adapter->dev, "SDIO write err\n"); + return RDWR_STATUS_FAILURE; + } + } + usleep_range(100, 200); + } + if (ctrl_data == FW_DUMP_HOST_READY) { + dev_err(adapter->dev, "Fail to pull ctrl_data\n"); + return RDWR_STATUS_FAILURE; + } + + return RDWR_STATUS_SUCCESS; +} + +/* This function dump firmware memory to file */ +static void mwifiex_sdio_fw_dump_work(struct work_struct *work) +{ + struct mwifiex_adapter *adapter = + container_of(work, struct mwifiex_adapter, iface_work); + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + unsigned int reg, reg_start, reg_end; + u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0; + struct timeval t; + enum rdwr_status stat; + u32 memory_size; + static char *env[] = { "DRIVER=mwifiex_sdio", "EVENT=fw_dump", NULL }; + + if (!card->supports_fw_dump) + return; + + for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) { + struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; + + if (entry->mem_ptr) { + vfree(entry->mem_ptr); + entry->mem_ptr = NULL; + } + entry->mem_size = 0; + } + + mwifiex_pm_wakeup_card(adapter); + sdio_claim_host(card->func); + + do_gettimeofday(&t); + dev_info(adapter->dev, "== mwifiex firmware dump start: %u.%06u ==\n", + (u32)t.tv_sec, (u32)t.tv_usec); + + stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + + reg = card->reg->fw_dump_start; + /* Read the number of the memories which will dump */ + dump_num = sdio_readb(card->func, reg, &ret); + if (ret) { + dev_err(adapter->dev, "SDIO read memory length err\n"); + goto done; + } + + /* Read the length of every memory which will dump */ + for (idx = 0; idx < dump_num; idx++) { + struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; + + stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + + memory_size = 0; + reg = card->reg->fw_dump_start; + for (i = 0; i < 4; i++) { + read_reg = sdio_readb(card->func, reg, &ret); + if (ret) { + dev_err(adapter->dev, "SDIO read err\n"); + goto done; + } + memory_size |= (read_reg << i*8); + reg++; + } + + if (memory_size == 0) { + dev_info(adapter->dev, "Firmware dump Finished!\n"); + break; + } + + dev_info(adapter->dev, + "%s_SIZE=0x%x\n", entry->mem_name, memory_size); + entry->mem_ptr = vmalloc(memory_size + 1); + entry->mem_size = memory_size; + if (!entry->mem_ptr) { + dev_err(adapter->dev, "Vmalloc %s failed\n", + entry->mem_name); + goto done; + } + dbg_ptr = entry->mem_ptr; + end_ptr = dbg_ptr + memory_size; + + doneflag = entry->done_flag; + do_gettimeofday(&t); + dev_info(adapter->dev, "Start %s output %u.%06u, please wait...\n", + entry->mem_name, (u32)t.tv_sec, (u32)t.tv_usec); + + do { + stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag); + if (stat == RDWR_STATUS_FAILURE) + goto done; + + reg_start = card->reg->fw_dump_start; + reg_end = card->reg->fw_dump_end; + for (reg = reg_start; reg <= reg_end; reg++) { + *dbg_ptr = sdio_readb(card->func, reg, &ret); + if (ret) { + dev_err(adapter->dev, + "SDIO read err\n"); + goto done; + } + if (dbg_ptr < end_ptr) + dbg_ptr++; + else + dev_err(adapter->dev, + "Allocated buf not enough\n"); + } + + if (stat != RDWR_STATUS_DONE) + continue; + + dev_info(adapter->dev, "%s done: size=0x%tx\n", + entry->mem_name, dbg_ptr - entry->mem_ptr); + break; + } while (1); + } + do_gettimeofday(&t); + dev_info(adapter->dev, "== mwifiex firmware dump end: %u.%06u ==\n", + (u32)t.tv_sec, (u32)t.tv_usec); + + kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env); + +done: + sdio_release_host(card->func); + adapter->curr_mem_idx = 0; +} + static void mwifiex_sdio_work(struct work_struct *work) { struct mwifiex_adapter *adapter = @@ -1944,6 +2139,9 @@ static void mwifiex_sdio_work(struct work_struct *work) if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &adapter->iface_work_flags)) mwifiex_sdio_card_reset_work(adapter); + if (test_and_clear_bit(MWIFIEX_IFACE_WORK_FW_DUMP, + &adapter->iface_work_flags)) + mwifiex_sdio_fw_dump_work(work); } /* This function resets the card */ @@ -1957,6 +2155,16 @@ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) schedule_work(&adapter->iface_work); } +/* This function dumps FW information */ +static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter) +{ + if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags)) + return; + + set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags); + schedule_work(&adapter->iface_work); +} + static struct mwifiex_if_ops sdio_ops = { .init_if = mwifiex_init_sdio, .cleanup_if = mwifiex_cleanup_sdio, @@ -1978,6 +2186,7 @@ static struct mwifiex_if_ops sdio_ops = { .event_complete = mwifiex_sdio_event_complete, .card_reset = mwifiex_sdio_card_reset, .iface_work = mwifiex_sdio_work, + .fw_dump = mwifiex_sdio_fw_dump, }; /* diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 6eea30b43ed7..e5633095984e 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -219,6 +219,9 @@ struct mwifiex_sdio_card_reg { u8 rd_len_p0_l; u8 rd_len_p0_u; u8 card_misc_cfg_reg; + u8 fw_dump_ctrl; + u8 fw_dump_start; + u8 fw_dump_end; }; struct sdio_mmc_card { @@ -231,6 +234,7 @@ struct sdio_mmc_card { u8 mp_agg_pkt_limit; bool supports_sdio_new_mode; bool has_control_mask; + bool supports_fw_dump; u16 tx_buf_size; u32 mp_tx_agg_buf_size; u32 mp_rx_agg_buf_size; @@ -257,6 +261,7 @@ struct mwifiex_sdio_device { u8 mp_agg_pkt_limit; bool supports_sdio_new_mode; bool has_control_mask; + bool supports_fw_dump; u16 tx_buf_size; u32 mp_tx_agg_buf_size; u32 mp_rx_agg_buf_size; @@ -307,6 +312,9 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = { .rd_len_p0_l = 0x0c, .rd_len_p0_u = 0x0d, .card_misc_cfg_reg = 0xcc, + .fw_dump_ctrl = 0xe2, + .fw_dump_start = 0xe3, + .fw_dump_end = 0xea, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { @@ -319,6 +327,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, + .supports_fw_dump = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { @@ -331,6 +340,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, + .supports_fw_dump = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { @@ -343,6 +353,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, + .supports_fw_dump = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { @@ -355,6 +366,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, + .supports_fw_dump = true, }; /* -- cgit v1.2.3 From 937a50451b0d1d1834485b47f00a7c0295413d09 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Thu, 19 Jun 2014 21:38:56 -0700 Subject: mwifiex: add hscfg to debugfs Some SDIO controllers do not support MMC_PM_KEEP_POWER properly. To test host sleep feature without putting the system into sleep we need to simulate host sleep configuration & handshake between driver and firmware using customized parameters. This patch adds hscfg debugfs item, with which user could change host sleep parameters for debugging. Signed-off-by: Xinming Hu Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/README | 30 +++++++++++ drivers/net/wireless/mwifiex/debugfs.c | 93 ++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/main.h | 2 + drivers/net/wireless/mwifiex/sta_ioctl.c | 4 +- 4 files changed, 127 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README index 3b55ce5690a5..831a98fdeda8 100644 --- a/drivers/net/wireless/mwifiex/README +++ b/drivers/net/wireless/mwifiex/README @@ -194,6 +194,36 @@ rdeeprom Example: echo "0 20" > rdeeprom : Read 20 bytes of EEPROM data from offset 0 +hscfg + This command is used to debug/simulate host sleep feature using + different configuration parameters. + + Usage: + echo " [GPIO# [gap]]]" > hscfg + cat hscfg + + where the parameters are, + : bit 0 = 1 -- broadcast data + bit 1 = 1 -- unicast data + bit 2 = 1 -- mac event + bit 3 = 1 -- multicast data + [GPIO#]: pin number of GPIO used to wakeup the host. + GPIO pin# (e.g. 0-7) or 0xff (interface, e.g. SDIO + will be used instead). + [gap]: the gap in milliseconds between wakeup signal and + wakeup event or 0xff for special setting (host + acknowledge required) when GPIO is used to wakeup host. + + Examples: + echo "-1" > hscfg : Cancel host sleep mode + echo "3" > hscfg : Broadcast and unicast data; + Use GPIO and gap set previously + echo "2 3" > hscfg : Unicast data and GPIO 3; + Use gap set previously + echo "2 1 160" > hscfg : Unicast data, GPIO 1 and gap 160 ms + echo "2 1 0xff" > hscfg : Unicast data, GPIO 1; Wait for host + to ack before sending wakeup event + getlog This command is used to get the statistics available in the station. Usage: diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 7b419bbcd544..6a194a996836 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -692,6 +692,97 @@ done: return ret; } +/* Proc hscfg file write handler + * This function can be used to configure the host sleep parameters. + */ +static ssize_t +mwifiex_hscfg_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = (void *)file->private_data; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1); + int ret, arg_num; + struct mwifiex_ds_hs_cfg hscfg; + int conditions = HS_CFG_COND_DEF; + u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF; + + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, ubuf, buf_size)) { + ret = -EFAULT; + goto done; + } + + arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap); + + memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg)); + + if (arg_num > 3) { + dev_err(priv->adapter->dev, "Too many arguments\n"); + ret = -EINVAL; + goto done; + } + + if (arg_num >= 1 && arg_num < 3) + mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET, + MWIFIEX_SYNC_CMD, &hscfg); + + if (arg_num) { + if (conditions == HS_CFG_CANCEL) { + mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD); + ret = count; + goto done; + } + hscfg.conditions = conditions; + } + if (arg_num >= 2) + hscfg.gpio = gpio; + if (arg_num == 3) + hscfg.gap = gap; + + hscfg.is_invoke_hostcmd = false; + mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, + MWIFIEX_SYNC_CMD, &hscfg); + + mwifiex_enable_hs(priv->adapter); + priv->adapter->hs_enabling = false; + ret = count; +done: + free_page(addr); + return ret; +} + +/* Proc hscfg file read handler + * This function can be used to read host sleep configuration + * parameters from driver. + */ +static ssize_t +mwifiex_hscfg_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = (void *)file->private_data; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + int pos, ret; + struct mwifiex_ds_hs_cfg hscfg; + + if (!buf) + return -ENOMEM; + + mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET, + MWIFIEX_SYNC_CMD, &hscfg); + + pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions, + hscfg.gpio, hscfg.gap); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + + free_page(addr); + return ret; +} #define MWIFIEX_DFS_ADD_FILE(name) do { \ if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \ @@ -725,6 +816,7 @@ MWIFIEX_DFS_FILE_READ_OPS(getlog); MWIFIEX_DFS_FILE_READ_OPS(fw_dump); MWIFIEX_DFS_FILE_OPS(regrdwr); MWIFIEX_DFS_FILE_OPS(rdeeprom); +MWIFIEX_DFS_FILE_OPS(hscfg); /* * This function creates the debug FS directory structure and the files. @@ -747,6 +839,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) MWIFIEX_DFS_ADD_FILE(regrdwr); MWIFIEX_DFS_ADD_FILE(rdeeprom); MWIFIEX_DFS_ADD_FILE(fw_dump); + MWIFIEX_DFS_ADD_FILE(hscfg); } /* diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 582a9f9fee93..5e734f948b07 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -920,6 +920,8 @@ int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, void mwifiex_process_hs_config(struct mwifiex_adapter *adapter); void mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated); +int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, + int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg); int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); int mwifiex_process_rx_packet(struct mwifiex_private *priv, diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 229526356d9b..6b9395f37742 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -389,8 +389,8 @@ done: * This function prepares the correct firmware command and * issues it. */ -static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, - int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) +int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, + int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) { struct mwifiex_adapter *adapter = priv->adapter; -- cgit v1.2.3 From 65da33f5557f0ed3f1227063bcf1f25248d456e5 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Thu, 19 Jun 2014 21:38:57 -0700 Subject: mwifiex: update Copyright to 2014 This patch updates mwifiex Copyright to 2014. Signed-off-by: Xinming Hu Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11ac.c | 2 +- drivers/net/wireless/mwifiex/11ac.h | 2 +- drivers/net/wireless/mwifiex/11h.c | 2 +- drivers/net/wireless/mwifiex/11n.c | 2 +- drivers/net/wireless/mwifiex/11n.h | 2 +- drivers/net/wireless/mwifiex/11n_aggr.c | 2 +- drivers/net/wireless/mwifiex/11n_aggr.h | 2 +- drivers/net/wireless/mwifiex/11n_rxreorder.c | 2 +- drivers/net/wireless/mwifiex/11n_rxreorder.h | 2 +- drivers/net/wireless/mwifiex/Makefile | 2 +- drivers/net/wireless/mwifiex/README | 2 +- drivers/net/wireless/mwifiex/cfg80211.c | 2 +- drivers/net/wireless/mwifiex/cfg80211.h | 2 +- drivers/net/wireless/mwifiex/cfp.c | 2 +- drivers/net/wireless/mwifiex/cmdevt.c | 2 +- drivers/net/wireless/mwifiex/debugfs.c | 2 +- drivers/net/wireless/mwifiex/decl.h | 2 +- drivers/net/wireless/mwifiex/ethtool.c | 2 +- drivers/net/wireless/mwifiex/fw.h | 2 +- drivers/net/wireless/mwifiex/ie.c | 2 +- drivers/net/wireless/mwifiex/init.c | 2 +- drivers/net/wireless/mwifiex/ioctl.h | 2 +- drivers/net/wireless/mwifiex/join.c | 2 +- drivers/net/wireless/mwifiex/main.c | 2 +- drivers/net/wireless/mwifiex/main.h | 2 +- drivers/net/wireless/mwifiex/pcie.c | 2 +- drivers/net/wireless/mwifiex/pcie.h | 2 +- drivers/net/wireless/mwifiex/scan.c | 2 +- drivers/net/wireless/mwifiex/sdio.c | 2 +- drivers/net/wireless/mwifiex/sdio.h | 2 +- drivers/net/wireless/mwifiex/sta_cmd.c | 2 +- drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 +- drivers/net/wireless/mwifiex/sta_event.c | 2 +- drivers/net/wireless/mwifiex/sta_ioctl.c | 2 +- drivers/net/wireless/mwifiex/sta_rx.c | 2 +- drivers/net/wireless/mwifiex/sta_tx.c | 2 +- drivers/net/wireless/mwifiex/txrx.c | 2 +- drivers/net/wireless/mwifiex/uap_cmd.c | 2 +- drivers/net/wireless/mwifiex/uap_event.c | 2 +- drivers/net/wireless/mwifiex/uap_txrx.c | 2 +- drivers/net/wireless/mwifiex/usb.c | 2 +- drivers/net/wireless/mwifiex/usb.h | 2 +- drivers/net/wireless/mwifiex/util.c | 2 +- drivers/net/wireless/mwifiex/util.h | 2 +- drivers/net/wireless/mwifiex/wmm.c | 2 +- drivers/net/wireless/mwifiex/wmm.h | 2 +- 46 files changed, 46 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/mwifiex/11ac.c b/drivers/net/wireless/mwifiex/11ac.c index 706831df1fa2..59d23fb2365f 100644 --- a/drivers/net/wireless/mwifiex/11ac.c +++ b/drivers/net/wireless/mwifiex/11ac.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: 802.11ac * - * Copyright (C) 2013, Marvell International Ltd. + * Copyright (C) 2013-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/11ac.h b/drivers/net/wireless/mwifiex/11ac.h index 0b02cb6cfcb4..1ca92c7a8a4a 100644 --- a/drivers/net/wireless/mwifiex/11ac.h +++ b/drivers/net/wireless/mwifiex/11ac.h @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: 802.11ac * - * Copyright (C) 2013, Marvell International Ltd. + * Copyright (C) 2013-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c index e76b0db4e3e6..2668e83afbb6 100644 --- a/drivers/net/wireless/mwifiex/11h.c +++ b/drivers/net/wireless/mwifiex/11h.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: 802.11h * - * Copyright (C) 2013, Marvell International Ltd. + * Copyright (C) 2013-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index e1c2f67ae85e..9d6d8d9f01e3 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: 802.11n * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 0b73fa08f5d4..2ee268b632be 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: 802.11n * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 5b32106182f8..b4c14b0fd3cb 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: 802.11n Aggregation * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/11n_aggr.h b/drivers/net/wireless/mwifiex/11n_aggr.h index 892098d6a696..0cd2a3eb6c17 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.h +++ b/drivers/net/wireless/mwifiex/11n_aggr.h @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: 802.11n Aggregation * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 0c3571f830b0..b22bae3d1205 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: 802.11n RX Re-ordering * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h index 0fc76e4a60f8..3a87bb0e3a62 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.h +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: 802.11n RX Re-ordering * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile index 2aa208ffbe23..9487d728ac20 100644 --- a/drivers/net/wireless/mwifiex/Makefile +++ b/drivers/net/wireless/mwifiex/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011, Marvell International Ltd. +# Copyright (C) 2011-2014, Marvell International Ltd. # # This software file (the "File") is distributed by Marvell International # Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README index 831a98fdeda8..31928caeeed2 100644 --- a/drivers/net/wireless/mwifiex/README +++ b/drivers/net/wireless/mwifiex/README @@ -1,4 +1,4 @@ -# Copyright (C) 2011, Marvell International Ltd. +# Copyright (C) 2011-2014, Marvell International Ltd. # # This software file (the "File") is distributed by Marvell International # Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index e33a0347d3e2..15fa7b453372 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: CFG80211 * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h index c5848934f111..908367857d58 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.h +++ b/drivers/net/wireless/mwifiex/cfg80211.h @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: CFG80211 * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index 0ddec3d4b059..b8242eb2be6f 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: Channel, Frequence and Power * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 421322f5e5fb..606877bc24d6 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: commands and events * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 6a194a996836..2713f7acd35e 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: debugfs * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 38da6ff6f416..0e03fe39fc35 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: generic data structures and APIs * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/ethtool.c b/drivers/net/wireless/mwifiex/ethtool.c index 528bdfa6c60c..04e56b5fc535 100644 --- a/drivers/net/wireless/mwifiex/ethtool.c +++ b/drivers/net/wireless/mwifiex/ethtool.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: ethtool * - * Copyright (C) 2013, Marvell International Ltd. + * Copyright (C) 2013-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 3175dd04834b..5561573452bb 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: Firmware specific macros & structures * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index 3bf3d58bbc02..b933794758b7 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -2,7 +2,7 @@ * Marvell Wireless LAN device driver: management IE handling- setting and * deleting IE. * - * Copyright (C) 2012, Marvell International Ltd. + * Copyright (C) 2012-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 2b68cf3aa336..269a277d0a2e 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: HW/FW Initialization * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 1b576722671d..0847f3e07ab7 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: ioctl data structures & APIs * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 89dc62a467f4..fc135649b85f 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: association and ad-hoc start/join * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 31bd34d0f79b..657504c3c79d 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: major functions * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 5e734f948b07..a2733b1e63f9 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: major data structures and prototypes * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 6ea8e9d314b7..3c224a793b82 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: PCIE specific handling * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index ee073f5c9f0d..a1a8fd3bc1be 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -3,7 +3,7 @@ * @brief This file contains definitions for PCI-E interface. * driver. * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 45c5b3450cf5..dee717a19ddb 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: scan ioctl and command handling * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 95a1d1face95..1da04a086bd9 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: SDIO specific handling * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index e5633095984e..6b8835ec88f1 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: SDIO specific definitions * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 88202ce0c139..0f077aaadab6 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: station command handling * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 577f2979ed8f..822357b7b0bb 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: station command response handling * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index f6395ef11a72..f1c240eca0cd 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: station event handling * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 6b9395f37742..1a03d4d8b418 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: functions for station ioctl * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index 8b639d7fe6df..9ceb1dbe34c5 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: station RX data handling * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index 5fce7e78a36e..cf330ba951cd 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: station TX data handling * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 37f26afd4314..08205683f877 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: generic TX/RX data handling * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index 32643555dd2a..300bab438011 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: AP specific command handling * - * Copyright (C) 2012, Marvell International Ltd. + * Copyright (C) 2012-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 92e77a398ecf..7c2b97660a03 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: AP event handling * - * Copyright (C) 2012, Marvell International Ltd. + * Copyright (C) 2012-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index 0c87f8f9113a..ddfc3c6c1e78 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: AP TX and RX data handling * - * Copyright (C) 2012, Marvell International Ltd. + * Copyright (C) 2012-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index a8ce8130cfae..7118a18b91ba 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: USB specific handling * - * Copyright (C) 2012, Marvell International Ltd. + * Copyright (C) 2012-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/usb.h b/drivers/net/wireless/mwifiex/usb.h index 15b73d12e998..4c41c2a193c5 100644 --- a/drivers/net/wireless/mwifiex/usb.h +++ b/drivers/net/wireless/mwifiex/usb.h @@ -1,7 +1,7 @@ /* * This file contains definitions for mwifiex USB interface driver. * - * Copyright (C) 2012, Marvell International Ltd. + * Copyright (C) 2012-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 6da5abf52e61..cee028321a9a 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: utility functions * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h index ddae57021397..9a31215487dd 100644 --- a/drivers/net/wireless/mwifiex/util.h +++ b/drivers/net/wireless/mwifiex/util.h @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: utility functions * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 6e86d1e17d3e..e8556b6e04ee 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: WMM * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index eca56e371a57..569bd73f33c5 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -1,7 +1,7 @@ /* * Marvell Wireless LAN device driver: WMM * - * Copyright (C) 2011, Marvell International Ltd. + * Copyright (C) 2011-2014, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 -- cgit v1.2.3 From 363c1b4f75d7a8cec61b74ee163f1f315a56f639 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Thu, 19 Jun 2014 21:38:58 -0700 Subject: mwifiex: print sleep_confirm cmd/response and power save events Sleep Confirm command is sent separately while other commands are handled through cmd_pending_q. Print sleep_confirm cmd and its response as well as power save events so that we have a clearer picture of power save handshake in driver log. Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 606877bc24d6..df42f066d70c 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -273,6 +273,7 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) (struct mwifiex_opt_sleep_confirm *) adapter->sleep_cfm->data; struct sk_buff *sleep_cfm_tmp; + struct timeval ts; __le32 tmp; priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); @@ -283,6 +284,14 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) (adapter->seq_num, priv->bss_num, priv->bss_type))); + do_gettimeofday(&ts); + dev_dbg(adapter->dev, + "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d, seqno %#x\n", + ts.tv_sec, ts.tv_usec, le16_to_cpu(sleep_cfm_buf->command), + le16_to_cpu(sleep_cfm_buf->action), + le16_to_cpu(sleep_cfm_buf->size), + le16_to_cpu(sleep_cfm_buf->seq_num)); + if (adapter->iface_type == MWIFIEX_USB) { sleep_cfm_tmp = dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm) @@ -457,11 +466,10 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) rx_info->bss_type = priv->bss_type; } - if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) { - do_gettimeofday(&tstamp); - dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n", - tstamp.tv_sec, tstamp.tv_usec, eventcause); - } else { + do_gettimeofday(&tstamp); + dev_dbg(adapter->dev, "EVENT: %lu.%lu: cause: %#x\n", + tstamp.tv_sec, tstamp.tv_usec, eventcause); + if (eventcause == EVENT_PS_SLEEP || eventcause == EVENT_PS_AWAKE) { /* Handle PS_SLEEP/AWAKE events on STA */ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); if (!priv) @@ -1228,12 +1236,19 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, uint16_t result = le16_to_cpu(cmd->result); uint16_t command = le16_to_cpu(cmd->command); uint16_t seq_num = le16_to_cpu(cmd->seq_num); + struct timeval ts; if (!upld_len) { dev_err(adapter->dev, "%s: cmd size is 0\n", __func__); return; } + do_gettimeofday(&ts); + dev_dbg(adapter->dev, + "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d, len %d, seqno 0x%x\n", + ts.tv_sec, ts.tv_usec, command, result, le16_to_cpu(cmd->size), + seq_num); + /* Get BSS number and corresponding priv */ priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num), HostCmd_GET_BSS_TYPE(seq_num)); -- cgit v1.2.3 From e843bb199ba58ce5d1364d4c82fcf6975f08eec2 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Sun, 22 Jun 2014 20:50:40 +0200 Subject: net/wireless/brcm80211/brcmfmac: Make return type and name reflect actual semantics Applying ++ to a bool is equivalent to setting it true, regardless of its initial value (bools are not uint1_t). Hence the function wl_get_vif_state_all can only ever return true/false. The only in-tree caller uses its return value as a boolean. So update its return type, and since the list traversal and bit testing have no side effects, just return true immediately. Its return value tells if any vif is in the specified state, so also rename it to brcmf_get_vif_state_any. Reviewed-by: Arend van Spriel Signed-off-by: Rasmus Villemoes Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 2 +- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 7 +++---- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index f3445ac627e4..588fdbdb3255 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -708,7 +708,7 @@ static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans, active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS; else if (num_chans == AF_PEER_SEARCH_CNT) active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS; - else if (wl_get_vif_state_all(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED)) + else if (brcmf_get_vif_state_any(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED)) active = -1; else active = P2PAPI_SCAN_DWELL_TIME_MS; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index db3d8487dc42..cec55fc26f2e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -5619,16 +5619,15 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp) return wdev->iftype; } -u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state) +bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state) { struct brcmf_cfg80211_vif *vif; - bool result = 0; list_for_each_entry(vif, &cfg->vif_list, list) { if (test_bit(state, &vif->sme_state)) - result++; + return true; } - return result; + return false; } static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index 283c525a44f7..f9fb10998e79 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -477,7 +477,7 @@ const struct brcmf_tlv * brcmf_parse_tlvs(const void *buf, int buflen, uint key); u16 channel_to_chanspec(struct brcmu_d11inf *d11inf, struct ieee80211_channel *ch); -u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state); +bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state); void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, struct brcmf_cfg80211_vif *vif); bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg); -- cgit v1.2.3 From b6fd7fd23ef2fe32a6cf64c02211e48d79766b58 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sat, 21 Jun 2014 12:11:12 +0200 Subject: brcmfmac: Add 43569 USB support. Added usb device id for the new device 43569 to the list of supported devices. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 6db51a666f61..aa2355932a7e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -55,6 +55,7 @@ #define BRCMF_USB_43143_FW_NAME "brcm/brcmfmac43143.bin" #define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.bin" #define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin" +#define BRCMF_USB_43569_FW_NAME "brcm/brcmfmac43569.bin" struct brcmf_usb_image { struct list_head list; @@ -928,6 +929,8 @@ static bool brcmf_usb_chip_support(int chipid, int chiprev) return (chiprev == 3); case 43242: return true; + case 43569: + return true; default: break; } @@ -1028,6 +1031,8 @@ static const char *brcmf_usb_get_fwname(struct brcmf_usbdev_info *devinfo) return BRCMF_USB_43236_FW_NAME; case 43242: return BRCMF_USB_43242_FW_NAME; + case 43569: + return BRCMF_USB_43569_FW_NAME; default: return NULL; } @@ -1229,7 +1234,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) u8 endpoint_num; struct brcmf_usbdev_info *devinfo; - brcmf_dbg(USB, "Enter\n"); + brcmf_dbg(USB, "Enter 0x%04x:0x%04x\n", id->idVendor, id->idProduct); devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC); if (devinfo == NULL) @@ -1392,12 +1397,14 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf) #define BRCMF_USB_DEVICE_ID_43143 0xbd1e #define BRCMF_USB_DEVICE_ID_43236 0xbd17 #define BRCMF_USB_DEVICE_ID_43242 0xbd1f +#define BRCMF_USB_DEVICE_ID_43569 0xbd27 #define BRCMF_USB_DEVICE_ID_BCMFW 0x0bdc static struct usb_device_id brcmf_usb_devid_table[] = { { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43143) }, { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43236) }, { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43242) }, + { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43569) }, /* special entry for device with firmware loaded and running */ { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) }, { } @@ -1407,6 +1414,7 @@ MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table); MODULE_FIRMWARE(BRCMF_USB_43143_FW_NAME); MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME); MODULE_FIRMWARE(BRCMF_USB_43242_FW_NAME); +MODULE_FIRMWARE(BRCMF_USB_43569_FW_NAME); static struct usb_driver brcmf_usbdrvr = { .name = KBUILD_MODNAME, -- cgit v1.2.3 From 457cfabb99461b9f8d6bf32396f9c14445b7155a Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sat, 21 Jun 2014 12:11:13 +0200 Subject: brcmfmac: Add USB device 43566 to supported devices. Add the USB 43566 device to the supported devices list. The 43566 is a WiFi-only variant of the 43569. It uses the same FW as 43569. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index aa2355932a7e..d2927acfbd79 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -929,6 +929,7 @@ static bool brcmf_usb_chip_support(int chipid, int chiprev) return (chiprev == 3); case 43242: return true; + case 43566: case 43569: return true; default: @@ -1031,6 +1032,7 @@ static const char *brcmf_usb_get_fwname(struct brcmf_usbdev_info *devinfo) return BRCMF_USB_43236_FW_NAME; case 43242: return BRCMF_USB_43242_FW_NAME; + case 43566: case 43569: return BRCMF_USB_43569_FW_NAME; default: -- cgit v1.2.3 From d83f8face594340551b2c57ae95acfe70ae444f8 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 21 Jun 2014 12:11:14 +0200 Subject: brcmfmac: clear ht info during attach phase After updating 2G bandwidth capability clear ht info. This will be properly set upon calling brcmf_update_wiphy_bands(). Reviewed-by: Hante Meuleman Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index cec55fc26f2e..2261918f734c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -5051,6 +5051,9 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, err = brcmf_fil_iovar_int_set(ifp, "obss_coex", BRCMF_OBSS_COEX_AUTO); } + /* clear for now and rely on update later */ + wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.ht_supported = false; + wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap = 0; err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); if (err) { -- cgit v1.2.3 From 51c7f5eddd0f2e8eb6b49a3025b04148cf3b3912 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sat, 21 Jun 2014 12:11:15 +0200 Subject: brcmfmac: Change USB probe routine to support Composite USB Some of the USB devices also have Bluetooth inside. These devices can with specific firmware result in a composite USB device. This change will update the driver such that it will also accept the correct interface of composite devices. It is backward compatible with old non-composite USB fw. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/usb.c | 204 +++++++++++--------------- 1 file changed, 87 insertions(+), 117 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index d2927acfbd79..839bcda9465a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -29,33 +29,24 @@ #include "usb_rdl.h" #include "usb.h" -#define IOCTL_RESP_TIMEOUT 2000 +#define IOCTL_RESP_TIMEOUT 2000 #define BRCMF_USB_RESET_GETVER_SPINWAIT 100 /* in unit of ms */ #define BRCMF_USB_RESET_GETVER_LOOP_CNT 10 #define BRCMF_POSTBOOT_ID 0xA123 /* ID to detect if dongle has boot up */ -#define BRCMF_USB_NRXQ 50 -#define BRCMF_USB_NTXQ 50 +#define BRCMF_USB_NRXQ 50 +#define BRCMF_USB_NTXQ 50 -#define CONFIGDESC(usb) (&((usb)->actconfig)->desc) -#define IFPTR(usb, idx) ((usb)->actconfig->interface[(idx)]) -#define IFALTS(usb, idx) (IFPTR((usb), (idx))->altsetting[0]) -#define IFDESC(usb, idx) IFALTS((usb), (idx)).desc -#define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[(ep)]).desc +#define BRCMF_USB_CBCTL_WRITE 0 +#define BRCMF_USB_CBCTL_READ 1 +#define BRCMF_USB_MAX_PKT_SIZE 1600 -#define CONTROL_IF 0 -#define BULK_IF 0 - -#define BRCMF_USB_CBCTL_WRITE 0 -#define BRCMF_USB_CBCTL_READ 1 -#define BRCMF_USB_MAX_PKT_SIZE 1600 - -#define BRCMF_USB_43143_FW_NAME "brcm/brcmfmac43143.bin" -#define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.bin" -#define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin" -#define BRCMF_USB_43569_FW_NAME "brcm/brcmfmac43569.bin" +#define BRCMF_USB_43143_FW_NAME "brcm/brcmfmac43143.bin" +#define BRCMF_USB_43236_FW_NAME "brcm/brcmfmac43236b.bin" +#define BRCMF_USB_43242_FW_NAME "brcm/brcmfmac43242a.bin" +#define BRCMF_USB_43569_FW_NAME "brcm/brcmfmac43569.bin" struct brcmf_usb_image { struct list_head list; @@ -71,7 +62,7 @@ struct brcmf_usbdev_info { struct list_head rx_postq; struct list_head tx_freeq; struct list_head tx_postq; - uint rx_pipe, tx_pipe, rx_pipe2; + uint rx_pipe, tx_pipe; int rx_low_watermark; int tx_low_watermark; @@ -98,6 +89,7 @@ struct brcmf_usbdev_info { int ctl_completed; wait_queue_head_t ioctl_resp_wait; ulong ctl_op; + u8 ifnum; struct urb *bulk_urb; /* used for FW download */ }; @@ -577,7 +569,6 @@ fail: static int brcmf_usb_up(struct device *dev) { struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); - u16 ifnum; brcmf_dbg(USB, "Enter\n"); if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) @@ -590,21 +581,19 @@ static int brcmf_usb_up(struct device *dev) devinfo->ctl_in_pipe = usb_rcvctrlpipe(devinfo->usbdev, 0); devinfo->ctl_out_pipe = usb_sndctrlpipe(devinfo->usbdev, 0); - ifnum = IFDESC(devinfo->usbdev, CONTROL_IF).bInterfaceNumber; - /* CTL Write */ devinfo->ctl_write.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; devinfo->ctl_write.bRequest = 0; devinfo->ctl_write.wValue = cpu_to_le16(0); - devinfo->ctl_write.wIndex = cpu_to_le16p(&ifnum); + devinfo->ctl_write.wIndex = cpu_to_le16(devinfo->ifnum); /* CTL Read */ devinfo->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; devinfo->ctl_read.bRequest = 1; devinfo->ctl_read.wValue = cpu_to_le16(0); - devinfo->ctl_read.wIndex = cpu_to_le16p(&ifnum); + devinfo->ctl_read.wIndex = cpu_to_le16(devinfo->ifnum); } brcmf_usb_rx_fill_all(devinfo); return 0; @@ -643,19 +632,19 @@ brcmf_usb_sync_complete(struct urb *urb) brcmf_usb_ioctl_resp_wake(devinfo); } -static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd, - void *buffer, int buflen) +static int brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd, + void *buffer, int buflen) { - int ret = 0; + int ret; char *tmpbuf; u16 size; if ((!devinfo) || (devinfo->ctl_urb == NULL)) - return false; + return -EINVAL; tmpbuf = kmalloc(buflen, GFP_ATOMIC); if (!tmpbuf) - return false; + return -ENOMEM; size = buflen; devinfo->ctl_urb->transfer_buffer_length = size; @@ -676,14 +665,16 @@ static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd, ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC); if (ret < 0) { brcmf_err("usb_submit_urb failed %d\n", ret); - kfree(tmpbuf); - return false; + goto finalize; } - ret = brcmf_usb_ioctl_resp_wait(devinfo); - memcpy(buffer, tmpbuf, buflen); - kfree(tmpbuf); + if (!brcmf_usb_ioctl_resp_wait(devinfo)) + ret = -ETIMEDOUT; + else + memcpy(buffer, tmpbuf, buflen); +finalize: + kfree(tmpbuf); return ret; } @@ -725,6 +716,7 @@ brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo) { struct bootrom_id_le id; u32 loop_cnt; + int err; brcmf_dbg(USB, "Enter\n"); @@ -733,7 +725,9 @@ brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo) mdelay(BRCMF_USB_RESET_GETVER_SPINWAIT); loop_cnt++; id.chip = cpu_to_le32(0xDEAD); /* Get the ID */ - brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id)); + err = brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id)); + if ((err) && (err != -ETIMEDOUT)) + return err; if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) break; } while (loop_cnt < BRCMF_USB_RESET_GETVER_LOOP_CNT); @@ -795,8 +789,7 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen) } /* 1) Prepare USB boot loader for runtime image */ - brcmf_usb_dl_cmd(devinfo, DL_START, &state, - sizeof(struct rdl_state_le)); + brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state)); rdlstate = le32_to_cpu(state.state); rdlbytes = le32_to_cpu(state.bytes); @@ -840,10 +833,10 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen) dlpos += sendlen; sent += sendlen; } - if (!brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state, - sizeof(struct rdl_state_le))) { - brcmf_err("DL_GETSTATE Failed xxxx\n"); - err = -EINVAL; + err = brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state, + sizeof(state)); + if (err) { + brcmf_err("DL_GETSTATE Failed\n"); goto fail; } @@ -899,13 +892,12 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo) return -EINVAL; /* Check we are runnable */ - brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state, - sizeof(struct rdl_state_le)); + state.state = 0; + brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state, sizeof(state)); /* Start the image */ if (state.state == cpu_to_le32(DL_RUNNABLE)) { - if (!brcmf_usb_dl_cmd(devinfo, DL_GO, &state, - sizeof(struct rdl_state_le))) + if (brcmf_usb_dl_cmd(devinfo, DL_GO, &state, sizeof(state))) return -ENODEV; if (brcmf_usb_resetcfg(devinfo)) return -ENODEV; @@ -1228,13 +1220,13 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo) static int brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - int ep; - struct usb_endpoint_descriptor *endpoint; - int ret = 0; struct usb_device *usb = interface_to_usbdev(intf); - int num_of_eps; - u8 endpoint_num; struct brcmf_usbdev_info *devinfo; + struct usb_interface_descriptor *desc; + struct usb_endpoint_descriptor *endpoint; + int ret = 0; + u32 num_of_eps; + u8 endpoint_num, ep; brcmf_dbg(USB, "Enter 0x%04x:0x%04x\n", id->idVendor, id->idProduct); @@ -1244,92 +1236,71 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) devinfo->usbdev = usb; devinfo->dev = &usb->dev; - usb_set_intfdata(intf, devinfo); /* Check that the device supports only one configuration */ if (usb->descriptor.bNumConfigurations != 1) { - ret = -1; - goto fail; - } - - if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) { - ret = -1; - goto fail; - } - - /* - * Only the BDC interface configuration is supported: - * Device class: USB_CLASS_VENDOR_SPEC - * if0 class: USB_CLASS_VENDOR_SPEC - * if0/ep0: control - * if0/ep1: bulk in - * if0/ep2: bulk out (ok if swapped with bulk in) - */ - if (CONFIGDESC(usb)->bNumInterfaces != 1) { - ret = -1; + brcmf_err("Number of configurations: %d not supported\n", + usb->descriptor.bNumConfigurations); + ret = -ENODEV; goto fail; } - /* Check interface */ - if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC || - IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 || - IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff) { - brcmf_err("invalid control interface: class %d, subclass %d, proto %d\n", - IFDESC(usb, CONTROL_IF).bInterfaceClass, - IFDESC(usb, CONTROL_IF).bInterfaceSubClass, - IFDESC(usb, CONTROL_IF).bInterfaceProtocol); - ret = -1; + if ((usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) && + (usb->descriptor.bDeviceClass != USB_CLASS_MISC) && + (usb->descriptor.bDeviceClass != USB_CLASS_WIRELESS_CONTROLLER)) { + brcmf_err("Device class: 0x%x not supported\n", + usb->descriptor.bDeviceClass); + ret = -ENODEV; goto fail; } - /* Check control endpoint */ - endpoint = &IFEPDESC(usb, CONTROL_IF, 0); - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_INT) { - brcmf_err("invalid control endpoint %d\n", - endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); - ret = -1; + desc = &intf->altsetting[0].desc; + if ((desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || + (desc->bInterfaceSubClass != 2) || + (desc->bInterfaceProtocol != 0xff)) { + brcmf_err("non WLAN interface %d: 0x%x:0x%x:0x%x\n", + desc->bInterfaceNumber, desc->bInterfaceClass, + desc->bInterfaceSubClass, desc->bInterfaceProtocol); + ret = -ENODEV; goto fail; } - devinfo->rx_pipe = 0; - devinfo->rx_pipe2 = 0; - devinfo->tx_pipe = 0; - num_of_eps = IFDESC(usb, BULK_IF).bNumEndpoints - 1; - - /* Check data endpoints and get pipes */ - for (ep = 1; ep <= num_of_eps; ep++) { - endpoint = &IFEPDESC(usb, BULK_IF, ep); - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != - USB_ENDPOINT_XFER_BULK) { - brcmf_err("invalid data endpoint %d\n", ep); - ret = -1; - goto fail; - } - - endpoint_num = endpoint->bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - == USB_DIR_IN) { - if (!devinfo->rx_pipe) { + num_of_eps = desc->bNumEndpoints; + for (ep = 0; ep < num_of_eps; ep++) { + endpoint = &intf->altsetting[0].endpoint[ep].desc; + endpoint_num = usb_endpoint_num(endpoint); + if (!usb_endpoint_xfer_bulk(endpoint)) + continue; + if (usb_endpoint_dir_in(endpoint)) { + if (!devinfo->rx_pipe) devinfo->rx_pipe = usb_rcvbulkpipe(usb, endpoint_num); - } else { - devinfo->rx_pipe2 = - usb_rcvbulkpipe(usb, endpoint_num); - } } else { - devinfo->tx_pipe = usb_sndbulkpipe(usb, endpoint_num); + if (!devinfo->tx_pipe) + devinfo->tx_pipe = + usb_sndbulkpipe(usb, endpoint_num); } } + if (devinfo->rx_pipe == 0) { + brcmf_err("No RX (in) Bulk EP found\n"); + ret = -ENODEV; + goto fail; + } + if (devinfo->tx_pipe == 0) { + brcmf_err("No TX (out) Bulk EP found\n"); + ret = -ENODEV; + goto fail; + } + + devinfo->ifnum = desc->bInterfaceNumber; if (usb->speed == USB_SPEED_SUPER) - brcmf_dbg(USB, "Broadcom super speed USB wireless device detected\n"); + brcmf_dbg(USB, "Broadcom super speed USB WLAN interface detected\n"); else if (usb->speed == USB_SPEED_HIGH) - brcmf_dbg(USB, "Broadcom high speed USB wireless device detected\n"); + brcmf_dbg(USB, "Broadcom high speed USB WLAN interface detected\n"); else - brcmf_dbg(USB, "Broadcom full speed USB wireless device detected\n"); + brcmf_dbg(USB, "Broadcom full speed USB WLAN interface detected\n"); ret = brcmf_usb_probe_cb(devinfo); if (ret) @@ -1339,11 +1310,9 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) return 0; fail: - brcmf_err("failed with errno %d\n", ret); kfree(devinfo); usb_set_intfdata(intf, NULL); return ret; - } static void @@ -1388,6 +1357,7 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf) { struct usb_device *usb = interface_to_usbdev(intf); struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); + brcmf_dbg(USB, "Enter\n"); return brcmf_fw_get_firmwares(&usb->dev, 0, -- cgit v1.2.3 From 1bacb0487d0ed914a9fd08fa7c24fa6c4b27cacc Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Sat, 21 Jun 2014 12:11:16 +0200 Subject: brcmfmac: replace cfg80211 testmode with vendor command Passing a pointer from user space and using it directly in driver is not a preferable behavior. Switch to cfg80211 vendor mode for dongle command for better cross platform compatibility. Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/Makefile | 3 +- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 10 -- drivers/net/wireless/brcm80211/brcmfmac/vendor.c | 115 +++++++++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/vendor.h | 64 ++++++++++++ .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 37 ++----- 5 files changed, 188 insertions(+), 41 deletions(-) create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/vendor.c create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/vendor.h diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 98e67c18f276..4cffb2ee3673 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -34,7 +34,8 @@ brcmfmac-objs += \ dhd_common.o \ dhd_linux.o \ firmware.o \ - btcoex.o + btcoex.o \ + vendor.o brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ dhd_sdio.o \ bcmsdh.o diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 16f9ab2568a8..a8998eb60d22 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -49,16 +49,6 @@ */ #define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32 -/* Bus independent dongle command */ -struct brcmf_dcmd { - uint cmd; /* common dongle cmd definition */ - void *buf; /* pointer to user buffer */ - uint len; /* length of user buffer */ - u8 set; /* get or set request (optional) */ - uint used; /* bytes read or written (optional) */ - uint needed; /* bytes needed (optional) */ -}; - /** * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info * diff --git a/drivers/net/wireless/brcm80211/brcmfmac/vendor.c b/drivers/net/wireless/brcm80211/brcmfmac/vendor.c new file mode 100644 index 000000000000..5960d827508c --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/vendor.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include +#include "fwil_types.h" +#include "dhd.h" +#include "p2p.h" +#include "dhd_dbg.h" +#include "wl_cfg80211.h" +#include "vendor.h" +#include "fwil.h" + +static int brcmf_cfg80211_vndr_cmds_dcmd_handler(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int len) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct net_device *ndev = cfg_to_ndev(cfg); + const struct brcmf_vndr_dcmd_hdr *cmdhdr = data; + struct sk_buff *reply; + int ret, payload, ret_len; + void *dcmd_buf = NULL, *wr_pointer; + u16 msglen, maxmsglen = PAGE_SIZE - 0x100; + + brcmf_dbg(TRACE, "cmd %x set %d len %d\n", cmdhdr->cmd, cmdhdr->set, + cmdhdr->len); + + len -= sizeof(struct brcmf_vndr_dcmd_hdr); + ret_len = cmdhdr->len; + if (ret_len > 0 || len > 0) { + if (len > BRCMF_DCMD_MAXLEN) { + brcmf_err("oversize input buffer %d\n", len); + len = BRCMF_DCMD_MAXLEN; + } + if (ret_len > BRCMF_DCMD_MAXLEN) { + brcmf_err("oversize return buffer %d\n", ret_len); + ret_len = BRCMF_DCMD_MAXLEN; + } + payload = max(ret_len, len) + 1; + dcmd_buf = vzalloc(payload); + if (NULL == dcmd_buf) + return -ENOMEM; + + memcpy(dcmd_buf, (void *)cmdhdr + cmdhdr->offset, len); + *(char *)(dcmd_buf + len) = '\0'; + } + + if (cmdhdr->set) + ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), cmdhdr->cmd, + dcmd_buf, ret_len); + else + ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), cmdhdr->cmd, + dcmd_buf, ret_len); + if (ret != 0) + goto exit; + + wr_pointer = dcmd_buf; + while (ret_len > 0) { + msglen = ret_len > maxmsglen ? maxmsglen : ret_len; + ret_len -= msglen; + payload = msglen + sizeof(msglen); + reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload); + if (NULL == reply) { + ret = -ENOMEM; + break; + } + + if (nla_put(reply, BRCMF_NLATTR_DATA, msglen, wr_pointer) || + nla_put_u16(reply, BRCMF_NLATTR_LEN, msglen)) { + kfree_skb(reply); + ret = -ENOBUFS; + break; + } + + ret = cfg80211_vendor_cmd_reply(reply); + if (ret) + break; + + wr_pointer += msglen; + } + +exit: + vfree(dcmd_buf); + + return ret; +} + +const struct wiphy_vendor_command brcmf_vendor_cmds[] = { + { + { + .vendor_id = BROADCOM_OUI, + .subcmd = BRCMF_VNDR_CMDS_DCMD + }, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = brcmf_cfg80211_vndr_cmds_dcmd_handler + }, +}; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/vendor.h b/drivers/net/wireless/brcm80211/brcmfmac/vendor.h new file mode 100644 index 000000000000..061b7bfa2e1c --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/vendor.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _vendor_h_ +#define _vendor_h_ + +#define BROADCOM_OUI 0x001018 + +enum brcmf_vndr_cmds { + BRCMF_VNDR_CMDS_UNSPEC, + BRCMF_VNDR_CMDS_DCMD, + BRCMF_VNDR_CMDS_LAST +}; + +/** + * enum brcmf_nlattrs - nl80211 message attributes + * + * @BRCMF_NLATTR_LEN: message body length + * @BRCMF_NLATTR_DATA: message body + */ +enum brcmf_nlattrs { + BRCMF_NLATTR_UNSPEC, + + BRCMF_NLATTR_LEN, + BRCMF_NLATTR_DATA, + + __BRCMF_NLATTR_AFTER_LAST, + BRCMF_NLATTR_MAX = __BRCMF_NLATTR_AFTER_LAST - 1 +}; + +/** + * struct brcmf_vndr_dcmd_hdr - message header for cfg80211 vendor command dcmd + * support + * + * @cmd: common dongle cmd definition + * @len: length of expecting return buffer + * @offset: offset of data buffer + * @set: get or set request(optional) + * @magic: magic number for verification + */ +struct brcmf_vndr_dcmd_hdr { + uint cmd; + int len; + uint offset; + uint set; + uint magic; +}; + +extern const struct wiphy_vendor_command brcmf_vendor_cmds[]; + +#endif /* _vendor_h_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 2261918f734c..46b57eafa130 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,7 @@ #include "btcoex.h" #include "wl_cfg80211.h" #include "fwil.h" +#include "vendor.h" #define BRCMF_SCAN_IE_LEN_MAX 2048 #define BRCMF_PNO_VERSION 2 @@ -3257,35 +3259,6 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, return 0; } -#ifdef CONFIG_NL80211_TESTMODE -static int brcmf_cfg80211_testmode(struct wiphy *wiphy, - struct wireless_dev *wdev, - void *data, int len) -{ - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_to_ndev(cfg); - struct brcmf_dcmd *dcmd = data; - struct sk_buff *reply; - int ret; - - brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set, - dcmd->buf, dcmd->len); - - if (dcmd->set) - ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd, - dcmd->buf, dcmd->len); - else - ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd, - dcmd->buf, dcmd->len); - if (ret == 0) { - reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd)); - nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd); - ret = cfg80211_testmode_reply(reply); - } - return ret; -} -#endif - static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp) { s32 err; @@ -4303,7 +4276,6 @@ static struct cfg80211_ops wl_cfg80211_ops = { .crit_proto_start = brcmf_cfg80211_crit_proto_start, .crit_proto_stop = brcmf_cfg80211_crit_proto_stop, .tdls_oper = brcmf_cfg80211_tdls_oper, - CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode) }; static void brcmf_wiphy_pno_params(struct wiphy *wiphy) @@ -4408,6 +4380,11 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) brcmf_dbg(INFO, "Registering custom regulatory\n"); wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); + + /* vendor commands/events support */ + wiphy->vendor_commands = brcmf_vendor_cmds; + wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1; + err = wiphy_register(wiphy); if (err < 0) { brcmf_err("Could not register wiphy device (%d)\n", err); -- cgit v1.2.3 From 2bb443d9ade2d4557bffdb40447fdfbdadb6071c Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 21 Jun 2014 12:11:17 +0200 Subject: brcmfmac: correct logging levels in btcoex source All log messages were set to TRACE level, which is intended for function entry and exit. Using INFO instead in other places. Also reducing an error message that always popped up upon module unload. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/btcoex.c | 38 ++++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c index 0cb591b050b3..a29ac4977b3a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c @@ -157,7 +157,7 @@ static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci, */ /* save current */ - brcmf_dbg(TRACE, "new SCO/eSCO coex algo {save & override}\n"); + brcmf_dbg(INFO, "new SCO/eSCO coex algo {save & override}\n"); brcmf_btcoex_params_read(ifp, 50, &btci->reg50); brcmf_btcoex_params_read(ifp, 51, &btci->reg51); brcmf_btcoex_params_read(ifp, 64, &btci->reg64); @@ -165,7 +165,7 @@ static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci, brcmf_btcoex_params_read(ifp, 71, &btci->reg71); btci->saved_regs_part2 = true; - brcmf_dbg(TRACE, + brcmf_dbg(INFO, "saved bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n", btci->reg50, btci->reg51, btci->reg64, btci->reg65, btci->reg71); @@ -179,21 +179,21 @@ static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci, } else if (btci->saved_regs_part2) { /* restore previously saved bt params */ - brcmf_dbg(TRACE, "Do new SCO/eSCO coex algo {restore}\n"); + brcmf_dbg(INFO, "Do new SCO/eSCO coex algo {restore}\n"); brcmf_btcoex_params_write(ifp, 50, btci->reg50); brcmf_btcoex_params_write(ifp, 51, btci->reg51); brcmf_btcoex_params_write(ifp, 64, btci->reg64); brcmf_btcoex_params_write(ifp, 65, btci->reg65); brcmf_btcoex_params_write(ifp, 71, btci->reg71); - brcmf_dbg(TRACE, + brcmf_dbg(INFO, "restored bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n", btci->reg50, btci->reg51, btci->reg64, btci->reg65, btci->reg71); btci->saved_regs_part2 = false; } else { - brcmf_err("attempted to restore not saved BTCOEX params\n"); + brcmf_dbg(INFO, "attempted to restore not saved BTCOEX params\n"); } } @@ -219,14 +219,14 @@ static bool brcmf_btcoex_is_sco_active(struct brcmf_if *ifp) break; } - brcmf_dbg(TRACE, "sample[%d], btc_params 27:%x\n", i, param27); + brcmf_dbg(INFO, "sample[%d], btc_params 27:%x\n", i, param27); if ((param27 & 0x6) == 2) { /* count both sco & esco */ sco_id_cnt++; } if (sco_id_cnt > 2) { - brcmf_dbg(TRACE, + brcmf_dbg(INFO, "sco/esco detected, pkt id_cnt:%d samples:%d\n", sco_id_cnt, i); res = true; @@ -250,7 +250,7 @@ static void btcmf_btcoex_save_part1(struct brcmf_btcoex_info *btci) brcmf_btcoex_params_read(ifp, 41, &btci->reg41); brcmf_btcoex_params_read(ifp, 68, &btci->reg68); btci->saved_regs_part1 = true; - brcmf_dbg(TRACE, + brcmf_dbg(INFO, "saved btc_params regs (66,41,68) 0x%x 0x%x 0x%x\n", btci->reg66, btci->reg41, btci->reg68); @@ -270,7 +270,7 @@ static void brcmf_btcoex_restore_part1(struct brcmf_btcoex_info *btci) brcmf_btcoex_params_write(ifp, 66, btci->reg66); brcmf_btcoex_params_write(ifp, 41, btci->reg41); brcmf_btcoex_params_write(ifp, 68, btci->reg68); - brcmf_dbg(TRACE, + brcmf_dbg(INFO, "restored btc_params regs {66,41,68} 0x%x 0x%x 0x%x\n", btci->reg66, btci->reg41, btci->reg68); @@ -307,7 +307,7 @@ static void brcmf_btcoex_handler(struct work_struct *work) /* DHCP started provide OPPORTUNITY window to get DHCP address */ - brcmf_dbg(TRACE, "DHCP started\n"); + brcmf_dbg(INFO, "DHCP started\n"); btci->bt_state = BRCMF_BT_DHCP_OPPR_WIN; if (btci->timeout < BRCMF_BTCOEX_OPPR_WIN_TIME) { mod_timer(&btci->timer, btci->timer.expires); @@ -322,12 +322,12 @@ static void brcmf_btcoex_handler(struct work_struct *work) case BRCMF_BT_DHCP_OPPR_WIN: if (btci->dhcp_done) { - brcmf_dbg(TRACE, "DHCP done before T1 expiration\n"); + brcmf_dbg(INFO, "DHCP done before T1 expiration\n"); goto idle; } /* DHCP is not over yet, start lowering BT priority */ - brcmf_dbg(TRACE, "DHCP T1:%d expired\n", + brcmf_dbg(INFO, "DHCP T1:%d expired\n", BRCMF_BTCOEX_OPPR_WIN_TIME); brcmf_btcoex_boost_wifi(btci, true); @@ -339,9 +339,9 @@ static void brcmf_btcoex_handler(struct work_struct *work) case BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT: if (btci->dhcp_done) - brcmf_dbg(TRACE, "DHCP done before T2 expiration\n"); + brcmf_dbg(INFO, "DHCP done before T2 expiration\n"); else - brcmf_dbg(TRACE, "DHCP T2:%d expired\n", + brcmf_dbg(INFO, "DHCP T2:%d expired\n", BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT); goto idle; @@ -440,13 +440,13 @@ static void brcmf_btcoex_dhcp_end(struct brcmf_btcoex_info *btci) /* Stop any bt timer because DHCP session is done */ btci->dhcp_done = true; if (btci->timer_on) { - brcmf_dbg(TRACE, "disable BT DHCP Timer\n"); + brcmf_dbg(INFO, "disable BT DHCP Timer\n"); btci->timer_on = false; del_timer_sync(&btci->timer); /* schedule worker if transition to IDLE is needed */ if (btci->bt_state != BRCMF_BT_DHCP_IDLE) { - brcmf_dbg(TRACE, "bt_state:%d\n", + brcmf_dbg(INFO, "bt_state:%d\n", btci->bt_state); schedule_work(&btci->work); } @@ -472,7 +472,7 @@ int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif, switch (mode) { case BRCMF_BTCOEX_DISABLED: - brcmf_dbg(TRACE, "DHCP session starts\n"); + brcmf_dbg(INFO, "DHCP session starts\n"); if (btci->bt_state != BRCMF_BT_DHCP_IDLE) return -EBUSY; /* Start BT timer only for SCO connection */ @@ -484,14 +484,14 @@ int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif, break; case BRCMF_BTCOEX_ENABLED: - brcmf_dbg(TRACE, "DHCP session ends\n"); + brcmf_dbg(INFO, "DHCP session ends\n"); if (btci->bt_state != BRCMF_BT_DHCP_IDLE && vif == btci->vif) { brcmf_btcoex_dhcp_end(btci); } break; default: - brcmf_dbg(TRACE, "Unknown mode, ignored\n"); + brcmf_dbg(INFO, "Unknown mode, ignored\n"); } return 0; } -- cgit v1.2.3 From 5e787f7588ff69d3bcd546a64bf70e58a4e98fc5 Mon Sep 17 00:00:00 2001 From: Daniel Kim Date: Sat, 21 Jun 2014 12:11:18 +0200 Subject: brcmfmac: Don't control mpc setting during scan operation Instead of controlling mpc setting during scan operation, initialize mpc setting and then let firmware take care of it. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Daniel Kim [arend@broadcom.com: keep mpc setting for bcm4329] Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c | 7 +++++++ drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 16 +++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index ed3e32ce8c23..d991f8e3d9ec 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -282,6 +282,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) ptr = strrchr(buf, ' ') + 1; strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver)); + /* set mpc */ + err = brcmf_fil_iovar_int_set(ifp, "mpc", 1); + if (err) { + brcmf_err("failed setting mpc\n"); + goto done; + } + /* * Setup timeout if Beacons are lost and roam is off to report * link down diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 46b57eafa130..9682cf213ec4 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -590,6 +590,12 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, } } +static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc) +{ + if ((brcmf_get_chip_info(ifp) >> 4) == 0x4329) + brcmf_set_mpc(ifp, mpc); +} + void brcmf_set_mpc(struct brcmf_if *ifp, int mpc) { s32 err = 0; @@ -643,7 +649,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, brcmf_err("Scan abort failed\n"); } - brcmf_set_mpc(ifp, 1); + brcmf_scan_config_mpc(ifp, 1); /* * e-scan can be initiated by scheduled scan @@ -922,7 +928,7 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, brcmf_err("error (%d)\n", err); return err; } - brcmf_set_mpc(ifp, 0); + brcmf_scan_config_mpc(ifp, 0); results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf; results->version = 0; results->count = 0; @@ -930,7 +936,7 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START); if (err) - brcmf_set_mpc(ifp, 1); + brcmf_scan_config_mpc(ifp, 1); return err; } @@ -1021,7 +1027,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif, brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err); goto scan_out; } - brcmf_set_mpc(ifp, 0); + brcmf_scan_config_mpc(ifp, 0); err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, &sr->ssid_le, sizeof(sr->ssid_le)); if (err) { @@ -1031,7 +1037,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif, else brcmf_err("WLC_SCAN error (%d)\n", err); - brcmf_set_mpc(ifp, 1); + brcmf_scan_config_mpc(ifp, 1); goto scan_out; } } -- cgit v1.2.3 From c94b7e6cb223986a1eaf7bd4c49f2ab758752649 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 21 Jun 2014 12:11:19 +0200 Subject: brcmfmac: reduce log level in fwil if firmware returns error The users of the fwil put an error message in the log so there is no need to do the same in the lower level functions in fwil when the firmware on the device returns an error. Some errors can be ignored for the driver to function and this will avoid driver users to point at the low-level error message as potential bug. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/fwil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index 59a5af5bf994..ded328f80cd1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c @@ -54,7 +54,7 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) if (err >= 0) err = 0; else - brcmf_err("Failed err=%d\n", err); + brcmf_dbg(FIL, "Failed err=%d\n", err); return err; } -- cgit v1.2.3 From ed03033e3033c98e83d45bf4cdca1efdfd86e98e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 22 Jun 2014 23:18:21 +0200 Subject: b43: N-PHY: update code for sending sample tone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 6398c7e45ab7..d9409b446ac1 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1248,7 +1248,8 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, - u16 wait, bool iqmode, bool dac_test) + u16 wait, bool iqmode, bool dac_test, + bool modify_bbmult) { struct b43_phy_n *nphy = dev->phy.n; int i; @@ -1262,12 +1263,10 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000; } - /* TODO: add modify_bbmult argument */ - if (!b43_is_40mhz(dev)) - tmp = 0x6464; - else - tmp = 0x4747; - b43_ntab_write(dev, B43_NTAB16(15, 87), tmp); + if (modify_bbmult) { + tmp = !b43_is_40mhz(dev) ? 0x6464 : 0x4747; + b43_ntab_write(dev, B43_NTAB16(15, 87), tmp); + } b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1)); @@ -1285,10 +1284,8 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF); b43_phy_set(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8000); } else { - if (dac_test) - b43_phy_write(dev, B43_NPHY_SAMP_CMD, 5); - else - b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1); + tmp = dac_test ? 5 : 1; + b43_phy_write(dev, B43_NPHY_SAMP_CMD, tmp); } for (i = 0; i < 100; i++) { if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & 1)) { @@ -2947,12 +2944,13 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone */ static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val, - bool iqmode, bool dac_test) + bool iqmode, bool dac_test, bool modify_bbmult) { u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test); if (samp == 0) return -1; - b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test); + b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test, + modify_bbmult); return 0; } @@ -3390,7 +3388,7 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev) b43_nphy_rf_ctl_override(dev, 0x2000, 0, 3, false); b43_nphy_stop_playback(dev); - b43_nphy_tx_tone(dev, 0xFA0, 0, false, false); + b43_nphy_tx_tone(dev, 4000, 0, false, false, false); udelay(20); tmp = b43_nphy_poll_rssi(dev, N_RSSI_TSSI_2G, rssi, 1); b43_nphy_stop_playback(dev); @@ -4648,9 +4646,9 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, if (nphy->mphase_cal_phase_id > 2) b43_nphy_run_samples(dev, (b43_is_40mhz(dev) ? 40 : 20) * 8, - 0xFFFF, 0, true, false); + 0xFFFF, 0, true, false, false); else - error = b43_nphy_tx_tone(dev, freq, 250, true, false); + error = b43_nphy_tx_tone(dev, freq, 250, true, false, false); if (error == 0) { if (nphy->mphase_cal_phase_id > 2) { @@ -4973,11 +4971,11 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, if (playtone) { ret = b43_nphy_tx_tone(dev, 4000, (nphy->rxcalparams & 0xFFFF), - false, false); + false, false, true); playtone = false; } else { - b43_nphy_run_samples(dev, 160, 0xFFFF, 0, - false, false); + b43_nphy_run_samples(dev, 160, 0xFFFF, 0, false, + false, true); } if (ret == 0) { -- cgit v1.2.3 From 8ac3a2aa7224a7d05f1a71240663c80532969791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 22 Jun 2014 23:18:22 +0200 Subject: b43: N-PHY: update low-pass filter setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for external PA and clean code a bit. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index d9409b446ac1..0fb5e14a4554 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -3706,21 +3706,28 @@ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */ -static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev) +/* + * TX low-pass filter bandwidth setup + * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw + */ +static void b43_nphy_tx_lpf_bw(struct b43_wldev *dev) { u16 tmp; - if (dev->phy.rev >= 3) { - if (b43_nphy_ipa(dev)) { - tmp = 4; - b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2, - (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp); - } + if (dev->phy.rev < 3 || dev->phy.rev >= 7) + return; - tmp = 1; + if (b43_nphy_ipa(dev)) + tmp = b43_is_40mhz(dev) ? 5 : 4; + else + tmp = b43_is_40mhz(dev) ? 3 : 1; + b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2, + (tmp << 9) | (tmp << 6) | (tmp << 3) | tmp); + + if (b43_nphy_ipa(dev)) { + tmp = b43_is_40mhz(dev) ? 4 : 1; b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S2, - (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp); + (tmp << 9) | (tmp << 6) | (tmp << 3) | tmp); } } @@ -5347,7 +5354,7 @@ static int b43_phy_initn(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320); if (phy->rev >= 3 && phy->rev <= 6) b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0032); - b43_nphy_tx_lp_fbw(dev); + b43_nphy_tx_lpf_bw(dev); if (phy->rev >= 3) b43_nphy_spur_workaround(dev); @@ -5433,7 +5440,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, if (dev->phy.rev < 3) b43_nphy_adjust_lna_gain_table(dev); - b43_nphy_tx_lp_fbw(dev); + b43_nphy_tx_lpf_bw(dev); if (dev->phy.rev >= 3 && dev->phy.n->spur_avoid != B43_SPUR_AVOID_DISABLE) { -- cgit v1.2.3 From 8a607208f522e6b37a93c9258d28d75c15263961 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Mon, 23 Jun 2014 23:48:17 +0200 Subject: rtlwifi/rtl8192de: Fix media status register mask bt_msr & 0xfc will never match 0x3. Fix this by using a mask that actually matches the available types. Signed-off-by: Rickard Strandqvist Reviewed-by: Peter Wu Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192de/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192de/reg.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index 2b08671004a0..280c3da42993 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c @@ -1128,7 +1128,7 @@ static int _rtl92de_set_media_status(struct ieee80211_hw *hw, } rtl_write_byte(rtlpriv, REG_CR + 2, bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); - if ((bt_msr & 0xfc) == MSR_AP) + if ((bt_msr & MSR_MASK) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); else rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h index 7f29b8d765b3..315a298bab06 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h @@ -369,6 +369,7 @@ #define MSR_ADHOC 0x01 #define MSR_INFRA 0x02 #define MSR_AP 0x03 +#define MSR_MASK 0x03 /* 6. Adaptive Control Registers (Offset: 0x0160 - 0x01CF) */ /* ----------------------------------------------------- */ -- cgit v1.2.3 From 965ec74110011dbcb4e6a7059c7b4d31ee95c33a Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Mon, 23 Jun 2014 23:53:55 +0200 Subject: rtlwifi/rtl8192c[eu]: Fix media status register mask bt_msr & 0xfc will never match 0x3. Fix this by using a mask that actually matches the available types. Signed-off-by: Rickard Strandqvist Reviewed-by: Peter Wu Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192ce/reg.h | 1 + drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index cdecb0fd4d8e..e2736929b5d0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -1206,7 +1206,7 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, rtl_write_byte(rtlpriv, (MSR), bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); - if ((bt_msr & 0xfc) == MSR_AP) + if ((bt_msr & MSR_MASK) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); else rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h index ed703a1b3b7c..dc8460c0b32f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h @@ -375,6 +375,7 @@ #define MSR_ADHOC 0x01 #define MSR_INFRA 0x02 #define MSR_AP 0x03 +#define MSR_MASK 0x03 #define RRSR_RSC_OFFSET 21 #define RRSR_SHORT_OFFSET 23 diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index a903c2671b4d..270cbffcac70 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1360,7 +1360,7 @@ static int _rtl92cu_set_media_status(struct ieee80211_hw *hw, } rtl_write_byte(rtlpriv, (MSR), bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); - if ((bt_msr & 0xfc) == MSR_AP) + if ((bt_msr & MSR_MASK) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); else rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); -- cgit v1.2.3 From 1dabe76c348f9ced521e412b9bd63ee5ec4924fd Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Tue, 24 Jun 2014 00:00:22 +0200 Subject: rtlwifi/rtl8188ee: Fix media status register mask bt_msr & 0xfc will never match 0x3. Fix this by using a mask that actually matches the available types. Signed-off-by: Rickard Strandqvist Reviewed-by: Peter Wu Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8188ee/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8188ee/reg.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c index b14cf5a10f44..d840ad7bdf65 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c @@ -1231,7 +1231,7 @@ static int _rtl88ee_set_media_status(struct ieee80211_hw *hw, rtl_write_byte(rtlpriv, (MSR), bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); - if ((bt_msr & 0xfc) == MSR_AP) + if ((bt_msr & MSR_MASK) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); else rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h index 7af85cfa8f87..cd7e7a527133 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h @@ -411,6 +411,7 @@ #define MSR_ADHOC 0x01 #define MSR_INFRA 0x02 #define MSR_AP 0x03 +#define MSR_MASK 0x03 #define RRSR_RSC_OFFSET 21 #define RRSR_SHORT_OFFSET 23 -- cgit v1.2.3 From a3a228e4d6ceb51c54572e4faad7607f997fa342 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Tue, 24 Jun 2014 00:05:24 +0200 Subject: rtlwifi/rtl8723ae: Replace magic number by macro For consistency with other drivers, replace a magic number by a macro. Signed-off-by: Rickard Strandqvist Reviewed-by: Peter Wu Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8723ae/reg.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index 87f69166a7ed..539e53987372 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -1109,7 +1109,7 @@ static int _rtl8723ae_set_media_status(struct ieee80211_hw *hw, rtl_write_byte(rtlpriv, (MSR), bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); - if ((bt_msr & 0x03) == MSR_AP) + if ((bt_msr & MSR_MASK) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); else rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h index 64376b38708b..ce2c66fd9eee 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h @@ -361,6 +361,7 @@ #define MSR_ADHOC 0x01 #define MSR_INFRA 0x02 #define MSR_AP 0x03 +#define MSR_MASK 0x03 #define RRSR_RSC_OFFSET 21 #define RRSR_SHORT_OFFSET 23 -- cgit v1.2.3 From e5c3ef3652d8a05890cf49c1e2895f3d1fbd7f41 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Tue, 24 Jun 2014 00:07:13 +0200 Subject: rtlwifi/rtl8723be: Replace magic number by macro For consistency with other drivers, replace a magic number by a macro. Signed-off-by: Rickard Strandqvist Reviewed-by: Peter Wu Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8723be/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8723be/reg.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c index 3d555495b453..3cd286930fe0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c @@ -1197,7 +1197,7 @@ static int _rtl8723be_set_media_status(struct ieee80211_hw *hw, } rtl_write_byte(rtlpriv, (MSR), bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); - if ((bt_msr & 0x03) == MSR_AP) + if ((bt_msr & MSR_MASK) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); else rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/reg.h b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h index 4c653fab8795..3006849ed439 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h @@ -412,6 +412,7 @@ #define MSR_ADHOC 0x01 #define MSR_INFRA 0x02 #define MSR_AP 0x03 +#define MSR_MASK 0x03 #define RRSR_RSC_OFFSET 21 #define RRSR_SHORT_OFFSET 23 -- cgit v1.2.3 From a60f99f75dd35179094a4e9ed4ae8ce0c7ece908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 24 Jun 2014 10:50:41 +0200 Subject: b43: update list and code making a selection of firmware files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean ucode selection, fix choice of firmware for LCN, drop some goto-s, add new devices. Tested on 14e4:4312, 14e4:4315, 14e4:4328, 14e4:432b, 14e4:4353. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 224 ++++++++++++++++++++++------------------ 1 file changed, 125 insertions(+), 99 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 9cf07bb7adf8..aae3af2a7a9f 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2201,52 +2201,78 @@ err_format: return -EPROTO; } +/* http://bcm-v4.sipsolutions.net/802.11/Init/Firmware */ static int b43_try_request_fw(struct b43_request_fw_context *ctx) { struct b43_wldev *dev = ctx->dev; struct b43_firmware *fw = &ctx->dev->fw; + struct b43_phy *phy = &dev->phy; const u8 rev = ctx->dev->dev->core_rev; const char *filename; - u32 tmshigh; int err; - /* Files for HT and LCN were found by trying one by one */ - /* Get microcode */ - if ((rev >= 5) && (rev <= 10)) { - filename = "ucode5"; - } else if ((rev >= 11) && (rev <= 12)) { - filename = "ucode11"; - } else if (rev == 13) { - filename = "ucode13"; - } else if (rev == 14) { - filename = "ucode14"; - } else if (rev == 15) { + filename = NULL; + switch (rev) { + case 42: + if (phy->type == B43_PHYTYPE_AC) + filename = "ucode42"; + break; + case 33: + if (phy->type == B43_PHYTYPE_LCN40) + filename = "ucode33_lcn40"; + break; + case 30: + if (phy->type == B43_PHYTYPE_N) + filename = "ucode30_mimo"; + break; + case 29: + if (phy->type == B43_PHYTYPE_HT) + filename = "ucode29_mimo"; + break; + case 26: + if (phy->type == B43_PHYTYPE_HT) + filename = "ucode26_mimo"; + break; + case 28: + case 25: + if (phy->type == B43_PHYTYPE_N) + filename = "ucode25_mimo"; + else if (phy->type == B43_PHYTYPE_LCN) + filename = "ucode25_lcn"; + break; + case 24: + if (phy->type == B43_PHYTYPE_LCN) + filename = "ucode24_lcn"; + break; + case 23: + if (phy->type == B43_PHYTYPE_N) + filename = "ucode16_mimo"; + break; + case 16 ... 19: + if (phy->type == B43_PHYTYPE_N) + filename = "ucode16_mimo"; + else if (phy->type == B43_PHYTYPE_LP) + filename = "ucode16_lp"; + break; + case 15: filename = "ucode15"; - } else { - switch (dev->phy.type) { - case B43_PHYTYPE_N: - if (rev >= 16) - filename = "ucode16_mimo"; - else - goto err_no_ucode; - break; - case B43_PHYTYPE_HT: - if (rev == 29) - filename = "ucode29_mimo"; - else - goto err_no_ucode; - break; - case B43_PHYTYPE_LCN: - if (rev == 24) - filename = "ucode24_mimo"; - else - goto err_no_ucode; - break; - default: - goto err_no_ucode; - } + break; + case 14: + filename = "ucode14"; + break; + case 13: + filename = "ucode13"; + break; + case 11 ... 12: + filename = "ucode11"; + break; + case 5 ... 10: + filename = "ucode5"; + break; } + if (!filename) + goto err_no_ucode; err = b43_do_request_fw(ctx, filename, &fw->ucode, true); if (err) goto err_load; @@ -2268,117 +2294,117 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) goto err_load; /* Get initvals */ + filename = NULL; switch (dev->phy.type) { - case B43_PHYTYPE_A: - if ((rev >= 5) && (rev <= 10)) { - tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH); - if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY) - filename = "a0g1initvals5"; - else - filename = "a0g0initvals5"; - } else - goto err_no_initvals; - break; case B43_PHYTYPE_G: - if ((rev >= 5) && (rev <= 10)) - filename = "b0g0initvals5"; - else if (rev >= 13) + if (rev == 13) filename = "b0g0initvals13"; - else - goto err_no_initvals; + else if (rev >= 5 && rev <= 10) + filename = "b0g0initvals5"; break; case B43_PHYTYPE_N: - if (rev >= 16) + if (rev == 30) + filename = "n16initvals30"; + else if (rev == 28 || rev == 25) + filename = "n0initvals25"; + else if (rev == 24) + filename = "n0initvals24"; + else if (rev == 23) + filename = "n0initvals16"; /* What about n0initvals22? */ + else if (rev >= 16 && rev <= 18) filename = "n0initvals16"; - else if ((rev >= 11) && (rev <= 12)) + else if (rev >= 11 && rev <= 12) filename = "n0initvals11"; - else - goto err_no_initvals; break; case B43_PHYTYPE_LP: - if (rev == 13) - filename = "lp0initvals13"; + if (rev >= 16 && rev <= 18) + filename = "lp0initvals16"; + else if (rev == 15) + filename = "lp0initvals15"; else if (rev == 14) filename = "lp0initvals14"; - else if (rev >= 15) - filename = "lp0initvals15"; - else - goto err_no_initvals; + else if (rev == 13) + filename = "lp0initvals13"; break; case B43_PHYTYPE_HT: if (rev == 29) filename = "ht0initvals29"; - else - goto err_no_initvals; + else if (rev == 26) + filename = "ht0initvals26"; break; case B43_PHYTYPE_LCN: if (rev == 24) filename = "lcn0initvals24"; - else - goto err_no_initvals; break; - default: - goto err_no_initvals; + case B43_PHYTYPE_LCN40: + if (rev == 33) + filename = "lcn400initvals33"; + break; + case B43_PHYTYPE_AC: + if (rev == 42) + filename = "ac1initvals42"; + break; } + if (!filename) + goto err_no_initvals; err = b43_do_request_fw(ctx, filename, &fw->initvals, false); if (err) goto err_load; /* Get bandswitch initvals */ + filename = NULL; switch (dev->phy.type) { - case B43_PHYTYPE_A: - if ((rev >= 5) && (rev <= 10)) { - tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH); - if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY) - filename = "a0g1bsinitvals5"; - else - filename = "a0g0bsinitvals5"; - } else if (rev >= 11) - filename = NULL; - else - goto err_no_initvals; - break; case B43_PHYTYPE_G: - if ((rev >= 5) && (rev <= 10)) + if (rev == 13) + filename = "b0g0bsinitvals13"; + else if (rev >= 5 && rev <= 10) filename = "b0g0bsinitvals5"; - else if (rev >= 11) - filename = NULL; - else - goto err_no_initvals; break; case B43_PHYTYPE_N: - if (rev >= 16) + if (rev == 30) + filename = "n16bsinitvals30"; + else if (rev == 28 || rev == 25) + filename = "n0bsinitvals25"; + else if (rev == 24) + filename = "n0bsinitvals24"; + else if (rev == 23) + filename = "n0bsinitvals16"; /* What about n0bsinitvals22? */ + else if (rev >= 16 && rev <= 18) filename = "n0bsinitvals16"; - else if ((rev >= 11) && (rev <= 12)) + else if (rev >= 11 && rev <= 12) filename = "n0bsinitvals11"; - else - goto err_no_initvals; break; case B43_PHYTYPE_LP: - if (rev == 13) - filename = "lp0bsinitvals13"; + if (rev >= 16 && rev <= 18) + filename = "lp0bsinitvals16"; + else if (rev == 15) + filename = "lp0bsinitvals15"; else if (rev == 14) filename = "lp0bsinitvals14"; - else if (rev >= 15) - filename = "lp0bsinitvals15"; - else - goto err_no_initvals; + else if (rev == 13) + filename = "lp0bsinitvals13"; break; case B43_PHYTYPE_HT: if (rev == 29) filename = "ht0bsinitvals29"; - else - goto err_no_initvals; + else if (rev == 26) + filename = "ht0bsinitvals26"; break; case B43_PHYTYPE_LCN: if (rev == 24) filename = "lcn0bsinitvals24"; - else - goto err_no_initvals; break; - default: - goto err_no_initvals; + case B43_PHYTYPE_LCN40: + if (rev == 33) + filename = "lcn400bsinitvals33"; + break; + case B43_PHYTYPE_AC: + if (rev == 42) + filename = "ac1bsinitvals42"; + break; } + if (!filename) + goto err_no_initvals; err = b43_do_request_fw(ctx, filename, &fw->initvals_band, false); if (err) goto err_load; -- cgit v1.2.3 From efeb1430160109d4f1e21d28e79cf6093359ea01 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 24 Jun 2014 22:27:36 +0530 Subject: ath9k_hw: update CCK loop coefficients for AR953x 1.0 Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar953x_initvals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h index 8e5c3b9786e3..1907f863ab25 100644 --- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h @@ -219,7 +219,7 @@ static const u32 qca953x_1p0_baseband_core[][2] = { {0x00009d04, 0x40206c10}, {0x00009d08, 0x009c4060}, {0x00009d0c, 0x9883800a}, - {0x00009d10, 0x01884061}, + {0x00009d10, 0x018848c6}, {0x00009d14, 0x00c0040b}, {0x00009d18, 0x00000000}, {0x00009e08, 0x0038230c}, -- cgit v1.2.3 From c01a72987162fb7b29769522c0a55aae7a203ccc Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 24 Jun 2014 22:27:37 +0530 Subject: ath9k_hw: Add QCA953x 2.0 initvals Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 15 +- drivers/net/wireless/ath/ath9k/ar953x_initvals.h | 199 +++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/reg.h | 4 + 3 files changed, 214 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index ec1da0cc25f5..ddef9eedbac6 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -314,10 +314,17 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) qca953x_1p0_mac_core); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], qca953x_1p0_mac_postamble); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - qca953x_1p0_baseband_core); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - qca953x_1p0_baseband_postamble); + if (AR_SREV_9531_20(ah)) { + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + qca953x_2p0_baseband_core); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + qca953x_2p0_baseband_postamble); + } else { + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + qca953x_1p0_baseband_core); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + qca953x_1p0_baseband_postamble); + } INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], qca953x_1p0_radio_core); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h index 1907f863ab25..812a9d787bf3 100644 --- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h @@ -715,4 +715,203 @@ static const u32 qca953x_1p1_modes_no_xpa_tx_gain_table[][2] = { {0x00016448, 0x6c927a70}, }; +static const u32 qca953x_2p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0x0280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x6400a190}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14000600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x32840bbe}, + {0x000098bc, 0x00000002}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x9883800a}, + {0x00009d10, 0x018848c6}, + {0x00009d14, 0x00c0040b}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038230c}, + {0x00009e24, 0x990bb515}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009fc0, 0x813e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x02993b93}, + {0x0000a20c, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a248, 0x00000140}, + {0x0000a2a0, 0x00000007}, + {0x0000a2c0, 0x00000007}, + {0x0000a2c8, 0x00000000}, + {0x0000a2d4, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, + {0x0000a3a4, 0x000400ff}, + {0x0000a3a8, 0x6a6a6a6a}, + {0x0000a3ac, 0x6a6a6a6a}, + {0x0000a3b0, 0x00c8641a}, + {0x0000a3b4, 0x0000001a}, + {0x0000a3b8, 0x0088642a}, + {0x0000a3bc, 0x000001fa}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000000}, + {0x0000a3f8, 0x0c9bd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce42108}, + {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce73908}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce738e7}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00100000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x05000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a458, 0x00000000}, + {0x0000a644, 0xbfad9d74}, + {0x0000a648, 0x0048060a}, + {0x0000a64c, 0x00003c37}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x09080504}, + {0x0000a678, 0x0d0c0b0a}, + {0x0000a67c, 0x13121110}, + {0x0000a680, 0x31301514}, + {0x0000a684, 0x35343332}, + {0x0000a688, 0x00000036}, + {0x0000a690, 0x08000838}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000000}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, +}; + +static const u32 qca953x_2p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946222, 0xcf946222}, + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, + {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, + {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, + {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, + {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, +}; + #endif /* INITVALS_953X_H */ diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index f1bbce3f7774..a1499700bcf2 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -813,6 +813,7 @@ #define AR_SREV_VERSION_9531 0x500 #define AR_SREV_REVISION_9531_10 0 #define AR_SREV_REVISION_9531_11 1 +#define AR_SREV_REVISION_9531_20 2 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -958,6 +959,9 @@ #define AR_SREV_9531_11(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_11)) +#define AR_SREV_9531_20(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_20)) /* NOTE: When adding chips newer than Peacock, add chip check here */ #define AR_SREV_9580_10_OR_LATER(_ah) \ -- cgit v1.2.3 From ddbbd9e854f00f4f78d5f3df4e374af3d9eec5b2 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 24 Jun 2014 22:27:38 +0530 Subject: ath9k_hw: fix XPABIASLEVEL settings for AR9531 Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 235053ba7737..80c6eacbda53 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3535,7 +3535,8 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) { int bias = ar9003_modal_header(ah, is2ghz)->xpaBiasLvl; - if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah) || + AR_SREV_9531(ah)) REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); else if (AR_SREV_9462(ah) || AR_SREV_9550(ah) || AR_SREV_9565(ah)) REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); -- cgit v1.2.3 From af2db444855a574cb58db1f5f6b7a53f2c0fefda Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 24 Jun 2014 22:27:39 +0530 Subject: ath9k_hw: fix tx gain table index for AR953x Fix tx gain table index on fast channel change for AR953x. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 8927fc34d84c..542a8d51d3b0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1552,13 +1552,15 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, u8 *ini_reloaded) { unsigned int regWrites = 0; - u32 modesIndex; + u32 modesIndex, txgain_index; if (IS_CHAN_5GHZ(chan)) modesIndex = IS_CHAN_HT40(chan) ? 2 : 1; else modesIndex = IS_CHAN_HT40(chan) ? 3 : 4; + txgain_index = AR_SREV_9531(ah) ? 1 : modesIndex; + if (modesIndex == ah->modes_index) { *ini_reloaded = false; goto set_rfmode; @@ -1573,7 +1575,7 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, ar9003_hw_prog_ini(ah, &ah->ini_radio_post_sys2ant, modesIndex); - REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); + REG_WRITE_ARRAY(&ah->iniModesTxGain, txgain_index, regWrites); if (AR_SREV_9462_20_OR_LATER(ah)) { /* -- cgit v1.2.3 From 76ac9ed6ffb32eb38d2f208204159ae0cd3394b6 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 24 Jun 2014 22:27:40 +0530 Subject: ath9k_hw: Fix pll2_divfrac for AR953x Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ace4fe2740d4..fd0158fdf144 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -791,7 +791,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, refdiv = 5; } else { pll2_divint = 0x11; - pll2_divfrac = 0x26666; + pll2_divfrac = + AR_SREV_9531(ah) ? 0x26665 : 0x26666; refdiv = 1; } } -- cgit v1.2.3 From 80140b71e0bd2d9f6762791567cfd0aa04f20419 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 24 Jun 2014 15:39:43 -0700 Subject: p54: use request_firmware_direct() for optional EEPROM override The p54 driver uses request_firmware() twice, once for actual firmware and then another time for an optional user overide on EEPROM, 3826.eeprom. The custom EEPROM is optional but if not present we'll introduce an extra lag of 60 seconds with udev present. Annotate we don't want udev nonsense here to avoid the lag in case its not present. This was found with the following SmPL patch. @ firmware_not_critical @ expression cf; expression config_file; expression dev; int ret; identifier l; statement S; @@ - ret = request_firmware(&cf, config_file, dev); + ret = request_firmware_direct(&cf, config_file, dev); if (ret < 0) { ... when != goto l; when != return ret; when any } else { ... release_firmware(cf); ... } Cc: Takashi Iwai Cc: Christian Lamparter Cc: linux-wireless@vger.kernel.org Cc: cocci@systeme.lip6.fr Signed-off-by: Luis R. Rodriguez Acked-By: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index de15171e2cd8..63de5eed25cf 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -193,7 +193,7 @@ static int p54spi_request_eeprom(struct ieee80211_hw *dev) /* allow users to customize their eeprom. */ - ret = request_firmware(&eeprom, "3826.eeprom", &priv->spi->dev); + ret = request_firmware_direct(&eeprom, "3826.eeprom", &priv->spi->dev); if (ret < 0) { #ifdef CONFIG_P54_SPI_DEFAULT_EEPROM dev_info(&priv->spi->dev, "loading default eeprom...\n"); -- cgit v1.2.3 From 688df7ec26ffde2c8d79b0ac1a3378155da59ff2 Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Wed, 25 Jun 2014 15:47:45 +0530 Subject: rsi: Fixed errors and warnings reported by static code analyzers. Fixed a potential buffer overflow in 'rsi_rates' and a sparse warning related to difference in endianness in rsi_91x_mgmt.c. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 83abe580cf5f..8d110fd9eba1 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1055,7 +1055,8 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) rate_table_offset = 4; } - for (ii = 0, jj = 0; ii < ARRAY_SIZE(rsi_rates); ii++) { + for (ii = 0, jj = 0; + ii < (ARRAY_SIZE(rsi_rates) - rate_table_offset); ii++) { if (rate_bitmap & BIT(ii)) { selected_rates[jj++] = (rsi_rates[ii + rate_table_offset].bitrate / 5); @@ -1103,7 +1104,7 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) } for (; ii < RSI_TBL_SZ; ii++) - auto_rate->supported_rates[ii] = min_rate; + auto_rate->supported_rates[ii] = cpu_to_le16(min_rate); auto_rate->num_supported_rates = cpu_to_le16(num_supported_rates * 2); auto_rate->moderate_rate_inx = cpu_to_le16(num_supported_rates / 2); -- cgit v1.2.3 From d51193d4ae181df37e9196a54b1fe3360ca920f2 Mon Sep 17 00:00:00 2001 From: Jahnavi Meher Date: Wed, 25 Jun 2014 15:48:15 +0530 Subject: rsi: Fixed warnings reported by static code analyzers. Fixed a warning related to incorrect return type and removed an unnecessary semi colon. Signed-off-by: Jahnavi Meher Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 1cd0914db270..f3d3995d8f6b 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -92,6 +92,7 @@ static u32 rsi_get_num_pkts_dequeue(struct rsi_common *common, u8 q_num) struct sk_buff *skb; u32 pkt_cnt = 0; s16 txop = common->tx_qinfo[q_num].txop * 32; + __le16 r_txop; struct ieee80211_rate rate; rate.bitrate = RSI_RATE_MCS0 * 5 * 10; /* Convert to Kbps */ @@ -104,10 +105,11 @@ static u32 rsi_get_num_pkts_dequeue(struct rsi_common *common, u8 q_num) return 0; do { - txop -= ieee80211_generic_frame_duration(adapter->hw, - adapter->vifs[0], - common->band, - skb->len, &rate); + r_txop = ieee80211_generic_frame_duration(adapter->hw, + adapter->vifs[0], + common->band, + skb->len, &rate); + txop -= le16_to_cpu(r_txop); pkt_cnt += 1; /*checking if pkts are still there*/ if (skb_queue_len(&common->tx_queue[q_num]) - pkt_cnt) @@ -191,7 +193,7 @@ get_queue_num: if (q_num == VO_Q || q_num == VI_Q) { common->pkt_cnt = rsi_get_num_pkts_dequeue(common, q_num); common->pkt_cnt -= 1; - }; + } return q_num; } -- cgit v1.2.3 From ad362984aad7127e46ff2403a85a3706530ac22b Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 25 Jun 2014 15:46:51 -0400 Subject: b43: b43_phyops_a can be static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC: "Rafał Miłecki" CC: "John W. Linville" Signed-off-by: Fengguang Wu Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index a6c38104693d..25e40432d68b 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -573,7 +573,7 @@ static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev) {//TODO } -const struct b43_phy_operations b43_phyops_a = { +static const struct b43_phy_operations b43_phyops_a = { .allocate = b43_aphy_op_allocate, .free = b43_aphy_op_free, .prepare_structs = b43_aphy_op_prepare_structs, -- cgit v1.2.3 From 057d32f03d0d5425b3e089d98712d6cc962b705f Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 20 Jun 2014 17:07:42 -0700 Subject: Revert "mwifiex: Use the proper interfaces" This reverts commit a82fc3b4a2bceb7c6587249cb690342eb5065979. Thomas corrected me on that I misunderstood Johannes' comment for net_timedelta() and the ktime_get_real() usage inside __net_timestamp(). Cc: Thomas Gleixner Cc: Johannes Berg Cc: John W. Linville Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 4 +++- drivers/net/wireless/mwifiex/main.c | 4 +++- drivers/net/wireless/mwifiex/tdls.c | 8 ++++++-- drivers/net/wireless/mwifiex/uap_txrx.c | 4 +++- drivers/net/wireless/mwifiex/wmm.c | 9 ++++++++- 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 15fa7b453372..44b8f4ab3b35 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -121,6 +121,7 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) u8 addr[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; u16 pkt_len; u32 tx_control = 0, pkt_type = PKT_TYPE_MGMT; + struct timeval tv; pkt_len = len + ETH_ALEN; @@ -142,7 +143,8 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) len - sizeof(struct ieee80211_hdr_3addr)); skb->priority = LOW_PRIO_TID; - __net_timestamp(skb); + do_gettimeofday(&tv); + skb->tstamp = timeval_to_ktime(tv); return 0; } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 657504c3c79d..1261d9a41e11 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -609,6 +609,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct sk_buff *new_skb; struct mwifiex_txinfo *tx_info; + struct timeval tv; dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n", jiffies, priv->bss_type, priv->bss_num); @@ -655,7 +656,8 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) * firmware for aggregate delay calculation for stats and * MSDU lifetime expiry. */ - __net_timestamp(skb); + do_gettimeofday(&tv); + skb->tstamp = timeval_to_ktime(tv); mwifiex_queue_tx_pkt(priv, skb); diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 3efbcbe7e891..e73034fbbde9 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -530,6 +530,7 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, { struct sk_buff *skb; struct mwifiex_txinfo *tx_info; + struct timeval tv; int ret; u16 skb_len; @@ -607,7 +608,8 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, tx_info->bss_num = priv->bss_num; tx_info->bss_type = priv->bss_type; - __net_timestamp(skb); + do_gettimeofday(&tv); + skb->tstamp = timeval_to_ktime(tv); mwifiex_queue_tx_pkt(priv, skb); return 0; @@ -700,6 +702,7 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer, { struct sk_buff *skb; struct mwifiex_txinfo *tx_info; + struct timeval tv; u8 *pos; u32 pkt_type, tx_control; u16 pkt_len, skb_len; @@ -764,7 +767,8 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer, pkt_len = skb->len - MWIFIEX_MGMT_FRAME_HEADER_SIZE - sizeof(pkt_len); memcpy(skb->data + MWIFIEX_MGMT_FRAME_HEADER_SIZE, &pkt_len, sizeof(pkt_len)); - __net_timestamp(skb); + do_gettimeofday(&tv); + skb->tstamp = timeval_to_ktime(tv); mwifiex_queue_tx_pkt(priv, skb); return 0; diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index ddfc3c6c1e78..57fa47d2c616 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -96,6 +96,7 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, struct sk_buff *new_skb; struct mwifiex_txinfo *tx_info; int hdr_chop; + struct timeval tv; struct ethhdr *p_ethhdr; uap_rx_pd = (struct uap_rxpd *)(skb->data); @@ -191,7 +192,8 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, tx_info->pkt_len = skb->len; } - __net_timestamp(skb); + do_gettimeofday(&tv); + skb->tstamp = timeval_to_ktime(tv); mwifiex_wmm_add_buf_txqueue(priv, skb); atomic_inc(&adapter->tx_pending); atomic_inc(&adapter->pending_bridged_pkts); diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index e8556b6e04ee..8cd123ecebbf 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -878,8 +878,15 @@ u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, const struct sk_buff *skb) { - u32 queue_delay = ktime_to_ms(ktime_sub(ktime_get(), skb->tstamp)); u8 ret_val; + struct timeval out_tstamp, in_tstamp; + u32 queue_delay; + + do_gettimeofday(&out_tstamp); + in_tstamp = ktime_to_timeval(skb->tstamp); + + queue_delay = (out_tstamp.tv_sec - in_tstamp.tv_sec) * 1000; + queue_delay += (out_tstamp.tv_usec - in_tstamp.tv_usec) / 1000; /* * Queue delay is passed as a uint8 in units of 2ms (ms shifted -- cgit v1.2.3 From c64800e772a03a8162e107c2d03d06175fff443d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 12 Jun 2014 08:31:34 +0100 Subject: wireless: mwifiex: Use the proper interfaces Why is converting time formats so desired if there are proper interfaces for this? Signed-off-by: Thomas Gleixner Acked-by: Bing Zhao Cc: "John W. Linville" Cc: linux-wireless@vger.kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 4 +--- drivers/net/wireless/mwifiex/main.c | 4 +--- drivers/net/wireless/mwifiex/tdls.c | 8 ++------ drivers/net/wireless/mwifiex/uap_txrx.c | 4 +--- drivers/net/wireless/mwifiex/wmm.c | 9 +-------- 5 files changed, 6 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 44b8f4ab3b35..15fa7b453372 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -121,7 +121,6 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) u8 addr[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; u16 pkt_len; u32 tx_control = 0, pkt_type = PKT_TYPE_MGMT; - struct timeval tv; pkt_len = len + ETH_ALEN; @@ -143,8 +142,7 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) len - sizeof(struct ieee80211_hdr_3addr)); skb->priority = LOW_PRIO_TID; - do_gettimeofday(&tv); - skb->tstamp = timeval_to_ktime(tv); + __net_timestamp(skb); return 0; } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 1261d9a41e11..657504c3c79d 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -609,7 +609,6 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct sk_buff *new_skb; struct mwifiex_txinfo *tx_info; - struct timeval tv; dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n", jiffies, priv->bss_type, priv->bss_num); @@ -656,8 +655,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) * firmware for aggregate delay calculation for stats and * MSDU lifetime expiry. */ - do_gettimeofday(&tv); - skb->tstamp = timeval_to_ktime(tv); + __net_timestamp(skb); mwifiex_queue_tx_pkt(priv, skb); diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index e73034fbbde9..3efbcbe7e891 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -530,7 +530,6 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, { struct sk_buff *skb; struct mwifiex_txinfo *tx_info; - struct timeval tv; int ret; u16 skb_len; @@ -608,8 +607,7 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, tx_info->bss_num = priv->bss_num; tx_info->bss_type = priv->bss_type; - do_gettimeofday(&tv); - skb->tstamp = timeval_to_ktime(tv); + __net_timestamp(skb); mwifiex_queue_tx_pkt(priv, skb); return 0; @@ -702,7 +700,6 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer, { struct sk_buff *skb; struct mwifiex_txinfo *tx_info; - struct timeval tv; u8 *pos; u32 pkt_type, tx_control; u16 pkt_len, skb_len; @@ -767,8 +764,7 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer, pkt_len = skb->len - MWIFIEX_MGMT_FRAME_HEADER_SIZE - sizeof(pkt_len); memcpy(skb->data + MWIFIEX_MGMT_FRAME_HEADER_SIZE, &pkt_len, sizeof(pkt_len)); - do_gettimeofday(&tv); - skb->tstamp = timeval_to_ktime(tv); + __net_timestamp(skb); mwifiex_queue_tx_pkt(priv, skb); return 0; diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index 57fa47d2c616..ddfc3c6c1e78 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -96,7 +96,6 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, struct sk_buff *new_skb; struct mwifiex_txinfo *tx_info; int hdr_chop; - struct timeval tv; struct ethhdr *p_ethhdr; uap_rx_pd = (struct uap_rxpd *)(skb->data); @@ -192,8 +191,7 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv, tx_info->pkt_len = skb->len; } - do_gettimeofday(&tv); - skb->tstamp = timeval_to_ktime(tv); + __net_timestamp(skb); mwifiex_wmm_add_buf_txqueue(priv, skb); atomic_inc(&adapter->tx_pending); atomic_inc(&adapter->pending_bridged_pkts); diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 8cd123ecebbf..94c98a86ebbe 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -878,15 +878,8 @@ u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, const struct sk_buff *skb) { + u32 queue_delay = ktime_to_ms(net_timedelta(skb->tstamp)); u8 ret_val; - struct timeval out_tstamp, in_tstamp; - u32 queue_delay; - - do_gettimeofday(&out_tstamp); - in_tstamp = ktime_to_timeval(skb->tstamp); - - queue_delay = (out_tstamp.tv_sec - in_tstamp.tv_sec) * 1000; - queue_delay += (out_tstamp.tv_usec - in_tstamp.tv_usec) / 1000; /* * Queue delay is passed as a uint8 in units of 2ms (ms shifted -- cgit v1.2.3 From 6d514b4e7737ad75a7e7e0a3f7dde45d46341691 Mon Sep 17 00:00:00 2001 From: George Spelvin Date: Mon, 23 Jun 2014 15:11:54 +0200 Subject: lib: crc32: Greatly shrink CRC combining code There's no need for a full 32x32 matrix, when rows before the last are just shifted copies of the rows after them. There's still room for improvement (especially on X86 processors with CRC32 and PCLMUL instructions), but this is a large step in the right direction [which is in particular useful for its current user, namely SCTP checksumming over multiple skb frags[] entries, i.e. in IPVS balancing when other CRC32 offloads are not available]. The internal primitive is now called crc32_generic_shift and takes one less argument; the XOR with crc2 is done in inline wrappers. Signed-off-by: George Spelvin Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/linux/crc32.h | 14 ++++- lib/crc32.c | 147 ++++++++++++++++++++++++-------------------------- 2 files changed, 82 insertions(+), 79 deletions(-) diff --git a/include/linux/crc32.h b/include/linux/crc32.h index 7d275c4fc011..edf34e876e40 100644 --- a/include/linux/crc32.h +++ b/include/linux/crc32.h @@ -29,7 +29,12 @@ extern u32 crc32_be(u32 crc, unsigned char const *p, size_t len); * with the same initializer as crc1, and crc2 seed was 0. See * also crc32_combine_test(). */ -extern u32 crc32_le_combine(u32 crc1, u32 crc2, size_t len2); +u32 __attribute_const__ crc32_le_shift(u32 crc, size_t len); + +static inline u32 crc32_le_combine(u32 crc1, u32 crc2, size_t len2) +{ + return crc32_le_shift(crc1, len2) ^ crc2; +} extern u32 __crc32c_le(u32 crc, unsigned char const *p, size_t len); @@ -51,7 +56,12 @@ extern u32 __crc32c_le(u32 crc, unsigned char const *p, size_t len); * seeded with the same initializer as crc1, and crc2 seed * was 0. See also crc32c_combine_test(). */ -extern u32 __crc32c_le_combine(u32 crc1, u32 crc2, size_t len2); +u32 __attribute_const__ __crc32c_le_shift(u32 crc, size_t len); + +static inline u32 __crc32c_le_combine(u32 crc1, u32 crc2, size_t len2) +{ + return __crc32c_le_shift(crc1, len2) ^ crc2; +} #define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)(data), length) diff --git a/lib/crc32.c b/lib/crc32.c index 21a7b2135af6..9af30ff334c5 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -50,30 +50,6 @@ MODULE_AUTHOR("Matt Domsch "); MODULE_DESCRIPTION("Various CRC32 calculations"); MODULE_LICENSE("GPL"); -#define GF2_DIM 32 - -static u32 gf2_matrix_times(u32 *mat, u32 vec) -{ - u32 sum = 0; - - while (vec) { - if (vec & 1) - sum ^= *mat; - vec >>= 1; - mat++; - } - - return sum; -} - -static void gf2_matrix_square(u32 *square, u32 *mat) -{ - int i; - - for (i = 0; i < GF2_DIM; i++) - square[i] = gf2_matrix_times(mat, mat[i]); -} - #if CRC_LE_BITS > 8 || CRC_BE_BITS > 8 /* implements slicing-by-4 or slicing-by-8 algorithm */ @@ -155,51 +131,6 @@ crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256]) } #endif -/* For conditions of distribution and use, see copyright notice in zlib.h */ -static u32 crc32_generic_combine(u32 crc1, u32 crc2, size_t len2, - u32 polynomial) -{ - u32 even[GF2_DIM]; /* Even-power-of-two zeros operator */ - u32 odd[GF2_DIM]; /* Odd-power-of-two zeros operator */ - u32 row; - int i; - - if (len2 <= 0) - return crc1; - - /* Put operator for one zero bit in odd */ - odd[0] = polynomial; - row = 1; - for (i = 1; i < GF2_DIM; i++) { - odd[i] = row; - row <<= 1; - } - - gf2_matrix_square(even, odd); /* Put operator for two zero bits in even */ - gf2_matrix_square(odd, even); /* Put operator for four zero bits in odd */ - - /* Apply len2 zeros to crc1 (first square will put the operator for one - * zero byte, eight zero bits, in even). - */ - do { - /* Apply zeros operator for this bit of len2 */ - gf2_matrix_square(even, odd); - if (len2 & 1) - crc1 = gf2_matrix_times(even, crc1); - len2 >>= 1; - /* If no more bits set, then done */ - if (len2 == 0) - break; - /* Another iteration of the loop with odd and even swapped */ - gf2_matrix_square(odd, even); - if (len2 & 1) - crc1 = gf2_matrix_times(odd, crc1); - len2 >>= 1; - } while (len2 != 0); - - crc1 ^= crc2; - return crc1; -} /** * crc32_le_generic() - Calculate bitwise little-endian Ethernet AUTODIN II @@ -271,19 +202,81 @@ u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len) (const u32 (*)[256])crc32ctable_le, CRC32C_POLY_LE); } #endif -u32 __pure crc32_le_combine(u32 crc1, u32 crc2, size_t len2) +EXPORT_SYMBOL(crc32_le); +EXPORT_SYMBOL(__crc32c_le); + +/* + * This multiplies the polynomials x and y modulo the given modulus. + * This follows the "little-endian" CRC convention that the lsbit + * represents the highest power of x, and the msbit represents x^0. + */ +static u32 __attribute_const__ gf2_multiply(u32 x, u32 y, u32 modulus) { - return crc32_generic_combine(crc1, crc2, len2, CRCPOLY_LE); + u32 product = x & 1 ? y : 0; + int i; + + for (i = 0; i < 31; i++) { + product = (product >> 1) ^ (product & 1 ? modulus : 0); + x >>= 1; + product ^= x & 1 ? y : 0; + } + + return product; } -u32 __pure __crc32c_le_combine(u32 crc1, u32 crc2, size_t len2) +/** + * crc32_generic_shift - Append len 0 bytes to crc, in logarithmic time + * @crc: The original little-endian CRC (i.e. lsbit is x^31 coefficient) + * @len: The number of bytes. @crc is multiplied by x^(8*@len) + * @polynomial: The modulus used to reduce the result to 32 bits. + * + * It's possible to parallelize CRC computations by computing a CRC + * over separate ranges of a buffer, then summing them. + * This shifts the given CRC by 8*len bits (i.e. produces the same effect + * as appending len bytes of zero to the data), in time proportional + * to log(len). + */ +static u32 __attribute_const__ crc32_generic_shift(u32 crc, size_t len, + u32 polynomial) { - return crc32_generic_combine(crc1, crc2, len2, CRC32C_POLY_LE); + u32 power = polynomial; /* CRC of x^32 */ + int i; + + /* Shift up to 32 bits in the simple linear way */ + for (i = 0; i < 8 * (int)(len & 3); i++) + crc = (crc >> 1) ^ (crc & 1 ? polynomial : 0); + + len >>= 2; + if (!len) + return crc; + + for (;;) { + /* "power" is x^(2^i), modulo the polynomial */ + if (len & 1) + crc = gf2_multiply(crc, power, polynomial); + + len >>= 1; + if (!len) + break; + + /* Square power, advancing to x^(2^(i+1)) */ + power = gf2_multiply(power, power, polynomial); + } + + return crc; } -EXPORT_SYMBOL(crc32_le); -EXPORT_SYMBOL(crc32_le_combine); -EXPORT_SYMBOL(__crc32c_le); -EXPORT_SYMBOL(__crc32c_le_combine); + +u32 __attribute_const__ crc32_le_shift(u32 crc, size_t len) +{ + return crc32_generic_shift(crc, len, CRCPOLY_LE); +} + +u32 __attribute_const__ __crc32c_le_shift(u32 crc, size_t len) +{ + return crc32_generic_shift(crc, len, CRC32C_POLY_LE); +} +EXPORT_SYMBOL(crc32_le_shift); +EXPORT_SYMBOL(__crc32c_le_shift); /** * crc32_be_generic() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32 -- cgit v1.2.3 From 4fa8e03b22df9b34f87906fa29de788bfa628bff Mon Sep 17 00:00:00 2001 From: George Spelvin Date: Mon, 23 Jun 2014 15:11:55 +0200 Subject: lib: crc32: Mark test data __initconst So it gets discarded after the selftest. Signed-off-by: George Spelvin Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- lib/crc32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/crc32.c b/lib/crc32.c index 9af30ff334c5..af938ab12468 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -344,7 +344,7 @@ EXPORT_SYMBOL(crc32_be); #ifdef CONFIG_CRC32_SELFTEST /* 4096 random bytes */ -static u8 __attribute__((__aligned__(8))) test_buf[] = +static u8 const __aligned(8) test_buf[] __initconst = { 0x5b, 0x85, 0x21, 0xcb, 0x09, 0x68, 0x7d, 0x30, 0xc7, 0x69, 0xd7, 0x30, 0x92, 0xde, 0x59, 0xe4, @@ -868,7 +868,7 @@ static struct crc_test { u32 crc_le; /* expected crc32_le result */ u32 crc_be; /* expected crc32_be result */ u32 crc32c_le; /* expected crc32c_le result */ -} test[] = +} const test[] __initconst = { {0x674bf11d, 0x00000038, 0x00000542, 0x0af6d466, 0xd8b6e4c1, 0xf6e93d6c}, {0x35c672c6, 0x0000003a, 0x000001aa, 0xc6d3dfba, 0x28aaf3ad, 0x0fe92aca}, -- cgit v1.2.3 From d8f1c4778e957273c3b5b6e045d8d3af38484ca8 Mon Sep 17 00:00:00 2001 From: George Spelvin Date: Mon, 23 Jun 2014 15:11:56 +0200 Subject: lib: crc32: Add some additional __pure annotations In case they help the compiler. Signed-off-by: George Spelvin Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/linux/crc32.h | 6 +++--- lib/crc32.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/crc32.h b/include/linux/crc32.h index edf34e876e40..9e8a032c1788 100644 --- a/include/linux/crc32.h +++ b/include/linux/crc32.h @@ -8,8 +8,8 @@ #include #include -extern u32 crc32_le(u32 crc, unsigned char const *p, size_t len); -extern u32 crc32_be(u32 crc, unsigned char const *p, size_t len); +u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len); +u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len); /** * crc32_le_combine - Combine two crc32 check values into one. For two @@ -36,7 +36,7 @@ static inline u32 crc32_le_combine(u32 crc1, u32 crc2, size_t len2) return crc32_le_shift(crc1, len2) ^ crc2; } -extern u32 __crc32c_le(u32 crc, unsigned char const *p, size_t len); +u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len); /** * __crc32c_le_combine - Combine two crc32c check values into one. For two diff --git a/lib/crc32.c b/lib/crc32.c index af938ab12468..9a907d489d95 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -53,7 +53,7 @@ MODULE_LICENSE("GPL"); #if CRC_LE_BITS > 8 || CRC_BE_BITS > 8 /* implements slicing-by-4 or slicing-by-8 algorithm */ -static inline u32 +static inline u32 __pure crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256]) { # ifdef __LITTLE_ENDIAN -- cgit v1.2.3 From 1f74714f1e34a84fe4ef2a6d9b76c20794fb5dcf Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 23 Jun 2014 19:32:47 +0200 Subject: net/dsa/dsa.c: remove unnecessary null test before kfree Fix checkpatch warning: WARNING: kfree(NULL) is safe this check is probably not required Cc: "David S. Miller" Cc: Grant Likely Cc: netdev@vger.kernel.org Cc: Joe Perches Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/dsa/dsa.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 5db37cef50a9..0a49632fac47 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -351,8 +351,7 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd) for (i = 0; i < pd->nr_chips; i++) { port_index = 0; while (port_index < DSA_MAX_PORTS) { - if (pd->chip[i].port_names[port_index]) - kfree(pd->chip[i].port_names[port_index]); + kfree(pd->chip[i].port_names[port_index]); port_index++; } kfree(pd->chip[i].rtable); -- cgit v1.2.3 From 28c4ec0df60c8162c2da48c1df5e1cb2f04cdaa5 Mon Sep 17 00:00:00 2001 From: Jitendra Kalsaria Date: Mon, 23 Jun 2014 15:10:33 -0400 Subject: bnx2: Rebranding bnx2 driver. o QLogic has acquired the NetXtremeII products and drivers from Broadcom. This patch re-brands bnx2 driver as a QLogic driver Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/Kconfig | 4 ++-- drivers/net/ethernet/broadcom/bnx2.c | 9 +++++---- drivers/net/ethernet/broadcom/bnx2.h | 5 +++-- drivers/net/ethernet/broadcom/bnx2_fw.h | 3 ++- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 3e488094b073..0bde4710158a 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -72,12 +72,12 @@ config BCMGENET Broadcom BCM7xxx Set Top Box family chipset. config BNX2 - tristate "Broadcom NetXtremeII support" + tristate "QLogic NetXtremeII support" depends on PCI select CRC32 select FW_LOADER ---help--- - This driver supports Broadcom NetXtremeII gigabit Ethernet cards. + This driver supports QLogic NetXtremeII gigabit Ethernet cards. To compile this driver as a module, choose M here: the module will be called bnx2. This is recommended. diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 67d2b0047371..e64c963fe775 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -1,6 +1,7 @@ -/* bnx2.c: Broadcom NX2 network driver. +/* bnx2.c: QLogic NX2 network driver. * - * Copyright (c) 2004-2013 Broadcom Corporation + * Copyright (c) 2004-2014 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation * * 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 @@ -71,10 +72,10 @@ #define TX_TIMEOUT (5*HZ) static char version[] = - "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + "QLogic NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Michael Chan "); -MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/5716 Driver"); +MODULE_DESCRIPTION("QLogic NetXtreme II BCM5706/5708/5709/5716 Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); MODULE_FIRMWARE(FW_MIPS_FILE_06); diff --git a/drivers/net/ethernet/broadcom/bnx2.h b/drivers/net/ethernet/broadcom/bnx2.h index e341bc366fa5..28df35d35893 100644 --- a/drivers/net/ethernet/broadcom/bnx2.h +++ b/drivers/net/ethernet/broadcom/bnx2.h @@ -1,6 +1,7 @@ -/* bnx2.h: Broadcom NX2 network driver. +/* bnx2.h: QLogic NX2 network driver. * - * Copyright (c) 2004-2013 Broadcom Corporation + * Copyright (c) 2004-2014 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2_fw.h b/drivers/net/ethernet/broadcom/bnx2_fw.h index 940eb91f209d..7db79c28b5ff 100644 --- a/drivers/net/ethernet/broadcom/bnx2_fw.h +++ b/drivers/net/ethernet/broadcom/bnx2_fw.h @@ -1,6 +1,7 @@ -/* bnx2_fw.h: Broadcom NX2 network driver. +/* bnx2_fw.h: QLogic NX2 network driver. * * Copyright (c) 2004, 2005, 2006, 2007 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation * * 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 -- cgit v1.2.3 From d7afae05ad2e9c2cbf74e1419de5a0d6aa9c74f4 Mon Sep 17 00:00:00 2001 From: Jitendra Kalsaria Date: Mon, 23 Jun 2014 15:10:34 -0400 Subject: cnic: Rebranding cnic driver. o QLogic has acquired the NetXtremeII products and drivers from Broadcom. This patch re-brands cnic driver as a QLogic driver Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/Kconfig | 4 ++-- drivers/net/ethernet/broadcom/cnic.c | 10 ++++++---- drivers/net/ethernet/broadcom/cnic.h | 3 ++- drivers/net/ethernet/broadcom/cnic_defs.h | 3 ++- drivers/net/ethernet/broadcom/cnic_if.h | 3 ++- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 0bde4710158a..7dcfb19a31c8 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -83,12 +83,12 @@ config BNX2 will be called bnx2. This is recommended. config CNIC - tristate "Broadcom CNIC support" + tristate "QLogic CNIC support" depends on PCI select BNX2 select UIO ---help--- - This driver supports offload features of Broadcom NetXtremeII + This driver supports offload features of QLogic NetXtremeII gigabit Ethernet cards. To compile this driver as a module, choose M here: the module diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c index 8244e2b14bb4..27861a6c7ca5 100644 --- a/drivers/net/ethernet/broadcom/cnic.c +++ b/drivers/net/ethernet/broadcom/cnic.c @@ -1,13 +1,15 @@ -/* cnic.c: Broadcom CNIC core network driver. +/* cnic.c: QLogic CNIC core network driver. * * Copyright (c) 2006-2014 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation * * 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. * * Original skeleton written by: John(Zongxi) Chen (zongxi@broadcom.com) - * Modified and maintained by: Michael Chan + * Previously modified and maintained by: Michael Chan + * Maintained By: Dept-HSGLinuxNICDev@qlogic.com */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -56,11 +58,11 @@ #define CNIC_MODULE_NAME "cnic" static char version[] = - "Broadcom NetXtreme II CNIC Driver " CNIC_MODULE_NAME " v" CNIC_MODULE_VERSION " (" CNIC_MODULE_RELDATE ")\n"; + "QLogic NetXtreme II CNIC Driver " CNIC_MODULE_NAME " v" CNIC_MODULE_VERSION " (" CNIC_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Michael Chan and John(Zongxi) " "Chen (zongxi@broadcom.com"); -MODULE_DESCRIPTION("Broadcom NetXtreme II CNIC Driver"); +MODULE_DESCRIPTION("QLogic NetXtreme II CNIC Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(CNIC_MODULE_VERSION); diff --git a/drivers/net/ethernet/broadcom/cnic.h b/drivers/net/ethernet/broadcom/cnic.h index d535ae4228b4..4baea81bae7a 100644 --- a/drivers/net/ethernet/broadcom/cnic.h +++ b/drivers/net/ethernet/broadcom/cnic.h @@ -1,6 +1,7 @@ -/* cnic.h: Broadcom CNIC core network driver. +/* cnic.h: QLogic CNIC core network driver. * * Copyright (c) 2006-2014 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation * * 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 diff --git a/drivers/net/ethernet/broadcom/cnic_defs.h b/drivers/net/ethernet/broadcom/cnic_defs.h index dcbca6997e8f..b38499774071 100644 --- a/drivers/net/ethernet/broadcom/cnic_defs.h +++ b/drivers/net/ethernet/broadcom/cnic_defs.h @@ -1,7 +1,8 @@ -/* cnic.c: Broadcom CNIC core network driver. +/* cnic.c: QLogic CNIC core network driver. * * Copyright (c) 2006-2014 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation * * 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 diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h index 5f4d5573a73d..8bb36c1c4d68 100644 --- a/drivers/net/ethernet/broadcom/cnic_if.h +++ b/drivers/net/ethernet/broadcom/cnic_if.h @@ -1,6 +1,7 @@ -/* cnic_if.h: Broadcom CNIC core network driver. +/* cnic_if.h: QLogic CNIC core network driver. * * Copyright (c) 2006-2014 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation * * 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 -- cgit v1.2.3 From f1d1baebd1f81904cd12d2bd578353853daa56b9 Mon Sep 17 00:00:00 2001 From: Jitendra Kalsaria Date: Mon, 23 Jun 2014 15:10:35 -0400 Subject: MAINTAINERS: Update bnx2 maintainers Signed-off-by: Jitendra Kalsaria Signed-off-by: David S. Miller --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 134483f206e4..884803978ed4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1894,7 +1894,8 @@ S: Supported F: drivers/net/ethernet/broadcom/genet/ BROADCOM BNX2 GIGABIT ETHERNET DRIVER -M: Michael Chan +M: Sony Chacko +M: Dept-HSGLinuxNICDev@qlogic.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/broadcom/bnx2.* -- cgit v1.2.3 From bb446c19fefd7b4435adb12a9dd7666adc5b553a Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Mon, 23 Jun 2014 15:36:02 -0700 Subject: veth: add netpoll support It is trivial to add netpoll support to veth, since it is not a stacked device, we don't need to setup and clean up netpoll. Reported-by: Stefan Priebe Cc: "David S. Miller" Cc: Neil Horman Acked-by: Neil Horman Signed-off-by: Cong Wang Acked-by: Neil Horman Signed-off-by: David S. Miller --- drivers/net/veth.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index b4a10bcb66a0..9b945e60530e 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -248,6 +248,21 @@ static void veth_dev_free(struct net_device *dev) free_netdev(dev); } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void veth_poll_controller(struct net_device *dev) +{ + /* veth only receives frames when its peer sends one + * Since it's a synchronous operation, we are guaranteed + * never to have pending data when we poll for it so + * there is nothing to do here. + * + * We need this though so netpoll recognizes us as an interface that + * supports polling, which enables bridge devices in virt setups to + * still use netconsole + */ +} +#endif /* CONFIG_NET_POLL_CONTROLLER */ + static const struct net_device_ops veth_netdev_ops = { .ndo_init = veth_dev_init, .ndo_open = veth_open, @@ -257,6 +272,9 @@ static const struct net_device_ops veth_netdev_ops = { .ndo_get_stats64 = veth_get_stats64, .ndo_set_rx_mode = veth_set_multicast_list, .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = veth_poll_controller, +#endif }; #define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \ -- cgit v1.2.3 From f6d8cb2eeded7df18b821a321d4cd1cdd1754bf8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 24 Jun 2014 05:32:48 -0700 Subject: inet: reduce TLB pressure for listeners It seems overkill to use vmalloc() for typical listeners with less than 2048 hash buckets. Try kmalloc() and fallback to vmalloc() to reduce TLB pressure. Use kvfree() helper as it is now available. Use ilog2() instead of a loop. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/request_sock.c | 43 ++++++++++++------------------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/net/core/request_sock.c b/net/core/request_sock.c index 467f326126e0..04db318e6218 100644 --- a/net/core/request_sock.c +++ b/net/core/request_sock.c @@ -41,27 +41,27 @@ int reqsk_queue_alloc(struct request_sock_queue *queue, unsigned int nr_table_entries) { size_t lopt_size = sizeof(struct listen_sock); - struct listen_sock *lopt; + struct listen_sock *lopt = NULL; nr_table_entries = min_t(u32, nr_table_entries, sysctl_max_syn_backlog); nr_table_entries = max_t(u32, nr_table_entries, 8); nr_table_entries = roundup_pow_of_two(nr_table_entries + 1); lopt_size += nr_table_entries * sizeof(struct request_sock *); - if (lopt_size > PAGE_SIZE) + + if (lopt_size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) + lopt = kzalloc(lopt_size, GFP_KERNEL | + __GFP_NOWARN | + __GFP_NORETRY); + if (!lopt) lopt = vzalloc(lopt_size); - else - lopt = kzalloc(lopt_size, GFP_KERNEL); - if (lopt == NULL) + if (!lopt) return -ENOMEM; - for (lopt->max_qlen_log = 3; - (1 << lopt->max_qlen_log) < nr_table_entries; - lopt->max_qlen_log++); - get_random_bytes(&lopt->hash_rnd, sizeof(lopt->hash_rnd)); rwlock_init(&queue->syn_wait_lock); queue->rskq_accept_head = NULL; lopt->nr_table_entries = nr_table_entries; + lopt->max_qlen_log = ilog2(nr_table_entries); write_lock_bh(&queue->syn_wait_lock); queue->listen_opt = lopt; @@ -72,22 +72,8 @@ int reqsk_queue_alloc(struct request_sock_queue *queue, void __reqsk_queue_destroy(struct request_sock_queue *queue) { - struct listen_sock *lopt; - size_t lopt_size; - - /* - * this is an error recovery path only - * no locking needed and the lopt is not NULL - */ - - lopt = queue->listen_opt; - lopt_size = sizeof(struct listen_sock) + - lopt->nr_table_entries * sizeof(struct request_sock *); - - if (lopt_size > PAGE_SIZE) - vfree(lopt); - else - kfree(lopt); + /* This is an error recovery path only, no locking needed */ + kvfree(queue->listen_opt); } static inline struct listen_sock *reqsk_queue_yank_listen_sk( @@ -107,8 +93,6 @@ void reqsk_queue_destroy(struct request_sock_queue *queue) { /* make all the listen_opt local to us */ struct listen_sock *lopt = reqsk_queue_yank_listen_sk(queue); - size_t lopt_size = sizeof(struct listen_sock) + - lopt->nr_table_entries * sizeof(struct request_sock *); if (lopt->qlen != 0) { unsigned int i; @@ -125,10 +109,7 @@ void reqsk_queue_destroy(struct request_sock_queue *queue) } WARN_ON(lopt->qlen != 0); - if (lopt_size > PAGE_SIZE) - vfree(lopt); - else - kfree(lopt); + kvfree(lopt); } /* -- cgit v1.2.3 From a69f5edb8ba20c87c5f7c96ec40581f9f51f2910 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 24 Jun 2014 11:20:48 -0700 Subject: mac_pton: Use bool not int return Use bool instead of int as the return type. All uses are tested with !. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- include/linux/kernel.h | 2 +- lib/net_utils.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 4c52907a6d8b..a9e2268ecccb 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -501,7 +501,7 @@ static inline char * __deprecated pack_hex_byte(char *buf, u8 byte) extern int hex_to_bin(char ch); extern int __must_check hex2bin(u8 *dst, const char *src, size_t count); -int mac_pton(const char *s, u8 *mac); +bool mac_pton(const char *s, u8 *mac); /* * General tracing related utility functions - trace_printk(), diff --git a/lib/net_utils.c b/lib/net_utils.c index 2e3c52c8d050..148fc6e99ef6 100644 --- a/lib/net_utils.c +++ b/lib/net_utils.c @@ -3,24 +3,24 @@ #include #include -int mac_pton(const char *s, u8 *mac) +bool mac_pton(const char *s, u8 *mac) { int i; /* XX:XX:XX:XX:XX:XX */ if (strlen(s) < 3 * ETH_ALEN - 1) - return 0; + return false; /* Don't dirty result unless string is valid MAC. */ for (i = 0; i < ETH_ALEN; i++) { if (!isxdigit(s[i * 3]) || !isxdigit(s[i * 3 + 1])) - return 0; + return false; if (i != ETH_ALEN - 1 && s[i * 3 + 2] != ':') - return 0; + return false; } for (i = 0; i < ETH_ALEN; i++) { mac[i] = (hex_to_bin(s[i * 3]) << 4) | hex_to_bin(s[i * 3 + 1]); } - return 1; + return true; } EXPORT_SYMBOL(mac_pton); -- cgit v1.2.3 From a6eacef7fba7834da4d22762ea0d8524df3993a8 Mon Sep 17 00:00:00 2001 From: Erik Hugne Date: Wed, 25 Jun 2014 10:07:05 +0200 Subject: tipc: bump max configurable window size The maximum window size is limited by the sequence gap field, which was expanded with bd7845337b105e090dd18912d511139945fa7586 ("tipc: Expand link sequence gap field to 13 bits") We remove the artificial limit that prevents the link window to be set larger than 150. Signed-off-by: Erik Hugne Reviewed-by: Jon Maloy Signed-off-by: David S. Miller --- include/uapi/linux/tipc_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/tipc_config.h b/include/uapi/linux/tipc_config.h index 41a76acbb305..876d0a14863c 100644 --- a/include/uapi/linux/tipc_config.h +++ b/include/uapi/linux/tipc_config.h @@ -182,7 +182,7 @@ #define TIPC_MIN_LINK_WIN 16 #define TIPC_DEF_LINK_WIN 50 -#define TIPC_MAX_LINK_WIN 150 +#define TIPC_MAX_LINK_WIN 8191 struct tipc_node_info { -- cgit v1.2.3 From 644a918d20336a7deaa81f675c3c2f25bf3dafbb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 25 Jun 2014 10:31:09 +0200 Subject: enic: Make dummy rfs functions inline to fix !CONFIG_RFS_ACCEL build If CONFIG_RFS_ACCEL=n: drivers/net/ethernet/cisco/enic/enic_main.c: In function 'enic_open': drivers/net/ethernet/cisco/enic/enic_main.c:1603:2: error: implicit declaration of function 'enic_rfs_flw_tbl_init' [-Werror=implicit-function-declaration] drivers/net/ethernet/cisco/enic/enic_main.c: In function 'enic_stop': drivers/net/ethernet/cisco/enic/enic_main.c:1630:2: error: implicit declaration of function 'enic_rfs_flw_tbl_free' [-Werror=implicit-function-declaration] Introduced in commit a145df23ef32c7b933875f334ba28791ee75766e ("enic: Add Accelerated RFS support"). Dummy functions are provided, but their prototypes are missing, causing the build failure. Provide dummy static inline functions instead to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_clsf.c | 10 ---------- drivers/net/ethernet/cisco/enic/enic_clsf.h | 3 +++ 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index c2322adfccdc..bc451baac4cd 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -266,14 +266,4 @@ ret_unlock: return res; } -#else - -void enic_rfs_flw_tbl_init(struct enic *enic) -{ -} - -void enic_rfs_flw_tbl_free(struct enic *enic) -{ -} - #endif /* CONFIG_RFS_ACCEL */ diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.h b/drivers/net/ethernet/cisco/enic/enic_clsf.h index 76a85bb0bb73..d572704cd117 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.h +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.h @@ -14,6 +14,9 @@ void enic_rfs_flw_tbl_init(struct enic *enic); void enic_rfs_flw_tbl_free(struct enic *enic); int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, u16 rxq_index, u32 flow_id); +#else +static inline void enic_rfs_flw_tbl_init(struct enic *enic) {} +static inline void enic_rfs_flw_tbl_free(struct enic *enic) {} #endif /* CONFIG_RFS_ACCEL */ #endif /* _ENIC_CLSF_H_ */ -- cgit v1.2.3 From e59d82fd33f7670cf67fd69cf684aa589ec8340a Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Fri, 9 May 2014 23:43:41 +0200 Subject: vti6: Simplify error handling in module init and exit The error handling in the module init and exit functions can be shortened to safe us some code. 1/ Remove the code duplications in the init function, jump straight to the existing cleanup code by adding some labels. Also give the error message some more value by telling the reason why loading the module has failed. 2/ Remove the error handling in the exit function as the only legitimate reason xfrm6_protocol_deregister() might fail is inet6_del_protocol() returning -1. That, in turn, means some other protocol handler had been registered for this very protocol in the meantime. But that essentially means we haven't been handling that protocol any more, anyway. What it definitely means not is that we "can't deregister protocol". Therefore just get rid of that bogus warning. It's plain wrong. Signed-off-by: Mathias Krause Signed-off-by: Steffen Klassert --- net/ipv6/ip6_vti.c | 51 ++++++++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 9aaa6bb229e4..b61b0b1bb7ce 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -1089,36 +1089,26 @@ static struct xfrm6_protocol vti_ipcomp6_protocol __read_mostly = { **/ static int __init vti6_tunnel_init(void) { - int err; + const char *msg; + int err; + msg = "tunnel device"; err = register_pernet_device(&vti6_net_ops); if (err < 0) - goto out_pernet; + goto pernet_dev_failed; + msg = "tunnel protocols"; err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP); - if (err < 0) { - pr_err("%s: can't register vti6 protocol\n", __func__); - - goto out; - } - + if (err < 0) + goto xfrm_proto_esp_failed; err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH); - if (err < 0) { - xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); - pr_err("%s: can't register vti6 protocol\n", __func__); - - goto out; - } - + if (err < 0) + goto xfrm_proto_ah_failed; err = xfrm6_protocol_register(&vti_ipcomp6_protocol, IPPROTO_COMP); - if (err < 0) { - xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); - xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); - pr_err("%s: can't register vti6 protocol\n", __func__); - - goto out; - } + if (err < 0) + goto xfrm_proto_comp_failed; + msg = "netlink interface"; err = rtnl_link_register(&vti6_link_ops); if (err < 0) goto rtnl_link_failed; @@ -1127,11 +1117,14 @@ static int __init vti6_tunnel_init(void) rtnl_link_failed: xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP); +xfrm_proto_comp_failed: xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); +xfrm_proto_ah_failed: xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); -out: +xfrm_proto_esp_failed: unregister_pernet_device(&vti6_net_ops); -out_pernet: +pernet_dev_failed: + pr_err("vti6 init: failed to register %s\n", msg); return err; } @@ -1141,13 +1134,9 @@ out_pernet: static void __exit vti6_tunnel_cleanup(void) { rtnl_link_unregister(&vti6_link_ops); - if (xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP)) - pr_info("%s: can't deregister protocol\n", __func__); - if (xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH)) - pr_info("%s: can't deregister protocol\n", __func__); - if (xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP)) - pr_info("%s: can't deregister protocol\n", __func__); - + xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP); + xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); + xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); unregister_pernet_device(&vti6_net_ops); } -- cgit v1.2.3 From 1990e4f883a6383b04ef37f32bdaa02dc0dbae8d Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Fri, 9 May 2014 23:43:42 +0200 Subject: vti: Simplify error handling in module init and exit The error handling in the module init and exit functions can be shortened to safe us some code. 1/ Remove the code duplications in the init function, jump straight to the existing cleanup code by adding some labels. Also give the error message some more value by telling the reason why loading the module has failed. Furthermore fix the "IPSec" typo -- it should be "IPsec" instead. 2/ Remove the error handling in the exit function as the only legitimate reason xfrm4_protocol_deregister() might fail is inet_del_protocol() returning -1. That, in turn, means some other protocol handler had been registered for this very protocol in the meantime. But that essentially means we haven't been handling that protocol any more, anyway. What it definitely means not is that we "can't deregister tunnel". Therefore just get rid of that bogus warning. It's plain wrong. Signed-off-by: Mathias Krause Signed-off-by: Steffen Klassert --- net/ipv4/ip_vti.c | 54 +++++++++++++++++++++--------------------------------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index b8960f3527f3..e453cb724a95 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -534,40 +534,28 @@ static struct rtnl_link_ops vti_link_ops __read_mostly = { static int __init vti_init(void) { + const char *msg; int err; - pr_info("IPv4 over IPSec tunneling driver\n"); + pr_info("IPv4 over IPsec tunneling driver\n"); + msg = "tunnel device"; err = register_pernet_device(&vti_net_ops); if (err < 0) - return err; - err = xfrm4_protocol_register(&vti_esp4_protocol, IPPROTO_ESP); - if (err < 0) { - unregister_pernet_device(&vti_net_ops); - pr_info("vti init: can't register tunnel\n"); - - return err; - } + goto pernet_dev_failed; + msg = "tunnel protocols"; + err = xfrm4_protocol_register(&vti_esp4_protocol, IPPROTO_ESP); + if (err < 0) + goto xfrm_proto_esp_failed; err = xfrm4_protocol_register(&vti_ah4_protocol, IPPROTO_AH); - if (err < 0) { - xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP); - unregister_pernet_device(&vti_net_ops); - pr_info("vti init: can't register tunnel\n"); - - return err; - } - + if (err < 0) + goto xfrm_proto_ah_failed; err = xfrm4_protocol_register(&vti_ipcomp4_protocol, IPPROTO_COMP); - if (err < 0) { - xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); - xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP); - unregister_pernet_device(&vti_net_ops); - pr_info("vti init: can't register tunnel\n"); - - return err; - } + if (err < 0) + goto xfrm_proto_comp_failed; + msg = "netlink interface"; err = rtnl_link_register(&vti_link_ops); if (err < 0) goto rtnl_link_failed; @@ -576,23 +564,23 @@ static int __init vti_init(void) rtnl_link_failed: xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP); +xfrm_proto_comp_failed: xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); +xfrm_proto_ah_failed: xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP); +xfrm_proto_esp_failed: unregister_pernet_device(&vti_net_ops); +pernet_dev_failed: + pr_err("vti init: failed to register %s\n", msg); return err; } static void __exit vti_fini(void) { rtnl_link_unregister(&vti_link_ops); - if (xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP)) - pr_info("vti close: can't deregister tunnel\n"); - if (xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH)) - pr_info("vti close: can't deregister tunnel\n"); - if (xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP)) - pr_info("vti close: can't deregister tunnel\n"); - - + xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP); + xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); + xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP); unregister_pernet_device(&vti_net_ops); } -- cgit v1.2.3 From 7a208e83fcedc0b845facc17d05ead0b9b73a967 Mon Sep 17 00:00:00 2001 From: Kamil Krawczyk Date: Wed, 4 Jun 2014 04:22:36 +0000 Subject: i40e: do not take NVM ownership for SR read We do not need to acquire NVM for Shadow RAM XSUM calculation, as we only read from SR through SRCTL register for which having the ownership is not required. Change-ID: Ie238a8f09917d1d25f24cc7cec271951ac7b98f2 Signed-off-by: Kamil Krawczyk Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_nvm.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index 81299189a47d..66bcb15422da 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c @@ -324,13 +324,9 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, u16 checksum_sr = 0; u16 checksum_local = 0; - ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); - if (ret_code) - goto i40e_validate_nvm_checksum_exit; - ret_code = i40e_calc_nvm_checksum(hw, &checksum_local); if (ret_code) - goto i40e_validate_nvm_checksum_free; + goto i40e_validate_nvm_checksum_exit; /* Do not use i40e_read_nvm_word() because we do not want to take * the synchronization semaphores twice here. @@ -347,9 +343,6 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, if (checksum) *checksum = checksum_local; -i40e_validate_nvm_checksum_free: - i40e_release_nvm(hw); - i40e_validate_nvm_checksum_exit: return ret_code; } -- cgit v1.2.3 From 3ba3faeb62220411284551a6443395ce7960b17d Mon Sep 17 00:00:00 2001 From: Paul M Stillwell Jr Date: Wed, 4 Jun 2014 05:35:54 +0000 Subject: i40e/i40evf: Big endian fixes for handling HMC Fix HMC handling for big endian architectures. Change-ID: Id8c46fc341815d47bfe0af8b819f0ab9a1e9e515 Signed-off-by: Paul M Stillwell Jr Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c | 247 ++++++++++++++++++----- drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h | 28 ++- drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h | 28 ++- 3 files changed, 236 insertions(+), 67 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c index 870ab1ee072c..5a603a5e9aa8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c @@ -746,6 +746,194 @@ static struct i40e_context_ele i40e_hmc_rxq_ce_info[] = { { 0 } }; +/** + * i40e_write_byte - replace HMC context byte + * @hmc_bits: pointer to the HMC memory + * @ce_info: a description of the struct to be read from + * @src: the struct to be read from + **/ +static void i40e_write_byte(u8 *hmc_bits, + struct i40e_context_ele *ce_info, + u8 *src) +{ + u8 src_byte, dest_byte, mask; + u8 *from, *dest; + u16 shift_width; + + /* copy from the next struct field */ + from = src + ce_info->offset; + + /* prepare the bits and mask */ + shift_width = ce_info->lsb % 8; + mask = ((u8)1 << ce_info->width) - 1; + + src_byte = *from; + src_byte &= mask; + + /* shift to correct alignment */ + mask <<= shift_width; + src_byte <<= shift_width; + + /* get the current bits from the target bit string */ + dest = hmc_bits + (ce_info->lsb / 8); + + memcpy(&dest_byte, dest, sizeof(dest_byte)); + + dest_byte &= ~mask; /* get the bits not changing */ + dest_byte |= src_byte; /* add in the new bits */ + + /* put it all back */ + memcpy(dest, &dest_byte, sizeof(dest_byte)); +} + +/** + * i40e_write_word - replace HMC context word + * @hmc_bits: pointer to the HMC memory + * @ce_info: a description of the struct to be read from + * @src: the struct to be read from + **/ +static void i40e_write_word(u8 *hmc_bits, + struct i40e_context_ele *ce_info, + u8 *src) +{ + u16 src_word, mask; + u8 *from, *dest; + u16 shift_width; + __le16 dest_word; + + /* copy from the next struct field */ + from = src + ce_info->offset; + + /* prepare the bits and mask */ + shift_width = ce_info->lsb % 8; + mask = ((u16)1 << ce_info->width) - 1; + + /* don't swizzle the bits until after the mask because the mask bits + * will be in a different bit position on big endian machines + */ + src_word = *(u16 *)from; + src_word &= mask; + + /* shift to correct alignment */ + mask <<= shift_width; + src_word <<= shift_width; + + /* get the current bits from the target bit string */ + dest = hmc_bits + (ce_info->lsb / 8); + + memcpy(&dest_word, dest, sizeof(dest_word)); + + dest_word &= ~(cpu_to_le16(mask)); /* get the bits not changing */ + dest_word |= cpu_to_le16(src_word); /* add in the new bits */ + + /* put it all back */ + memcpy(dest, &dest_word, sizeof(dest_word)); +} + +/** + * i40e_write_dword - replace HMC context dword + * @hmc_bits: pointer to the HMC memory + * @ce_info: a description of the struct to be read from + * @src: the struct to be read from + **/ +static void i40e_write_dword(u8 *hmc_bits, + struct i40e_context_ele *ce_info, + u8 *src) +{ + u32 src_dword, mask; + u8 *from, *dest; + u16 shift_width; + __le32 dest_dword; + + /* copy from the next struct field */ + from = src + ce_info->offset; + + /* prepare the bits and mask */ + shift_width = ce_info->lsb % 8; + + /* if the field width is exactly 32 on an x86 machine, then the shift + * operation will not work because the SHL instructions count is masked + * to 5 bits so the shift will do nothing + */ + if (ce_info->width < 32) + mask = ((u32)1 << ce_info->width) - 1; + else + mask = -1; + + /* don't swizzle the bits until after the mask because the mask bits + * will be in a different bit position on big endian machines + */ + src_dword = *(u32 *)from; + src_dword &= mask; + + /* shift to correct alignment */ + mask <<= shift_width; + src_dword <<= shift_width; + + /* get the current bits from the target bit string */ + dest = hmc_bits + (ce_info->lsb / 8); + + memcpy(&dest_dword, dest, sizeof(dest_dword)); + + dest_dword &= ~(cpu_to_le32(mask)); /* get the bits not changing */ + dest_dword |= cpu_to_le32(src_dword); /* add in the new bits */ + + /* put it all back */ + memcpy(dest, &dest_dword, sizeof(dest_dword)); +} + +/** + * i40e_write_qword - replace HMC context qword + * @hmc_bits: pointer to the HMC memory + * @ce_info: a description of the struct to be read from + * @src: the struct to be read from + **/ +static void i40e_write_qword(u8 *hmc_bits, + struct i40e_context_ele *ce_info, + u8 *src) +{ + u64 src_qword, mask; + u8 *from, *dest; + u16 shift_width; + __le64 dest_qword; + + /* copy from the next struct field */ + from = src + ce_info->offset; + + /* prepare the bits and mask */ + shift_width = ce_info->lsb % 8; + + /* if the field width is exactly 64 on an x86 machine, then the shift + * operation will not work because the SHL instructions count is masked + * to 6 bits so the shift will do nothing + */ + if (ce_info->width < 64) + mask = ((u64)1 << ce_info->width) - 1; + else + mask = -1; + + /* don't swizzle the bits until after the mask because the mask bits + * will be in a different bit position on big endian machines + */ + src_qword = *(u64 *)from; + src_qword &= mask; + + /* shift to correct alignment */ + mask <<= shift_width; + src_qword <<= shift_width; + + /* get the current bits from the target bit string */ + dest = hmc_bits + (ce_info->lsb / 8); + + memcpy(&dest_qword, dest, sizeof(dest_qword)); + + dest_qword &= ~(cpu_to_le64(mask)); /* get the bits not changing */ + dest_qword |= cpu_to_le64(src_qword); /* add in the new bits */ + + /* put it all back */ + memcpy(dest, &dest_qword, sizeof(dest_qword)); +} + /** * i40e_clear_hmc_context - zero out the HMC context bits * @hw: the hardware struct @@ -772,71 +960,28 @@ static i40e_status i40e_set_hmc_context(u8 *context_bytes, struct i40e_context_ele *ce_info, u8 *dest) { - u16 shift_width; - u64 bitfield; - u8 hi_byte; - u8 hi_mask; - u64 t_bits; - u64 mask; - u8 *p; int f; for (f = 0; ce_info[f].width != 0; f++) { - /* clear out the field */ - bitfield = 0; - /* copy from the next struct field */ - p = dest + ce_info[f].offset; + /* we have to deal with each element of the HMC using the + * correct size so that we are correct regardless of the + * endianness of the machine + */ switch (ce_info[f].size_of) { case 1: - bitfield = *p; + i40e_write_byte(context_bytes, &ce_info[f], dest); break; case 2: - bitfield = cpu_to_le16(*(u16 *)p); + i40e_write_word(context_bytes, &ce_info[f], dest); break; case 4: - bitfield = cpu_to_le32(*(u32 *)p); + i40e_write_dword(context_bytes, &ce_info[f], dest); break; case 8: - bitfield = cpu_to_le64(*(u64 *)p); + i40e_write_qword(context_bytes, &ce_info[f], dest); break; } - - /* prepare the bits and mask */ - shift_width = ce_info[f].lsb % 8; - mask = ((u64)1 << ce_info[f].width) - 1; - - /* save upper bytes for special case */ - hi_mask = (u8)((mask >> 56) & 0xff); - hi_byte = (u8)((bitfield >> 56) & 0xff); - - /* shift to correct alignment */ - mask <<= shift_width; - bitfield <<= shift_width; - - /* get the current bits from the target bit string */ - p = context_bytes + (ce_info[f].lsb / 8); - memcpy(&t_bits, p, sizeof(u64)); - - t_bits &= ~mask; /* get the bits not changing */ - t_bits |= bitfield; /* add in the new bits */ - - /* put it all back */ - memcpy(p, &t_bits, sizeof(u64)); - - /* deal with the special case if needed - * example: 62 bit field that starts in bit 5 of first byte - * will overlap 3 bits into byte 9 - */ - if ((shift_width + ce_info[f].width) > 64) { - u8 byte; - - hi_mask >>= (8 - shift_width); - hi_byte >>= (8 - shift_width); - byte = p[8] & ~hi_mask; /* get the bits not changing */ - byte |= hi_byte; /* add in the new bits */ - p[8] = byte; /* put it back */ - } } return 0; diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h index eb65fe23c4a7..e74128db5be5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h @@ -32,16 +32,22 @@ struct i40e_hw; /* HMC element context information */ -/* Rx queue context data */ +/* Rx queue context data + * + * The sizes of the variables may be larger than needed due to crossing byte + * boundaries. If we do not have the width of the variable set to the correct + * size then we could end up shifting bits off the top of the variable when the + * variable is at the top of a byte and crosses over into the next byte. + */ struct i40e_hmc_obj_rxq { u16 head; - u8 cpuid; + u16 cpuid; /* bigger than needed, see above for reason */ u64 base; u16 qlen; #define I40E_RXQ_CTX_DBUFF_SHIFT 7 - u8 dbuff; + u16 dbuff; /* bigger than needed, see above for reason */ #define I40E_RXQ_CTX_HBUFF_SHIFT 6 - u8 hbuff; + u16 hbuff; /* bigger than needed, see above for reason */ u8 dtype; u8 dsize; u8 crcstrip; @@ -50,16 +56,22 @@ struct i40e_hmc_obj_rxq { u8 hsplit_0; u8 hsplit_1; u8 showiv; - u16 rxmax; + u32 rxmax; /* bigger than needed, see above for reason */ u8 tphrdesc_ena; u8 tphwdesc_ena; u8 tphdata_ena; u8 tphhead_ena; - u8 lrxqthresh; + u16 lrxqthresh; /* bigger than needed, see above for reason */ u8 prefena; /* NOTE: normally must be set to 1 at init */ }; -/* Tx queue context data */ +/* Tx queue context data +* +* The sizes of the variables may be larger than needed due to crossing byte +* boundaries. If we do not have the width of the variable set to the correct +* size then we could end up shifting bits off the top of the variable when the +* variable is at the top of a byte and crosses over into the next byte. +*/ struct i40e_hmc_obj_txq { u16 head; u8 new_context; @@ -69,7 +81,7 @@ struct i40e_hmc_obj_txq { u8 fd_ena; u8 alt_vlan_ena; u16 thead_wb; - u16 cpuid; + u8 cpuid; u8 head_wb_ena; u16 qlen; u8 tphrdesc_ena; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h index d6f762241537..a5d79877354c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h @@ -32,16 +32,22 @@ struct i40e_hw; /* HMC element context information */ -/* Rx queue context data */ +/* Rx queue context data + * + * The sizes of the variables may be larger than needed due to crossing byte + * boundaries. If we do not have the width of the variable set to the correct + * size then we could end up shifting bits off the top of the variable when the + * variable is at the top of a byte and crosses over into the next byte. + */ struct i40e_hmc_obj_rxq { u16 head; - u8 cpuid; + u16 cpuid; /* bigger than needed, see above for reason */ u64 base; u16 qlen; #define I40E_RXQ_CTX_DBUFF_SHIFT 7 - u8 dbuff; + u16 dbuff; /* bigger than needed, see above for reason */ #define I40E_RXQ_CTX_HBUFF_SHIFT 6 - u8 hbuff; + u16 hbuff; /* bigger than needed, see above for reason */ u8 dtype; u8 dsize; u8 crcstrip; @@ -50,16 +56,22 @@ struct i40e_hmc_obj_rxq { u8 hsplit_0; u8 hsplit_1; u8 showiv; - u16 rxmax; + u32 rxmax; /* bigger than needed, see above for reason */ u8 tphrdesc_ena; u8 tphwdesc_ena; u8 tphdata_ena; u8 tphhead_ena; - u8 lrxqthresh; + u16 lrxqthresh; /* bigger than needed, see above for reason */ u8 prefena; /* NOTE: normally must be set to 1 at init */ }; -/* Tx queue context data */ +/* Tx queue context data +* +* The sizes of the variables may be larger than needed due to crossing byte +* boundaries. If we do not have the width of the variable set to the correct +* size then we could end up shifting bits off the top of the variable when the +* variable is at the top of a byte and crosses over into the next byte. +*/ struct i40e_hmc_obj_txq { u16 head; u8 new_context; @@ -69,7 +81,7 @@ struct i40e_hmc_obj_txq { u8 fd_ena; u8 alt_vlan_ena; u16 thead_wb; - u16 cpuid; + u8 cpuid; u8 head_wb_ena; u16 qlen; u8 tphrdesc_ena; -- cgit v1.2.3 From e5d17c3ed2cf0485c6b85d783e1d20a8cfad93c1 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 4 Jun 2014 04:22:38 +0000 Subject: i40evf: don't stop watchdog if it hasn't started If the VF driver fails to complete early init, then rmmod can cause a softlock when the driver tries to stop a watchdog timer that never even got initialized. Add a check to see if the timer is actually initialized before stopping it. Change-ID: Id9d550aa8838e07f4b02afe7bc017ef983779efc Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index b473172708f5..36b1ad76a8bf 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2408,7 +2408,9 @@ static void i40evf_remove(struct pci_dev *pdev) i40evf_reset_interrupt_capability(adapter); } - del_timer_sync(&adapter->watchdog_timer); + if (adapter->watchdog_timer.function) + del_timer_sync(&adapter->watchdog_timer); + flush_scheduled_work(); if (hw->aq.asq.count) -- cgit v1.2.3 From 6a8e93db98e36b5b3b8c10b9adae073d6bd1062a Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 5 Jun 2014 00:09:17 +0000 Subject: i40evf: return more useful error information When verifying the API version (which is the first time the driver communicates with the firmware and thus the PF driver), there are many ways in which a failure can occur. There may be an error from the firmware, there may be unresponsive firmware, there may be an error from the PF driver, etc, etc. Make this function return more useful information, instead of just -EIO. Propagate FW errors back to the caller, and log a message if the PF sends an invalid reply. Change-ID: I3e9135a2b80f7acdb855f62f12b2b2668c9a8951 Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 2dc0bac76717..0ed2ad7e4eee 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -80,8 +80,9 @@ int i40evf_send_api_ver(struct i40evf_adapter *adapter) * @adapter: adapter structure * * Compare API versions with the PF. Must be called after admin queue is - * initialized. Returns 0 if API versions match, -EIO if - * they do not, or I40E_ERR_ADMIN_QUEUE_NO_WORK if the admin queue is empty. + * initialized. Returns 0 if API versions match, -EIO if they do not, + * I40E_ERR_ADMIN_QUEUE_NO_WORK if the admin queue is empty, and any errors + * from the firmware are propagated. **/ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) { @@ -102,13 +103,13 @@ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) goto out_alloc; err = (i40e_status)le32_to_cpu(event.desc.cookie_low); - if (err) { - err = -EIO; + if (err) goto out_alloc; - } if ((enum i40e_virtchnl_ops)le32_to_cpu(event.desc.cookie_high) != I40E_VIRTCHNL_OP_VERSION) { + dev_info(&adapter->pdev->dev, "Invalid reply type %d from PF\n", + le32_to_cpu(event.desc.cookie_high)); err = -EIO; goto out_alloc; } -- cgit v1.2.3 From 3f2ab1721f77935eb4ee50b78c6ecfe24b3a2648 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 4 Jun 2014 04:22:40 +0000 Subject: i40evf: fix typo Correct a missing word in a log message. Change-ID: Id94da7d9f842382d073b3947e0b616503e2f8e91 Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 36b1ad76a8bf..7138ab483625 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2022,7 +2022,7 @@ static void i40evf_init_task(struct work_struct *work) } err = i40evf_send_vf_config_msg(adapter); if (err) { - dev_err(&pdev->dev, "Unable send config request (%d)\n", + dev_err(&pdev->dev, "Unable to send config request (%d)\n", err); goto err; } -- cgit v1.2.3 From 56f9920a952130a7cd20952b3525bc238a87e489 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 4 Jun 2014 04:22:41 +0000 Subject: i40evf: resend FW request if no response Sometimes the firmware will not indicate an error but fail to pass a message between the VF and the PF driver. If this happens, just resend the request. This fixes an initialization failure if many VFs are instantiated at the same time and the VF module is autoloaded. Change-ID: Idd1ad8da2fd5137859244685c355941427d317d7 Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 7138ab483625..8082a9fa5d10 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2018,6 +2018,10 @@ static void i40evf_init_task(struct work_struct *work) if (err) { dev_info(&pdev->dev, "Unable to verify API version (%d), retrying\n", err); + if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) { + dev_info(&pdev->dev, "Resending request\n"); + err = i40evf_send_api_ver(adapter); + } goto err; } err = i40evf_send_vf_config_msg(adapter); -- cgit v1.2.3 From 69d1a70c3f0046d06f5520a230eee9a829ee6689 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 4 Jun 2014 04:22:42 +0000 Subject: i40e: rename i40e_ptp_enable to i40e_ptp_feature_enable Reduces possible confusion and ambiguity in purpose of the ancillary feature control entry point function. Change-ID: I21d773c1a86878f6d061505185b596c788d1b7cc Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 101f439acda6..6f7d73b6affb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -216,7 +216,7 @@ static int i40e_ptp_settime(struct ptp_clock_info *ptp, } /** - * i40e_ptp_enable - Enable/disable ancillary features of the PHC subsystem + * i40e_ptp_feature_enable - Enable/disable ancillary features of the PHC subsystem * @ptp: The PTP clock structure * @rq: The requested feature to change * @on: Enable/disable flag @@ -224,8 +224,8 @@ static int i40e_ptp_settime(struct ptp_clock_info *ptp, * The XL710 does not support any of the ancillary features of the PHC * subsystem, so this function may just return. **/ -static int i40e_ptp_enable(struct ptp_clock_info *ptp, - struct ptp_clock_request *rq, int on) +static int i40e_ptp_feature_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) { return -EOPNOTSUPP; } @@ -560,7 +560,7 @@ void i40e_ptp_init(struct i40e_pf *pf) pf->ptp_caps.adjtime = i40e_ptp_adjtime; pf->ptp_caps.gettime = i40e_ptp_gettime; pf->ptp_caps.settime = i40e_ptp_settime; - pf->ptp_caps.enable = i40e_ptp_enable; + pf->ptp_caps.enable = i40e_ptp_feature_enable; /* Attempt to register the clock before enabling the hardware. */ pf->ptp_clock = ptp_clock_register(&pf->ptp_caps, &pf->pdev->dev); -- cgit v1.2.3 From 189464555a4aef4db07f90294bd3723079f7c19a Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 4 Jun 2014 06:08:29 +0000 Subject: i40e: break PTP hardware control from ioctl command for timestamp mode This patch facilitates future work by breaking the PTP hardware control bits out of the i40e_set_ts_config function. By doing this, we can maintain state about the 1588 timestamping mode and properly re-enable to the last known mode during a re-initialize of 1588 bits. This patch also modifies i40e_ptp_init to call the i40e_ptp_set_timestamp_mode during the reconfiguration process. A future patch will ensure that the hwtstamp_config structure is not reset during this process, so that timestamp mode will be maintained across a reset. Change-ID: Ic20832c96c5c512ac203b6c7534e10d891c560f0 Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 59 ++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 6f7d73b6affb..e5f558c9d7d0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -423,28 +423,23 @@ int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr) } /** - * i40e_ptp_set_ts_config - ioctl interface to control the HW timestamping + * i40e_ptp_set_timestamp_mode - setup hardware for requested timestamp mode * @pf: Board private structure - * @ifreq: ioctl data + * @config: hwtstamp settings requested or saved * - * Respond to the user filter requests and make the appropriate hardware - * changes here. The XL710 cannot support splitting of the Tx/Rx timestamping - * logic, so keep track in software of whether to indicate these timestamps - * or not. + * Control hardware registers to enter the specific mode requested by the + * user. Also used during reset path to ensure that timestamp settings are + * maintained. * - * It is permissible to "upgrade" the user request to a broader filter, as long - * as the user receives the timestamps they care about and the user is notified - * the filter has been broadened. + * Note: modifies config in place, and may update the requested mode to be + * more broad if the specific filter is not directly supported. **/ -int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr) +static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, + struct hwtstamp_config *config) { struct i40e_hw *hw = &pf->hw; - struct hwtstamp_config *config = &pf->tstamp_config; u32 pf_id, tsyntype, regval; - if (copy_from_user(config, ifr->ifr_data, sizeof(*config))) - return -EFAULT; - /* Reserved for future extensions. */ if (config->flags) return -EINVAL; @@ -535,6 +530,35 @@ int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr) wr32(hw, I40E_PRTTSYN_CTL1, regval); } + return 0; +} + +/** + * i40e_ptp_set_ts_config - ioctl interface to control the HW timestamping + * @pf: Board private structure + * @ifreq: ioctl data + * + * Respond to the user filter requests and make the appropriate hardware + * changes here. The XL710 cannot support splitting of the Tx/Rx timestamping + * logic, so keep track in software of whether to indicate these timestamps + * or not. + * + * It is permissible to "upgrade" the user request to a broader filter, as long + * as the user receives the timestamps they care about and the user is notified + * the filter has been broadened. + **/ +int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr) +{ + struct hwtstamp_config *config = &pf->tstamp_config; + int err; + + if (copy_from_user(config, ifr->ifr_data, sizeof(*config))) + return -EFAULT; + + err = i40e_ptp_set_timestamp_mode(pf, config); + if (err) + return err; + return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? -EFAULT : 0; } @@ -578,6 +602,9 @@ void i40e_ptp_init(struct i40e_pf *pf) netdev->name); pf->flags |= I40E_FLAG_PTP; + pf->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; + pf->tstamp_config.tx_type = HWTSTAMP_TX_OFF; + /* Ensure the clocks are running. */ regval = rd32(hw, I40E_PRTTSYN_CTL0); regval |= I40E_PRTTSYN_CTL0_TSYNENA_MASK; @@ -589,8 +616,8 @@ void i40e_ptp_init(struct i40e_pf *pf) /* Set the increment value per clock tick. */ i40e_ptp_set_increment(pf); - /* reset the tstamp_config */ - memset(&pf->tstamp_config, 0, sizeof(pf->tstamp_config)); + /* reset timestamping mode */ + i40e_ptp_set_timestamp_mode(pf, &pf->tstamp_config); /* Set the clock value. */ ts = ktime_to_timespec(ktime_get_real()); -- cgit v1.2.3 From d19af2afe70c11c17552e3290560037a8812f467 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 4 Jun 2014 04:22:44 +0000 Subject: i40e: don't store user requested mode until we've validated it This patch prevents the SIOCGHWTSTAMP ioctl from possibly returning bad data, by not permanently storing the setting into the private structure until after we've finished validating that we can support it. Change-ID: Ib59f9b4f73f451d5a2e76fb8efa5d4271b218433 Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index e5f558c9d7d0..f7dded9976e9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -549,17 +549,20 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, **/ int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr) { - struct hwtstamp_config *config = &pf->tstamp_config; + struct hwtstamp_config config; int err; - if (copy_from_user(config, ifr->ifr_data, sizeof(*config))) + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) return -EFAULT; - err = i40e_ptp_set_timestamp_mode(pf, config); + err = i40e_ptp_set_timestamp_mode(pf, &config); if (err) return err; - return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? + /* save these settings for future reference */ + pf->tstamp_config = config; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; } -- cgit v1.2.3 From fbd5e2df9f9e65439f41953455e3eb5b9aab3685 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 4 Jun 2014 04:22:45 +0000 Subject: i40e: only create PTP device node once Currently every time we run through the i40e_ptp_init routine, we create a new device node. This function is called by i40e_reset_and_rebuild which is used to handle reset of the device. Even though the 1588 registers only get cleared on a GLOBAL reset, this function is still called to handle a CORE reset. This causes a leak of PTP device nodes at every reset. To fix this, break PTP device clock node creation out of i40e_ptp_init, and only call this if we don't already have a device created. Further invocation of i40e_ptp_init will not generate new PTP devices. Instead, only the necessary work required to reconfigure 1588 will be done. This change also fixes an issue where a reset can cause the device to forget it's timestamp configuration, and revert to the default mode. Change-ID: I741d01c61d9fe1d24887859d1316e1a8a892909e Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 58 +++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index f7dded9976e9..0c935e8f3a6c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -567,18 +567,22 @@ int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr) } /** - * i40e_ptp_init - Initialize the 1588 support and register the PHC + * i40e_ptp_create_clock - Create PTP clock device for userspace * @pf: Board private structure * - * This function registers the device clock as a PHC. If it is successful, it - * starts the clock in the hardware. + * This function creates a new PTP clock device. It only creates one if we + * don't already have one, so it is safe to call. Will return error if it + * can't create one, but success if we already have a device. Should be used + * by i40e_ptp_init to create clock initially, and prevent global resets from + * creating new clock devices. **/ -void i40e_ptp_init(struct i40e_pf *pf) +static long i40e_ptp_create_clock(struct i40e_pf *pf) { - struct i40e_hw *hw = &pf->hw; - struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev; + /* no need to create a clock device if we already have one */ + if (!IS_ERR_OR_NULL(pf->ptp_clock)) + return 0; - strncpy(pf->ptp_caps.name, "i40e", sizeof(pf->ptp_caps.name)); + strncpy(pf->ptp_caps.name, i40e_driver_name, sizeof(pf->ptp_caps.name)); pf->ptp_caps.owner = THIS_MODULE; pf->ptp_caps.max_adj = 999999999; pf->ptp_caps.n_ext_ts = 0; @@ -592,6 +596,41 @@ void i40e_ptp_init(struct i40e_pf *pf) /* Attempt to register the clock before enabling the hardware. */ pf->ptp_clock = ptp_clock_register(&pf->ptp_caps, &pf->pdev->dev); if (IS_ERR(pf->ptp_clock)) { + return PTR_ERR(pf->ptp_clock); + } + + /* clear the hwtstamp settings here during clock create, instead of + * during regular init, so that we can maintain settings across a + * reset or suspend. + */ + pf->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; + pf->tstamp_config.tx_type = HWTSTAMP_TX_OFF; + + return 0; +} + +/** + * i40e_ptp_init - Initialize the 1588 support after device probe or reset + * @pf: Board private structure + * + * This function sets device up for 1588 support. The first time it is run, it + * will create a PHC clock device. It does not create a clock device if one + * already exists. It also reconfigures the device after a reset. + **/ +void i40e_ptp_init(struct i40e_pf *pf) +{ + struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev; + struct i40e_hw *hw = &pf->hw; + long err; + + /* we have to initialize the lock first, since we can't control + * when the user will enter the PHC device entry points + */ + spin_lock_init(&pf->tmreg_lock); + + /* ensure we have a clock device */ + err = i40e_ptp_create_clock(pf); + if (err) { pf->ptp_clock = NULL; dev_err(&pf->pdev->dev, "%s: ptp_clock_register failed\n", __func__); @@ -599,15 +638,10 @@ void i40e_ptp_init(struct i40e_pf *pf) struct timespec ts; u32 regval; - spin_lock_init(&pf->tmreg_lock); - dev_info(&pf->pdev->dev, "%s: added PHC on %s\n", __func__, netdev->name); pf->flags |= I40E_FLAG_PTP; - pf->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; - pf->tstamp_config.tx_type = HWTSTAMP_TX_OFF; - /* Ensure the clocks are running. */ regval = rd32(hw, I40E_PRTTSYN_CTL0); regval |= I40E_PRTTSYN_CTL0_TSYNENA_MASK; -- cgit v1.2.3 From 12be846ddda83b9f641be6cdbfd6891594fda4ec Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 4 Jun 2014 04:22:46 +0000 Subject: i40e: Avoid adding the TCP-IPv4 filter twice There wasn't a need to play the logic twice, it seems like a left over from when we had to add two PTYPEs for one filter. There should be no change in the number of filters that actually got added to the hardware. Change-ID: I5071d02eafd020b60e30eb96219f110f334eec85 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index e49f31dbd5d8..4d96b743f991 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -271,19 +271,6 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, fd_data->pctype, ret); } - fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP; - - ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add); - if (ret) { - dev_info(&pf->pdev->dev, - "Filter command send failed for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - err = true; - } else { - dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - } - return err ? -EOPNOTSUPP : 0; } -- cgit v1.2.3 From 129573883c5b39d978c4a7fbe513f8e54898e27e Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 4 Jun 2014 04:22:47 +0000 Subject: i40e: Fix the FD sideband logic to detect a FD table full condition Hardware does not have a way of telling a PF how much of the global shared FD table space is still available or is consumed. Previously, every PF but PF0 would think there was still space available when there wasn't. The PFs would continue to try to add filters and fail. With this new logic if a filter programming error is detected we just check if we are close to the guaranteed space full and that can be used as a hint to say, there might not be space and we should turn off the features. This way we can turn off the feature in SW for all PFs in time. Change-ID: I725cb2fab16c033f883056362b4542c1400503c5 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 3 ++- drivers/net/ethernet/intel/i40e/i40e_main.c | 20 ++++++++++++++++---- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 4 ++-- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 2ec6e8a11ee1..0fbb32a8ad42 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -154,7 +154,7 @@ struct i40e_lump_tracking { #define I40E_DEFAULT_ATR_SAMPLE_RATE 20 #define I40E_FDIR_MAX_RAW_PACKET_SIZE 512 #define I40E_FDIR_BUFFER_FULL_MARGIN 10 -#define I40E_FDIR_BUFFER_HEAD_ROOM 200 +#define I40E_FDIR_BUFFER_HEAD_ROOM 32 enum i40e_fd_stat_idx { I40E_FD_STAT_ATR, @@ -582,6 +582,7 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi, struct i40e_fdir_filter *input, bool add); void i40e_fdir_check_and_reenable(struct i40e_pf *pf); int i40e_get_current_fd_count(struct i40e_pf *pf); +int i40e_get_cur_guaranteed_fd_count(struct i40e_pf *pf); bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features); void i40e_set_ethtool_ops(struct net_device *netdev); struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 5980d6b3fb1a..17b1295bf35a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4944,7 +4944,20 @@ static void i40e_service_event_complete(struct i40e_pf *pf) } /** - * i40e_get_current_fd_count - Get the count of FD filters programmed in the HW + * i40e_get_cur_guaranteed_fd_count - Get the consumed guaranteed FD filters + * @pf: board private structure + **/ +int i40e_get_cur_guaranteed_fd_count(struct i40e_pf *pf) +{ + int val, fcnt_prog; + + val = rd32(&pf->hw, I40E_PFQF_FDSTAT); + fcnt_prog = (val & I40E_PFQF_FDSTAT_GUARANT_CNT_MASK); + return fcnt_prog; +} + +/** + * i40e_get_current_fd_count - Get the count of total FD filters programmed * @pf: board private structure **/ int i40e_get_current_fd_count(struct i40e_pf *pf) @@ -4956,7 +4969,6 @@ int i40e_get_current_fd_count(struct i40e_pf *pf) I40E_PFQF_FDSTAT_BEST_CNT_SHIFT); return fcnt_prog; } - /** * i40e_fdir_check_and_reenable - Function to reenabe FD ATR or SB if disabled * @pf: board private structure @@ -4971,8 +4983,8 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf) if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && (pf->flags & I40E_FLAG_FD_SB_ENABLED)) return; - fcnt_prog = i40e_get_current_fd_count(pf); - fcnt_avail = i40e_get_fd_cnt_all(pf); + fcnt_prog = i40e_get_cur_guaranteed_fd_count(pf); + fcnt_avail = pf->fdir_pf_filter_count; if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) { if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) && (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 4d96b743f991..c5749d6526ea 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -437,8 +437,8 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, rx_desc->wb.qword0.hi_dword.fd_id); /* filter programming failed most likely due to table full */ - fcnt_prog = i40e_get_current_fd_count(pf); - fcnt_avail = i40e_get_fd_cnt_all(pf); + fcnt_prog = i40e_get_cur_guaranteed_fd_count(pf); + fcnt_avail = pf->fdir_pf_filter_count; /* If ATR is running fcnt_prog can quickly change, * if we are very close to full, it makes sense to disable * FD ATR/SB and then re-enable it when there is room. -- cgit v1.2.3 From e17ff05c5d9ee64550030d03e63719e6dc62d729 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 4 Jun 2014 04:22:48 +0000 Subject: i40e: Add debugfs hooks to print current total FD filter count "fd current cnt" can be used to print the total filters consumed by this interface, this includes guaranteed and best effort filters. Change-ID: I2c417810c4999ce1388d2ea26f8e69679ba33966 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 910b01b90cdc..ec07332e109e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1743,6 +1743,9 @@ static ssize_t i40e_dbg_command_write(struct file *filp, i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_ATR_ENABLED, false); } else if (strncmp(cmd_buf, "fd-atr on", 9) == 0) { i40e_dbg_cmd_fd_ctrl(pf, I40E_FLAG_FD_ATR_ENABLED, true); + } else if (strncmp(cmd_buf, "fd current cnt", 14) == 0) { + dev_info(&pf->pdev->dev, "FD current total filter count for this interface: %d\n", + i40e_get_current_fd_count(pf)); } else if (strncmp(cmd_buf, "lldp", 4) == 0) { if (strncmp(&cmd_buf[5], "stop", 4) == 0) { int ret; @@ -1962,6 +1965,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, dev_info(&pf->pdev->dev, " rem fd_filter \n"); dev_info(&pf->pdev->dev, " fd-atr off\n"); dev_info(&pf->pdev->dev, " fd-atr on\n"); + dev_info(&pf->pdev->dev, " fd current cnt"); dev_info(&pf->pdev->dev, " lldp start\n"); dev_info(&pf->pdev->dev, " lldp stop\n"); dev_info(&pf->pdev->dev, " lldp get local\n"); -- cgit v1.2.3 From 99753ea60626a4c5059b24e2a4c22f8fd88b8207 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 4 Jun 2014 04:22:49 +0000 Subject: i40e: fix fdir programming There were a couple of fields in the fdir descriptor setup that were not being reprogrammed, which left the opportunity for stale data to be pushed as part of the descriptor next time it was used. Change-ID: Ieee5c96a7d4713d469693f086c4854de949a7633 Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index c5749d6526ea..5cc27fba8ad5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -100,8 +100,6 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) & I40E_TXD_FLTR_QW0_DEST_VSI_MASK; - fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(fpt); - dcc = I40E_TX_DESC_DTYPE_FILTER_PROG; if (add) @@ -124,6 +122,8 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, I40E_TXD_FLTR_QW1_CNTINDEX_MASK; } + fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(fpt); + fdir_desc->rsvd = cpu_to_le32(0); fdir_desc->dtype_cmd_cntindex = cpu_to_le32(dcc); fdir_desc->fd_id = cpu_to_le32(fdir_data->fd_id); @@ -1688,7 +1688,9 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, I40E_TXD_FLTR_QW1_CNTINDEX_MASK; fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype); + fdir_desc->rsvd = cpu_to_le32(0); fdir_desc->dtype_cmd_cntindex = cpu_to_le32(dtype_cmd); + fdir_desc->fd_id = cpu_to_le32(0); } /** -- cgit v1.2.3 From d0a8ba6cba0a05ce79df100a3d99502b94117d88 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 24 Jun 2014 16:19:06 -0500 Subject: amd-xgbe: Make defines in xgbe.h unique In order to avoid conflicts with other include files, add a prefix to the defines in xgbe.h. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 23 +++---- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 100 +++++++++++++++--------------- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 28 +++++---- drivers/net/ethernet/amd/xgbe/xgbe-main.c | 8 +-- drivers/net/ethernet/amd/xgbe/xgbe.h | 43 +++++++------ 5 files changed, 102 insertions(+), 100 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c index 6f1c85956d50..a9ce56d5e988 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c @@ -131,7 +131,7 @@ static void xgbe_free_ring(struct xgbe_prv_data *pdata, if (ring->rdata) { for (i = 0; i < ring->rdesc_count; i++) { - rdata = GET_DESC_DATA(ring, i); + rdata = XGBE_GET_DESC_DATA(ring, i); xgbe_unmap_skb(pdata, rdata); } @@ -256,7 +256,7 @@ static void xgbe_wrapper_tx_descriptor_init(struct xgbe_prv_data *pdata) rdesc_dma = ring->rdesc_dma; for (j = 0; j < ring->rdesc_count; j++) { - rdata = GET_DESC_DATA(ring, j); + rdata = XGBE_GET_DESC_DATA(ring, j); rdata->rdesc = rdesc; rdata->rdesc_dma = rdesc_dma; @@ -298,7 +298,7 @@ static void xgbe_wrapper_rx_descriptor_init(struct xgbe_prv_data *pdata) rdesc_dma = ring->rdesc_dma; for (j = 0; j < ring->rdesc_count; j++) { - rdata = GET_DESC_DATA(ring, j); + rdata = XGBE_GET_DESC_DATA(ring, j); rdata->rdesc = rdesc; rdata->rdesc_dma = rdesc_dma; @@ -392,7 +392,7 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb) if ((tso && (packet->mss != ring->tx.cur_mss)) || (vlan && (packet->vlan_ctag != ring->tx.cur_vlan_ctag))) cur_index++; - rdata = GET_DESC_DATA(ring, cur_index); + rdata = XGBE_GET_DESC_DATA(ring, cur_index); if (tso) { DBGPR(" TSO packet\n"); @@ -413,12 +413,12 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb) packet->length += packet->header_len; cur_index++; - rdata = GET_DESC_DATA(ring, cur_index); + rdata = XGBE_GET_DESC_DATA(ring, cur_index); } /* Map the (remainder of the) packet */ for (datalen = skb_headlen(skb) - offset; datalen; ) { - len = min_t(unsigned int, datalen, TX_MAX_BUF_SIZE); + len = min_t(unsigned int, datalen, XGBE_TX_MAX_BUF_SIZE); skb_dma = dma_map_single(pdata->dev, skb->data + offset, len, DMA_TO_DEVICE); @@ -437,7 +437,7 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb) packet->length += len; cur_index++; - rdata = GET_DESC_DATA(ring, cur_index); + rdata = XGBE_GET_DESC_DATA(ring, cur_index); } for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { @@ -447,7 +447,8 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb) offset = 0; for (datalen = skb_frag_size(frag); datalen; ) { - len = min_t(unsigned int, datalen, TX_MAX_BUF_SIZE); + len = min_t(unsigned int, datalen, + XGBE_TX_MAX_BUF_SIZE); skb_dma = skb_frag_dma_map(pdata->dev, frag, offset, len, DMA_TO_DEVICE); @@ -468,7 +469,7 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb) packet->length += len; cur_index++; - rdata = GET_DESC_DATA(ring, cur_index); + rdata = XGBE_GET_DESC_DATA(ring, cur_index); } } @@ -484,7 +485,7 @@ static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb) err_out: while (start_index < cur_index) { - rdata = GET_DESC_DATA(ring, start_index++); + rdata = XGBE_GET_DESC_DATA(ring, start_index++); xgbe_unmap_skb(pdata, rdata); } @@ -507,7 +508,7 @@ static void xgbe_realloc_skb(struct xgbe_channel *channel) ring->rx.realloc_index); for (i = 0; i < ring->dirty; i++) { - rdata = GET_DESC_DATA(ring, ring->rx.realloc_index); + rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index); /* Reset rdata values */ xgbe_unmap_skb(pdata, rdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 002293b0819d..864af2da54cd 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -766,7 +766,7 @@ static void xgbe_tx_desc_init(struct xgbe_channel *channel) /* Initialze all descriptors */ for (i = 0; i < ring->rdesc_count; i++) { - rdata = GET_DESC_DATA(ring, i); + rdata = XGBE_GET_DESC_DATA(ring, i); rdesc = rdata->rdesc; /* Initialize Tx descriptor @@ -791,7 +791,7 @@ static void xgbe_tx_desc_init(struct xgbe_channel *channel) XGMAC_DMA_IOWRITE(channel, DMA_CH_TDRLR, ring->rdesc_count - 1); /* Update the starting address of descriptor ring */ - rdata = GET_DESC_DATA(ring, start_index); + rdata = XGBE_GET_DESC_DATA(ring, start_index); XGMAC_DMA_IOWRITE(channel, DMA_CH_TDLR_HI, upper_32_bits(rdata->rdesc_dma)); XGMAC_DMA_IOWRITE(channel, DMA_CH_TDLR_LO, @@ -848,7 +848,7 @@ static void xgbe_rx_desc_init(struct xgbe_channel *channel) /* Initialize all descriptors */ for (i = 0; i < ring->rdesc_count; i++) { - rdata = GET_DESC_DATA(ring, i); + rdata = XGBE_GET_DESC_DATA(ring, i); rdesc = rdata->rdesc; /* Initialize Rx descriptor @@ -882,14 +882,14 @@ static void xgbe_rx_desc_init(struct xgbe_channel *channel) XGMAC_DMA_IOWRITE(channel, DMA_CH_RDRLR, ring->rdesc_count - 1); /* Update the starting address of descriptor ring */ - rdata = GET_DESC_DATA(ring, start_index); + rdata = XGBE_GET_DESC_DATA(ring, start_index); XGMAC_DMA_IOWRITE(channel, DMA_CH_RDLR_HI, upper_32_bits(rdata->rdesc_dma)); XGMAC_DMA_IOWRITE(channel, DMA_CH_RDLR_LO, lower_32_bits(rdata->rdesc_dma)); /* Update the Rx Descriptor Tail Pointer */ - rdata = GET_DESC_DATA(ring, start_index + ring->rdesc_count - 1); + rdata = XGBE_GET_DESC_DATA(ring, start_index + ring->rdesc_count - 1); XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO, lower_32_bits(rdata->rdesc_dma)); @@ -933,7 +933,7 @@ static void xgbe_pre_xmit(struct xgbe_channel *channel) if (tx_coalesce && !channel->tx_timer_active) ring->coalesce_count = 0; - rdata = GET_DESC_DATA(ring, ring->cur); + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); rdesc = rdata->rdesc; /* Create a context descriptor if this is a TSO packet */ @@ -977,7 +977,7 @@ static void xgbe_pre_xmit(struct xgbe_channel *channel) } ring->cur++; - rdata = GET_DESC_DATA(ring, ring->cur); + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); rdesc = rdata->rdesc; } @@ -1034,7 +1034,7 @@ static void xgbe_pre_xmit(struct xgbe_channel *channel) for (i = ring->cur - start_index + 1; i < packet->rdesc_count; i++) { ring->cur++; - rdata = GET_DESC_DATA(ring, ring->cur); + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); rdesc = rdata->rdesc; /* Update buffer address */ @@ -1074,7 +1074,7 @@ static void xgbe_pre_xmit(struct xgbe_channel *channel) wmb(); /* Set OWN bit for the first descriptor */ - rdata = GET_DESC_DATA(ring, start_index); + rdata = XGBE_GET_DESC_DATA(ring, start_index); rdesc = rdata->rdesc; XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1); @@ -1088,7 +1088,7 @@ static void xgbe_pre_xmit(struct xgbe_channel *channel) /* Issue a poll command to Tx DMA by writing address * of next immediate free descriptor */ ring->cur++; - rdata = GET_DESC_DATA(ring, ring->cur); + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); XGMAC_DMA_IOWRITE(channel, DMA_CH_TDTR_LO, lower_32_bits(rdata->rdesc_dma)); @@ -1117,7 +1117,7 @@ static int xgbe_dev_read(struct xgbe_channel *channel) DBGPR("-->xgbe_dev_read: cur = %d\n", ring->cur); - rdata = GET_DESC_DATA(ring, ring->cur); + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); rdesc = rdata->rdesc; /* Check for data availability */ @@ -1195,7 +1195,7 @@ static void xgbe_save_interrupt_status(struct xgbe_channel *channel, if (int_state == XGMAC_INT_STATE_SAVE) { channel->saved_ier = XGMAC_DMA_IOREAD(channel, DMA_CH_IER); - channel->saved_ier &= DMA_INTERRUPT_MASK; + channel->saved_ier &= XGBE_DMA_INTERRUPT_MASK; } else { dma_ch_ier = XGMAC_DMA_IOREAD(channel, DMA_CH_IER); dma_ch_ier |= channel->saved_ier; @@ -1275,7 +1275,7 @@ static int xgbe_disable_int(struct xgbe_channel *channel, xgbe_save_interrupt_status(channel, XGMAC_INT_STATE_SAVE); dma_ch_ier = XGMAC_DMA_IOREAD(channel, DMA_CH_IER); - dma_ch_ier &= ~DMA_INTERRUPT_MASK; + dma_ch_ier &= ~XGBE_DMA_INTERRUPT_MASK; XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier); break; default: @@ -1342,23 +1342,23 @@ static void xgbe_config_dma_cache(struct xgbe_prv_data *pdata) unsigned int arcache, awcache; arcache = 0; - XGMAC_SET_BITS(arcache, DMA_AXIARCR, DRC, DMA_ARCACHE_SETTING); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, DRD, DMA_ARDOMAIN_SETTING); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, TEC, DMA_ARCACHE_SETTING); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, TED, DMA_ARDOMAIN_SETTING); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, THC, DMA_ARCACHE_SETTING); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, THD, DMA_ARDOMAIN_SETTING); + XGMAC_SET_BITS(arcache, DMA_AXIARCR, DRC, XGBE_DMA_ARCACHE); + XGMAC_SET_BITS(arcache, DMA_AXIARCR, DRD, XGBE_DMA_ARDOMAIN); + XGMAC_SET_BITS(arcache, DMA_AXIARCR, TEC, XGBE_DMA_ARCACHE); + XGMAC_SET_BITS(arcache, DMA_AXIARCR, TED, XGBE_DMA_ARDOMAIN); + XGMAC_SET_BITS(arcache, DMA_AXIARCR, THC, XGBE_DMA_ARCACHE); + XGMAC_SET_BITS(arcache, DMA_AXIARCR, THD, XGBE_DMA_ARDOMAIN); XGMAC_IOWRITE(pdata, DMA_AXIARCR, arcache); awcache = 0; - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, DWC, DMA_AWCACHE_SETTING); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, DWD, DMA_AWDOMAIN_SETTING); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RPC, DMA_AWCACHE_SETTING); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RPD, DMA_AWDOMAIN_SETTING); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RHC, DMA_AWCACHE_SETTING); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RHD, DMA_AWDOMAIN_SETTING); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, TDC, DMA_AWCACHE_SETTING); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, TDD, DMA_AWDOMAIN_SETTING); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, DWC, XGBE_DMA_AWCACHE); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, DWD, XGBE_DMA_AWDOMAIN); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RPC, XGBE_DMA_AWCACHE); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RPD, XGBE_DMA_AWDOMAIN); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RHC, XGBE_DMA_AWCACHE); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RHD, XGBE_DMA_AWDOMAIN); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, TDC, XGBE_DMA_AWCACHE); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, TDD, XGBE_DMA_AWDOMAIN); XGMAC_IOWRITE(pdata, DMA_AXIAWCR, awcache); } @@ -1388,66 +1388,66 @@ static unsigned int xgbe_calculate_per_queue_fifo(unsigned long fifo_size, /* Calculate Tx/Rx fifo share per queue */ switch (fifo_size) { case 0: - q_fifo_size = FIFO_SIZE_B(128); + q_fifo_size = XGBE_FIFO_SIZE_B(128); break; case 1: - q_fifo_size = FIFO_SIZE_B(256); + q_fifo_size = XGBE_FIFO_SIZE_B(256); break; case 2: - q_fifo_size = FIFO_SIZE_B(512); + q_fifo_size = XGBE_FIFO_SIZE_B(512); break; case 3: - q_fifo_size = FIFO_SIZE_KB(1); + q_fifo_size = XGBE_FIFO_SIZE_KB(1); break; case 4: - q_fifo_size = FIFO_SIZE_KB(2); + q_fifo_size = XGBE_FIFO_SIZE_KB(2); break; case 5: - q_fifo_size = FIFO_SIZE_KB(4); + q_fifo_size = XGBE_FIFO_SIZE_KB(4); break; case 6: - q_fifo_size = FIFO_SIZE_KB(8); + q_fifo_size = XGBE_FIFO_SIZE_KB(8); break; case 7: - q_fifo_size = FIFO_SIZE_KB(16); + q_fifo_size = XGBE_FIFO_SIZE_KB(16); break; case 8: - q_fifo_size = FIFO_SIZE_KB(32); + q_fifo_size = XGBE_FIFO_SIZE_KB(32); break; case 9: - q_fifo_size = FIFO_SIZE_KB(64); + q_fifo_size = XGBE_FIFO_SIZE_KB(64); break; case 10: - q_fifo_size = FIFO_SIZE_KB(128); + q_fifo_size = XGBE_FIFO_SIZE_KB(128); break; case 11: - q_fifo_size = FIFO_SIZE_KB(256); + q_fifo_size = XGBE_FIFO_SIZE_KB(256); break; } q_fifo_size = q_fifo_size / queue_count; /* Set the queue fifo size programmable value */ - if (q_fifo_size >= FIFO_SIZE_KB(256)) + if (q_fifo_size >= XGBE_FIFO_SIZE_KB(256)) p_fifo = XGMAC_MTL_FIFO_SIZE_256K; - else if (q_fifo_size >= FIFO_SIZE_KB(128)) + else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(128)) p_fifo = XGMAC_MTL_FIFO_SIZE_128K; - else if (q_fifo_size >= FIFO_SIZE_KB(64)) + else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(64)) p_fifo = XGMAC_MTL_FIFO_SIZE_64K; - else if (q_fifo_size >= FIFO_SIZE_KB(32)) + else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(32)) p_fifo = XGMAC_MTL_FIFO_SIZE_32K; - else if (q_fifo_size >= FIFO_SIZE_KB(16)) + else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(16)) p_fifo = XGMAC_MTL_FIFO_SIZE_16K; - else if (q_fifo_size >= FIFO_SIZE_KB(8)) + else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(8)) p_fifo = XGMAC_MTL_FIFO_SIZE_8K; - else if (q_fifo_size >= FIFO_SIZE_KB(4)) + else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(4)) p_fifo = XGMAC_MTL_FIFO_SIZE_4K; - else if (q_fifo_size >= FIFO_SIZE_KB(2)) + else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(2)) p_fifo = XGMAC_MTL_FIFO_SIZE_2K; - else if (q_fifo_size >= FIFO_SIZE_KB(1)) + else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(1)) p_fifo = XGMAC_MTL_FIFO_SIZE_1K; - else if (q_fifo_size >= FIFO_SIZE_B(512)) + else if (q_fifo_size >= XGBE_FIFO_SIZE_B(512)) p_fifo = XGMAC_MTL_FIFO_SIZE_512; - else if (q_fifo_size >= FIFO_SIZE_B(256)) + else if (q_fifo_size >= XGBE_FIFO_SIZE_B(256)) p_fifo = XGMAC_MTL_FIFO_SIZE_256; return p_fifo; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index cfe3d93b5f52..0efb5062e271 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -144,9 +144,10 @@ static int xgbe_calc_rx_buf_size(struct net_device *netdev, unsigned int mtu) } rx_buf_size = mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; - if (rx_buf_size < RX_MIN_BUF_SIZE) - rx_buf_size = RX_MIN_BUF_SIZE; - rx_buf_size = (rx_buf_size + RX_BUF_ALIGN - 1) & ~(RX_BUF_ALIGN - 1); + if (rx_buf_size < XGBE_RX_MIN_BUF_SIZE) + rx_buf_size = XGBE_RX_MIN_BUF_SIZE; + rx_buf_size = (rx_buf_size + XGBE_RX_BUF_ALIGN - 1) & + ~(XGBE_RX_BUF_ALIGN - 1); return rx_buf_size; } @@ -446,7 +447,7 @@ static void xgbe_free_tx_skbuff(struct xgbe_prv_data *pdata) break; for (j = 0; j < ring->rdesc_count; j++) { - rdata = GET_DESC_DATA(ring, j); + rdata = XGBE_GET_DESC_DATA(ring, j); desc_if->unmap_skb(pdata, rdata); } } @@ -471,7 +472,7 @@ static void xgbe_free_rx_skbuff(struct xgbe_prv_data *pdata) break; for (j = 0; j < ring->rdesc_count; j++) { - rdata = GET_DESC_DATA(ring, j); + rdata = XGBE_GET_DESC_DATA(ring, j); desc_if->unmap_skb(pdata, rdata); } } @@ -726,14 +727,14 @@ static void xgbe_packet_info(struct xgbe_ring *ring, struct sk_buff *skb, for (len = skb_headlen(skb); len;) { packet->rdesc_count++; - len -= min_t(unsigned int, len, TX_MAX_BUF_SIZE); + len -= min_t(unsigned int, len, XGBE_TX_MAX_BUF_SIZE); } for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { frag = &skb_shinfo(skb)->frags[i]; for (len = skb_frag_size(frag); len; ) { packet->rdesc_count++; - len -= min_t(unsigned int, len, TX_MAX_BUF_SIZE); + len -= min_t(unsigned int, len, XGBE_TX_MAX_BUF_SIZE); } } } @@ -1089,8 +1090,9 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) spin_lock_irqsave(&ring->lock, flags); - while ((processed < TX_DESC_MAX_PROC) && (ring->dirty < ring->cur)) { - rdata = GET_DESC_DATA(ring, ring->dirty); + while ((processed < XGBE_TX_DESC_MAX_PROC) && + (ring->dirty < ring->cur)) { + rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); rdesc = rdata->rdesc; if (!hw_if->tx_complete(rdesc)) @@ -1109,7 +1111,7 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) } if ((ring->tx.queue_stopped == 1) && - (xgbe_tx_avail_desc(ring) > TX_DESC_MIN_FREE)) { + (xgbe_tx_avail_desc(ring) > XGBE_TX_DESC_MIN_FREE)) { ring->tx.queue_stopped = 0; netif_wake_subqueue(netdev, channel->queue_index); } @@ -1152,7 +1154,7 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) cur_len = 0; read_again: - rdata = GET_DESC_DATA(ring, ring->cur); + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); if (hw_if->dev_read(channel)) break; @@ -1244,7 +1246,7 @@ read_again: /* Update the Rx Tail Pointer Register with address of * the last cleaned entry */ - rdata = GET_DESC_DATA(ring, ring->rx.realloc_index - 1); + rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index - 1); XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO, lower_32_bits(rdata->rdesc_dma)); } @@ -1296,7 +1298,7 @@ void xgbe_dump_tx_desc(struct xgbe_ring *ring, unsigned int idx, struct xgbe_ring_desc *rdesc; while (count--) { - rdata = GET_DESC_DATA(ring, idx); + rdata = XGBE_GET_DESC_DATA(ring, idx); rdesc = rdata->rdesc; DBGPR("TX_NORMAL_DESC[%d %s] = %08x:%08x:%08x:%08x\n", idx, (flag == 1) ? "QUEUED FOR TX" : "TX BY DEVICE", diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index c83584a26713..fefcbb6c69a8 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -247,16 +247,16 @@ static int xgbe_probe(struct platform_device *pdev) mutex_init(&pdata->xpcs_mutex); /* Set and validate the number of descriptors for a ring */ - BUILD_BUG_ON_NOT_POWER_OF_2(TX_DESC_CNT); - pdata->tx_desc_count = TX_DESC_CNT; + BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT); + pdata->tx_desc_count = XGBE_TX_DESC_CNT; if (pdata->tx_desc_count & (pdata->tx_desc_count - 1)) { dev_err(dev, "tx descriptor count (%d) is not valid\n", pdata->tx_desc_count); ret = -EINVAL; goto err_io; } - BUILD_BUG_ON_NOT_POWER_OF_2(RX_DESC_CNT); - pdata->rx_desc_count = RX_DESC_CNT; + BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_RX_DESC_CNT); + pdata->rx_desc_count = XGBE_RX_DESC_CNT; if (pdata->rx_desc_count & (pdata->rx_desc_count - 1)) { dev_err(dev, "rx descriptor count (%d) is not valid\n", pdata->rx_desc_count); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index ab0627162c01..f5da54cddd8d 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -128,22 +128,25 @@ #define XGBE_DRV_DESC "AMD 10 Gigabit Ethernet Driver" /* Descriptor related defines */ -#define TX_DESC_CNT 512 -#define TX_DESC_MIN_FREE (TX_DESC_CNT >> 3) -#define TX_DESC_MAX_PROC (TX_DESC_CNT >> 1) -#define RX_DESC_CNT 512 +#define XGBE_TX_DESC_CNT 512 +#define XGBE_TX_DESC_MIN_FREE (XGBE_TX_DESC_CNT >> 3) +#define XGBE_TX_DESC_MAX_PROC (XGBE_TX_DESC_CNT >> 1) +#define XGBE_RX_DESC_CNT 512 -#define TX_MAX_BUF_SIZE (0x3fff & ~(64 - 1)) +#define XGBE_TX_MAX_BUF_SIZE (0x3fff & ~(64 - 1)) -#define RX_MIN_BUF_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN) -#define RX_BUF_ALIGN 64 +#define XGBE_RX_MIN_BUF_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN) +#define XGBE_RX_BUF_ALIGN 64 #define XGBE_MAX_DMA_CHANNELS 16 -#define DMA_ARDOMAIN_SETTING 0x2 -#define DMA_ARCACHE_SETTING 0xb -#define DMA_AWDOMAIN_SETTING 0x2 -#define DMA_AWCACHE_SETTING 0x7 -#define DMA_INTERRUPT_MASK 0x31c7 + +/* DMA cache settings - Outer sharable, write-back, write-allocate */ +#define XGBE_DMA_ARDOMAIN 0x2 +#define XGBE_DMA_ARCACHE 0xb +#define XGBE_DMA_AWDOMAIN 0x2 +#define XGBE_DMA_AWCACHE 0x7 + +#define XGBE_DMA_INTERRUPT_MASK 0x31c7 #define XGMAC_MIN_PACKET 60 #define XGMAC_STD_PACKET_MTU 1500 @@ -151,10 +154,6 @@ #define XGMAC_JUMBO_PACKET_MTU 9000 #define XGMAC_MAX_JUMBO_PACKET 9018 -#define MAX_MULTICAST_LIST 14 -#define TX_FLAGS_IP_PKT 0x00000001 -#define TX_FLAGS_TCP_PKT 0x00000002 - /* MDIO bus phy name */ #define XGBE_PHY_NAME "amd_xgbe_phy" #define XGBE_PRTAD 0 @@ -163,18 +162,18 @@ #define XGMAC_DRIVER_CONTEXT 1 #define XGMAC_IOCTL_CONTEXT 2 -#define FIFO_SIZE_B(x) (x) -#define FIFO_SIZE_KB(x) (x * 1024) +#define XGBE_FIFO_SIZE_B(x) (x) +#define XGBE_FIFO_SIZE_KB(x) (x * 1024) #define XGBE_TC_CNT 2 /* Helper macro for descriptor handling - * Always use GET_DESC_DATA to access the descriptor data + * Always use XGBE_GET_DESC_DATA to access the descriptor data * since the index is free-running and needs to be and-ed * with the descriptor count value of the ring to index to * the proper descriptor data. */ -#define GET_DESC_DATA(_ring, _idx) \ +#define XGBE_GET_DESC_DATA(_ring, _idx) \ ((_ring)->rdata + \ ((_idx) & ((_ring)->rdesc_count - 1))) @@ -219,7 +218,7 @@ struct xgbe_ring_desc { /* Structure used to hold information related to the descriptor * and the packet associated with the descriptor (always use - * use the GET_DESC_DATA macro to access this data from the ring) + * use the XGBE_GET_DESC_DATA macro to access this data from the ring) */ struct xgbe_ring_data { struct xgbe_ring_desc *rdesc; /* Virtual address of descriptor */ @@ -250,7 +249,7 @@ struct xgbe_ring { unsigned int rdesc_count; /* Array of descriptor data corresponding the descriptor memory - * (always use the GET_DESC_DATA macro to access this data) + * (always use the XGBE_GET_DESC_DATA macro to access this data) */ struct xgbe_ring_data *rdata; -- cgit v1.2.3 From 6e5eed042fcac4166874d25cf9fb89bee841eb26 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 24 Jun 2014 16:19:12 -0500 Subject: amd-xgbe: VLAN Tx tag insertion fix The MAC_VLAN_Incl register (0x0060) must be set to indicate that the VLAN tag to be inserted comes from a Tx context descriptor and not the MAC_VLAN_Incl register. Also, even though it is the default, explicitly set the type of tag to be inserted as a CTAG. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 4 ++++ drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index bf462ee86f5c..129d322977f1 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -427,6 +427,10 @@ #define MAC_TCR_SS_WIDTH 2 #define MAC_TCR_TE_INDEX 0 #define MAC_TCR_TE_WIDTH 1 +#define MAC_VLANIR_VLTI_INDEX 20 +#define MAC_VLANIR_VLTI_WIDTH 1 +#define MAC_VLANIR_CSVL_INDEX 19 +#define MAC_VLANIR_CSVL_WIDTH 1 #define MAC_VLANTR_DOVLTC_INDEX 20 #define MAC_VLANTR_DOVLTC_WIDTH 1 #define MAC_VLANTR_ERSVLM_INDEX 19 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 864af2da54cd..b239b216e191 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -1541,6 +1541,10 @@ static void xgbe_config_checksum_offload(struct xgbe_prv_data *pdata) static void xgbe_config_vlan_support(struct xgbe_prv_data *pdata) { + /* Indicate that VLAN Tx CTAGs come from context descriptors */ + XGMAC_IOWRITE_BITS(pdata, MAC_VLANIR, CSVL, 0); + XGMAC_IOWRITE_BITS(pdata, MAC_VLANIR, VLTI, 1); + if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) xgbe_enable_rx_vlan_stripping(pdata); else -- cgit v1.2.3 From c52e9c6385ec5578eaac2989b855742e52777711 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 24 Jun 2014 16:19:18 -0500 Subject: amd-xgbe: VLAN Rx tag stripping fix When receiving a VLAN packet check to be sure that VLAN RX CTAG stripping is enabled before indicating that the tag has been stripped in the packet information data structure. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index b239b216e191..d0f437945dd4 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -1113,6 +1113,7 @@ static int xgbe_dev_read(struct xgbe_channel *channel) struct xgbe_ring_data *rdata; struct xgbe_ring_desc *rdesc; struct xgbe_packet_data *packet = &ring->packet_data; + struct net_device *netdev = channel->pdata->netdev; unsigned int err, etlt; DBGPR("-->xgbe_dev_read: cur = %d\n", ring->cur); @@ -1153,7 +1154,8 @@ static int xgbe_dev_read(struct xgbe_channel *channel) DBGPR(" err=%u, etlt=%#x\n", err, etlt); if (!err || (err && !etlt)) { - if (etlt == 0x09) { + if ((etlt == 0x09) && + (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) { XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, VLAN_CTAG, 1); packet->vlan_ctag = XGMAC_GET_BITS_LE(rdesc->desc0, -- cgit v1.2.3 From 801c62d945c6121c0262924732e430f0553bfb37 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 24 Jun 2014 16:19:24 -0500 Subject: amd-xgbe: Add support for VLAN filtering This patch adds support for (imperfect) filtering of VLAN tag ids using a 16-bit filter hash table. When VLANs are added, a 4-bit hash is calculated with the result indicating the bit in the hash table to set. This table is used by the hardware to drop packets with a VLAN id that does not hash to a set bit in the table. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/Kconfig | 1 + drivers/net/ethernet/amd/xgbe/xgbe-common.h | 12 ++++ drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 95 +++++++++++++++++++++++++++++ drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 60 ++++++++++++++---- drivers/net/ethernet/amd/xgbe/xgbe-main.c | 3 +- drivers/net/ethernet/amd/xgbe/xgbe.h | 8 +++ 6 files changed, 165 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index bbaf36d9f5e1..8e83e4c8fff0 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -182,6 +182,7 @@ config AMD_XGBE depends on OF_NET select PHYLIB select AMD_XGBE_PHY + select BITREVERSE ---help--- This driver supports the AMD 10GbE Ethernet device found on an AMD SoC. diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index 129d322977f1..1de9d0fc594a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -393,6 +393,8 @@ #define MAC_PFR_PM_WIDTH 1 #define MAC_PFR_PR_INDEX 0 #define MAC_PFR_PR_WIDTH 1 +#define MAC_PFR_VTFE_INDEX 16 +#define MAC_PFR_VTFE_WIDTH 1 #define MAC_PMTCSR_MGKPKTEN_INDEX 1 #define MAC_PMTCSR_MGKPKTEN_WIDTH 1 #define MAC_PMTCSR_PWRDWN_INDEX 0 @@ -427,6 +429,8 @@ #define MAC_TCR_SS_WIDTH 2 #define MAC_TCR_TE_INDEX 0 #define MAC_TCR_TE_WIDTH 1 +#define MAC_VLANHTR_VLHT_INDEX 0 +#define MAC_VLANHTR_VLHT_WIDTH 16 #define MAC_VLANIR_VLTI_INDEX 20 #define MAC_VLANIR_VLTI_WIDTH 1 #define MAC_VLANIR_CSVL_INDEX 19 @@ -437,10 +441,18 @@ #define MAC_VLANTR_ERSVLM_WIDTH 1 #define MAC_VLANTR_ESVL_INDEX 18 #define MAC_VLANTR_ESVL_WIDTH 1 +#define MAC_VLANTR_ETV_INDEX 16 +#define MAC_VLANTR_ETV_WIDTH 1 #define MAC_VLANTR_EVLS_INDEX 21 #define MAC_VLANTR_EVLS_WIDTH 2 #define MAC_VLANTR_EVLRXS_INDEX 24 #define MAC_VLANTR_EVLRXS_WIDTH 1 +#define MAC_VLANTR_VL_INDEX 0 +#define MAC_VLANTR_VL_WIDTH 16 +#define MAC_VLANTR_VTHM_INDEX 25 +#define MAC_VLANTR_VTHM_WIDTH 1 +#define MAC_VLANTR_VTIM_INDEX 17 +#define MAC_VLANTR_VTIM_WIDTH 1 #define MAC_VR_DEVID_INDEX 8 #define MAC_VR_DEVID_WIDTH 8 #define MAC_VR_SNPSVER_INDEX 0 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index d0f437945dd4..2c7d582e0859 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -116,6 +116,7 @@ #include #include +#include #include "xgbe.h" #include "xgbe-common.h" @@ -738,6 +739,89 @@ static int xgbe_disable_rx_vlan_stripping(struct xgbe_prv_data *pdata) return 0; } +static int xgbe_enable_rx_vlan_filtering(struct xgbe_prv_data *pdata) +{ + /* Enable VLAN filtering */ + XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 1); + + /* Enable VLAN Hash Table filtering */ + XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VTHM, 1); + + /* Disable VLAN tag inverse matching */ + XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VTIM, 0); + + /* Only filter on the lower 12-bits of the VLAN tag */ + XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ETV, 1); + + /* In order for the VLAN Hash Table filtering to be effective, + * the VLAN tag identifier in the VLAN Tag Register must not + * be zero. Set the VLAN tag identifier to "1" to enable the + * VLAN Hash Table filtering. This implies that a VLAN tag of + * 1 will always pass filtering. + */ + XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VL, 1); + + return 0; +} + +static int xgbe_disable_rx_vlan_filtering(struct xgbe_prv_data *pdata) +{ + /* Disable VLAN filtering */ + XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 0); + + return 0; +} + +#ifndef CRCPOLY_LE +#define CRCPOLY_LE 0xedb88320 +#endif +static u32 xgbe_vid_crc32_le(__le16 vid_le) +{ + u32 poly = CRCPOLY_LE; + u32 crc = ~0; + u32 temp = 0; + unsigned char *data = (unsigned char *)&vid_le; + unsigned char data_byte = 0; + int i, bits; + + bits = get_bitmask_order(VLAN_VID_MASK); + for (i = 0; i < bits; i++) { + if ((i % 8) == 0) + data_byte = data[i / 8]; + + temp = ((crc & 1) ^ data_byte) & 1; + crc >>= 1; + data_byte >>= 1; + + if (temp) + crc ^= poly; + } + + return crc; +} + +static int xgbe_update_vlan_hash_table(struct xgbe_prv_data *pdata) +{ + u32 crc; + u16 vid; + __le16 vid_le; + u16 vlan_hash_table = 0; + + /* Generate the VLAN Hash Table value */ + for_each_set_bit(vid, pdata->active_vlans, VLAN_N_VID) { + /* Get the CRC32 value of the VLAN ID */ + vid_le = cpu_to_le16(vid); + crc = bitrev32(~xgbe_vid_crc32_le(vid_le)) >> 28; + + vlan_hash_table |= (1 << crc); + } + + /* Set the VLAN Hash Table filtering register */ + XGMAC_IOWRITE_BITS(pdata, MAC_VLANHTR, VLHT, vlan_hash_table); + + return 0; +} + static void xgbe_tx_desc_reset(struct xgbe_ring_data *rdata) { struct xgbe_ring_desc *rdesc = rdata->rdesc; @@ -1547,6 +1631,14 @@ static void xgbe_config_vlan_support(struct xgbe_prv_data *pdata) XGMAC_IOWRITE_BITS(pdata, MAC_VLANIR, CSVL, 0); XGMAC_IOWRITE_BITS(pdata, MAC_VLANIR, VLTI, 1); + /* Set the current VLAN Hash Table register value */ + xgbe_update_vlan_hash_table(pdata); + + if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER) + xgbe_enable_rx_vlan_filtering(pdata); + else + xgbe_disable_rx_vlan_filtering(pdata); + if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) xgbe_enable_rx_vlan_stripping(pdata); else @@ -2118,6 +2210,9 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) hw_if->enable_rx_vlan_stripping = xgbe_enable_rx_vlan_stripping; hw_if->disable_rx_vlan_stripping = xgbe_disable_rx_vlan_stripping; + hw_if->enable_rx_vlan_filtering = xgbe_enable_rx_vlan_filtering; + hw_if->disable_rx_vlan_filtering = xgbe_disable_rx_vlan_filtering; + hw_if->update_vlan_hash_table = xgbe_update_vlan_hash_table; hw_if->read_mmd_regs = xgbe_read_mmd_regs; hw_if->write_mmd_regs = xgbe_write_mmd_regs; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 0efb5062e271..2acc37c07d9b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1000,6 +1000,38 @@ static struct rtnl_link_stats64 *xgbe_get_stats64(struct net_device *netdev, return s; } +static int xgbe_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, + u16 vid) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + struct xgbe_hw_if *hw_if = &pdata->hw_if; + + DBGPR("-->%s\n", __func__); + + set_bit(vid, pdata->active_vlans); + hw_if->update_vlan_hash_table(pdata); + + DBGPR("<--%s\n", __func__); + + return 0; +} + +static int xgbe_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, + u16 vid) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + struct xgbe_hw_if *hw_if = &pdata->hw_if; + + DBGPR("-->%s\n", __func__); + + clear_bit(vid, pdata->active_vlans); + hw_if->update_vlan_hash_table(pdata); + + DBGPR("<--%s\n", __func__); + + return 0; +} + #ifdef CONFIG_NET_POLL_CONTROLLER static void xgbe_poll_controller(struct net_device *netdev) { @@ -1022,26 +1054,26 @@ static int xgbe_set_features(struct net_device *netdev, { struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_hw_if *hw_if = &pdata->hw_if; - unsigned int rxcsum_enabled, rxvlan_enabled; + unsigned int rxcsum, rxvlan, rxvlan_filter; - rxcsum_enabled = !!(pdata->netdev_features & NETIF_F_RXCSUM); - rxvlan_enabled = !!(pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_RX); + rxcsum = pdata->netdev_features & NETIF_F_RXCSUM; + rxvlan = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_RX; + rxvlan_filter = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_FILTER; - if ((features & NETIF_F_RXCSUM) && !rxcsum_enabled) { + if ((features & NETIF_F_RXCSUM) && !rxcsum) hw_if->enable_rx_csum(pdata); - netdev_alert(netdev, "state change - rxcsum enabled\n"); - } else if (!(features & NETIF_F_RXCSUM) && rxcsum_enabled) { + else if (!(features & NETIF_F_RXCSUM) && rxcsum) hw_if->disable_rx_csum(pdata); - netdev_alert(netdev, "state change - rxcsum disabled\n"); - } - if ((features & NETIF_F_HW_VLAN_CTAG_RX) && !rxvlan_enabled) { + if ((features & NETIF_F_HW_VLAN_CTAG_RX) && !rxvlan) hw_if->enable_rx_vlan_stripping(pdata); - netdev_alert(netdev, "state change - rxvlan enabled\n"); - } else if (!(features & NETIF_F_HW_VLAN_CTAG_RX) && rxvlan_enabled) { + else if (!(features & NETIF_F_HW_VLAN_CTAG_RX) && rxvlan) hw_if->disable_rx_vlan_stripping(pdata); - netdev_alert(netdev, "state change - rxvlan disabled\n"); - } + + if ((features & NETIF_F_HW_VLAN_CTAG_FILTER) && !rxvlan_filter) + hw_if->enable_rx_vlan_filtering(pdata); + else if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER) && rxvlan_filter) + hw_if->disable_rx_vlan_filtering(pdata); pdata->netdev_features = features; @@ -1059,6 +1091,8 @@ static const struct net_device_ops xgbe_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = xgbe_change_mtu, .ndo_get_stats64 = xgbe_get_stats64, + .ndo_vlan_rx_add_vid = xgbe_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = xgbe_vlan_rx_kill_vid, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = xgbe_poll_controller, #endif diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index fefcbb6c69a8..c3a48b7c2aed 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -385,7 +385,8 @@ static int xgbe_probe(struct platform_device *pdev) NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_HW_VLAN_CTAG_RX | - NETIF_F_HW_VLAN_CTAG_TX; + NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_FILTER; netdev->vlan_features |= NETIF_F_SG | NETIF_F_IP_CSUM | diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index f5da54cddd8d..3cb911f39b60 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -121,6 +121,8 @@ #include #include #include +#include +#include #define XGBE_DRV_NAME "amd-xgbe" @@ -393,6 +395,9 @@ struct xgbe_hw_if { int (*enable_rx_vlan_stripping)(struct xgbe_prv_data *); int (*disable_rx_vlan_stripping)(struct xgbe_prv_data *); + int (*enable_rx_vlan_filtering)(struct xgbe_prv_data *); + int (*disable_rx_vlan_filtering)(struct xgbe_prv_data *); + int (*update_vlan_hash_table)(struct xgbe_prv_data *); int (*read_mmd_regs)(struct xgbe_prv_data *, int, int); void (*write_mmd_regs)(struct xgbe_prv_data *, int, int, int); @@ -588,6 +593,9 @@ struct xgbe_prv_data { struct napi_struct napi; struct xgbe_mmc_stats mmc_stats; + /* Filtering support */ + unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; + /* System clock value used for Rx watchdog */ struct clk *sysclock; -- cgit v1.2.3 From b85e4d8960f10e4b28613a3e7b76f8889a2089e3 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 24 Jun 2014 16:19:29 -0500 Subject: amd-xgbe: Change destination address filtering support Currently the driver makes use of the additional mac address registers in the hardware to provide perfect filtering. The hardware can also have a set of hash table registers that can be used for imperfect filtering. By using imperfect filtering the additional mac address registers can be used for layer 2 filtering support. Use the hash table registers if the device has them. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/Kconfig | 1 + drivers/net/ethernet/amd/xgbe/xgbe-common.h | 10 +- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 141 ++++++++++++++++++---------- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 27 ++++-- drivers/net/ethernet/amd/xgbe/xgbe-main.c | 2 + drivers/net/ethernet/amd/xgbe/xgbe.h | 4 +- 6 files changed, 116 insertions(+), 69 deletions(-) diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 8e83e4c8fff0..6e314dbba805 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -183,6 +183,7 @@ config AMD_XGBE select PHYLIB select AMD_XGBE_PHY select BITREVERSE + select CRC32 ---help--- This driver supports the AMD 10GbE Ethernet device found on an AMD SoC. diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index 1de9d0fc594a..ccbceba553e5 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -276,13 +276,6 @@ #define MAC_PFR 0x0008 #define MAC_WTR 0x000c #define MAC_HTR0 0x0010 -#define MAC_HTR1 0x0014 -#define MAC_HTR2 0x0018 -#define MAC_HTR3 0x001c -#define MAC_HTR4 0x0020 -#define MAC_HTR5 0x0024 -#define MAC_HTR6 0x0028 -#define MAC_HTR7 0x002c #define MAC_VLANTR 0x0050 #define MAC_VLANHTR 0x0058 #define MAC_VLANIR 0x0060 @@ -315,6 +308,7 @@ #define MAC_QTFCR_INC 4 #define MAC_MACA_INC 4 +#define MAC_HTR_INC 4 /* MAC register entry bit positions and sizes */ #define MAC_HWF0R_ADDMACADRSEL_INDEX 18 @@ -387,6 +381,8 @@ #define MAC_MACA1HR_AE_WIDTH 1 #define MAC_PFR_HMC_INDEX 2 #define MAC_PFR_HMC_WIDTH 1 +#define MAC_PFR_HPF_INDEX 10 +#define MAC_PFR_HPF_WIDTH 1 #define MAC_PFR_HUC_INDEX 1 #define MAC_PFR_HUC_WIDTH 1 #define MAC_PFR_PM_INDEX 4 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 2c7d582e0859..a56069c91fc4 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -117,6 +117,7 @@ #include #include #include +#include #include "xgbe.h" #include "xgbe-common.h" @@ -548,24 +549,16 @@ static int xgbe_set_all_multicast_mode(struct xgbe_prv_data *pdata, return 0; } -static int xgbe_set_addn_mac_addrs(struct xgbe_prv_data *pdata, - unsigned int am_mode) +static void xgbe_set_mac_reg(struct xgbe_prv_data *pdata, + struct netdev_hw_addr *ha, unsigned int *mac_reg) { - struct netdev_hw_addr *ha; - unsigned int mac_reg; unsigned int mac_addr_hi, mac_addr_lo; u8 *mac_addr; - unsigned int i; - XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HUC, 0); - XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HMC, 0); - - i = 0; - mac_reg = MAC_MACA1HR; + mac_addr_lo = 0; + mac_addr_hi = 0; - netdev_for_each_uc_addr(ha, pdata->netdev) { - mac_addr_lo = 0; - mac_addr_hi = 0; + if (ha) { mac_addr = (u8 *)&mac_addr_lo; mac_addr[0] = ha->addr[0]; mac_addr[1] = ha->addr[1]; @@ -575,54 +568,93 @@ static int xgbe_set_addn_mac_addrs(struct xgbe_prv_data *pdata, mac_addr[0] = ha->addr[4]; mac_addr[1] = ha->addr[5]; - DBGPR(" adding unicast address %pM at 0x%04x\n", - ha->addr, mac_reg); + DBGPR(" adding mac address %pM at 0x%04x\n", ha->addr, + *mac_reg); XGMAC_SET_BITS(mac_addr_hi, MAC_MACA1HR, AE, 1); + } - XGMAC_IOWRITE(pdata, mac_reg, mac_addr_hi); - mac_reg += MAC_MACA_INC; - XGMAC_IOWRITE(pdata, mac_reg, mac_addr_lo); - mac_reg += MAC_MACA_INC; + XGMAC_IOWRITE(pdata, *mac_reg, mac_addr_hi); + *mac_reg += MAC_MACA_INC; + XGMAC_IOWRITE(pdata, *mac_reg, mac_addr_lo); + *mac_reg += MAC_MACA_INC; +} - i++; - } +static void xgbe_set_mac_addn_addrs(struct xgbe_prv_data *pdata) +{ + struct net_device *netdev = pdata->netdev; + struct netdev_hw_addr *ha; + unsigned int mac_reg; + unsigned int addn_macs; + + mac_reg = MAC_MACA1HR; + addn_macs = pdata->hw_feat.addn_mac; - if (!am_mode) { - netdev_for_each_mc_addr(ha, pdata->netdev) { - mac_addr_lo = 0; - mac_addr_hi = 0; - mac_addr = (u8 *)&mac_addr_lo; - mac_addr[0] = ha->addr[0]; - mac_addr[1] = ha->addr[1]; - mac_addr[2] = ha->addr[2]; - mac_addr[3] = ha->addr[3]; - mac_addr = (u8 *)&mac_addr_hi; - mac_addr[0] = ha->addr[4]; - mac_addr[1] = ha->addr[5]; - - DBGPR(" adding multicast address %pM at 0x%04x\n", - ha->addr, mac_reg); - - XGMAC_SET_BITS(mac_addr_hi, MAC_MACA1HR, AE, 1); - - XGMAC_IOWRITE(pdata, mac_reg, mac_addr_hi); - mac_reg += MAC_MACA_INC; - XGMAC_IOWRITE(pdata, mac_reg, mac_addr_lo); - mac_reg += MAC_MACA_INC; - - i++; + if (netdev_uc_count(netdev) > addn_macs) { + xgbe_set_promiscuous_mode(pdata, 1); + } else { + netdev_for_each_uc_addr(ha, netdev) { + xgbe_set_mac_reg(pdata, ha, &mac_reg); + addn_macs--; + } + + if (netdev_mc_count(netdev) > addn_macs) { + xgbe_set_all_multicast_mode(pdata, 1); + } else { + netdev_for_each_mc_addr(ha, netdev) { + xgbe_set_mac_reg(pdata, ha, &mac_reg); + addn_macs--; + } } } /* Clear remaining additional MAC address entries */ - for (; i < pdata->hw_feat.addn_mac; i++) { - XGMAC_IOWRITE(pdata, mac_reg, 0); - mac_reg += MAC_MACA_INC; - XGMAC_IOWRITE(pdata, mac_reg, 0); - mac_reg += MAC_MACA_INC; + while (addn_macs--) + xgbe_set_mac_reg(pdata, NULL, &mac_reg); +} + +static void xgbe_set_mac_hash_table(struct xgbe_prv_data *pdata) +{ + struct net_device *netdev = pdata->netdev; + struct netdev_hw_addr *ha; + unsigned int hash_reg; + unsigned int hash_table_shift, hash_table_count; + u32 hash_table[XGBE_MAC_HASH_TABLE_SIZE]; + u32 crc; + unsigned int i; + + hash_table_shift = 26 - (pdata->hw_feat.hash_table_size >> 7); + hash_table_count = pdata->hw_feat.hash_table_size / 32; + memset(hash_table, 0, sizeof(hash_table)); + + /* Build the MAC Hash Table register values */ + netdev_for_each_uc_addr(ha, netdev) { + crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN)); + crc >>= hash_table_shift; + hash_table[crc >> 5] |= (1 << (crc & 0x1f)); + } + + netdev_for_each_mc_addr(ha, netdev) { + crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN)); + crc >>= hash_table_shift; + hash_table[crc >> 5] |= (1 << (crc & 0x1f)); } + /* Set the MAC Hash Table registers */ + hash_reg = MAC_HTR0; + for (i = 0; i < hash_table_count; i++) { + XGMAC_IOWRITE(pdata, hash_reg, hash_table[i]); + hash_reg += MAC_HTR_INC; + } +} + +static int xgbe_add_mac_addresses(struct xgbe_prv_data *pdata) +{ + if (pdata->hw_feat.hash_table_size) + xgbe_set_mac_hash_table(pdata); + else + xgbe_set_mac_addn_addrs(pdata); + return 0; } @@ -1606,6 +1638,13 @@ static void xgbe_config_flow_control_threshold(struct xgbe_prv_data *pdata) static void xgbe_config_mac_address(struct xgbe_prv_data *pdata) { xgbe_set_mac_address(pdata, pdata->netdev->dev_addr); + + /* Filtering is done using perfect filtering and hash filtering */ + if (pdata->hw_feat.hash_table_size) { + XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HPF, 1); + XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HUC, 1); + XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HMC, 1); + } } static void xgbe_config_jumbo_enable(struct xgbe_prv_data *pdata) @@ -2202,7 +2241,7 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) hw_if->set_promiscuous_mode = xgbe_set_promiscuous_mode; hw_if->set_all_multicast_mode = xgbe_set_all_multicast_mode; - hw_if->set_addn_mac_addrs = xgbe_set_addn_mac_addrs; + hw_if->add_mac_addresses = xgbe_add_mac_addresses; hw_if->set_mac_address = xgbe_set_mac_address; hw_if->enable_rx_csum = xgbe_enable_rx_csum; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 2acc37c07d9b..72dd61166a1c 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -378,6 +378,21 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) hw_feat->pps_out_num = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, PPSOUTNUM); hw_feat->aux_snap_num = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, AUXSNAPNUM); + /* Translate the Hash Table size into actual number */ + switch (hw_feat->hash_table_size) { + case 0: + break; + case 1: + hw_feat->hash_table_size = 64; + break; + case 2: + hw_feat->hash_table_size = 128; + break; + case 3: + hw_feat->hash_table_size = 256; + break; + } + /* The Queue and Channel counts are zero based so increment them * to get the actual number */ @@ -912,18 +927,10 @@ static void xgbe_set_rx_mode(struct net_device *netdev) pr_mode = ((netdev->flags & IFF_PROMISC) != 0); am_mode = ((netdev->flags & IFF_ALLMULTI) != 0); - if (netdev_uc_count(netdev) > pdata->hw_feat.addn_mac) - pr_mode = 1; - if (netdev_mc_count(netdev) > pdata->hw_feat.addn_mac) - am_mode = 1; - if ((netdev_uc_count(netdev) + netdev_mc_count(netdev)) > - pdata->hw_feat.addn_mac) - pr_mode = 1; - hw_if->set_promiscuous_mode(pdata, pr_mode); hw_if->set_all_multicast_mode(pdata, am_mode); - if (!pr_mode) - hw_if->set_addn_mac_addrs(pdata, am_mode); + + hw_if->add_mac_addresses(pdata); DBGPR("<--xgbe_set_rx_mode\n"); } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index c3a48b7c2aed..b411ac557c47 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -397,6 +397,8 @@ static int xgbe_probe(struct platform_device *pdev) netdev->features |= netdev->hw_features; pdata->netdev_features = netdev->features; + netdev->priv_flags |= IFF_UNICAST_FLT; + xgbe_init_rx_coalesce(pdata); xgbe_init_tx_coalesce(pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 3cb911f39b60..a2d5f5f5d8b7 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -191,6 +191,8 @@ /* Flow control queue count */ #define XGMAC_MAX_FLOW_CONTROL_QUEUES 8 +/* Maximum MAC address hash table size (256 bits = 8 bytes) */ +#define XGBE_MAC_HASH_TABLE_SIZE 8 struct xgbe_prv_data; @@ -387,7 +389,7 @@ struct xgbe_hw_if { int (*set_promiscuous_mode)(struct xgbe_prv_data *, unsigned int); int (*set_all_multicast_mode)(struct xgbe_prv_data *, unsigned int); - int (*set_addn_mac_addrs)(struct xgbe_prv_data *, unsigned int); + int (*add_mac_addresses)(struct xgbe_prv_data *); int (*set_mac_address)(struct xgbe_prv_data *, u8 *addr); int (*enable_rx_csum)(struct xgbe_prv_data *); -- cgit v1.2.3 From 66f95c35c413f674a835034dc667099b44225df2 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 24 Jun 2014 16:19:35 -0500 Subject: amd-xgbe: Resolve checkpatch warning about sscanf usage Checkpatch issued a warning preferring to use kstrto when using a single variable sscanf. Change the sscanf invocation to a kstrtouint call. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c index 6bb76d5c817b..81198587a6c6 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c @@ -151,7 +151,7 @@ static ssize_t xgbe_common_write(const char __user *buffer, size_t count, { char workarea[32]; ssize_t len; - unsigned int scan_value; + int ret; if (*ppos != 0) return 0; @@ -165,10 +165,9 @@ static ssize_t xgbe_common_write(const char __user *buffer, size_t count, return len; workarea[len] = '\0'; - if (sscanf(workarea, "%x", &scan_value) == 1) - *value = scan_value; - else - return -EIO; + ret = kstrtouint(workarea, 0, value); + if (ret) + return ret; return len; } -- cgit v1.2.3 From 83e96d443b372611adf19e4171d41deb1d8760cf Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 19 Jun 2014 20:47:14 +0200 Subject: netfilter: log: split family specific code to nf_log_{ip,ip6,common}.c files The plain text logging is currently embedded into the xt_LOG target. In order to be able to use the plain text logging from nft_log, as a first step, this patch moves the family specific code to the following files and Kconfig symbols: 1) net/ipv4/netfilter/nf_log_ip.c: CONFIG_NF_LOG_IPV4 2) net/ipv6/netfilter/nf_log_ip6.c: CONFIG_NF_LOG_IPV6 3) net/netfilter/nf_log_common.c: CONFIG_NF_LOG_COMMON These new modules will be required by xt_LOG and nft_log. This patch is based on original patch from Arturo Borrero Gonzalez. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_log.h | 28 ++ net/ipv4/netfilter/Kconfig | 5 + net/ipv4/netfilter/Makefile | 3 + net/ipv4/netfilter/nf_log_ipv4.c | 385 +++++++++++++++++ net/ipv6/netfilter/Kconfig | 5 + net/ipv6/netfilter/Makefile | 3 + net/ipv6/netfilter/nf_log_ipv6.c | 417 +++++++++++++++++++ net/netfilter/Kconfig | 6 + net/netfilter/Makefile | 3 + net/netfilter/nf_log_common.c | 187 +++++++++ net/netfilter/xt_LOG.c | 879 +-------------------------------------- 11 files changed, 1047 insertions(+), 874 deletions(-) create mode 100644 net/ipv4/netfilter/nf_log_ipv4.c create mode 100644 net/ipv6/netfilter/nf_log_ipv6.c create mode 100644 net/netfilter/nf_log_common.c diff --git a/include/net/netfilter/nf_log.h b/include/net/netfilter/nf_log.h index aaec845de106..bba354e78f49 100644 --- a/include/net/netfilter/nf_log.h +++ b/include/net/netfilter/nf_log.h @@ -78,4 +78,32 @@ struct nf_log_buf *nf_log_buf_open(void); __printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...); void nf_log_buf_close(struct nf_log_buf *m); +void nf_log_ip_packet(struct net *net, u_int8_t pf, + unsigned int hooknum, const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix); + +void nf_log_ip6_packet(struct net *net, u_int8_t pf, + unsigned int hooknum, const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix); + +/* common logging functions */ +int nf_log_dump_udp_header(struct nf_log_buf *m, const struct sk_buff *skb, + u8 proto, int fragment, unsigned int offset); +int nf_log_dump_tcp_header(struct nf_log_buf *m, const struct sk_buff *skb, + u8 proto, int fragment, unsigned int offset, + unsigned int logflags); +void nf_log_dump_sk_uid_gid(struct nf_log_buf *m, struct sock *sk); +void nf_log_dump_packet_common(struct nf_log_buf *m, u_int8_t pf, + unsigned int hooknum, const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix); + #endif /* _NF_LOG_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 730faacbc5f8..0c980293d225 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -159,6 +159,11 @@ config IP_NF_TARGET_SYNPROXY To compile it as a module, choose M here. If unsure, say N. +config NF_LOG_IPV4 + tristate "IPv4 packet logging" + default m if NETFILTER_ADVANCED=n + select NF_LOG_COMMON + # NAT + specific targets: nf_conntrack config NF_NAT_IPV4 tristate "IPv4 NAT" diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 90b82405331e..730e0c1ead90 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -19,6 +19,9 @@ obj-$(CONFIG_NF_NAT_IPV4) += nf_nat_ipv4.o # defrag obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o +# logging +obj-$(CONFIG_NF_LOG_IPV4) += nf_log_ipv4.o + # NAT helpers (nf_conntrack) obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o diff --git a/net/ipv4/netfilter/nf_log_ipv4.c b/net/ipv4/netfilter/nf_log_ipv4.c new file mode 100644 index 000000000000..7e69a401a29e --- /dev/null +++ b/net/ipv4/netfilter/nf_log_ipv4.c @@ -0,0 +1,385 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2004 Netfilter Core Team + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct nf_loginfo default_loginfo = { + .type = NF_LOG_TYPE_LOG, + .u = { + .log = { + .level = 5, + .logflags = NF_LOG_MASK, + }, + }, +}; + +/* One level of recursion won't kill us */ +static void dump_ipv4_packet(struct nf_log_buf *m, + const struct nf_loginfo *info, + const struct sk_buff *skb, unsigned int iphoff) +{ + struct iphdr _iph; + const struct iphdr *ih; + unsigned int logflags; + + if (info->type == NF_LOG_TYPE_LOG) + logflags = info->u.log.logflags; + else + logflags = NF_LOG_MASK; + + ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); + if (ih == NULL) { + nf_log_buf_add(m, "TRUNCATED"); + return; + } + + /* Important fields: + * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ + /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ + nf_log_buf_add(m, "SRC=%pI4 DST=%pI4 ", &ih->saddr, &ih->daddr); + + /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ + nf_log_buf_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", + ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, + ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); + + /* Max length: 6 "CE DF MF " */ + if (ntohs(ih->frag_off) & IP_CE) + nf_log_buf_add(m, "CE "); + if (ntohs(ih->frag_off) & IP_DF) + nf_log_buf_add(m, "DF "); + if (ntohs(ih->frag_off) & IP_MF) + nf_log_buf_add(m, "MF "); + + /* Max length: 11 "FRAG:65535 " */ + if (ntohs(ih->frag_off) & IP_OFFSET) + nf_log_buf_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); + + if ((logflags & XT_LOG_IPOPT) && + ih->ihl * 4 > sizeof(struct iphdr)) { + const unsigned char *op; + unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; + unsigned int i, optsize; + + optsize = ih->ihl * 4 - sizeof(struct iphdr); + op = skb_header_pointer(skb, iphoff+sizeof(_iph), + optsize, _opt); + if (op == NULL) { + nf_log_buf_add(m, "TRUNCATED"); + return; + } + + /* Max length: 127 "OPT (" 15*4*2chars ") " */ + nf_log_buf_add(m, "OPT ("); + for (i = 0; i < optsize; i++) + nf_log_buf_add(m, "%02X", op[i]); + nf_log_buf_add(m, ") "); + } + + switch (ih->protocol) { + case IPPROTO_TCP: + if (nf_log_dump_tcp_header(m, skb, ih->protocol, + ntohs(ih->frag_off) & IP_OFFSET, + iphoff+ih->ihl*4, logflags)) + return; + break; + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + if (nf_log_dump_udp_header(m, skb, ih->protocol, + ntohs(ih->frag_off) & IP_OFFSET, + iphoff+ih->ihl*4)) + return; + break; + case IPPROTO_ICMP: { + struct icmphdr _icmph; + const struct icmphdr *ich; + static const size_t required_len[NR_ICMP_TYPES+1] + = { [ICMP_ECHOREPLY] = 4, + [ICMP_DEST_UNREACH] + = 8 + sizeof(struct iphdr), + [ICMP_SOURCE_QUENCH] + = 8 + sizeof(struct iphdr), + [ICMP_REDIRECT] + = 8 + sizeof(struct iphdr), + [ICMP_ECHO] = 4, + [ICMP_TIME_EXCEEDED] + = 8 + sizeof(struct iphdr), + [ICMP_PARAMETERPROB] + = 8 + sizeof(struct iphdr), + [ICMP_TIMESTAMP] = 20, + [ICMP_TIMESTAMPREPLY] = 20, + [ICMP_ADDRESS] = 12, + [ICMP_ADDRESSREPLY] = 12 }; + + /* Max length: 11 "PROTO=ICMP " */ + nf_log_buf_add(m, "PROTO=ICMP "); + + if (ntohs(ih->frag_off) & IP_OFFSET) + break; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, + sizeof(_icmph), &_icmph); + if (ich == NULL) { + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + /* Max length: 18 "TYPE=255 CODE=255 " */ + nf_log_buf_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + if (ich->type <= NR_ICMP_TYPES && + required_len[ich->type] && + skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + switch (ich->type) { + case ICMP_ECHOREPLY: + case ICMP_ECHO: + /* Max length: 19 "ID=65535 SEQ=65535 " */ + nf_log_buf_add(m, "ID=%u SEQ=%u ", + ntohs(ich->un.echo.id), + ntohs(ich->un.echo.sequence)); + break; + + case ICMP_PARAMETERPROB: + /* Max length: 14 "PARAMETER=255 " */ + nf_log_buf_add(m, "PARAMETER=%u ", + ntohl(ich->un.gateway) >> 24); + break; + case ICMP_REDIRECT: + /* Max length: 24 "GATEWAY=255.255.255.255 " */ + nf_log_buf_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); + /* Fall through */ + case ICMP_DEST_UNREACH: + case ICMP_SOURCE_QUENCH: + case ICMP_TIME_EXCEEDED: + /* Max length: 3+maxlen */ + if (!iphoff) { /* Only recurse once. */ + nf_log_buf_add(m, "["); + dump_ipv4_packet(m, info, skb, + iphoff + ih->ihl*4+sizeof(_icmph)); + nf_log_buf_add(m, "] "); + } + + /* Max length: 10 "MTU=65535 " */ + if (ich->type == ICMP_DEST_UNREACH && + ich->code == ICMP_FRAG_NEEDED) { + nf_log_buf_add(m, "MTU=%u ", + ntohs(ich->un.frag.mtu)); + } + } + break; + } + /* Max Length */ + case IPPROTO_AH: { + struct ip_auth_hdr _ahdr; + const struct ip_auth_hdr *ah; + + if (ntohs(ih->frag_off) & IP_OFFSET) + break; + + /* Max length: 9 "PROTO=AH " */ + nf_log_buf_add(m, "PROTO=AH "); + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + ah = skb_header_pointer(skb, iphoff+ih->ihl*4, + sizeof(_ahdr), &_ahdr); + if (ah == NULL) { + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + /* Length: 15 "SPI=0xF1234567 " */ + nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi)); + break; + } + case IPPROTO_ESP: { + struct ip_esp_hdr _esph; + const struct ip_esp_hdr *eh; + + /* Max length: 10 "PROTO=ESP " */ + nf_log_buf_add(m, "PROTO=ESP "); + + if (ntohs(ih->frag_off) & IP_OFFSET) + break; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + eh = skb_header_pointer(skb, iphoff+ih->ihl*4, + sizeof(_esph), &_esph); + if (eh == NULL) { + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", + skb->len - iphoff - ih->ihl*4); + break; + } + + /* Length: 15 "SPI=0xF1234567 " */ + nf_log_buf_add(m, "SPI=0x%x ", ntohl(eh->spi)); + break; + } + /* Max length: 10 "PROTO 255 " */ + default: + nf_log_buf_add(m, "PROTO=%u ", ih->protocol); + } + + /* Max length: 15 "UID=4294967295 " */ + if ((logflags & XT_LOG_UID) && !iphoff) + nf_log_dump_sk_uid_gid(m, skb->sk); + + /* Max length: 16 "MARK=0xFFFFFFFF " */ + if (!iphoff && skb->mark) + nf_log_buf_add(m, "MARK=0x%x ", skb->mark); + + /* Proto Max log string length */ + /* IP: 40+46+6+11+127 = 230 */ + /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ + /* UDP: 10+max(25,20) = 35 */ + /* UDPLITE: 14+max(25,20) = 39 */ + /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ + /* ESP: 10+max(25)+15 = 50 */ + /* AH: 9+max(25)+15 = 49 */ + /* unknown: 10 */ + + /* (ICMP allows recursion one level deep) */ + /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ + /* maxlen = 230+ 91 + 230 + 252 = 803 */ +} + +static void dump_ipv4_mac_header(struct nf_log_buf *m, + const struct nf_loginfo *info, + const struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + unsigned int logflags = 0; + + if (info->type == NF_LOG_TYPE_LOG) + logflags = info->u.log.logflags; + + if (!(logflags & XT_LOG_MACDECODE)) + goto fallback; + + switch (dev->type) { + case ARPHRD_ETHER: + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, + ntohs(eth_hdr(skb)->h_proto)); + return; + default: + break; + } + +fallback: + nf_log_buf_add(m, "MAC="); + if (dev->hard_header_len && + skb->mac_header != skb->network_header) { + const unsigned char *p = skb_mac_header(skb); + unsigned int i; + + nf_log_buf_add(m, "%02x", *p++); + for (i = 1; i < dev->hard_header_len; i++, p++) + nf_log_buf_add(m, ":%02x", *p); + } + nf_log_buf_add(m, " "); +} + +void nf_log_ip_packet(struct net *net, u_int8_t pf, + unsigned int hooknum, const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix) +{ + struct nf_log_buf *m; + + /* FIXME: Disabled from containers until syslog ns is supported */ + if (!net_eq(net, &init_net)) + return; + + m = nf_log_buf_open(); + + if (!loginfo) + loginfo = &default_loginfo; + + nf_log_dump_packet_common(m, pf, hooknum, skb, in, + out, loginfo, prefix); + + if (in != NULL) + dump_ipv4_mac_header(m, loginfo, skb); + + dump_ipv4_packet(m, loginfo, skb, 0); + + nf_log_buf_close(m); +} +EXPORT_SYMBOL_GPL(nf_log_ip_packet); + +static struct nf_logger nf_ip_logger __read_mostly = { + .name = "nf_log_ipv4", + .type = NF_LOG_TYPE_LOG, + .logfn = nf_log_ip_packet, + .me = THIS_MODULE, +}; + +static int __net_init nf_log_ipv4_net_init(struct net *net) +{ + nf_log_set(net, NFPROTO_IPV4, &nf_ip_logger); + return 0; +} + +static void __net_exit nf_log_ipv4_net_exit(struct net *net) +{ + nf_log_unset(net, &nf_ip_logger); +} + +static struct pernet_operations nf_log_ipv4_net_ops = { + .init = nf_log_ipv4_net_init, + .exit = nf_log_ipv4_net_exit, +}; + +static int __init nf_log_ipv4_init(void) +{ + int ret; + + ret = register_pernet_subsys(&nf_log_ipv4_net_ops); + if (ret < 0) + return ret; + + nf_log_register(NFPROTO_IPV4, &nf_ip_logger); + return 0; +} + +static void __exit nf_log_ipv4_exit(void) +{ + unregister_pernet_subsys(&nf_log_ipv4_net_ops); + nf_log_unregister(&nf_ip_logger); +} + +module_init(nf_log_ipv4_init); +module_exit(nf_log_ipv4_exit); + +MODULE_AUTHOR("Netfilter Core Team "); +MODULE_DESCRIPTION("Netfilter IPv4 packet logging"); +MODULE_LICENSE("GPL"); diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 4bff1f297e39..1537130e9f5b 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -227,6 +227,11 @@ config IP6_NF_SECURITY If unsure, say N. +config NF_LOG_IPV6 + tristate "IPv6 packet logging" + depends on NETFILTER_ADVANCED + select NF_LOG_COMMON + config NF_NAT_IPV6 tristate "IPv6 NAT" depends on NF_CONNTRACK_IPV6 diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 70d3dd66f2cd..c0b263104ed2 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile @@ -23,6 +23,9 @@ obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o +# logging +obj-$(CONFIG_NF_LOG_IPV6) += nf_log_ipv6.o + # nf_tables obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o diff --git a/net/ipv6/netfilter/nf_log_ipv6.c b/net/ipv6/netfilter/nf_log_ipv6.c new file mode 100644 index 000000000000..804060946d2b --- /dev/null +++ b/net/ipv6/netfilter/nf_log_ipv6.c @@ -0,0 +1,417 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2004 Netfilter Core Team + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static struct nf_loginfo default_loginfo = { + .type = NF_LOG_TYPE_LOG, + .u = { + .log = { + .level = 5, + .logflags = NF_LOG_MASK, + }, + }, +}; + +/* One level of recursion won't kill us */ +static void dump_ipv6_packet(struct nf_log_buf *m, + const struct nf_loginfo *info, + const struct sk_buff *skb, unsigned int ip6hoff, + int recurse) +{ + u_int8_t currenthdr; + int fragment; + struct ipv6hdr _ip6h; + const struct ipv6hdr *ih; + unsigned int ptr; + unsigned int hdrlen = 0; + unsigned int logflags; + + if (info->type == NF_LOG_TYPE_LOG) + logflags = info->u.log.logflags; + else + logflags = NF_LOG_MASK; + + ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); + if (ih == NULL) { + nf_log_buf_add(m, "TRUNCATED"); + return; + } + + /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ + nf_log_buf_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); + + /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ + nf_log_buf_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", + ntohs(ih->payload_len) + sizeof(struct ipv6hdr), + (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, + ih->hop_limit, + (ntohl(*(__be32 *)ih) & 0x000fffff)); + + fragment = 0; + ptr = ip6hoff + sizeof(struct ipv6hdr); + currenthdr = ih->nexthdr; + while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) { + struct ipv6_opt_hdr _hdr; + const struct ipv6_opt_hdr *hp; + + hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); + if (hp == NULL) { + nf_log_buf_add(m, "TRUNCATED"); + return; + } + + /* Max length: 48 "OPT (...) " */ + if (logflags & XT_LOG_IPOPT) + nf_log_buf_add(m, "OPT ( "); + + switch (currenthdr) { + case IPPROTO_FRAGMENT: { + struct frag_hdr _fhdr; + const struct frag_hdr *fh; + + nf_log_buf_add(m, "FRAG:"); + fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), + &_fhdr); + if (fh == NULL) { + nf_log_buf_add(m, "TRUNCATED "); + return; + } + + /* Max length: 6 "65535 " */ + nf_log_buf_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); + + /* Max length: 11 "INCOMPLETE " */ + if (fh->frag_off & htons(0x0001)) + nf_log_buf_add(m, "INCOMPLETE "); + + nf_log_buf_add(m, "ID:%08x ", + ntohl(fh->identification)); + + if (ntohs(fh->frag_off) & 0xFFF8) + fragment = 1; + + hdrlen = 8; + + break; + } + case IPPROTO_DSTOPTS: + case IPPROTO_ROUTING: + case IPPROTO_HOPOPTS: + if (fragment) { + if (logflags & XT_LOG_IPOPT) + nf_log_buf_add(m, ")"); + return; + } + hdrlen = ipv6_optlen(hp); + break; + /* Max Length */ + case IPPROTO_AH: + if (logflags & XT_LOG_IPOPT) { + struct ip_auth_hdr _ahdr; + const struct ip_auth_hdr *ah; + + /* Max length: 3 "AH " */ + nf_log_buf_add(m, "AH "); + + if (fragment) { + nf_log_buf_add(m, ")"); + return; + } + + ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), + &_ahdr); + if (ah == NULL) { + /* + * Max length: 26 "INCOMPLETE [65535 + * bytes] )" + */ + nf_log_buf_add(m, "INCOMPLETE [%u bytes] )", + skb->len - ptr); + return; + } + + /* Length: 15 "SPI=0xF1234567 */ + nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi)); + + } + + hdrlen = (hp->hdrlen+2)<<2; + break; + case IPPROTO_ESP: + if (logflags & XT_LOG_IPOPT) { + struct ip_esp_hdr _esph; + const struct ip_esp_hdr *eh; + + /* Max length: 4 "ESP " */ + nf_log_buf_add(m, "ESP "); + + if (fragment) { + nf_log_buf_add(m, ")"); + return; + } + + /* + * Max length: 26 "INCOMPLETE [65535 bytes] )" + */ + eh = skb_header_pointer(skb, ptr, sizeof(_esph), + &_esph); + if (eh == NULL) { + nf_log_buf_add(m, "INCOMPLETE [%u bytes] )", + skb->len - ptr); + return; + } + + /* Length: 16 "SPI=0xF1234567 )" */ + nf_log_buf_add(m, "SPI=0x%x )", + ntohl(eh->spi)); + } + return; + default: + /* Max length: 20 "Unknown Ext Hdr 255" */ + nf_log_buf_add(m, "Unknown Ext Hdr %u", currenthdr); + return; + } + if (logflags & XT_LOG_IPOPT) + nf_log_buf_add(m, ") "); + + currenthdr = hp->nexthdr; + ptr += hdrlen; + } + + switch (currenthdr) { + case IPPROTO_TCP: + if (nf_log_dump_tcp_header(m, skb, currenthdr, fragment, + ptr, logflags)) + return; + break; + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + if (nf_log_dump_udp_header(m, skb, currenthdr, fragment, ptr)) + return; + break; + case IPPROTO_ICMPV6: { + struct icmp6hdr _icmp6h; + const struct icmp6hdr *ic; + + /* Max length: 13 "PROTO=ICMPv6 " */ + nf_log_buf_add(m, "PROTO=ICMPv6 "); + + if (fragment) + break; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); + if (ic == NULL) { + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", + skb->len - ptr); + return; + } + + /* Max length: 18 "TYPE=255 CODE=255 " */ + nf_log_buf_add(m, "TYPE=%u CODE=%u ", + ic->icmp6_type, ic->icmp6_code); + + switch (ic->icmp6_type) { + case ICMPV6_ECHO_REQUEST: + case ICMPV6_ECHO_REPLY: + /* Max length: 19 "ID=65535 SEQ=65535 " */ + nf_log_buf_add(m, "ID=%u SEQ=%u ", + ntohs(ic->icmp6_identifier), + ntohs(ic->icmp6_sequence)); + break; + case ICMPV6_MGM_QUERY: + case ICMPV6_MGM_REPORT: + case ICMPV6_MGM_REDUCTION: + break; + + case ICMPV6_PARAMPROB: + /* Max length: 17 "POINTER=ffffffff " */ + nf_log_buf_add(m, "POINTER=%08x ", + ntohl(ic->icmp6_pointer)); + /* Fall through */ + case ICMPV6_DEST_UNREACH: + case ICMPV6_PKT_TOOBIG: + case ICMPV6_TIME_EXCEED: + /* Max length: 3+maxlen */ + if (recurse) { + nf_log_buf_add(m, "["); + dump_ipv6_packet(m, info, skb, + ptr + sizeof(_icmp6h), 0); + nf_log_buf_add(m, "] "); + } + + /* Max length: 10 "MTU=65535 " */ + if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) { + nf_log_buf_add(m, "MTU=%u ", + ntohl(ic->icmp6_mtu)); + } + } + break; + } + /* Max length: 10 "PROTO=255 " */ + default: + nf_log_buf_add(m, "PROTO=%u ", currenthdr); + } + + /* Max length: 15 "UID=4294967295 " */ + if ((logflags & XT_LOG_UID) && recurse) + nf_log_dump_sk_uid_gid(m, skb->sk); + + /* Max length: 16 "MARK=0xFFFFFFFF " */ + if (recurse && skb->mark) + nf_log_buf_add(m, "MARK=0x%x ", skb->mark); +} + +static void dump_ipv6_mac_header(struct nf_log_buf *m, + const struct nf_loginfo *info, + const struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + unsigned int logflags = 0; + + if (info->type == NF_LOG_TYPE_LOG) + logflags = info->u.log.logflags; + + if (!(logflags & XT_LOG_MACDECODE)) + goto fallback; + + switch (dev->type) { + case ARPHRD_ETHER: + nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, + ntohs(eth_hdr(skb)->h_proto)); + return; + default: + break; + } + +fallback: + nf_log_buf_add(m, "MAC="); + if (dev->hard_header_len && + skb->mac_header != skb->network_header) { + const unsigned char *p = skb_mac_header(skb); + unsigned int len = dev->hard_header_len; + unsigned int i; + + if (dev->type == ARPHRD_SIT) { + p -= ETH_HLEN; + + if (p < skb->head) + p = NULL; + } + + if (p != NULL) { + nf_log_buf_add(m, "%02x", *p++); + for (i = 1; i < len; i++) + nf_log_buf_add(m, ":%02x", *p++); + } + nf_log_buf_add(m, " "); + + if (dev->type == ARPHRD_SIT) { + const struct iphdr *iph = + (struct iphdr *)skb_mac_header(skb); + nf_log_buf_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, + &iph->daddr); + } + } else { + nf_log_buf_add(m, " "); + } +} + +void nf_log_ip6_packet(struct net *net, u_int8_t pf, + unsigned int hooknum, const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix) +{ + struct nf_log_buf *m; + + /* FIXME: Disabled from containers until syslog ns is supported */ + if (!net_eq(net, &init_net)) + return; + + m = nf_log_buf_open(); + + if (!loginfo) + loginfo = &default_loginfo; + + nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, + loginfo, prefix); + + if (in != NULL) + dump_ipv6_mac_header(m, loginfo, skb); + + dump_ipv6_packet(m, loginfo, skb, skb_network_offset(skb), 1); + + nf_log_buf_close(m); +} +EXPORT_SYMBOL_GPL(nf_log_ip6_packet); + +static struct nf_logger nf_ip6_logger __read_mostly = { + .name = "nf_log_ipv6", + .type = NF_LOG_TYPE_LOG, + .logfn = nf_log_ip6_packet, + .me = THIS_MODULE, +}; + +static int __net_init nf_log_ipv6_net_init(struct net *net) +{ + nf_log_set(net, NFPROTO_IPV6, &nf_ip6_logger); + return 0; +} + +static void __net_exit nf_log_ipv6_net_exit(struct net *net) +{ + nf_log_unset(net, &nf_ip6_logger); +} + +static struct pernet_operations nf_log_ipv6_net_ops = { + .init = nf_log_ipv6_net_init, + .exit = nf_log_ipv6_net_exit, +}; + +static int __init nf_log_ipv6_init(void) +{ + int ret; + + ret = register_pernet_subsys(&nf_log_ipv6_net_ops); + if (ret < 0) + return ret; + + nf_log_register(NFPROTO_IPV6, &nf_ip6_logger); + return 0; +} + +static void __exit nf_log_ipv6_exit(void) +{ + unregister_pernet_subsys(&nf_log_ipv6_net_ops); + nf_log_unregister(&nf_ip6_logger); +} + +module_init(nf_log_ipv6_init); +module_exit(nf_log_ipv6_exit); + +MODULE_AUTHOR("Netfilter Core Team "); +MODULE_DESCRIPTION("Netfilter IPv4 packet logging"); +MODULE_LICENSE("GPL"); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index e9410d17619d..f17b273c9082 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -359,6 +359,9 @@ config NETFILTER_NETLINK_QUEUE_CT If this option is enabled, NFQUEUE can include Connection Tracking information together with the packet is the enqueued via NFNETLINK. +config NF_LOG_COMMON + tristate + config NF_NAT tristate @@ -744,6 +747,9 @@ config NETFILTER_XT_TARGET_LED config NETFILTER_XT_TARGET_LOG tristate "LOG target support" + select NF_LOG + select NF_LOG_IPV4 + select NF_LOG_IPV6 default m if NETFILTER_ADVANCED=n help This option adds a `LOG' target, which allows you to create rules in diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index bffdad774da7..8308624a406a 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -47,6 +47,9 @@ obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o nf_nat-y := nf_nat_core.o nf_nat_proto_unknown.o nf_nat_proto_common.o \ nf_nat_proto_udp.o nf_nat_proto_tcp.o nf_nat_helper.o +# generic transport layer logging +obj-$(CONFIG_NF_LOG_COMMON) += nf_log_common.o + obj-$(CONFIG_NF_NAT) += nf_nat.o # NAT protocols (nf_nat) diff --git a/net/netfilter/nf_log_common.c b/net/netfilter/nf_log_common.c new file mode 100644 index 000000000000..eeb8ef4ff1a3 --- /dev/null +++ b/net/netfilter/nf_log_common.c @@ -0,0 +1,187 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2004 Netfilter Core Team + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int nf_log_dump_udp_header(struct nf_log_buf *m, const struct sk_buff *skb, + u8 proto, int fragment, unsigned int offset) +{ + struct udphdr _udph; + const struct udphdr *uh; + + if (proto == IPPROTO_UDP) + /* Max length: 10 "PROTO=UDP " */ + nf_log_buf_add(m, "PROTO=UDP "); + else /* Max length: 14 "PROTO=UDPLITE " */ + nf_log_buf_add(m, "PROTO=UDPLITE "); + + if (fragment) + goto out; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); + if (uh == NULL) { + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); + + return 1; + } + + /* Max length: 20 "SPT=65535 DPT=65535 " */ + nf_log_buf_add(m, "SPT=%u DPT=%u LEN=%u ", + ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); + +out: + return 0; +} +EXPORT_SYMBOL_GPL(nf_log_dump_udp_header); + +int nf_log_dump_tcp_header(struct nf_log_buf *m, const struct sk_buff *skb, + u8 proto, int fragment, unsigned int offset, + unsigned int logflags) +{ + struct tcphdr _tcph; + const struct tcphdr *th; + + /* Max length: 10 "PROTO=TCP " */ + nf_log_buf_add(m, "PROTO=TCP "); + + if (fragment) + return 0; + + /* Max length: 25 "INCOMPLETE [65535 bytes] " */ + th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); + if (th == NULL) { + nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); + return 1; + } + + /* Max length: 20 "SPT=65535 DPT=65535 " */ + nf_log_buf_add(m, "SPT=%u DPT=%u ", + ntohs(th->source), ntohs(th->dest)); + /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ + if (logflags & XT_LOG_TCPSEQ) { + nf_log_buf_add(m, "SEQ=%u ACK=%u ", + ntohl(th->seq), ntohl(th->ack_seq)); + } + + /* Max length: 13 "WINDOW=65535 " */ + nf_log_buf_add(m, "WINDOW=%u ", ntohs(th->window)); + /* Max length: 9 "RES=0x3C " */ + nf_log_buf_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & + TCP_RESERVED_BITS) >> 22)); + /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ + if (th->cwr) + nf_log_buf_add(m, "CWR "); + if (th->ece) + nf_log_buf_add(m, "ECE "); + if (th->urg) + nf_log_buf_add(m, "URG "); + if (th->ack) + nf_log_buf_add(m, "ACK "); + if (th->psh) + nf_log_buf_add(m, "PSH "); + if (th->rst) + nf_log_buf_add(m, "RST "); + if (th->syn) + nf_log_buf_add(m, "SYN "); + if (th->fin) + nf_log_buf_add(m, "FIN "); + /* Max length: 11 "URGP=65535 " */ + nf_log_buf_add(m, "URGP=%u ", ntohs(th->urg_ptr)); + + if ((logflags & XT_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) { + u_int8_t _opt[60 - sizeof(struct tcphdr)]; + const u_int8_t *op; + unsigned int i; + unsigned int optsize = th->doff*4 - sizeof(struct tcphdr); + + op = skb_header_pointer(skb, offset + sizeof(struct tcphdr), + optsize, _opt); + if (op == NULL) { + nf_log_buf_add(m, "OPT (TRUNCATED)"); + return 1; + } + + /* Max length: 127 "OPT (" 15*4*2chars ") " */ + nf_log_buf_add(m, "OPT ("); + for (i = 0; i < optsize; i++) + nf_log_buf_add(m, "%02X", op[i]); + + nf_log_buf_add(m, ") "); + } + + return 0; +} +EXPORT_SYMBOL_GPL(nf_log_dump_tcp_header); + +void nf_log_dump_sk_uid_gid(struct nf_log_buf *m, struct sock *sk) +{ + if (!sk || sk->sk_state == TCP_TIME_WAIT) + return; + + read_lock_bh(&sk->sk_callback_lock); + if (sk->sk_socket && sk->sk_socket->file) { + const struct cred *cred = sk->sk_socket->file->f_cred; + nf_log_buf_add(m, "UID=%u GID=%u ", + from_kuid_munged(&init_user_ns, cred->fsuid), + from_kgid_munged(&init_user_ns, cred->fsgid)); + } + read_unlock_bh(&sk->sk_callback_lock); +} +EXPORT_SYMBOL_GPL(nf_log_dump_sk_uid_gid); + +void +nf_log_dump_packet_common(struct nf_log_buf *m, u_int8_t pf, + unsigned int hooknum, const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, const char *prefix) +{ + nf_log_buf_add(m, KERN_SOH "%c%sIN=%s OUT=%s ", + '0' + loginfo->u.log.level, prefix, + in ? in->name : "", + out ? out->name : ""); +#ifdef CONFIG_BRIDGE_NETFILTER + if (skb->nf_bridge) { + const struct net_device *physindev; + const struct net_device *physoutdev; + + physindev = skb->nf_bridge->physindev; + if (physindev && in != physindev) + nf_log_buf_add(m, "PHYSIN=%s ", physindev->name); + physoutdev = skb->nf_bridge->physoutdev; + if (physoutdev && out != physoutdev) + nf_log_buf_add(m, "PHYSOUT=%s ", physoutdev->name); + } +#endif +} +EXPORT_SYMBOL_GPL(nf_log_dump_packet_common); + +static int __init nf_log_common_init(void) +{ + return 0; +} + +static void __exit nf_log_common_exit(void) {} + +module_init(nf_log_common_init); +module_exit(nf_log_common_exit); + +MODULE_LICENSE("GPL"); diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c index 649b85fc5463..5a6bd60e20d6 100644 --- a/net/netfilter/xt_LOG.c +++ b/net/netfilter/xt_LOG.c @@ -28,813 +28,6 @@ #include #include -static struct nf_loginfo default_loginfo = { - .type = NF_LOG_TYPE_LOG, - .u = { - .log = { - .level = 5, - .logflags = NF_LOG_MASK, - }, - }, -}; - -static int dump_udp_header(struct nf_log_buf *m, const struct sk_buff *skb, - u8 proto, int fragment, unsigned int offset) -{ - struct udphdr _udph; - const struct udphdr *uh; - - if (proto == IPPROTO_UDP) - /* Max length: 10 "PROTO=UDP " */ - nf_log_buf_add(m, "PROTO=UDP "); - else /* Max length: 14 "PROTO=UDPLITE " */ - nf_log_buf_add(m, "PROTO=UDPLITE "); - - if (fragment) - goto out; - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); - if (uh == NULL) { - nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); - - return 1; - } - - /* Max length: 20 "SPT=65535 DPT=65535 " */ - nf_log_buf_add(m, "SPT=%u DPT=%u LEN=%u ", - ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); - -out: - return 0; -} - -static int dump_tcp_header(struct nf_log_buf *m, const struct sk_buff *skb, - u8 proto, int fragment, unsigned int offset, - unsigned int logflags) -{ - struct tcphdr _tcph; - const struct tcphdr *th; - - /* Max length: 10 "PROTO=TCP " */ - nf_log_buf_add(m, "PROTO=TCP "); - - if (fragment) - return 0; - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); - if (th == NULL) { - nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); - return 1; - } - - /* Max length: 20 "SPT=65535 DPT=65535 " */ - nf_log_buf_add(m, "SPT=%u DPT=%u ", - ntohs(th->source), ntohs(th->dest)); - /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ - if (logflags & XT_LOG_TCPSEQ) { - nf_log_buf_add(m, "SEQ=%u ACK=%u ", - ntohl(th->seq), ntohl(th->ack_seq)); - } - - /* Max length: 13 "WINDOW=65535 " */ - nf_log_buf_add(m, "WINDOW=%u ", ntohs(th->window)); - /* Max length: 9 "RES=0x3C " */ - nf_log_buf_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & - TCP_RESERVED_BITS) >> 22)); - /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ - if (th->cwr) - nf_log_buf_add(m, "CWR "); - if (th->ece) - nf_log_buf_add(m, "ECE "); - if (th->urg) - nf_log_buf_add(m, "URG "); - if (th->ack) - nf_log_buf_add(m, "ACK "); - if (th->psh) - nf_log_buf_add(m, "PSH "); - if (th->rst) - nf_log_buf_add(m, "RST "); - if (th->syn) - nf_log_buf_add(m, "SYN "); - if (th->fin) - nf_log_buf_add(m, "FIN "); - /* Max length: 11 "URGP=65535 " */ - nf_log_buf_add(m, "URGP=%u ", ntohs(th->urg_ptr)); - - if ((logflags & XT_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) { - u_int8_t _opt[60 - sizeof(struct tcphdr)]; - const u_int8_t *op; - unsigned int i; - unsigned int optsize = th->doff*4 - sizeof(struct tcphdr); - - op = skb_header_pointer(skb, offset + sizeof(struct tcphdr), - optsize, _opt); - if (op == NULL) { - nf_log_buf_add(m, "OPT (TRUNCATED)"); - return 1; - } - - /* Max length: 127 "OPT (" 15*4*2chars ") " */ - nf_log_buf_add(m, "OPT ("); - for (i = 0; i < optsize; i++) - nf_log_buf_add(m, "%02X", op[i]); - - nf_log_buf_add(m, ") "); - } - - return 0; -} - -static void dump_sk_uid_gid(struct nf_log_buf *m, struct sock *sk) -{ - if (!sk || sk->sk_state == TCP_TIME_WAIT) - return; - - read_lock_bh(&sk->sk_callback_lock); - if (sk->sk_socket && sk->sk_socket->file) { - const struct cred *cred = sk->sk_socket->file->f_cred; - nf_log_buf_add(m, "UID=%u GID=%u ", - from_kuid_munged(&init_user_ns, cred->fsuid), - from_kgid_munged(&init_user_ns, cred->fsgid)); - } - read_unlock_bh(&sk->sk_callback_lock); -} - -/* One level of recursion won't kill us */ -static void dump_ipv4_packet(struct nf_log_buf *m, - const struct nf_loginfo *info, - const struct sk_buff *skb, unsigned int iphoff) -{ - struct iphdr _iph; - const struct iphdr *ih; - unsigned int logflags; - - if (info->type == NF_LOG_TYPE_LOG) - logflags = info->u.log.logflags; - else - logflags = NF_LOG_MASK; - - ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); - if (ih == NULL) { - nf_log_buf_add(m, "TRUNCATED"); - return; - } - - /* Important fields: - * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ - /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ - nf_log_buf_add(m, "SRC=%pI4 DST=%pI4 ", - &ih->saddr, &ih->daddr); - - /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ - nf_log_buf_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", - ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, - ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); - - /* Max length: 6 "CE DF MF " */ - if (ntohs(ih->frag_off) & IP_CE) - nf_log_buf_add(m, "CE "); - if (ntohs(ih->frag_off) & IP_DF) - nf_log_buf_add(m, "DF "); - if (ntohs(ih->frag_off) & IP_MF) - nf_log_buf_add(m, "MF "); - - /* Max length: 11 "FRAG:65535 " */ - if (ntohs(ih->frag_off) & IP_OFFSET) - nf_log_buf_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); - - if ((logflags & XT_LOG_IPOPT) && - ih->ihl * 4 > sizeof(struct iphdr)) { - const unsigned char *op; - unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; - unsigned int i, optsize; - - optsize = ih->ihl * 4 - sizeof(struct iphdr); - op = skb_header_pointer(skb, iphoff+sizeof(_iph), - optsize, _opt); - if (op == NULL) { - nf_log_buf_add(m, "TRUNCATED"); - return; - } - - /* Max length: 127 "OPT (" 15*4*2chars ") " */ - nf_log_buf_add(m, "OPT ("); - for (i = 0; i < optsize; i++) - nf_log_buf_add(m, "%02X", op[i]); - nf_log_buf_add(m, ") "); - } - - switch (ih->protocol) { - case IPPROTO_TCP: - if (dump_tcp_header(m, skb, ih->protocol, - ntohs(ih->frag_off) & IP_OFFSET, - iphoff+ih->ihl*4, logflags)) - return; - break; - case IPPROTO_UDP: - case IPPROTO_UDPLITE: - if (dump_udp_header(m, skb, ih->protocol, - ntohs(ih->frag_off) & IP_OFFSET, - iphoff+ih->ihl*4)) - return; - break; - case IPPROTO_ICMP: { - struct icmphdr _icmph; - const struct icmphdr *ich; - static const size_t required_len[NR_ICMP_TYPES+1] - = { [ICMP_ECHOREPLY] = 4, - [ICMP_DEST_UNREACH] - = 8 + sizeof(struct iphdr), - [ICMP_SOURCE_QUENCH] - = 8 + sizeof(struct iphdr), - [ICMP_REDIRECT] - = 8 + sizeof(struct iphdr), - [ICMP_ECHO] = 4, - [ICMP_TIME_EXCEEDED] - = 8 + sizeof(struct iphdr), - [ICMP_PARAMETERPROB] - = 8 + sizeof(struct iphdr), - [ICMP_TIMESTAMP] = 20, - [ICMP_TIMESTAMPREPLY] = 20, - [ICMP_ADDRESS] = 12, - [ICMP_ADDRESSREPLY] = 12 }; - - /* Max length: 11 "PROTO=ICMP " */ - nf_log_buf_add(m, "PROTO=ICMP "); - - if (ntohs(ih->frag_off) & IP_OFFSET) - break; - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, - sizeof(_icmph), &_icmph); - if (ich == NULL) { - nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); - break; - } - - /* Max length: 18 "TYPE=255 CODE=255 " */ - nf_log_buf_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - if (ich->type <= NR_ICMP_TYPES && - required_len[ich->type] && - skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { - nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); - break; - } - - switch (ich->type) { - case ICMP_ECHOREPLY: - case ICMP_ECHO: - /* Max length: 19 "ID=65535 SEQ=65535 " */ - nf_log_buf_add(m, "ID=%u SEQ=%u ", - ntohs(ich->un.echo.id), - ntohs(ich->un.echo.sequence)); - break; - - case ICMP_PARAMETERPROB: - /* Max length: 14 "PARAMETER=255 " */ - nf_log_buf_add(m, "PARAMETER=%u ", - ntohl(ich->un.gateway) >> 24); - break; - case ICMP_REDIRECT: - /* Max length: 24 "GATEWAY=255.255.255.255 " */ - nf_log_buf_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); - /* Fall through */ - case ICMP_DEST_UNREACH: - case ICMP_SOURCE_QUENCH: - case ICMP_TIME_EXCEEDED: - /* Max length: 3+maxlen */ - if (!iphoff) { /* Only recurse once. */ - nf_log_buf_add(m, "["); - dump_ipv4_packet(m, info, skb, - iphoff + ih->ihl*4+sizeof(_icmph)); - nf_log_buf_add(m, "] "); - } - - /* Max length: 10 "MTU=65535 " */ - if (ich->type == ICMP_DEST_UNREACH && - ich->code == ICMP_FRAG_NEEDED) { - nf_log_buf_add(m, "MTU=%u ", - ntohs(ich->un.frag.mtu)); - } - } - break; - } - /* Max Length */ - case IPPROTO_AH: { - struct ip_auth_hdr _ahdr; - const struct ip_auth_hdr *ah; - - if (ntohs(ih->frag_off) & IP_OFFSET) - break; - - /* Max length: 9 "PROTO=AH " */ - nf_log_buf_add(m, "PROTO=AH "); - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - ah = skb_header_pointer(skb, iphoff+ih->ihl*4, - sizeof(_ahdr), &_ahdr); - if (ah == NULL) { - nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); - break; - } - - /* Length: 15 "SPI=0xF1234567 " */ - nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi)); - break; - } - case IPPROTO_ESP: { - struct ip_esp_hdr _esph; - const struct ip_esp_hdr *eh; - - /* Max length: 10 "PROTO=ESP " */ - nf_log_buf_add(m, "PROTO=ESP "); - - if (ntohs(ih->frag_off) & IP_OFFSET) - break; - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - eh = skb_header_pointer(skb, iphoff+ih->ihl*4, - sizeof(_esph), &_esph); - if (eh == NULL) { - nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", - skb->len - iphoff - ih->ihl*4); - break; - } - - /* Length: 15 "SPI=0xF1234567 " */ - nf_log_buf_add(m, "SPI=0x%x ", ntohl(eh->spi)); - break; - } - /* Max length: 10 "PROTO 255 " */ - default: - nf_log_buf_add(m, "PROTO=%u ", ih->protocol); - } - - /* Max length: 15 "UID=4294967295 " */ - if ((logflags & XT_LOG_UID) && !iphoff) - dump_sk_uid_gid(m, skb->sk); - - /* Max length: 16 "MARK=0xFFFFFFFF " */ - if (!iphoff && skb->mark) - nf_log_buf_add(m, "MARK=0x%x ", skb->mark); - - /* Proto Max log string length */ - /* IP: 40+46+6+11+127 = 230 */ - /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ - /* UDP: 10+max(25,20) = 35 */ - /* UDPLITE: 14+max(25,20) = 39 */ - /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ - /* ESP: 10+max(25)+15 = 50 */ - /* AH: 9+max(25)+15 = 49 */ - /* unknown: 10 */ - - /* (ICMP allows recursion one level deep) */ - /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ - /* maxlen = 230+ 91 + 230 + 252 = 803 */ -} - -static void dump_ipv4_mac_header(struct nf_log_buf *m, - const struct nf_loginfo *info, - const struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - unsigned int logflags = 0; - - if (info->type == NF_LOG_TYPE_LOG) - logflags = info->u.log.logflags; - - if (!(logflags & XT_LOG_MACDECODE)) - goto fallback; - - switch (dev->type) { - case ARPHRD_ETHER: - nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", - eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, - ntohs(eth_hdr(skb)->h_proto)); - return; - default: - break; - } - -fallback: - nf_log_buf_add(m, "MAC="); - if (dev->hard_header_len && - skb->mac_header != skb->network_header) { - const unsigned char *p = skb_mac_header(skb); - unsigned int i; - - nf_log_buf_add(m, "%02x", *p++); - for (i = 1; i < dev->hard_header_len; i++, p++) - nf_log_buf_add(m, ":%02x", *p); - } - nf_log_buf_add(m, " "); -} - -static void -log_packet_common(struct nf_log_buf *m, - u_int8_t pf, - unsigned int hooknum, - const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct nf_loginfo *loginfo, - const char *prefix) -{ - nf_log_buf_add(m, KERN_SOH "%c%sIN=%s OUT=%s ", - '0' + loginfo->u.log.level, prefix, - in ? in->name : "", - out ? out->name : ""); -#ifdef CONFIG_BRIDGE_NETFILTER - if (skb->nf_bridge) { - const struct net_device *physindev; - const struct net_device *physoutdev; - - physindev = skb->nf_bridge->physindev; - if (physindev && in != physindev) - nf_log_buf_add(m, "PHYSIN=%s ", physindev->name); - physoutdev = skb->nf_bridge->physoutdev; - if (physoutdev && out != physoutdev) - nf_log_buf_add(m, "PHYSOUT=%s ", physoutdev->name); - } -#endif -} - - -static void -ipt_log_packet(struct net *net, - u_int8_t pf, - unsigned int hooknum, - const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct nf_loginfo *loginfo, - const char *prefix) -{ - struct nf_log_buf *m; - - /* FIXME: Disabled from containers until syslog ns is supported */ - if (!net_eq(net, &init_net)) - return; - - m = nf_log_buf_open(); - - if (!loginfo) - loginfo = &default_loginfo; - - log_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix); - - if (in != NULL) - dump_ipv4_mac_header(m, loginfo, skb); - - dump_ipv4_packet(m, loginfo, skb, 0); - - nf_log_buf_close(m); -} - -#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) -/* One level of recursion won't kill us */ -static void dump_ipv6_packet(struct nf_log_buf *m, - const struct nf_loginfo *info, - const struct sk_buff *skb, unsigned int ip6hoff, - int recurse) -{ - u_int8_t currenthdr; - int fragment; - struct ipv6hdr _ip6h; - const struct ipv6hdr *ih; - unsigned int ptr; - unsigned int hdrlen = 0; - unsigned int logflags; - - if (info->type == NF_LOG_TYPE_LOG) - logflags = info->u.log.logflags; - else - logflags = NF_LOG_MASK; - - ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); - if (ih == NULL) { - nf_log_buf_add(m, "TRUNCATED"); - return; - } - - /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ - nf_log_buf_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); - - /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ - nf_log_buf_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", - ntohs(ih->payload_len) + sizeof(struct ipv6hdr), - (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, - ih->hop_limit, (ntohl(*(__be32 *)ih) & 0x000fffff)); - - fragment = 0; - ptr = ip6hoff + sizeof(struct ipv6hdr); - currenthdr = ih->nexthdr; - while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) { - struct ipv6_opt_hdr _hdr; - const struct ipv6_opt_hdr *hp; - - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); - if (hp == NULL) { - nf_log_buf_add(m, "TRUNCATED"); - return; - } - - /* Max length: 48 "OPT (...) " */ - if (logflags & XT_LOG_IPOPT) - nf_log_buf_add(m, "OPT ( "); - - switch (currenthdr) { - case IPPROTO_FRAGMENT: { - struct frag_hdr _fhdr; - const struct frag_hdr *fh; - - nf_log_buf_add(m, "FRAG:"); - fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), - &_fhdr); - if (fh == NULL) { - nf_log_buf_add(m, "TRUNCATED "); - return; - } - - /* Max length: 6 "65535 " */ - nf_log_buf_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); - - /* Max length: 11 "INCOMPLETE " */ - if (fh->frag_off & htons(0x0001)) - nf_log_buf_add(m, "INCOMPLETE "); - - nf_log_buf_add(m, "ID:%08x ", ntohl(fh->identification)); - - if (ntohs(fh->frag_off) & 0xFFF8) - fragment = 1; - - hdrlen = 8; - - break; - } - case IPPROTO_DSTOPTS: - case IPPROTO_ROUTING: - case IPPROTO_HOPOPTS: - if (fragment) { - if (logflags & XT_LOG_IPOPT) - nf_log_buf_add(m, ")"); - return; - } - hdrlen = ipv6_optlen(hp); - break; - /* Max Length */ - case IPPROTO_AH: - if (logflags & XT_LOG_IPOPT) { - struct ip_auth_hdr _ahdr; - const struct ip_auth_hdr *ah; - - /* Max length: 3 "AH " */ - nf_log_buf_add(m, "AH "); - - if (fragment) { - nf_log_buf_add(m, ")"); - return; - } - - ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), - &_ahdr); - if (ah == NULL) { - /* - * Max length: 26 "INCOMPLETE [65535 - * bytes] )" - */ - nf_log_buf_add(m, "INCOMPLETE [%u bytes] )", - skb->len - ptr); - return; - } - - /* Length: 15 "SPI=0xF1234567 */ - nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi)); - - } - - hdrlen = (hp->hdrlen+2)<<2; - break; - case IPPROTO_ESP: - if (logflags & XT_LOG_IPOPT) { - struct ip_esp_hdr _esph; - const struct ip_esp_hdr *eh; - - /* Max length: 4 "ESP " */ - nf_log_buf_add(m, "ESP "); - - if (fragment) { - nf_log_buf_add(m, ")"); - return; - } - - /* - * Max length: 26 "INCOMPLETE [65535 bytes] )" - */ - eh = skb_header_pointer(skb, ptr, sizeof(_esph), - &_esph); - if (eh == NULL) { - nf_log_buf_add(m, "INCOMPLETE [%u bytes] )", - skb->len - ptr); - return; - } - - /* Length: 16 "SPI=0xF1234567 )" */ - nf_log_buf_add(m, "SPI=0x%x )", ntohl(eh->spi)); - - } - return; - default: - /* Max length: 20 "Unknown Ext Hdr 255" */ - nf_log_buf_add(m, "Unknown Ext Hdr %u", currenthdr); - return; - } - if (logflags & XT_LOG_IPOPT) - nf_log_buf_add(m, ") "); - - currenthdr = hp->nexthdr; - ptr += hdrlen; - } - - switch (currenthdr) { - case IPPROTO_TCP: - if (dump_tcp_header(m, skb, currenthdr, fragment, ptr, - logflags)) - return; - break; - case IPPROTO_UDP: - case IPPROTO_UDPLITE: - if (dump_udp_header(m, skb, currenthdr, fragment, ptr)) - return; - break; - case IPPROTO_ICMPV6: { - struct icmp6hdr _icmp6h; - const struct icmp6hdr *ic; - - /* Max length: 13 "PROTO=ICMPv6 " */ - nf_log_buf_add(m, "PROTO=ICMPv6 "); - - if (fragment) - break; - - /* Max length: 25 "INCOMPLETE [65535 bytes] " */ - ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); - if (ic == NULL) { - nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", - skb->len - ptr); - return; - } - - /* Max length: 18 "TYPE=255 CODE=255 " */ - nf_log_buf_add(m, "TYPE=%u CODE=%u ", - ic->icmp6_type, ic->icmp6_code); - - switch (ic->icmp6_type) { - case ICMPV6_ECHO_REQUEST: - case ICMPV6_ECHO_REPLY: - /* Max length: 19 "ID=65535 SEQ=65535 " */ - nf_log_buf_add(m, "ID=%u SEQ=%u ", - ntohs(ic->icmp6_identifier), - ntohs(ic->icmp6_sequence)); - break; - case ICMPV6_MGM_QUERY: - case ICMPV6_MGM_REPORT: - case ICMPV6_MGM_REDUCTION: - break; - - case ICMPV6_PARAMPROB: - /* Max length: 17 "POINTER=ffffffff " */ - nf_log_buf_add(m, "POINTER=%08x ", - ntohl(ic->icmp6_pointer)); - /* Fall through */ - case ICMPV6_DEST_UNREACH: - case ICMPV6_PKT_TOOBIG: - case ICMPV6_TIME_EXCEED: - /* Max length: 3+maxlen */ - if (recurse) { - nf_log_buf_add(m, "["); - dump_ipv6_packet(m, info, skb, - ptr + sizeof(_icmp6h), 0); - nf_log_buf_add(m, "] "); - } - - /* Max length: 10 "MTU=65535 " */ - if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) - nf_log_buf_add(m, "MTU=%u ", - ntohl(ic->icmp6_mtu)); - } - break; - } - /* Max length: 10 "PROTO=255 " */ - default: - nf_log_buf_add(m, "PROTO=%u ", currenthdr); - } - - /* Max length: 15 "UID=4294967295 " */ - if ((logflags & XT_LOG_UID) && recurse) - dump_sk_uid_gid(m, skb->sk); - - /* Max length: 16 "MARK=0xFFFFFFFF " */ - if (recurse && skb->mark) - nf_log_buf_add(m, "MARK=0x%x ", skb->mark); -} - -static void dump_ipv6_mac_header(struct nf_log_buf *m, - const struct nf_loginfo *info, - const struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - unsigned int logflags = 0; - - if (info->type == NF_LOG_TYPE_LOG) - logflags = info->u.log.logflags; - - if (!(logflags & XT_LOG_MACDECODE)) - goto fallback; - - switch (dev->type) { - case ARPHRD_ETHER: - nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", - eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, - ntohs(eth_hdr(skb)->h_proto)); - return; - default: - break; - } - -fallback: - nf_log_buf_add(m, "MAC="); - if (dev->hard_header_len && - skb->mac_header != skb->network_header) { - const unsigned char *p = skb_mac_header(skb); - unsigned int len = dev->hard_header_len; - unsigned int i; - - if (dev->type == ARPHRD_SIT) { - p -= ETH_HLEN; - - if (p < skb->head) - p = NULL; - } - - if (p != NULL) { - nf_log_buf_add(m, "%02x", *p++); - for (i = 1; i < len; i++) - nf_log_buf_add(m, ":%02x", *p++); - } - nf_log_buf_add(m, " "); - - if (dev->type == ARPHRD_SIT) { - const struct iphdr *iph = - (struct iphdr *)skb_mac_header(skb); - nf_log_buf_add(m, "TUNNEL=%pI4->%pI4 ", - &iph->saddr, &iph->daddr); - } - } else { - nf_log_buf_add(m, " "); - } -} - -static void -ip6t_log_packet(struct net *net, - u_int8_t pf, - unsigned int hooknum, - const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct nf_loginfo *loginfo, - const char *prefix) -{ - struct nf_log_buf *m; - - /* FIXME: Disabled from containers until syslog ns is supported */ - if (!net_eq(net, &init_net)) - return; - - m = nf_log_buf_open(); - - if (!loginfo) - loginfo = &default_loginfo; - - log_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix); - - if (in != NULL) - dump_ipv6_mac_header(m, loginfo, skb); - - dump_ipv6_packet(m, loginfo, skb, skb_network_offset(skb), 1); - - nf_log_buf_close(m); -} -#endif - static unsigned int log_tg(struct sk_buff *skb, const struct xt_action_param *par) { @@ -847,12 +40,12 @@ log_tg(struct sk_buff *skb, const struct xt_action_param *par) li.u.log.logflags = loginfo->logflags; if (par->family == NFPROTO_IPV4) - ipt_log_packet(net, NFPROTO_IPV4, par->hooknum, skb, par->in, - par->out, &li, loginfo->prefix); + nf_log_ip_packet(net, NFPROTO_IPV4, par->hooknum, skb, par->in, + par->out, &li, loginfo->prefix); #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) else if (par->family == NFPROTO_IPV6) - ip6t_log_packet(net, NFPROTO_IPV6, par->hooknum, skb, par->in, - par->out, &li, loginfo->prefix); + nf_log_ip6_packet(net, NFPROTO_IPV6, par->hooknum, skb, par->in, + par->out, &li, loginfo->prefix); #endif else WARN_ON_ONCE(1); @@ -901,75 +94,13 @@ static struct xt_target log_tg_regs[] __read_mostly = { #endif }; -static struct nf_logger ipt_log_logger __read_mostly = { - .name = "ipt_LOG", - .type = NF_LOG_TYPE_LOG, - .logfn = &ipt_log_packet, - .me = THIS_MODULE, -}; - -#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) -static struct nf_logger ip6t_log_logger __read_mostly = { - .name = "ip6t_LOG", - .type = NF_LOG_TYPE_LOG, - .logfn = &ip6t_log_packet, - .me = THIS_MODULE, -}; -#endif - -static int __net_init log_net_init(struct net *net) -{ - nf_log_set(net, NFPROTO_IPV4, &ipt_log_logger); -#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) - nf_log_set(net, NFPROTO_IPV6, &ip6t_log_logger); -#endif - return 0; -} - -static void __net_exit log_net_exit(struct net *net) -{ - nf_log_unset(net, &ipt_log_logger); -#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) - nf_log_unset(net, &ip6t_log_logger); -#endif -} - -static struct pernet_operations log_net_ops = { - .init = log_net_init, - .exit = log_net_exit, -}; - static int __init log_tg_init(void) { - int ret; - - ret = register_pernet_subsys(&log_net_ops); - if (ret < 0) - goto err_pernet; - - ret = xt_register_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); - if (ret < 0) - goto err_target; - - nf_log_register(NFPROTO_IPV4, &ipt_log_logger); -#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) - nf_log_register(NFPROTO_IPV6, &ip6t_log_logger); -#endif - return 0; - -err_target: - unregister_pernet_subsys(&log_net_ops); -err_pernet: - return ret; + return xt_register_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); } static void __exit log_tg_exit(void) { - unregister_pernet_subsys(&log_net_ops); - nf_log_unregister(&ipt_log_logger); -#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) - nf_log_unregister(&ip6t_log_logger); -#endif xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); } -- cgit v1.2.3 From fab4085f4e248b8a80bb1dadbbacb2bacd8017c3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 18 Jun 2014 19:38:25 +0200 Subject: netfilter: log: nf_log_packet() as real unified interface Before this patch, the nf_loginfo parameter specified the logging configuration in case the specified default logger was loaded. This patch updates the semantics of the nf_loginfo parameter in nf_log_packet() which now indicates the logger that you explicitly want to use. Thus, nf_log_packet() is exposed as an unified interface which internally routes the log message to the corresponding logger type by family. The module dependencies are expressed by the new nf_logger_find_get() and nf_logger_put() functions which bump the logger module refcount. Thus, you can not remove logger modules that are used by rules anymore. Another important effect of this change is that the family specific module is only loaded when required. Therefore, xt_LOG and nft_log will just trigger the autoload of the nf_log_{ip,ip6} modules according to the family. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_log.h | 20 ++++++-------------- net/ipv4/netfilter/nf_log_ipv4.c | 14 +++++++------- net/ipv6/netfilter/nf_log_ipv6.c | 14 +++++++------- net/netfilter/nf_log.c | 41 +++++++++++++++++++++++++++++++++++++++- net/netfilter/nfnetlink_log.c | 3 +++ net/netfilter/xt_LOG.c | 22 ++++++++++----------- 6 files changed, 73 insertions(+), 41 deletions(-) diff --git a/include/net/netfilter/nf_log.h b/include/net/netfilter/nf_log.h index bba354e78f49..b82dd19b8f26 100644 --- a/include/net/netfilter/nf_log.h +++ b/include/net/netfilter/nf_log.h @@ -61,6 +61,12 @@ int nf_log_bind_pf(struct net *net, u_int8_t pf, const struct nf_logger *logger); void nf_log_unbind_pf(struct net *net, u_int8_t pf); +int nf_logger_find_get(int pf, enum nf_log_type type); +void nf_logger_put(int pf, enum nf_log_type type); + +#define MODULE_ALIAS_NF_LOGGER(family, type) \ + MODULE_ALIAS("nf-logger-" __stringify(family) "-" __stringify(type)) + /* Calls the registered backend logging function */ __printf(8, 9) void nf_log_packet(struct net *net, @@ -78,20 +84,6 @@ struct nf_log_buf *nf_log_buf_open(void); __printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...); void nf_log_buf_close(struct nf_log_buf *m); -void nf_log_ip_packet(struct net *net, u_int8_t pf, - unsigned int hooknum, const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct nf_loginfo *loginfo, - const char *prefix); - -void nf_log_ip6_packet(struct net *net, u_int8_t pf, - unsigned int hooknum, const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct nf_loginfo *loginfo, - const char *prefix); - /* common logging functions */ int nf_log_dump_udp_header(struct nf_log_buf *m, const struct sk_buff *skb, u8 proto, int fragment, unsigned int offset); diff --git a/net/ipv4/netfilter/nf_log_ipv4.c b/net/ipv4/netfilter/nf_log_ipv4.c index 7e69a401a29e..078bdca1b607 100644 --- a/net/ipv4/netfilter/nf_log_ipv4.c +++ b/net/ipv4/netfilter/nf_log_ipv4.c @@ -306,12 +306,12 @@ fallback: nf_log_buf_add(m, " "); } -void nf_log_ip_packet(struct net *net, u_int8_t pf, - unsigned int hooknum, const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct nf_loginfo *loginfo, - const char *prefix) +static void nf_log_ip_packet(struct net *net, u_int8_t pf, + unsigned int hooknum, const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix) { struct nf_log_buf *m; @@ -334,7 +334,6 @@ void nf_log_ip_packet(struct net *net, u_int8_t pf, nf_log_buf_close(m); } -EXPORT_SYMBOL_GPL(nf_log_ip_packet); static struct nf_logger nf_ip_logger __read_mostly = { .name = "nf_log_ipv4", @@ -383,3 +382,4 @@ module_exit(nf_log_ipv4_exit); MODULE_AUTHOR("Netfilter Core Team "); MODULE_DESCRIPTION("Netfilter IPv4 packet logging"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NF_LOGGER(AF_INET, 0); diff --git a/net/ipv6/netfilter/nf_log_ipv6.c b/net/ipv6/netfilter/nf_log_ipv6.c index 804060946d2b..7b17a0be93e7 100644 --- a/net/ipv6/netfilter/nf_log_ipv6.c +++ b/net/ipv6/netfilter/nf_log_ipv6.c @@ -338,12 +338,12 @@ fallback: } } -void nf_log_ip6_packet(struct net *net, u_int8_t pf, - unsigned int hooknum, const struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - const struct nf_loginfo *loginfo, - const char *prefix) +static void nf_log_ip6_packet(struct net *net, u_int8_t pf, + unsigned int hooknum, const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix) { struct nf_log_buf *m; @@ -366,7 +366,6 @@ void nf_log_ip6_packet(struct net *net, u_int8_t pf, nf_log_buf_close(m); } -EXPORT_SYMBOL_GPL(nf_log_ip6_packet); static struct nf_logger nf_ip6_logger __read_mostly = { .name = "nf_log_ipv6", @@ -415,3 +414,4 @@ module_exit(nf_log_ipv6_exit); MODULE_AUTHOR("Netfilter Core Team "); MODULE_DESCRIPTION("Netfilter IPv4 packet logging"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NF_LOGGER(AF_INET6, 0); diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index 0b6b2c874199..0b2161c689e0 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -132,6 +132,41 @@ void nf_log_unbind_pf(struct net *net, u_int8_t pf) } EXPORT_SYMBOL(nf_log_unbind_pf); +int nf_logger_find_get(int pf, enum nf_log_type type) +{ + struct nf_logger *logger; + int ret = -ENOENT; + + logger = loggers[pf][type]; + if (logger == NULL) + request_module("nf-logger-%u-%u", pf, type); + + rcu_read_lock(); + logger = rcu_dereference(loggers[pf][type]); + if (logger == NULL) + goto out; + + if (logger && try_module_get(logger->me)) + ret = 0; +out: + rcu_read_unlock(); + return ret; +} +EXPORT_SYMBOL_GPL(nf_logger_find_get); + +void nf_logger_put(int pf, enum nf_log_type type) +{ + struct nf_logger *logger; + + BUG_ON(loggers[pf][type] == NULL); + + rcu_read_lock(); + logger = rcu_dereference(loggers[pf][type]); + module_put(logger->me); + rcu_read_unlock(); +} +EXPORT_SYMBOL_GPL(nf_logger_put); + void nf_log_packet(struct net *net, u_int8_t pf, unsigned int hooknum, @@ -146,7 +181,11 @@ void nf_log_packet(struct net *net, const struct nf_logger *logger; rcu_read_lock(); - logger = rcu_dereference(net->nf.nf_loggers[pf]); + if (loginfo != NULL) + logger = rcu_dereference(loggers[pf][loginfo->type]); + else + logger = rcu_dereference(net->nf.nf_loggers[pf]); + if (logger) { va_start(args, fmt); vsnprintf(prefix, sizeof(prefix), fmt, args); diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 160bb8ea9923..a11c5ff2f720 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -1106,6 +1106,9 @@ MODULE_DESCRIPTION("netfilter userspace logging"); MODULE_AUTHOR("Harald Welte "); MODULE_LICENSE("GPL"); MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ULOG); +MODULE_ALIAS_NF_LOGGER(AF_INET, 1); +MODULE_ALIAS_NF_LOGGER(AF_INET6, 1); +MODULE_ALIAS_NF_LOGGER(AF_BRIDGE, 1); module_init(nfnetlink_log_init); module_exit(nfnetlink_log_fini); diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c index 5a6bd60e20d6..00eb49196e75 100644 --- a/net/netfilter/xt_LOG.c +++ b/net/netfilter/xt_LOG.c @@ -39,17 +39,8 @@ log_tg(struct sk_buff *skb, const struct xt_action_param *par) li.u.log.level = loginfo->level; li.u.log.logflags = loginfo->logflags; - if (par->family == NFPROTO_IPV4) - nf_log_ip_packet(net, NFPROTO_IPV4, par->hooknum, skb, par->in, - par->out, &li, loginfo->prefix); -#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) - else if (par->family == NFPROTO_IPV6) - nf_log_ip6_packet(net, NFPROTO_IPV6, par->hooknum, skb, par->in, - par->out, &li, loginfo->prefix); -#endif - else - WARN_ON_ONCE(1); - + nf_log_packet(net, par->family, par->hooknum, skb, par->in, par->out, + &li, loginfo->prefix); return XT_CONTINUE; } @@ -70,7 +61,12 @@ static int log_tg_check(const struct xt_tgchk_param *par) return -EINVAL; } - return 0; + return nf_logger_find_get(par->family, NF_LOG_TYPE_LOG); +} + +static void log_tg_destroy(const struct xt_tgdtor_param *par) +{ + nf_logger_put(par->family, NF_LOG_TYPE_LOG); } static struct xt_target log_tg_regs[] __read_mostly = { @@ -80,6 +76,7 @@ static struct xt_target log_tg_regs[] __read_mostly = { .target = log_tg, .targetsize = sizeof(struct xt_log_info), .checkentry = log_tg_check, + .destroy = log_tg_destroy, .me = THIS_MODULE, }, #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) @@ -89,6 +86,7 @@ static struct xt_target log_tg_regs[] __read_mostly = { .target = log_tg, .targetsize = sizeof(struct xt_log_info), .checkentry = log_tg_check, + .destroy = log_tg_destroy, .me = THIS_MODULE, }, #endif -- cgit v1.2.3 From 35b9395104d51f4b85847fa72a1bf4136d36c56e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 20 Jun 2014 20:36:23 +0200 Subject: netfilter: add generic ARP packet logger This adds the generic plain text packet loggger for ARP packets. It is based on the ebt_log code. Nevertheless, the output has been modified to make it consistent with the original xt_LOG output. This is an example output: IN=wlan0 OUT= ARP HTYPE=1 PTYPE=0x0800 OPCODE=2 MACSRC=00:ab:12:34:55:63 IPSRC=192.168.10.1 MACDST=80:09:12:70:4f:50 IPDST=192.168.10.150 This patch enables packet logging from ARP chains, eg. nft add rule arp filter input log prefix "input: " Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/Kconfig | 5 ++ net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_log_arp.c | 149 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 net/ipv4/netfilter/nf_log_arp.c diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 0c980293d225..12e6057daea1 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -159,6 +159,11 @@ config IP_NF_TARGET_SYNPROXY To compile it as a module, choose M here. If unsure, say N. +config NF_LOG_ARP + tristate "ARP packet logging" + default m if NETFILTER_ADVANCED=n + select NF_LOG_INET + config NF_LOG_IPV4 tristate "IPv4 packet logging" default m if NETFILTER_ADVANCED=n diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 730e0c1ead90..245db9df3337 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_NF_NAT_IPV4) += nf_nat_ipv4.o obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o # logging +obj-$(CONFIG_NF_LOG_ARP) += nf_log_arp.o obj-$(CONFIG_NF_LOG_IPV4) += nf_log_ipv4.o # NAT helpers (nf_conntrack) diff --git a/net/ipv4/netfilter/nf_log_arp.c b/net/ipv4/netfilter/nf_log_arp.c new file mode 100644 index 000000000000..ccfc78db12ee --- /dev/null +++ b/net/ipv4/netfilter/nf_log_arp.c @@ -0,0 +1,149 @@ +/* + * (C) 2014 by Pablo Neira Ayuso + * + * Based on code from ebt_log from: + * + * Bart De Schuymer + * Harald Welte + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct nf_loginfo default_loginfo = { + .type = NF_LOG_TYPE_LOG, + .u = { + .log = { + .level = 5, + .logflags = NF_LOG_MASK, + }, + }, +}; + +struct arppayload { + unsigned char mac_src[ETH_ALEN]; + unsigned char ip_src[4]; + unsigned char mac_dst[ETH_ALEN]; + unsigned char ip_dst[4]; +}; + +static void dump_arp_packet(struct nf_log_buf *m, + const struct nf_loginfo *info, + const struct sk_buff *skb, unsigned int nhoff) +{ + const struct arphdr *ah; + struct arphdr _arph; + const struct arppayload *ap; + struct arppayload _arpp; + + ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); + if (ah == NULL) { + nf_log_buf_add(m, "TRUNCATED"); + return; + } + nf_log_buf_add(m, "ARP HTYPE=%d PTYPE=0x%04x OPCODE=%d", + ntohs(ah->ar_hrd), ntohs(ah->ar_pro), ntohs(ah->ar_op)); + + /* If it's for Ethernet and the lengths are OK, then log the ARP + * payload. + */ + if (ah->ar_hrd != htons(1) || + ah->ar_hln != ETH_ALEN || + ah->ar_pln != sizeof(__be32)) + return; + + ap = skb_header_pointer(skb, sizeof(_arph), sizeof(_arpp), &_arpp); + if (ap == NULL) { + nf_log_buf_add(m, " INCOMPLETE [%Zu bytes]", + skb->len - sizeof(_arph)); + return; + } + nf_log_buf_add(m, " MACSRC=%pM IPSRC=%pI4 MACDST=%pM IPDST=%pI4", + ap->mac_src, ap->ip_src, ap->mac_dst, ap->ip_dst); +} + +void nf_log_arp_packet(struct net *net, u_int8_t pf, + unsigned int hooknum, const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix) +{ + struct nf_log_buf *m; + + /* FIXME: Disabled from containers until syslog ns is supported */ + if (!net_eq(net, &init_net)) + return; + + m = nf_log_buf_open(); + + if (!loginfo) + loginfo = &default_loginfo; + + nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo, + prefix); + dump_arp_packet(m, loginfo, skb, 0); + + nf_log_buf_close(m); +} + +static struct nf_logger nf_arp_logger __read_mostly = { + .name = "nf_log_arp", + .type = NF_LOG_TYPE_LOG, + .logfn = nf_log_arp_packet, + .me = THIS_MODULE, +}; + +static int __net_init nf_log_arp_net_init(struct net *net) +{ + nf_log_set(net, NFPROTO_ARP, &nf_arp_logger); + return 0; +} + +static void __net_exit nf_log_arp_net_exit(struct net *net) +{ + nf_log_unset(net, &nf_arp_logger); +} + +static struct pernet_operations nf_log_arp_net_ops = { + .init = nf_log_arp_net_init, + .exit = nf_log_arp_net_exit, +}; + +static int __init nf_log_arp_init(void) +{ + int ret; + + ret = register_pernet_subsys(&nf_log_arp_net_ops); + if (ret < 0) + return ret; + + nf_log_register(NFPROTO_ARP, &nf_arp_logger); + return 0; +} + +static void __exit nf_log_arp_exit(void) +{ + unregister_pernet_subsys(&nf_log_arp_net_ops); + nf_log_unregister(&nf_arp_logger); +} + +module_init(nf_log_arp_init); +module_exit(nf_log_arp_exit); + +MODULE_AUTHOR("Pablo Neira Ayuso "); +MODULE_DESCRIPTION("Netfilter ARP packet logging"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NF_LOGGER(3, 0); -- cgit v1.2.3 From 960649d1923c31a7f771162fa0eef00210044262 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 23 Jun 2014 00:28:18 +0200 Subject: netfilter: bridge: add generic packet logger This adds the generic plain text packet loggger for bridged packets. It routes the logging message to the real protocol packet logger. I decided not to refactor the ebt_log code for two reasons: 1) The ebt_log output is not consistent with the IPv4 and IPv6 Netfilter packet loggers. The output is different for no good reason and it adds redundant code to handle packet logging. 2) To avoid breaking backward compatibility for applications outthere that are parsing the specific ebt_log output, the ebt_log output has been left as is. So only nftables will use the new consistent logging format for logged bridged packets. More decisions coming in this patch: 1) This also removes ebt_log as default logger for bridged packets. Thus, nf_log_packet() routes packet to this new packet logger instead. This doesn't break backward compatibility since nf_log_packet() is not used to log packets in plain text format from anywhere in the ebtables/netfilter bridge code. 2) The new bridge packet logger also performs a lazy request to register the real IPv4, ARP and IPv6 netfilter packet loggers. If the real protocol logger is no available (not compiled or the module is not available in the system, not packet logging happens. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_log.h | 1 + net/bridge/netfilter/Kconfig | 3 ++ net/bridge/netfilter/Makefile | 3 ++ net/bridge/netfilter/ebt_log.c | 48 ++---------------- net/bridge/netfilter/nf_log_bridge.c | 96 ++++++++++++++++++++++++++++++++++++ net/netfilter/nf_log.c | 7 +++ 6 files changed, 115 insertions(+), 43 deletions(-) create mode 100644 net/bridge/netfilter/nf_log_bridge.c diff --git a/include/net/netfilter/nf_log.h b/include/net/netfilter/nf_log.h index b82dd19b8f26..534e1f2ac4fc 100644 --- a/include/net/netfilter/nf_log.h +++ b/include/net/netfilter/nf_log.h @@ -63,6 +63,7 @@ void nf_log_unbind_pf(struct net *net, u_int8_t pf); int nf_logger_find_get(int pf, enum nf_log_type type); void nf_logger_put(int pf, enum nf_log_type type); +void nf_logger_request_module(int pf, enum nf_log_type type); #define MODULE_ALIAS_NF_LOGGER(family, type) \ MODULE_ALIAS("nf-logger-" __stringify(family) "-" __stringify(type)) diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig index 3a76ac7b7141..4ce0b313f72c 100644 --- a/net/bridge/netfilter/Kconfig +++ b/net/bridge/netfilter/Kconfig @@ -14,6 +14,9 @@ config NFT_BRIDGE_META help Add support for bridge dedicated meta key. +config NF_LOG_BRIDGE + tristate "Bridge packet logging" + endif # NF_TABLES_BRIDGE menuconfig BRIDGE_NF_EBTABLES diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile index 6f2f3943d66f..1f78ea0d90e4 100644 --- a/net/bridge/netfilter/Makefile +++ b/net/bridge/netfilter/Makefile @@ -5,6 +5,9 @@ obj-$(CONFIG_NF_TABLES_BRIDGE) += nf_tables_bridge.o obj-$(CONFIG_NFT_BRIDGE_META) += nft_meta_bridge.o +# packet logging +obj-$(CONFIG_NF_LOG_BRIDGE) += nf_log_bridge.o + obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o # tables diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index 0577477aacd8..17f2e4bc2a29 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c @@ -186,6 +186,10 @@ ebt_log_tg(struct sk_buff *skb, const struct xt_action_param *par) li.u.log.level = info->loglevel; li.u.log.logflags = info->bitmask; + /* Remember that we have to use ebt_log_packet() not to break backward + * compatibility. We cannot use the default bridge packet logger via + * nf_log_packet() with NFT_LOG_TYPE_LOG here. --Pablo + */ if (info->bitmask & EBT_LOG_NFLOG) nf_log_packet(net, NFPROTO_BRIDGE, par->hooknum, skb, par->in, par->out, &li, "%s", info->prefix); @@ -205,55 +209,13 @@ static struct xt_target ebt_log_tg_reg __read_mostly = { .me = THIS_MODULE, }; -static struct nf_logger ebt_log_logger __read_mostly = { - .name = "ebt_log", - .type = NF_LOG_TYPE_LOG, - .logfn = &ebt_log_packet, - .me = THIS_MODULE, -}; - -static int __net_init ebt_log_net_init(struct net *net) -{ - nf_log_set(net, NFPROTO_BRIDGE, &ebt_log_logger); - return 0; -} - -static void __net_exit ebt_log_net_fini(struct net *net) -{ - nf_log_unset(net, &ebt_log_logger); -} - -static struct pernet_operations ebt_log_net_ops = { - .init = ebt_log_net_init, - .exit = ebt_log_net_fini, -}; - static int __init ebt_log_init(void) { - int ret; - - ret = register_pernet_subsys(&ebt_log_net_ops); - if (ret < 0) - goto err_pernet; - - ret = xt_register_target(&ebt_log_tg_reg); - if (ret < 0) - goto err_target; - - nf_log_register(NFPROTO_BRIDGE, &ebt_log_logger); - - return ret; - -err_target: - unregister_pernet_subsys(&ebt_log_net_ops); -err_pernet: - return ret; + return xt_register_target(&ebt_log_tg_reg); } static void __exit ebt_log_fini(void) { - unregister_pernet_subsys(&ebt_log_net_ops); - nf_log_unregister(&ebt_log_logger); xt_unregister_target(&ebt_log_tg_reg); } diff --git a/net/bridge/netfilter/nf_log_bridge.c b/net/bridge/netfilter/nf_log_bridge.c new file mode 100644 index 000000000000..5d9953a90929 --- /dev/null +++ b/net/bridge/netfilter/nf_log_bridge.c @@ -0,0 +1,96 @@ +/* + * (C) 2014 by Pablo Neira Ayuso + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +static void nf_log_bridge_packet(struct net *net, u_int8_t pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix) +{ + switch (eth_hdr(skb)->h_proto) { + case htons(ETH_P_IP): + nf_log_packet(net, NFPROTO_IPV4, hooknum, skb, in, out, + loginfo, "%s", prefix); + break; + case htons(ETH_P_IPV6): + nf_log_packet(net, NFPROTO_IPV6, hooknum, skb, in, out, + loginfo, "%s", prefix); + break; + case htons(ETH_P_ARP): + case htons(ETH_P_RARP): + nf_log_packet(net, NFPROTO_ARP, hooknum, skb, in, out, + loginfo, "%s", prefix); + break; + } +} + +static struct nf_logger nf_bridge_logger __read_mostly = { + .name = "nf_log_bridge", + .type = NF_LOG_TYPE_LOG, + .logfn = nf_log_bridge_packet, + .me = THIS_MODULE, +}; + +static int __net_init nf_log_bridge_net_init(struct net *net) +{ + nf_log_set(net, NFPROTO_BRIDGE, &nf_bridge_logger); + return 0; +} + +static void __net_exit nf_log_bridge_net_exit(struct net *net) +{ + nf_log_unset(net, &nf_bridge_logger); +} + +static struct pernet_operations nf_log_bridge_net_ops = { + .init = nf_log_bridge_net_init, + .exit = nf_log_bridge_net_exit, +}; + +static int __init nf_log_bridge_init(void) +{ + int ret; + + /* Request to load the real packet loggers. */ + nf_logger_request_module(NFPROTO_IPV4, NF_LOG_TYPE_LOG); + nf_logger_request_module(NFPROTO_IPV6, NF_LOG_TYPE_LOG); + nf_logger_request_module(NFPROTO_ARP, NF_LOG_TYPE_LOG); + + ret = register_pernet_subsys(&nf_log_bridge_net_ops); + if (ret < 0) + return ret; + + nf_log_register(NFPROTO_BRIDGE, &nf_bridge_logger); + return 0; +} + +static void __exit nf_log_bridge_exit(void) +{ + unregister_pernet_subsys(&nf_log_bridge_net_ops); + nf_log_unregister(&nf_bridge_logger); +} + +module_init(nf_log_bridge_init); +module_exit(nf_log_bridge_exit); + +MODULE_AUTHOR("Pablo Neira Ayuso "); +MODULE_DESCRIPTION("Netfilter bridge packet logging"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NF_LOGGER(AF_BRIDGE, 0); diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index 0b2161c689e0..daad6022c689 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -132,6 +132,13 @@ void nf_log_unbind_pf(struct net *net, u_int8_t pf) } EXPORT_SYMBOL(nf_log_unbind_pf); +void nf_logger_request_module(int pf, enum nf_log_type type) +{ + if (loggers[pf][type] == NULL) + request_module("nf-logger-%u-%u", pf, type); +} +EXPORT_SYMBOL_GPL(nf_logger_request_module); + int nf_logger_find_get(int pf, enum nf_log_type type) { struct nf_logger *logger; -- cgit v1.2.3 From 85d30e24166e86686aa2d805e2ef1fa8d770852c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 25 Jun 2014 13:29:15 +0200 Subject: netfilter: nft_log: request explicit logger when loading rules This includes the special handling for NFPROTO_INET. There is no real inet logger since we don't see packets of this family. However, rules are loaded using this special family type. So let's just request both IPV4 and IPV6 loggers. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_log.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c index 10cfb156cdf4..55d4297d8417 100644 --- a/net/netfilter/nft_log.c +++ b/net/netfilter/nft_log.c @@ -50,6 +50,7 @@ static int nft_log_init(const struct nft_ctx *ctx, struct nft_log *priv = nft_expr_priv(expr); struct nf_loginfo *li = &priv->loginfo; const struct nlattr *nla; + int ret; nla = tb[NFTA_LOG_PREFIX]; if (nla != NULL) { @@ -71,16 +72,37 @@ static int nft_log_init(const struct nft_ctx *ctx, ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD])); } - return 0; + if (ctx->afi->family == NFPROTO_INET) { + ret = nf_logger_find_get(NFPROTO_IPV4, li->type); + if (ret < 0) + return ret; + + ret = nf_logger_find_get(NFPROTO_IPV6, li->type); + if (ret < 0) { + nf_logger_put(NFPROTO_IPV4, li->type); + return ret; + } + return 0; + } + + return nf_logger_find_get(ctx->afi->family, li->type); } static void nft_log_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { struct nft_log *priv = nft_expr_priv(expr); + struct nf_loginfo *li = &priv->loginfo; if (priv->prefix != nft_log_null_prefix) kfree(priv->prefix); + + if (ctx->afi->family == NFPROTO_INET) { + nf_logger_put(NFPROTO_IPV4, li->type); + nf_logger_put(NFPROTO_IPV6, li->type); + } else { + nf_logger_put(ctx->afi->family, li->type); + } } static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr) -- cgit v1.2.3 From 09d27b88f15f08fcfbaf57d9b0b4489816264815 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 25 Jun 2014 13:37:13 +0200 Subject: netfilter: nft_log: complete logging support Use the unified nf_log_packet() interface that allows us explicit logger selection through the nf_loginfo structure. If you specify the group attribute, this means you want to receive logging messages through nfnetlink_log. In that case, the snaplen and qthreshold attributes allows you to tune internal aspects of the netlink logging infrastructure. On the other hand, if the level is specified, then the plain text format through the kernel logging ring is used instead, which is also used by default if neither group nor level are indicated. Signed-off-by: Pablo Neira Ayuso --- include/uapi/linux/netfilter/nf_tables.h | 4 ++ net/netfilter/nft_log.c | 76 +++++++++++++++++++++++++------- 2 files changed, 63 insertions(+), 17 deletions(-) diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index 2a88f645a5d8..801bdd1e56e3 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -697,6 +697,8 @@ enum nft_counter_attributes { * @NFTA_LOG_PREFIX: prefix to prepend to log messages (NLA_STRING) * @NFTA_LOG_SNAPLEN: length of payload to include in netlink message (NLA_U32) * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U32) + * @NFTA_LOG_LEVEL: log level (NLA_U32) + * @NFTA_LOG_FLAGS: logging flags (NLA_U32) */ enum nft_log_attributes { NFTA_LOG_UNSPEC, @@ -704,6 +706,8 @@ enum nft_log_attributes { NFTA_LOG_PREFIX, NFTA_LOG_SNAPLEN, NFTA_LOG_QTHRESHOLD, + NFTA_LOG_LEVEL, + NFTA_LOG_FLAGS, __NFTA_LOG_MAX }; #define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1) diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c index 55d4297d8417..5b1a4f5c3dcc 100644 --- a/net/netfilter/nft_log.c +++ b/net/netfilter/nft_log.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2009 Patrick McHardy + * Copyright (c) 2012-2014 Pablo Neira Ayuso * * 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 @@ -41,6 +42,8 @@ static const struct nla_policy nft_log_policy[NFTA_LOG_MAX + 1] = { [NFTA_LOG_PREFIX] = { .type = NLA_STRING }, [NFTA_LOG_SNAPLEN] = { .type = NLA_U32 }, [NFTA_LOG_QTHRESHOLD] = { .type = NLA_U16 }, + [NFTA_LOG_LEVEL] = { .type = NLA_U32 }, + [NFTA_LOG_FLAGS] = { .type = NLA_U32 }, }; static int nft_log_init(const struct nft_ctx *ctx, @@ -58,18 +61,41 @@ static int nft_log_init(const struct nft_ctx *ctx, if (priv->prefix == NULL) return -ENOMEM; nla_strlcpy(priv->prefix, nla, nla_len(nla) + 1); - } else + } else { priv->prefix = (char *)nft_log_null_prefix; + } - li->type = NF_LOG_TYPE_ULOG; + li->type = NF_LOG_TYPE_LOG; + if (tb[NFTA_LOG_LEVEL] != NULL && + tb[NFTA_LOG_GROUP] != NULL) + return -EINVAL; if (tb[NFTA_LOG_GROUP] != NULL) + li->type = NF_LOG_TYPE_ULOG; + + switch (li->type) { + case NF_LOG_TYPE_LOG: + if (tb[NFTA_LOG_LEVEL] != NULL) { + li->u.log.level = + ntohl(nla_get_be32(tb[NFTA_LOG_LEVEL]));; + } else { + li->u.log.level = 4; + } + if (tb[NFTA_LOG_FLAGS] != NULL) { + li->u.log.logflags = + ntohl(nla_get_be32(tb[NFTA_LOG_FLAGS])); + } + break; + case NF_LOG_TYPE_ULOG: li->u.ulog.group = ntohs(nla_get_be16(tb[NFTA_LOG_GROUP])); - - if (tb[NFTA_LOG_SNAPLEN] != NULL) - li->u.ulog.copy_len = ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN])); - if (tb[NFTA_LOG_QTHRESHOLD] != NULL) { - li->u.ulog.qthreshold = - ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD])); + if (tb[NFTA_LOG_SNAPLEN] != NULL) { + li->u.ulog.copy_len = + ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN])); + } + if (tb[NFTA_LOG_QTHRESHOLD] != NULL) { + li->u.ulog.qthreshold = + ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD])); + } + break; } if (ctx->afi->family == NFPROTO_INET) { @@ -113,17 +139,33 @@ static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr) if (priv->prefix != nft_log_null_prefix) if (nla_put_string(skb, NFTA_LOG_PREFIX, priv->prefix)) goto nla_put_failure; - if (li->u.ulog.group) - if (nla_put_be16(skb, NFTA_LOG_GROUP, htons(li->u.ulog.group))) - goto nla_put_failure; - if (li->u.ulog.copy_len) - if (nla_put_be32(skb, NFTA_LOG_SNAPLEN, - htonl(li->u.ulog.copy_len))) + switch (li->type) { + case NF_LOG_TYPE_LOG: + if (nla_put_be32(skb, NFTA_LOG_LEVEL, htonl(li->u.log.level))) goto nla_put_failure; - if (li->u.ulog.qthreshold) - if (nla_put_be16(skb, NFTA_LOG_QTHRESHOLD, - htons(li->u.ulog.qthreshold))) + + if (li->u.log.logflags) { + if (nla_put_be32(skb, NFTA_LOG_FLAGS, + htonl(li->u.log.logflags))) + goto nla_put_failure; + } + break; + case NF_LOG_TYPE_ULOG: + if (nla_put_be16(skb, NFTA_LOG_GROUP, htons(li->u.ulog.group))) goto nla_put_failure; + + if (li->u.ulog.copy_len) { + if (nla_put_be32(skb, NFTA_LOG_SNAPLEN, + htonl(li->u.ulog.copy_len))) + goto nla_put_failure; + } + if (li->u.ulog.qthreshold) { + if (nla_put_be16(skb, NFTA_LOG_QTHRESHOLD, + htons(li->u.ulog.qthreshold))) + goto nla_put_failure; + } + break; + } return 0; nla_put_failure: -- cgit v1.2.3 From 3d09fc424406b5610964507b3eb73cebbc3b4c38 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:30 -0500 Subject: tipc: eliminate case of writing to freed memory In the function tipc_nodesub_notify() we call a function pointer aggregated into the object to be notified, whereafter we set the function pointer to NULL. However, in some cases the function pointed to will free the struct containing the function pointer, resulting in a write to already freed memory. This bug seems to always have been there, without causing any notable harm. In this commit we fix the problem by inverting the order of the zeroing and the function call. Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/node_subscr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c index 7c59ab1d6ecb..2d13eea8574a 100644 --- a/net/tipc/node_subscr.c +++ b/net/tipc/node_subscr.c @@ -84,11 +84,13 @@ void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub) void tipc_nodesub_notify(struct list_head *nsub_list) { struct tipc_node_subscr *ns, *safe; + net_ev_handler handle_node_down; list_for_each_entry_safe(ns, safe, nsub_list, nodesub_list) { - if (ns->handle_node_down) { - ns->handle_node_down(ns->usr_handle); + handle_node_down = ns->handle_node_down; + if (handle_node_down) { ns->handle_node_down = NULL; + handle_node_down(ns->usr_handle); } } } -- cgit v1.2.3 From e4de5fab806f74622600ab7fd6ed22b7f911a8c5 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:31 -0500 Subject: tipc: use negative error return values in functions In some places, TIPC functions returns positive integers as return codes. This goes against standard Linux coding practice, and may even cause problems in some cases. We now change the return values of the functions filter_rcv() and filter_connect() to become signed integers, and return negative error codes when needed. The codes we use in these particular cases are still TIPC specific, since they are both part of the TIPC API and have no correspondence in errno.h Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/socket.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index ef0475568f9e..9a95dab13b7e 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1269,17 +1269,16 @@ static void tipc_data_ready(struct sock *sk) * @tsk: TIPC socket * @msg: message * - * Returns TIPC error status code and socket error status code - * once it encounters some errors + * Returns 0 (TIPC_OK) if everyting ok, -TIPC_ERR_NO_PORT otherwise */ -static u32 filter_connect(struct tipc_sock *tsk, struct sk_buff **buf) +static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf) { struct sock *sk = &tsk->sk; struct tipc_port *port = &tsk->port; struct socket *sock = sk->sk_socket; struct tipc_msg *msg = buf_msg(*buf); - u32 retval = TIPC_ERR_NO_PORT; + int retval = -TIPC_ERR_NO_PORT; int res; if (msg_mcast(msg)) @@ -1382,32 +1381,33 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) * * Called with socket lock already taken; port lock may also be taken. * - * Returns TIPC error status code (TIPC_OK if message is not to be rejected) + * Returns 0 (TIPC_OK) if message was consumed, -TIPC error code if message + * to be rejected. */ -static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) +static int filter_rcv(struct sock *sk, struct sk_buff *buf) { struct socket *sock = sk->sk_socket; struct tipc_sock *tsk = tipc_sk(sk); struct tipc_msg *msg = buf_msg(buf); unsigned int limit = rcvbuf_limit(sk, buf); - u32 res = TIPC_OK; + int rc = TIPC_OK; /* Reject message if it is wrong sort of message for socket */ if (msg_type(msg) > TIPC_DIRECT_MSG) - return TIPC_ERR_NO_PORT; + return -TIPC_ERR_NO_PORT; if (sock->state == SS_READY) { if (msg_connected(msg)) - return TIPC_ERR_NO_PORT; + return -TIPC_ERR_NO_PORT; } else { - res = filter_connect(tsk, &buf); - if (res != TIPC_OK || buf == NULL) - return res; + rc = filter_connect(tsk, &buf); + if (rc != TIPC_OK || buf == NULL) + return rc; } /* Reject message if there isn't room to queue it */ if (sk_rmem_alloc_get(sk) + buf->truesize >= limit) - return TIPC_ERR_OVERLOAD; + return -TIPC_ERR_OVERLOAD; /* Enqueue message */ TIPC_SKB_CB(buf)->handle = NULL; @@ -1429,13 +1429,13 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) */ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf) { - u32 res; + int rc; struct tipc_sock *tsk = tipc_sk(sk); uint truesize = buf->truesize; - res = filter_rcv(sk, buf); - if (unlikely(res)) - tipc_reject_msg(buf, res); + rc = filter_rcv(sk, buf); + if (unlikely(rc)) + tipc_reject_msg(buf, -rc); if (atomic_read(&tsk->dupl_rcvcnt) < TIPC_CONN_OVERLOAD_LIMIT) atomic_add(truesize, &tsk->dupl_rcvcnt); @@ -1455,7 +1455,7 @@ int tipc_sk_rcv(struct sk_buff *buf) struct tipc_port *port; struct sock *sk; u32 dport = msg_destport(buf_msg(buf)); - int err = TIPC_OK; + int rc = TIPC_OK; uint limit; /* Forward unresolved named message */ @@ -1467,7 +1467,7 @@ int tipc_sk_rcv(struct sk_buff *buf) /* Validate destination */ port = tipc_port_lock(dport); if (unlikely(!port)) { - err = TIPC_ERR_NO_PORT; + rc = -TIPC_ERR_NO_PORT; goto exit; } @@ -1478,22 +1478,22 @@ int tipc_sk_rcv(struct sk_buff *buf) bh_lock_sock(sk); if (!sock_owned_by_user(sk)) { - err = filter_rcv(sk, buf); + rc = filter_rcv(sk, buf); } else { if (sk->sk_backlog.len == 0) atomic_set(&tsk->dupl_rcvcnt, 0); limit = rcvbuf_limit(sk, buf) + atomic_read(&tsk->dupl_rcvcnt); if (sk_add_backlog(sk, buf, limit)) - err = TIPC_ERR_OVERLOAD; + rc = -TIPC_ERR_OVERLOAD; } bh_unlock_sock(sk); tipc_port_unlock(port); - if (likely(!err)) + if (likely(!rc)) return 0; exit: - tipc_reject_msg(buf, err); + tipc_reject_msg(buf, -rc); return -EHOSTUNREACH; } -- cgit v1.2.3 From 4f1688b2c63cd86f0d7bcf95a9b3040e38bd3c1a Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:32 -0500 Subject: tipc: introduce send functions for chained buffers in link The current link implementation provides several different transmit functions, depending on the characteristics of the message to be sent: if it is an iovec or an sk_buff, if it needs fragmentation or not, if the caller holds the node_lock or not. The permutation of these options gives us an unwanted amount of unnecessarily complex code. As a first step towards simplifying the send path for all messages, we introduce two new send functions at link level, tipc_link_xmit2() and __tipc_link_xmit2(). The former looks up a link to the message destination, and if one is found, it grabs the node lock and calls the second function, which works exclusively inside the node lock protection. If no link is found, and the destination is on the same node, it delivers the message directly to the local destination socket. The new functions take a buffer chain where all packet headers are already prepared, and the correct MTU has been used. These two functions will later replace all other link-level transmit functions. The functions are not backwards compatible, so we have added them as new functions with temporary names. They are tested, but have no users yet. Those will be added later in this series. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/link.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- net/tipc/link.h | 2 + net/tipc/msg.c | 96 +++++++++++++++++++++++++++++++++----- net/tipc/msg.h | 25 +++++++++- 4 files changed, 250 insertions(+), 13 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index ad2c57f5868d..68d2afb44f2f 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -850,6 +850,144 @@ int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector) return res; } +/* tipc_link_cong: determine return value and how to treat the + * sent buffer during link congestion. + * - For plain, errorless user data messages we keep the buffer and + * return -ELINKONG. + * - For all other messages we discard the buffer and return -EHOSTUNREACH + * - For TIPC internal messages we also reset the link + */ +static int tipc_link_cong(struct tipc_link *link, struct sk_buff *buf) +{ + struct tipc_msg *msg = buf_msg(buf); + uint psz = msg_size(msg); + uint imp = tipc_msg_tot_importance(msg); + u32 oport = msg_tot_origport(msg); + + if (likely(imp <= TIPC_CRITICAL_IMPORTANCE)) { + if (!msg_errcode(msg) && !msg_reroute_cnt(msg)) { + link_schedule_port(link, oport, psz); + return -ELINKCONG; + } + } else { + pr_warn("%s<%s>, send queue full", link_rst_msg, link->name); + tipc_link_reset(link); + } + kfree_skb_list(buf); + return -EHOSTUNREACH; +} + +/** + * __tipc_link_xmit2(): same as tipc_link_xmit2, but destlink is known & locked + * @link: link to use + * @buf: chain of buffers containing message + * Consumes the buffer chain, except when returning -ELINKCONG + * Returns 0 if success, otherwise errno: -ELINKCONG, -EMSGSIZE (plain socket + * user data messages) or -EHOSTUNREACH (all other messages/senders) + * Only the socket functions tipc_send_stream() and tipc_send_packet() need + * to act on the return value, since they may need to do more send attempts. + */ +int __tipc_link_xmit2(struct tipc_link *link, struct sk_buff *buf) +{ + struct tipc_msg *msg = buf_msg(buf); + uint psz = msg_size(msg); + uint qsz = link->out_queue_size; + uint sndlim = link->queue_limit[0]; + uint imp = tipc_msg_tot_importance(msg); + uint mtu = link->max_pkt; + uint ack = mod(link->next_in_no - 1); + uint seqno = link->next_out_no; + uint bc_last_in = link->owner->bclink.last_in; + struct tipc_media_addr *addr = &link->media_addr; + struct sk_buff *next = buf->next; + + /* Match queue limits against msg importance: */ + if (unlikely(qsz >= link->queue_limit[imp])) + return tipc_link_cong(link, buf); + + /* Has valid packet limit been used ? */ + if (unlikely(psz > mtu)) { + kfree_skb_list(buf); + return -EMSGSIZE; + } + + /* Prepare each packet for sending, and add to outqueue: */ + while (buf) { + next = buf->next; + msg = buf_msg(buf); + msg_set_word(msg, 2, ((ack << 16) | mod(seqno))); + msg_set_bcast_ack(msg, bc_last_in); + + if (!link->first_out) { + link->first_out = buf; + } else if (qsz < sndlim) { + link->last_out->next = buf; + } else if (tipc_msg_bundle(link->last_out, buf, mtu)) { + link->stats.sent_bundled++; + buf = next; + next = buf->next; + continue; + } else if (tipc_msg_make_bundle(&buf, mtu, link->addr)) { + link->stats.sent_bundled++; + link->stats.sent_bundles++; + link->last_out->next = buf; + if (!link->next_out) + link->next_out = buf; + } else { + link->last_out->next = buf; + if (!link->next_out) + link->next_out = buf; + } + + /* Send packet if possible: */ + if (likely(++qsz <= sndlim)) { + tipc_bearer_send(link->bearer_id, buf, addr); + link->next_out = next; + link->unacked_window = 0; + } + seqno++; + link->last_out = buf; + buf = next; + } + link->next_out_no = seqno; + link->out_queue_size = qsz; + return 0; +} + +/** + * tipc_link_xmit2() is the general link level function for message sending + * @buf: chain of buffers containing message + * @dsz: amount of user data to be sent + * @dnode: address of destination node + * @selector: a number used for deterministic link selection + * Consumes the buffer chain, except when returning -ELINKCONG + * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE + */ +int tipc_link_xmit2(struct sk_buff *buf, u32 dnode, u32 selector) +{ + struct tipc_link *link = NULL; + struct tipc_node *node; + int rc = -EHOSTUNREACH; + + node = tipc_node_find(dnode); + if (node) { + tipc_node_lock(node); + link = node->active_links[selector & 1]; + if (link) + rc = __tipc_link_xmit2(link, buf); + tipc_node_unlock(node); + } + + if (link) + return rc; + + if (likely(in_own_node(dnode))) + return tipc_sk_rcv(buf); + + kfree_skb_list(buf); + return rc; +} + /* * tipc_link_sync_xmit - synchronize broadcast link endpoints. * @@ -1238,7 +1376,7 @@ static u32 tipc_link_push_packet(struct tipc_link *l_ptr) tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr); if (msg_user(msg) == MSG_BUNDLER) - msg_set_type(msg, CLOSED_MSG); + msg_set_type(msg, BUNDLE_CLOSED); l_ptr->next_out = buf->next; return 0; } diff --git a/net/tipc/link.h b/net/tipc/link.h index 200d518b218e..227ff8120897 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -227,8 +227,10 @@ void tipc_link_reset_all(struct tipc_node *node); void tipc_link_reset(struct tipc_link *l_ptr); void tipc_link_reset_list(unsigned int bearer_id); int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector); +int tipc_link_xmit2(struct sk_buff *buf, u32 dest, u32 selector); void tipc_link_names_xmit(struct list_head *message_list, u32 dest); int __tipc_link_xmit(struct tipc_link *l_ptr, struct sk_buff *buf); +int __tipc_link_xmit2(struct tipc_link *link, struct sk_buff *buf); int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf); u32 tipc_link_get_max_pkt(u32 dest, u32 selector); int tipc_link_iovec_xmit_fast(struct tipc_port *sender, diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 8be6e94a1ca9..e02afc96edd7 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -37,20 +37,11 @@ #include "core.h" #include "msg.h" -u32 tipc_msg_tot_importance(struct tipc_msg *m) +static unsigned int align(unsigned int i) { - if (likely(msg_isdata(m))) { - if (likely(msg_orignode(m) == tipc_own_addr)) - return msg_importance(m); - return msg_importance(m) + 4; - } - if ((msg_user(m) == MSG_FRAGMENTER) && - (msg_type(m) == FIRST_FRAGMENT)) - return msg_importance(msg_get_wrapped(m)); - return msg_importance(m); + return (i + 3) & ~3u; } - void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, u32 destnode) { @@ -152,3 +143,86 @@ out_free: kfree_skb(*buf); return 0; } + +/** + * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one + * @bbuf: the existing buffer ("bundle") + * @buf: buffer to be appended + * @mtu: max allowable size for the bundle buffer + * Consumes buffer if successful + * Returns true if bundling could be performed, otherwise false + */ +bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu) +{ + struct tipc_msg *bmsg = buf_msg(bbuf); + struct tipc_msg *msg = buf_msg(buf); + unsigned int bsz = msg_size(bmsg); + unsigned int msz = msg_size(msg); + u32 start = align(bsz); + u32 max = mtu - INT_H_SIZE; + u32 pad = start - bsz; + + if (likely(msg_user(msg) == MSG_FRAGMENTER)) + return false; + if (unlikely(msg_user(msg) == CHANGEOVER_PROTOCOL)) + return false; + if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) + return false; + if (likely(msg_user(bmsg) != MSG_BUNDLER)) + return false; + if (likely(msg_type(bmsg) != BUNDLE_OPEN)) + return false; + if (unlikely(skb_tailroom(bbuf) < (pad + msz))) + return false; + if (unlikely(max < (start + msz))) + return false; + + skb_put(bbuf, pad + msz); + skb_copy_to_linear_data_offset(bbuf, start, buf->data, msz); + msg_set_size(bmsg, start + msz); + msg_set_msgcnt(bmsg, msg_msgcnt(bmsg) + 1); + bbuf->next = buf->next; + kfree_skb(buf); + return true; +} + +/** + * tipc_msg_make_bundle(): Create bundle buf and append message to its tail + * @buf: buffer to be appended and replaced + * @mtu: max allowable size for the bundle buffer, inclusive header + * @dnode: destination node for message. (Not always present in header) + * Replaces buffer if successful + * Returns true if sucess, otherwise false + */ +bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode) +{ + struct sk_buff *bbuf; + struct tipc_msg *bmsg; + struct tipc_msg *msg = buf_msg(*buf); + u32 msz = msg_size(msg); + u32 max = mtu - INT_H_SIZE; + + if (msg_user(msg) == MSG_FRAGMENTER) + return false; + if (msg_user(msg) == CHANGEOVER_PROTOCOL) + return false; + if (msg_user(msg) == BCAST_PROTOCOL) + return false; + if (msz > (max / 2)) + return false; + + bbuf = tipc_buf_acquire(max); + if (!bbuf) + return false; + + skb_trim(bbuf, INT_H_SIZE); + bmsg = buf_msg(bbuf); + tipc_msg_init(bmsg, MSG_BUNDLER, BUNDLE_OPEN, INT_H_SIZE, dnode); + msg_set_seqno(bmsg, msg_seqno(msg)); + msg_set_ack(bmsg, msg_ack(msg)); + msg_set_bcast_ack(bmsg, msg_bcast_ack(msg)); + bbuf->next = (*buf)->next; + tipc_msg_bundle(bbuf, *buf, mtu); + *buf = bbuf; + return true; +} diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 503511903d1d..41a05fa8d608 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -463,6 +463,11 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) #define FRAGMENT 1 #define LAST_FRAGMENT 2 +/* Bundling protocol message types + */ +#define BUNDLE_OPEN 0 +#define BUNDLE_CLOSED 1 + /* * Link management protocol message types */ @@ -706,12 +711,30 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n) msg_set_bits(m, 9, 0, 0xffff, n); } -u32 tipc_msg_tot_importance(struct tipc_msg *m); +static inline u32 tipc_msg_tot_importance(struct tipc_msg *m) +{ + if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT)) + return msg_importance(msg_get_wrapped(m)); + return msg_importance(m); +} + +static inline u32 msg_tot_origport(struct tipc_msg *m) +{ + if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT)) + return msg_origport(msg_get_wrapped(m)); + return msg_origport(m); +} + void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, u32 destnode); + int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, unsigned int len, int max_size, struct sk_buff **buf); int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf); +bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu); + +bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode); + #endif -- cgit v1.2.3 From 16e166b88cdfd508b88934ec0c8a0ec97e6b30f8 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:33 -0500 Subject: tipc: make link mtu easily accessible from socket Message fragmentation is currently performed at link level, inside the protection of node_lock. This potentially binds up the sending link structure for a long time, instead of letting it do other tasks, such as handle reception of new packets. In this commit, we make the MTUs of each active link become easily accessible from the socket level, i.e., without taking any spinlock or dereferencing the target link pointer. This way, we make it possible to perform fragmentation in the sending socket, before sending the whole fragment chain to the link for transport. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/node.c | 25 +++++++++++++++++++++---- net/tipc/node.h | 17 +++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/net/tipc/node.c b/net/tipc/node.c index 5b44c3041be4..d959343043fd 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -1,7 +1,7 @@ /* * net/tipc/node.c: TIPC node management routines * - * Copyright (c) 2000-2006, 2012 Ericsson AB + * Copyright (c) 2000-2006, 2012-2014, Ericsson AB * Copyright (c) 2005-2006, 2010-2014, Wind River Systems * All rights reserved. * @@ -155,21 +155,25 @@ void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr) if (!active[0]) { active[0] = active[1] = l_ptr; node_established_contact(n_ptr); - return; + goto exit; } if (l_ptr->priority < active[0]->priority) { pr_info("New link <%s> becomes standby\n", l_ptr->name); - return; + goto exit; } tipc_link_dup_queue_xmit(active[0], l_ptr); if (l_ptr->priority == active[0]->priority) { active[0] = l_ptr; - return; + goto exit; } pr_info("Old link <%s> becomes standby\n", active[0]->name); if (active[1] != active[0]) pr_info("Old link <%s> becomes standby\n", active[1]->name); active[0] = active[1] = l_ptr; +exit: + /* Leave room for changeover header when returning 'mtu' to users: */ + n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE; + n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE; } /** @@ -229,6 +233,19 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr) tipc_link_failover_send_queue(l_ptr); else node_lost_contact(n_ptr); + + /* Leave room for changeover header when returning 'mtu' to users: */ + if (active[0]) { + n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE; + n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE; + return; + } + + /* Loopback link went down? No fragmentation needed from now on. */ + if (n_ptr->addr == tipc_own_addr) { + n_ptr->act_mtus[0] = MAX_MSG_SIZE; + n_ptr->act_mtus[1] = MAX_MSG_SIZE; + } } int tipc_node_active_links(struct tipc_node *n_ptr) diff --git a/net/tipc/node.h b/net/tipc/node.h index 9087063793f2..b61716a8218e 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -41,6 +41,7 @@ #include "addr.h" #include "net.h" #include "bearer.h" +#include "msg.h" /* * Out-of-range value for node signature @@ -105,6 +106,7 @@ struct tipc_node { spinlock_t lock; struct hlist_node hash; struct tipc_link *active_links[2]; + u32 act_mtus[2]; struct tipc_link *links[MAX_BEARERS]; unsigned int action_flags; struct tipc_node_bclink bclink; @@ -143,4 +145,19 @@ static inline bool tipc_node_blocked(struct tipc_node *node) TIPC_NOTIFY_NODE_DOWN | TIPC_WAIT_OWN_LINKS_DOWN)); } +static inline uint tipc_node_get_mtu(u32 addr, u32 selector) +{ + struct tipc_node *node; + u32 mtu; + + node = tipc_node_find(addr); + + if (likely(node)) + mtu = node->act_mtus[selector & 1]; + else + mtu = MAX_MSG_SIZE; + + return mtu; +} + #endif -- cgit v1.2.3 From 067608e9d019d6477fd45dd948e81af0e5bf599f Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:34 -0500 Subject: tipc: introduce direct iovec to buffer chain fragmentation function Fragmentation at message sending is currently performed in two places in link.c, depending on whether data to be transmitted is delivered in the form of an iovec or as a big sk_buff. Those functions are also tightly entangled with the send functions that are using them. We now introduce a re-entrant, standalone function, tipc_msg_build2(), that builds a packet chain directly from an iovec. Each fragment is sized according to the MTU value given by the caller, and is prepended with a correctly built fragment header, when needed. The function is independent from who is calling and where the chain will be delivered, as long as the caller is able to indicate a correct MTU. The function is tested, but not called by anybody yet. Since it is incompatible with the existing tipc_msg_build(), and we cannot yet remove that function, we have given it a temporary name. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/msg.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ net/tipc/msg.h | 3 ++ 2 files changed, 105 insertions(+) diff --git a/net/tipc/msg.c b/net/tipc/msg.c index e02afc96edd7..4093b4c94d26 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -144,6 +144,108 @@ out_free: return 0; } + +/** + * tipc_msg_build2 - create buffer chain containing specified header and data + * @mhdr: Message header, to be prepended to data + * @iov: User data + * @offset: Posision in iov to start copying from + * @dsz: Total length of user data + * @pktmax: Max packet size that can be used + * @chain: Buffer or chain of buffers to be returned to caller + * Returns message data size or errno: -ENOMEM, -EFAULT + */ +int tipc_msg_build2(struct tipc_msg *mhdr, struct iovec const *iov, + int offset, int dsz, int pktmax , struct sk_buff **chain) +{ + int mhsz = msg_hdr_sz(mhdr); + int msz = mhsz + dsz; + int pktno = 1; + int pktsz; + int pktrem = pktmax; + int drem = dsz; + struct tipc_msg pkthdr; + struct sk_buff *buf, *prev; + char *pktpos; + int rc; + + msg_set_size(mhdr, msz); + + /* No fragmentation needed? */ + if (likely(msz <= pktmax)) { + buf = tipc_buf_acquire(msz); + *chain = buf; + if (unlikely(!buf)) + return -ENOMEM; + skb_copy_to_linear_data(buf, mhdr, mhsz); + pktpos = buf->data + mhsz; + if (!dsz || !memcpy_fromiovecend(pktpos, iov, offset, dsz)) + return dsz; + rc = -EFAULT; + goto error; + } + + /* Prepare reusable fragment header */ + tipc_msg_init(&pkthdr, MSG_FRAGMENTER, FIRST_FRAGMENT, + INT_H_SIZE, msg_destnode(mhdr)); + msg_set_size(&pkthdr, pktmax); + msg_set_fragm_no(&pkthdr, pktno); + + /* Prepare first fragment */ + *chain = buf = tipc_buf_acquire(pktmax); + if (!buf) + return -ENOMEM; + pktpos = buf->data; + skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE); + pktpos += INT_H_SIZE; + pktrem -= INT_H_SIZE; + skb_copy_to_linear_data_offset(buf, INT_H_SIZE, mhdr, mhsz); + pktpos += mhsz; + pktrem -= mhsz; + + do { + if (drem < pktrem) + pktrem = drem; + + if (memcpy_fromiovecend(pktpos, iov, offset, pktrem)) { + rc = -EFAULT; + goto error; + } + drem -= pktrem; + offset += pktrem; + + if (!drem) + break; + + /* Prepare new fragment: */ + if (drem < (pktmax - INT_H_SIZE)) + pktsz = drem + INT_H_SIZE; + else + pktsz = pktmax; + prev = buf; + buf = tipc_buf_acquire(pktsz); + if (!buf) { + rc = -ENOMEM; + goto error; + } + prev->next = buf; + msg_set_type(&pkthdr, FRAGMENT); + msg_set_size(&pkthdr, pktsz); + msg_set_fragm_no(&pkthdr, ++pktno); + skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE); + pktpos = buf->data + INT_H_SIZE; + pktrem = pktsz - INT_H_SIZE; + + } while (1); + + msg_set_type(buf_msg(buf), LAST_FRAGMENT); + return dsz; +error: + kfree_skb_list(*chain); + *chain = NULL; + return rc; +} + /** * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one * @bbuf: the existing buffer ("bundle") diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 41a05fa8d608..5e1339d60c69 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -737,4 +737,7 @@ bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu); bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode); +int tipc_msg_build2(struct tipc_msg *mhdr, struct iovec const *iov, + int offset, int dsz, int mtu , struct sk_buff **chain); + #endif -- cgit v1.2.3 From 8db1bae30b7cd3c3abc05f467d0f7c69b33b80e9 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:35 -0500 Subject: tipc: separate building and sending of rejected messages The way we build and send rejected message is currenty perceived as hard to follow, partly because we let the transmission go via deep call chains through functions such as tipc_reject_msg() and net_route_msg(). We want to remove those functions, and make the call sequences shallower and simpler. For this purpose, we separate building and sending of rejected messages. We build the reject message using the new function tipc_msg_reverse(), and let the transmission go via the newly introduced tipc_link_xmit2() function, as all transmission eventually will do. We also ensure that all calls to tipc_link_xmit2() are made outside port_lock/bh_lock_sock. Finally, we replace all calls to tipc_reject_msg() with the two new calls at all locations in the code that we want to keep. The remaining calls are made from code that we are planning to remove, along with tipc_reject_msg() itself. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/msg.c | 42 ++++++++++++++++++++++++++++++++++++++++++ net/tipc/msg.h | 2 ++ net/tipc/socket.c | 28 ++++++++++++++++++++-------- 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 4093b4c94d26..6070dd0ec634 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -37,6 +37,8 @@ #include "core.h" #include "msg.h" +#define MAX_FORWARD_SIZE 1024 + static unsigned int align(unsigned int i) { return (i + 3) & ~3u; @@ -328,3 +330,43 @@ bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode) *buf = bbuf; return true; } + +/** + * tipc_msg_reverse(): swap source and destination addresses and add error code + * @buf: buffer containing message to be reversed + * @dnode: return value: node where to send message after reversal + * @err: error code to be set in message + * Consumes buffer if failure + * Returns true if success, otherwise false + */ +bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err) +{ + struct tipc_msg *msg = buf_msg(buf); + uint imp = msg_importance(msg); + struct tipc_msg ohdr; + uint rdsz = min_t(uint, msg_data_sz(msg), MAX_FORWARD_SIZE); + + if (skb_linearize(buf) || !msg_isdata(msg)) + goto exit; + if (msg_dest_droppable(msg) || msg_errcode(msg)) + goto exit; + + memcpy(&ohdr, msg, msg_hdr_sz(msg)); + msg_set_importance(msg, min_t(uint, ++imp, TIPC_CRITICAL_IMPORTANCE)); + msg_set_errcode(msg, err); + msg_set_origport(msg, msg_destport(&ohdr)); + msg_set_destport(msg, msg_origport(&ohdr)); + msg_set_prevnode(msg, tipc_own_addr); + if (!msg_short(msg)) { + msg_set_orignode(msg, msg_destnode(&ohdr)); + msg_set_destnode(msg, msg_orignode(&ohdr)); + } + msg_set_size(msg, msg_hdr_sz(msg) + rdsz); + skb_trim(buf, msg_size(msg)); + skb_orphan(buf); + *dnode = msg_orignode(&ohdr); + return true; +exit: + kfree_skb(buf); + return false; +} diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 5e1339d60c69..38050941a504 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -725,6 +725,8 @@ static inline u32 msg_tot_origport(struct tipc_msg *m) return msg_origport(m); } +bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err); + void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, u32 destnode); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 9a95dab13b7e..5961a6335f49 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -39,6 +39,7 @@ #include "node.h" #include +#include "link.h" #define SS_LISTENING -1 /* socket is listening */ #define SS_READY -2 /* socket is connectionless */ @@ -123,9 +124,12 @@ static void advance_rx_queue(struct sock *sk) static void reject_rx_queue(struct sock *sk) { struct sk_buff *buf; + u32 dnode; - while ((buf = __skb_dequeue(&sk->sk_receive_queue))) - tipc_reject_msg(buf, TIPC_ERR_NO_PORT); + while ((buf = __skb_dequeue(&sk->sk_receive_queue))) { + if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT)) + tipc_link_xmit2(buf, dnode, 0); + } } /** @@ -303,6 +307,7 @@ static int tipc_release(struct socket *sock) struct tipc_sock *tsk; struct tipc_port *port; struct sk_buff *buf; + u32 dnode; /* * Exit if socket isn't fully initialized (occurs when a failed accept() @@ -331,7 +336,8 @@ static int tipc_release(struct socket *sock) sock->state = SS_DISCONNECTING; tipc_port_disconnect(port->ref); } - tipc_reject_msg(buf, TIPC_ERR_NO_PORT); + if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT)) + tipc_link_xmit2(buf, dnode, 0); } } @@ -1430,14 +1436,15 @@ static int filter_rcv(struct sock *sk, struct sk_buff *buf) static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf) { int rc; + u32 onode; struct tipc_sock *tsk = tipc_sk(sk); uint truesize = buf->truesize; rc = filter_rcv(sk, buf); - if (unlikely(rc)) - tipc_reject_msg(buf, -rc); - if (atomic_read(&tsk->dupl_rcvcnt) < TIPC_CONN_OVERLOAD_LIMIT) + if (unlikely(rc && tipc_msg_reverse(buf, &onode, -rc))) + tipc_link_xmit2(buf, onode, 0); + else if (atomic_read(&tsk->dupl_rcvcnt) < TIPC_CONN_OVERLOAD_LIMIT) atomic_add(truesize, &tsk->dupl_rcvcnt); return 0; @@ -1457,6 +1464,7 @@ int tipc_sk_rcv(struct sk_buff *buf) u32 dport = msg_destport(buf_msg(buf)); int rc = TIPC_OK; uint limit; + u32 dnode; /* Forward unresolved named message */ if (unlikely(!dport)) { @@ -1493,7 +1501,9 @@ int tipc_sk_rcv(struct sk_buff *buf) if (likely(!rc)) return 0; exit: - tipc_reject_msg(buf, -rc); + if (!tipc_msg_reverse(buf, &dnode, -rc)) + return -EHOSTUNREACH; + tipc_link_xmit2(buf, dnode, 0); return -EHOSTUNREACH; } @@ -1758,6 +1768,7 @@ static int tipc_shutdown(struct socket *sock, int how) struct tipc_sock *tsk = tipc_sk(sk); struct tipc_port *port = &tsk->port; struct sk_buff *buf; + u32 peer; int res; if (how != SHUT_RDWR) @@ -1778,7 +1789,8 @@ restart: goto restart; } tipc_port_disconnect(port->ref); - tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN); + if (tipc_msg_reverse(buf, &peer, TIPC_CONN_SHUTDOWN)) + tipc_link_xmit2(buf, peer, 0); } else { tipc_port_shutdown(port->ref); } -- cgit v1.2.3 From 5a379074a7dd6d288ec9e6472769ba0e0c54dd85 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:36 -0500 Subject: tipc: introduce message evaluation function When a message arrives in a node and finds no destination socket, we may need to drop it, reject it, or forward it after a secondary destination lookup. The latter two cases currently results in a code path that is perceived as complex, because it follows a deep call chain via obscure functions such as net_route_named_msg() and net_route_msg(). We now introduce a function, tipc_msg_eval(), that takes the decision about whether such a message should be rejected or forwarded, but leaves it to the caller to actually perform the indicated action. If the decision is 'reject', it is still the task of the recently introduced function tipc_msg_reverse() to take the final decision about whether the message is rejectable or not. In the latter case it drops the message. As a result of this change, we can finally eliminate the function net_route_named_msg(), and hence become independent of net_route_msg(). Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/msg.c | 38 ++++++++++++++++++++++++++++++++++++++ net/tipc/msg.h | 2 ++ net/tipc/net.c | 33 ++++++--------------------------- net/tipc/socket.c | 16 +++++----------- 4 files changed, 51 insertions(+), 38 deletions(-) diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 6070dd0ec634..7bfc4422bf2c 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -36,6 +36,8 @@ #include "core.h" #include "msg.h" +#include "addr.h" +#include "name_table.h" #define MAX_FORWARD_SIZE 1024 @@ -370,3 +372,39 @@ exit: kfree_skb(buf); return false; } + +/** + * tipc_msg_eval: determine fate of message that found no destination + * @buf: the buffer containing the message. + * @dnode: return value: next-hop node, if message to be forwarded + * @err: error code to use, if message to be rejected + * + * Does not consume buffer + * Returns 0 (TIPC_OK) if message ok and we can try again, -TIPC error + * code if message to be rejected + */ +int tipc_msg_eval(struct sk_buff *buf, u32 *dnode) +{ + struct tipc_msg *msg = buf_msg(buf); + u32 dport; + + if (msg_type(msg) != TIPC_NAMED_MSG) + return -TIPC_ERR_NO_PORT; + if (skb_linearize(buf)) + return -TIPC_ERR_NO_NAME; + if (msg_data_sz(msg) > MAX_FORWARD_SIZE) + return -TIPC_ERR_NO_NAME; + if (msg_reroute_cnt(msg) > 0) + return -TIPC_ERR_NO_NAME; + + *dnode = addr_domain(msg_lookup_scope(msg)); + dport = tipc_nametbl_translate(msg_nametype(msg), + msg_nameinst(msg), + dnode); + if (!dport) + return -TIPC_ERR_NO_NAME; + msg_incr_reroute_cnt(msg); + msg_set_destnode(msg, *dnode); + msg_set_destport(msg, dport); + return TIPC_OK; +} diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 38050941a504..7d574346e75e 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -727,6 +727,8 @@ static inline u32 msg_tot_origport(struct tipc_msg *m) bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err); +int tipc_msg_eval(struct sk_buff *buf, u32 *dnode); + void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, u32 destnode); diff --git a/net/tipc/net.c b/net/tipc/net.c index f64375e7f99f..5f7d6ffb5465 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c @@ -1,7 +1,7 @@ /* * net/tipc/net.c: TIPC network routing code * - * Copyright (c) 1995-2006, Ericsson AB + * Copyright (c) 1995-2006, 2014, Ericsson AB * Copyright (c) 2005, 2010-2011, Wind River Systems * All rights reserved. * @@ -103,29 +103,6 @@ * This is always used within the scope of a tipc_nametbl_lock(read). * - A local spin_lock protecting the queue of subscriber events. */ - -static void net_route_named_msg(struct sk_buff *buf) -{ - struct tipc_msg *msg = buf_msg(buf); - u32 dnode; - u32 dport; - - if (!msg_named(msg)) { - kfree_skb(buf); - return; - } - - dnode = addr_domain(msg_lookup_scope(msg)); - dport = tipc_nametbl_translate(msg_nametype(msg), msg_nameinst(msg), &dnode); - if (dport) { - msg_set_destnode(msg, dnode); - msg_set_destport(msg, dport); - tipc_net_route_msg(buf); - return; - } - tipc_reject_msg(buf, TIPC_ERR_NO_NAME); -} - void tipc_net_route_msg(struct sk_buff *buf) { struct tipc_msg *msg; @@ -141,10 +118,12 @@ void tipc_net_route_msg(struct sk_buff *buf) if (msg_isdata(msg)) { if (msg_mcast(msg)) tipc_port_mcast_rcv(buf, NULL); - else if (msg_destport(msg)) + else if (msg_destport(msg)) { tipc_sk_rcv(buf); - else - net_route_named_msg(buf); + } else { + pr_warn("Cannot route msg; no destination\n"); + kfree_skb(buf); + } return; } switch (msg_user(msg)) { diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 5961a6335f49..e642ed5b3602 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1466,16 +1466,10 @@ int tipc_sk_rcv(struct sk_buff *buf) uint limit; u32 dnode; - /* Forward unresolved named message */ - if (unlikely(!dport)) { - tipc_net_route_msg(buf); - return 0; - } - - /* Validate destination */ + /* Validate destination and message */ port = tipc_port_lock(dport); if (unlikely(!port)) { - rc = -TIPC_ERR_NO_PORT; + rc = tipc_msg_eval(buf, &dnode); goto exit; } @@ -1494,17 +1488,17 @@ int tipc_sk_rcv(struct sk_buff *buf) if (sk_add_backlog(sk, buf, limit)) rc = -TIPC_ERR_OVERLOAD; } - bh_unlock_sock(sk); tipc_port_unlock(port); if (likely(!rc)) return 0; exit: - if (!tipc_msg_reverse(buf, &dnode, -rc)) + if ((rc < 0) && !tipc_msg_reverse(buf, &dnode, -rc)) return -EHOSTUNREACH; + tipc_link_xmit2(buf, dnode, 0); - return -EHOSTUNREACH; + return (rc < 0) ? -EHOSTUNREACH : 0; } static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) -- cgit v1.2.3 From e2dafe87d328774a94fdd77718422b9cbd97ed47 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:37 -0500 Subject: tipc: RDM/DGRAM transport uses new fragmenting and sending functions We merge the code for sending port name and port identity addressed messages into the corresponding send functions in socket.c, and start using the new fragmenting and transmit functions we just have introduced. This saves a call level and quite a few code lines, as well as making this part of the code easier to follow. As a consequence, the functions tipc_send2name() and tipc_send2port() in port.c can be removed. For practical reasons, we break out the code for sending multicast messages from tipc_sendmsg() and move it into a separate function, tipc_sendmcast(), but we do not yet convert it into using the new build/send functions. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/port.c | 90 ------------------------------- net/tipc/port.h | 11 ---- net/tipc/socket.c | 158 +++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 110 insertions(+), 149 deletions(-) diff --git a/net/tipc/port.c b/net/tipc/port.c index 5fd7acce01ea..8350ec932514 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -806,93 +806,3 @@ int tipc_send(struct tipc_port *p_ptr, } return -ELINKCONG; } - -/** - * tipc_send2name - send message sections to port name - */ -int tipc_send2name(struct tipc_port *p_ptr, - struct tipc_name const *name, - unsigned int domain, - struct iovec const *msg_sect, - unsigned int len) -{ - struct tipc_msg *msg; - u32 destnode = domain; - u32 destport; - int res; - - if (p_ptr->connected) - return -EINVAL; - - msg = &p_ptr->phdr; - msg_set_type(msg, TIPC_NAMED_MSG); - msg_set_hdr_sz(msg, NAMED_H_SIZE); - msg_set_nametype(msg, name->type); - msg_set_nameinst(msg, name->instance); - msg_set_lookup_scope(msg, tipc_addr_scope(domain)); - destport = tipc_nametbl_translate(name->type, name->instance, &destnode); - msg_set_destnode(msg, destnode); - msg_set_destport(msg, destport); - - if (likely(destport || destnode)) { - if (likely(in_own_node(destnode))) - res = tipc_port_iovec_rcv(p_ptr, msg_sect, len); - else if (tipc_own_addr) - res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, - destnode); - else - res = tipc_port_iovec_reject(p_ptr, msg, msg_sect, - len, TIPC_ERR_NO_NODE); - if (likely(res != -ELINKCONG)) { - if (res > 0) - p_ptr->sent++; - return res; - } - if (tipc_port_unreliable(p_ptr)) - return len; - - return -ELINKCONG; - } - return tipc_port_iovec_reject(p_ptr, msg, msg_sect, len, - TIPC_ERR_NO_NAME); -} - -/** - * tipc_send2port - send message sections to port identity - */ -int tipc_send2port(struct tipc_port *p_ptr, - struct tipc_portid const *dest, - struct iovec const *msg_sect, - unsigned int len) -{ - struct tipc_msg *msg; - int res; - - if (p_ptr->connected) - return -EINVAL; - - msg = &p_ptr->phdr; - msg_set_type(msg, TIPC_DIRECT_MSG); - msg_set_lookup_scope(msg, 0); - msg_set_destnode(msg, dest->node); - msg_set_destport(msg, dest->ref); - msg_set_hdr_sz(msg, BASIC_H_SIZE); - - if (in_own_node(dest->node)) - res = tipc_port_iovec_rcv(p_ptr, msg_sect, len); - else if (tipc_own_addr) - res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, - dest->node); - else - res = tipc_port_iovec_reject(p_ptr, msg, msg_sect, len, - TIPC_ERR_NO_NODE); - if (likely(res != -ELINKCONG)) { - if (res > 0) - p_ptr->sent++; - return res; - } - if (tipc_port_unreliable(p_ptr)) - return len; - - return -ELINKCONG; -} diff --git a/net/tipc/port.h b/net/tipc/port.h index cf4ca5b1d9a4..e566d55e2655 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -140,17 +140,6 @@ int tipc_send(struct tipc_port *port, struct iovec const *msg_sect, unsigned int len); -int tipc_send2name(struct tipc_port *port, - struct tipc_name const *name, - u32 domain, - struct iovec const *msg_sect, - unsigned int len); - -int tipc_send2port(struct tipc_port *port, - struct tipc_portid const *dest, - struct iovec const *msg_sect, - unsigned int len); - int tipc_port_mcast_xmit(struct tipc_port *port, struct tipc_name_seq const *seq, struct iovec const *msg, diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e642ed5b3602..5690751cbfa5 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -36,8 +36,9 @@ #include "core.h" #include "port.h" +#include "name_table.h" #include "node.h" - +#include "link.h" #include #include "link.h" @@ -545,6 +546,8 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) { struct tipc_cfg_msg_hdr hdr; + if (unlikely(dest->addrtype == TIPC_ADDR_ID)) + return 0; if (likely(dest->addr.name.name.type >= TIPC_RESERVED_TYPES)) return 0; if (likely(dest->addr.name.name.type == TIPC_TOP_SRV)) @@ -587,13 +590,49 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) return 0; } +/** + * tipc_sendmcast - send multicast message + * @sock: socket structure + * @seq: destination address + * @iov: message data to send + * @dsz: total length of message data + * @timeo: timeout to wait for wakeup + * + * Called from function tipc_sendmsg(), which has done all sanity checks + * Returns the number of bytes sent on success, or errno + */ +static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq, + struct iovec *iov, size_t dsz, long timeo) +{ + struct sock *sk = sock->sk; + struct tipc_sock *tsk = tipc_sk(sk); + int rc; + + do { + if (sock->state != SS_READY) { + rc = -EOPNOTSUPP; + break; + } + rc = tipc_port_mcast_xmit(&tsk->port, seq, iov, dsz); + if (likely(rc >= 0)) { + if (sock->state != SS_READY) + sock->state = SS_CONNECTING; + break; + } + if (rc != -ELINKCONG) + break; + rc = tipc_wait_for_sndmsg(sock, &timeo); + } while (!rc); + + return rc; +} /** * tipc_sendmsg - send message in connectionless manner * @iocb: if NULL, indicates that socket lock is already held * @sock: socket structure * @m: message to send - * @total_len: length of message + * @dsz: amount of user data to be sent * * Message must have an destination specified explicitly. * Used for SOCK_RDM and SOCK_DGRAM messages, @@ -603,93 +642,116 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) * Returns the number of bytes sent on success, or errno otherwise */ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *m, size_t total_len) + struct msghdr *m, size_t dsz) { + DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); struct sock *sk = sock->sk; struct tipc_sock *tsk = tipc_sk(sk); struct tipc_port *port = &tsk->port; - DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); - int needs_conn; + struct tipc_msg *mhdr = &port->phdr; + struct iovec *iov = m->msg_iov; + u32 dnode, dport; + struct sk_buff *buf; + struct tipc_name_seq *seq = &dest->addr.nameseq; + u32 mtu; long timeo; - int res = -EINVAL; + int rc = -EINVAL; if (unlikely(!dest)) return -EDESTADDRREQ; + if (unlikely((m->msg_namelen < sizeof(*dest)) || (dest->family != AF_TIPC))) return -EINVAL; - if (total_len > TIPC_MAX_USER_MSG_SIZE) + + if (dsz > TIPC_MAX_USER_MSG_SIZE) return -EMSGSIZE; if (iocb) lock_sock(sk); - needs_conn = (sock->state != SS_READY); - if (unlikely(needs_conn)) { + if (unlikely(sock->state != SS_READY)) { if (sock->state == SS_LISTENING) { - res = -EPIPE; + rc = -EPIPE; goto exit; } if (sock->state != SS_UNCONNECTED) { - res = -EISCONN; + rc = -EISCONN; goto exit; } if (tsk->port.published) { - res = -EOPNOTSUPP; + rc = -EOPNOTSUPP; goto exit; } if (dest->addrtype == TIPC_ADDR_NAME) { tsk->port.conn_type = dest->addr.name.name.type; tsk->port.conn_instance = dest->addr.name.name.instance; } - - /* Abort any pending connection attempts (very unlikely) */ - reject_rx_queue(sk); } + rc = dest_name_check(dest, m); + if (rc) + goto exit; timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); - do { - if (dest->addrtype == TIPC_ADDR_NAME) { - res = dest_name_check(dest, m); - if (res) - break; - res = tipc_send2name(port, - &dest->addr.name.name, - dest->addr.name.domain, - m->msg_iov, - total_len); - } else if (dest->addrtype == TIPC_ADDR_ID) { - res = tipc_send2port(port, - &dest->addr.id, - m->msg_iov, - total_len); - } else if (dest->addrtype == TIPC_ADDR_MCAST) { - if (needs_conn) { - res = -EOPNOTSUPP; - break; - } - res = dest_name_check(dest, m); - if (res) - break; - res = tipc_port_mcast_xmit(port, - &dest->addr.nameseq, - m->msg_iov, - total_len); + + if (dest->addrtype == TIPC_ADDR_MCAST) { + rc = tipc_sendmcast(sock, seq, iov, dsz, timeo); + goto exit; + } else if (dest->addrtype == TIPC_ADDR_NAME) { + u32 type = dest->addr.name.name.type; + u32 inst = dest->addr.name.name.instance; + u32 domain = dest->addr.name.domain; + + dnode = domain; + msg_set_type(mhdr, TIPC_NAMED_MSG); + msg_set_hdr_sz(mhdr, NAMED_H_SIZE); + msg_set_nametype(mhdr, type); + msg_set_nameinst(mhdr, inst); + msg_set_lookup_scope(mhdr, tipc_addr_scope(domain)); + dport = tipc_nametbl_translate(type, inst, &dnode); + msg_set_destnode(mhdr, dnode); + msg_set_destport(mhdr, dport); + if (unlikely(!dport && !dnode)) { + rc = -EHOSTUNREACH; + goto exit; } - if (likely(res != -ELINKCONG)) { - if (needs_conn && (res >= 0)) + } else if (dest->addrtype == TIPC_ADDR_ID) { + dnode = dest->addr.id.node; + msg_set_type(mhdr, TIPC_DIRECT_MSG); + msg_set_lookup_scope(mhdr, 0); + msg_set_destnode(mhdr, dnode); + msg_set_destport(mhdr, dest->addr.id.ref); + msg_set_hdr_sz(mhdr, BASIC_H_SIZE); + } + +new_mtu: + mtu = tipc_node_get_mtu(dnode, tsk->port.ref); + rc = tipc_msg_build2(mhdr, iov, 0, dsz, mtu, &buf); + if (rc < 0) + goto exit; + + do { + rc = tipc_link_xmit2(buf, dnode, tsk->port.ref); + if (likely(rc >= 0)) { + if (sock->state != SS_READY) sock->state = SS_CONNECTING; + rc = dsz; break; } - res = tipc_wait_for_sndmsg(sock, &timeo); - if (res) + if (rc == -EMSGSIZE) + goto new_mtu; + + if (rc != -ELINKCONG) break; - } while (1); + + rc = tipc_wait_for_sndmsg(sock, &timeo); + } while (!rc); exit: if (iocb) release_sock(sk); - return res; + + return rc; } static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) -- cgit v1.2.3 From 4ccfe5e0419eefcab3010ff6a87ffb03aef86c5d Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:38 -0500 Subject: tipc: connection oriented transport uses new send functions We move the message sending across established connections to use the message preparation and send functions introduced earlier in this series. We now do the message preparation and call to the link send function directly from the socket, instead of going via the port layer. As a consequence of this change, the functions tipc_send(), tipc_port_iovec_rcv(), tipc_port_iovec_reject() and tipc_reject_msg() become unreferenced and can be eliminated from port.c. For the same reason, the functions tipc_link_xmit_fast(), tipc_link_iovec_xmit_long() and tipc_link_iovec_fast() can be eliminated from link.c. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/link.c | 249 ------------------------------------------------------ net/tipc/port.c | 142 +------------------------------ net/tipc/port.h | 12 --- net/tipc/socket.c | 180 +++++++++++++++------------------------ 4 files changed, 70 insertions(+), 513 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 68d2afb44f2f..93a8033263c0 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -82,9 +82,6 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf); static int tipc_link_tunnel_rcv(struct tipc_node *n_ptr, struct sk_buff **buf); static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); -static int tipc_link_iovec_long_xmit(struct tipc_port *sender, - struct iovec const *msg_sect, - unsigned int len, u32 destnode); static void link_state_event(struct tipc_link *l_ptr, u32 event); static void link_reset_statistics(struct tipc_link *l_ptr); static void link_print(struct tipc_link *l_ptr, const char *str); @@ -1070,252 +1067,6 @@ void tipc_link_names_xmit(struct list_head *message_list, u32 dest) } } -/* - * tipc_link_xmit_fast: Entry for data messages where the - * destination link is known and the header is complete, - * inclusive total message length. Very time critical. - * Link is locked. Returns user data length. - */ -static int tipc_link_xmit_fast(struct tipc_link *l_ptr, struct sk_buff *buf, - u32 *used_max_pkt) -{ - struct tipc_msg *msg = buf_msg(buf); - int res = msg_data_sz(msg); - - if (likely(!link_congested(l_ptr))) { - if (likely(msg_size(msg) <= l_ptr->max_pkt)) { - link_add_to_outqueue(l_ptr, buf, msg); - tipc_bearer_send(l_ptr->bearer_id, buf, - &l_ptr->media_addr); - l_ptr->unacked_window = 0; - return res; - } - else - *used_max_pkt = l_ptr->max_pkt; - } - return __tipc_link_xmit(l_ptr, buf); /* All other cases */ -} - -/* - * tipc_link_iovec_xmit_fast: Entry for messages where the - * destination processor is known and the header is complete, - * except for total message length. - * Returns user data length or errno. - */ -int tipc_link_iovec_xmit_fast(struct tipc_port *sender, - struct iovec const *msg_sect, - unsigned int len, u32 destaddr) -{ - struct tipc_msg *hdr = &sender->phdr; - struct tipc_link *l_ptr; - struct sk_buff *buf; - struct tipc_node *node; - int res; - u32 selector = msg_origport(hdr) & 1; - -again: - /* - * Try building message using port's max_pkt hint. - * (Must not hold any locks while building message.) - */ - res = tipc_msg_build(hdr, msg_sect, len, sender->max_pkt, &buf); - /* Exit if build request was invalid */ - if (unlikely(res < 0)) - return res; - - node = tipc_node_find(destaddr); - if (likely(node)) { - tipc_node_lock(node); - l_ptr = node->active_links[selector]; - if (likely(l_ptr)) { - if (likely(buf)) { - res = tipc_link_xmit_fast(l_ptr, buf, - &sender->max_pkt); -exit: - tipc_node_unlock(node); - return res; - } - - /* Exit if link (or bearer) is congested */ - if (link_congested(l_ptr)) { - res = link_schedule_port(l_ptr, - sender->ref, res); - goto exit; - } - - /* - * Message size exceeds max_pkt hint; update hint, - * then re-try fast path or fragment the message - */ - sender->max_pkt = l_ptr->max_pkt; - tipc_node_unlock(node); - - - if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt) - goto again; - - return tipc_link_iovec_long_xmit(sender, msg_sect, - len, destaddr); - } - tipc_node_unlock(node); - } - - /* Couldn't find a link to the destination node */ - kfree_skb(buf); - tipc_port_iovec_reject(sender, hdr, msg_sect, len, TIPC_ERR_NO_NODE); - return -ENETUNREACH; -} - -/* - * tipc_link_iovec_long_xmit(): Entry for long messages where the - * destination node is known and the header is complete, - * inclusive total message length. - * Link and bearer congestion status have been checked to be ok, - * and are ignored if they change. - * - * Note that fragments do not use the full link MTU so that they won't have - * to undergo refragmentation if link changeover causes them to be sent - * over another link with an additional tunnel header added as prefix. - * (Refragmentation will still occur if the other link has a smaller MTU.) - * - * Returns user data length or errno. - */ -static int tipc_link_iovec_long_xmit(struct tipc_port *sender, - struct iovec const *msg_sect, - unsigned int len, u32 destaddr) -{ - struct tipc_link *l_ptr; - struct tipc_node *node; - struct tipc_msg *hdr = &sender->phdr; - u32 dsz = len; - u32 max_pkt, fragm_sz, rest; - struct tipc_msg fragm_hdr; - struct sk_buff *buf, *buf_chain, *prev; - u32 fragm_crs, fragm_rest, hsz, sect_rest; - const unchar __user *sect_crs; - int curr_sect; - u32 fragm_no; - int res = 0; - -again: - fragm_no = 1; - max_pkt = sender->max_pkt - INT_H_SIZE; - /* leave room for tunnel header in case of link changeover */ - fragm_sz = max_pkt - INT_H_SIZE; - /* leave room for fragmentation header in each fragment */ - rest = dsz; - fragm_crs = 0; - fragm_rest = 0; - sect_rest = 0; - sect_crs = NULL; - curr_sect = -1; - - /* Prepare reusable fragment header */ - tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, - INT_H_SIZE, msg_destnode(hdr)); - msg_set_size(&fragm_hdr, max_pkt); - msg_set_fragm_no(&fragm_hdr, 1); - - /* Prepare header of first fragment */ - buf_chain = buf = tipc_buf_acquire(max_pkt); - if (!buf) - return -ENOMEM; - buf->next = NULL; - skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE); - hsz = msg_hdr_sz(hdr); - skb_copy_to_linear_data_offset(buf, INT_H_SIZE, hdr, hsz); - - /* Chop up message */ - fragm_crs = INT_H_SIZE + hsz; - fragm_rest = fragm_sz - hsz; - - do { /* For all sections */ - u32 sz; - - if (!sect_rest) { - sect_rest = msg_sect[++curr_sect].iov_len; - sect_crs = msg_sect[curr_sect].iov_base; - } - - if (sect_rest < fragm_rest) - sz = sect_rest; - else - sz = fragm_rest; - - if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) { - res = -EFAULT; -error: - kfree_skb_list(buf_chain); - return res; - } - sect_crs += sz; - sect_rest -= sz; - fragm_crs += sz; - fragm_rest -= sz; - rest -= sz; - - if (!fragm_rest && rest) { - - /* Initiate new fragment: */ - if (rest <= fragm_sz) { - fragm_sz = rest; - msg_set_type(&fragm_hdr, LAST_FRAGMENT); - } else { - msg_set_type(&fragm_hdr, FRAGMENT); - } - msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); - msg_set_fragm_no(&fragm_hdr, ++fragm_no); - prev = buf; - buf = tipc_buf_acquire(fragm_sz + INT_H_SIZE); - if (!buf) { - res = -ENOMEM; - goto error; - } - - buf->next = NULL; - prev->next = buf; - skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE); - fragm_crs = INT_H_SIZE; - fragm_rest = fragm_sz; - } - } while (rest > 0); - - /* - * Now we have a buffer chain. Select a link and check - * that packet size is still OK - */ - node = tipc_node_find(destaddr); - if (likely(node)) { - tipc_node_lock(node); - l_ptr = node->active_links[sender->ref & 1]; - if (!l_ptr) { - tipc_node_unlock(node); - goto reject; - } - if (l_ptr->max_pkt < max_pkt) { - sender->max_pkt = l_ptr->max_pkt; - tipc_node_unlock(node); - kfree_skb_list(buf_chain); - goto again; - } - } else { -reject: - kfree_skb_list(buf_chain); - tipc_port_iovec_reject(sender, hdr, msg_sect, len, - TIPC_ERR_NO_NODE); - return -ENETUNREACH; - } - - /* Append chain of fragments to send queue & send them */ - l_ptr->long_msg_seq_no++; - link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no); - l_ptr->stats.sent_fragments += fragm_no; - l_ptr->stats.sent_fragmented++; - tipc_link_push_queue(l_ptr); - tipc_node_unlock(node); - return dsz; -} - /* * tipc_link_push_packet: Push one unsent packet to the media */ diff --git a/net/tipc/port.c b/net/tipc/port.c index 8350ec932514..606ff1a78e2b 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -211,6 +211,7 @@ u32 tipc_port_init(struct tipc_port *p_ptr, } p_ptr->max_pkt = MAX_PKT_DEFAULT; + p_ptr->sent = 1; p_ptr->ref = ref; INIT_LIST_HEAD(&p_ptr->wait_list); INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list); @@ -279,92 +280,6 @@ static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr, return buf; } -int tipc_reject_msg(struct sk_buff *buf, u32 err) -{ - struct tipc_msg *msg = buf_msg(buf); - struct sk_buff *rbuf; - struct tipc_msg *rmsg; - int hdr_sz; - u32 imp; - u32 data_sz = msg_data_sz(msg); - u32 src_node; - u32 rmsg_sz; - - /* discard rejected message if it shouldn't be returned to sender */ - if (WARN(!msg_isdata(msg), - "attempt to reject message with user=%u", msg_user(msg))) { - dump_stack(); - goto exit; - } - if (msg_errcode(msg) || msg_dest_droppable(msg)) - goto exit; - - /* - * construct returned message by copying rejected message header and - * data (or subset), then updating header fields that need adjusting - */ - hdr_sz = msg_hdr_sz(msg); - rmsg_sz = hdr_sz + min_t(u32, data_sz, MAX_REJECT_SIZE); - - rbuf = tipc_buf_acquire(rmsg_sz); - if (rbuf == NULL) - goto exit; - - rmsg = buf_msg(rbuf); - skb_copy_to_linear_data(rbuf, msg, rmsg_sz); - - if (msg_connected(rmsg)) { - imp = msg_importance(rmsg); - if (imp < TIPC_CRITICAL_IMPORTANCE) - msg_set_importance(rmsg, ++imp); - } - msg_set_non_seq(rmsg, 0); - msg_set_size(rmsg, rmsg_sz); - msg_set_errcode(rmsg, err); - msg_set_prevnode(rmsg, tipc_own_addr); - msg_swap_words(rmsg, 4, 5); - if (!msg_short(rmsg)) - msg_swap_words(rmsg, 6, 7); - - /* send self-abort message when rejecting on a connected port */ - if (msg_connected(msg)) { - struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg)); - - if (p_ptr) { - struct sk_buff *abuf = NULL; - - if (p_ptr->connected) - abuf = port_build_self_abort_msg(p_ptr, err); - tipc_port_unlock(p_ptr); - tipc_net_route_msg(abuf); - } - } - - /* send returned message & dispose of rejected message */ - src_node = msg_prevnode(msg); - if (in_own_node(src_node)) - tipc_sk_rcv(rbuf); - else - tipc_link_xmit(rbuf, src_node, msg_link_selector(rmsg)); -exit: - kfree_skb(buf); - return data_sz; -} - -int tipc_port_iovec_reject(struct tipc_port *p_ptr, struct tipc_msg *hdr, - struct iovec const *msg_sect, unsigned int len, - int err) -{ - struct sk_buff *buf; - int res; - - res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf); - if (!buf) - return res; - - return tipc_reject_msg(buf, err); -} - static void port_timeout(unsigned long ref) { struct tipc_port *p_ptr = tipc_port_lock(ref); @@ -698,7 +613,7 @@ int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr, (net_ev_handler)port_handle_node_down); res = 0; exit: - p_ptr->max_pkt = tipc_link_get_max_pkt(peer->node, ref); + p_ptr->max_pkt = tipc_node_get_mtu(peer->node, ref); return res; } @@ -753,56 +668,3 @@ int tipc_port_shutdown(u32 ref) tipc_net_route_msg(buf); return tipc_port_disconnect(ref); } - -/* - * tipc_port_iovec_rcv: Concatenate and deliver sectioned - * message for this node. - */ -static int tipc_port_iovec_rcv(struct tipc_port *sender, - struct iovec const *msg_sect, - unsigned int len) -{ - struct sk_buff *buf; - int res; - - res = tipc_msg_build(&sender->phdr, msg_sect, len, MAX_MSG_SIZE, &buf); - if (likely(buf)) - tipc_sk_rcv(buf); - return res; -} - -/** - * tipc_send - send message sections on connection - */ -int tipc_send(struct tipc_port *p_ptr, - struct iovec const *msg_sect, - unsigned int len) -{ - u32 destnode; - int res; - - if (!p_ptr->connected) - return -EINVAL; - - p_ptr->congested = 1; - if (!tipc_port_congested(p_ptr)) { - destnode = tipc_port_peernode(p_ptr); - if (likely(!in_own_node(destnode))) - res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, - destnode); - else - res = tipc_port_iovec_rcv(p_ptr, msg_sect, len); - - if (likely(res != -ELINKCONG)) { - p_ptr->congested = 0; - if (res > 0) - p_ptr->sent++; - return res; - } - } - if (tipc_port_unreliable(p_ptr)) { - p_ptr->congested = 0; - return len; - } - return -ELINKCONG; -} diff --git a/net/tipc/port.h b/net/tipc/port.h index e566d55e2655..231d9488189c 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -104,8 +104,6 @@ struct tipc_port_list; u32 tipc_port_init(struct tipc_port *p_ptr, const unsigned int importance); -int tipc_reject_msg(struct sk_buff *buf, u32 err); - void tipc_acknowledge(u32 port_ref, u32 ack); void tipc_port_destroy(struct tipc_port *p_ptr); @@ -136,21 +134,11 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg); * TIPC messaging routines */ -int tipc_send(struct tipc_port *port, - struct iovec const *msg_sect, - unsigned int len); - int tipc_port_mcast_xmit(struct tipc_port *port, struct tipc_name_seq const *seq, struct iovec const *msg, unsigned int len); -int tipc_port_iovec_reject(struct tipc_port *p_ptr, - struct tipc_msg *hdr, - struct iovec const *msg_sect, - unsigned int len, - int err); - struct sk_buff *tipc_port_get_ports(void); void tipc_port_proto_rcv(struct sk_buff *buf); void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 5690751cbfa5..bfe79bbd83a1 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -206,6 +206,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock, sk->sk_data_ready = tipc_data_ready; sk->sk_write_space = tipc_write_space; tsk->conn_timeout = CONN_TIMEOUT_DEFAULT; + tsk->port.sent = 0; atomic_set(&tsk->dupl_rcvcnt, 0); tipc_port_unlock(port); @@ -784,30 +785,40 @@ static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) } /** - * tipc_send_packet - send a connection-oriented message - * @iocb: if NULL, indicates that socket lock is already held + * tipc_send_stream - send stream-oriented data + * @iocb: (unused) * @sock: socket structure - * @m: message to send - * @total_len: length of message + * @m: data to send + * @dsz: total length of data to be transmitted * - * Used for SOCK_SEQPACKET messages and SOCK_STREAM data. + * Used for SOCK_STREAM data. * - * Returns the number of bytes sent on success, or errno otherwise + * Returns the number of bytes sent on success (or partial success), + * or errno if no data sent */ -static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, - struct msghdr *m, size_t total_len) +static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, + struct msghdr *m, size_t dsz) { struct sock *sk = sock->sk; struct tipc_sock *tsk = tipc_sk(sk); + struct tipc_port *port = &tsk->port; + struct tipc_msg *mhdr = &port->phdr; + struct sk_buff *buf; DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); - int res = -EINVAL; + u32 ref = port->ref; + int rc = -EINVAL; long timeo; + u32 dnode; + uint mtu, send, sent = 0; /* Handle implied connection establishment */ - if (unlikely(dest)) - return tipc_sendmsg(iocb, sock, m, total_len); - - if (total_len > TIPC_MAX_USER_MSG_SIZE) + if (unlikely(dest)) { + rc = tipc_sendmsg(iocb, sock, m, dsz); + if (dsz && (dsz == rc)) + tsk->port.sent = 1; + return rc; + } + if (dsz > (uint)INT_MAX) return -EMSGSIZE; if (iocb) @@ -815,123 +826,68 @@ static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, if (unlikely(sock->state != SS_CONNECTED)) { if (sock->state == SS_DISCONNECTING) - res = -EPIPE; + rc = -EPIPE; else - res = -ENOTCONN; + rc = -ENOTCONN; goto exit; } timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); + dnode = tipc_port_peernode(port); + port->congested = 1; + +next: + mtu = port->max_pkt; + send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE); + rc = tipc_msg_build2(mhdr, m->msg_iov, sent, send, mtu, &buf); + if (unlikely(rc < 0)) + goto exit; do { - res = tipc_send(&tsk->port, m->msg_iov, total_len); - if (likely(res != -ELINKCONG)) - break; - res = tipc_wait_for_sndpkt(sock, &timeo); - if (res) - break; - } while (1); + port->congested = 1; + if (likely(!tipc_port_congested(port))) { + rc = tipc_link_xmit2(buf, dnode, ref); + if (likely(!rc)) { + port->sent++; + sent += send; + if (sent == dsz) + break; + goto next; + } + if (rc == -EMSGSIZE) { + port->max_pkt = tipc_node_get_mtu(dnode, ref); + goto next; + } + if (rc != -ELINKCONG) + break; + } + rc = tipc_wait_for_sndpkt(sock, &timeo); + } while (!rc); + + port->congested = 0; exit: if (iocb) release_sock(sk); - return res; + return sent ? sent : rc; } /** - * tipc_send_stream - send stream-oriented data - * @iocb: (unused) + * tipc_send_packet - send a connection-oriented message + * @iocb: if NULL, indicates that socket lock is already held * @sock: socket structure - * @m: data to send - * @total_len: total length of data to be sent + * @m: message to send + * @dsz: length of data to be transmitted * - * Used for SOCK_STREAM data. + * Used for SOCK_SEQPACKET messages. * - * Returns the number of bytes sent on success (or partial success), - * or errno if no data sent + * Returns the number of bytes sent on success, or errno otherwise */ -static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, - struct msghdr *m, size_t total_len) +static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, + struct msghdr *m, size_t dsz) { - struct sock *sk = sock->sk; - struct tipc_sock *tsk = tipc_sk(sk); - struct msghdr my_msg; - struct iovec my_iov; - struct iovec *curr_iov; - int curr_iovlen; - char __user *curr_start; - u32 hdr_size; - int curr_left; - int bytes_to_send; - int bytes_sent; - int res; - - lock_sock(sk); - - /* Handle special cases where there is no connection */ - if (unlikely(sock->state != SS_CONNECTED)) { - if (sock->state == SS_UNCONNECTED) - res = tipc_send_packet(NULL, sock, m, total_len); - else - res = sock->state == SS_DISCONNECTING ? -EPIPE : -ENOTCONN; - goto exit; - } - - if (unlikely(m->msg_name)) { - res = -EISCONN; - goto exit; - } - - if (total_len > (unsigned int)INT_MAX) { - res = -EMSGSIZE; - goto exit; - } - - /* - * Send each iovec entry using one or more messages - * - * Note: This algorithm is good for the most likely case - * (i.e. one large iovec entry), but could be improved to pass sets - * of small iovec entries into send_packet(). - */ - curr_iov = m->msg_iov; - curr_iovlen = m->msg_iovlen; - my_msg.msg_iov = &my_iov; - my_msg.msg_iovlen = 1; - my_msg.msg_flags = m->msg_flags; - my_msg.msg_name = NULL; - bytes_sent = 0; - - hdr_size = msg_hdr_sz(&tsk->port.phdr); - - while (curr_iovlen--) { - curr_start = curr_iov->iov_base; - curr_left = curr_iov->iov_len; - - while (curr_left) { - bytes_to_send = tsk->port.max_pkt - hdr_size; - if (bytes_to_send > TIPC_MAX_USER_MSG_SIZE) - bytes_to_send = TIPC_MAX_USER_MSG_SIZE; - if (curr_left < bytes_to_send) - bytes_to_send = curr_left; - my_iov.iov_base = curr_start; - my_iov.iov_len = bytes_to_send; - res = tipc_send_packet(NULL, sock, &my_msg, - bytes_to_send); - if (res < 0) { - if (bytes_sent) - res = bytes_sent; - goto exit; - } - curr_left -= bytes_to_send; - curr_start += bytes_to_send; - bytes_sent += bytes_to_send; - } + if (dsz > TIPC_MAX_USER_MSG_SIZE) + return -EMSGSIZE; - curr_iov++; - } - res = bytes_sent; -exit: - release_sock(sk); - return res; + return tipc_send_stream(iocb, sock, m, dsz); } /** -- cgit v1.2.3 From b786e2b0faea1265d72533d59ec4482f764ad60f Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:39 -0500 Subject: tipc: let port protocol senders use new link send function Several functions in port.c, related to the port protocol and connection shutdown, need to send messages. We now convert them to use the new link send function. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/port.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/net/tipc/port.c b/net/tipc/port.c index 606ff1a78e2b..60aede075b52 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -236,6 +236,8 @@ u32 tipc_port_init(struct tipc_port *p_ptr, void tipc_port_destroy(struct tipc_port *p_ptr) { struct sk_buff *buf = NULL; + struct tipc_msg *msg = NULL; + u32 peer; tipc_withdraw(p_ptr, 0, NULL); @@ -247,14 +249,15 @@ void tipc_port_destroy(struct tipc_port *p_ptr) if (p_ptr->connected) { buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT); tipc_nodesub_unsubscribe(&p_ptr->subscription); + msg = buf_msg(buf); + peer = msg_destnode(msg); + tipc_link_xmit2(buf, peer, msg_link_selector(msg)); } - spin_lock_bh(&tipc_port_list_lock); list_del(&p_ptr->port_list); list_del(&p_ptr->wait_list); spin_unlock_bh(&tipc_port_list_lock); k_term_timer(&p_ptr->timer); - tipc_net_route_msg(buf); } /* @@ -276,6 +279,7 @@ static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr, msg_set_destport(msg, tipc_port_peerport(p_ptr)); msg_set_origport(msg, p_ptr->ref); msg_set_msgcnt(msg, ack); + buf->next = NULL; } return buf; } @@ -284,6 +288,7 @@ static void port_timeout(unsigned long ref) { struct tipc_port *p_ptr = tipc_port_lock(ref); struct sk_buff *buf = NULL; + struct tipc_msg *msg = NULL; if (!p_ptr) return; @@ -302,7 +307,8 @@ static void port_timeout(unsigned long ref) k_start_timer(&p_ptr->timer, p_ptr->probing_interval); } tipc_port_unlock(p_ptr); - tipc_net_route_msg(buf); + msg = buf_msg(buf); + tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg)); } @@ -310,12 +316,14 @@ static void port_handle_node_down(unsigned long ref) { struct tipc_port *p_ptr = tipc_port_lock(ref); struct sk_buff *buf = NULL; + struct tipc_msg *msg = NULL; if (!p_ptr) return; buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE); tipc_port_unlock(p_ptr); - tipc_net_route_msg(buf); + msg = buf_msg(buf); + tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg)); } @@ -327,6 +335,7 @@ static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 er struct tipc_msg *msg = buf_msg(buf); msg_swap_words(msg, 4, 5); msg_swap_words(msg, 6, 7); + buf->next = NULL; } return buf; } @@ -351,6 +360,7 @@ static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 er if (imp < TIPC_CRITICAL_IMPORTANCE) msg_set_importance(msg, ++imp); msg_set_errcode(msg, err); + buf->next = NULL; } return buf; } @@ -401,7 +411,7 @@ void tipc_port_proto_rcv(struct sk_buff *buf) p_ptr->probing_state = CONFIRMED; tipc_port_unlock(p_ptr); exit: - tipc_net_route_msg(r_buf); + tipc_link_xmit2(r_buf, msg_destnode(msg), msg_link_selector(msg)); kfree_skb(buf); } @@ -496,6 +506,7 @@ void tipc_acknowledge(u32 ref, u32 ack) { struct tipc_port *p_ptr; struct sk_buff *buf = NULL; + struct tipc_msg *msg; p_ptr = tipc_port_lock(ref); if (!p_ptr) @@ -505,7 +516,10 @@ void tipc_acknowledge(u32 ref, u32 ack) buf = port_build_proto_msg(p_ptr, CONN_ACK, ack); } tipc_port_unlock(p_ptr); - tipc_net_route_msg(buf); + if (!buf) + return; + msg = buf_msg(buf); + tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg)); } int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, @@ -656,6 +670,7 @@ int tipc_port_disconnect(u32 ref) */ int tipc_port_shutdown(u32 ref) { + struct tipc_msg *msg; struct tipc_port *p_ptr; struct sk_buff *buf = NULL; @@ -665,6 +680,7 @@ int tipc_port_shutdown(u32 ref) buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN); tipc_port_unlock(p_ptr); - tipc_net_route_msg(buf); + msg = buf_msg(buf); + tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg)); return tipc_port_disconnect(ref); } -- cgit v1.2.3 From ec8a2e5621db2da24badb3969eda7fd359e1869f Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:40 -0500 Subject: tipc: same receive code path for connection protocol and data messages As a preparation to eliminate port_lock we need to bring reception of connection protocol messages under proper protection of bh_lock_sock or socket owner. We fix this by letting those messages follow the same code path as incoming data messages. As a side effect of this change, the last reference to the function net_route_msg() disappears, and we can eliminate that function. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/link.c | 18 ++++++++++++------ net/tipc/net.c | 40 ---------------------------------------- net/tipc/net.h | 2 -- net/tipc/port.c | 7 +------ net/tipc/port.h | 2 +- net/tipc/socket.c | 5 +++++ 6 files changed, 19 insertions(+), 55 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 93a8033263c0..96a8072f73cc 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1479,6 +1479,7 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) case TIPC_MEDIUM_IMPORTANCE: case TIPC_HIGH_IMPORTANCE: case TIPC_CRITICAL_IMPORTANCE: + case CONN_MANAGER: tipc_node_unlock(n_ptr); tipc_sk_rcv(buf); continue; @@ -1493,10 +1494,6 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) tipc_node_unlock(n_ptr); tipc_named_rcv(buf); continue; - case CONN_MANAGER: - tipc_node_unlock(n_ptr); - tipc_port_proto_rcv(buf); - continue; case BCAST_PROTOCOL: tipc_link_sync_rcv(n_ptr, buf); break; @@ -2106,6 +2103,7 @@ void tipc_link_bundle_rcv(struct sk_buff *buf) u32 msgcount = msg_msgcnt(buf_msg(buf)); u32 pos = INT_H_SIZE; struct sk_buff *obuf; + struct tipc_msg *omsg; while (msgcount--) { obuf = buf_extract(buf, pos); @@ -2113,8 +2111,16 @@ void tipc_link_bundle_rcv(struct sk_buff *buf) pr_warn("Link unable to unbundle message(s)\n"); break; } - pos += align(msg_size(buf_msg(obuf))); - tipc_net_route_msg(obuf); + omsg = buf_msg(obuf); + pos += align(msg_size(omsg)); + if (msg_isdata(omsg) || (msg_user(omsg) == CONN_MANAGER)) { + tipc_sk_rcv(obuf); + } else if (msg_user(omsg) == NAME_DISTRIBUTOR) { + tipc_named_rcv(obuf); + } else { + pr_warn("Illegal bundled msg: %u\n", msg_user(omsg)); + kfree_skb(obuf); + } } kfree_skb(buf); } diff --git a/net/tipc/net.c b/net/tipc/net.c index 5f7d6ffb5465..7fcc94998fea 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c @@ -103,46 +103,6 @@ * This is always used within the scope of a tipc_nametbl_lock(read). * - A local spin_lock protecting the queue of subscriber events. */ -void tipc_net_route_msg(struct sk_buff *buf) -{ - struct tipc_msg *msg; - u32 dnode; - - if (!buf) - return; - msg = buf_msg(buf); - - /* Handle message for this node */ - dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg); - if (tipc_in_scope(dnode, tipc_own_addr)) { - if (msg_isdata(msg)) { - if (msg_mcast(msg)) - tipc_port_mcast_rcv(buf, NULL); - else if (msg_destport(msg)) { - tipc_sk_rcv(buf); - } else { - pr_warn("Cannot route msg; no destination\n"); - kfree_skb(buf); - } - return; - } - switch (msg_user(msg)) { - case NAME_DISTRIBUTOR: - tipc_named_rcv(buf); - break; - case CONN_MANAGER: - tipc_port_proto_rcv(buf); - break; - default: - kfree_skb(buf); - } - return; - } - - /* Handle message for another node */ - skb_trim(buf, msg_size(msg)); - tipc_link_xmit(buf, dnode, msg_link_selector(msg)); -} int tipc_net_start(u32 addr) { diff --git a/net/tipc/net.h b/net/tipc/net.h index c6c2b46f7c28..59ef3388be2c 100644 --- a/net/tipc/net.h +++ b/net/tipc/net.h @@ -37,8 +37,6 @@ #ifndef _TIPC_NET_H #define _TIPC_NET_H -void tipc_net_route_msg(struct sk_buff *buf); - int tipc_net_start(u32 addr); void tipc_net_stop(void); diff --git a/net/tipc/port.c b/net/tipc/port.c index 60aede075b52..dcc630948e04 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -365,16 +365,14 @@ static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 er return buf; } -void tipc_port_proto_rcv(struct sk_buff *buf) +void tipc_port_proto_rcv(struct tipc_port *p_ptr, struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); - struct tipc_port *p_ptr; struct sk_buff *r_buf = NULL; u32 destport = msg_destport(msg); int wakeable; /* Validate connection */ - p_ptr = tipc_port_lock(destport); if (!p_ptr || !p_ptr->connected || !tipc_port_peer_msg(p_ptr, msg)) { r_buf = tipc_buf_acquire(BASIC_H_SIZE); if (r_buf) { @@ -385,8 +383,6 @@ void tipc_port_proto_rcv(struct sk_buff *buf) msg_set_origport(msg, destport); msg_set_destport(msg, msg_origport(msg)); } - if (p_ptr) - tipc_port_unlock(p_ptr); goto exit; } @@ -409,7 +405,6 @@ void tipc_port_proto_rcv(struct sk_buff *buf) break; } p_ptr->probing_state = CONFIRMED; - tipc_port_unlock(p_ptr); exit: tipc_link_xmit2(r_buf, msg_destnode(msg), msg_link_selector(msg)); kfree_skb(buf); diff --git a/net/tipc/port.h b/net/tipc/port.h index 231d9488189c..3f28fd420ff9 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -140,7 +140,7 @@ int tipc_port_mcast_xmit(struct tipc_port *port, unsigned int len); struct sk_buff *tipc_port_get_ports(void); -void tipc_port_proto_rcv(struct sk_buff *buf); +void tipc_port_proto_rcv(struct tipc_port *port, struct sk_buff *buf); void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp); void tipc_port_reinit(void); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index bfe79bbd83a1..d838a4b66d3a 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1416,6 +1416,11 @@ static int filter_rcv(struct sock *sk, struct sk_buff *buf) unsigned int limit = rcvbuf_limit(sk, buf); int rc = TIPC_OK; + if (unlikely(msg_user(msg) == CONN_MANAGER)) { + tipc_port_proto_rcv(&tsk->port, buf); + return TIPC_OK; + } + /* Reject message if it is wrong sort of message for socket */ if (msg_type(msg) > TIPC_DIRECT_MSG) return -TIPC_ERR_NO_PORT; -- cgit v1.2.3 From ac0074ee70ddb32f62d918b31cb20e3c947c75a1 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:41 -0500 Subject: tipc: clean up connection protocol reception function We simplify the code for receiving connection probes, leveraging the recently introduced tipc_msg_reverse() function. We also stick to the principle of sending a possible response message directly from the calling (tipc_sk_rcv or backlog_rcv) functions, hence making the call chain shallower and easier to follow. We make one small protocol change here, allowed according to the spec. If a protocol message arrives from a remote socket that is not the one we are connected to, we are currently generating a connection abort message and send it to the source. This behavior is unnecessary, and might even be a security risk, so instead we now choose to only ignore the message. The consequnce for the sender is that he will need longer time to discover his mistake (until the next timeout), but this is an extreme corner case, and may happen anyway under other circumstances, so we deem this change acceptable. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/msg.c | 10 ++++++--- net/tipc/port.c | 53 +++------------------------------------------ net/tipc/port.h | 1 - net/tipc/socket.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++-------- net/tipc/socket.h | 3 +++ 5 files changed, 68 insertions(+), 63 deletions(-) diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 7bfc4422bf2c..6ec958401f78 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -348,13 +348,17 @@ bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err) struct tipc_msg ohdr; uint rdsz = min_t(uint, msg_data_sz(msg), MAX_FORWARD_SIZE); - if (skb_linearize(buf) || !msg_isdata(msg)) + if (skb_linearize(buf)) + goto exit; + if (msg_dest_droppable(msg)) goto exit; - if (msg_dest_droppable(msg) || msg_errcode(msg)) + if (msg_errcode(msg)) goto exit; memcpy(&ohdr, msg, msg_hdr_sz(msg)); - msg_set_importance(msg, min_t(uint, ++imp, TIPC_CRITICAL_IMPORTANCE)); + imp = min_t(uint, imp + 1, TIPC_CRITICAL_IMPORTANCE); + if (msg_isdata(msg)) + msg_set_importance(msg, imp); msg_set_errcode(msg, err); msg_set_origport(msg, msg_destport(&ohdr)); msg_set_destport(msg, msg_origport(&ohdr)); diff --git a/net/tipc/port.c b/net/tipc/port.c index dcc630948e04..9f53d5ac35e1 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -42,8 +42,6 @@ /* Connection management: */ #define PROBING_INTERVAL 3600000 /* [ms] => 1 h */ -#define CONFIRMED 0 -#define PROBING 1 #define MAX_REJECT_SIZE 1024 @@ -299,11 +297,11 @@ static void port_timeout(unsigned long ref) } /* Last probe answered ? */ - if (p_ptr->probing_state == PROBING) { + if (p_ptr->probing_state == TIPC_CONN_PROBING) { buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT); } else { buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0); - p_ptr->probing_state = PROBING; + p_ptr->probing_state = TIPC_CONN_PROBING; k_start_timer(&p_ptr->timer, p_ptr->probing_interval); } tipc_port_unlock(p_ptr); @@ -365,51 +363,6 @@ static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 er return buf; } -void tipc_port_proto_rcv(struct tipc_port *p_ptr, struct sk_buff *buf) -{ - struct tipc_msg *msg = buf_msg(buf); - struct sk_buff *r_buf = NULL; - u32 destport = msg_destport(msg); - int wakeable; - - /* Validate connection */ - if (!p_ptr || !p_ptr->connected || !tipc_port_peer_msg(p_ptr, msg)) { - r_buf = tipc_buf_acquire(BASIC_H_SIZE); - if (r_buf) { - msg = buf_msg(r_buf); - tipc_msg_init(msg, TIPC_HIGH_IMPORTANCE, TIPC_CONN_MSG, - BASIC_H_SIZE, msg_orignode(msg)); - msg_set_errcode(msg, TIPC_ERR_NO_PORT); - msg_set_origport(msg, destport); - msg_set_destport(msg, msg_origport(msg)); - } - goto exit; - } - - /* Process protocol message sent by peer */ - switch (msg_type(msg)) { - case CONN_ACK: - wakeable = tipc_port_congested(p_ptr) && p_ptr->congested; - p_ptr->acked += msg_msgcnt(msg); - if (!tipc_port_congested(p_ptr)) { - p_ptr->congested = 0; - if (wakeable) - tipc_port_wakeup(p_ptr); - } - break; - case CONN_PROBE: - r_buf = port_build_proto_msg(p_ptr, CONN_PROBE_REPLY, 0); - break; - default: - /* CONN_PROBE_REPLY or unrecognized - no action required */ - break; - } - p_ptr->probing_state = CONFIRMED; -exit: - tipc_link_xmit2(r_buf, msg_destnode(msg), msg_link_selector(msg)); - kfree_skb(buf); -} - static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id) { struct publication *publ; @@ -613,7 +566,7 @@ int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr, msg_set_hdr_sz(msg, SHORT_H_SIZE); p_ptr->probing_interval = PROBING_INTERVAL; - p_ptr->probing_state = CONFIRMED; + p_ptr->probing_state = TIPC_CONN_OK; p_ptr->connected = 1; k_start_timer(&p_ptr->timer, p_ptr->probing_interval); diff --git a/net/tipc/port.h b/net/tipc/port.h index 3f28fd420ff9..3a4f808135c3 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -140,7 +140,6 @@ int tipc_port_mcast_xmit(struct tipc_port *port, unsigned int len); struct sk_buff *tipc_port_get_ports(void); -void tipc_port_proto_rcv(struct tipc_port *port, struct sk_buff *buf); void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp); void tipc_port_reinit(void); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index d838a4b66d3a..1762323156af 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -46,6 +46,7 @@ #define SS_READY -2 /* socket is connectionless */ #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ +#define TIPC_FWD_MSG 1 static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb); static void tipc_data_ready(struct sock *sk); @@ -533,6 +534,46 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, return mask; } +/** + * tipc_sk_proto_rcv - receive a connection mng protocol message + * @tsk: receiving socket + * @dnode: node to send response message to, if any + * @buf: buffer containing protocol message + * Returns 0 (TIPC_OK) if message was consumed, 1 (TIPC_FWD_MSG) if + * (CONN_PROBE_REPLY) message should be forwarded. + */ +int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode, struct sk_buff *buf) +{ + struct tipc_msg *msg = buf_msg(buf); + struct tipc_port *port = &tsk->port; + int wakeable; + + /* Ignore if connection cannot be validated: */ + if (!port->connected || !tipc_port_peer_msg(port, msg)) + goto exit; + + port->probing_state = TIPC_CONN_OK; + + if (msg_type(msg) == CONN_ACK) { + wakeable = tipc_port_congested(port) && port->congested; + port->acked += msg_msgcnt(msg); + if (!tipc_port_congested(port)) { + port->congested = 0; + if (wakeable) + tipc_port_wakeup(port); + } + } else if (msg_type(msg) == CONN_PROBE) { + if (!tipc_msg_reverse(buf, dnode, TIPC_OK)) + return TIPC_OK; + msg_set_type(msg, CONN_PROBE_REPLY); + return TIPC_FWD_MSG; + } + /* Do nothing if msg_type() == CONN_PROBE_REPLY */ +exit: + kfree_skb(buf); + return TIPC_OK; +} + /** * dest_name_check - verify user is permitted to send to specified port name * @dest: destination address @@ -1406,7 +1447,7 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) * Called with socket lock already taken; port lock may also be taken. * * Returns 0 (TIPC_OK) if message was consumed, -TIPC error code if message - * to be rejected. + * to be rejected, 1 (TIPC_FWD_MSG) if (CONN_MANAGER) message to be forwarded */ static int filter_rcv(struct sock *sk, struct sk_buff *buf) { @@ -1414,12 +1455,11 @@ static int filter_rcv(struct sock *sk, struct sk_buff *buf) struct tipc_sock *tsk = tipc_sk(sk); struct tipc_msg *msg = buf_msg(buf); unsigned int limit = rcvbuf_limit(sk, buf); + u32 onode; int rc = TIPC_OK; - if (unlikely(msg_user(msg) == CONN_MANAGER)) { - tipc_port_proto_rcv(&tsk->port, buf); - return TIPC_OK; - } + if (unlikely(msg_user(msg) == CONN_MANAGER)) + return tipc_sk_proto_rcv(tsk, &onode, buf); /* Reject message if it is wrong sort of message for socket */ if (msg_type(msg) > TIPC_DIRECT_MSG) @@ -1465,10 +1505,16 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf) rc = filter_rcv(sk, buf); - if (unlikely(rc && tipc_msg_reverse(buf, &onode, -rc))) - tipc_link_xmit2(buf, onode, 0); - else if (atomic_read(&tsk->dupl_rcvcnt) < TIPC_CONN_OVERLOAD_LIMIT) - atomic_add(truesize, &tsk->dupl_rcvcnt); + if (likely(!rc)) { + if (atomic_read(&tsk->dupl_rcvcnt) < TIPC_CONN_OVERLOAD_LIMIT) + atomic_add(truesize, &tsk->dupl_rcvcnt); + return 0; + } + + if ((rc < 0) && !tipc_msg_reverse(buf, &onode, -rc)) + return 0; + + tipc_link_xmit2(buf, onode, 0); return 0; } diff --git a/net/tipc/socket.h b/net/tipc/socket.h index 3afcd2a70b31..69fd06bce68a 100644 --- a/net/tipc/socket.h +++ b/net/tipc/socket.h @@ -38,6 +38,9 @@ #include "port.h" #include +#define TIPC_CONN_OK 0 +#define TIPC_CONN_PROBING 1 + /** * struct tipc_sock - TIPC socket structure * @sk: socket - interacts with 'port' and with user via the socket API -- cgit v1.2.3 From 60120526c26f42fd658e32bf4a6d548483d09da8 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 25 Jun 2014 20:41:42 -0500 Subject: tipc: simplify connection congestion handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a consequence of the recently introduced serialized access to the socket in commit 8d94168a761819d10252bab1f8de6d7b202c3baa ("tipc: same receive code path for connection protocol and data messages") we can make a number of simplifications in the detection and handling of connection congestion situations. - We don't need to keep two counters, one for sent messages and one for acked messages. There is no longer any risk for races between acknowledge messages arriving in BH and data message sending running in user context. So we merge this into one counter, 'sent_unacked', which is incremented at sending and subtracted from at acknowledge reception. - We don't need to set the 'congested' field in tipc_port to true before we sent the message, and clear it when sending is successful. (As a matter of fact, it was never necessary; the field was set in link_schedule_port() before any wakeup could arrive anyway.) - We keep the conditions for link congestion and connection connection congestion separated. There would otherwise be a risk that an arriving acknowledge message may wake up a user sleeping because of link congestion. - We can simplify reception of acknowledge messages. We also make some cosmetic/structural changes: - We rename the 'congested' field to the more correct 'link_cong´. - We rename 'conn_unacked' to 'rcv_unacked' - We move the above mentioned fields from struct tipc_port to struct tipc_sock. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/link.c | 10 +++++++--- net/tipc/port.c | 12 ++---------- net/tipc/port.h | 16 ---------------- net/tipc/socket.c | 48 +++++++++++++++++++++++------------------------- net/tipc/socket.h | 11 +++++++++++ 5 files changed, 43 insertions(+), 54 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 96a8072f73cc..a081e7d08d22 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -332,13 +332,15 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down) static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz) { struct tipc_port *p_ptr; + struct tipc_sock *tsk; spin_lock_bh(&tipc_port_list_lock); p_ptr = tipc_port_lock(origport); if (p_ptr) { if (!list_empty(&p_ptr->wait_list)) goto exit; - p_ptr->congested = 1; + tsk = tipc_port_to_sock(p_ptr); + tsk->link_cong = 1; p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt); list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports); l_ptr->stats.link_congs++; @@ -352,6 +354,7 @@ exit: void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all) { struct tipc_port *p_ptr; + struct tipc_sock *tsk; struct tipc_port *temp_p_ptr; int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size; @@ -367,10 +370,11 @@ void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all) wait_list) { if (win <= 0) break; + tsk = tipc_port_to_sock(p_ptr); list_del_init(&p_ptr->wait_list); spin_lock_bh(p_ptr->lock); - p_ptr->congested = 0; - tipc_port_wakeup(p_ptr); + tsk->link_cong = 0; + tipc_sock_wakeup(tsk); win -= p_ptr->waiting_pkts; spin_unlock_bh(p_ptr->lock); } diff --git a/net/tipc/port.c b/net/tipc/port.c index 9f53d5ac35e1..0d09dcb6da18 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -186,12 +186,6 @@ exit: tipc_port_list_free(dp); } - -void tipc_port_wakeup(struct tipc_port *port) -{ - tipc_sock_wakeup(tipc_port_to_sock(port)); -} - /* tipc_port_init - intiate TIPC port and lock it * * Returns obtained reference if initialization is successful, zero otherwise @@ -209,7 +203,6 @@ u32 tipc_port_init(struct tipc_port *p_ptr, } p_ptr->max_pkt = MAX_PKT_DEFAULT; - p_ptr->sent = 1; p_ptr->ref = ref; INIT_LIST_HEAD(&p_ptr->wait_list); INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list); @@ -459,10 +452,9 @@ void tipc_acknowledge(u32 ref, u32 ack) p_ptr = tipc_port_lock(ref); if (!p_ptr) return; - if (p_ptr->connected) { - p_ptr->conn_unacked -= ack; + if (p_ptr->connected) buf = port_build_proto_msg(p_ptr, CONN_ACK, ack); - } + tipc_port_unlock(p_ptr); if (!buf) return; diff --git a/net/tipc/port.h b/net/tipc/port.h index 3a4f808135c3..0e47052daa29 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -53,17 +53,13 @@ * @connected: non-zero if port is currently connected to a peer port * @conn_type: TIPC type used when connection was established * @conn_instance: TIPC instance used when connection was established - * @conn_unacked: number of unacknowledged messages received from peer port * @published: non-zero if port has one or more associated names - * @congested: non-zero if cannot send because of link or port congestion * @max_pkt: maximum packet size "hint" used when building messages sent by port * @ref: unique reference to port in TIPC object registry * @phdr: preformatted message header used when sending messages * @port_list: adjacent ports in TIPC's global list of ports * @wait_list: adjacent ports in list of ports waiting on link congestion * @waiting_pkts: - * @sent: # of non-empty messages sent by port - * @acked: # of non-empty message acknowledgements from connected port's peer * @publications: list of publications for port * @pub_count: total # of publications port has made during its lifetime * @probing_state: @@ -76,17 +72,13 @@ struct tipc_port { int connected; u32 conn_type; u32 conn_instance; - u32 conn_unacked; int published; - u32 congested; u32 max_pkt; u32 ref; struct tipc_msg phdr; struct list_head port_list; struct list_head wait_list; u32 waiting_pkts; - u32 sent; - u32 acked; struct list_head publications; u32 pub_count; u32 probing_state; @@ -120,8 +112,6 @@ int tipc_port_disconnect(u32 portref); int tipc_port_shutdown(u32 ref); -void tipc_port_wakeup(struct tipc_port *port); - /* * The following routines require that the port be locked on entry */ @@ -161,12 +151,6 @@ static inline void tipc_port_unlock(struct tipc_port *p_ptr) spin_unlock_bh(p_ptr->lock); } -static inline int tipc_port_congested(struct tipc_port *p_ptr) -{ - return ((p_ptr->sent - p_ptr->acked) >= TIPC_FLOWCTRL_WIN); -} - - static inline u32 tipc_port_peernode(struct tipc_port *p_ptr) { return msg_destnode(&p_ptr->phdr); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 1762323156af..ede78b144dcf 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -207,7 +207,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock, sk->sk_data_ready = tipc_data_ready; sk->sk_write_space = tipc_write_space; tsk->conn_timeout = CONN_TIMEOUT_DEFAULT; - tsk->port.sent = 0; + tsk->sent_unacked = 0; atomic_set(&tsk->dupl_rcvcnt, 0); tipc_port_unlock(port); @@ -513,12 +513,12 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, switch ((int)sock->state) { case SS_UNCONNECTED: - if (!tsk->port.congested) + if (!tsk->link_cong) mask |= POLLOUT; break; case SS_READY: case SS_CONNECTED: - if (!tsk->port.congested) + if (!tsk->link_cong && !tipc_sk_conn_cong(tsk)) mask |= POLLOUT; /* fall thru' */ case SS_CONNECTING: @@ -546,7 +546,7 @@ int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode, struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); struct tipc_port *port = &tsk->port; - int wakeable; + int conn_cong; /* Ignore if connection cannot be validated: */ if (!port->connected || !tipc_port_peer_msg(port, msg)) @@ -555,13 +555,10 @@ int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode, struct sk_buff *buf) port->probing_state = TIPC_CONN_OK; if (msg_type(msg) == CONN_ACK) { - wakeable = tipc_port_congested(port) && port->congested; - port->acked += msg_msgcnt(msg); - if (!tipc_port_congested(port)) { - port->congested = 0; - if (wakeable) - tipc_port_wakeup(port); - } + conn_cong = tipc_sk_conn_cong(tsk); + tsk->sent_unacked -= msg_msgcnt(msg); + if (conn_cong) + tipc_sock_wakeup(tsk); } else if (msg_type(msg) == CONN_PROBE) { if (!tipc_msg_reverse(buf, dnode, TIPC_OK)) return TIPC_OK; @@ -626,7 +623,7 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) return sock_intr_errno(*timeo_p); prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - done = sk_wait_event(sk, timeo_p, !tsk->port.congested); + done = sk_wait_event(sk, timeo_p, !tsk->link_cong); finish_wait(sk_sleep(sk), &wait); } while (!done); return 0; @@ -800,7 +797,6 @@ static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) { struct sock *sk = sock->sk; struct tipc_sock *tsk = tipc_sk(sk); - struct tipc_port *port = &tsk->port; DEFINE_WAIT(wait); int done; @@ -819,7 +815,9 @@ static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); done = sk_wait_event(sk, timeo_p, - (!port->congested || !port->connected)); + (!tsk->link_cong && + !tipc_sk_conn_cong(tsk)) || + !tsk->port.connected); finish_wait(sk_sleep(sk), &wait); } while (!done); return 0; @@ -856,7 +854,7 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, if (unlikely(dest)) { rc = tipc_sendmsg(iocb, sock, m, dsz); if (dsz && (dsz == rc)) - tsk->port.sent = 1; + tsk->sent_unacked = 1; return rc; } if (dsz > (uint)INT_MAX) @@ -875,7 +873,6 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); dnode = tipc_port_peernode(port); - port->congested = 1; next: mtu = port->max_pkt; @@ -884,11 +881,10 @@ next: if (unlikely(rc < 0)) goto exit; do { - port->congested = 1; - if (likely(!tipc_port_congested(port))) { + if (likely(!tipc_sk_conn_cong(tsk))) { rc = tipc_link_xmit2(buf, dnode, ref); if (likely(!rc)) { - port->sent++; + tsk->sent_unacked++; sent += send; if (sent == dsz) break; @@ -903,8 +899,6 @@ next: } rc = tipc_wait_for_sndpkt(sock, &timeo); } while (!rc); - - port->congested = 0; exit: if (iocb) release_sock(sk); @@ -1169,8 +1163,10 @@ restart: /* Consume received message (optional) */ if (likely(!(flags & MSG_PEEK))) { if ((sock->state != SS_READY) && - (++port->conn_unacked >= TIPC_CONNACK_INTV)) - tipc_acknowledge(port->ref, port->conn_unacked); + (++tsk->rcv_unacked >= TIPC_CONNACK_INTV)) { + tipc_acknowledge(port->ref, tsk->rcv_unacked); + tsk->rcv_unacked = 0; + } advance_rx_queue(sk); } exit: @@ -1278,8 +1274,10 @@ restart: /* Consume received message (optional) */ if (likely(!(flags & MSG_PEEK))) { - if (unlikely(++port->conn_unacked >= TIPC_CONNACK_INTV)) - tipc_acknowledge(port->ref, port->conn_unacked); + if (unlikely(++tsk->rcv_unacked >= TIPC_CONNACK_INTV)) { + tipc_acknowledge(port->ref, tsk->rcv_unacked); + tsk->rcv_unacked = 0; + } advance_rx_queue(sk); } diff --git a/net/tipc/socket.h b/net/tipc/socket.h index 69fd06bce68a..2cdede9eda1b 100644 --- a/net/tipc/socket.h +++ b/net/tipc/socket.h @@ -48,6 +48,9 @@ * @peer_name: the peer of the connection, if any * @conn_timeout: the time we can wait for an unresponded setup request * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue + * @link_cong: non-zero if owner must sleep because of link congestion + * @sent_unacked: # messages sent by socket, and not yet acked by peer + * @rcv_unacked: # messages read by user, but not yet acked back to peer */ struct tipc_sock { @@ -55,6 +58,9 @@ struct tipc_sock { struct tipc_port port; unsigned int conn_timeout; atomic_t dupl_rcvcnt; + int link_cong; + uint sent_unacked; + uint rcv_unacked; }; static inline struct tipc_sock *tipc_sk(const struct sock *sk) @@ -72,6 +78,11 @@ static inline void tipc_sock_wakeup(struct tipc_sock *tsk) tsk->sk.sk_write_space(&tsk->sk); } +static inline int tipc_sk_conn_cong(struct tipc_sock *tsk) +{ + return tsk->sent_unacked >= TIPC_FLOWCTRL_WIN; +} + int tipc_sk_rcv(struct sk_buff *buf); #endif -- cgit v1.2.3 From 57b47553f65e12e2e4f1608168374b0e651de843 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:09:50 +0300 Subject: tcp: cookie_v4_init_sequence: skb should be const Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/tcp.h | 5 +++-- net/ipv4/syncookies.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 06a3023080c0..39e47c4e4f19 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -493,10 +493,11 @@ static inline u32 tcp_cookie_time(void) u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th, u16 *mssp); -__u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mss); +__u32 cookie_v4_init_sequence(struct sock *sk, const struct sk_buff *skb, + __u16 *mss); #else static inline __u32 cookie_v4_init_sequence(struct sock *sk, - struct sk_buff *skb, + const struct sk_buff *skb, __u16 *mss) { return 0; diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index c86624b36a62..c0c75688896e 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -170,7 +170,8 @@ u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th, } EXPORT_SYMBOL_GPL(__cookie_v4_init_sequence); -__u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) +__u32 cookie_v4_init_sequence(struct sock *sk, const struct sk_buff *skb, + __u16 *mssp) { const struct iphdr *iph = ip_hdr(skb); const struct tcphdr *th = tcp_hdr(skb); -- cgit v1.2.3 From aa27fc501850030fb5d1ee705feb836ee6a21f2a Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:09:51 +0300 Subject: tcp: tcp_v[46]_conn_request: fix snt_synack initialization Commit 016818d07 (tcp: TCP Fast Open Server - take SYNACK RTT after completing 3WHS) changes the code to only take a snt_synack timestamp when a SYNACK transmit or retransmit succeeds. This behaviour is later broken by commit 843f4a55e (tcp: use tcp_v4_send_synack on first SYN-ACK), as snt_synack is now updated even if tcp_v4_send_synack fails. Also, commit 3a19ce0ee (tcp: IPv6 support for fastopen server) misses the required IPv6 updates for 016818d07. This patch makes sure that snt_synack is updated only when the SYNACK trasnmit/retransmit succeeds, for both IPv4 and IPv6. Cc: Cardwell Cc: Daniel Lee Cc: Yuchung Cheng Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 2 -- net/ipv6/tcp_ipv6.c | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 180336d47df6..145f6402c560 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1370,7 +1370,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) goto drop_and_free; tcp_rsk(req)->snt_isn = isn; - tcp_rsk(req)->snt_synack = tcp_time_stamp; tcp_openreq_init_rwin(req, sk, dst); fastopen = !want_cookie && tcp_try_fastopen(sk, skb, req, &foc, dst); @@ -1380,7 +1379,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (err || want_cookie) goto drop_and_free; - tcp_rsk(req)->snt_synack = tcp_time_stamp; tcp_rsk(req)->listener = NULL; inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 08ae3da0db4a..a962455471ba 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -497,6 +497,8 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, skb_set_queue_mapping(skb, queue_mapping); err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass); err = net_xmit_eval(err); + if (!tcp_rsk(req)->snt_synack && !err) + tcp_rsk(req)->snt_synack = tcp_time_stamp; } done: @@ -1100,7 +1102,6 @@ have_isn: goto drop_and_free; tcp_rsk(req)->snt_isn = isn; - tcp_rsk(req)->snt_synack = tcp_time_stamp; tcp_openreq_init_rwin(req, sk, dst); fastopen = !want_cookie && tcp_try_fastopen(sk, skb, req, &foc, dst); -- cgit v1.2.3 From 476eab8251641ea2ae4666ca8a1436ebc2b8e9c3 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:09:52 +0300 Subject: net: remove inet6_reqsk_alloc Since pktops is only used for IPv6 only and opts is used for IPv4 only, we can move these fields into a union and this allows us to drop the inet6_reqsk_alloc function as after this change it becomes equivalent with inet_reqsk_alloc. This patch also fixes a kmemcheck issue in the IPv6 stack: the flags field was not annotated after a request_sock was allocated. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/linux/ipv6.h | 10 ---------- include/net/inet_sock.h | 6 ++++-- net/dccp/ipv6.c | 2 +- net/ipv6/syncookies.c | 2 +- net/ipv6/tcp_ipv6.c | 2 +- 5 files changed, 7 insertions(+), 15 deletions(-) diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 2faef339d8f2..c811300b0b0c 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -256,16 +256,6 @@ static inline struct ipv6_pinfo * inet6_sk(const struct sock *__sk) return inet_sk(__sk)->pinet6; } -static inline struct request_sock *inet6_reqsk_alloc(struct request_sock_ops *ops) -{ - struct request_sock *req = reqsk_alloc(ops); - - if (req) - inet_rsk(req)->pktopts = NULL; - - return req; -} - static inline struct raw6_sock *raw6_sk(const struct sock *sk) { return (struct raw6_sock *)sk; diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index b1edf17bec01..a829b77523cf 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -88,8 +88,10 @@ struct inet_request_sock { acked : 1, no_srccheck: 1; kmemcheck_bitfield_end(flags); - struct ip_options_rcu *opt; - struct sk_buff *pktopts; + union { + struct ip_options_rcu *opt; + struct sk_buff *pktopts; + }; u32 ir_mark; }; diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 4db3c2a1679c..04cb17d4b0ce 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -386,7 +386,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) goto drop; - req = inet6_reqsk_alloc(&dccp6_request_sock_ops); + req = inet_reqsk_alloc(&dccp6_request_sock_ops); if (req == NULL) goto drop; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index a822b880689b..83cea1d39466 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -187,7 +187,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) goto out; ret = NULL; - req = inet6_reqsk_alloc(&tcp6_request_sock_ops); + req = inet_reqsk_alloc(&tcp6_request_sock_ops); if (!req) goto out; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index a962455471ba..5e2d7e655c0f 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1010,7 +1010,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) goto drop; } - req = inet6_reqsk_alloc(&tcp6_request_sock_ops); + req = inet_reqsk_alloc(&tcp6_request_sock_ops); if (req == NULL) goto drop; -- cgit v1.2.3 From 16bea70aa7302b6f3bf3502d5a0efb4ea2ce4712 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:09:53 +0300 Subject: tcp: add init_req method to tcp_request_sock_ops Move the specific IPv4/IPv6 intializations to a new method in tcp_request_sock_ops in preparation for unifying tcp_v4_conn_request and tcp_v6_conn_request. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/linux/tcp.h | 3 --- include/net/tcp.h | 2 ++ net/ipv4/tcp_ipv4.c | 29 ++++++++++++++++------------ net/ipv6/tcp_ipv6.c | 55 +++++++++++++++++++++++++++++++---------------------- 4 files changed, 51 insertions(+), 38 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index a0513210798f..fa5258f322e7 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -111,10 +111,7 @@ struct tcp_request_sock_ops; struct tcp_request_sock { struct inet_request_sock req; -#ifdef CONFIG_TCP_MD5SIG - /* Only used by TCP MD5 Signature so far. */ const struct tcp_request_sock_ops *af_specific; -#endif struct sock *listener; /* needed for TFO */ u32 rcv_isn; u32 snt_isn; diff --git a/include/net/tcp.h b/include/net/tcp.h index 39e47c4e4f19..7ad8ce296c3b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1613,6 +1613,8 @@ struct tcp_request_sock_ops { const struct request_sock *req, const struct sk_buff *skb); #endif + void (*init_req)(struct request_sock *req, struct sock *sk, + struct sk_buff *skb); }; int tcpv4_offload_init(void); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 145f6402c560..f86a86b30d20 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1237,6 +1237,17 @@ static bool tcp_v4_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb) #endif +static void tcp_v4_init_req(struct request_sock *req, struct sock *sk, + struct sk_buff *skb) +{ + struct inet_request_sock *ireq = inet_rsk(req); + + ireq->ir_loc_addr = ip_hdr(skb)->daddr; + ireq->ir_rmt_addr = ip_hdr(skb)->saddr; + ireq->no_srccheck = inet_sk(sk)->transparent; + ireq->opt = tcp_v4_save_options(skb); +} + struct request_sock_ops tcp_request_sock_ops __read_mostly = { .family = PF_INET, .obj_size = sizeof(struct tcp_request_sock), @@ -1247,26 +1258,26 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = { .syn_ack_timeout = tcp_syn_ack_timeout, }; -#ifdef CONFIG_TCP_MD5SIG static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { +#ifdef CONFIG_TCP_MD5SIG .md5_lookup = tcp_v4_reqsk_md5_lookup, .calc_md5_hash = tcp_v4_md5_hash_skb, -}; #endif + .init_req = tcp_v4_init_req, +}; int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) { struct tcp_options_received tmp_opt; struct request_sock *req; - struct inet_request_sock *ireq; struct tcp_sock *tp = tcp_sk(sk); struct dst_entry *dst = NULL; __be32 saddr = ip_hdr(skb)->saddr; - __be32 daddr = ip_hdr(skb)->daddr; __u32 isn = TCP_SKB_CB(skb)->when; bool want_cookie = false, fastopen; struct flowi4 fl4; struct tcp_fastopen_cookie foc = { .len = -1 }; + const struct tcp_request_sock_ops *af_ops; int err; /* Never answer to SYNs send to broadcast or multicast */ @@ -1298,9 +1309,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (!req) goto drop; -#ifdef CONFIG_TCP_MD5SIG - tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops; -#endif + af_ops = tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops; tcp_clear_options(&tmp_opt); tmp_opt.mss_clamp = TCP_MSS_DEFAULT; @@ -1313,11 +1322,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; tcp_openreq_init(req, &tmp_opt, skb, sk); - ireq = inet_rsk(req); - ireq->ir_loc_addr = daddr; - ireq->ir_rmt_addr = saddr; - ireq->no_srccheck = inet_sk(sk)->transparent; - ireq->opt = tcp_v4_save_options(skb); + af_ops->init_req(req, sk, skb); if (security_inet_conn_request(sk, skb, req)) goto drop_and_free; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5e2d7e655c0f..87a360c3eba9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -720,6 +720,31 @@ static int tcp_v6_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb) } #endif +static void tcp_v6_init_req(struct request_sock *req, struct sock *sk, + struct sk_buff *skb) +{ + struct inet_request_sock *ireq = inet_rsk(req); + struct ipv6_pinfo *np = inet6_sk(sk); + + ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; + ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; + + ireq->ir_iif = sk->sk_bound_dev_if; + + /* So that link locals have meaning */ + if (!sk->sk_bound_dev_if && + ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) + ireq->ir_iif = inet6_iif(skb); + + if (!TCP_SKB_CB(skb)->when && + (ipv6_opt_accepted(sk, skb) || np->rxopt.bits.rxinfo || + np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim || + np->rxopt.bits.rxohlim || np->repflow)) { + atomic_inc(&skb->users); + ireq->pktopts = skb; + } +} + struct request_sock_ops tcp6_request_sock_ops __read_mostly = { .family = AF_INET6, .obj_size = sizeof(struct tcp6_request_sock), @@ -730,12 +755,13 @@ struct request_sock_ops tcp6_request_sock_ops __read_mostly = { .syn_ack_timeout = tcp_syn_ack_timeout, }; -#ifdef CONFIG_TCP_MD5SIG static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { +#ifdef CONFIG_TCP_MD5SIG .md5_lookup = tcp_v6_reqsk_md5_lookup, .calc_md5_hash = tcp_v6_md5_hash_skb, -}; #endif + .init_req = tcp_v6_init_req, +}; static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, @@ -983,13 +1009,13 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) struct tcp_options_received tmp_opt; struct request_sock *req; struct inet_request_sock *ireq; - struct ipv6_pinfo *np = inet6_sk(sk); struct tcp_sock *tp = tcp_sk(sk); __u32 isn = TCP_SKB_CB(skb)->when; struct dst_entry *dst = NULL; struct tcp_fastopen_cookie foc = { .len = -1 }; bool want_cookie = false, fastopen; struct flowi6 fl6; + const struct tcp_request_sock_ops *af_ops; int err; if (skb->protocol == htons(ETH_P_IP)) @@ -1014,9 +1040,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) if (req == NULL) goto drop; -#ifdef CONFIG_TCP_MD5SIG - tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops; -#endif + af_ops = tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops; tcp_clear_options(&tmp_opt); tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); @@ -1030,27 +1054,12 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) tcp_openreq_init(req, &tmp_opt, skb, sk); ireq = inet_rsk(req); - ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; - ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; + af_ops->init_req(req, sk, skb); + if (!want_cookie || tmp_opt.tstamp_ok) TCP_ECN_create_request(req, skb, sock_net(sk)); - ireq->ir_iif = sk->sk_bound_dev_if; - - /* So that link locals have meaning */ - if (!sk->sk_bound_dev_if && - ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) - ireq->ir_iif = inet6_iif(skb); - if (!isn) { - if (ipv6_opt_accepted(sk, skb) || - np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || - np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim || - np->repflow) { - atomic_inc(&skb->users); - ireq->pktopts = skb; - } - if (want_cookie) { isn = cookie_v6_init_sequence(sk, skb, &req->mss); req->cookie_ts = tmp_opt.tstamp_ok; -- cgit v1.2.3 From fb7b37a7f3d6f7b7ba05ee526fee96810d5b92a8 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:09:54 +0300 Subject: tcp: add init_cookie_seq method to tcp_request_sock_ops Move the specific IPv4/IPv6 cookie sequence initialization to a new method in tcp_request_sock_ops in preparation for unifying tcp_v4_conn_request and tcp_v6_conn_request. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/tcp.h | 34 ++++++++++++++++++++-------------- net/ipv4/tcp_ipv4.c | 5 ++++- net/ipv6/tcp_ipv6.c | 5 ++++- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 7ad8ce296c3b..086d00ec6d8b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -495,13 +495,6 @@ u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th, u16 *mssp); __u32 cookie_v4_init_sequence(struct sock *sk, const struct sk_buff *skb, __u16 *mss); -#else -static inline __u32 cookie_v4_init_sequence(struct sock *sk, - const struct sk_buff *skb, - __u16 *mss) -{ - return 0; -} #endif __u32 cookie_init_timestamp(struct request_sock *req); @@ -517,13 +510,6 @@ u32 __cookie_v6_init_sequence(const struct ipv6hdr *iph, const struct tcphdr *th, u16 *mssp); __u32 cookie_v6_init_sequence(struct sock *sk, const struct sk_buff *skb, __u16 *mss); -#else -static inline __u32 cookie_v6_init_sequence(struct sock *sk, - struct sk_buff *skb, - __u16 *mss) -{ - return 0; -} #endif /* tcp_output.c */ @@ -1615,8 +1601,28 @@ struct tcp_request_sock_ops { #endif void (*init_req)(struct request_sock *req, struct sock *sk, struct sk_buff *skb); +#ifdef CONFIG_SYN_COOKIES + __u32 (*cookie_init_seq)(struct sock *sk, const struct sk_buff *skb, + __u16 *mss); +#endif }; +#ifdef CONFIG_SYN_COOKIES +static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, + struct sock *sk, struct sk_buff *skb, + __u16 *mss) +{ + return ops->cookie_init_seq(sk, skb, mss); +} +#else +static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, + struct sock *sk, struct sk_buff *skb, + __u16 *mss) +{ + return 0; +} +#endif + int tcpv4_offload_init(void); void tcp_v4_init(void); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index f86a86b30d20..8c69e44c287b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1264,6 +1264,9 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { .calc_md5_hash = tcp_v4_md5_hash_skb, #endif .init_req = tcp_v4_init_req, +#ifdef CONFIG_SYN_COOKIES + .cookie_init_seq = cookie_v4_init_sequence, +#endif }; int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) @@ -1331,7 +1334,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) TCP_ECN_create_request(req, skb, sock_net(sk)); if (want_cookie) { - isn = cookie_v4_init_sequence(sk, skb, &req->mss); + isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); req->cookie_ts = tmp_opt.tstamp_ok; } else if (!isn) { /* VJ's idea. We save last timestamp seen diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 87a360c3eba9..17710cffddaa 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -761,6 +761,9 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { .calc_md5_hash = tcp_v6_md5_hash_skb, #endif .init_req = tcp_v6_init_req, +#ifdef CONFIG_SYN_COOKIES + .cookie_init_seq = cookie_v6_init_sequence, +#endif }; static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, @@ -1061,7 +1064,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) if (!isn) { if (want_cookie) { - isn = cookie_v6_init_sequence(sk, skb, &req->mss); + isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); req->cookie_ts = tmp_opt.tstamp_ok; goto have_isn; } -- cgit v1.2.3 From d94e0417ad8d96d7d96b69335338ad942eaeecf1 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:09:55 +0300 Subject: tcp: add route_req method to tcp_request_sock_ops Create wrappers with same signature for the IPv4/IPv6 request routing calls and use these wrappers (via route_req method from tcp_request_sock_ops) in tcp_v4_conn_request and tcp_v6_conn_request with the purpose of unifying the two functions in a later patch. We can later drop the wrapper functions and modify inet_csk_route_req and inet6_cks_route_req to use the same signature. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/tcp.h | 3 +++ net/ipv4/tcp_ipv4.c | 36 +++++++++++++++++++++++++++++------- net/ipv6/tcp_ipv6.c | 26 ++++++++++++++++++++------ 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 086d00ec6d8b..59fcc5934c79 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1605,6 +1605,9 @@ struct tcp_request_sock_ops { __u32 (*cookie_init_seq)(struct sock *sk, const struct sk_buff *skb, __u16 *mss); #endif + struct dst_entry *(*route_req)(struct sock *sk, struct flowi *fl, + const struct request_sock *req, + bool *strict); }; #ifdef CONFIG_SYN_COOKIES diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 8c69e44c287b..54fbbd8b4fcd 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1248,6 +1248,22 @@ static void tcp_v4_init_req(struct request_sock *req, struct sock *sk, ireq->opt = tcp_v4_save_options(skb); } +static struct dst_entry *tcp_v4_route_req(struct sock *sk, struct flowi *fl, + const struct request_sock *req, + bool *strict) +{ + struct dst_entry *dst = inet_csk_route_req(sk, &fl->u.ip4, req); + + if (strict) { + if (fl->u.ip4.daddr == inet_rsk(req)->ir_rmt_addr) + *strict = true; + else + *strict = false; + } + + return dst; +} + struct request_sock_ops tcp_request_sock_ops __read_mostly = { .family = PF_INET, .obj_size = sizeof(struct tcp_request_sock), @@ -1267,6 +1283,7 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { #ifdef CONFIG_SYN_COOKIES .cookie_init_seq = cookie_v4_init_sequence, #endif + .route_req = tcp_v4_route_req, }; int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) @@ -1346,11 +1363,13 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) * timewait bucket, so that all the necessary checks * are made in the function processing timewait state. */ - if (tmp_opt.saw_tstamp && - tcp_death_row.sysctl_tw_recycle && - (dst = inet_csk_route_req(sk, &fl4, req)) != NULL && - fl4.daddr == saddr) { - if (!tcp_peer_is_proven(req, dst, true)) { + if (tmp_opt.saw_tstamp && tcp_death_row.sysctl_tw_recycle) { + bool strict; + + dst = af_ops->route_req(sk, (struct flowi *)&fl4, req, + &strict); + if (dst && strict && + !tcp_peer_is_proven(req, dst, true)) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); goto drop_and_release; } @@ -1374,8 +1393,11 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) isn = tcp_v4_init_sequence(skb); } - if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL) - goto drop_and_free; + if (!dst) { + dst = af_ops->route_req(sk, (struct flowi *)&fl4, req, NULL); + if (!dst) + goto drop_and_free; + } tcp_rsk(req)->snt_isn = isn; tcp_openreq_init_rwin(req, sk, dst); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 17710cffddaa..d780d8808566 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -745,6 +745,16 @@ static void tcp_v6_init_req(struct request_sock *req, struct sock *sk, } } +static struct dst_entry *tcp_v6_route_req(struct sock *sk, struct flowi *fl, + const struct request_sock *req, + bool *strict) +{ + if (strict) + *strict = true; + return inet6_csk_route_req(sk, &fl->u.ip6, req); +} + + struct request_sock_ops tcp6_request_sock_ops __read_mostly = { .family = AF_INET6, .obj_size = sizeof(struct tcp6_request_sock), @@ -764,6 +774,7 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { #ifdef CONFIG_SYN_COOKIES .cookie_init_seq = cookie_v6_init_sequence, #endif + .route_req = tcp_v6_route_req, }; static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, @@ -1078,10 +1089,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) * timewait bucket, so that all the necessary checks * are made in the function processing timewait state. */ - if (tmp_opt.saw_tstamp && - tcp_death_row.sysctl_tw_recycle && - (dst = inet6_csk_route_req(sk, &fl6, req)) != NULL) { - if (!tcp_peer_is_proven(req, dst, true)) { + if (tmp_opt.saw_tstamp && tcp_death_row.sysctl_tw_recycle) { + dst = af_ops->route_req(sk, (struct flowi *)&fl6, req, + NULL); + if (dst && !tcp_peer_is_proven(req, dst, true)) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); goto drop_and_release; } @@ -1110,8 +1121,11 @@ have_isn: if (security_inet_conn_request(sk, skb, req)) goto drop_and_release; - if (!dst && (dst = inet6_csk_route_req(sk, &fl6, req)) == NULL) - goto drop_and_free; + if (!dst) { + dst = af_ops->route_req(sk, (struct flowi *)&fl6, req, NULL); + if (!dst) + goto drop_and_free; + } tcp_rsk(req)->snt_isn = isn; tcp_openreq_init_rwin(req, sk, dst); -- cgit v1.2.3 From 9403715977075c89b1dbcdd7713ab542807a04ac Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:09:56 +0300 Subject: tcp: move around a few calls in tcp_v6_conn_request Make the tcp_v6_conn_request calls flow similar with that of tcp_v4_conn_request. Note that want_cookie can be true only if isn is zero and that is why we can move the if (want_cookie) block out of the if (!isn) block. Moving security_inet_conn_request() has a couple of side effects: missing inet_rsk(req)->ecn_ok update and the req->cookie_ts update. However, neither SELinux nor Smack security hooks seems to check them. This change should also avoid future different behaviour for IPv4 and IPv6 in the security hooks. Signed-off-by: Octavian Purdila Acked-by: Paul Moore Signed-off-by: David S. Miller --- net/ipv6/tcp_ipv6.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index d780d8808566..91b8a2e699f3 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1070,16 +1070,16 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) ireq = inet_rsk(req); af_ops->init_req(req, sk, skb); + if (security_inet_conn_request(sk, skb, req)) + goto drop_and_release; + if (!want_cookie || tmp_opt.tstamp_ok) TCP_ECN_create_request(req, skb, sock_net(sk)); - if (!isn) { - if (want_cookie) { - isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); - req->cookie_ts = tmp_opt.tstamp_ok; - goto have_isn; - } - + if (want_cookie) { + isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); + req->cookie_ts = tmp_opt.tstamp_ok; + } else if (!isn) { /* VJ's idea. We save last timestamp seen * from the destination in peer table, when entering * state TIME-WAIT, and check against it before @@ -1116,10 +1116,6 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) isn = tcp_v6_init_sequence(skb); } -have_isn: - - if (security_inet_conn_request(sk, skb, req)) - goto drop_and_release; if (!dst) { dst = af_ops->route_req(sk, (struct flowi *)&fl6, req, NULL); -- cgit v1.2.3 From 936b8bdb53f90840e658904530f9db8d02ac804b Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:09:57 +0300 Subject: tcp: add init_seq method to tcp_request_sock_ops More work in preparation of unifying tcp_v4_conn_request and tcp_v6_conn_request: indirect the init sequence calls via the tcp_request_sock_ops. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/tcp.h | 1 + net/ipv4/tcp_ipv4.c | 5 +++-- net/ipv6/tcp_ipv6.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 59fcc5934c79..8cacf0d6ed4d 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1608,6 +1608,7 @@ struct tcp_request_sock_ops { struct dst_entry *(*route_req)(struct sock *sk, struct flowi *fl, const struct request_sock *req, bool *strict); + __u32 (*init_seq)(const struct sk_buff *skb); }; #ifdef CONFIG_SYN_COOKIES diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 54fbbd8b4fcd..43478265006a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -99,7 +99,7 @@ static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, struct inet_hashinfo tcp_hashinfo; EXPORT_SYMBOL(tcp_hashinfo); -static inline __u32 tcp_v4_init_sequence(const struct sk_buff *skb) +static __u32 tcp_v4_init_sequence(const struct sk_buff *skb) { return secure_tcp_sequence_number(ip_hdr(skb)->daddr, ip_hdr(skb)->saddr, @@ -1284,6 +1284,7 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { .cookie_init_seq = cookie_v4_init_sequence, #endif .route_req = tcp_v4_route_req, + .init_seq = tcp_v4_init_sequence, }; int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) @@ -1391,7 +1392,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) goto drop_and_release; } - isn = tcp_v4_init_sequence(skb); + isn = af_ops->init_seq(skb); } if (!dst) { dst = af_ops->route_req(sk, (struct flowi *)&fl4, req, NULL); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 91b8a2e699f3..2fd886fe8340 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -775,6 +775,7 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { .cookie_init_seq = cookie_v6_init_sequence, #endif .route_req = tcp_v6_route_req, + .init_seq = tcp_v6_init_sequence, }; static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, @@ -1114,7 +1115,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) goto drop_and_release; } - isn = tcp_v6_init_sequence(skb); + isn = af_ops->init_seq(skb); } if (!dst) { -- cgit v1.2.3 From d6274bd8d6ea84b7b54cc1c3fde6bcb6143b104f Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:09:58 +0300 Subject: tcp: add send_synack method to tcp_request_sock_ops Create a new tcp_request_sock_ops method to unify the IPv4/IPv6 signature for tcp_v[46]_send_synack. This allows us to later unify tcp_v4_rtx_synack with tcp_v6_rtx_synack and tcp_v4_conn_request with tcp_v4_conn_request. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/tcp.h | 3 +++ net/ipv4/tcp_ipv4.c | 9 ++++++--- net/ipv6/tcp_ipv6.c | 14 ++++++++------ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 8cacf0d6ed4d..8c05c25018d5 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1609,6 +1609,9 @@ struct tcp_request_sock_ops { const struct request_sock *req, bool *strict); __u32 (*init_seq)(const struct sk_buff *skb); + int (*send_synack)(struct sock *sk, struct dst_entry *dst, + struct flowi *fl, struct request_sock *req, + u16 queue_mapping, struct tcp_fastopen_cookie *foc); }; #ifdef CONFIG_SYN_COOKIES diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 43478265006a..b5945ac50876 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -814,6 +814,7 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, * socket. */ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, + struct flowi *fl, struct request_sock *req, u16 queue_mapping, struct tcp_fastopen_cookie *foc) @@ -846,7 +847,8 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req) { - int res = tcp_v4_send_synack(sk, NULL, req, 0, NULL); + const struct tcp_request_sock_ops *af_ops = tcp_rsk(req)->af_specific; + int res = af_ops->send_synack(sk, NULL, NULL, req, 0, NULL); if (!res) { TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); @@ -1285,6 +1287,7 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { #endif .route_req = tcp_v4_route_req, .init_seq = tcp_v4_init_sequence, + .send_synack = tcp_v4_send_synack, }; int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) @@ -1404,8 +1407,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) tcp_openreq_init_rwin(req, sk, dst); fastopen = !want_cookie && tcp_try_fastopen(sk, skb, req, &foc, dst); - err = tcp_v4_send_synack(sk, dst, req, - skb_get_queue_mapping(skb), &foc); + err = af_ops->send_synack(sk, dst, NULL, req, + skb_get_queue_mapping(skb), &foc); if (!fastopen) { if (err || want_cookie) goto drop_and_free; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 2fd886fe8340..210b6105afed 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -470,13 +470,14 @@ out: static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, - struct flowi6 *fl6, + struct flowi *fl, struct request_sock *req, u16 queue_mapping, struct tcp_fastopen_cookie *foc) { struct inet_request_sock *ireq = inet_rsk(req); struct ipv6_pinfo *np = inet6_sk(sk); + struct flowi6 *fl6 = &fl->u.ip6; struct sk_buff *skb; int err = -ENOMEM; @@ -507,10 +508,11 @@ done: static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req) { - struct flowi6 fl6; + const struct tcp_request_sock_ops *af_ops = tcp_rsk(req)->af_specific; + struct flowi fl; int res; - res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0, NULL); + res = af_ops->send_synack(sk, NULL, &fl, req, 0, NULL); if (!res) { TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); @@ -754,7 +756,6 @@ static struct dst_entry *tcp_v6_route_req(struct sock *sk, struct flowi *fl, return inet6_csk_route_req(sk, &fl->u.ip6, req); } - struct request_sock_ops tcp6_request_sock_ops __read_mostly = { .family = AF_INET6, .obj_size = sizeof(struct tcp6_request_sock), @@ -776,6 +777,7 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { #endif .route_req = tcp_v6_route_req, .init_seq = tcp_v6_init_sequence, + .send_synack = tcp_v6_send_synack, }; static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, @@ -1128,8 +1130,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) tcp_openreq_init_rwin(req, sk, dst); fastopen = !want_cookie && tcp_try_fastopen(sk, skb, req, &foc, dst); - err = tcp_v6_send_synack(sk, dst, &fl6, req, - skb_get_queue_mapping(skb), &foc); + err = af_ops->send_synack(sk, dst, (struct flowi *)&fl6, req, + skb_get_queue_mapping(skb), &foc); if (!fastopen) { if (err || want_cookie) goto drop_and_free; -- cgit v1.2.3 From 5db92c994982ed826cf38f38d58bd09bc326aef6 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:09:59 +0300 Subject: tcp: unify tcp_v4_rtx_synack and tcp_v6_rtx_synack Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/tcp.h | 2 ++ net/ipv4/tcp_ipv4.c | 14 +------------- net/ipv4/tcp_output.c | 15 +++++++++++++++ net/ipv6/tcp_ipv6.c | 15 +-------------- 4 files changed, 19 insertions(+), 27 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 8c05c25018d5..8e9c28dccb80 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1573,6 +1573,8 @@ int tcp4_proc_init(void); void tcp4_proc_exit(void); #endif +int tcp_rtx_synack(struct sock *sk, struct request_sock *req); + /* TCP af-specific functions */ struct tcp_sock_af_ops { #ifdef CONFIG_TCP_MD5SIG diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index b5945ac50876..597dd9d75210 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -845,18 +845,6 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, return err; } -static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req) -{ - const struct tcp_request_sock_ops *af_ops = tcp_rsk(req)->af_specific; - int res = af_ops->send_synack(sk, NULL, NULL, req, 0, NULL); - - if (!res) { - TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); - } - return res; -} - /* * IPv4 request_sock destructor. */ @@ -1269,7 +1257,7 @@ static struct dst_entry *tcp_v4_route_req(struct sock *sk, struct flowi *fl, struct request_sock_ops tcp_request_sock_ops __read_mostly = { .family = PF_INET, .obj_size = sizeof(struct tcp_request_sock), - .rtx_syn_ack = tcp_v4_rtx_synack, + .rtx_syn_ack = tcp_rtx_synack, .send_ack = tcp_v4_reqsk_send_ack, .destructor = tcp_v4_reqsk_destructor, .send_reset = tcp_v4_send_reset, diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index d92bce0ea24e..f8f2a944a1ce 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3299,3 +3299,18 @@ void tcp_send_probe0(struct sock *sk) TCP_RTO_MAX); } } + +int tcp_rtx_synack(struct sock *sk, struct request_sock *req) +{ + const struct tcp_request_sock_ops *af_ops = tcp_rsk(req)->af_specific; + struct flowi fl; + int res; + + res = af_ops->send_synack(sk, NULL, &fl, req, 0, NULL); + if (!res) { + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); + } + return res; +} +EXPORT_SYMBOL(tcp_rtx_synack); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 210b6105afed..41389bbb08c0 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -506,19 +506,6 @@ done: return err; } -static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req) -{ - const struct tcp_request_sock_ops *af_ops = tcp_rsk(req)->af_specific; - struct flowi fl; - int res; - - res = af_ops->send_synack(sk, NULL, &fl, req, 0, NULL); - if (!res) { - TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); - } - return res; -} static void tcp_v6_reqsk_destructor(struct request_sock *req) { @@ -759,7 +746,7 @@ static struct dst_entry *tcp_v6_route_req(struct sock *sk, struct flowi *fl, struct request_sock_ops tcp6_request_sock_ops __read_mostly = { .family = AF_INET6, .obj_size = sizeof(struct tcp6_request_sock), - .rtx_syn_ack = tcp_v6_rtx_synack, + .rtx_syn_ack = tcp_rtx_synack, .send_ack = tcp_v6_reqsk_send_ack, .destructor = tcp_v6_reqsk_destructor, .send_reset = tcp_v6_send_reset, -- cgit v1.2.3 From 2aec4a297b21f3690486bbf8f7d5d29281ba6a48 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:10:00 +0300 Subject: tcp: add mss_clamp to tcp_request_sock_ops Add mss_clamp member to tcp_request_sock_ops so that we can later unify tcp_v4_conn_request and tcp_v6_conn_request. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/tcp.h | 1 + net/ipv4/tcp_ipv4.c | 3 ++- net/ipv6/tcp_ipv6.c | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 8e9c28dccb80..30fe98bc8957 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1592,6 +1592,7 @@ struct tcp_sock_af_ops { }; struct tcp_request_sock_ops { + u16 mss_clamp; #ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *(*md5_lookup) (struct sock *sk, struct request_sock *req); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 597dd9d75210..499d440539ad 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1265,6 +1265,7 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = { }; static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { + .mss_clamp = TCP_MSS_DEFAULT, #ifdef CONFIG_TCP_MD5SIG .md5_lookup = tcp_v4_reqsk_md5_lookup, .calc_md5_hash = tcp_v4_md5_hash_skb, @@ -1324,7 +1325,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) af_ops = tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops; tcp_clear_options(&tmp_opt); - tmp_opt.mss_clamp = TCP_MSS_DEFAULT; + tmp_opt.mss_clamp = af_ops->mss_clamp; tmp_opt.user_mss = tp->rx_opt.user_mss; tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 41389bbb08c0..ad658332cf7d 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -754,6 +754,8 @@ struct request_sock_ops tcp6_request_sock_ops __read_mostly = { }; static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { + .mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - + sizeof(struct ipv6hdr), #ifdef CONFIG_TCP_MD5SIG .md5_lookup = tcp_v6_reqsk_md5_lookup, .calc_md5_hash = tcp_v6_md5_hash_skb, @@ -1047,7 +1049,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) af_ops = tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops; tcp_clear_options(&tmp_opt); - tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); + tmp_opt.mss_clamp = af_ops->mss_clamp; tmp_opt.user_mss = tp->rx_opt.user_mss; tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc); -- cgit v1.2.3 From 695da14eb0af21129187ed3810e329b21262e45f Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:10:01 +0300 Subject: tcp: add queue_add_hash to tcp_request_sock_ops Add queue_add_hash member to tcp_request_sock_ops so that we can later unify tcp_v4_conn_request and tcp_v6_conn_request. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/tcp.h | 2 ++ net/ipv4/tcp_ipv4.c | 3 ++- net/ipv6/tcp_ipv6.c | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 30fe98bc8957..cec6e2cf0610 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1615,6 +1615,8 @@ struct tcp_request_sock_ops { int (*send_synack)(struct sock *sk, struct dst_entry *dst, struct flowi *fl, struct request_sock *req, u16 queue_mapping, struct tcp_fastopen_cookie *foc); + void (*queue_hash_add)(struct sock *sk, struct request_sock *req, + const unsigned long timeout); }; #ifdef CONFIG_SYN_COOKIES diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 499d440539ad..845c39de97ab 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1277,6 +1277,7 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { .route_req = tcp_v4_route_req, .init_seq = tcp_v4_init_sequence, .send_synack = tcp_v4_send_synack, + .queue_hash_add = inet_csk_reqsk_queue_hash_add, }; int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) @@ -1403,7 +1404,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) goto drop_and_free; tcp_rsk(req)->listener = NULL; - inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); + af_ops->queue_hash_add(sk, req, TCP_TIMEOUT_INIT); } return 0; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index ad658332cf7d..8232bc7423c6 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -767,6 +767,7 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { .route_req = tcp_v6_route_req, .init_seq = tcp_v6_init_sequence, .send_synack = tcp_v6_send_synack, + .queue_hash_add = inet6_csk_reqsk_queue_hash_add, }; static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, @@ -1126,7 +1127,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) goto drop_and_free; tcp_rsk(req)->listener = NULL; - inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); + af_ops->queue_hash_add(sk, req, TCP_TIMEOUT_INIT); } return 0; -- cgit v1.2.3 From 1fb6f159fd21c640a28eb65fbd62ce8c9f6a777e Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 25 Jun 2014 17:10:02 +0300 Subject: tcp: add tcp_conn_request Create tcp_conn_request and remove most of the code from tcp_v4_conn_request and tcp_v6_conn_request. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/tcp.h | 3 ++ net/ipv4/tcp_input.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp_ipv4.c | 128 +------------------------------------------- net/ipv6/tcp_ipv6.c | 120 +---------------------------------------- 4 files changed, 155 insertions(+), 244 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index cec6e2cf0610..0d5389aecf18 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1574,6 +1574,9 @@ void tcp4_proc_exit(void); #endif int tcp_rtx_synack(struct sock *sk, struct request_sock *req); +int tcp_conn_request(struct request_sock_ops *rsk_ops, + const struct tcp_request_sock_ops *af_ops, + struct sock *sk, struct sk_buff *skb); /* TCP af-specific functions */ struct tcp_sock_af_ops { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b5c23756965a..97e48d60c4e8 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5877,3 +5877,151 @@ discard: return 0; } EXPORT_SYMBOL(tcp_rcv_state_process); + +static inline void pr_drop_req(struct request_sock *req, __u16 port, int family) +{ + struct inet_request_sock *ireq = inet_rsk(req); + + if (family == AF_INET) + LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI4/%u\n"), + &ireq->ir_rmt_addr, port); + else + LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI6/%u\n"), + &ireq->ir_v6_rmt_addr, port); +} + +int tcp_conn_request(struct request_sock_ops *rsk_ops, + const struct tcp_request_sock_ops *af_ops, + struct sock *sk, struct sk_buff *skb) +{ + struct tcp_options_received tmp_opt; + struct request_sock *req; + struct tcp_sock *tp = tcp_sk(sk); + struct dst_entry *dst = NULL; + __u32 isn = TCP_SKB_CB(skb)->when; + bool want_cookie = false, fastopen; + struct flowi fl; + struct tcp_fastopen_cookie foc = { .len = -1 }; + int err; + + + /* TW buckets are converted to open requests without + * limitations, they conserve resources and peer is + * evidently real one. + */ + if ((sysctl_tcp_syncookies == 2 || + inet_csk_reqsk_queue_is_full(sk)) && !isn) { + want_cookie = tcp_syn_flood_action(sk, skb, rsk_ops->slab_name); + if (!want_cookie) + goto drop; + } + + + /* Accept backlog is full. If we have already queued enough + * of warm entries in syn queue, drop request. It is better than + * clogging syn queue with openreqs with exponentially increasing + * timeout. + */ + if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); + goto drop; + } + + req = inet_reqsk_alloc(rsk_ops); + if (!req) + goto drop; + + tcp_rsk(req)->af_specific = af_ops; + + tcp_clear_options(&tmp_opt); + tmp_opt.mss_clamp = af_ops->mss_clamp; + tmp_opt.user_mss = tp->rx_opt.user_mss; + tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc); + + if (want_cookie && !tmp_opt.saw_tstamp) + tcp_clear_options(&tmp_opt); + + tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; + tcp_openreq_init(req, &tmp_opt, skb, sk); + + af_ops->init_req(req, sk, skb); + + if (security_inet_conn_request(sk, skb, req)) + goto drop_and_free; + + if (!want_cookie || tmp_opt.tstamp_ok) + TCP_ECN_create_request(req, skb, sock_net(sk)); + + if (want_cookie) { + isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); + req->cookie_ts = tmp_opt.tstamp_ok; + } else if (!isn) { + /* VJ's idea. We save last timestamp seen + * from the destination in peer table, when entering + * state TIME-WAIT, and check against it before + * accepting new connection request. + * + * If "isn" is not zero, this request hit alive + * timewait bucket, so that all the necessary checks + * are made in the function processing timewait state. + */ + if (tmp_opt.saw_tstamp && tcp_death_row.sysctl_tw_recycle) { + bool strict; + + dst = af_ops->route_req(sk, &fl, req, &strict); + if (dst && strict && + !tcp_peer_is_proven(req, dst, true)) { + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); + goto drop_and_release; + } + } + /* Kill the following clause, if you dislike this way. */ + else if (!sysctl_tcp_syncookies && + (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < + (sysctl_max_syn_backlog >> 2)) && + !tcp_peer_is_proven(req, dst, false)) { + /* Without syncookies last quarter of + * backlog is filled with destinations, + * proven to be alive. + * It means that we continue to communicate + * to destinations, already remembered + * to the moment of synflood. + */ + pr_drop_req(req, ntohs(tcp_hdr(skb)->source), + rsk_ops->family); + goto drop_and_release; + } + + isn = af_ops->init_seq(skb); + } + if (!dst) { + dst = af_ops->route_req(sk, &fl, req, NULL); + if (!dst) + goto drop_and_free; + } + + tcp_rsk(req)->snt_isn = isn; + tcp_openreq_init_rwin(req, sk, dst); + fastopen = !want_cookie && + tcp_try_fastopen(sk, skb, req, &foc, dst); + err = af_ops->send_synack(sk, dst, &fl, req, + skb_get_queue_mapping(skb), &foc); + if (!fastopen) { + if (err || want_cookie) + goto drop_and_free; + + tcp_rsk(req)->listener = NULL; + af_ops->queue_hash_add(sk, req, TCP_TIMEOUT_INIT); + } + + return 0; + +drop_and_release: + dst_release(dst); +drop_and_free: + reqsk_free(req); +drop: + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); + return 0; +} +EXPORT_SYMBOL(tcp_conn_request); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 845c39de97ab..5dfebd2f2e38 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1282,137 +1282,13 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) { - struct tcp_options_received tmp_opt; - struct request_sock *req; - struct tcp_sock *tp = tcp_sk(sk); - struct dst_entry *dst = NULL; - __be32 saddr = ip_hdr(skb)->saddr; - __u32 isn = TCP_SKB_CB(skb)->when; - bool want_cookie = false, fastopen; - struct flowi4 fl4; - struct tcp_fastopen_cookie foc = { .len = -1 }; - const struct tcp_request_sock_ops *af_ops; - int err; - /* Never answer to SYNs send to broadcast or multicast */ if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) goto drop; - /* TW buckets are converted to open requests without - * limitations, they conserve resources and peer is - * evidently real one. - */ - if ((sysctl_tcp_syncookies == 2 || - inet_csk_reqsk_queue_is_full(sk)) && !isn) { - want_cookie = tcp_syn_flood_action(sk, skb, "TCP"); - if (!want_cookie) - goto drop; - } - - /* Accept backlog is full. If we have already queued enough - * of warm entries in syn queue, drop request. It is better than - * clogging syn queue with openreqs with exponentially increasing - * timeout. - */ - if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); - goto drop; - } - - req = inet_reqsk_alloc(&tcp_request_sock_ops); - if (!req) - goto drop; - - af_ops = tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops; - - tcp_clear_options(&tmp_opt); - tmp_opt.mss_clamp = af_ops->mss_clamp; - tmp_opt.user_mss = tp->rx_opt.user_mss; - tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc); - - if (want_cookie && !tmp_opt.saw_tstamp) - tcp_clear_options(&tmp_opt); - - tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; - tcp_openreq_init(req, &tmp_opt, skb, sk); - - af_ops->init_req(req, sk, skb); - - if (security_inet_conn_request(sk, skb, req)) - goto drop_and_free; + return tcp_conn_request(&tcp_request_sock_ops, + &tcp_request_sock_ipv4_ops, sk, skb); - if (!want_cookie || tmp_opt.tstamp_ok) - TCP_ECN_create_request(req, skb, sock_net(sk)); - - if (want_cookie) { - isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); - req->cookie_ts = tmp_opt.tstamp_ok; - } else if (!isn) { - /* VJ's idea. We save last timestamp seen - * from the destination in peer table, when entering - * state TIME-WAIT, and check against it before - * accepting new connection request. - * - * If "isn" is not zero, this request hit alive - * timewait bucket, so that all the necessary checks - * are made in the function processing timewait state. - */ - if (tmp_opt.saw_tstamp && tcp_death_row.sysctl_tw_recycle) { - bool strict; - - dst = af_ops->route_req(sk, (struct flowi *)&fl4, req, - &strict); - if (dst && strict && - !tcp_peer_is_proven(req, dst, true)) { - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); - goto drop_and_release; - } - } - /* Kill the following clause, if you dislike this way. */ - else if (!sysctl_tcp_syncookies && - (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < - (sysctl_max_syn_backlog >> 2)) && - !tcp_peer_is_proven(req, dst, false)) { - /* Without syncookies last quarter of - * backlog is filled with destinations, - * proven to be alive. - * It means that we continue to communicate - * to destinations, already remembered - * to the moment of synflood. - */ - LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI4/%u\n"), - &saddr, ntohs(tcp_hdr(skb)->source)); - goto drop_and_release; - } - - isn = af_ops->init_seq(skb); - } - if (!dst) { - dst = af_ops->route_req(sk, (struct flowi *)&fl4, req, NULL); - if (!dst) - goto drop_and_free; - } - - tcp_rsk(req)->snt_isn = isn; - tcp_openreq_init_rwin(req, sk, dst); - fastopen = !want_cookie && - tcp_try_fastopen(sk, skb, req, &foc, dst); - err = af_ops->send_synack(sk, dst, NULL, req, - skb_get_queue_mapping(skb), &foc); - if (!fastopen) { - if (err || want_cookie) - goto drop_and_free; - - tcp_rsk(req)->listener = NULL; - af_ops->queue_hash_add(sk, req, TCP_TIMEOUT_INIT); - } - - return 0; - -drop_and_release: - dst_release(dst); -drop_and_free: - reqsk_free(req); drop: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return 0; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8232bc7423c6..bc24ee21339a 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1008,133 +1008,17 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb) return sk; } -/* FIXME: this is substantially similar to the ipv4 code. - * Can some kind of merge be done? -- erics - */ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) { - struct tcp_options_received tmp_opt; - struct request_sock *req; - struct inet_request_sock *ireq; - struct tcp_sock *tp = tcp_sk(sk); - __u32 isn = TCP_SKB_CB(skb)->when; - struct dst_entry *dst = NULL; - struct tcp_fastopen_cookie foc = { .len = -1 }; - bool want_cookie = false, fastopen; - struct flowi6 fl6; - const struct tcp_request_sock_ops *af_ops; - int err; - if (skb->protocol == htons(ETH_P_IP)) return tcp_v4_conn_request(sk, skb); if (!ipv6_unicast_destination(skb)) goto drop; - if ((sysctl_tcp_syncookies == 2 || - inet_csk_reqsk_queue_is_full(sk)) && !isn) { - want_cookie = tcp_syn_flood_action(sk, skb, "TCPv6"); - if (!want_cookie) - goto drop; - } + return tcp_conn_request(&tcp6_request_sock_ops, + &tcp_request_sock_ipv6_ops, sk, skb); - if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); - goto drop; - } - - req = inet_reqsk_alloc(&tcp6_request_sock_ops); - if (req == NULL) - goto drop; - - af_ops = tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops; - - tcp_clear_options(&tmp_opt); - tmp_opt.mss_clamp = af_ops->mss_clamp; - tmp_opt.user_mss = tp->rx_opt.user_mss; - tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc); - - if (want_cookie && !tmp_opt.saw_tstamp) - tcp_clear_options(&tmp_opt); - - tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; - tcp_openreq_init(req, &tmp_opt, skb, sk); - - ireq = inet_rsk(req); - af_ops->init_req(req, sk, skb); - - if (security_inet_conn_request(sk, skb, req)) - goto drop_and_release; - - if (!want_cookie || tmp_opt.tstamp_ok) - TCP_ECN_create_request(req, skb, sock_net(sk)); - - if (want_cookie) { - isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); - req->cookie_ts = tmp_opt.tstamp_ok; - } else if (!isn) { - /* VJ's idea. We save last timestamp seen - * from the destination in peer table, when entering - * state TIME-WAIT, and check against it before - * accepting new connection request. - * - * If "isn" is not zero, this request hit alive - * timewait bucket, so that all the necessary checks - * are made in the function processing timewait state. - */ - if (tmp_opt.saw_tstamp && tcp_death_row.sysctl_tw_recycle) { - dst = af_ops->route_req(sk, (struct flowi *)&fl6, req, - NULL); - if (dst && !tcp_peer_is_proven(req, dst, true)) { - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); - goto drop_and_release; - } - } - /* Kill the following clause, if you dislike this way. */ - else if (!sysctl_tcp_syncookies && - (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < - (sysctl_max_syn_backlog >> 2)) && - !tcp_peer_is_proven(req, dst, false)) { - /* Without syncookies last quarter of - * backlog is filled with destinations, - * proven to be alive. - * It means that we continue to communicate - * to destinations, already remembered - * to the moment of synflood. - */ - LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n", - &ireq->ir_v6_rmt_addr, ntohs(tcp_hdr(skb)->source)); - goto drop_and_release; - } - - isn = af_ops->init_seq(skb); - } - - if (!dst) { - dst = af_ops->route_req(sk, (struct flowi *)&fl6, req, NULL); - if (!dst) - goto drop_and_free; - } - - tcp_rsk(req)->snt_isn = isn; - tcp_openreq_init_rwin(req, sk, dst); - fastopen = !want_cookie && - tcp_try_fastopen(sk, skb, req, &foc, dst); - err = af_ops->send_synack(sk, dst, (struct flowi *)&fl6, req, - skb_get_queue_mapping(skb), &foc); - if (!fastopen) { - if (err || want_cookie) - goto drop_and_free; - - tcp_rsk(req)->listener = NULL; - af_ops->queue_hash_add(sk, req, TCP_TIMEOUT_INIT); - } - return 0; - -drop_and_release: - dst_release(dst); -drop_and_free: - reqsk_free(req); drop: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return 0; /* don't send reset */ -- cgit v1.2.3 From c1878869c0c8e0def3df5397155f369442ce4e06 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 28 Jun 2014 18:39:01 +0200 Subject: netfilter: fix several Kconfig problems in NF_LOG_* warning: (NETFILTER_XT_TARGET_LOG) selects NF_LOG_IPV6 which has unmet direct dependencies (NET && INET && IPV6 && NETFILTER && IP6_NF_IPTABLES && NETFILTER_ADVANCED) warning: (NF_LOG_IPV4 && NF_LOG_IPV6) selects NF_LOG_COMMON which has unmet direct dependencies (NET && INET && NETFILTER && NF_CONNTRACK) Fixes: 83e96d4 ("netfilter: log: split family specific code to nf_log_{ip,ip6,common}.c files") Reported-by: Fengguang Wu Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/Kconfig | 20 ++++++++++---------- net/ipv6/netfilter/Kconfig | 10 +++++----- net/netfilter/Kconfig | 10 ++++------ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 12e6057daea1..fb173126f03d 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -36,6 +36,16 @@ config NF_CONNTRACK_PROC_COMPAT If unsure, say Y. +config NF_LOG_ARP + tristate "ARP packet logging" + default m if NETFILTER_ADVANCED=n + select NF_LOG_COMMON + +config NF_LOG_IPV4 + tristate "IPv4 packet logging" + default m if NETFILTER_ADVANCED=n + select NF_LOG_COMMON + config NF_TABLES_IPV4 depends on NF_TABLES tristate "IPv4 nf_tables support" @@ -159,16 +169,6 @@ config IP_NF_TARGET_SYNPROXY To compile it as a module, choose M here. If unsure, say N. -config NF_LOG_ARP - tristate "ARP packet logging" - default m if NETFILTER_ADVANCED=n - select NF_LOG_INET - -config NF_LOG_IPV4 - tristate "IPv4 packet logging" - default m if NETFILTER_ADVANCED=n - select NF_LOG_COMMON - # NAT + specific targets: nf_conntrack config NF_NAT_IPV4 tristate "IPv4 NAT" diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 1537130e9f5b..ac93df16f5af 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -55,6 +55,11 @@ config NFT_REJECT_IPV6 default NFT_REJECT tristate +config NF_LOG_IPV6 + tristate "IPv6 packet logging" + depends on NETFILTER_ADVANCED + select NF_LOG_COMMON + config IP6_NF_IPTABLES tristate "IP6 tables support (required for filtering)" depends on INET && IPV6 @@ -227,11 +232,6 @@ config IP6_NF_SECURITY If unsure, say N. -config NF_LOG_IPV6 - tristate "IPv6 packet logging" - depends on NETFILTER_ADVANCED - select NF_LOG_COMMON - config NF_NAT_IPV6 tristate "IPv6 NAT" depends on NF_CONNTRACK_IPV6 diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f17b273c9082..ad751fe2e82b 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -46,6 +46,9 @@ config NF_CONNTRACK To compile it as a module, choose M here. If unsure, say N. +config NF_LOG_COMMON + tristate + if NF_CONNTRACK config NF_CONNTRACK_MARK @@ -359,9 +362,6 @@ config NETFILTER_NETLINK_QUEUE_CT If this option is enabled, NFQUEUE can include Connection Tracking information together with the packet is the enqueued via NFNETLINK. -config NF_LOG_COMMON - tristate - config NF_NAT tristate @@ -747,9 +747,7 @@ config NETFILTER_XT_TARGET_LED config NETFILTER_XT_TARGET_LOG tristate "LOG target support" - select NF_LOG - select NF_LOG_IPV4 - select NF_LOG_IPV6 + depends on NF_LOG_IPV4 && NF_LOG_IPV6 default m if NETFILTER_ADVANCED=n help This option adds a `LOG' target, which allows you to create rules in -- cgit v1.2.3 From ca1aa54f272d47bec77baa292f803df7a81f966b Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 28 Jun 2014 18:42:41 +0200 Subject: netfilter: xt_LOG: add missing string format in nf_log_packet() net/netfilter/xt_LOG.c: In function 'log_tg': >> net/netfilter/xt_LOG.c:43: error: format not a string literal and no format arguments Fixes: fab4085 ("netfilter: log: nf_log_packet() as real unified interface") Reported-by: Fengguang Wu Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_LOG.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c index 00eb49196e75..c13b79440ede 100644 --- a/net/netfilter/xt_LOG.c +++ b/net/netfilter/xt_LOG.c @@ -40,7 +40,7 @@ log_tg(struct sk_buff *skb, const struct xt_action_param *par) li.u.log.logflags = loginfo->logflags; nf_log_packet(net, par->family, par->hooknum, skb, par->in, par->out, - &li, loginfo->prefix); + &li, "%s", loginfo->prefix); return XT_CONTINUE; } -- cgit v1.2.3 From 5cbfda2043814f4989efad12be02086a2e4c59fd Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Sun, 29 Jun 2014 13:55:08 +0200 Subject: netfilter: nft_log: fix coccinelle warnings net/netfilter/nft_log.c:79:44-45: Unneeded semicolon Removes unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci CC: Pablo Neira Ayuso Signed-off-by: Fengguang Wu Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c index 5b1a4f5c3dcc..bde05f28cf14 100644 --- a/net/netfilter/nft_log.c +++ b/net/netfilter/nft_log.c @@ -76,7 +76,7 @@ static int nft_log_init(const struct nft_ctx *ctx, case NF_LOG_TYPE_LOG: if (tb[NFTA_LOG_LEVEL] != NULL) { li->u.log.level = - ntohl(nla_get_be32(tb[NFTA_LOG_LEVEL]));; + ntohl(nla_get_be32(tb[NFTA_LOG_LEVEL])); } else { li->u.log.level = 4; } -- cgit v1.2.3 From 1759389e8af46d724220785bf710b7bdbebdfa48 Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Sat, 28 Jun 2014 14:12:44 +0200 Subject: xfrm4: Remove duplicate semicolon 3328715e6c1fc (xfrm4: Add IPsec protocol multiplexer) adds a duplicate semicolon after the return-statement. Although it has no negative impact, the second semicolon should be removed. Cc: Steffen Klassert Cc: Herbert Xu Signed-off-by: Christoph Paasch Signed-off-by: Steffen Klassert --- net/ipv4/xfrm4_protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c index a2ce0101eaac..dccefa9d84cf 100644 --- a/net/ipv4/xfrm4_protocol.c +++ b/net/ipv4/xfrm4_protocol.c @@ -124,7 +124,7 @@ static int xfrm4_ah_rcv(struct sk_buff *skb) for_each_protocol_rcu(ah4_handlers, handler) if ((ret = handler->handler(skb)) != -EINVAL) - return ret;; + return ret; icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); -- cgit v1.2.3 From 4135ab8208048a1586385fae1298726d7dacfc26 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 28 Jun 2014 21:20:54 +0300 Subject: tcp: tcp_conn_request: fix build error when IPv6 is disabled Fixes build error introduced by commit 1fb6f159fd21c64 (tcp: add tcp_conn_request): net/ipv4/tcp_input.c: In function 'pr_drop_req': net/ipv4/tcp_input.c:5889:130: error: 'struct sock_common' has no member named 'skc_v6_daddr' Reported-by: kbuild test robot Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 97e48d60c4e8..bb684967f7a7 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5885,9 +5885,11 @@ static inline void pr_drop_req(struct request_sock *req, __u16 port, int family) if (family == AF_INET) LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI4/%u\n"), &ireq->ir_rmt_addr, port); - else +#if IS_ENABLED(CONFIG_IPV6) + else if (family == AF_INET6) LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI6/%u\n"), &ireq->ir_v6_rmt_addr, port); +#endif } int tcp_conn_request(struct request_sock_ops *rsk_ops, -- cgit v1.2.3 From 24de3d377539e384621c5b8f8f8d8d01852dddc8 Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Mon, 30 Jun 2014 09:19:32 +0800 Subject: netfilter: use IS_ENABLED() macro replace: #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) with #if IS_ENABLED(CONFIG_NF_CT_NETLINK) replace: #if !defined(CONFIG_NF_NAT) && !defined(CONFIG_NF_NAT_MODULE) with #if !IS_ENABLED(CONFIG_NF_NAT) replace: #if !defined(CONFIG_NF_CONNTRACK) && !defined(CONFIG_NF_CONNTRACK_MODULE) with #if !IS_ENABLED(CONFIG_NF_CONNTRACK) And add missing: IS_ENABLED(CONFIG_NF_CT_NETLINK) in net/ipv{4,6}/netfilter/nf_nat_l3proto_ipv{4,6}.c Signed-off-by: Duan Jiong Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 4 ++-- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 4 ++-- net/ipv4/netfilter/nf_defrag_ipv4.c | 8 ++++---- net/ipv4/netfilter/nf_nat_l3proto_ipv4.c | 4 ++++ net/ipv4/netfilter/nf_nat_proto_gre.c | 2 +- net/ipv4/netfilter/nf_nat_proto_icmp.c | 2 +- net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | 4 ++++ net/netfilter/nf_nat_core.c | 2 +- net/netfilter/nf_nat_proto_common.c | 2 +- net/netfilter/nf_nat_proto_dccp.c | 2 +- net/netfilter/nf_nat_proto_sctp.c | 2 +- net/netfilter/nf_nat_proto_tcp.c | 2 +- net/netfilter/nf_nat_proto_udp.c | 2 +- net/netfilter/nf_nat_proto_udplite.c | 2 +- 14 files changed, 25 insertions(+), 17 deletions(-) diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 8127dc802865..4ce44c4bc57b 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -314,7 +314,7 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) return -ENOENT; } -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #include #include @@ -388,7 +388,7 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = { .invert_tuple = ipv4_invert_tuple, .print_tuple = ipv4_print_tuple, .get_l4proto = ipv4_get_l4proto, -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) .tuple_to_nlattr = ipv4_tuple_to_nlattr, .nlattr_tuple_size = ipv4_nlattr_tuple_size, .nlattr_to_tuple = ipv4_nlattr_to_tuple, diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index a338dad41b7d..b91b2641adda 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -226,7 +226,7 @@ icmp_error(struct net *net, struct nf_conn *tmpl, return icmp_error_message(net, tmpl, skb, ctinfo, hooknum); } -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #include #include @@ -408,7 +408,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = .error = icmp_error, .destroy = NULL, .me = NULL, -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) .tuple_to_nlattr = icmp_tuple_to_nlattr, .nlattr_tuple_size = icmp_nlattr_tuple_size, .nlattr_to_tuple = icmp_nlattr_to_tuple, diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c index b8f6381c7d0b..76bd1aef257f 100644 --- a/net/ipv4/netfilter/nf_defrag_ipv4.c +++ b/net/ipv4/netfilter/nf_defrag_ipv4.c @@ -17,7 +17,7 @@ #include #include #include -#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) +#if IS_ENABLED(CONFIG_NF_CONNTRACK) #include #endif #include @@ -45,7 +45,7 @@ static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum, { u16 zone = NF_CT_DEFAULT_ZONE; -#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) +#if IS_ENABLED(CONFIG_NF_CONNTRACK) if (skb->nfct) zone = nf_ct_zone((struct nf_conn *)skb->nfct); #endif @@ -74,8 +74,8 @@ static unsigned int ipv4_conntrack_defrag(const struct nf_hook_ops *ops, inet->nodefrag) return NF_ACCEPT; -#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) -#if !defined(CONFIG_NF_NAT) && !defined(CONFIG_NF_NAT_MODULE) +#if IS_ENABLED(CONFIG_NF_CONNTRACK) +#if !IS_ENABLED(CONFIG_NF_NAT) /* Previously seen (loopback)? Ignore. Do this before fragment check. */ if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) diff --git a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c index d8b2e14efddc..14f5ccd06337 100644 --- a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c @@ -154,6 +154,7 @@ static void nf_nat_ipv4_csum_recalc(struct sk_buff *skb, htons(oldlen), htons(datalen), 1); } +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) static int nf_nat_ipv4_nlattr_to_range(struct nlattr *tb[], struct nf_nat_range *range) { @@ -169,6 +170,7 @@ static int nf_nat_ipv4_nlattr_to_range(struct nlattr *tb[], return 0; } +#endif static const struct nf_nat_l3proto nf_nat_l3proto_ipv4 = { .l3proto = NFPROTO_IPV4, @@ -177,7 +179,9 @@ static const struct nf_nat_l3proto nf_nat_l3proto_ipv4 = { .manip_pkt = nf_nat_ipv4_manip_pkt, .csum_update = nf_nat_ipv4_csum_update, .csum_recalc = nf_nat_ipv4_csum_recalc, +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) .nlattr_to_range = nf_nat_ipv4_nlattr_to_range, +#endif #ifdef CONFIG_XFRM .decode_session = nf_nat_ipv4_decode_session, #endif diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c index 690d890111bb..9414923f1e15 100644 --- a/net/ipv4/netfilter/nf_nat_proto_gre.c +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c @@ -124,7 +124,7 @@ static const struct nf_nat_l4proto gre = { .manip_pkt = gre_manip_pkt, .in_range = nf_nat_l4proto_in_range, .unique_tuple = gre_unique_tuple, -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, #endif }; diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c index eb303471bcf6..4557b4ab8342 100644 --- a/net/ipv4/netfilter/nf_nat_proto_icmp.c +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c @@ -77,7 +77,7 @@ const struct nf_nat_l4proto nf_nat_l4proto_icmp = { .manip_pkt = icmp_manip_pkt, .in_range = icmp_in_range, .unique_tuple = icmp_unique_tuple, -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, #endif }; diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c index abfe75a2e316..fc8e49b2ff3e 100644 --- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c @@ -158,6 +158,7 @@ static void nf_nat_ipv6_csum_recalc(struct sk_buff *skb, htons(oldlen), htons(datalen), 1); } +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) static int nf_nat_ipv6_nlattr_to_range(struct nlattr *tb[], struct nf_nat_range *range) { @@ -175,6 +176,7 @@ static int nf_nat_ipv6_nlattr_to_range(struct nlattr *tb[], return 0; } +#endif static const struct nf_nat_l3proto nf_nat_l3proto_ipv6 = { .l3proto = NFPROTO_IPV6, @@ -183,7 +185,9 @@ static const struct nf_nat_l3proto nf_nat_l3proto_ipv6 = { .manip_pkt = nf_nat_ipv6_manip_pkt, .csum_update = nf_nat_ipv6_csum_update, .csum_recalc = nf_nat_ipv6_csum_recalc, +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) .nlattr_to_range = nf_nat_ipv6_nlattr_to_range, +#endif #ifdef CONFIG_XFRM .decode_session = nf_nat_ipv6_decode_session, #endif diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 09096a670c45..31c5015394e9 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c @@ -677,7 +677,7 @@ static struct nf_ct_ext_type nat_extend __read_mostly = { .flags = NF_CT_EXT_F_PREALLOC, }; -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #include #include diff --git a/net/netfilter/nf_nat_proto_common.c b/net/netfilter/nf_nat_proto_common.c index 83a72a235cae..fbce552a796e 100644 --- a/net/netfilter/nf_nat_proto_common.c +++ b/net/netfilter/nf_nat_proto_common.c @@ -95,7 +95,7 @@ void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto, } EXPORT_SYMBOL_GPL(nf_nat_l4proto_unique_tuple); -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) int nf_nat_l4proto_nlattr_to_range(struct nlattr *tb[], struct nf_nat_range *range) { diff --git a/net/netfilter/nf_nat_proto_dccp.c b/net/netfilter/nf_nat_proto_dccp.c index c8be2cdac0bf..b8067b53ff3a 100644 --- a/net/netfilter/nf_nat_proto_dccp.c +++ b/net/netfilter/nf_nat_proto_dccp.c @@ -78,7 +78,7 @@ static const struct nf_nat_l4proto nf_nat_l4proto_dccp = { .manip_pkt = dccp_manip_pkt, .in_range = nf_nat_l4proto_in_range, .unique_tuple = dccp_unique_tuple, -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, #endif }; diff --git a/net/netfilter/nf_nat_proto_sctp.c b/net/netfilter/nf_nat_proto_sctp.c index 754536f2c674..cbc7ade1487b 100644 --- a/net/netfilter/nf_nat_proto_sctp.c +++ b/net/netfilter/nf_nat_proto_sctp.c @@ -59,7 +59,7 @@ static const struct nf_nat_l4proto nf_nat_l4proto_sctp = { .manip_pkt = sctp_manip_pkt, .in_range = nf_nat_l4proto_in_range, .unique_tuple = sctp_unique_tuple, -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, #endif }; diff --git a/net/netfilter/nf_nat_proto_tcp.c b/net/netfilter/nf_nat_proto_tcp.c index 83ec8a6e4c36..37f5505f4529 100644 --- a/net/netfilter/nf_nat_proto_tcp.c +++ b/net/netfilter/nf_nat_proto_tcp.c @@ -79,7 +79,7 @@ const struct nf_nat_l4proto nf_nat_l4proto_tcp = { .manip_pkt = tcp_manip_pkt, .in_range = nf_nat_l4proto_in_range, .unique_tuple = tcp_unique_tuple, -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, #endif }; diff --git a/net/netfilter/nf_nat_proto_udp.c b/net/netfilter/nf_nat_proto_udp.c index 7df613fb34a2..b0ede2f0d8bc 100644 --- a/net/netfilter/nf_nat_proto_udp.c +++ b/net/netfilter/nf_nat_proto_udp.c @@ -70,7 +70,7 @@ const struct nf_nat_l4proto nf_nat_l4proto_udp = { .manip_pkt = udp_manip_pkt, .in_range = nf_nat_l4proto_in_range, .unique_tuple = udp_unique_tuple, -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, #endif }; diff --git a/net/netfilter/nf_nat_proto_udplite.c b/net/netfilter/nf_nat_proto_udplite.c index 776a0d1317b1..368f14e01e75 100644 --- a/net/netfilter/nf_nat_proto_udplite.c +++ b/net/netfilter/nf_nat_proto_udplite.c @@ -69,7 +69,7 @@ static const struct nf_nat_l4proto nf_nat_l4proto_udplite = { .manip_pkt = udplite_manip_pkt, .in_range = nf_nat_l4proto_in_range, .unique_tuple = udplite_unique_tuple, -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +#if IS_ENABLED(CONFIG_NF_CT_NETLINK) .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, #endif }; -- cgit v1.2.3 From 87dc346433edbc069bf547402d321c1f419b2dcc Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 4 Jun 2014 20:41:17 +0000 Subject: i40e/i40evf: Add base address registers to aq struct Add the Base Address High and Low to the admin queue struct to simplify another bit of "which context" logic in the config routines. Change-ID: Iae195a7da3baffc1a9d522119e1e2b427068ad07 Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 58 +++++++++---------------- drivers/net/ethernet/intel/i40e/i40e_adminq.h | 2 + drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 58 +++++++++---------------- drivers/net/ethernet/intel/i40evf/i40e_adminq.h | 2 + 4 files changed, 44 insertions(+), 76 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 95aab708a88d..87f1d8bcb095 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -55,16 +55,24 @@ static void i40e_adminq_init_regs(struct i40e_hw *hw) hw->aq.asq.tail = I40E_VF_ATQT1; hw->aq.asq.head = I40E_VF_ATQH1; hw->aq.asq.len = I40E_VF_ATQLEN1; + hw->aq.asq.bal = I40E_VF_ATQBAL1; + hw->aq.asq.bah = I40E_VF_ATQBAH1; hw->aq.arq.tail = I40E_VF_ARQT1; hw->aq.arq.head = I40E_VF_ARQH1; hw->aq.arq.len = I40E_VF_ARQLEN1; + hw->aq.arq.bal = I40E_VF_ARQBAL1; + hw->aq.arq.bah = I40E_VF_ARQBAH1; } else { hw->aq.asq.tail = I40E_PF_ATQT; hw->aq.asq.head = I40E_PF_ATQH; hw->aq.asq.len = I40E_PF_ATQLEN; + hw->aq.asq.bal = I40E_PF_ATQBAL; + hw->aq.asq.bah = I40E_PF_ATQBAH; hw->aq.arq.tail = I40E_PF_ARQT; hw->aq.arq.head = I40E_PF_ARQH; hw->aq.arq.len = I40E_PF_ARQLEN; + hw->aq.arq.bal = I40E_PF_ARQBAL; + hw->aq.arq.bah = I40E_PF_ARQBAH; } } @@ -300,27 +308,14 @@ static i40e_status i40e_config_asq_regs(struct i40e_hw *hw) wr32(hw, hw->aq.asq.head, 0); wr32(hw, hw->aq.asq.tail, 0); - if (hw->mac.type == I40E_MAC_VF) { - /* configure the transmit queue */ - wr32(hw, I40E_VF_ATQBAH1, - upper_32_bits(hw->aq.asq.desc_buf.pa)); - wr32(hw, I40E_VF_ATQBAL1, - lower_32_bits(hw->aq.asq.desc_buf.pa)); - wr32(hw, I40E_VF_ATQLEN1, (hw->aq.num_asq_entries | - I40E_VF_ATQLEN1_ATQENABLE_MASK)); - reg = rd32(hw, I40E_VF_ATQBAL1); - } else { - /* configure the transmit queue */ - wr32(hw, I40E_PF_ATQBAH, - upper_32_bits(hw->aq.asq.desc_buf.pa)); - wr32(hw, I40E_PF_ATQBAL, - lower_32_bits(hw->aq.asq.desc_buf.pa)); - wr32(hw, I40E_PF_ATQLEN, (hw->aq.num_asq_entries | - I40E_PF_ATQLEN_ATQENABLE_MASK)); - reg = rd32(hw, I40E_PF_ATQBAL); - } + /* set starting point */ + wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | + I40E_PF_ATQLEN_ATQENABLE_MASK)); + wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa)); + wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa)); /* Check one register to verify that config was applied */ + reg = rd32(hw, hw->aq.asq.bal); if (reg != lower_32_bits(hw->aq.asq.desc_buf.pa)) ret_code = I40E_ERR_ADMIN_QUEUE_ERROR; @@ -342,30 +337,17 @@ static i40e_status i40e_config_arq_regs(struct i40e_hw *hw) wr32(hw, hw->aq.arq.head, 0); wr32(hw, hw->aq.arq.tail, 0); - if (hw->mac.type == I40E_MAC_VF) { - /* configure the receive queue */ - wr32(hw, I40E_VF_ARQBAH1, - upper_32_bits(hw->aq.arq.desc_buf.pa)); - wr32(hw, I40E_VF_ARQBAL1, - lower_32_bits(hw->aq.arq.desc_buf.pa)); - wr32(hw, I40E_VF_ARQLEN1, (hw->aq.num_arq_entries | - I40E_VF_ARQLEN1_ARQENABLE_MASK)); - reg = rd32(hw, I40E_VF_ARQBAL1); - } else { - /* configure the receive queue */ - wr32(hw, I40E_PF_ARQBAH, - upper_32_bits(hw->aq.arq.desc_buf.pa)); - wr32(hw, I40E_PF_ARQBAL, - lower_32_bits(hw->aq.arq.desc_buf.pa)); - wr32(hw, I40E_PF_ARQLEN, (hw->aq.num_arq_entries | - I40E_PF_ARQLEN_ARQENABLE_MASK)); - reg = rd32(hw, I40E_PF_ARQBAL); - } + /* set starting point */ + wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | + I40E_PF_ARQLEN_ARQENABLE_MASK)); + wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa)); + wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa)); /* Update tail in the HW to post pre-allocated buffers */ wr32(hw, hw->aq.arq.tail, hw->aq.num_arq_entries - 1); /* Check one register to verify that config was applied */ + reg = rd32(hw, hw->aq.arq.bal); if (reg != lower_32_bits(hw->aq.arq.desc_buf.pa)) ret_code = I40E_ERR_ADMIN_QUEUE_ERROR; diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h index b1552fbc48a0..c6142ba3a10d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h @@ -56,6 +56,8 @@ struct i40e_adminq_ring { u32 head; u32 tail; u32 len; + u32 bah; + u32 bal; }; /* ASQ transaction details */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index 15853fd699a4..79a30dd8c26f 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -53,16 +53,24 @@ static void i40e_adminq_init_regs(struct i40e_hw *hw) hw->aq.asq.tail = I40E_VF_ATQT1; hw->aq.asq.head = I40E_VF_ATQH1; hw->aq.asq.len = I40E_VF_ATQLEN1; + hw->aq.asq.bal = I40E_VF_ATQBAL1; + hw->aq.asq.bah = I40E_VF_ATQBAH1; hw->aq.arq.tail = I40E_VF_ARQT1; hw->aq.arq.head = I40E_VF_ARQH1; hw->aq.arq.len = I40E_VF_ARQLEN1; + hw->aq.arq.bal = I40E_VF_ARQBAL1; + hw->aq.arq.bah = I40E_VF_ARQBAH1; } else { hw->aq.asq.tail = I40E_PF_ATQT; hw->aq.asq.head = I40E_PF_ATQH; hw->aq.asq.len = I40E_PF_ATQLEN; + hw->aq.asq.bal = I40E_PF_ATQBAL; + hw->aq.asq.bah = I40E_PF_ATQBAH; hw->aq.arq.tail = I40E_PF_ARQT; hw->aq.arq.head = I40E_PF_ARQH; hw->aq.arq.len = I40E_PF_ARQLEN; + hw->aq.arq.bal = I40E_PF_ARQBAL; + hw->aq.arq.bah = I40E_PF_ARQBAH; } } @@ -298,27 +306,14 @@ static i40e_status i40e_config_asq_regs(struct i40e_hw *hw) wr32(hw, hw->aq.asq.head, 0); wr32(hw, hw->aq.asq.tail, 0); - if (hw->mac.type == I40E_MAC_VF) { - /* configure the transmit queue */ - wr32(hw, I40E_VF_ATQBAH1, - upper_32_bits(hw->aq.asq.desc_buf.pa)); - wr32(hw, I40E_VF_ATQBAL1, - lower_32_bits(hw->aq.asq.desc_buf.pa)); - wr32(hw, I40E_VF_ATQLEN1, (hw->aq.num_asq_entries | - I40E_VF_ATQLEN1_ATQENABLE_MASK)); - reg = rd32(hw, I40E_VF_ATQBAL1); - } else { - /* configure the transmit queue */ - wr32(hw, I40E_PF_ATQBAH, - upper_32_bits(hw->aq.asq.desc_buf.pa)); - wr32(hw, I40E_PF_ATQBAL, - lower_32_bits(hw->aq.asq.desc_buf.pa)); - wr32(hw, I40E_PF_ATQLEN, (hw->aq.num_asq_entries | - I40E_PF_ATQLEN_ATQENABLE_MASK)); - reg = rd32(hw, I40E_PF_ATQBAL); - } + /* set starting point */ + wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | + I40E_PF_ATQLEN_ATQENABLE_MASK)); + wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa)); + wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa)); /* Check one register to verify that config was applied */ + reg = rd32(hw, hw->aq.asq.bal); if (reg != lower_32_bits(hw->aq.asq.desc_buf.pa)) ret_code = I40E_ERR_ADMIN_QUEUE_ERROR; @@ -340,30 +335,17 @@ static i40e_status i40e_config_arq_regs(struct i40e_hw *hw) wr32(hw, hw->aq.arq.head, 0); wr32(hw, hw->aq.arq.tail, 0); - if (hw->mac.type == I40E_MAC_VF) { - /* configure the receive queue */ - wr32(hw, I40E_VF_ARQBAH1, - upper_32_bits(hw->aq.arq.desc_buf.pa)); - wr32(hw, I40E_VF_ARQBAL1, - lower_32_bits(hw->aq.arq.desc_buf.pa)); - wr32(hw, I40E_VF_ARQLEN1, (hw->aq.num_arq_entries | - I40E_VF_ARQLEN1_ARQENABLE_MASK)); - reg = rd32(hw, I40E_VF_ARQBAL1); - } else { - /* configure the receive queue */ - wr32(hw, I40E_PF_ARQBAH, - upper_32_bits(hw->aq.arq.desc_buf.pa)); - wr32(hw, I40E_PF_ARQBAL, - lower_32_bits(hw->aq.arq.desc_buf.pa)); - wr32(hw, I40E_PF_ARQLEN, (hw->aq.num_arq_entries | - I40E_PF_ARQLEN_ARQENABLE_MASK)); - reg = rd32(hw, I40E_PF_ARQBAL); - } + /* set starting point */ + wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | + I40E_PF_ARQLEN_ARQENABLE_MASK)); + wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa)); + wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa)); /* Update tail in the HW to post pre-allocated buffers */ wr32(hw, hw->aq.arq.tail, hw->aq.num_arq_entries - 1); /* Check one register to verify that config was applied */ + reg = rd32(hw, hw->aq.arq.bal); if (reg != lower_32_bits(hw->aq.arq.desc_buf.pa)) ret_code = I40E_ERR_ADMIN_QUEUE_ERROR; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h index e3472c62e155..933537564d95 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h @@ -56,6 +56,8 @@ struct i40e_adminq_ring { u32 head; u32 tail; u32 len; + u32 bah; + u32 bal; }; /* ASQ transaction details */ -- cgit v1.2.3 From 4346940b961606d0628ffa25780797b2e611e9b4 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 4 Jun 2014 20:41:22 +0000 Subject: i40e/i40evf: clear aq bah-bal on shutdown Clear the AQ BAH and BAL registers on a clean shutdown to help make sure all is tidy when the driver is done. Change-ID: I393e92680247daa52a8e00bab183213672d73578 Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 4 ++++ drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 87f1d8bcb095..a8244a54b5dd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -489,6 +489,8 @@ static i40e_status i40e_shutdown_asq(struct i40e_hw *hw) wr32(hw, hw->aq.asq.head, 0); wr32(hw, hw->aq.asq.tail, 0); wr32(hw, hw->aq.asq.len, 0); + wr32(hw, hw->aq.asq.bal, 0); + wr32(hw, hw->aq.asq.bah, 0); /* make sure lock is available */ mutex_lock(&hw->aq.asq_mutex); @@ -520,6 +522,8 @@ static i40e_status i40e_shutdown_arq(struct i40e_hw *hw) wr32(hw, hw->aq.arq.head, 0); wr32(hw, hw->aq.arq.tail, 0); wr32(hw, hw->aq.arq.len, 0); + wr32(hw, hw->aq.arq.bal, 0); + wr32(hw, hw->aq.arq.bah, 0); /* make sure lock is available */ mutex_lock(&hw->aq.arq_mutex); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index 79a30dd8c26f..c277763bcac0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -487,6 +487,8 @@ static i40e_status i40e_shutdown_asq(struct i40e_hw *hw) wr32(hw, hw->aq.asq.head, 0); wr32(hw, hw->aq.asq.tail, 0); wr32(hw, hw->aq.asq.len, 0); + wr32(hw, hw->aq.asq.bal, 0); + wr32(hw, hw->aq.asq.bah, 0); /* make sure lock is available */ mutex_lock(&hw->aq.asq_mutex); @@ -518,6 +520,8 @@ static i40e_status i40e_shutdown_arq(struct i40e_hw *hw) wr32(hw, hw->aq.arq.head, 0); wr32(hw, hw->aq.arq.tail, 0); wr32(hw, hw->aq.arq.len, 0); + wr32(hw, hw->aq.arq.bal, 0); + wr32(hw, hw->aq.arq.bah, 0); /* make sure lock is available */ mutex_lock(&hw->aq.arq_mutex); -- cgit v1.2.3 From 838d41d92a90cc0395893006e20991aa9fd0ac85 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 4 Jun 2014 20:41:27 +0000 Subject: i40e: clear all queues and interrupts Per a recent HW designer comment, this code is for ripping through the queues and interrupts to fully disable them on driver init, specifically to help clean up after a PXE or other early boot activity. Change-ID: I32ed452021a1c2b06dace1969976f882a37b9741 Signed-off-by: Shannon Nelson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 93 ++++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_main.c | 1 + drivers/net/ethernet/intel/i40e/i40e_prototype.h | 1 + 3 files changed, 95 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index bbace40bd114..8305c8a4a0d8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -810,6 +810,99 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw) return 0; } +/** + * i40e_clear_hw - clear out any left over hw state + * @hw: pointer to the hw struct + * + * Clear queues and interrupts, typically called at init time, + * but after the capabilities have been found so we know how many + * queues and msix vectors have been allocated. + **/ +void i40e_clear_hw(struct i40e_hw *hw) +{ + u32 num_queues, base_queue; + u32 num_pf_int; + u32 num_vf_int; + u32 num_vfs; + u32 i, j; + u32 val; + u32 eol = 0x7ff; + + /* get number of interrupts, queues, and vfs */ + val = rd32(hw, I40E_GLPCI_CNF2); + num_pf_int = (val & I40E_GLPCI_CNF2_MSI_X_PF_N_MASK) >> + I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT; + num_vf_int = (val & I40E_GLPCI_CNF2_MSI_X_VF_N_MASK) >> + I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT; + + val = rd32(hw, I40E_PFLAN_QALLOC); + base_queue = (val & I40E_PFLAN_QALLOC_FIRSTQ_MASK) >> + I40E_PFLAN_QALLOC_FIRSTQ_SHIFT; + j = (val & I40E_PFLAN_QALLOC_LASTQ_MASK) >> + I40E_PFLAN_QALLOC_LASTQ_SHIFT; + if (val & I40E_PFLAN_QALLOC_VALID_MASK) + num_queues = (j - base_queue) + 1; + else + num_queues = 0; + + val = rd32(hw, I40E_PF_VT_PFALLOC); + i = (val & I40E_PF_VT_PFALLOC_FIRSTVF_MASK) >> + I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT; + j = (val & I40E_PF_VT_PFALLOC_LASTVF_MASK) >> + I40E_PF_VT_PFALLOC_LASTVF_SHIFT; + if (val & I40E_PF_VT_PFALLOC_VALID_MASK) + num_vfs = (j - i) + 1; + else + num_vfs = 0; + + /* stop all the interrupts */ + wr32(hw, I40E_PFINT_ICR0_ENA, 0); + val = 0x3 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; + for (i = 0; i < num_pf_int - 2; i++) + wr32(hw, I40E_PFINT_DYN_CTLN(i), val); + + /* Set the FIRSTQ_INDX field to 0x7FF in PFINT_LNKLSTx */ + val = eol << I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT; + wr32(hw, I40E_PFINT_LNKLST0, val); + for (i = 0; i < num_pf_int - 2; i++) + wr32(hw, I40E_PFINT_LNKLSTN(i), val); + val = eol << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT; + for (i = 0; i < num_vfs; i++) + wr32(hw, I40E_VPINT_LNKLST0(i), val); + for (i = 0; i < num_vf_int - 2; i++) + wr32(hw, I40E_VPINT_LNKLSTN(i), val); + + /* warn the HW of the coming Tx disables */ + for (i = 0; i < num_queues; i++) { + u32 abs_queue_idx = base_queue + i; + u32 reg_block = 0; + + if (abs_queue_idx >= 128) { + reg_block = abs_queue_idx / 128; + abs_queue_idx %= 128; + } + + val = rd32(hw, I40E_GLLAN_TXPRE_QDIS(reg_block)); + val &= ~I40E_GLLAN_TXPRE_QDIS_QINDX_MASK; + val |= (abs_queue_idx << I40E_GLLAN_TXPRE_QDIS_QINDX_SHIFT); + val |= I40E_GLLAN_TXPRE_QDIS_SET_QDIS_MASK; + + wr32(hw, I40E_GLLAN_TXPRE_QDIS(reg_block), val); + } + udelay(400); + + /* stop all the queues */ + for (i = 0; i < num_queues; i++) { + wr32(hw, I40E_QINT_TQCTL(i), 0); + wr32(hw, I40E_QTX_ENA(i), 0); + wr32(hw, I40E_QINT_RQCTL(i), 0); + wr32(hw, I40E_QRX_ENA(i), 0); + } + + /* short wait for all queue disables to settle */ + udelay(50); +} + /** * i40e_clear_pxe_mode - clear pxe operations mode * @hw: pointer to the hw struct diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 17b1295bf35a..2c285385b4cb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -8636,6 +8636,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Reset here to make sure all is clean and to define PF 'n' */ + i40e_clear_hw(hw); err = i40e_pf_reset(hw); if (err) { dev_info(&pdev->dev, "Initial pf_reset failed: %d\n", err); diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 3300b996a467..77c515d026be 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -217,6 +217,7 @@ i40e_status i40e_aq_query_switch_comp_bw_config(struct i40e_hw *hw, /* i40e_common */ i40e_status i40e_init_shared_code(struct i40e_hw *hw); i40e_status i40e_pf_reset(struct i40e_hw *hw); +void i40e_clear_hw(struct i40e_hw *hw); void i40e_clear_pxe_mode(struct i40e_hw *hw); bool i40e_get_link_status(struct i40e_hw *hw); i40e_status i40e_get_mac_addr(struct i40e_hw *hw, -- cgit v1.2.3 From 0b9754e9324b268d5ca14a0900ede7f350be489a Mon Sep 17 00:00:00 2001 From: Kevin Scott Date: Wed, 4 Jun 2014 20:41:33 +0000 Subject: i40e: Correct mask assignment value Make mask value of all 1s. Value of -1 can't be used for u32 type. Change-ID: I49d58b77639939fe7447a229dbf1f4a1bf7419ce Signed-off-by: Kevin Scott Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c index 5a603a5e9aa8..0d74b46d177f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c @@ -858,7 +858,7 @@ static void i40e_write_dword(u8 *hmc_bits, if (ce_info->width < 32) mask = ((u32)1 << ce_info->width) - 1; else - mask = -1; + mask = 0xFFFFFFFF; /* don't swizzle the bits until after the mask because the mask bits * will be in a different bit position on big endian machines @@ -910,7 +910,7 @@ static void i40e_write_qword(u8 *hmc_bits, if (ce_info->width < 64) mask = ((u64)1 << ce_info->width) - 1; else - mask = -1; + mask = 0xFFFFFFFFFFFFFFFF; /* don't swizzle the bits until after the mask because the mask bits * will be in a different bit position on big endian machines -- cgit v1.2.3 From fc86a970a4628e85242d81255dd789da35f344b4 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 4 Jun 2014 20:41:38 +0000 Subject: i40evf: set flags before sending message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In some circumstances, the firmware could beat us to the punch, and the reply from the PF would come back before we were able to properly modify the aq_pending and aq_required flags. This would mess up the flags and put the driver in an indeterminate state, much like Schrödinger's cat. However, unlike the cat, the driver is definitely dead. To fix this, simply set the flags before sending the request to the AQ. This way, it won't matter if the interrupt comes back too soon. Change-ID: I9784655e475675ebcb3140cc7f36f4a96aaadce5 Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40evf/i40evf_virtchnl.c | 33 +++++++++++----------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 0ed2ad7e4eee..66d12f5b4ca8 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -248,11 +248,11 @@ void i40evf_configure_queues(struct i40evf_adapter *adapter) vqpi++; } + adapter->aq_pending |= I40EVF_FLAG_AQ_CONFIGURE_QUEUES; + adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_QUEUES; i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, (u8 *)vqci, len); kfree(vqci); - adapter->aq_pending |= I40EVF_FLAG_AQ_CONFIGURE_QUEUES; - adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_QUEUES; } /** @@ -275,10 +275,10 @@ void i40evf_enable_queues(struct i40evf_adapter *adapter) vqs.vsi_id = adapter->vsi_res->vsi_id; vqs.tx_queues = (1 << adapter->vsi_res->num_queue_pairs) - 1; vqs.rx_queues = vqs.tx_queues; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ENABLE_QUEUES, - (u8 *)&vqs, sizeof(vqs)); adapter->aq_pending |= I40EVF_FLAG_AQ_ENABLE_QUEUES; adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_QUEUES; + i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ENABLE_QUEUES, + (u8 *)&vqs, sizeof(vqs)); } /** @@ -301,10 +301,10 @@ void i40evf_disable_queues(struct i40evf_adapter *adapter) vqs.vsi_id = adapter->vsi_res->vsi_id; vqs.tx_queues = (1 << adapter->vsi_res->num_queue_pairs) - 1; vqs.rx_queues = vqs.tx_queues; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DISABLE_QUEUES, - (u8 *)&vqs, sizeof(vqs)); adapter->aq_pending |= I40EVF_FLAG_AQ_DISABLE_QUEUES; adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_QUEUES; + i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DISABLE_QUEUES, + (u8 *)&vqs, sizeof(vqs)); } /** @@ -352,11 +352,11 @@ void i40evf_map_queues(struct i40evf_adapter *adapter) vimi->vecmap[v_idx].txq_map = 0; vimi->vecmap[v_idx].rxq_map = 0; + adapter->aq_pending |= I40EVF_FLAG_AQ_MAP_VECTORS; + adapter->aq_required &= ~I40EVF_FLAG_AQ_MAP_VECTORS; i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, (u8 *)vimi, len); kfree(vimi); - adapter->aq_pending |= I40EVF_FLAG_AQ_MAP_VECTORS; - adapter->aq_required &= ~I40EVF_FLAG_AQ_MAP_VECTORS; } /** @@ -413,12 +413,11 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) f->add = false; } } + adapter->aq_pending |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; + adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER; i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, (u8 *)veal, len); kfree(veal); - adapter->aq_pending |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; - adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER; - } /** @@ -475,11 +474,11 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) kfree(f); } } + adapter->aq_pending |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; + adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER; i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS, (u8 *)veal, len); kfree(veal); - adapter->aq_pending |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; - adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER; } /** @@ -536,10 +535,10 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter) f->add = false; } } - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len); - kfree(vvfl); adapter->aq_pending |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER; adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER; + i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len); + kfree(vvfl); } /** @@ -597,10 +596,10 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter) kfree(f); } } - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len); - kfree(vvfl); adapter->aq_pending |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER; adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER; + i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len); + kfree(vvfl); } /** -- cgit v1.2.3 From 09c4e56b3cddecb6cac70339dcec63ed1b4e18c2 Mon Sep 17 00:00:00 2001 From: Kamil Krawczyk Date: Wed, 4 Jun 2014 20:41:43 +0000 Subject: i40e/i40evf: add ASQ write back timeout variable to AQ structure Add new variable defining ASQ command write back timeout to allow for dynamic modification of this timeout. Initialize it on AQ initialize routine with default value, vary it on device ID. Change-ID: I5c9908f9d7c5455634353b694a986d6f146d1b9d Signed-off-by: Kamil Krawczyk Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 5 ++++- drivers/net/ethernet/intel/i40e/i40e_adminq.h | 1 + drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 5 ++++- drivers/net/ethernet/intel/i40evf/i40e_adminq.h | 1 + 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index a8244a54b5dd..2708bcdddd41 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -571,6 +571,9 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw) /* Set up register offsets */ i40e_adminq_init_regs(hw); + /* setup ASQ command write back timeout */ + hw->aq.asq_cmd_timeout = I40E_ASQ_CMD_TIMEOUT; + /* allocate the ASQ */ ret_code = i40e_init_asq(hw); if (ret_code) @@ -860,7 +863,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, /* ugh! delay while spin_lock */ udelay(delay_len); total_delay += delay_len; - } while (total_delay < I40E_ASQ_CMD_TIMEOUT); + } while (total_delay < hw->aq.asq_cmd_timeout); } /* if ready, copy the desc back to temp */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h index c6142ba3a10d..bb76be1d38f7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h @@ -84,6 +84,7 @@ struct i40e_arq_event_info { struct i40e_adminq_info { struct i40e_adminq_ring arq; /* receive queue */ struct i40e_adminq_ring asq; /* send queue */ + u32 asq_cmd_timeout; /* send queue cmd write back timeout*/ u16 num_arq_entries; /* receive queue depth */ u16 num_asq_entries; /* send queue depth */ u16 arq_buf_size; /* receive queue buffer size */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index c277763bcac0..cc4b6db10b04 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -567,6 +567,9 @@ i40e_status i40evf_init_adminq(struct i40e_hw *hw) /* Set up register offsets */ i40e_adminq_init_regs(hw); + /* setup ASQ command write back timeout */ + hw->aq.asq_cmd_timeout = I40E_ASQ_CMD_TIMEOUT; + /* allocate the ASQ */ ret_code = i40e_init_asq(hw); if (ret_code) @@ -814,7 +817,7 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, /* ugh! delay while spin_lock */ udelay(delay_len); total_delay += delay_len; - } while (total_delay < I40E_ASQ_CMD_TIMEOUT); + } while (total_delay < hw->aq.asq_cmd_timeout); } /* if ready, copy the desc back to temp */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h index 933537564d95..162845589bf7 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h @@ -84,6 +84,7 @@ struct i40e_arq_event_info { struct i40e_adminq_info { struct i40e_adminq_ring arq; /* receive queue */ struct i40e_adminq_ring asq; /* send queue */ + u32 asq_cmd_timeout; /* send queue cmd write back timeout*/ u16 num_arq_entries; /* receive queue depth */ u16 num_asq_entries; /* send queue depth */ u16 arq_buf_size; /* receive queue buffer size */ -- cgit v1.2.3 From b814ba65fc625c6791987329737a4dc5b6c95566 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 4 Jun 2014 20:41:48 +0000 Subject: i40e: FD filter replay logic bug fix With the auto_disable flags added there was a bug that was causing the replay logic to not work correctly. This patch fixes the issue so that we call a replay after a sideband reset correctly. Change-ID: I005fe1ac361188ee5b19517a83c922038cba1b00 Signed-off-by: Anjali Singhai Jain Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 5cc27fba8ad5..babb7e6a66bd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -445,14 +445,16 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, */ if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) { /* Turn off ATR first */ - if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) { - pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED; + if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && + !(pf->auto_disable_flags & + I40E_FLAG_FD_ATR_ENABLED)) { dev_warn(&pdev->dev, "FD filter space full, ATR for further flows will be turned off\n"); pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED; pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT; - } else if (pf->flags & I40E_FLAG_FD_SB_ENABLED) { - pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; + } else if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) && + !(pf->auto_disable_flags & + I40E_FLAG_FD_SB_ENABLED)) { dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n"); pf->auto_disable_flags |= I40E_FLAG_FD_SB_ENABLED; -- cgit v1.2.3 From 3efbbb202b6a6f553d40cc7e779e5c375f20efa6 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 4 Jun 2014 20:41:54 +0000 Subject: i40e/i40evf: initialize context descriptor Driver needs to initialize all members of context descriptor. Stale data is possible otherwise. Change-ID: Idc6b53af45583509da42d5ec0824cbaf78aee64f Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 1 + drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index babb7e6a66bd..051e2136715f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1991,6 +1991,7 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring, /* cpu_to_le32 and assign to struct fields */ context_desc->tunneling_params = cpu_to_le32(cd_tunneling); context_desc->l2tag2 = cpu_to_le16(cd_l2tag2); + context_desc->rsvd = cpu_to_le16(0); context_desc->type_cmd_tso_mss = cpu_to_le64(cd_type_cmd_tso_mss); } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 48ebb6cd69f2..f2762f5927cc 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1336,6 +1336,7 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring, /* cpu_to_le32 and assign to struct fields */ context_desc->tunneling_params = cpu_to_le32(cd_tunneling); context_desc->l2tag2 = cpu_to_le16(cd_l2tag2); + context_desc->rsvd = cpu_to_le16(0); context_desc->type_cmd_tso_mss = cpu_to_le64(cd_type_cmd_tso_mss); } -- cgit v1.2.3 From 24a768cfc4f8cbbb3eaf56284610e652ef05fc5b Mon Sep 17 00:00:00 2001 From: Christopher Pau Date: Wed, 4 Jun 2014 20:41:59 +0000 Subject: i40e: limit GLLAN_TXPRE_QDIS to QINDX 0-127 Prevent writing to reserved bits, queue index is 0-127 Change-ID: Ic923e1c92012a265983414acd8f547c4bdac2e34 Signed-off-by: Christopher Pau Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 8305c8a4a0d8..9d09ab31ec89 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -669,8 +669,10 @@ void i40e_pre_tx_queue_cfg(struct i40e_hw *hw, u32 queue, bool enable) u32 reg_block = 0; u32 reg_val; - if (abs_queue_idx >= 128) + if (abs_queue_idx >= 128) { reg_block = abs_queue_idx / 128; + abs_queue_idx %= 128; + } reg_val = rd32(hw, I40E_GLLAN_TXPRE_QDIS(reg_block)); reg_val &= ~I40E_GLLAN_TXPRE_QDIS_QINDX_MASK; -- cgit v1.2.3 From 8efd8e7e821f3daa67ebd2e419646d89dda61f1a Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 4 Jun 2014 20:42:04 +0000 Subject: i40e: remove linux/export.h header from i40e_ptp.c We don't need the export.h header so we can just go ahead and remove it. Change-ID: I9057396b141ee449d8299409081358b9270a7c4d Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 0c935e8f3a6c..c364781c8160 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -25,7 +25,6 @@ ******************************************************************************/ #include "i40e.h" -#include #include /* The XL710 timesync is very much like Intel's 82599 design when it comes to -- cgit v1.2.3 From 0af56f44313644d79ce67d843076520d0302e0fa Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 4 Jun 2014 20:42:10 +0000 Subject: i40evf: change branding string Add a slash to the branding string to reduce confusion and match up with our other marketing materials. Change-ID: I8229e8c3e43083b7a29c859a250f8d2d4dc46b9e Signed-off-by: Mitch Williams Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 8082a9fa5d10..64a267afc3fb 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -34,7 +34,7 @@ static int i40evf_close(struct net_device *netdev); char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = - "Intel(R) XL710 X710 Virtual Function Network Driver"; + "Intel(R) XL710/X710 Virtual Function Network Driver"; #define DRV_VERSION "0.9.36" const char i40evf_driver_version[] = DRV_VERSION; -- cgit v1.2.3 From 67b807e834463ca295bc79c94af4e8fb6db55ee6 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 20:42:15 +0000 Subject: i40e/i40evf: Bump i40e to 0.4.19 and i40evf to 0.9.38 Bump versions. Change-ID: Id5082d7c3995fbddd22b3e303d804c86fcd240a3 Signed-off-by: Catherine Sullivan Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 2c285385b4cb..31709b8cdd5a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 4 -#define DRV_VERSION_BUILD 17 +#define DRV_VERSION_BUILD 19 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 64a267afc3fb..5f29e58bf5ea 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710/X710 Virtual Function Network Driver"; -#define DRV_VERSION "0.9.36" +#define DRV_VERSION "0.9.38" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; -- cgit v1.2.3 From aec653c43b0c55667355e26d7de1236bda9fb4e3 Mon Sep 17 00:00:00 2001 From: Todd Fujinaka Date: Tue, 17 Jun 2014 06:58:11 +0000 Subject: igb: bring link up when PHY is powered up Call igb_setup_link() when the PHY is powered up. Signed-off-by: Todd Fujinaka Reported-by: Jeff Westfahl Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index f145adbb55ac..5759a56aab00 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1630,6 +1630,8 @@ void igb_power_up_link(struct igb_adapter *adapter) igb_power_up_phy_copper(&adapter->hw); else igb_power_up_serdes_link_82575(&adapter->hw); + + igb_setup_link(&adapter->hw); } /** -- cgit v1.2.3 From a5a0fc0461c70047d7fd771499db1710e3630122 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 28 May 2014 07:21:47 +0000 Subject: ixgbe: change PTP NSECS_PER_SEC to IXGBE_PTP_PPS_HALF_SECOND The PPS signal is not correct, as it generates a one half HZ clock signal, as it only generates one level change per second. To generate a full clock, we need two level changes per second. Also, change the name of the #define, in order to prevent confusion between it and NSEC_PER_SEC which is not guaranteed to be a 64bit value. Signed-off-by: Jacob Keller Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index 68f87ecb8a76..5fd4b5271f9a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -98,9 +98,11 @@ #define IXGBE_OVERFLOW_PERIOD (HZ * 30) #define IXGBE_PTP_TX_TIMEOUT (HZ * 15) -#ifndef NSECS_PER_SEC -#define NSECS_PER_SEC 1000000000ULL -#endif +/* half of a one second clock period, for use with PPS signal. We have to use + * this instead of something pre-defined like IXGBE_PTP_PPS_HALF_SECOND, in + * order to force at least 64bits of precision for shifting + */ +#define IXGBE_PTP_PPS_HALF_SECOND 500000000ULL /** * ixgbe_ptp_setup_sdp @@ -146,8 +148,8 @@ static void ixgbe_ptp_setup_sdp(struct ixgbe_adapter *adapter) IXGBE_TSAUXC_SDP0_INT); /* clock period (or pulse length) */ - clktiml = (u32)(NSECS_PER_SEC << shift); - clktimh = (u32)((NSECS_PER_SEC << shift) >> 32); + clktiml = (u32)(IXGBE_PTP_PPS_HALF_SECOND << shift); + clktimh = (u32)((IXGBE_PTP_PPS_HALF_SECOND << shift) >> 32); /* * Account for the cyclecounter wrap-around value by @@ -158,8 +160,8 @@ static void ixgbe_ptp_setup_sdp(struct ixgbe_adapter *adapter) clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32; ns = timecounter_cyc2time(&adapter->tc, clock_edge); - div_u64_rem(ns, NSECS_PER_SEC, &rem); - clock_edge += ((NSECS_PER_SEC - (u64)rem) << shift); + div_u64_rem(ns, IXGBE_PTP_PPS_HALF_SECOND, &rem); + clock_edge += ((IXGBE_PTP_PPS_HALF_SECOND - (u64)rem) << shift); /* specify the initial clock start time */ trgttiml = (u32)clock_edge; -- cgit v1.2.3 From 41881354f93a5e82f16c811f95e0700bf99283ec Mon Sep 17 00:00:00 2001 From: Mathy Vanhoef Date: Fri, 13 Jun 2014 23:40:22 +0200 Subject: ath5k: support for FIF_FCSFAIL filter When the FIF_FCSFAIL filter flag is set, pass frames with CRC errors. Signed-off-by: Mathy Vanhoef Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 1 + drivers/net/wireless/ath/ath5k/base.c | 16 ++++++++++++++-- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 74bd54d6aceb..85316bb3f8c6 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1285,6 +1285,7 @@ struct ath5k_hw { #define ATH_STAT_STARTED 3 /* opened & irqs enabled */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ + unsigned int fif_filter_flags; /* Current FIF_* filter flags */ struct ieee80211_channel *curchan; /* current h/w channel */ u16 nvifs; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 4b18434ba697..5839a3434119 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1382,6 +1382,9 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, rxs->flag = 0; if (unlikely(rs->rs_status & AR5K_RXERR_MIC)) rxs->flag |= RX_FLAG_MMIC_ERROR; + if (unlikely(rs->rs_status & AR5K_RXERR_CRC)) + rxs->flag |= RX_FLAG_FAILED_FCS_CRC; + /* * always extend the mac timestamp, since this information is @@ -1449,6 +1452,8 @@ ath5k_receive_frame_ok(struct ath5k_hw *ah, struct ath5k_rx_status *rs) ah->stats.rx_bytes_count += rs->rs_datalen; if (unlikely(rs->rs_status)) { + unsigned int filters; + if (rs->rs_status & AR5K_RXERR_CRC) ah->stats.rxerr_crc++; if (rs->rs_status & AR5K_RXERR_FIFO) @@ -1480,8 +1485,15 @@ ath5k_receive_frame_ok(struct ath5k_hw *ah, struct ath5k_rx_status *rs) return true; } - /* reject any frames with non-crypto errors */ - if (rs->rs_status & ~(AR5K_RXERR_DECRYPT)) + /* + * Reject any frames with non-crypto errors, and take into account the + * current FIF_* filters. + */ + filters = AR5K_RXERR_DECRYPT; + if (ah->fif_filter_flags & FIF_FCSFAIL) + filters |= AR5K_RXERR_CRC; + + if (rs->rs_status & ~filters) return false; } diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index afb23b3cc7be..b65c38fdaa4b 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -473,6 +473,8 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, /* Set the cached hw filter flags, this will later actually * be set in HW */ ah->filter_flags = rfilt; + /* Store current FIF filter flags */ + ah->fif_filter_flags = *new_flags; mutex_unlock(&ah->lock); } -- cgit v1.2.3 From b76ff0d2e0aaf52adf0e7ec0625aa48a039cba23 Mon Sep 17 00:00:00 2001 From: Mathy Vanhoef Date: Sat, 14 Jun 2014 01:14:56 +0200 Subject: ath5k: capture CCK and OFDM restarts Treat frames that underwent a CCK or OFDM restart as frames with an invalid CRC. Signed-off-by: Mathy Vanhoef Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 5839a3434119..8ad2550bce7f 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1462,7 +1462,20 @@ ath5k_receive_frame_ok(struct ath5k_hw *ah, struct ath5k_rx_status *rs) ah->stats.rxerr_phy++; if (rs->rs_phyerr > 0 && rs->rs_phyerr < 32) ah->stats.rxerr_phy_code[rs->rs_phyerr]++; - return false; + + /* + * Treat packets that underwent a CCK or OFDM reset as having a bad CRC. + * These restarts happen when the radio resynchronizes to a stronger frame + * while receiving a weaker frame. Here we receive the prefix of the weak + * frame. Since these are incomplete packets, mark their CRC as invalid. + */ + if (rs->rs_phyerr == AR5K_RX_PHY_ERROR_OFDM_RESTART || + rs->rs_phyerr == AR5K_RX_PHY_ERROR_CCK_RESTART) { + rs->rs_status |= AR5K_RXERR_CRC; + rs->rs_status &= ~AR5K_RXERR_PHY; + } else { + return false; + } } if (rs->rs_status & AR5K_RXERR_DECRYPT) { /* -- cgit v1.2.3 From 9198cf4a84249f5eed8be1f02b17245b7d763477 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 26 Jun 2014 16:54:40 +0530 Subject: ath9k: Cache beacon config after association The beacon configurations are not cached properly after the station associates with AP. Not handling BEACON_INFO, is failing to update dtim period and also it is causing below warning message. WARNING: CPU: 1 PID: 0 at drivers/net/wireless/ath/ath9k/recv.c:548 ath_rx_tasklet+0xc89/0xca0 [ath9k]() Call Trace: [] dump_stack+0x48/0x69 [] warn_slowpath_common+0x82/0xa0 [] ? ath_rx_tasklet+0xc89/0xca0 [ath9k] [] ? ath_rx_tasklet+0xc89/0xca0 [ath9k] Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index f5727c7a53b8..e6ac8d2e610c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1787,7 +1787,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if ((changed & BSS_CHANGED_BEACON_ENABLED) || - (changed & BSS_CHANGED_BEACON_INT)) { + (changed & BSS_CHANGED_BEACON_INT) || + (changed & BSS_CHANGED_BEACON_INFO)) { if (changed & BSS_CHANGED_BEACON_ENABLED) ath9k_calculate_summary_state(sc, avp->chanctx); ath9k_beacon_config(sc, vif, changed); -- cgit v1.2.3 From 5f2f9e44badc5e322523ef3b4583684255b80a07 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 26 Jun 2014 16:54:41 +0530 Subject: ath9k: Increase max listen interval Earlier the listen interval is used to decide switching between operating and off-channels during bgscan and to improve throughput, the listen interval is reduced to 1. After optimiztion in scan state machine, listen period is not used for decision making and hence reverting it back to original value. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 79fdab6a4003..39419ea845cc 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -797,7 +797,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) /* last queue for offchannel */ hw->offchannel_tx_hw_queue = hw->queues - 1; hw->max_rates = 4; - hw->max_listen_interval = 1; + hw->max_listen_interval = 10; hw->max_rate_tries = 10; hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vif); -- cgit v1.2.3 From 09ebb810927a110e4c354beb20308830d108a54b Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 26 Jun 2014 16:54:42 +0530 Subject: ath9k: Calculate sleep duration Right now sleep duration is configured as beacon interval. It should be the multiple of beacon interval by listen period which helps to reduce station power consumption. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common-beacon.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c index 775d1d20ce0b..733be5178481 100644 --- a/drivers/net/wireless/ath/ath9k/common-beacon.c +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -57,7 +57,7 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, struct ath9k_beacon_state *bs) { struct ath_common *common = ath9k_hw_common(ah); - int dtim_intval; + int dtim_intval, sleepduration; u64 tsf; /* No need to configure beacon if we are not associated */ @@ -75,6 +75,7 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, * last beacon we received (which may be none). */ dtim_intval = conf->intval * conf->dtim_period; + sleepduration = ah->hw->conf.listen_interval * conf->intval; /* * Pull nexttbtt forward to reflect the current @@ -112,7 +113,7 @@ int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, */ bs->bs_sleepduration = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), - conf->intval)); + sleepduration)); if (bs->bs_sleepduration > bs->bs_dtimperiod) bs->bs_sleepduration = bs->bs_dtimperiod; -- cgit v1.2.3 From 5bc5ca85d54e0176cb967f550093f42bb0d65b67 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Fri, 27 Jun 2014 02:51:24 +0400 Subject: rsi: GFP_ATOMIC is not needed in rsi_init_usb_interface() Signed-off-by: Alexey Khoroshilov Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 3226f19989e7..f89695abafcd 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -397,7 +397,7 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter, return -ENOMEM; } - rsi_dev->tx_buffer = kmalloc(2048, GFP_ATOMIC); + rsi_dev->tx_buffer = kmalloc(2048, GFP_KERNEL); rsi_dev->rx_usb_urb[0] = usb_alloc_urb(0, GFP_KERNEL); rsi_dev->rx_usb_urb[0]->transfer_buffer = adapter->priv->rx_data_pkt; rsi_dev->tx_blk_size = 252; -- cgit v1.2.3 From 50591c60a93ad3a8d13833cb8048b02d3c2c4bd4 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Fri, 27 Jun 2014 02:51:25 +0400 Subject: rsi: fix memory leaks and error handling in rsi_91x_usb The patch fixes a couple of issues: - absence of deallocation of rsi_dev->rx_usb_urb[0] in the driver; - potential NULL pointer dereference because of lack of checks for memory allocation success in rsi_init_usb_interface(). By the way, it makes rsi_probe() returning error code instead of 1 and fixes comments regarding returning values. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_usb.c | 58 ++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index f89695abafcd..ef5d394f185b 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -25,7 +25,7 @@ * @len: Length to be written. * @endpoint: Type of endpoint. * - * Return: status: 0 on success, -1 on failure. + * Return: status: 0 on success, a negative error code on failure. */ static int rsi_usb_card_write(struct rsi_hw *adapter, void *buf, @@ -60,7 +60,7 @@ static int rsi_usb_card_write(struct rsi_hw *adapter, * @data: Pointer to the data that has to be written. * @count: Number of multiple bytes to be written. * - * Return: 0 on success, -1 on failure. + * Return: 0 on success, a negative error code on failure. */ static int rsi_write_multiple(struct rsi_hw *adapter, u8 endpoint, @@ -147,7 +147,7 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface, * @value: Value to be read. * @len: length of data to be read. * - * Return: status: 0 on success, -1 on failure. + * Return: status: 0 on success, a negative error code on failure. */ static int rsi_usb_reg_read(struct usb_device *usbdev, u32 reg, @@ -189,7 +189,7 @@ static int rsi_usb_reg_read(struct usb_device *usbdev, * @value: Value to write. * @len: Length of data to be written. * - * Return: status: 0 on success, -1 on failure. + * Return: status: 0 on success, a negative error code on failure. */ static int rsi_usb_reg_write(struct usb_device *usbdev, u32 reg, @@ -249,7 +249,7 @@ static void rsi_rx_done_handler(struct urb *urb) * rsi_rx_urb_submit() - This function submits the given URB to the USB stack. * @adapter: Pointer to the adapter structure. * - * Return: 0 on success, -1 on failure. + * Return: 0 on success, a negative error code on failure. */ static int rsi_rx_urb_submit(struct rsi_hw *adapter) { @@ -281,7 +281,7 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter) * @data: Pointer to the data that has to be written. * @count: Number of multiple bytes to be written on to the registers. * - * Return: status: 0 on success, -1 on failure. + * Return: status: 0 on success, a negative error code on failure. */ int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr, @@ -331,7 +331,7 @@ int rsi_usb_write_register_multiple(struct rsi_hw *adapter, * @pkt: Pointer to the data to be written on to the card. * @len: Length of the data to be written on to the card. * - * Return: 0 on success, -1 on failure. + * Return: 0 on success, a negative error code on failure. */ static int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter, u8 *pkt, @@ -359,6 +359,7 @@ static void rsi_deinit_usb_interface(struct rsi_hw *adapter) struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; rsi_kill_thread(&dev->rx_thread); + usb_free_urb(dev->rx_usb_urb[0]); kfree(adapter->priv->rx_data_pkt); kfree(dev->tx_buffer); } @@ -368,7 +369,7 @@ static void rsi_deinit_usb_interface(struct rsi_hw *adapter) * @adapter: Pointer to the adapter structure. * @pfunction: Pointer to USB interface structure. * - * Return: 0 on success, -1 on failure. + * Return: 0 on success, a negative error code on failure. */ static int rsi_init_usb_interface(struct rsi_hw *adapter, struct usb_interface *pfunction) @@ -398,7 +399,15 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter, } rsi_dev->tx_buffer = kmalloc(2048, GFP_KERNEL); + if (!rsi_dev->tx_buffer) { + status = -ENOMEM; + goto fail_tx; + } rsi_dev->rx_usb_urb[0] = usb_alloc_urb(0, GFP_KERNEL); + if (!rsi_dev->rx_usb_urb[0]) { + status = -ENOMEM; + goto fail_rx; + } rsi_dev->rx_usb_urb[0]->transfer_buffer = adapter->priv->rx_data_pkt; rsi_dev->tx_blk_size = 252; @@ -413,7 +422,7 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter, rsi_usb_rx_thread, "RX-Thread"); if (status) { rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__); - goto fail; + goto fail_thread; } #ifdef CONFIG_RSI_DEBUGFS @@ -424,8 +433,11 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter, rsi_dbg(INIT_ZONE, "%s: Enabled the interface\n", __func__); return 0; -fail: +fail_thread: + usb_free_urb(rsi_dev->rx_usb_urb[0]); +fail_rx: kfree(rsi_dev->tx_buffer); +fail_tx: kfree(common->rx_data_pkt); return status; } @@ -437,7 +449,7 @@ fail: * @pfunction: Pointer to the USB interface structure. * @id: Pointer to the usb_device_id structure. * - * Return: 0 on success, -1 on failure. + * Return: 0 on success, a negative error code on failure. */ static int rsi_probe(struct usb_interface *pfunction, const struct usb_device_id *id) @@ -445,6 +457,7 @@ static int rsi_probe(struct usb_interface *pfunction, struct rsi_hw *adapter; struct rsi_91x_usbdev *dev; u16 fw_status; + int status; rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__); @@ -452,10 +465,11 @@ static int rsi_probe(struct usb_interface *pfunction, if (!adapter) { rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n", __func__); - return 1; + return -ENOMEM; } - if (rsi_init_usb_interface(adapter, pfunction)) { + status = rsi_init_usb_interface(adapter, pfunction); + if (status) { rsi_dbg(ERR_ZONE, "%s: Failed to init usb interface\n", __func__); goto err; @@ -465,26 +479,30 @@ static int rsi_probe(struct usb_interface *pfunction, dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; - if (rsi_usb_reg_read(dev->usbdev, FW_STATUS_REG, &fw_status, 2) < 0) + status = rsi_usb_reg_read(dev->usbdev, FW_STATUS_REG, &fw_status, 2); + if (status) goto err1; else fw_status &= 1; if (!fw_status) { - if (rsi_usb_device_init(adapter->priv)) { + status = rsi_usb_device_init(adapter->priv); + if (status) { rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__); goto err1; } - if (rsi_usb_reg_write(dev->usbdev, - USB_INTERNAL_REG_1, - RSI_USB_READY_MAGIC_NUM, 1) < 0) + status = rsi_usb_reg_write(dev->usbdev, + USB_INTERNAL_REG_1, + RSI_USB_READY_MAGIC_NUM, 1); + if (status) goto err1; rsi_dbg(INIT_ZONE, "%s: Performed device init\n", __func__); } - if (rsi_rx_urb_submit(adapter)) + status = rsi_rx_urb_submit(adapter); + if (status) goto err1; return 0; @@ -493,7 +511,7 @@ err1: err: rsi_91x_deinit(adapter); rsi_dbg(ERR_ZONE, "%s: Failed in probe...Exiting\n", __func__); - return 1; + return status; } /** -- cgit v1.2.3 From f528f664d61cdb87fe12eb24ed9b05548a3e71b3 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 28 Jun 2014 14:18:52 +0200 Subject: drivers/net/wireless/ipw2x00/libipw_module.c: remove unnecessary null test before kfree Fix checkpatch warning: WARNING: kfree(NULL) is safe this check is probably not required Cc: Stanislav Yakovlev Cc: "John W. Linville" Cc: linux-wireless@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/libipw_module.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index 3adb24021a28..5f31b72a4921 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -100,8 +100,7 @@ static inline void libipw_networks_free(struct libipw_device *ieee) int i; for (i = 0; i < MAX_NETWORK_COUNT; i++) { - if (ieee->networks[i]->ibss_dfs) - kfree(ieee->networks[i]->ibss_dfs); + kfree(ieee->networks[i]->ibss_dfs); kfree(ieee->networks[i]); } } -- cgit v1.2.3 From b49c3caf5ef1476895f92ea5fac0b6bd48854628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 29 Jun 2014 21:46:45 +0200 Subject: b43: treat LCNXN-PHY as extra N-PHY devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LCNXN is simply a continuation of N, e.g. code handling LCNXN revs 0 and 1 is mostly the same as for N-PHY revs 7+. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index aae3af2a7a9f..3740b76162f9 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4331,6 +4331,13 @@ static int b43_phy_versioning(struct b43_wldev *dev) analog_type = (tmp & B43_PHYVER_ANALOG) >> B43_PHYVER_ANALOG_SHIFT; phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT; phy_rev = (tmp & B43_PHYVER_VERSION); + + /* LCNXN is continuation of N which run out of revisions */ + if (phy_type == B43_PHYTYPE_LCNXN) { + phy_type = B43_PHYTYPE_N; + phy_rev += 16; + } + switch (phy_type) { #ifdef CONFIG_B43_PHY_G case B43_PHYTYPE_G: -- cgit v1.2.3 From 1f622d76fa704bc67b4fbf0d72cc6c369112986c Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Mon, 30 Jun 2014 18:17:48 +0200 Subject: rtl818x_pci: Fix BSSID register written incorrectly BSSID register was written with six byte-writes. It seems that, similarly to what happens with MAC registers, they needs to be written with one 16-bit and one 32-bit writes, otherwise the write does not work. The byte write didn't work only on my rtl8185, while it worked on rtl8180 and rtl8187se, BTW since there are probably a number of different ASIC revisions out of there, I let the change to affect all cards. It shouldn't hurt anyway. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 1e2592918fc6..e2dcedee5e41 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -1461,9 +1461,10 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, vif_priv = (struct rtl8180_vif *)&vif->drv_priv; if (changed & BSS_CHANGED_BSSID) { - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->BSSID[i], - info->bssid[i]); + rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->BSSID[0], + le16_to_cpu(*(__le16 *)info->bssid)); + rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->BSSID[2], + le32_to_cpu(*(__le32 *)(info->bssid + 2))); if (is_valid_ether_addr(info->bssid)) { if (vif->type == NL80211_IFTYPE_ADHOC) -- cgit v1.2.3 From 7df007243be47808f647c23dd2727528135d1c7f Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Mon, 30 Jun 2014 18:18:25 +0200 Subject: rtl818x_pci: Fix rtl8185 excessive IFS after CTS-to-self Measuring time between _end_ of CTS-to-self and _end_ of datapacket (with a prism54 board and mac80211 hacked to let the MAC timestamp stay untouched in the radiotap header) resulted in about 300uS, while the datapacket itself should be by far shorter (less than 100uS) and IFS should be SIFS (10uS). This measure was confirmed whith a scope: about 250uS IFS has been seen between the two packets. This situation causes the CTS-to-self protection mechanism to work incorrectly due to the NAV expiring during, or even before beginning, the packet transmission, and it also causes the performances to be anyway reduced due to time waste. This problem has been seen at every packet TXed with CTS-to-self enabled on rtl8185 board. rtl8187se seems not affected (and rtl8180, being a 802.11b card, does not have CTS-to-self mechaninsm). This patch fixes this by adding a magic register write, making the board wait for correct SIFS after CTS-to-self packet. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index e2dcedee5e41..73baf268fe67 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -879,6 +879,8 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev) reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2)); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + /* fix eccessive IFS after CTS-to-self */ + rtl818x_iowrite8(priv, REG_ADDR1(0x1ff), 0x35); } if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { -- cgit v1.2.3 From f82be7c46a452fbd229cfbc4ddfb8fbcaf5b644f Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Mon, 30 Jun 2014 18:18:36 +0200 Subject: rtl818x_pci: add comment pointing to the rtl8187se reference code Rtl8187se support has been added to the rtl818x_pci driver by extracting a lot of information from a rtl8187se Linux staging driver included in the kernel at the time rtl8187se support was added. The rtl818x_pci main file has a comment that advertises this. Recently this staging driver has been removed from the kernel, but I still feel it can be useful as "reference" code (in case of bugs, or to implement improvements in rtl818x_pci driver). This one-line patch adds a comment in rtl818x_pci driver to point people searching for that "reference code" to the last kernel version still containing it (3.14). Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 73baf268fe67..8a64bc116bfd 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -16,6 +16,7 @@ * * based also on: * - portions of rtl8187se Linux staging driver, Copyright Realtek corp. + * (available in drivers/staging/rtl8187se directory of Linux 3.14) * - other GPL, unpublished (until now), Linux driver code, * Copyright Larry Finger * -- cgit v1.2.3 From 81129fce7e4fc60fce616c53510699b093d87e26 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Mon, 30 Jun 2014 18:18:55 +0200 Subject: rtl8180: fix incorrect TX retry. HW is programmed with wrong retry count value for TX: Mac80211 passes to driver the number of times the TX should be attempted. The HW, instead, wants the number of time the TX should be retried if it fails the first time (assuming we have to TX it at least one time). This patch correct this. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 8a64bc116bfd..4f4fcf8b2013 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -542,7 +542,7 @@ static void rtl8180_tx(struct ieee80211_hw *dev, entry->flags2 = info->control.rates[1].idx >= 0 ? ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; - entry->retry_limit = info->control.rates[0].count; + entry->retry_limit = info->control.rates[0].count - 1; /* We must be sure that tx_flags is written last because the HW * looks at it to check if the rest of data is valid or not -- cgit v1.2.3 From fe67bcd4c8407f12664cf45cc4bbd86d951515f2 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Mon, 30 Jun 2014 18:19:10 +0200 Subject: rtl8180: disable buggy rate fallback mechanism Currently the driver configures mac80211 to provide two rates for each TX frame: One initial rate and one alternate fallback rate, each one with its retry count. HW does not support fully this: rtl8180 doesn't have support for rate scaling at all, and rtl8185/rtl8187SE supports it in a way that does not fit with mac80211: The HW does automatically fall back to the next lower rate, and only a lower limit can be specified, so the HW may TX also on rates in between the two rates specified by mac80211. Furthermore only the total TX retry count can be specified for each packet, while the number of TX attempts before scaling rate can be configured only globally (not per each packet). Currently the driver sets the HW auto rate fallback mechanism to quickly scale rate after a couple of retries, and it uses the alternate rate requested by mac80211 as fallback limit rate (and it does this even wrongly). The HW indeed will behave differently than what mac80211 mandates, that is probably undesirable, and the reported TX retry count may not refer to what mac80211 thinks, and this could fool mac80211. This patch makes the driver to declare to mac80211 to support only one rate configuration for each packet, and it does disable the HW auto rate fallback mechanism, relying only on SW and letting mac80211 to do all by itself. This should ensure correct operation and fairness respect to mac80211. Indeed here tests with iperf do not show significant performance differences. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 4f4fcf8b2013..5303b8f1d928 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -348,7 +348,6 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) info->flags |= IEEE80211_TX_STAT_ACK; info->status.rates[0].count = (flags & 0xFF) + 1; - info->status.rates[1].idx = -1; ieee80211_tx_status_irqsafe(dev, skb); if (ring->entries - skb_queue_len(&ring->queue) == 2) @@ -540,8 +539,6 @@ static void rtl8180_tx(struct ieee80211_hw *dev, entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); - entry->flags2 = info->control.rates[1].idx >= 0 ? - ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; entry->retry_limit = info->control.rates[0].count - 1; /* We must be sure that tx_flags is written last because the HW @@ -864,7 +861,7 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev) if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180) { rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); - rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); + rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0); } else { rtl818x_iowrite8(priv, &priv->map->SECURITY, 0); @@ -1738,7 +1735,7 @@ static int rtl8180_probe(struct pci_dev *pdev, priv = dev->priv; priv->pdev = pdev; - dev->max_rates = 2; + dev->max_rates = 1; SET_IEEE80211_DEV(dev, &pdev->dev); pci_set_drvdata(pdev, dev); -- cgit v1.2.3 From f4cf628781f802ecf5efa0ceb5e81a2f80dea5b8 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Mon, 30 Jun 2014 18:19:27 +0200 Subject: rtl818x_pci: handle broken PIO mapping All boards supported by this driver could work using PIO or MMIO for accessing registers. This driver tries to access HW by using MMIO, and, if this fails for somewhat reason, the driver tries to fall back to PIO mode. MMIO-mode is straightforward on all boards. PIO-mode is straightforward on rtl8180 only. On rtl8185 and rtl8187se boards not all registers are directly available in PIO mode (they are paged). On rtl8185 there are two pages and it is known how to switch page. PIO mode works, except for only one access to a register out of default page, recently added by me in the initialization code with patch: rtl818x_pci: Fix rtl8185 excessive IFS after CTS-to-self This can be easily fixed to work in both cases (MMIO and PIO). On rtl8187se, for a number of reasons, there is much more work to do to fix PIO access. PIO access is currently broken on rtl8187se, and it never worked. This patch fixes the said register write for rtl8185 and makes the driver to fail cleanly if PIO mode is attempted with rtl8187se boards. While doing this, I converted also a couple of printk(KERN_ERR) to dev_err(), in order to make checkpatch happy. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 24 ++++++++++++++++++++---- drivers/net/wireless/rtl818x/rtl8180/rtl8180.h | 1 + 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 5303b8f1d928..68304a9297fd 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -878,7 +878,15 @@ static int rtl8180_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2)); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); /* fix eccessive IFS after CTS-to-self */ - rtl818x_iowrite8(priv, REG_ADDR1(0x1ff), 0x35); + if (priv->map_pio) { + u8 reg; + + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1); + rtl818x_iowrite8(priv, REG_ADDR1(0xff), 0x35); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + } else + rtl818x_iowrite8(priv, REG_ADDR1(0x1ff), 0x35); } if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) { @@ -1739,13 +1747,15 @@ static int rtl8180_probe(struct pci_dev *pdev, SET_IEEE80211_DEV(dev, &pdev->dev); pci_set_drvdata(pdev, dev); + priv->map_pio = false; priv->map = pci_iomap(pdev, 1, mem_len); - if (!priv->map) + if (!priv->map) { priv->map = pci_iomap(pdev, 0, io_len); + priv->map_pio = true; + } if (!priv->map) { - printk(KERN_ERR "%s (rtl8180): Cannot map device memory\n", - pci_name(pdev)); + dev_err(&pdev->dev, "Cannot map device memory/PIO\n"); goto err_free_dev; } @@ -1794,6 +1804,12 @@ static int rtl8180_probe(struct pci_dev *pdev, case RTL818X_TX_CONF_RTL8187SE: chip_name = "RTL8187SE"; + if (priv->map_pio) { + dev_err(&pdev->dev, + "MMIO failed. PIO not supported on RTL8187SE\n"); + err = -ENOMEM; + goto err_iounmap; + } priv->chip_family = RTL818X_CHIP_FAMILY_RTL8187SE; break; diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h index 291a55970d1a..e8243a44d6b6 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h +++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8180.h @@ -107,6 +107,7 @@ struct rtl8180_priv { struct ieee80211_vif *vif; /* rtl8180 driver specific */ + bool map_pio; spinlock_t lock; void *rx_ring; u8 rx_ring_sz; -- cgit v1.2.3 From c1084e026b4fe73fcc54f82d6a6bd26d9372d583 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Mon, 30 Jun 2014 18:19:40 +0200 Subject: rtl818x_pci: fix pci probe returns success when it fails There are several exit path from the PCI probe function. Some of them, that are taken in case of errors, forget to set the "err" variable, that is returned by the probe function. This can lead to the kernel thinking the probe function succeeds while it didn't, and this in turn causes extra calls to the "remove" function. This patch fix this problem by ensuring "err" variable is assigned to a proper non-zero value in each exit path. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 68304a9297fd..4b904f708184 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -1756,6 +1756,7 @@ static int rtl8180_probe(struct pci_dev *pdev, if (!priv->map) { dev_err(&pdev->dev, "Cannot map device memory/PIO\n"); + err = -ENOMEM; goto err_free_dev; } @@ -1816,6 +1817,7 @@ static int rtl8180_probe(struct pci_dev *pdev, default: printk(KERN_ERR "%s (rtl8180): Unknown chip! (0x%x)\n", pci_name(pdev), reg >> 25); + err = -ENODEV; goto err_iounmap; } @@ -1866,12 +1868,14 @@ static int rtl8180_probe(struct pci_dev *pdev, default: printk(KERN_ERR "%s (rtl8180): Unknown RF! (0x%x)\n", pci_name(pdev), priv->rf_type); + err = -ENODEV; goto err_iounmap; } if (!priv->rf) { printk(KERN_ERR "%s (rtl8180): %s RF frontend not supported!\n", pci_name(pdev), rf_name); + err = -ENODEV; goto err_iounmap; } -- cgit v1.2.3 From e90cf1c7abf6b190f51f89e4f63f961defba38a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 1 Jul 2014 16:19:07 +0200 Subject: b43: N-PHY: fixes for radio 0x2057 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable initialization and update calibration code to fix: b43-phy0 ERROR: Radio 0x2057 rcal timeout b43-phy0 debug: Radio 0x2057 rccal timeout b43-phy0 debug: Radio 0x2057 rccal timeout b43-phy0 ERROR: Radio 0x2057 rcal timeout Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 63 +++++++++++++++++++++++++++++------ drivers/net/wireless/b43/radio_2057.c | 20 +++++------ 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 0fb5e14a4554..8369a08f0327 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -590,7 +590,9 @@ static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd, * Radio 0x2057 **************************************************/ -/* http://bcm-v4.sipsolutions.net/PHY/radio2057_rcal */ +/* Calibrate resistors in LPF of PLL? + * http://bcm-v4.sipsolutions.net/PHY/radio205x_rcal + */ static u8 b43_radio_2057_rcal(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -603,15 +605,25 @@ static u8 b43_radio_2057_rcal(struct b43_wldev *dev) b43_radio_maskset(dev, 0x1ca, ~0x2, 0x1); } + /* Enable */ b43_radio_set(dev, R2057_RCAL_CONFIG, 0x1); udelay(10); - b43_radio_set(dev, R2057_RCAL_CONFIG, 0x3); - if (!b43_radio_wait_value(dev, R2057_RCCAL_N1_1, 1, 1, 100, 1000000)) { + + /* Start */ + b43_radio_set(dev, R2057_RCAL_CONFIG, 0x2); + usleep_range(100, 200); + + /* Stop */ + b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x2); + + /* Wait and check for result */ + if (!b43_radio_wait_value(dev, R2057_RCAL_STATUS, 1, 1, 100, 1000000)) { b43err(dev->wl, "Radio 0x2057 rcal timeout\n"); return 0; } - b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x2); tmp = b43_radio_read(dev, R2057_RCAL_STATUS) & 0x3E; + + /* Disable */ b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x1); if (phy->radio_rev == 5) { @@ -627,7 +639,9 @@ static u8 b43_radio_2057_rcal(struct b43_wldev *dev) return tmp & 0x3e; } -/* http://bcm-v4.sipsolutions.net/PHY/radio2057_rccal */ +/* Calibrate the internal RC oscillator? + * http://bcm-v4.sipsolutions.net/PHY/radio2057_rccal + */ static u16 b43_radio_2057_rccal(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -635,49 +649,76 @@ static u16 b43_radio_2057_rccal(struct b43_wldev *dev) phy->radio_rev == 6); u16 tmp; + /* Setup cal */ if (special) { b43_radio_write(dev, R2057_RCCAL_MASTER, 0x61); b43_radio_write(dev, R2057_RCCAL_TRC0, 0xC0); } else { - b43_radio_write(dev, 0x1AE, 0x61); + b43_radio_write(dev, R2057v7_RCCAL_MASTER, 0x61); b43_radio_write(dev, R2057_RCCAL_TRC0, 0xE1); } b43_radio_write(dev, R2057_RCCAL_X1, 0x6E); + + /* Start, wait, stop */ b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55); - if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500, + if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 2, 2, 500, 5000000)) b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n"); + usleep_range(35, 70); b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15); + usleep_range(70, 140); + + /* Setup cal */ if (special) { b43_radio_write(dev, R2057_RCCAL_MASTER, 0x69); b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0); } else { - b43_radio_write(dev, 0x1AE, 0x69); + b43_radio_write(dev, R2057v7_RCCAL_MASTER, 0x69); b43_radio_write(dev, R2057_RCCAL_TRC0, 0xD5); } b43_radio_write(dev, R2057_RCCAL_X1, 0x6E); + + /* Start, wait, stop */ + usleep_range(35, 70); b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55); - if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500, + usleep_range(70, 140); + if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 2, 2, 500, 5000000)) b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n"); + usleep_range(35, 70); b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15); + usleep_range(70, 140); + + /* Setup cal */ if (special) { b43_radio_write(dev, R2057_RCCAL_MASTER, 0x73); b43_radio_write(dev, R2057_RCCAL_X1, 0x28); b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0); } else { - b43_radio_write(dev, 0x1AE, 0x73); + b43_radio_write(dev, R2057v7_RCCAL_MASTER, 0x73); b43_radio_write(dev, R2057_RCCAL_X1, 0x6E); b43_radio_write(dev, R2057_RCCAL_TRC0, 0x99); } + + /* Start, wait, stop */ + usleep_range(35, 70); b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55); - if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500, + usleep_range(70, 140); + if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 2, 2, 500, 5000000)) { b43err(dev->wl, "Radio 0x2057 rcal timeout\n"); return 0; } tmp = b43_radio_read(dev, R2057_RCCAL_DONE_OSCCAP); + usleep_range(35, 70); b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15); + usleep_range(70, 140); + + if (special) + b43_radio_mask(dev, R2057_RCCAL_MASTER, ~0x1); + else + b43_radio_mask(dev, R2057v7_RCCAL_MASTER, ~0x1); + return tmp; } diff --git a/drivers/net/wireless/b43/radio_2057.c b/drivers/net/wireless/b43/radio_2057.c index d61d6830c5c7..5e49440d4125 100644 --- a/drivers/net/wireless/b43/radio_2057.c +++ b/drivers/net/wireless/b43/radio_2057.c @@ -26,7 +26,7 @@ #include "radio_2057.h" #include "phy_common.h" -static u16 r2057_rev4_init[42][2] = { +static u16 r2057_rev4_init[][2] = { { 0x0E, 0x20 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x35, 0x26 }, { 0x3C, 0xff }, { 0x3D, 0xff }, { 0x3E, 0xff }, { 0x3F, 0xff }, { 0x62, 0x33 }, { 0x8A, 0xf0 }, { 0x8B, 0x10 }, @@ -40,7 +40,7 @@ static u16 r2057_rev4_init[42][2] = { { 0x1AB, 0x00 }, { 0x1AC, 0x00 }, }; -static u16 r2057_rev5_init[44][2] = { +static u16 r2057_rev5_init[][2] = { { 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x23, 0x6 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, @@ -54,7 +54,7 @@ static u16 r2057_rev5_init[44][2] = { { 0x1AC, 0x00 }, { 0x1B7, 0x0c }, { 0x1C1, 0x01 }, { 0x1C2, 0x80 }, }; -static u16 r2057_rev5a_init[45][2] = { +static u16 r2057_rev5a_init[][2] = { { 0x00, 0x15 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x23, 0x6 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, @@ -69,7 +69,7 @@ static u16 r2057_rev5a_init[45][2] = { { 0x1C2, 0x80 }, }; -static u16 r2057_rev7_init[54][2] = { +static u16 r2057_rev7_init[][2] = { { 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x13 }, @@ -86,7 +86,7 @@ static u16 r2057_rev7_init[54][2] = { { 0x1B7, 0x05 }, { 0x1C2, 0xa0 }, }; -static u16 r2057_rev8_init[54][2] = { +static u16 r2057_rev8_init[][2] = { { 0x00, 0x08 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x0f }, @@ -130,12 +130,10 @@ void r2057_upload_inittabs(struct b43_wldev *dev) } } + B43_WARN_ON(!table); + if (table) { - for (i = 0; i < 10; i++) { - pr_info("radio_write 0x%X ", *table); - table++; - pr_info("0x%X\n", *table); - table++; - } + for (i = 0; i < size; i++, table += 2) + b43_radio_write(dev, table[0], table[1]); } } -- cgit v1.2.3 From fe255b40cbf0a760b4e62a5948d77aff12b6b0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 1 Jul 2014 16:19:08 +0200 Subject: b43: N-PHY: complete generic support for 0x2057 radio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It doesn't include any device (radio revision) specific code yet, so it isn't really usable. As the commit says, it's just some generic code. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 132 +++++++++++++++++++++++++++++++--- drivers/net/wireless/b43/radio_2057.c | 104 +++++++++++++++++++++++---- drivers/net/wireless/b43/radio_2057.h | 66 +++++++++++++++++ 3 files changed, 282 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8369a08f0327..0a6f04be9073 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -590,6 +590,100 @@ static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd, * Radio 0x2057 **************************************************/ +static void b43_radio_2057_chantab_upload(struct b43_wldev *dev, + const struct b43_nphy_chantabent_rev7 *e_r7, + const struct b43_nphy_chantabent_rev7_2g *e_r7_2g) +{ + if (e_r7_2g) { + b43_radio_write(dev, R2057_VCOCAL_COUNTVAL0, e_r7_2g->radio_vcocal_countval0); + b43_radio_write(dev, R2057_VCOCAL_COUNTVAL1, e_r7_2g->radio_vcocal_countval1); + b43_radio_write(dev, R2057_RFPLL_REFMASTER_SPAREXTALSIZE, e_r7_2g->radio_rfpll_refmaster_sparextalsize); + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_R1, e_r7_2g->radio_rfpll_loopfilter_r1); + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C2, e_r7_2g->radio_rfpll_loopfilter_c2); + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C1, e_r7_2g->radio_rfpll_loopfilter_c1); + b43_radio_write(dev, R2057_CP_KPD_IDAC, e_r7_2g->radio_cp_kpd_idac); + b43_radio_write(dev, R2057_RFPLL_MMD0, e_r7_2g->radio_rfpll_mmd0); + b43_radio_write(dev, R2057_RFPLL_MMD1, e_r7_2g->radio_rfpll_mmd1); + b43_radio_write(dev, R2057_VCOBUF_TUNE, e_r7_2g->radio_vcobuf_tune); + b43_radio_write(dev, R2057_LOGEN_MX2G_TUNE, e_r7_2g->radio_logen_mx2g_tune); + b43_radio_write(dev, R2057_LOGEN_INDBUF2G_TUNE, e_r7_2g->radio_logen_indbuf2g_tune); + b43_radio_write(dev, R2057_TXMIX2G_TUNE_BOOST_PU_CORE0, e_r7_2g->radio_txmix2g_tune_boost_pu_core0); + b43_radio_write(dev, R2057_PAD2G_TUNE_PUS_CORE0, e_r7_2g->radio_pad2g_tune_pus_core0); + b43_radio_write(dev, R2057_LNA2G_TUNE_CORE0, e_r7_2g->radio_lna2g_tune_core0); + b43_radio_write(dev, R2057_TXMIX2G_TUNE_BOOST_PU_CORE1, e_r7_2g->radio_txmix2g_tune_boost_pu_core1); + b43_radio_write(dev, R2057_PAD2G_TUNE_PUS_CORE1, e_r7_2g->radio_pad2g_tune_pus_core1); + b43_radio_write(dev, R2057_LNA2G_TUNE_CORE1, e_r7_2g->radio_lna2g_tune_core1); + + } else { + b43_radio_write(dev, R2057_VCOCAL_COUNTVAL0, e_r7->radio_vcocal_countval0); + b43_radio_write(dev, R2057_VCOCAL_COUNTVAL1, e_r7->radio_vcocal_countval1); + b43_radio_write(dev, R2057_RFPLL_REFMASTER_SPAREXTALSIZE, e_r7->radio_rfpll_refmaster_sparextalsize); + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_R1, e_r7->radio_rfpll_loopfilter_r1); + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C2, e_r7->radio_rfpll_loopfilter_c2); + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C1, e_r7->radio_rfpll_loopfilter_c1); + b43_radio_write(dev, R2057_CP_KPD_IDAC, e_r7->radio_cp_kpd_idac); + b43_radio_write(dev, R2057_RFPLL_MMD0, e_r7->radio_rfpll_mmd0); + b43_radio_write(dev, R2057_RFPLL_MMD1, e_r7->radio_rfpll_mmd1); + b43_radio_write(dev, R2057_VCOBUF_TUNE, e_r7->radio_vcobuf_tune); + b43_radio_write(dev, R2057_LOGEN_MX2G_TUNE, e_r7->radio_logen_mx2g_tune); + b43_radio_write(dev, R2057_LOGEN_MX5G_TUNE, e_r7->radio_logen_mx5g_tune); + b43_radio_write(dev, R2057_LOGEN_INDBUF2G_TUNE, e_r7->radio_logen_indbuf2g_tune); + b43_radio_write(dev, R2057_LOGEN_INDBUF5G_TUNE, e_r7->radio_logen_indbuf5g_tune); + b43_radio_write(dev, R2057_TXMIX2G_TUNE_BOOST_PU_CORE0, e_r7->radio_txmix2g_tune_boost_pu_core0); + b43_radio_write(dev, R2057_PAD2G_TUNE_PUS_CORE0, e_r7->radio_pad2g_tune_pus_core0); + b43_radio_write(dev, R2057_PGA_BOOST_TUNE_CORE0, e_r7->radio_pga_boost_tune_core0); + b43_radio_write(dev, R2057_TXMIX5G_BOOST_TUNE_CORE0, e_r7->radio_txmix5g_boost_tune_core0); + b43_radio_write(dev, R2057_PAD5G_TUNE_MISC_PUS_CORE0, e_r7->radio_pad5g_tune_misc_pus_core0); + b43_radio_write(dev, R2057_LNA2G_TUNE_CORE0, e_r7->radio_lna2g_tune_core0); + b43_radio_write(dev, R2057_LNA5G_TUNE_CORE0, e_r7->radio_lna5g_tune_core0); + b43_radio_write(dev, R2057_TXMIX2G_TUNE_BOOST_PU_CORE1, e_r7->radio_txmix2g_tune_boost_pu_core1); + b43_radio_write(dev, R2057_PAD2G_TUNE_PUS_CORE1, e_r7->radio_pad2g_tune_pus_core1); + b43_radio_write(dev, R2057_PGA_BOOST_TUNE_CORE1, e_r7->radio_pga_boost_tune_core1); + b43_radio_write(dev, R2057_TXMIX5G_BOOST_TUNE_CORE1, e_r7->radio_txmix5g_boost_tune_core1); + b43_radio_write(dev, R2057_PAD5G_TUNE_MISC_PUS_CORE1, e_r7->radio_pad5g_tune_misc_pus_core1); + b43_radio_write(dev, R2057_LNA2G_TUNE_CORE1, e_r7->radio_lna2g_tune_core1); + b43_radio_write(dev, R2057_LNA5G_TUNE_CORE1, e_r7->radio_lna5g_tune_core1); + } +} + +static void b43_radio_2057_setup(struct b43_wldev *dev, + const struct b43_nphy_chantabent_rev7 *tabent_r7, + const struct b43_nphy_chantabent_rev7_2g *tabent_r7_2g) +{ + struct b43_phy *phy = &dev->phy; + + b43_radio_2057_chantab_upload(dev, tabent_r7, tabent_r7_2g); + + switch (phy->radio_rev) { + case 0 ... 4: + case 6: + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_R1, 0x3f); + b43_radio_write(dev, R2057_CP_KPD_IDAC, 0x3f); + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C1, 0x8); + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C2, 0x8); + } else { + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_R1, 0x1f); + b43_radio_write(dev, R2057_CP_KPD_IDAC, 0x3f); + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C1, 0x8); + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C2, 0x8); + } + break; + /* TODO */ + } + + /* TODO */ + + usleep_range(50, 100); + + /* VCO calibration */ + b43_radio_mask(dev, R2057_RFPLL_MISC_EN, ~0x01); + b43_radio_mask(dev, R2057_RFPLL_MISC_CAL_RESETN, ~0x04); + b43_radio_set(dev, R2057_RFPLL_MISC_CAL_RESETN, 0x4); + b43_radio_set(dev, R2057_RFPLL_MISC_EN, 0x01); + usleep_range(300, 600); +} + /* Calibrate resistors in LPF of PLL? * http://bcm-v4.sipsolutions.net/PHY/radio205x_rcal */ @@ -5535,10 +5629,17 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, const struct b43_nphy_channeltab_entry_rev2 *tabent_r2 = NULL; const struct b43_nphy_channeltab_entry_rev3 *tabent_r3 = NULL; + const struct b43_nphy_chantabent_rev7 *tabent_r7 = NULL; + const struct b43_nphy_chantabent_rev7_2g *tabent_r7_2g = NULL; u8 tmp; - if (dev->phy.rev >= 3) { + if (phy->rev >= 7) { + r2057_get_chantabent_rev7(dev, channel->center_freq, + &tabent_r7, &tabent_r7_2g); + if (!tabent_r7 && !tabent_r7_2g) + return -ESRCH; + } else if (phy->rev >= 3) { tabent_r3 = b43_nphy_get_chantabent_rev3(dev, channel->center_freq); if (!tabent_r3) @@ -5560,14 +5661,29 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, ; /* TODO: BMAC BW Set (channel_type) */ #endif - if (channel_type == NL80211_CHAN_HT40PLUS) - b43_phy_set(dev, B43_NPHY_RXCTL, - B43_NPHY_RXCTL_BSELU20); - else if (channel_type == NL80211_CHAN_HT40MINUS) - b43_phy_mask(dev, B43_NPHY_RXCTL, - ~B43_NPHY_RXCTL_BSELU20); + if (channel_type == NL80211_CHAN_HT40PLUS) { + b43_phy_set(dev, B43_NPHY_RXCTL, B43_NPHY_RXCTL_BSELU20); + if (phy->rev >= 7) + b43_phy_set(dev, 0x310, 0x8000); + } else if (channel_type == NL80211_CHAN_HT40MINUS) { + b43_phy_mask(dev, B43_NPHY_RXCTL, ~B43_NPHY_RXCTL_BSELU20); + if (phy->rev >= 7) + b43_phy_mask(dev, 0x310, (u16)~0x8000); + } - if (dev->phy.rev >= 3) { + if (phy->rev >= 7) { + const struct b43_phy_n_sfo_cfg *phy_regs = tabent_r7 ? + &(tabent_r7->phy_regs) : &(tabent_r7_2g->phy_regs); + + if (phy->radio_rev <= 4 || phy->radio_rev == 6) { + tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 2 : 0; + b43_radio_maskset(dev, R2057_TIA_CONFIG_CORE0, ~2, tmp); + b43_radio_maskset(dev, R2057_TIA_CONFIG_CORE1, ~2, tmp); + } + + b43_radio_2057_setup(dev, tabent_r7, tabent_r7_2g); + b43_nphy_channel_setup(dev, phy_regs, channel); + } else if (phy->rev >= 3) { tmp = (channel->band == IEEE80211_BAND_5GHZ) ? 4 : 0; b43_radio_maskset(dev, 0x08, 0xFFFB, tmp); b43_radio_2056_setup(dev, tabent_r3); diff --git a/drivers/net/wireless/b43/radio_2057.c b/drivers/net/wireless/b43/radio_2057.c index 5e49440d4125..df3574545819 100644 --- a/drivers/net/wireless/b43/radio_2057.c +++ b/drivers/net/wireless/b43/radio_2057.c @@ -86,6 +86,7 @@ static u16 r2057_rev7_init[][2] = { { 0x1B7, 0x05 }, { 0x1C2, 0xa0 }, }; +/* TODO: Which devices should use it? static u16 r2057_rev8_init[][2] = { { 0x00, 0x08 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 }, @@ -102,6 +103,47 @@ static u16 r2057_rev8_init[][2] = { { 0x1A6, 0x00 }, { 0x1AA, 0x00 }, { 0x1AB, 0x00 }, { 0x1AC, 0x00 }, { 0x1B7, 0x05 }, { 0x1C2, 0xa0 }, }; +*/ + +#define RADIOREGS7(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \ + r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \ + r20, r21, r22, r23, r24, r25, r26, r27) \ + .radio_vcocal_countval0 = r00, \ + .radio_vcocal_countval1 = r01, \ + .radio_rfpll_refmaster_sparextalsize = r02, \ + .radio_rfpll_loopfilter_r1 = r03, \ + .radio_rfpll_loopfilter_c2 = r04, \ + .radio_rfpll_loopfilter_c1 = r05, \ + .radio_cp_kpd_idac = r06, \ + .radio_rfpll_mmd0 = r07, \ + .radio_rfpll_mmd1 = r08, \ + .radio_vcobuf_tune = r09, \ + .radio_logen_mx2g_tune = r10, \ + .radio_logen_mx5g_tune = r11, \ + .radio_logen_indbuf2g_tune = r12, \ + .radio_logen_indbuf5g_tune = r13, \ + .radio_txmix2g_tune_boost_pu_core0 = r14, \ + .radio_pad2g_tune_pus_core0 = r15, \ + .radio_pga_boost_tune_core0 = r16, \ + .radio_txmix5g_boost_tune_core0 = r17, \ + .radio_pad5g_tune_misc_pus_core0 = r18, \ + .radio_lna2g_tune_core0 = r19, \ + .radio_lna5g_tune_core0 = r20, \ + .radio_txmix2g_tune_boost_pu_core1 = r21, \ + .radio_pad2g_tune_pus_core1 = r22, \ + .radio_pga_boost_tune_core1 = r23, \ + .radio_txmix5g_boost_tune_core1 = r24, \ + .radio_pad5g_tune_misc_pus_core1 = r25, \ + .radio_lna2g_tune_core1 = r26, \ + .radio_lna5g_tune_core1 = r27 + +#define PHYREGS(r0, r1, r2, r3, r4, r5) \ + .phy_regs.phy_bw1a = r0, \ + .phy_regs.phy_bw2 = r1, \ + .phy_regs.phy_bw3 = r2, \ + .phy_regs.phy_bw4 = r3, \ + .phy_regs.phy_bw5 = r4, \ + .phy_regs.phy_bw6 = r5 void r2057_upload_inittabs(struct b43_wldev *dev) { @@ -109,25 +151,26 @@ void r2057_upload_inittabs(struct b43_wldev *dev) u16 *table = NULL; u16 size, i; - if (phy->rev == 7) { + switch (phy->rev) { + case 7: table = r2057_rev4_init[0]; size = ARRAY_SIZE(r2057_rev4_init); - } else if (phy->rev == 8 || phy->rev == 9) { + break; + case 8: if (phy->radio_rev == 5) { - if (phy->radio_rev == 8) { - table = r2057_rev5_init[0]; - size = ARRAY_SIZE(r2057_rev5_init); - } else { - table = r2057_rev5a_init[0]; - size = ARRAY_SIZE(r2057_rev5a_init); - } + table = r2057_rev5_init[0]; + size = ARRAY_SIZE(r2057_rev5_init); } else if (phy->radio_rev == 7) { table = r2057_rev7_init[0]; size = ARRAY_SIZE(r2057_rev7_init); - } else if (phy->radio_rev == 9) { - table = r2057_rev8_init[0]; - size = ARRAY_SIZE(r2057_rev8_init); } + break; + case 9: + if (phy->radio_rev == 5) { + table = r2057_rev5a_init[0]; + size = ARRAY_SIZE(r2057_rev5a_init); + } + break; } B43_WARN_ON(!table); @@ -137,3 +180,40 @@ void r2057_upload_inittabs(struct b43_wldev *dev) b43_radio_write(dev, table[0], table[1]); } } + +void r2057_get_chantabent_rev7(struct b43_wldev *dev, u16 freq, + const struct b43_nphy_chantabent_rev7 **tabent_r7, + const struct b43_nphy_chantabent_rev7_2g **tabent_r7_2g) +{ + struct b43_phy *phy = &dev->phy; + const struct b43_nphy_chantabent_rev7 *e_r7 = NULL; + const struct b43_nphy_chantabent_rev7_2g *e_r7_2g = NULL; + unsigned int len, i; + + *tabent_r7 = NULL; + *tabent_r7_2g = NULL; + + /* TODO */ + switch (phy->rev) { + default: + break; + } + + if (e_r7) { + for (i = 0; i < len; i++, e_r7++) { + if (e_r7->freq == freq) { + *tabent_r7 = e_r7; + return; + } + } + } else if (e_r7_2g) { + for (i = 0; i < len; i++, e_r7_2g++) { + if (e_r7_2g->freq == freq) { + *tabent_r7_2g = e_r7_2g; + return; + } + } + } else { + B43_WARN_ON(1); + } +} diff --git a/drivers/net/wireless/b43/radio_2057.h b/drivers/net/wireless/b43/radio_2057.h index eeebd8fbeb0d..675d1bb64429 100644 --- a/drivers/net/wireless/b43/radio_2057.h +++ b/drivers/net/wireless/b43/radio_2057.h @@ -425,6 +425,72 @@ #define R2057_VCM_MASK 0x7 +struct b43_nphy_chantabent_rev7 { + /* The channel frequency in MHz */ + u16 freq; + /* Radio regs values on channelswitch */ + u8 radio_vcocal_countval0; + u8 radio_vcocal_countval1; + u8 radio_rfpll_refmaster_sparextalsize; + u8 radio_rfpll_loopfilter_r1; + u8 radio_rfpll_loopfilter_c2; + u8 radio_rfpll_loopfilter_c1; + u8 radio_cp_kpd_idac; + u8 radio_rfpll_mmd0; + u8 radio_rfpll_mmd1; + u8 radio_vcobuf_tune; + u8 radio_logen_mx2g_tune; + u8 radio_logen_mx5g_tune; + u8 radio_logen_indbuf2g_tune; + u8 radio_logen_indbuf5g_tune; + u8 radio_txmix2g_tune_boost_pu_core0; + u8 radio_pad2g_tune_pus_core0; + u8 radio_pga_boost_tune_core0; + u8 radio_txmix5g_boost_tune_core0; + u8 radio_pad5g_tune_misc_pus_core0; + u8 radio_lna2g_tune_core0; + u8 radio_lna5g_tune_core0; + u8 radio_txmix2g_tune_boost_pu_core1; + u8 radio_pad2g_tune_pus_core1; + u8 radio_pga_boost_tune_core1; + u8 radio_txmix5g_boost_tune_core1; + u8 radio_pad5g_tune_misc_pus_core1; + u8 radio_lna2g_tune_core1; + u8 radio_lna5g_tune_core1; + /* PHY res values on channelswitch */ + struct b43_phy_n_sfo_cfg phy_regs; +}; + +struct b43_nphy_chantabent_rev7_2g { + /* The channel frequency in MHz */ + u16 freq; + /* Radio regs values on channelswitch */ + u8 radio_vcocal_countval0; + u8 radio_vcocal_countval1; + u8 radio_rfpll_refmaster_sparextalsize; + u8 radio_rfpll_loopfilter_r1; + u8 radio_rfpll_loopfilter_c2; + u8 radio_rfpll_loopfilter_c1; + u8 radio_cp_kpd_idac; + u8 radio_rfpll_mmd0; + u8 radio_rfpll_mmd1; + u8 radio_vcobuf_tune; + u8 radio_logen_mx2g_tune; + u8 radio_logen_indbuf2g_tune; + u8 radio_txmix2g_tune_boost_pu_core0; + u8 radio_pad2g_tune_pus_core0; + u8 radio_lna2g_tune_core0; + u8 radio_txmix2g_tune_boost_pu_core1; + u8 radio_pad2g_tune_pus_core1; + u8 radio_lna2g_tune_core1; + /* PHY regs values on channelswitch */ + struct b43_phy_n_sfo_cfg phy_regs; +}; + void r2057_upload_inittabs(struct b43_wldev *dev); +void r2057_get_chantabent_rev7(struct b43_wldev *dev, u16 freq, + const struct b43_nphy_chantabent_rev7 **tabent_r7, + const struct b43_nphy_chantabent_rev7_2g **tabent_r7_2g); + #endif /* B43_RADIO_2057_H_ */ -- cgit v1.2.3 From 15be8e89cdd999124a2307ffd6dacb895c3b802e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 1 Jul 2014 16:33:57 +0200 Subject: b43: add more bcma cores MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds some cores with 0x2057 radio which will be supported soon as well as core 40 that I missed in the earlier firmware patch. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 3740b76162f9..ca4a19077d7e 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -122,7 +122,11 @@ static const struct bcma_device_id b43_bcma_tbl[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x11, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x18, BCMA_ANY_CLASS), + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1C, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1D, BCMA_ANY_CLASS), + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1E, BCMA_ANY_CLASS), + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x28, BCMA_ANY_CLASS), + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x2A, BCMA_ANY_CLASS), BCMA_CORETABLE_END }; MODULE_DEVICE_TABLE(bcma, b43_bcma_tbl); @@ -2218,6 +2222,10 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) if (phy->type == B43_PHYTYPE_AC) filename = "ucode42"; break; + case 40: + if (phy->type == B43_PHYTYPE_AC) + filename = "ucode40"; + break; case 33: if (phy->type == B43_PHYTYPE_LCN40) filename = "ucode33_lcn40"; @@ -2343,6 +2351,8 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) case B43_PHYTYPE_AC: if (rev == 42) filename = "ac1initvals42"; + else if (rev == 40) + filename = "ac0initvals40"; break; } if (!filename) @@ -2401,6 +2411,8 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) case B43_PHYTYPE_AC: if (rev == 42) filename = "ac1bsinitvals42"; + else if (rev == 40) + filename = "ac0bsinitvals40"; break; } if (!filename) -- cgit v1.2.3 From f2a762d8a97032e58c09c5798832e25268e1c111 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 25 Jun 2014 14:44:52 -0700 Subject: ipv6: Add more debugging around accept-ra logic. This is disabled by default, just like similar debug info already in this module. But, makes it easier to find out why RA is not being accepted when debugging strange behaviour. Signed-off-by: Ben Greear Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 51 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index ca8d4ea48a5d..736c11c6d266 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1070,6 +1070,9 @@ static void ndisc_router_discovery(struct sk_buff *skb) optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) - sizeof(struct ra_msg); + ND_PRINTK(2, info, + "RA: %s, dev: %s\n", + __func__, skb->dev->name); if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { ND_PRINTK(2, warn, "RA: source address is not link-local\n"); return; @@ -1102,13 +1105,21 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } - if (!ipv6_accept_ra(in6_dev)) + if (!ipv6_accept_ra(in6_dev)) { + ND_PRINTK(2, info, + "RA: %s, did not accept ra for dev: %s\n", + __func__, skb->dev->name); goto skip_linkparms; + } #ifdef CONFIG_IPV6_NDISC_NODETYPE /* skip link-specific parameters from interior routers */ - if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) + if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) { + ND_PRINTK(2, info, + "RA: %s, nodetype is NODEFAULT, dev: %s\n", + __func__, skb->dev->name); goto skip_linkparms; + } #endif if (in6_dev->if_flags & IF_RS_SENT) { @@ -1130,11 +1141,20 @@ static void ndisc_router_discovery(struct sk_buff *skb) (ra_msg->icmph.icmp6_addrconf_other ? IF_RA_OTHERCONF : 0); - if (!in6_dev->cnf.accept_ra_defrtr) + if (!in6_dev->cnf.accept_ra_defrtr) { + ND_PRINTK(2, info, + "RA: %s, defrtr is false for dev: %s\n", + __func__, skb->dev->name); goto skip_defrtr; + } - if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0)) + if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, + NULL, 0)) { + ND_PRINTK(2, info, + "RA: %s, chk_addr failed for dev: %s\n", + __func__, skb->dev->name); goto skip_defrtr; + } lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); @@ -1163,8 +1183,10 @@ static void ndisc_router_discovery(struct sk_buff *skb) rt = NULL; } + ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n", + rt, lifetime, skb->dev->name); if (rt == NULL && lifetime) { - ND_PRINTK(3, dbg, "RA: adding default router\n"); + ND_PRINTK(3, info, "RA: adding default router\n"); rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref); if (rt == NULL) { @@ -1260,12 +1282,21 @@ skip_linkparms: NEIGH_UPDATE_F_ISROUTER); } - if (!ipv6_accept_ra(in6_dev)) + if (!ipv6_accept_ra(in6_dev)) { + ND_PRINTK(2, info, + "RA: %s, accept_ra is false for dev: %s\n", + __func__, skb->dev->name); goto out; + } #ifdef CONFIG_IPV6_ROUTE_INFO - if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0)) + if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, + NULL, 0)) { + ND_PRINTK(2, info, + "RA: %s, chk-addr (route info) is false for dev: %s\n", + __func__, skb->dev->name); goto skip_routeinfo; + } if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) { struct nd_opt_hdr *p; @@ -1293,8 +1324,12 @@ skip_routeinfo: #ifdef CONFIG_IPV6_NDISC_NODETYPE /* skip link-specific ndopts from interior routers */ - if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) + if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) { + ND_PRINTK(2, info, + "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n", + __func__, skb->dev->name); goto out; + } #endif if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { -- cgit v1.2.3 From d93331965729850303f6111381c1a4a9e9b8ae5a Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 25 Jun 2014 14:44:53 -0700 Subject: ipv6: Allow accepting RA from local IP addresses. This can be used in virtual networking applications, and may have other uses as well. The option is disabled by default. A specific use case is setting up virtual routers, bridges, and hosts on a single OS without the use of network namespaces or virtual machines. With proper use of ip rules, routing tables, veth interface pairs and/or other virtual interfaces, and applications that can bind to interfaces and/or IP addresses, it is possibly to create one or more virtual routers with multiple hosts attached. The host interfaces can act as IPv6 systems, with radvd running on the ports in the virtual routers. With the option provided in this patch enabled, those hosts can now properly obtain IPv6 addresses from the radvd. Signed-off-by: Ben Greear Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 12 ++++++++++++ include/linux/ipv6.h | 1 + include/uapi/linux/ipv6.h | 1 + include/uapi/linux/sysctl.h | 1 + kernel/sysctl_binary.c | 1 + net/ipv6/addrconf.c | 10 ++++++++++ net/ipv6/ndisc.c | 21 +++++++++++++-------- 7 files changed, 39 insertions(+), 8 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index ab42c95f9985..10e216c6e05e 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1210,6 +1210,18 @@ accept_ra_defrtr - BOOLEAN Functional default: enabled if accept_ra is enabled. disabled if accept_ra is disabled. +accept_ra_from_local - BOOLEAN + Accept RA with source-address that is found on local machine + if the RA is otherwise proper and able to be accepted. + Default is to NOT accept these as it may be an un-intended + network loop. + + Functional default: + enabled if accept_ra_from_local is enabled + on a specific interface. + disabled if accept_ra_from_local is disabled + on a specific interface. + accept_ra_pinfo - BOOLEAN Learn Prefix Information in Router Advertisement. diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index c811300b0b0c..b0f2452f1d58 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -39,6 +39,7 @@ struct ipv6_devconf { #endif __s32 proxy_ndp; __s32 accept_source_route; + __s32 accept_ra_from_local; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD __s32 optimistic_dad; #endif diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h index 593b0e32d956..efa2666f4b8a 100644 --- a/include/uapi/linux/ipv6.h +++ b/include/uapi/linux/ipv6.h @@ -163,6 +163,7 @@ enum { DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL, DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL, DEVCONF_SUPPRESS_FRAG_NDISC, + DEVCONF_ACCEPT_RA_FROM_LOCAL, DEVCONF_MAX }; diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h index 6d6721341f49..43aaba1cc037 100644 --- a/include/uapi/linux/sysctl.h +++ b/include/uapi/linux/sysctl.h @@ -568,6 +568,7 @@ enum { NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22, NET_IPV6_PROXY_NDP=23, NET_IPV6_ACCEPT_SOURCE_ROUTE=25, + NET_IPV6_ACCEPT_RA_FROM_LOCAL=26, __NET_IPV6_MAX }; diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c index 653cbbd9e7ad..e4ba9a5a5ccb 100644 --- a/kernel/sysctl_binary.c +++ b/kernel/sysctl_binary.c @@ -522,6 +522,7 @@ static const struct bin_table bin_net_ipv6_conf_var_table[] = { { CTL_INT, NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN, "accept_ra_rt_info_max_plen" }, { CTL_INT, NET_IPV6_PROXY_NDP, "proxy_ndp" }, { CTL_INT, NET_IPV6_ACCEPT_SOURCE_ROUTE, "accept_source_route" }, + { CTL_INT, NET_IPV6_ACCEPT_RA_FROM_LOCAL, "accept_ra_from_local" }, {} }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 5667b3003af9..358edd2272ac 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -186,6 +186,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { .max_desync_factor = MAX_DESYNC_FACTOR, .max_addresses = IPV6_MAX_ADDRESSES, .accept_ra_defrtr = 1, + .accept_ra_from_local = 0, .accept_ra_pinfo = 1, #ifdef CONFIG_IPV6_ROUTER_PREF .accept_ra_rtr_pref = 1, @@ -222,6 +223,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { .max_desync_factor = MAX_DESYNC_FACTOR, .max_addresses = IPV6_MAX_ADDRESSES, .accept_ra_defrtr = 1, + .accept_ra_from_local = 0, .accept_ra_pinfo = 1, #ifdef CONFIG_IPV6_ROUTER_PREF .accept_ra_rtr_pref = 1, @@ -4321,6 +4323,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify; array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; + array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local; } static inline size_t inet6_ifla6_size(void) @@ -5167,6 +5170,13 @@ static struct addrconf_sysctl_table .mode = 0644, .proc_handler = proc_dointvec }, + { + .procname = "accept_ra_from_local", + .data = &ipv6_devconf.accept_ra_from_local, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, { /* sentinel */ } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 736c11c6d266..a845e3d2057e 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1148,11 +1148,15 @@ static void ndisc_router_discovery(struct sk_buff *skb) goto skip_defrtr; } - if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, - NULL, 0)) { + /* Do not accept RA with source-addr found on local machine unless + * accept_ra_from_local is set to true. + */ + if (!(in6_dev->cnf.accept_ra_from_local || + ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, + NULL, 0))) { ND_PRINTK(2, info, - "RA: %s, chk_addr failed for dev: %s\n", - __func__, skb->dev->name); + "RA from local address detected on dev: %s: default router ignored\n", + skb->dev->name); goto skip_defrtr; } @@ -1290,11 +1294,12 @@ skip_linkparms: } #ifdef CONFIG_IPV6_ROUTE_INFO - if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, - NULL, 0)) { + if (!(in6_dev->cnf.accept_ra_from_local || + ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, + NULL, 0))) { ND_PRINTK(2, info, - "RA: %s, chk-addr (route info) is false for dev: %s\n", - __func__, skb->dev->name); + "RA from local address detected on dev: %s: router info ignored.\n", + skb->dev->name); goto skip_routeinfo; } -- cgit v1.2.3 From 9bf2b8c280b5c02ca8a9e75263bf3ca998fed144 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Thu, 26 Jun 2014 15:56:31 +0800 Subject: net: fix some typos in comment In commit 371121057607e3127e19b3fa094330181b5b031e("net: QDISC_STATE_RUNNING dont need atomic bit ops") the __QDISC_STATE_RUNNING is renamed to __QDISC___STATE_RUNNING, but the old names existing in comment are not replaced with the new name completely. Signed-off-by: Ying Xue Signed-off-by: David S. Miller --- net/core/dev.c | 4 ++-- net/sched/sch_generic.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index a04b12f31e18..de9774119541 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2738,8 +2738,8 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, /* * Heuristic to force contended enqueues to serialize on a * separate lock before trying to get qdisc main lock. - * This permits __QDISC_STATE_RUNNING owner to get the lock more often - * and dequeue packets faster. + * This permits __QDISC___STATE_RUNNING owner to get the lock more + * often and dequeue packets faster. */ contended = qdisc_is_running(q); if (unlikely(contended)) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index e1543b03e39d..fc04fe93c2da 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -108,7 +108,7 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb, /* * Transmit one skb, and handle the return status as required. Holding the - * __QDISC_STATE_RUNNING bit guarantees that only one CPU can execute this + * __QDISC___STATE_RUNNING bit guarantees that only one CPU can execute this * function. * * Returns to the caller: @@ -156,7 +156,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, /* * NOTE: Called under qdisc_lock(q) with locally disabled BH. * - * __QDISC_STATE_RUNNING guarantees only one CPU can process + * __QDISC___STATE_RUNNING guarantees only one CPU can process * this qdisc at a time. qdisc_lock(q) serializes queue accesses for * this queue. * -- cgit v1.2.3 From b0ab2fabb5b91da99c189db02e91ae10bc8355c5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 26 Jun 2014 09:58:25 +0200 Subject: rtnetlink: allow to register ops without ops->setup set So far, it is assumed that ops->setup is filled up. But there might be case that ops might make sense even without ->setup. In that case, forbid to newlink and dellink. This allows to register simple rtnl link ops containing only ->kind. That allows consistent way of passing device kind (either device-kind or slave-kind) to userspace. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- net/core/rtnetlink.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index de9774119541..6e2a2cd82321 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -7091,7 +7091,7 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list) rtnl_lock_unregistering(net_list); list_for_each_entry(net, net_list, exit_list) { for_each_netdev_reverse(net, dev) { - if (dev->rtnl_link_ops) + if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) dev->rtnl_link_ops->dellink(dev, &dev_kill_list); else unregister_netdevice_queue(dev, &dev_kill_list); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 1063996f8317..27acaf7ff6d7 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -299,7 +299,12 @@ int __rtnl_link_register(struct rtnl_link_ops *ops) if (rtnl_link_ops_get(ops->kind)) return -EEXIST; - if (!ops->dellink) + /* The check for setup is here because if ops + * does not have that filled up, it is not possible + * to use the ops for creating device. So do not + * fill up dellink as well. That disables rtnl_dellink. + */ + if (ops->setup && !ops->dellink) ops->dellink = unregister_netdevice_queue; list_add_tail(&ops->list, &link_ops); @@ -1777,7 +1782,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh) return -ENODEV; ops = dev->rtnl_link_ops; - if (!ops) + if (!ops || !ops->dellink) return -EOPNOTSUPP; ops->dellink(dev, &list_kill); @@ -2038,6 +2043,9 @@ replay: return -EOPNOTSUPP; } + if (!ops->setup) + return -EOPNOTSUPP; + if (!ifname[0]) snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); -- cgit v1.2.3 From 5b9e7e1607956e2454ccbd94ccf5631309ade054 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 26 Jun 2014 09:58:26 +0200 Subject: openvswitch: introduce rtnl ops stub This stub now allows userspace to see IFLA_INFO_KIND for ovs master and IFLA_INFO_SLAVE_KIND for slave. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- net/openvswitch/datapath.c | 9 ++++++++- net/openvswitch/vport-internal_dev.c | 16 ++++++++++++++++ net/openvswitch/vport-internal_dev.h | 2 ++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 0d407bca81e3..fe95b6c224a7 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -2054,10 +2054,14 @@ static int __init dp_init(void) pr_info("Open vSwitch switching datapath\n"); - err = ovs_flow_init(); + err = ovs_internal_dev_rtnl_link_register(); if (err) goto error; + err = ovs_flow_init(); + if (err) + goto error_unreg_rtnl_link; + err = ovs_vport_init(); if (err) goto error_flow_exit; @@ -2084,6 +2088,8 @@ error_vport_exit: ovs_vport_exit(); error_flow_exit: ovs_flow_exit(); +error_unreg_rtnl_link: + ovs_internal_dev_rtnl_link_unregister(); error: return err; } @@ -2096,6 +2102,7 @@ static void dp_cleanup(void) rcu_barrier(); ovs_vport_exit(); ovs_flow_exit(); + ovs_internal_dev_rtnl_link_unregister(); } module_init(dp_init); diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index 789af9280e77..295471a66c78 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -26,6 +26,7 @@ #include #include +#include #include "datapath.h" #include "vport-internal_dev.h" @@ -121,6 +122,10 @@ static const struct net_device_ops internal_dev_netdev_ops = { .ndo_get_stats64 = internal_dev_get_stats, }; +static struct rtnl_link_ops internal_dev_link_ops __read_mostly = { + .kind = "openvswitch", +}; + static void do_setup(struct net_device *netdev) { ether_setup(netdev); @@ -131,6 +136,7 @@ static void do_setup(struct net_device *netdev) netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; netdev->destructor = internal_dev_destructor; netdev->ethtool_ops = &internal_dev_ethtool_ops; + netdev->rtnl_link_ops = &internal_dev_link_ops; netdev->tx_queue_len = 0; netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST | @@ -248,3 +254,13 @@ struct vport *ovs_internal_dev_get_vport(struct net_device *netdev) return internal_dev_priv(netdev)->vport; } + +int ovs_internal_dev_rtnl_link_register(void) +{ + return rtnl_link_register(&internal_dev_link_ops); +} + +void ovs_internal_dev_rtnl_link_unregister(void) +{ + rtnl_link_unregister(&internal_dev_link_ops); +} diff --git a/net/openvswitch/vport-internal_dev.h b/net/openvswitch/vport-internal_dev.h index 9a7d30ecc6a2..1b179a190cff 100644 --- a/net/openvswitch/vport-internal_dev.h +++ b/net/openvswitch/vport-internal_dev.h @@ -24,5 +24,7 @@ int ovs_is_internal_dev(const struct net_device *); struct vport *ovs_internal_dev_get_vport(struct net_device *); +int ovs_internal_dev_rtnl_link_register(void); +void ovs_internal_dev_rtnl_link_unregister(void); #endif /* vport-internal_dev.h */ -- cgit v1.2.3 From 9ceb87fceacca86a37f189b84b79797c313b0c03 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Thu, 26 Jun 2014 13:16:27 +0200 Subject: pktgen: document tuning for max NIC performance Using pktgen I'm seeing the ixgbe driver "push-back", due TX ring running full. Thus, the TX ring is artificially limiting pktgen. (Diagnose via "ethtool -S", look for "tx_restart_queue" or "tx_busy" counters.) Using ixgbe, the real reason behind the TX ring running full, is due to TX ring not being cleaned up fast enough. The ixgbe driver combines TX+RX ring cleanups, and the cleanup interval is affected by the ethtool --coalesce setting of parameter "rx-usecs". Do not increase the default NIC TX ring buffer or default cleanup interval. Instead simply document that pktgen needs special NIC tuning for maximum packet per sec performance. Performance results with pktgen with clone_skb=100000. TX ring size 512 (default), adjusting "rx-usecs": (Single CPU performance, E5-2630, ixgbe) - 3935002 pps - rx-usecs: 1 (irqs: 9346) - 5132350 pps - rx-usecs: 10 (irqs: 99157) - 5375111 pps - rx-usecs: 20 (irqs: 50154) - 5454050 pps - rx-usecs: 30 (irqs: 33872) - 5496320 pps - rx-usecs: 40 (irqs: 26197) - 5502510 pps - rx-usecs: 50 (irqs: 21527) TX ring size adjusting (ethtool -G), "rx-usecs==1" (default): - 3935002 pps - tx-size: 512 - 5354401 pps - tx-size: 768 - 5356847 pps - tx-size: 1024 - 5327595 pps - tx-size: 1536 - 5356779 pps - tx-size: 2048 - 5353438 pps - tx-size: 4096 Notice after commit 6f25cd47d (pktgen: fix xmit test for BQL enabled devices) pktgen uses netif_xmit_frozen_or_drv_stopped() and ignores the BQL "stack" pause (QUEUE_STATE_STACK_XOFF) flag. This allow us to put more pressure on the TX ring buffers. It is the ixgbe_maybe_stop_tx() call that stops the transmits, and pktgen respecting this in the call to netif_xmit_frozen_or_drv_stopped(txq). Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- Documentation/networking/pktgen.txt | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt index 0e30c7845b2b..0dffc6e37902 100644 --- a/Documentation/networking/pktgen.txt +++ b/Documentation/networking/pktgen.txt @@ -24,6 +24,34 @@ For monitoring and control pktgen creates: /proc/net/pktgen/ethX +Tuning NIC for max performance +============================== + +The default NIC setting are (likely) not tuned for pktgen's artificial +overload type of benchmarking, as this could hurt the normal use-case. + +Specifically increasing the TX ring buffer in the NIC: + # ethtool -G ethX tx 1024 + +A larger TX ring can improve pktgen's performance, while it can hurt +in the general case, 1) because the TX ring buffer might get larger +than the CPUs L1/L2 cache, 2) because it allow more queueing in the +NIC HW layer (which is bad for bufferbloat). + +One should be careful to conclude, that packets/descriptors in the HW +TX ring cause delay. Drivers usually delay cleaning up the +ring-buffers (for various performance reasons), thus packets stalling +the TX ring, might just be waiting for cleanup. + +This cleanup issues is specifically the case, for the driver ixgbe +(Intel 82599 chip). This driver (ixgbe) combine TX+RX ring cleanups, +and the cleanup interval is affected by the ethtool --coalesce setting +of parameter "rx-usecs". + +For ixgbe use e.g "30" resulting in approx 33K interrupts/sec (1/30*10^6): + # ethtool -C ethX rx-usecs 30 + + Viewing threads =============== /proc/net/pktgen/kpktgend_0 -- cgit v1.2.3 From baac167b706600ebe7158acaeb7c489ae9d0bb8b Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Thu, 26 Jun 2014 13:16:49 +0200 Subject: pktgen: avoid expensive set_current_state() call in loop Avoid calling set_current_state() inside the busy-loop in pktgen_thread_worker(). In case of pkt_dev->delay, then it is still used/enabled in pktgen_xmit() via the spin() call. The set_current_state(TASK_INTERRUPTIBLE) uses a xchg, which implicit is LOCK prefixed. I've measured the asm LOCK operation to take approx 8ns on this E5-2630 CPU. Performance increase corrolate with this measurement. Performance data with CLONE_SKB==100000, rx-usecs=30: (single CPU performance, ixgbe 10Gbit/s, E5-2630) * Prev: 5454050 pps --> 183.35ns (1/5454050*10^9) * Now: 5684009 pps --> 175.93ns (1/5684009*10^9) * Diff: +229959 pps --> -7.42ns Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- net/core/pktgen.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index fc17a9d309ac..b61f553689b6 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3407,10 +3407,10 @@ static int pktgen_thread_worker(void *arg) pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); - set_current_state(TASK_INTERRUPTIBLE); - set_freezable(); + __set_current_state(TASK_RUNNING); + while (!kthread_should_stop()) { pkt_dev = next_to_run(t); @@ -3424,8 +3424,6 @@ static int pktgen_thread_worker(void *arg) continue; } - __set_current_state(TASK_RUNNING); - if (likely(pkt_dev)) { pktgen_xmit(pkt_dev); @@ -3456,9 +3454,8 @@ static int pktgen_thread_worker(void *arg) } try_to_freeze(); - - set_current_state(TASK_INTERRUPTIBLE); } + set_current_state(TASK_INTERRUPTIBLE); pr_debug("%s stopping all device\n", t->tsk->comm); pktgen_stop(t); -- cgit v1.2.3 From 8788370a1d4b1d89efc1aea1b13ea5e5bfe10fde Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Thu, 26 Jun 2014 13:16:59 +0200 Subject: pktgen: RCU-ify "if_list" to remove lock in next_to_run() The if_lock()/if_unlock() in next_to_run() adds a significant overhead, because its called for every packet in busy loop of pktgen_thread_worker(). (Thomas Graf originally pointed me at this lock problem). Removing these two "LOCK" operations should in theory save us approx 16ns (8ns x 2), as illustrated below we do save 16ns when removing the locks and introducing RCU protection. Performance data with CLONE_SKB==100000, TX-size=512, rx-usecs=30: (single CPU performance, ixgbe 10Gbit/s, E5-2630) * Prev : 5684009 pps --> 175.93ns (1/5684009*10^9) * RCU-fix: 6272204 pps --> 159.43ns (1/6272204*10^9) * Diff : +588195 pps --> -16.50ns To understand this RCU patch, I describe the pktgen thread model below. In pktgen there is several kernel threads, but there is only one CPU running each kernel thread. Communication with the kernel threads are done through some thread control flags. This allow the thread to change data structures at a know synchronization point, see main thread func pktgen_thread_worker(). Userspace changes are communicated through proc-file writes. There are three types of changes, general control changes "pgctrl" (func:pgctrl_write), thread changes "kpktgend_X" (func:pktgen_thread_write), and interface config changes "etcX@N" (func:pktgen_if_write). Userspace "pgctrl" and "thread" changes are synchronized via the mutex pktgen_thread_lock, thus only a single userspace instance can run. The mutex is taken while the packet generator is running, by pgctrl "start". Thus e.g. "add_device" cannot be invoked when pktgen is running/started. All "pgctrl" and all "thread" changes, except thread "add_device", communicate via the thread control flags. The main problem is the exception "add_device", that modifies threads "if_list" directly. Fortunately "add_device" cannot be invoked while pktgen is running. But there exists a race between "rem_device_all" and "add_device" (which normally don't occur, because "rem_device_all" waits 125ms before returning). Background'ing "rem_device_all" and running "add_device" immediately allow the race to occur. The race affects the threads (list of devices) "if_list". The if_lock is used for protecting this "if_list". Other readers are given lock-free access to the list under RCU read sections. Note, interface config changes (via proc) can occur while pktgen is running, which worries me a bit. I'm assuming proc_remove() takes appropriate locks, to assure no writers exists after proc_remove() finish. I've been running a script exercising the race condition (leading me to fix the proc_remove order), without any issues. The script also exercises concurrent proc writes, while the interface config is getting removed. Signed-off-by: Jesper Dangaard Brouer Reviewed-by: Florian Westphal Signed-off-by: David S. Miller --- net/core/pktgen.c | 101 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index b61f553689b6..5b05e364b8ae 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -69,8 +69,9 @@ * for running devices in the if_list and sends packets until count is 0 it * also the thread checks the thread->control which is used for inter-process * communication. controlling process "posts" operations to the threads this - * way. The if_lock should be possible to remove when add/rem_device is merged - * into this too. + * way. + * The if_list is RCU protected, and the if_lock remains to protect updating + * of if_list, from "add_device" as it invoked from userspace (via proc write). * * By design there should only be *one* "controlling" process. In practice * multiple write accesses gives unpredictable result. Understood by "write" @@ -208,7 +209,7 @@ #define T_REMDEVALL (1<<2) /* Remove all devs */ #define T_REMDEV (1<<3) /* Remove one dev */ -/* If lock -- can be removed after some work */ +/* If lock -- protects updating of if_list */ #define if_lock(t) spin_lock(&(t->if_lock)); #define if_unlock(t) spin_unlock(&(t->if_lock)); @@ -241,6 +242,7 @@ struct pktgen_dev { struct proc_dir_entry *entry; /* proc file */ struct pktgen_thread *pg_thread;/* the owner */ struct list_head list; /* chaining in the thread's run-queue */ + struct rcu_head rcu; /* freed by RCU */ int running; /* if false, the test will stop */ @@ -1737,14 +1739,14 @@ static int pktgen_thread_show(struct seq_file *seq, void *v) seq_puts(seq, "Running: "); - if_lock(t); - list_for_each_entry(pkt_dev, &t->if_list, list) + rcu_read_lock(); + list_for_each_entry_rcu(pkt_dev, &t->if_list, list) if (pkt_dev->running) seq_printf(seq, "%s ", pkt_dev->odevname); seq_puts(seq, "\nStopped: "); - list_for_each_entry(pkt_dev, &t->if_list, list) + list_for_each_entry_rcu(pkt_dev, &t->if_list, list) if (!pkt_dev->running) seq_printf(seq, "%s ", pkt_dev->odevname); @@ -1753,7 +1755,7 @@ static int pktgen_thread_show(struct seq_file *seq, void *v) else seq_puts(seq, "\nResult: NA\n"); - if_unlock(t); + rcu_read_unlock(); return 0; } @@ -1878,10 +1880,8 @@ static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn, pkt_dev = pktgen_find_dev(t, ifname, exact); if (pkt_dev) { if (remove) { - if_lock(t); pkt_dev->removal_mark = 1; t->control |= T_REMDEV; - if_unlock(t); } break; } @@ -1931,7 +1931,8 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *d list_for_each_entry(t, &pn->pktgen_threads, th_list) { struct pktgen_dev *pkt_dev; - list_for_each_entry(pkt_dev, &t->if_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { if (pkt_dev->odev != dev) continue; @@ -1946,6 +1947,7 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *d dev->name); break; } + rcu_read_unlock(); } } @@ -2997,8 +2999,8 @@ static void pktgen_run(struct pktgen_thread *t) func_enter(); - if_lock(t); - list_for_each_entry(pkt_dev, &t->if_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { /* * setup odev and create initial packet. @@ -3007,18 +3009,18 @@ static void pktgen_run(struct pktgen_thread *t) if (pkt_dev->odev) { pktgen_clear_counters(pkt_dev); - pkt_dev->running = 1; /* Cranke yeself! */ pkt_dev->skb = NULL; pkt_dev->started_at = pkt_dev->next_tx = ktime_get(); set_pkt_overhead(pkt_dev); strcpy(pkt_dev->result, "Starting"); + pkt_dev->running = 1; /* Cranke yeself! */ started++; } else strcpy(pkt_dev->result, "Error starting"); } - if_unlock(t); + rcu_read_unlock(); if (started) t->control &= ~(T_STOP); } @@ -3041,27 +3043,25 @@ static int thread_is_running(const struct pktgen_thread *t) { const struct pktgen_dev *pkt_dev; - list_for_each_entry(pkt_dev, &t->if_list, list) - if (pkt_dev->running) + rcu_read_lock(); + list_for_each_entry_rcu(pkt_dev, &t->if_list, list) + if (pkt_dev->running) { + rcu_read_unlock(); return 1; + } + rcu_read_unlock(); return 0; } static int pktgen_wait_thread_run(struct pktgen_thread *t) { - if_lock(t); - while (thread_is_running(t)) { - if_unlock(t); - msleep_interruptible(100); if (signal_pending(current)) goto signal; - if_lock(t); } - if_unlock(t); return 1; signal: return 0; @@ -3166,10 +3166,10 @@ static int pktgen_stop_device(struct pktgen_dev *pkt_dev) return -EINVAL; } + pkt_dev->running = 0; kfree_skb(pkt_dev->skb); pkt_dev->skb = NULL; pkt_dev->stopped_at = ktime_get(); - pkt_dev->running = 0; show_results(pkt_dev, nr_frags); @@ -3180,9 +3180,8 @@ static struct pktgen_dev *next_to_run(struct pktgen_thread *t) { struct pktgen_dev *pkt_dev, *best = NULL; - if_lock(t); - - list_for_each_entry(pkt_dev, &t->if_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { if (!pkt_dev->running) continue; if (best == NULL) @@ -3190,7 +3189,8 @@ static struct pktgen_dev *next_to_run(struct pktgen_thread *t) else if (ktime_compare(pkt_dev->next_tx, best->next_tx) < 0) best = pkt_dev; } - if_unlock(t); + rcu_read_unlock(); + return best; } @@ -3200,13 +3200,13 @@ static void pktgen_stop(struct pktgen_thread *t) func_enter(); - if_lock(t); + rcu_read_lock(); - list_for_each_entry(pkt_dev, &t->if_list, list) { + list_for_each_entry_rcu(pkt_dev, &t->if_list, list) { pktgen_stop_device(pkt_dev); } - if_unlock(t); + rcu_read_unlock(); } /* @@ -3220,8 +3220,6 @@ static void pktgen_rem_one_if(struct pktgen_thread *t) func_enter(); - if_lock(t); - list_for_each_safe(q, n, &t->if_list) { cur = list_entry(q, struct pktgen_dev, list); @@ -3235,8 +3233,6 @@ static void pktgen_rem_one_if(struct pktgen_thread *t) break; } - - if_unlock(t); } static void pktgen_rem_all_ifs(struct pktgen_thread *t) @@ -3248,8 +3244,6 @@ static void pktgen_rem_all_ifs(struct pktgen_thread *t) /* Remove all devices, free mem */ - if_lock(t); - list_for_each_safe(q, n, &t->if_list) { cur = list_entry(q, struct pktgen_dev, list); @@ -3258,8 +3252,6 @@ static void pktgen_rem_all_ifs(struct pktgen_thread *t) pktgen_remove_device(t, cur); } - - if_unlock(t); } static void pktgen_rem_thread(struct pktgen_thread *t) @@ -3482,8 +3474,8 @@ static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, struct pktgen_dev *p, *pkt_dev = NULL; size_t len = strlen(ifname); - if_lock(t); - list_for_each_entry(p, &t->if_list, list) + rcu_read_lock(); + list_for_each_entry_rcu(p, &t->if_list, list) if (strncmp(p->odevname, ifname, len) == 0) { if (p->odevname[len]) { if (exact || p->odevname[len] != '@') @@ -3493,7 +3485,7 @@ static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, break; } - if_unlock(t); + rcu_read_unlock(); pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev); return pkt_dev; } @@ -3507,6 +3499,12 @@ static int add_dev_to_thread(struct pktgen_thread *t, { int rv = 0; + /* This function cannot be called concurrently, as its called + * under pktgen_thread_lock mutex, but it can run from + * userspace on another CPU than the kthread. The if_lock() + * is used here to sync with concurrent instances of + * _rem_dev_from_if_list() invoked via kthread, which is also + * updating the if_list */ if_lock(t); if (pkt_dev->pg_thread) { @@ -3515,9 +3513,9 @@ static int add_dev_to_thread(struct pktgen_thread *t, goto out; } - list_add(&pkt_dev->list, &t->if_list); - pkt_dev->pg_thread = t; pkt_dev->running = 0; + pkt_dev->pg_thread = t; + list_add_rcu(&pkt_dev->list, &t->if_list); out: if_unlock(t); @@ -3672,11 +3670,13 @@ static void _rem_dev_from_if_list(struct pktgen_thread *t, struct list_head *q, *n; struct pktgen_dev *p; + if_lock(t); list_for_each_safe(q, n, &t->if_list) { p = list_entry(q, struct pktgen_dev, list); if (p == pkt_dev) - list_del(&p->list); + list_del_rcu(&p->list); } + if_unlock(t); } static int pktgen_remove_device(struct pktgen_thread *t, @@ -3696,20 +3696,22 @@ static int pktgen_remove_device(struct pktgen_thread *t, pkt_dev->odev = NULL; } - /* And update the thread if_list */ - - _rem_dev_from_if_list(t, pkt_dev); - + /* Remove proc before if_list entry, because add_device uses + * list to determine if interface already exist, avoid race + * with proc_create_data() */ if (pkt_dev->entry) proc_remove(pkt_dev->entry); + /* And update the thread if_list */ + _rem_dev_from_if_list(t, pkt_dev); + #ifdef CONFIG_XFRM free_SAs(pkt_dev); #endif vfree(pkt_dev->flows); if (pkt_dev->page) put_page(pkt_dev->page); - kfree(pkt_dev); + kfree_rcu(pkt_dev, rcu); return 0; } @@ -3809,6 +3811,7 @@ static void __exit pg_cleanup(void) { unregister_netdevice_notifier(&pktgen_notifier_block); unregister_pernet_subsys(&pg_net_ops); + /* Don't need rcu_barrier() due to use of kfree_rcu() */ } module_init(pg_init); -- cgit v1.2.3 From 6495d15a7cb1f3328dc38557c48afb754f900c14 Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Thu, 26 Jun 2014 14:31:04 +0300 Subject: bnx2x: VF can report link speed Until now VFs were oblvious to the actual configured link parameters. This patch does 2 things: 1. It enables a PF to inform its VF using the bulletin board of the link configured, and allows the VF to present that information. 2. It adds support of `ndo_set_vf_link_state', allowing the hypervisor to set the VF link state. Signed-off-by: Dmitry Kravkov Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 3 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 55 +++-- .../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 44 +++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 9 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 261 ++++++++++++++++----- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h | 35 ++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c | 30 ++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h | 17 +- 8 files changed, 366 insertions(+), 88 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 4cab09d3f807..faf262a0d6c4 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1482,6 +1482,7 @@ struct bnx2x { union pf_vf_bulletin *pf2vf_bulletin; dma_addr_t pf2vf_bulletin_mapping; + union pf_vf_bulletin shadow_bulletin; struct pf_vf_bulletin_content old_bulletin; u16 requested_nr_virtfn; @@ -1928,6 +1929,8 @@ struct bnx2x { struct semaphore stats_sema; u8 phys_port_id[ETH_ALEN]; + + struct bnx2x_link_report_data vf_link_vars; }; /* Tx queues may be less or equal to Rx queues */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 47c5814114e1..cb15e3ac03c4 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1185,29 +1185,38 @@ u16 bnx2x_get_mf_speed(struct bnx2x *bp) static void bnx2x_fill_report_data(struct bnx2x *bp, struct bnx2x_link_report_data *data) { - u16 line_speed = bnx2x_get_mf_speed(bp); - memset(data, 0, sizeof(*data)); - /* Fill the report data: effective line speed */ - data->line_speed = line_speed; - - /* Link is down */ - if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS)) - __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, - &data->link_report_flags); - - /* Full DUPLEX */ - if (bp->link_vars.duplex == DUPLEX_FULL) - __set_bit(BNX2X_LINK_REPORT_FD, &data->link_report_flags); - - /* Rx Flow Control is ON */ - if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) - __set_bit(BNX2X_LINK_REPORT_RX_FC_ON, &data->link_report_flags); - - /* Tx Flow Control is ON */ - if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) - __set_bit(BNX2X_LINK_REPORT_TX_FC_ON, &data->link_report_flags); + if (IS_PF(bp)) { + /* Fill the report data: effective line speed */ + data->line_speed = bnx2x_get_mf_speed(bp); + + /* Link is down */ + if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS)) + __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &data->link_report_flags); + + if (!BNX2X_NUM_ETH_QUEUES(bp)) + __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &data->link_report_flags); + + /* Full DUPLEX */ + if (bp->link_vars.duplex == DUPLEX_FULL) + __set_bit(BNX2X_LINK_REPORT_FD, + &data->link_report_flags); + + /* Rx Flow Control is ON */ + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) + __set_bit(BNX2X_LINK_REPORT_RX_FC_ON, + &data->link_report_flags); + + /* Tx Flow Control is ON */ + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) + __set_bit(BNX2X_LINK_REPORT_TX_FC_ON, + &data->link_report_flags); + } else { /* VF */ + *data = bp->vf_link_vars; + } } /** @@ -1261,6 +1270,10 @@ void __bnx2x_link_report(struct bnx2x *bp) */ memcpy(&bp->last_reported_link, &cur_data, sizeof(cur_data)); + /* propagate status to VFs */ + if (IS_PF(bp)) + bnx2x_iov_link_update(bp); + if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN, &cur_data.link_report_flags)) { netif_carrier_off(bp->dev); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index bd0600cf7266..08ea91cab738 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -216,6 +216,43 @@ static int bnx2x_get_port_type(struct bnx2x *bp) return port_type; } +static int bnx2x_get_vf_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (bp->state == BNX2X_STATE_OPEN) { + if (test_bit(BNX2X_LINK_REPORT_FD, + &bp->vf_link_vars.link_report_flags)) + cmd->duplex = DUPLEX_FULL; + else + cmd->duplex = DUPLEX_HALF; + + ethtool_cmd_speed_set(cmd, bp->vf_link_vars.line_speed); + } else { + cmd->duplex = DUPLEX_UNKNOWN; + ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN); + } + + cmd->port = PORT_OTHER; + cmd->phy_address = 0; + cmd->transceiver = XCVR_INTERNAL; + cmd->autoneg = AUTONEG_DISABLE; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + + DP(BNX2X_MSG_ETHTOOL, "ethtool_cmd: cmd %d\n" + " supported 0x%x advertising 0x%x speed %u\n" + " duplex %d port %d phy_address %d transceiver %d\n" + " autoneg %d maxtxpkt %d maxrxpkt %d\n", + cmd->cmd, cmd->supported, cmd->advertising, + ethtool_cmd_speed(cmd), + cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, + cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); + + return 0; +} + static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct bnx2x *bp = netdev_priv(dev); @@ -1110,6 +1147,10 @@ static u32 bnx2x_get_link(struct net_device *dev) if (bp->flags & MF_FUNC_DIS || (bp->state != BNX2X_STATE_OPEN)) return 0; + if (IS_VF(bp)) + return !test_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &bp->vf_link_vars.link_report_flags); + return bp->link_vars.link_up; } @@ -3484,8 +3525,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = { }; static const struct ethtool_ops bnx2x_vf_ethtool_ops = { - .get_settings = bnx2x_get_settings, - .set_settings = bnx2x_set_settings, + .get_settings = bnx2x_get_vf_settings, .get_drvinfo = bnx2x_get_drvinfo, .get_msglevel = bnx2x_get_msglevel, .set_msglevel = bnx2x_set_msglevel, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 2887034523e0..6af9e3c046a0 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -2698,6 +2698,14 @@ void bnx2x__link_status_update(struct bnx2x *bp) bp->link_vars.duplex = DUPLEX_FULL; bp->link_vars.flow_ctrl = BNX2X_FLOW_CTRL_NONE; __bnx2x_link_report(bp); + + bnx2x_sample_bulletin(bp); + + /* if bulletin board did not have an update for link status + * __bnx2x_link_report will report current status + * but it will NOT duplicate report in case of already reported + * during sampling bulletin board. + */ bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP); } } @@ -12424,6 +12432,7 @@ static const struct net_device_ops bnx2x_netdev_ops = { .ndo_busy_poll = bnx2x_low_latency_recv, #endif .ndo_get_phys_port_id = bnx2x_get_phys_port_id, + .ndo_set_vf_link_state = bnx2x_set_vf_link_state, }; static int bnx2x_set_coherency_mask(struct bnx2x *bp) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index c9988e3bfe2b..662310c5f4e9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -24,6 +24,11 @@ #include #include +static int bnx2x_vf_op_prep(struct bnx2x *bp, int vfidx, + struct bnx2x_virtf **vf, + struct pf_vf_bulletin_content **bulletin, + bool test_queue); + /* General service functions */ static void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid, u16 pf_id) @@ -1327,6 +1332,8 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param, /* Prepare the VFs event synchronization mechanism */ mutex_init(&bp->vfdb->event_mutex); + mutex_init(&bp->vfdb->bulletin_mutex); + return 0; failed: DP(BNX2X_MSG_IOV, "Failed err=%d\n", err); @@ -1472,6 +1479,107 @@ static void bnx2x_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf, vf->abs_vfid, q->sp_obj.func_id, q->cid); } +static int bnx2x_max_speed_cap(struct bnx2x *bp) +{ + u32 supported = bp->port.supported[bnx2x_get_link_cfg_idx(bp)]; + + if (supported & + (SUPPORTED_20000baseMLD2_Full | SUPPORTED_20000baseKR2_Full)) + return 20000; + + return 10000; /* assume lowest supported speed is 10G */ +} + +int bnx2x_iov_link_update_vf(struct bnx2x *bp, int idx) +{ + struct bnx2x_link_report_data *state = &bp->last_reported_link; + struct pf_vf_bulletin_content *bulletin; + struct bnx2x_virtf *vf; + bool update = true; + int rc = 0; + + /* sanity and init */ + rc = bnx2x_vf_op_prep(bp, idx, &vf, &bulletin, false); + if (rc) + return rc; + + mutex_lock(&bp->vfdb->bulletin_mutex); + + if (vf->link_cfg == IFLA_VF_LINK_STATE_AUTO) { + bulletin->valid_bitmap |= 1 << LINK_VALID; + + bulletin->link_speed = state->line_speed; + bulletin->link_flags = 0; + if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &state->link_report_flags)) + bulletin->link_flags |= VFPF_LINK_REPORT_LINK_DOWN; + if (test_bit(BNX2X_LINK_REPORT_FD, + &state->link_report_flags)) + bulletin->link_flags |= VFPF_LINK_REPORT_FULL_DUPLEX; + if (test_bit(BNX2X_LINK_REPORT_RX_FC_ON, + &state->link_report_flags)) + bulletin->link_flags |= VFPF_LINK_REPORT_RX_FC_ON; + if (test_bit(BNX2X_LINK_REPORT_TX_FC_ON, + &state->link_report_flags)) + bulletin->link_flags |= VFPF_LINK_REPORT_TX_FC_ON; + } else if (vf->link_cfg == IFLA_VF_LINK_STATE_DISABLE && + !(bulletin->link_flags & VFPF_LINK_REPORT_LINK_DOWN)) { + bulletin->valid_bitmap |= 1 << LINK_VALID; + bulletin->link_flags |= VFPF_LINK_REPORT_LINK_DOWN; + } else if (vf->link_cfg == IFLA_VF_LINK_STATE_ENABLE && + (bulletin->link_flags & VFPF_LINK_REPORT_LINK_DOWN)) { + bulletin->valid_bitmap |= 1 << LINK_VALID; + bulletin->link_speed = bnx2x_max_speed_cap(bp); + bulletin->link_flags &= ~VFPF_LINK_REPORT_LINK_DOWN; + } else { + update = false; + } + + if (update) { + DP(NETIF_MSG_LINK | BNX2X_MSG_IOV, + "vf %d mode %u speed %d flags %x\n", idx, + vf->link_cfg, bulletin->link_speed, bulletin->link_flags); + + /* Post update on VF's bulletin board */ + rc = bnx2x_post_vf_bulletin(bp, idx); + if (rc) { + BNX2X_ERR("failed to update VF[%d] bulletin\n", idx); + goto out; + } + } + +out: + mutex_unlock(&bp->vfdb->bulletin_mutex); + return rc; +} + +int bnx2x_set_vf_link_state(struct net_device *dev, int idx, int link_state) +{ + struct bnx2x *bp = netdev_priv(dev); + struct bnx2x_virtf *vf = BP_VF(bp, idx); + + if (!vf) + return -EINVAL; + + if (vf->link_cfg == link_state) + return 0; /* nothing todo */ + + vf->link_cfg = link_state; + + return bnx2x_iov_link_update_vf(bp, idx); +} + +void bnx2x_iov_link_update(struct bnx2x *bp) +{ + int vfid; + + if (!IS_SRIOV(bp)) + return; + + for_each_vf(bp, vfid) + bnx2x_iov_link_update_vf(bp, vfid); +} + /* called by bnx2x_nic_load */ int bnx2x_iov_nic_init(struct bnx2x *bp) { @@ -2509,22 +2617,23 @@ void bnx2x_disable_sriov(struct bnx2x *bp) pci_disable_sriov(bp->pdev); } -static int bnx2x_vf_ndo_prep(struct bnx2x *bp, int vfidx, - struct bnx2x_virtf **vf, - struct pf_vf_bulletin_content **bulletin) +static int bnx2x_vf_op_prep(struct bnx2x *bp, int vfidx, + struct bnx2x_virtf **vf, + struct pf_vf_bulletin_content **bulletin, + bool test_queue) { if (bp->state != BNX2X_STATE_OPEN) { - BNX2X_ERR("vf ndo called though PF is down\n"); + BNX2X_ERR("PF is down - can't utilize iov-related functionality\n"); return -EINVAL; } if (!IS_SRIOV(bp)) { - BNX2X_ERR("vf ndo called though sriov is disabled\n"); + BNX2X_ERR("sriov is disabled - can't utilize iov-realted functionality\n"); return -EINVAL; } if (vfidx >= BNX2X_NR_VIRTFN(bp)) { - BNX2X_ERR("vf ndo called for uninitialized VF. vfidx was %d BNX2X_NR_VIRTFN was %d\n", + BNX2X_ERR("VF is uninitialized - can't utilize iov-related functionality. vfidx was %d BNX2X_NR_VIRTFN was %d\n", vfidx, BNX2X_NR_VIRTFN(bp)); return -EINVAL; } @@ -2534,19 +2643,18 @@ static int bnx2x_vf_ndo_prep(struct bnx2x *bp, int vfidx, *bulletin = BP_VF_BULLETIN(bp, vfidx); if (!*vf) { - BNX2X_ERR("vf ndo called but vf struct is null. vfidx was %d\n", - vfidx); + BNX2X_ERR("Unable to get VF structure for vfidx %d\n", vfidx); return -EINVAL; } - if (!(*vf)->vfqs) { - BNX2X_ERR("vf ndo called but vfqs struct is null. Was ndo invoked before dynamically enabling SR-IOV? vfidx was %d\n", + if (test_queue && !(*vf)->vfqs) { + BNX2X_ERR("vfqs struct is null. Was this invoked before dynamically enabling SR-IOV? vfidx was %d\n", vfidx); return -EINVAL; } if (!*bulletin) { - BNX2X_ERR("vf ndo called but Bulletin Board struct is null. vfidx was %d\n", + BNX2X_ERR("Bulletin Board struct is null for vfidx %d\n", vfidx); return -EINVAL; } @@ -2565,9 +2673,10 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx, int rc; /* sanity and init */ - rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin); + rc = bnx2x_vf_op_prep(bp, vfidx, &vf, &bulletin, true); if (rc) return rc; + mac_obj = &bnx2x_leading_vfq(vf, mac_obj); vlan_obj = &bnx2x_leading_vfq(vf, vlan_obj); if (!mac_obj || !vlan_obj) { @@ -2590,6 +2699,7 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx, VLAN_HLEN); } } else { + mutex_lock(&bp->vfdb->bulletin_mutex); /* mac */ if (bulletin->valid_bitmap & (1 << MAC_ADDR_VALID)) /* mac configured by ndo so its in bulletin board */ @@ -2605,6 +2715,8 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx, else /* function has not been loaded yet. Show vlans as 0s */ memset(&ivi->vlan, 0, VLAN_HLEN); + + mutex_unlock(&bp->vfdb->bulletin_mutex); } return 0; @@ -2634,15 +2746,18 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac) struct bnx2x_virtf *vf = NULL; struct pf_vf_bulletin_content *bulletin = NULL; - /* sanity and init */ - rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin); - if (rc) - return rc; if (!is_valid_ether_addr(mac)) { BNX2X_ERR("mac address invalid\n"); return -EINVAL; } + /* sanity and init */ + rc = bnx2x_vf_op_prep(bp, vfidx, &vf, &bulletin, true); + if (rc) + return rc; + + mutex_lock(&bp->vfdb->bulletin_mutex); + /* update PF's copy of the VF's bulletin. Will no longer accept mac * configuration requests from vf unless match this mac */ @@ -2651,6 +2766,10 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac) /* Post update on VF's bulletin board */ rc = bnx2x_post_vf_bulletin(bp, vfidx); + + /* release lock before checking return code */ + mutex_unlock(&bp->vfdb->bulletin_mutex); + if (rc) { BNX2X_ERR("failed to update VF[%d] bulletin\n", vfidx); return rc; @@ -2715,11 +2834,6 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) unsigned long accept_flags; int rc; - /* sanity and init */ - rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin); - if (rc) - return rc; - if (vlan > 4095) { BNX2X_ERR("illegal vlan value %d\n", vlan); return -EINVAL; @@ -2728,18 +2842,27 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) DP(BNX2X_MSG_IOV, "configuring VF %d with VLAN %d qos %d\n", vfidx, vlan, 0); + /* sanity and init */ + rc = bnx2x_vf_op_prep(bp, vfidx, &vf, &bulletin, true); + if (rc) + return rc; + /* update PF's copy of the VF's bulletin. No point in posting the vlan * to the VF since it doesn't have anything to do with it. But it useful * to store it here in case the VF is not up yet and we can only * configure the vlan later when it does. Treat vlan id 0 as remove the * Host tag. */ + mutex_lock(&bp->vfdb->bulletin_mutex); + if (vlan > 0) bulletin->valid_bitmap |= 1 << VLAN_VALID; else bulletin->valid_bitmap &= ~(1 << VLAN_VALID); bulletin->vlan = vlan; + mutex_unlock(&bp->vfdb->bulletin_mutex); + /* is vf initialized and queue set up? */ if (vf->state != VF_ENABLED || bnx2x_get_q_logical_state(bp, &bnx2x_leading_vfq(vf, sp_obj)) != @@ -2849,10 +2972,9 @@ out: * entire bulletin board excluding the crc field itself. Use the length field * as the Bulletin Board was posted by a PF with possibly a different version * from the vf which will sample it. Therefore, the length is computed by the - * PF and the used blindly by the VF. + * PF and then used blindly by the VF. */ -u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp, - struct pf_vf_bulletin_content *bulletin) +u32 bnx2x_crc_vf_bulletin(struct pf_vf_bulletin_content *bulletin) { return crc32(BULLETIN_CRC_SEED, ((u8 *)bulletin) + sizeof(bulletin->crc), @@ -2862,47 +2984,74 @@ u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp, /* Check for new posts on the bulletin board */ enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp) { - struct pf_vf_bulletin_content bulletin = bp->pf2vf_bulletin->content; + struct pf_vf_bulletin_content *bulletin; int attempts; - /* bulletin board hasn't changed since last sample */ - if (bp->old_bulletin.version == bulletin.version) - return PFVF_BULLETIN_UNCHANGED; + /* sampling structure in mid post may result with corrupted data + * validate crc to ensure coherency. + */ + for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) { + u32 crc; - /* validate crc of new bulletin board */ - if (bp->old_bulletin.version != bp->pf2vf_bulletin->content.version) { - /* sampling structure in mid post may result with corrupted data - * validate crc to ensure coherency. - */ - for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) { - bulletin = bp->pf2vf_bulletin->content; - if (bulletin.crc == bnx2x_crc_vf_bulletin(bp, - &bulletin)) - break; - BNX2X_ERR("bad crc on bulletin board. Contained %x computed %x\n", - bulletin.crc, - bnx2x_crc_vf_bulletin(bp, &bulletin)); - } - if (attempts >= BULLETIN_ATTEMPTS) { - BNX2X_ERR("pf to vf bulletin board crc was wrong %d consecutive times. Aborting\n", - attempts); - return PFVF_BULLETIN_CRC_ERR; - } + /* sample the bulletin board */ + memcpy(&bp->shadow_bulletin, bp->pf2vf_bulletin, + sizeof(union pf_vf_bulletin)); + + crc = bnx2x_crc_vf_bulletin(&bp->shadow_bulletin.content); + + if (bp->shadow_bulletin.content.crc == crc) + break; + + BNX2X_ERR("bad crc on bulletin board. Contained %x computed %x\n", + bp->shadow_bulletin.content.crc, crc); + } + + if (attempts >= BULLETIN_ATTEMPTS) { + BNX2X_ERR("pf to vf bulletin board crc was wrong %d consecutive times. Aborting\n", + attempts); + return PFVF_BULLETIN_CRC_ERR; } + bulletin = &bp->shadow_bulletin.content; + + /* bulletin board hasn't changed since last sample */ + if (bp->old_bulletin.version == bulletin->version) + return PFVF_BULLETIN_UNCHANGED; /* the mac address in bulletin board is valid and is new */ - if (bulletin.valid_bitmap & 1 << MAC_ADDR_VALID && - !ether_addr_equal(bulletin.mac, bp->old_bulletin.mac)) { + if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID && + !ether_addr_equal(bulletin->mac, bp->old_bulletin.mac)) { /* update new mac to net device */ - memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN); + memcpy(bp->dev->dev_addr, bulletin->mac, ETH_ALEN); + } + + if (bulletin->valid_bitmap & (1 << LINK_VALID)) { + DP(BNX2X_MSG_IOV, "link update speed %d flags %x\n", + bulletin->link_speed, bulletin->link_flags); + + bp->vf_link_vars.line_speed = bulletin->link_speed; + bp->vf_link_vars.link_report_flags = 0; + /* Link is down */ + if (bulletin->link_flags & VFPF_LINK_REPORT_LINK_DOWN) + __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &bp->vf_link_vars.link_report_flags); + /* Full DUPLEX */ + if (bulletin->link_flags & VFPF_LINK_REPORT_FULL_DUPLEX) + __set_bit(BNX2X_LINK_REPORT_FD, + &bp->vf_link_vars.link_report_flags); + /* Rx Flow Control is ON */ + if (bulletin->link_flags & VFPF_LINK_REPORT_RX_FC_ON) + __set_bit(BNX2X_LINK_REPORT_RX_FC_ON, + &bp->vf_link_vars.link_report_flags); + /* Tx Flow Control is ON */ + if (bulletin->link_flags & VFPF_LINK_REPORT_TX_FC_ON) + __set_bit(BNX2X_LINK_REPORT_TX_FC_ON, + &bp->vf_link_vars.link_report_flags); + __bnx2x_link_report(bp); } - /* the vlan in bulletin board is valid and is new */ - if (bulletin.valid_bitmap & 1 << VLAN_VALID) - memcpy(&bulletin.vlan, &bp->old_bulletin.vlan, VLAN_HLEN); - /* copy new bulletin board to bp */ - bp->old_bulletin = bulletin; + memcpy(&bp->old_bulletin, bulletin, + sizeof(struct pf_vf_bulletin_content)); return PFVF_BULLETIN_UPDATED; } @@ -2947,6 +3096,8 @@ int bnx2x_vf_pci_alloc(struct bnx2x *bp) if (!bp->pf2vf_bulletin) goto alloc_mem_err; + bnx2x_vf_bulletin_finalize(&bp->pf2vf_bulletin->content, true); + return 0; alloc_mem_err: diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h index 96c575e147a5..ca1055f3d8af 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h @@ -126,7 +126,11 @@ struct bnx2x_virtf { #define VF_CACHE_LINE 0x0010 #define VF_CFG_VLAN 0x0020 #define VF_CFG_STATS_COALESCE 0x0040 - +#define VF_CFG_EXT_BULLETIN 0x0080 + u8 link_cfg; /* IFLA_VF_LINK_STATE_AUTO + * IFLA_VF_LINK_STATE_ENABLE + * IFLA_VF_LINK_STATE_DISABLE + */ u8 state; #define VF_FREE 0 /* VF ready to be acquired holds no resc */ #define VF_ACQUIRED 1 /* VF acquired, but not initialized */ @@ -295,22 +299,22 @@ struct bnx2x_vfdb { #define BP_VFDB(bp) ((bp)->vfdb) /* vf array */ struct bnx2x_virtf *vfs; -#define BP_VF(bp, idx) (&((bp)->vfdb->vfs[(idx)])) -#define bnx2x_vf(bp, idx, var) ((bp)->vfdb->vfs[(idx)].var) +#define BP_VF(bp, idx) (&((bp)->vfdb->vfs[idx])) +#define bnx2x_vf(bp, idx, var) ((bp)->vfdb->vfs[idx].var) /* queue array - for all vfs */ struct bnx2x_vf_queue *vfqs; /* vf HW contexts */ struct hw_dma context[BNX2X_VF_CIDS/ILT_PAGE_CIDS]; -#define BP_VF_CXT_PAGE(bp, i) (&(bp)->vfdb->context[(i)]) +#define BP_VF_CXT_PAGE(bp, i) (&(bp)->vfdb->context[i]) /* SR-IOV information */ struct bnx2x_sriov sriov; struct hw_dma mbx_dma; #define BP_VF_MBX_DMA(bp) (&((bp)->vfdb->mbx_dma)) struct bnx2x_vf_mbx mbxs[BNX2X_MAX_NUM_OF_VFS]; -#define BP_VF_MBX(bp, vfid) (&((bp)->vfdb->mbxs[(vfid)])) +#define BP_VF_MBX(bp, vfid) (&((bp)->vfdb->mbxs[vfid])) struct hw_dma bulletin_dma; #define BP_VF_BULLETIN_DMA(bp) (&((bp)->vfdb->bulletin_dma)) @@ -336,6 +340,9 @@ struct bnx2x_vfdb { /* sp_rtnl synchronization */ struct mutex event_mutex; u64 event_occur; + + /* bulletin board update synchronization */ + struct mutex bulletin_mutex; }; /* queue access */ @@ -467,9 +474,10 @@ void bnx2x_vf_handle_flr_event(struct bnx2x *bp); bool bnx2x_tlv_supported(u16 tlvtype); -u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp, - struct pf_vf_bulletin_content *bulletin); +u32 bnx2x_crc_vf_bulletin(struct pf_vf_bulletin_content *bulletin); int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf); +void bnx2x_vf_bulletin_finalize(struct pf_vf_bulletin_content *bulletin, + bool support_long); enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp); @@ -520,6 +528,11 @@ void bnx2x_iov_task(struct work_struct *work); void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag); +void bnx2x_iov_link_update(struct bnx2x *bp); +int bnx2x_iov_link_update_vf(struct bnx2x *bp, int idx); + +int bnx2x_set_vf_link_state(struct net_device *dev, int vf, int link_state); + #else /* CONFIG_BNX2X_SRIOV */ static inline void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid, @@ -579,6 +592,14 @@ static inline void bnx2x_iov_channel_down(struct bnx2x *bp) {} static inline void bnx2x_iov_task(struct work_struct *work) {} static inline void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag) {} +static inline void bnx2x_iov_link_update(struct bnx2x *bp) {} +static inline int bnx2x_iov_link_update_vf(struct bnx2x *bp, int idx) {return 0; } + +static inline int bnx2x_set_vf_link_state(struct net_device *dev, int vf, + int link_state) {return 0; } +struct pf_vf_bulletin_content; +static inline void bnx2x_vf_bulletin_finalize(struct pf_vf_bulletin_content *bulletin, + bool support_long) {} #endif /* CONFIG_BNX2X_SRIOV */ #endif /* bnx2x_sriov.h */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index d712d0ddd719..f35077366340 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -251,6 +251,9 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count) bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_PHYS_PORT_ID, sizeof(struct channel_tlv)); + /* Bulletin support for bulletin board with length > legacy length */ + req->vfdev_info.caps |= VF_CAP_SUPPORT_EXT_BULLETIN; + /* add list termination tlv */ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length + sizeof(struct channel_tlv), @@ -1252,6 +1255,13 @@ static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf, /* store address of vf's bulletin board */ vf->bulletin_map = acquire->bulletin_addr; + if (acquire->vfdev_info.caps & VF_CAP_SUPPORT_EXT_BULLETIN) { + DP(BNX2X_MSG_IOV, "VF[%d] supports long bulletin boards\n", + vf->abs_vfid); + vf->cfg_flags |= VF_CFG_EXT_BULLETIN; + } else { + vf->cfg_flags &= ~VF_CFG_EXT_BULLETIN; + } /* response */ bnx2x_vf_mbx_acquire_resp(bp, vf, mbx, rc); @@ -1273,6 +1283,10 @@ static void bnx2x_vf_mbx_init_vf(struct bnx2x *bp, struct bnx2x_virtf *vf, if (init->flags & VFPF_INIT_FLG_STATS_COALESCE) vf->cfg_flags |= VF_CFG_STATS_COALESCE; + /* Update VF's view of link state */ + if (vf->cfg_flags & VF_CFG_EXT_BULLETIN) + bnx2x_iov_link_update_vf(bp, vf->index); + /* response */ bnx2x_vf_mbx_resp(bp, vf, rc); } @@ -2007,6 +2021,17 @@ void bnx2x_vf_mbx(struct bnx2x *bp) } } +void bnx2x_vf_bulletin_finalize(struct pf_vf_bulletin_content *bulletin, + bool support_long) +{ + /* Older VFs contain a bug where they can't check CRC for bulletin + * boards of length greater than legacy size. + */ + bulletin->length = support_long ? BULLETIN_CONTENT_SIZE : + BULLETIN_CONTENT_LEGACY_SIZE; + bulletin->crc = bnx2x_crc_vf_bulletin(bulletin); +} + /* propagate local bulletin board to vf */ int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf) { @@ -2023,8 +2048,9 @@ int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf) /* increment bulletin board version and compute crc */ bulletin->version++; - bulletin->length = BULLETIN_CONTENT_SIZE; - bulletin->crc = bnx2x_crc_vf_bulletin(bp, bulletin); + bnx2x_vf_bulletin_finalize(bulletin, + (bnx2x_vf(bp, vf, cfg_flags) & + VF_CFG_EXT_BULLETIN) ? true : false); /* propagate bulletin board via dmae to vm memory */ rc = bnx2x_copy32_vf_dmae(bp, false, pf_addr, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h index e21e706762c9..ace4d7b0529f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h @@ -65,6 +65,7 @@ struct hw_sb_info { #define VFPF_RX_MASK_ACCEPT_ALL_MULTICAST 0x00000008 #define VFPF_RX_MASK_ACCEPT_BROADCAST 0x00000010 #define BULLETIN_CONTENT_SIZE (sizeof(struct pf_vf_bulletin_content)) +#define BULLETIN_CONTENT_LEGACY_SIZE (32) #define BULLETIN_ATTEMPTS 5 /* crc failures before throwing towel */ #define BULLETIN_CRC_SEED 0 @@ -117,7 +118,9 @@ struct vfpf_acquire_tlv { /* the following fields are for debug purposes */ u8 vf_id; /* ME register value */ u8 vf_os; /* e.g. Linux, W2K8 */ - u8 padding[2]; + u8 padding; + u8 caps; +#define VF_CAP_SUPPORT_EXT_BULLETIN (1 << 0) } vfdev_info; struct vf_pf_resc_request resc_request; @@ -393,11 +396,23 @@ struct pf_vf_bulletin_content { * to attempt to send messages on the * channel after this bit is set */ +#define LINK_VALID 3 /* alert the VF thet a new link status + * update is available for it + */ u8 mac[ETH_ALEN]; u8 mac_padding[2]; u16 vlan; u8 vlan_padding[6]; + + u16 link_speed; /* Effective line speed */ + u8 link_speed_padding[6]; + u32 link_flags; /* VFPF_LINK_REPORT_XXX flags */ +#define VFPF_LINK_REPORT_LINK_DOWN (1 << 0) +#define VFPF_LINK_REPORT_FULL_DUPLEX (1 << 1) +#define VFPF_LINK_REPORT_RX_FC_ON (1 << 2) +#define VFPF_LINK_REPORT_TX_FC_ON (1 << 3) + u8 link_flags_padding[4]; }; union pf_vf_bulletin { -- cgit v1.2.3 From 9927b51469494d50956978b533d848748b792cef Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Thu, 26 Jun 2014 14:31:05 +0300 Subject: bnx2x: enlarge minimal alignemnt of data offset This improves the performance of driver on machine with L1_CACHE_SHIFT of at most 32 bytes [HW was planned for 64-byte aligned fastpath data]. Signed-off-by: Dmitry Kravkov Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index faf262a0d6c4..ce8f86966c11 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1508,8 +1508,10 @@ struct bnx2x { /* TCP with Timestamp Option (32) + IPv6 (40) */ #define ETH_MAX_TPA_HEADER_SIZE 72 - /* Max supported alignment is 256 (8 shift) */ -#define BNX2X_RX_ALIGN_SHIFT min(8, L1_CACHE_SHIFT) + /* Max supported alignment is 256 (8 shift) + * minimal alignment shift 6 is optimal for 57xxx HW performance + */ +#define BNX2X_RX_ALIGN_SHIFT max(6, min(8, L1_CACHE_SHIFT)) /* FW uses 2 Cache lines Alignment for start packet and size * -- cgit v1.2.3 From ebf457f931e363cd5f57e661e103386af5a21629 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 26 Jun 2014 14:31:06 +0300 Subject: bnx2x: Fail probe of VFs using an old incompatible driver There are linux distributions where the inbox bnx2x driver contains SRIOV support but doesn't contain the changes introduced in b9871bcf "bnx2x: VF RSS support - PF side". A VF in a VM running that distribution over a new hypervisor will access incorrect addresses when trying to transmit packets, causing an attention in the hypervisor and making that VF inactive until FLRed. The driver in the VM has to ne upgraded [no real way to overcome this], but due to the HW attention currently arising upgrading the driver in the VM would not suffice [since the VF needs also be FLRed if the previous driver was already loaded]. This patch causes the PF to fail the acquire message from a VF running an old problematic driver; The VF will then gracefully fail it's probe preventing the HW attention [and allow clean upgrade of driver in VM]. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c | 48 ++++++++++++++++++++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h | 6 +++ 2 files changed, 54 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index f35077366340..54e0427a9ee6 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -1235,6 +1235,41 @@ static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf, bnx2x_vf_mbx_resp_send_msg(bp, vf, vfop_status); } +static bool bnx2x_vf_mbx_is_windows_vm(struct bnx2x *bp, + struct vfpf_acquire_tlv *acquire) +{ + /* Windows driver does one of three things: + * 1. Old driver doesn't have bulletin board address set. + * 2. 'Middle' driver sends mc_num == 32. + * 3. New driver sets the OS field. + */ + if (!acquire->bulletin_addr || + acquire->resc_request.num_mc_filters == 32 || + ((acquire->vfdev_info.vf_os & VF_OS_MASK) == + VF_OS_WINDOWS)) + return true; + + return false; +} + +static int bnx2x_vf_mbx_acquire_chk_dorq(struct bnx2x *bp, + struct bnx2x_virtf *vf, + struct bnx2x_vf_mbx *mbx) +{ + /* Linux drivers which correctly set the doorbell size also + * send a physical port request + */ + if (bnx2x_search_tlv_list(bp, &mbx->msg->req, + CHANNEL_TLV_PHYS_PORT_ID)) + return 0; + + /* Issue does not exist in windows VMs */ + if (bnx2x_vf_mbx_is_windows_vm(bp, &mbx->msg->req.acquire)) + return 0; + + return -EOPNOTSUPP; +} + static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf, struct bnx2x_vf_mbx *mbx) { @@ -1250,6 +1285,18 @@ static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf, acquire->resc_request.num_vlan_filters, acquire->resc_request.num_mc_filters); + /* Prevent VFs with old drivers from loading, since they calculate + * CIDs incorrectly requiring a VF-flr [VM reboot] in order to recover + * while being upgraded. + */ + rc = bnx2x_vf_mbx_acquire_chk_dorq(bp, vf, mbx); + if (rc) { + DP(BNX2X_MSG_IOV, + "VF [%d] - Can't support acquire request due to doorbell mismatch. Please update VM driver\n", + vf->abs_vfid); + goto out; + } + /* acquire the resources */ rc = bnx2x_vf_acquire(bp, vf, &acquire->resc_request); @@ -1263,6 +1310,7 @@ static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf, vf->cfg_flags &= ~VF_CFG_EXT_BULLETIN; } +out: /* response */ bnx2x_vf_mbx_acquire_resp(bp, vf, mbx, rc); } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h index ace4d7b0529f..15670c499a20 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h @@ -118,6 +118,12 @@ struct vfpf_acquire_tlv { /* the following fields are for debug purposes */ u8 vf_id; /* ME register value */ u8 vf_os; /* e.g. Linux, W2K8 */ +#define VF_OS_SUBVERSION_MASK (0x1f) +#define VF_OS_MASK (0xe0) +#define VF_OS_SHIFT (5) +#define VF_OS_UNDEFINED (0 << VF_OS_SHIFT) +#define VF_OS_WINDOWS (1 << VF_OS_SHIFT) + u8 padding; u8 caps; #define VF_CAP_SUPPORT_EXT_BULLETIN (1 << 0) -- cgit v1.2.3 From 35e872ae6330e72c1b6045c021314b32a4a047de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Fri, 27 Jun 2014 12:05:29 +0200 Subject: dp83640: Program pulsewidth2 values of perout triggers 0 and 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Periodic output triggers 0 and 1 of the dp83640 has a programmable duty-cycle which is controlled by the Pulsewidth2 field of the trigger data register. This field is not documented in the datasheet, but it is described in the "PHYTER Software Development Guide" section 3.1.4.1. Failing to set the field can result in unstable/no trigger output. Add programming of the Pulsewidth2 field, setting it to the same value as the Pulsewidth field for a 50% duty cycle. Signed-off-by: Stefan Sørensen Signed-off-by: David S. Miller --- drivers/net/phy/dp83640.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 6a999e6814a0..fcd50b77999f 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -353,6 +353,11 @@ static int periodic_output(struct dp83640_clock *clock, ext_write(0, phydev, PAGE4, PTP_TDR, sec >> 16); /* sec[31:16] */ ext_write(0, phydev, PAGE4, PTP_TDR, pwidth & 0xffff); /* ns[15:0] */ ext_write(0, phydev, PAGE4, PTP_TDR, pwidth >> 16); /* ns[31:16] */ + /* Triggers 0 and 1 has programmable pulsewidth2 */ + if (trigger < 2) { + ext_write(0, phydev, PAGE4, PTP_TDR, pwidth & 0xffff); + ext_write(0, phydev, PAGE4, PTP_TDR, pwidth >> 16); + } /*enable trigger*/ val &= ~TRIG_LOAD; -- cgit v1.2.3 From ad01577aeb92d7cc72bb945aeb28def3749065da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Fri, 27 Jun 2014 12:05:30 +0200 Subject: dp83640: Increase supported perout pins to 7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch increases the number of supported periodic output pins from 1 to 7. The last pin is reserved for sync. Signed-off-by: Stefan Sørensen Signed-off-by: David S. Miller --- drivers/net/phy/dp83640.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index fcd50b77999f..eabecff9b740 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -40,6 +40,7 @@ #define LAYER2 0x01 #define MAX_RXTS 64 #define N_EXT_TS 6 +#define N_PER_OUT 7 #define PSF_PTPVER 2 #define PSF_EVNT 0x4000 #define PSF_RX 0x2000 @@ -47,7 +48,6 @@ #define EXT_EVENT 1 #define CAL_EVENT 7 #define CAL_TRIGGER 7 -#define PER_TRIGGER 6 #define DP83640_N_PINS 12 #define MII_DP83640_MICR 0x11 @@ -300,23 +300,23 @@ static u64 phy2txts(struct phy_txts *p) } static int periodic_output(struct dp83640_clock *clock, - struct ptp_clock_request *clkreq, bool on) + struct ptp_clock_request *clkreq, bool on, + int trigger) { struct dp83640_private *dp83640 = clock->chosen; struct phy_device *phydev = dp83640->phydev; u32 sec, nsec, pwidth; - u16 gpio, ptp_trig, trigger, val; + u16 gpio, ptp_trig, val; if (on) { - gpio = 1 + ptp_find_pin(clock->ptp_clock, PTP_PF_PEROUT, 0); + gpio = 1 + ptp_find_pin(clock->ptp_clock, PTP_PF_PEROUT, + trigger); if (gpio < 1) return -EINVAL; } else { gpio = 0; } - trigger = PER_TRIGGER; - ptp_trig = TRIG_WR | (trigger & TRIG_CSEL_MASK) << TRIG_CSEL_SHIFT | (gpio & TRIG_GPIO_MASK) << TRIG_GPIO_SHIFT | @@ -496,9 +496,9 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp, return 0; case PTP_CLK_REQ_PEROUT: - if (rq->perout.index != 0) + if (rq->perout.index >= N_PER_OUT) return -EINVAL; - return periodic_output(clock, rq, on); + return periodic_output(clock, rq, on, rq->perout.index); default: break; @@ -949,7 +949,7 @@ static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus) clock->caps.max_adj = 1953124; clock->caps.n_alarm = 0; clock->caps.n_ext_ts = N_EXT_TS; - clock->caps.n_per_out = 1; + clock->caps.n_per_out = N_PER_OUT; clock->caps.n_pins = DP83640_N_PINS; clock->caps.pps = 0; clock->caps.adjfreq = ptp_dp83640_adjfreq; -- cgit v1.2.3 From 6f39eb87de043ce778f584f4ae1b23c6db415a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Fri, 27 Jun 2014 12:05:31 +0200 Subject: dp83640: Verify calibration pin assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This constraints the pin assignment to not allow the calibration function to be reassigned and only allow reassigning the calibratin pin if only one phy is connected. Signed-off-by: Stefan Sørensen Signed-off-by: David S. Miller --- drivers/net/phy/dp83640.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index eabecff9b740..ab4811242458 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -510,6 +510,16 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp, static int ptp_dp83640_verify(struct ptp_clock_info *ptp, unsigned int pin, enum ptp_pin_function func, unsigned int chan) { + struct dp83640_clock *clock = + container_of(ptp, struct dp83640_clock, caps); + + if (clock->caps.pin_config[pin].func == PTP_PF_PHYSYNC && + !list_empty(&clock->phylist)) + return 1; + + if (func == PTP_PF_PHYSYNC) + return 1; + return 0; } -- cgit v1.2.3 From e0155950f01d26c1ae82b99d13e05b2127c7b7ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Fri, 27 Jun 2014 12:05:32 +0200 Subject: dp83640: Get calibration pin with ptp_find_pin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency, use the ptp_find_pin function to get the calibration pin, not gpio_tab. Signed-off-by: Stefan Sørensen Signed-off-by: David S. Miller --- drivers/net/phy/dp83640.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index ab4811242458..293ad064905d 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -609,7 +609,11 @@ static void recalibrate(struct dp83640_clock *clock) u16 cal_gpio, cfg0, evnt, ptp_trig, trigger, val; trigger = CAL_TRIGGER; - cal_gpio = gpio_tab[CALIBRATE_GPIO]; + cal_gpio = 1 + ptp_find_pin(clock->ptp_clock, PTP_PF_PHYSYNC, 0); + if (cal_gpio < 1) { + pr_err("PHY calibration pin not avaible - PHY is not calibrated."); + return; + } mutex_lock(&clock->extreg_lock); -- cgit v1.2.3 From 72df7a7244c0d99414cbc1fd57c5cfeae964d3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Fri, 27 Jun 2014 12:05:33 +0200 Subject: ptp: Allow reassigning calibration pin function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ptp pin function programming does not allow calibration pin to change function. This is problematic on hardware that uses the default calibration pin for other purposes. Removing this limitation does not impact calibration if userspace does not reprogram the calibration pin. Signed-off-by: Stefan Sørensen Signed-off-by: David S. Miller --- drivers/ptp/ptp_chardev.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index 419056d7887e..f8a76090cbca 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -86,17 +86,12 @@ int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin, return -EINVAL; break; case PTP_PF_PHYSYNC: - pr_err("sorry, cannot reassign the calibration pin\n"); - return -EINVAL; + if (chan != 0) + return -EINVAL; default: return -EINVAL; } - if (pin2->func == PTP_PF_PHYSYNC) { - pr_err("sorry, cannot reprogram the calibration pin\n"); - return -EINVAL; - } - if (info->verify(info, pin, func, chan)) { pr_err("driver cannot use function %u on pin %u\n", func, chan); return -EOPNOTSUPP; -- cgit v1.2.3 From 35b1de5579704be0e03454f713dddd6f86eccb7e Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 27 Jun 2014 19:23:47 +0530 Subject: rdma/cxgb4: Fixes cxgb4 probe failure in VM when PF is exposed through PCI Passthrough Change logic which determines our Physical Function at PCI Probe time. Now we read the PL_WHOAMI register and get the Physical Function. Pass Physical Function to Upper Layer Drivers in lld_info structure in the new field "pf" added to lld_info. This is useful for the cases where the PF, say PF4, is attached to a Virtual Machine via some form of "PCI Pass Through" technology and the PCI Function shows up as PF0 in the VM. Based on original work by Casey Leedom Signed-off-by: Casey Leedom Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/cm.c | 3 ++- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 18 ++++++++++-------- drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 1 + 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 5e153f6d4b48..d62a0f9dd11a 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -465,7 +465,8 @@ static void send_flowc(struct c4iw_ep *ep, struct sk_buff *skb) 16)) | FW_WR_FLOWID(ep->hwtid)); flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN; - flowc->mnemval[0].val = cpu_to_be32(PCI_FUNC(ep->com.dev->rdev.lldi.pdev->devfn) << 8); + flowc->mnemval[0].val = cpu_to_be32(FW_PFVF_CMD_PFN + (ep->com.dev->rdev.lldi.pf)); flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH; flowc->mnemval[1].val = cpu_to_be32(ep->tx_chan); flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index b7154dc9936c..e8e77b806c7a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4053,6 +4053,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld) unsigned short i; lli.pdev = adap->pdev; + lli.pf = adap->fn; lli.l2t = adap->l2t; lli.tids = &adap->tids; lli.ports = adap->port; @@ -6294,13 +6295,6 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return err; } - /* We control everything through one PF */ - func = PCI_FUNC(pdev->devfn); - if (func != ent->driver_data) { - pci_save_state(pdev); /* to restore SR-IOV later */ - goto sriov; - } - err = pci_enable_device(pdev); if (err) { dev_err(&pdev->dev, "cannot enable PCI device\n"); @@ -6344,6 +6338,15 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_free_adapter; } + /* We control everything through one PF */ + func = SOURCEPF_GET(readl(adapter->regs + PL_WHOAMI)); + if ((pdev->device == 0xa000 && func != 0) || + func != ent->driver_data) { + pci_save_state(pdev); /* to restore SR-IOV later */ + err = 0; + goto out_unmap_bar0; + } + adapter->pdev = pdev; adapter->pdev_dev = &pdev->dev; adapter->mbox = func; @@ -6507,7 +6510,6 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (is_offload(adapter)) attach_ulds(adapter); -sriov: #ifdef CONFIG_PCI_IOV if (func < ARRAY_SIZE(num_vf) && num_vf[func] > 0) if (pci_enable_sriov(pdev, num_vf[func]) == 0) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index d719decbfb28..8f60851b75ad 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -253,6 +253,7 @@ struct cxgb4_lld_info { int dbfifo_int_thresh; /* doorbell fifo int threshold */ unsigned int sge_pktshift; /* Padding between CPL and */ /* packet data */ + unsigned int pf; /* Physical Function we're using */ bool enable_fw_ofld_conn; /* Enable connection through fw */ /* WR */ bool ulptx_memwrite_dsgl; /* use of T5 DSGL allowed */ -- cgit v1.2.3 From 0abfd1524b655f00597d419c8e63d06ebf637372 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 27 Jun 2014 19:23:48 +0530 Subject: cxgb4: Use FW interface to get BAR0 value Use the firmware interface to get the BAR0 value since we really don't want to use the PCI-E Configuration Space Backdoor access which is owned by the firmware. Set up PCI-E Memory Window registers using the true values programmed into BAR registers. When the PF4 "Master Function" is exported to a Virtual Machine, the values returned by pci_resource_start() will be for the synthetic PCI-E Configuration Space and not the real addresses. But we need to program the PCI-E Memory Window address decoders with the real addresses that we're going to be using in order to have accesses through the Memory Windows work. Based on origninal work by Casey Leedom Signed-off-by: Casey Leedom Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 5 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 72 ++++++++++++++++++++++--- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 24 +++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 5 ++ 4 files changed, 98 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 7b5425c9c0fb..4fd215185f93 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -85,7 +85,8 @@ enum { MEMWIN1_BASE_T5 = 0x52000, MEMWIN2_APERTURE = 65536, MEMWIN2_BASE = 0x30000, - MEMWIN2_BASE_T5 = 0x54000, + MEMWIN2_APERTURE_T5 = 131072, + MEMWIN2_BASE_T5 = 0x60000, }; enum dev_master { @@ -608,6 +609,7 @@ struct l2t_data; struct adapter { void __iomem *regs; void __iomem *bar2; + u32 t4_bar0; struct pci_dev *pdev; struct device *pdev_dev; unsigned int mbox; @@ -946,6 +948,7 @@ void t4_write_indirect(struct adapter *adap, unsigned int addr_reg, void t4_read_indirect(struct adapter *adap, unsigned int addr_reg, unsigned int data_reg, u32 *vals, unsigned int nregs, unsigned int start_idx); +void t4_hw_pci_read_cfg4(struct adapter *adapter, int reg, u32 *val); struct fw_filter_wr; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index e8e77b806c7a..524a8b2894e7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4773,20 +4773,75 @@ void t4_fatal_err(struct adapter *adap) dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n"); } +/* Return the specified PCI-E Configuration Space register from our Physical + * Function. We try first via a Firmware LDST Command since we prefer to let + * the firmware own all of these registers, but if that fails we go for it + * directly ourselves. + */ +static u32 t4_read_pcie_cfg4(struct adapter *adap, int reg) +{ + struct fw_ldst_cmd ldst_cmd; + u32 val; + int ret; + + /* Construct and send the Firmware LDST Command to retrieve the + * specified PCI-E Configuration Space register. + */ + memset(&ldst_cmd, 0, sizeof(ldst_cmd)); + ldst_cmd.op_to_addrspace = + htonl(FW_CMD_OP(FW_LDST_CMD) | + FW_CMD_REQUEST | + FW_CMD_READ | + FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FUNC_PCIE)); + ldst_cmd.cycles_to_len16 = htonl(FW_LEN16(ldst_cmd)); + ldst_cmd.u.pcie.select_naccess = FW_LDST_CMD_NACCESS(1); + ldst_cmd.u.pcie.ctrl_to_fn = + (FW_LDST_CMD_LC | FW_LDST_CMD_FN(adap->fn)); + ldst_cmd.u.pcie.r = reg; + ret = t4_wr_mbox(adap, adap->mbox, &ldst_cmd, sizeof(ldst_cmd), + &ldst_cmd); + + /* If the LDST Command suucceeded, exctract the returned register + * value. Otherwise read it directly ourself. + */ + if (ret == 0) + val = ntohl(ldst_cmd.u.pcie.data[0]); + else + t4_hw_pci_read_cfg4(adap, reg, &val); + + return val; +} + static void setup_memwin(struct adapter *adap) { - u32 bar0, mem_win0_base, mem_win1_base, mem_win2_base; + u32 mem_win0_base, mem_win1_base, mem_win2_base, mem_win2_aperture; - bar0 = pci_resource_start(adap->pdev, 0); /* truncation intentional */ if (is_t4(adap->params.chip)) { + u32 bar0; + + /* Truncation intentional: we only read the bottom 32-bits of + * the 64-bit BAR0/BAR1 ... We use the hardware backdoor + * mechanism to read BAR0 instead of using + * pci_resource_start() because we could be operating from + * within a Virtual Machine which is trapping our accesses to + * our Configuration Space and we need to set up the PCI-E + * Memory Window decoders with the actual addresses which will + * be coming across the PCI-E link. + */ + bar0 = t4_read_pcie_cfg4(adap, PCI_BASE_ADDRESS_0); + bar0 &= PCI_BASE_ADDRESS_MEM_MASK; + adap->t4_bar0 = bar0; + mem_win0_base = bar0 + MEMWIN0_BASE; mem_win1_base = bar0 + MEMWIN1_BASE; mem_win2_base = bar0 + MEMWIN2_BASE; + mem_win2_aperture = MEMWIN2_APERTURE; } else { /* For T5, only relative offset inside the PCIe BAR is passed */ mem_win0_base = MEMWIN0_BASE; - mem_win1_base = MEMWIN1_BASE_T5; + mem_win1_base = MEMWIN1_BASE; mem_win2_base = MEMWIN2_BASE_T5; + mem_win2_aperture = MEMWIN2_APERTURE_T5; } t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 0), mem_win0_base | BIR(0) | @@ -4796,16 +4851,19 @@ static void setup_memwin(struct adapter *adap) WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2), mem_win2_base | BIR(0) | - WINDOW(ilog2(MEMWIN2_APERTURE) - 10)); + WINDOW(ilog2(mem_win2_aperture) - 10)); + t4_read_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2)); } static void setup_memwin_rdma(struct adapter *adap) { if (adap->vres.ocq.size) { - unsigned int start, sz_kb; + u32 start; + unsigned int sz_kb; - start = pci_resource_start(adap->pdev, 2) + - OCQ_WIN_OFFSET(adap->pdev, &adap->vres); + start = t4_read_pcie_cfg4(adap, PCI_BASE_ADDRESS_2); + start &= PCI_BASE_ADDRESS_MEM_MASK; + start += OCQ_WIN_OFFSET(adap->pdev, &adap->vres); sz_kb = roundup_pow_of_two(adap->vres.ocq.size) >> 10; t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 3), diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 4536ea9f7018..2c3d00d77ef6 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -143,6 +143,30 @@ void t4_write_indirect(struct adapter *adap, unsigned int addr_reg, } } +/* + * Read a 32-bit PCI Configuration Space register via the PCI-E backdoor + * mechanism. This guarantees that we get the real value even if we're + * operating within a Virtual Machine and the Hypervisor is trapping our + * Configuration Space accesses. + */ +void t4_hw_pci_read_cfg4(struct adapter *adap, int reg, u32 *val) +{ + u32 req = ENABLE | FUNCTION(adap->fn) | reg; + + if (is_t4(adap->params.chip)) + req |= F_LOCALCFG; + + t4_write_reg(adap, PCIE_CFG_SPACE_REQ, req); + *val = t4_read_reg(adap, PCIE_CFG_SPACE_DATA); + + /* Reset ENABLE to 0 so reads of PCIE_CFG_SPACE_DATA won't cause a + * Configuration Space read. (None of the other fields matter when + * ENABLE is 0 so a simple register write is easier than a + * read-modify-write via t4_set_reg_field().) + */ + t4_write_reg(adap, PCIE_CFG_SPACE_REQ, 0); +} + /* * Get the reply to a mailbox command and store it in @rpl in big-endian order. */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 3360025ad922..f6b2ee13e715 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -387,6 +387,8 @@ #define MSTGRPPERR 0x00000001U #define PCIE_NONFAT_ERR 0x3010 +#define PCIE_CFG_SPACE_REQ 0x3060 +#define PCIE_CFG_SPACE_DATA 0x3064 #define PCIE_MEM_ACCESS_BASE_WIN 0x3068 #define S_PCIEOFST 10 #define M_PCIEOFST 0x3fffffU @@ -399,6 +401,9 @@ #define WINDOW_SHIFT 0 #define WINDOW(x) ((x) << WINDOW_SHIFT) #define PCIE_MEM_ACCESS_OFFSET 0x306c +#define ENABLE (1U << 30) +#define FUNCTION(x) ((x) << 12) +#define F_LOCALCFG (1U << 28) #define S_PFNUM 0 #define V_PFNUM(x) ((x) << S_PFNUM) -- cgit v1.2.3 From fc5ab020965067c457a4b5a9eb15648b6874bef2 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 27 Jun 2014 19:23:49 +0530 Subject: cxgb4: Replaced the backdoor mechanism to access the HW memory with PCIe Window method Rip out a bunch of redundant PCI-E Memory Window Read/Write routines, collapse the more general purpose routines into a single routine thereby eliminating the need for a large stack frame (and extra data copying) in the outer routine, change everything to use the improved routine t4_memory_rw. Based on origninal work by Casey Leedom and Steve Wise Signed-off-by: Casey Leedom Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 15 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 58 +++--- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 246 ++++++++++-------------- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 1 + 4 files changed, 148 insertions(+), 172 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 4fd215185f93..f338a7fcebf7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -654,6 +654,7 @@ struct adapter { struct dentry *debugfs_root; spinlock_t stats_lock; + spinlock_t win0_lock ____cacheline_aligned_in_smp; }; /* Defined bit width of user definable filter tuples @@ -960,8 +961,17 @@ int t4_wait_dev_ready(struct adapter *adap); int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, struct link_config *lc); int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port); -int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len, - __be32 *buf); + +#define T4_MEMORY_WRITE 0 +#define T4_MEMORY_READ 1 +int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, u32 len, + __be32 *buf, int dir); +static inline int t4_memory_write(struct adapter *adap, int mtype, u32 addr, + u32 len, __be32 *buf) +{ + return t4_memory_rw(adap, 0, mtype, addr, len, buf, 0); +} + int t4_seeprom_wp(struct adapter *adapter, bool enable); int get_vpd_params(struct adapter *adapter, struct vpd_params *p); int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); @@ -1059,7 +1069,6 @@ int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl); void t4_db_full(struct adapter *adapter); void t4_db_dropped(struct adapter *adapter); -int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len); int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, u32 addr, u32 val); void t4_sge_decode_idma_state(struct adapter *adapter, int state); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 524a8b2894e7..74ef0e69cdc4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -3066,6 +3066,8 @@ static ssize_t mem_read(struct file *file, char __user *buf, size_t count, loff_t avail = file_inode(file)->i_size; unsigned int mem = (uintptr_t)file->private_data & 3; struct adapter *adap = file->private_data - mem; + __be32 *data; + int ret; if (pos < 0) return -EINVAL; @@ -3074,29 +3076,24 @@ static ssize_t mem_read(struct file *file, char __user *buf, size_t count, if (count > avail - pos) count = avail - pos; - while (count) { - size_t len; - int ret, ofst; - __be32 data[16]; + data = t4_alloc_mem(count); + if (!data) + return -ENOMEM; - if ((mem == MEM_MC) || (mem == MEM_MC1)) - ret = t4_mc_read(adap, mem % MEM_MC, pos, data, NULL); - else - ret = t4_edc_read(adap, mem, pos, data, NULL); - if (ret) - return ret; + spin_lock(&adap->win0_lock); + ret = t4_memory_rw(adap, 0, mem, pos, count, data, T4_MEMORY_READ); + spin_unlock(&adap->win0_lock); + if (ret) { + t4_free_mem(data); + return ret; + } + ret = copy_to_user(buf, data, count); - ofst = pos % sizeof(data); - len = min(count, sizeof(data) - ofst); - if (copy_to_user(buf, (u8 *)data + ofst, len)) - return -EFAULT; + t4_free_mem(data); + if (ret) + return -EFAULT; - buf += len; - pos += len; - count -= len; - } - count = pos - *ppos; - *ppos = pos; + *ppos = pos + count; return count; } @@ -3757,7 +3754,11 @@ static int read_eq_indices(struct adapter *adap, u16 qid, u16 *pidx, u16 *cidx) __be64 indices; int ret; - ret = t4_mem_win_read_len(adap, addr, (__be32 *)&indices, 8); + spin_lock(&adap->win0_lock); + ret = t4_memory_rw(adap, 0, MEM_EDC0, addr, + sizeof(indices), (__be32 *)&indices, + T4_MEMORY_READ); + spin_unlock(&adap->win0_lock); if (!ret) { *cidx = (be64_to_cpu(indices) >> 25) & 0xffff; *pidx = (be64_to_cpu(indices) >> 9) & 0xffff; @@ -5076,7 +5077,7 @@ static int adap_init0_config(struct adapter *adapter, int reset) adapter->fn, 0, 1, params, val); if (ret == 0) { /* - * For t4_memory_write() below addresses and + * For t4_memory_rw() below addresses and * sizes have to be in terms of multiples of 4 * bytes. So, if the Configuration File isn't * a multiple of 4 bytes in length we'll have @@ -5092,8 +5093,9 @@ static int adap_init0_config(struct adapter *adapter, int reset) mtype = FW_PARAMS_PARAM_Y_GET(val[0]); maddr = FW_PARAMS_PARAM_Z_GET(val[0]) << 16; - ret = t4_memory_write(adapter, mtype, maddr, - size, data); + spin_lock(&adapter->win0_lock); + ret = t4_memory_rw(adapter, 0, mtype, maddr, + size, data, T4_MEMORY_WRITE); if (ret == 0 && resid != 0) { union { __be32 word; @@ -5104,10 +5106,12 @@ static int adap_init0_config(struct adapter *adapter, int reset) last.word = data[size >> 2]; for (i = resid; i < 4; i++) last.buf[i] = 0; - ret = t4_memory_write(adapter, mtype, - maddr + size, - 4, &last.word); + ret = t4_memory_rw(adapter, 0, mtype, + maddr + size, + 4, &last.word, + T4_MEMORY_WRITE); } + spin_unlock(&adapter->win0_lock); } } diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 2c3d00d77ef6..eb5a278e8045 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -413,78 +413,41 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc) return 0; } -/* - * t4_mem_win_rw - read/write memory through PCIE memory window - * @adap: the adapter - * @addr: address of first byte requested - * @data: MEMWIN0_APERTURE bytes of data containing the requested address - * @dir: direction of transfer 1 => read, 0 => write - * - * Read/write MEMWIN0_APERTURE bytes of data from MC starting at a - * MEMWIN0_APERTURE-byte-aligned address that covers the requested - * address @addr. - */ -static int t4_mem_win_rw(struct adapter *adap, u32 addr, __be32 *data, int dir) -{ - int i; - u32 win_pf = is_t4(adap->params.chip) ? 0 : V_PFNUM(adap->fn); - - /* - * Setup offset into PCIE memory window. Address must be a - * MEMWIN0_APERTURE-byte-aligned address. (Read back MA register to - * ensure that changes propagate before we attempt to use the new - * values.) - */ - t4_write_reg(adap, PCIE_MEM_ACCESS_OFFSET, - (addr & ~(MEMWIN0_APERTURE - 1)) | win_pf); - t4_read_reg(adap, PCIE_MEM_ACCESS_OFFSET); - - /* Collecting data 4 bytes at a time upto MEMWIN0_APERTURE */ - for (i = 0; i < MEMWIN0_APERTURE; i = i+0x4) { - if (dir) - *data++ = (__force __be32) t4_read_reg(adap, - (MEMWIN0_BASE + i)); - else - t4_write_reg(adap, (MEMWIN0_BASE + i), - (__force u32) *data++); - } - - return 0; -} - /** * t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window * @adap: the adapter + * @win: PCI-E Memory Window to use * @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC * @addr: address within indicated memory type * @len: amount of memory to transfer * @buf: host memory buffer - * @dir: direction of transfer 1 => read, 0 => write + * @dir: direction of transfer T4_MEMORY_READ (1) or T4_MEMORY_WRITE (0) * * Reads/writes an [almost] arbitrary memory region in the firmware: the - * firmware memory address, length and host buffer must be aligned on - * 32-bit boudaries. The memory is transferred as a raw byte sequence - * from/to the firmware's memory. If this memory contains data - * structures which contain multi-byte integers, it's the callers - * responsibility to perform appropriate byte order conversions. + * firmware memory address and host buffer must be aligned on 32-bit + * boudaries; the length may be arbitrary. The memory is transferred as + * a raw byte sequence from/to the firmware's memory. If this memory + * contains data structures which contain multi-byte integers, it's the + * caller's responsibility to perform appropriate byte order conversions. */ -static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len, - __be32 *buf, int dir) +int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, + u32 len, __be32 *buf, int dir) { - u32 pos, start, end, offset, memoffset; - u32 edc_size, mc_size; - int ret = 0; - __be32 *data; + u32 pos, offset, resid, memoffset; + u32 edc_size, mc_size, win_pf, mem_reg, mem_aperture, mem_base; - /* - * Argument sanity checks ... + /* Argument sanity checks ... */ - if ((addr & 0x3) || (len & 0x3)) + if (addr & 0x3) return -EINVAL; - data = vmalloc(MEMWIN0_APERTURE); - if (!data) - return -ENOMEM; + /* It's convenient to be able to handle lengths which aren't a + * multiple of 32-bits because we often end up transferring files to + * the firmware. So we'll handle that by normalizing the length here + * and then handling any residual transfer at the end. + */ + resid = len & 0x3; + len -= resid; /* Offset into the region of memory which is being accessed * MEM_EDC0 = 0 @@ -505,66 +468,98 @@ static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len, /* Determine the PCIE_MEM_ACCESS_OFFSET */ addr = addr + memoffset; - /* - * The underlaying EDC/MC read routines read MEMWIN0_APERTURE bytes - * at a time so we need to round down the start and round up the end. - * We'll start copying out of the first line at (addr - start) a word - * at a time. + /* Each PCI-E Memory Window is programmed with a window size -- or + * "aperture" -- which controls the granularity of its mapping onto + * adapter memory. We need to grab that aperture in order to know + * how to use the specified window. The window is also programmed + * with the base address of the Memory Window in BAR0's address + * space. For T4 this is an absolute PCI-E Bus Address. For T5 + * the address is relative to BAR0. */ - start = addr & ~(MEMWIN0_APERTURE-1); - end = (addr + len + MEMWIN0_APERTURE-1) & ~(MEMWIN0_APERTURE-1); - offset = (addr - start)/sizeof(__be32); + mem_reg = t4_read_reg(adap, + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, + win)); + mem_aperture = 1 << (GET_WINDOW(mem_reg) + 10); + mem_base = GET_PCIEOFST(mem_reg) << 10; + if (is_t4(adap->params.chip)) + mem_base -= adap->t4_bar0; + win_pf = is_t4(adap->params.chip) ? 0 : V_PFNUM(adap->fn); - for (pos = start; pos < end; pos += MEMWIN0_APERTURE, offset = 0) { + /* Calculate our initial PCI-E Memory Window Position and Offset into + * that Window. + */ + pos = addr & ~(mem_aperture-1); + offset = addr - pos; - /* - * If we're writing, copy the data from the caller's memory - * buffer + /* Set up initial PCI-E Memory Window to cover the start of our + * transfer. (Read it back to ensure that changes propagate before we + * attempt to use the new value.) + */ + t4_write_reg(adap, + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win), + pos | win_pf); + t4_read_reg(adap, + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win)); + + /* Transfer data to/from the adapter as long as there's an integral + * number of 32-bit transfers to complete. + */ + while (len > 0) { + if (dir == T4_MEMORY_READ) + *buf++ = (__force __be32) t4_read_reg(adap, + mem_base + offset); + else + t4_write_reg(adap, mem_base + offset, + (__force u32) *buf++); + offset += sizeof(__be32); + len -= sizeof(__be32); + + /* If we've reached the end of our current window aperture, + * move the PCI-E Memory Window on to the next. Note that + * doing this here after "len" may be 0 allows us to set up + * the PCI-E Memory Window for a possible final residual + * transfer below ... */ - if (!dir) { - /* - * If we're doing a partial write, then we need to do - * a read-modify-write ... - */ - if (offset || len < MEMWIN0_APERTURE) { - ret = t4_mem_win_rw(adap, pos, data, 1); - if (ret) - break; - } - while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) && - len > 0) { - data[offset++] = *buf++; - len -= sizeof(__be32); - } + if (offset == mem_aperture) { + pos += mem_aperture; + offset = 0; + t4_write_reg(adap, + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, + win), pos | win_pf); + t4_read_reg(adap, + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, + win)); } - - /* - * Transfer a block of memory and bail if there's an error. - */ - ret = t4_mem_win_rw(adap, pos, data, dir); - if (ret) - break; - - /* - * If we're reading, copy the data into the caller's memory - * buffer. - */ - if (dir) - while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) && - len > 0) { - *buf++ = data[offset++]; - len -= sizeof(__be32); - } } - vfree(data); - return ret; -} + /* If the original transfer had a length which wasn't a multiple of + * 32-bits, now's where we need to finish off the transfer of the + * residual amount. The PCI-E Memory Window has already been moved + * above (if necessary) to cover this final transfer. + */ + if (resid) { + union { + __be32 word; + char byte[4]; + } last; + unsigned char *bp; + int i; + + if (dir == T4_MEMORY_WRITE) { + last.word = (__force __be32) t4_read_reg(adap, + mem_base + offset); + for (bp = (unsigned char *)buf, i = resid; i < 4; i++) + bp[i] = last.byte[i]; + } else { + last.word = *buf; + for (i = resid; i < 4; i++) + last.byte[i] = 0; + t4_write_reg(adap, mem_base + offset, + (__force u32) last.word); + } + } -int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len, - __be32 *buf) -{ - return t4_memory_rw(adap, mtype, addr, len, buf, 0); + return 0; } #define EEPROM_STAT_ADDR 0x7bfc @@ -2528,39 +2523,6 @@ int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } -/** - * t4_mem_win_read_len - read memory through PCIE memory window - * @adap: the adapter - * @addr: address of first byte requested aligned on 32b. - * @data: len bytes to hold the data read - * @len: amount of data to read from window. Must be <= - * MEMWIN0_APERATURE after adjusting for 16B for T4 and - * 128B for T5 alignment requirements of the the memory window. - * - * Read len bytes of data from MC starting at @addr. - */ -int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len) -{ - int i, off; - u32 win_pf = is_t4(adap->params.chip) ? 0 : V_PFNUM(adap->fn); - - /* Align on a 2KB boundary. - */ - off = addr & MEMWIN0_APERTURE; - if ((addr & 3) || (len + off) > MEMWIN0_APERTURE) - return -EINVAL; - - t4_write_reg(adap, PCIE_MEM_ACCESS_OFFSET, - (addr & ~MEMWIN0_APERTURE) | win_pf); - t4_read_reg(adap, PCIE_MEM_ACCESS_OFFSET); - - for (i = 0; i < len; i += 4) - *data++ = (__force __be32) t4_read_reg(adap, - (MEMWIN0_BASE + off + i)); - - return 0; -} - /** * t4_mdio_rd - read a PHY register through MDIO * @adap: the adapter diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index f6b2ee13e715..ae7776471ceb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -400,6 +400,7 @@ #define WINDOW_MASK 0x000000ffU #define WINDOW_SHIFT 0 #define WINDOW(x) ((x) << WINDOW_SHIFT) +#define GET_WINDOW(x) (((x) >> WINDOW_SHIFT) & WINDOW_MASK) #define PCIE_MEM_ACCESS_OFFSET 0x306c #define ENABLE (1U << 30) #define FUNCTION(x) ((x) << 12) -- cgit v1.2.3 From fb1e933d3c1a7289dc3c3456ff9b97f53ed5f1d9 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 27 Jun 2014 19:23:50 +0530 Subject: cxgb4: Adds device ID for few more Chelsio T4 Adapters Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 74ef0e69cdc4..921f80500032 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -224,6 +224,17 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = { CH_DEVICE(0x4008, -1), CH_DEVICE(0x4009, -1), CH_DEVICE(0x400a, -1), + CH_DEVICE(0x400d, -1), + CH_DEVICE(0x400e, -1), + CH_DEVICE(0x4080, -1), + CH_DEVICE(0x4081, -1), + CH_DEVICE(0x4082, -1), + CH_DEVICE(0x4083, -1), + CH_DEVICE(0x4084, -1), + CH_DEVICE(0x4085, -1), + CH_DEVICE(0x4086, -1), + CH_DEVICE(0x4087, -1), + CH_DEVICE(0x4088, -1), CH_DEVICE(0x4401, 4), CH_DEVICE(0x4402, 4), CH_DEVICE(0x4403, 4), @@ -236,6 +247,15 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = { CH_DEVICE(0x440a, 4), CH_DEVICE(0x440d, 4), CH_DEVICE(0x440e, 4), + CH_DEVICE(0x4480, 4), + CH_DEVICE(0x4481, 4), + CH_DEVICE(0x4482, 4), + CH_DEVICE(0x4483, 4), + CH_DEVICE(0x4484, 4), + CH_DEVICE(0x4485, 4), + CH_DEVICE(0x4486, 4), + CH_DEVICE(0x4487, 4), + CH_DEVICE(0x4488, 4), CH_DEVICE(0x5001, 4), CH_DEVICE(0x5002, 4), CH_DEVICE(0x5003, 4), -- cgit v1.2.3 From dde3aadf53ce4d5c5857d87619eeb9ff777a9c2f Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 27 Jun 2014 19:23:51 +0530 Subject: cxgb4vf: Adds device ID for few more Chelsio T4 Adapters Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index ff1cdd1788b5..f002af190a65 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -2924,6 +2924,15 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4vf_pci_tbl) = { CH_DEVICE(0x480a, 0), /* T404-bt */ CH_DEVICE(0x480d, 0), /* T480-cr */ CH_DEVICE(0x480e, 0), /* T440-lp-cr */ + CH_DEVICE(0x4880, 0), + CH_DEVICE(0x4880, 1), + CH_DEVICE(0x4880, 2), + CH_DEVICE(0x4880, 3), + CH_DEVICE(0x4880, 4), + CH_DEVICE(0x4880, 5), + CH_DEVICE(0x4880, 6), + CH_DEVICE(0x4880, 7), + CH_DEVICE(0x4880, 8), CH_DEVICE(0x5800, 0), /* T580-dbg */ CH_DEVICE(0x5801, 0), /* T520-cr */ CH_DEVICE(0x5802, 0), /* T522-cr */ -- cgit v1.2.3 From 763e0ecd72fe90fdd73bb1aa1b72caf8381d2fff Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 27 Jun 2014 16:13:12 +0200 Subject: bonding: allow to add vlans on top of empty bond This limitation maybe had some reason in the past, but now there is not one -> removing this. Signed-off-by: Jiri Pirko Acked-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 3a451b6cd3d5..ffefb704b529 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1001,12 +1001,6 @@ static netdev_features_t bond_fix_features(struct net_device *dev, netdev_features_t mask; struct slave *slave; - if (!bond_has_slaves(bond)) { - /* Disable adding VLANs to empty bond. But why? --mq */ - features |= NETIF_F_VLAN_CHALLENGED; - return features; - } - mask = features; features &= ~NETIF_F_ONE_FOR_ALL; features |= NETIF_F_ALL_FOR_ALL; @@ -3956,13 +3950,6 @@ void bond_setup(struct net_device *bond_dev) bond_dev->priv_flags |= IFF_BONDING | IFF_UNICAST_FLT; bond_dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING); - /* At first, we block adding VLANs. That's the only way to - * prevent problems that occur when adding VLANs over an - * empty bond. The block will be removed once non-challenged - * slaves are enslaved. - */ - bond_dev->features |= NETIF_F_VLAN_CHALLENGED; - /* don't acquire bond device's netif_tx_lock when * transmitting */ bond_dev->features |= NETIF_F_LLTX; -- cgit v1.2.3 From 9fe516ba3fb29b6f6a752ffd93342fdee500ec01 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 27 Jun 2014 08:36:16 -0700 Subject: inet: move ipv6only in sock_common When an UDP application switches from AF_INET to AF_INET6 sockets, we have a small performance degradation for IPv4 communications because of extra cache line misses to access ipv6only information. This can also be noticed for TCP listeners, as ipv6_only_sock() is also used from __inet_lookup_listener()->compute_score() This is magnified when SO_REUSEPORT is used. Move ipv6only into struct sock_common so that it is available at no extra cost in lookups. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/ipv6.h | 10 +++++----- include/net/inet_timewait_sock.h | 3 ++- include/net/sock.h | 4 +++- net/dccp/minisocks.c | 4 +--- net/ipv4/tcp_minisocks.c | 2 +- net/ipv6/af_inet6.c | 6 +++--- net/ipv6/ipv6_sockglue.c | 4 ++-- net/ipv6/udp.c | 3 +-- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index b0f2452f1d58..5dc68c3ebcbd 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -194,7 +194,7 @@ struct ipv6_pinfo { sndflow:1, repflow:1, pmtudisc:3, - ipv6only:1, + padding:1, /* 1 bit hole */ srcprefs:3, /* 001: prefer temporary address * 010: prefer public address * 100: prefer care-of address @@ -273,8 +273,8 @@ static inline void inet_sk_copy_descendant(struct sock *sk_to, __inet_sk_copy_descendant(sk_to, sk_from, ancestor_size); } -#define __ipv6_only_sock(sk) (inet6_sk(sk)->ipv6only) -#define ipv6_only_sock(sk) ((sk)->sk_family == PF_INET6 && __ipv6_only_sock(sk)) +#define __ipv6_only_sock(sk) (sk->sk_ipv6only) +#define ipv6_only_sock(sk) (__ipv6_only_sock(sk)) #define ipv6_sk_rxinfo(sk) ((sk)->sk_family == PF_INET6 && \ inet6_sk(sk)->rxopt.bits.rxinfo) @@ -287,8 +287,8 @@ static inline const struct in6_addr *inet6_rcv_saddr(const struct sock *sk) static inline int inet_v6_ipv6only(const struct sock *sk) { - return likely(sk->sk_state != TCP_TIME_WAIT) ? - ipv6_only_sock(sk) : inet_twsk(sk)->tw_ipv6only; + /* ipv6only field is at same position for timewait and other sockets */ + return ipv6_only_sock(sk); } #else #define __ipv6_only_sock(sk) 0 diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 61474ea02152..6c566034e26d 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -108,6 +108,7 @@ struct inet_timewait_sock { #define tw_family __tw_common.skc_family #define tw_state __tw_common.skc_state #define tw_reuse __tw_common.skc_reuse +#define tw_ipv6only __tw_common.skc_ipv6only #define tw_bound_dev_if __tw_common.skc_bound_dev_if #define tw_node __tw_common.skc_nulls_node #define tw_bind_node __tw_common.skc_bind_node @@ -131,7 +132,7 @@ struct inet_timewait_sock { __be16 tw_sport; kmemcheck_bitfield_begin(flags); /* And these are ours. */ - unsigned int tw_ipv6only : 1, + unsigned int tw_pad0 : 1, /* 1 bit hole */ tw_transparent : 1, tw_flowlabel : 20, tw_pad : 2, /* 2 bits hole */ diff --git a/include/net/sock.h b/include/net/sock.h index 173cae485de1..8d4c9473e7d7 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -181,7 +181,8 @@ struct sock_common { unsigned short skc_family; volatile unsigned char skc_state; unsigned char skc_reuse:4; - unsigned char skc_reuseport:4; + unsigned char skc_reuseport:1; + unsigned char skc_ipv6only:1; int skc_bound_dev_if; union { struct hlist_node skc_bind_node; @@ -317,6 +318,7 @@ struct sock { #define sk_state __sk_common.skc_state #define sk_reuse __sk_common.skc_reuse #define sk_reuseport __sk_common.skc_reuseport +#define sk_ipv6only __sk_common.skc_ipv6only #define sk_bound_dev_if __sk_common.skc_bound_dev_if #define sk_bind_node __sk_common.skc_bind_node #define sk_prot __sk_common.skc_prot diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index c69eb9c4fbb8..b50dc436db1f 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -55,11 +55,9 @@ void dccp_time_wait(struct sock *sk, int state, int timeo) const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1); #if IS_ENABLED(CONFIG_IPV6) if (tw->tw_family == PF_INET6) { - const struct ipv6_pinfo *np = inet6_sk(sk); - tw->tw_v6_daddr = sk->sk_v6_daddr; tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr; - tw->tw_ipv6only = np->ipv6only; + tw->tw_ipv6only = sk->sk_ipv6only; } #endif /* Linkage updates. */ diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index e68e0d4af6c9..1649988bd1b6 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -298,7 +298,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr; tw->tw_tclass = np->tclass; tw->tw_flowlabel = np->flow_label >> 12; - tw->tw_ipv6only = np->ipv6only; + tw->tw_ipv6only = sk->sk_ipv6only; } #endif diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 7cb4392690dd..a426cd7099bb 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -197,7 +197,7 @@ lookup_protocol: np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; np->mc_loop = 1; np->pmtudisc = IPV6_PMTUDISC_WANT; - np->ipv6only = net->ipv6.sysctl.bindv6only; + sk->sk_ipv6only = net->ipv6.sysctl.bindv6only; /* Init the ipv4 part of the socket since we can have sockets * using v6 API for ipv4. @@ -294,7 +294,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) /* Binding to v4-mapped address on a v6-only socket * makes no sense */ - if (np->ipv6only) { + if (sk->sk_ipv6only) { err = -EINVAL; goto out; } @@ -371,7 +371,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr_type != IPV6_ADDR_ANY) { sk->sk_userlocks |= SOCK_BINDADDR_LOCK; if (addr_type != IPV6_ADDR_MAPPED) - np->ipv6only = 1; + sk->sk_ipv6only = 1; } if (snum) sk->sk_userlocks |= SOCK_BINDPORT_LOCK; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index edb58aff4ae7..cc34f65179e4 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -235,7 +235,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, if (optlen < sizeof(int) || inet_sk(sk)->inet_num) goto e_inval; - np->ipv6only = valbool; + sk->sk_ipv6only = valbool; retv = 0; break; @@ -1058,7 +1058,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, } case IPV6_V6ONLY: - val = np->ipv6only; + val = sk->sk_ipv6only; break; case IPV6_RECVPKTINFO: diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 95c834799288..c2bd28fd43e4 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -79,7 +79,6 @@ static unsigned int udp6_ehashfn(struct net *net, int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) { const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); - int sk_ipv6only = ipv6_only_sock(sk); int sk2_ipv6only = inet_v6_ipv6only(sk2); int addr_type = ipv6_addr_type(&sk->sk_v6_rcv_saddr); int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; @@ -95,7 +94,7 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) return 1; if (addr_type == IPV6_ADDR_ANY && - !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) + !(ipv6_only_sock(sk) && addr_type2 == IPV6_ADDR_MAPPED)) return 1; if (sk2_rcv_saddr6 && -- cgit v1.2.3 From 9f16dc2ec7cb3527c66581ad762876ba1f774cdb Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 27 Jun 2014 22:51:52 +0200 Subject: drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c: remove unnecessary null test before debugfs_remove_recursive Fix checkpatch warning: "WARNING: debugfs_remove_recursive(NULL) is safe this check is probably not required" Cc: Hariprasad S Cc: netdev@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 921f80500032..2b438bd68c73 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -6637,8 +6637,7 @@ static void remove_one(struct pci_dev *pdev) if (adapter->port[i]->reg_state == NETREG_REGISTERED) unregister_netdev(adapter->port[i]); - if (adapter->debugfs_root) - debugfs_remove_recursive(adapter->debugfs_root); + debugfs_remove_recursive(adapter->debugfs_root); /* If we allocated filters, free up state associated with any * valid filters ... -- cgit v1.2.3 From fb0d164cc1e46ddb22e8fac9f9cb94fdaeddd70f Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 27 Jun 2014 23:07:43 +0200 Subject: net/caif/caif_socket.c: remove unnecessary null test before debugfs_remove_recursive based on checkpatch: "debugfs_remove_recursive(NULL) is safe this check is probably not required" Cc: Dmitry Tarnyagin Cc: "David S. Miller" Cc: netdev@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/caif/caif_socket.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index e8437094d15f..43f750e88e19 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -908,8 +908,7 @@ static int caif_release(struct socket *sock) sock->sk = NULL; WARN_ON(IS_ERR(cf_sk->debugfs_socket_dir)); - if (cf_sk->debugfs_socket_dir != NULL) - debugfs_remove_recursive(cf_sk->debugfs_socket_dir); + debugfs_remove_recursive(cf_sk->debugfs_socket_dir); lock_sock(&(cf_sk->sk)); sk->sk_state = CAIF_DISCONNECTED; -- cgit v1.2.3 From 665d1eca03cb9c7a1fb7d74186459b75b4a6ba7c Mon Sep 17 00:00:00 2001 From: Harish Patil Date: Fri, 27 Jun 2014 19:01:38 -0400 Subject: qlcnic: Enhance Tx timeout debug data collection. - Collect a firmware dump on first Tx timeout if netif_msg_tx_err() is set - Log Receive and Status ring info on Tx timeout, in addition to Tx ring info - Log additional Tx ring info if netif_msg_tx_err() is set Signed-off-by: Harish Patil Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 41 ++++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 4fc186713b66..f8de2ae01a5a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -2980,17 +2980,43 @@ static inline void dump_tx_ring_desc(struct qlcnic_host_tx_ring *tx_ring) } } -static void qlcnic_dump_tx_rings(struct qlcnic_adapter *adapter) +static void qlcnic_dump_rings(struct qlcnic_adapter *adapter) { + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; struct net_device *netdev = adapter->netdev; + struct qlcnic_host_rds_ring *rds_ring; + struct qlcnic_host_sds_ring *sds_ring; struct qlcnic_host_tx_ring *tx_ring; int ring; if (!netdev || !netif_running(netdev)) return; + for (ring = 0; ring < adapter->max_rds_rings; ring++) { + rds_ring = &recv_ctx->rds_rings[ring]; + if (!rds_ring) + continue; + netdev_info(netdev, + "rds_ring=%d crb_rcv_producer=%d producer=%u num_desc=%u\n", + ring, readl(rds_ring->crb_rcv_producer), + rds_ring->producer, rds_ring->num_desc); + } + + for (ring = 0; ring < adapter->drv_sds_rings; ring++) { + sds_ring = &(recv_ctx->sds_rings[ring]); + if (!sds_ring) + continue; + netdev_info(netdev, + "sds_ring=%d crb_sts_consumer=%d consumer=%u crb_intr_mask=%d num_desc=%u\n", + ring, readl(sds_ring->crb_sts_consumer), + sds_ring->consumer, readl(sds_ring->crb_intr_mask), + sds_ring->num_desc); + } + for (ring = 0; ring < adapter->drv_tx_rings; ring++) { tx_ring = &adapter->tx_ring[ring]; + if (!tx_ring) + continue; netdev_info(netdev, "Tx ring=%d Context Id=0x%x\n", ring, tx_ring->ctx_id); netdev_info(netdev, @@ -3013,9 +3039,10 @@ static void qlcnic_dump_tx_rings(struct qlcnic_adapter *adapter) netdev_info(netdev, "Total desc=%d, Available desc=%d\n", tx_ring->num_desc, qlcnic_tx_avail(tx_ring)); - if (netif_msg_tx_done(adapter->ahw)) + if (netif_msg_tx_err(adapter->ahw)) dump_tx_ring_desc(tx_ring); } + } static void qlcnic_tx_timeout(struct net_device *netdev) @@ -3025,16 +3052,18 @@ static void qlcnic_tx_timeout(struct net_device *netdev) if (test_bit(__QLCNIC_RESETTING, &adapter->state)) return; - if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS) { - netdev_info(netdev, "Tx timeout, reset the adapter.\n"); + qlcnic_dump_rings(adapter); + + if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS || + netif_msg_tx_err(adapter->ahw)) { + netdev_err(netdev, "Tx timeout, reset the adapter.\n"); if (qlcnic_82xx_check(adapter)) adapter->need_fw_reset = 1; else if (qlcnic_83xx_check(adapter)) qlcnic_83xx_idc_request_reset(adapter, QLCNIC_FORCE_FW_DUMP_KEY); } else { - netdev_info(netdev, "Tx timeout, reset adapter context.\n"); - qlcnic_dump_tx_rings(adapter); + netdev_err(netdev, "Tx timeout, reset adapter context.\n"); adapter->ahw->reset_context = 1; } } -- cgit v1.2.3 From 28470572a66e1e676a3b974862ecaf5b4764bc9f Mon Sep 17 00:00:00 2001 From: Harish Patil Date: Fri, 27 Jun 2014 19:01:39 -0400 Subject: qlcnic: Update version to 5.3.61 Signed-off-by: Harish Patil Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index be618b9e874f..16039d1497b8 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -39,8 +39,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 3 -#define _QLCNIC_LINUX_SUBVERSION 60 -#define QLCNIC_LINUX_VERSIONID "5.3.60" +#define _QLCNIC_LINUX_SUBVERSION 61 +#define QLCNIC_LINUX_VERSIONID "5.3.61" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) -- cgit v1.2.3 From 236294774e24b7a7ccbf2c7b699ca7cf2b897f94 Mon Sep 17 00:00:00 2001 From: Prashant Sreedharan Date: Fri, 27 Jun 2014 16:21:50 -0700 Subject: MAINTAINERS: Update tg3 maintainer Signed-off-by: Prashant Sreedharan Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 48f4ef44b252..f492681ea99e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1940,7 +1940,7 @@ F: arch/arm/boot/dts/bcm5301x.dtsi F: arch/arm/boot/dts/bcm470* BROADCOM TG3 GIGABIT ETHERNET DRIVER -M: Nithin Nayak Sujir +M: Prashant Sreedharan M: Michael Chan L: netdev@vger.kernel.org S: Supported -- cgit v1.2.3 From 179d80aff82bf8dff9db30589fe5a2297c454d35 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 28 Jun 2014 04:10:00 +0400 Subject: sh_eth: remove checks around dev_kfree_skb() calls Since consume_skb() (and hence dev_kfree_skb() macro) checks the passed pointer for NULL, there's no need to check for NULL before invoking dev_kfree_skb(). Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 7622213beef1..67b11c833870 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1094,20 +1094,16 @@ static void sh_eth_ring_free(struct net_device *ndev) /* Free Rx skb ringbuffer */ if (mdp->rx_skbuff) { - for (i = 0; i < mdp->num_rx_ring; i++) { - if (mdp->rx_skbuff[i]) - dev_kfree_skb(mdp->rx_skbuff[i]); - } + for (i = 0; i < mdp->num_rx_ring; i++) + dev_kfree_skb(mdp->rx_skbuff[i]); } kfree(mdp->rx_skbuff); mdp->rx_skbuff = NULL; /* Free Tx skb ringbuffer */ if (mdp->tx_skbuff) { - for (i = 0; i < mdp->num_tx_ring; i++) { - if (mdp->tx_skbuff[i]) - dev_kfree_skb(mdp->tx_skbuff[i]); - } + for (i = 0; i < mdp->num_tx_ring; i++) + dev_kfree_skb(mdp->tx_skbuff[i]); } kfree(mdp->tx_skbuff); mdp->tx_skbuff = NULL; @@ -2077,13 +2073,11 @@ static void sh_eth_tx_timeout(struct net_device *ndev) rxdesc = &mdp->rx_ring[i]; rxdesc->status = 0; rxdesc->addr = 0xBADF00D0; - if (mdp->rx_skbuff[i]) - dev_kfree_skb(mdp->rx_skbuff[i]); + dev_kfree_skb(mdp->rx_skbuff[i]); mdp->rx_skbuff[i] = NULL; } for (i = 0; i < mdp->num_tx_ring; i++) { - if (mdp->tx_skbuff[i]) - dev_kfree_skb(mdp->tx_skbuff[i]); + dev_kfree_skb(mdp->tx_skbuff[i]); mdp->tx_skbuff[i] = NULL; } -- cgit v1.2.3 From bd4578bc84a8c8a390cf6002539e75447e78e935 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 28 Jun 2014 20:44:19 +0200 Subject: drivers/net/hyperv/netvsc.c: remove unnecessary null test before kfree Fix checkpatch warning: WARNING: kfree(NULL) is safe this check is probably not required Cc: Haiyang Zhang Cc: netdev@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 4ed38eaecea8..f13e0acc8a69 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -1094,9 +1094,7 @@ close: vmbus_close(device->channel); cleanup: - - if (net_device) - kfree(net_device); + kfree(net_device); return ret; } -- cgit v1.2.3 From ba48c0c92704c68065ffb07661e4f99c800aeca2 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Mon, 30 Jun 2014 13:01:30 +0530 Subject: be2net: remove be_cmd_get_profile_config_mbox/mccq() variants Fix be_cmd_get_profile_cmd() to use be_cmd_notify_wait() routine, which uses MBOX if MCCQ has not been created. Doing this reduces code duplication; we don't need the _mbox/_mccq() variants anymore. Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 81 +++++------------------------ 1 file changed, 14 insertions(+), 67 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index f4ea3490f446..0e2f6e1930ba 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -3440,76 +3440,16 @@ err: return status; } -/* Uses mbox */ -static int be_cmd_get_profile_config_mbox(struct be_adapter *adapter, - u8 domain, struct be_dma_mem *cmd) -{ - struct be_mcc_wrb *wrb; - struct be_cmd_req_get_profile_config *req; - int status; - - if (mutex_lock_interruptible(&adapter->mbox_lock)) - return -1; - wrb = wrb_from_mbox(adapter); - - req = cmd->va; - be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_GET_PROFILE_CONFIG, - cmd->size, wrb, cmd); - - req->type = ACTIVE_PROFILE_TYPE; - req->hdr.domain = domain; - if (!lancer_chip(adapter)) - req->hdr.version = 1; - - status = be_mbox_notify_wait(adapter); - - mutex_unlock(&adapter->mbox_lock); - return status; -} - -/* Uses sync mcc */ -static int be_cmd_get_profile_config_mccq(struct be_adapter *adapter, - u8 domain, struct be_dma_mem *cmd) -{ - struct be_mcc_wrb *wrb; - struct be_cmd_req_get_profile_config *req; - int status; - - spin_lock_bh(&adapter->mcc_lock); - - wrb = wrb_from_mccq(adapter); - if (!wrb) { - status = -EBUSY; - goto err; - } - - req = cmd->va; - be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_GET_PROFILE_CONFIG, - cmd->size, wrb, cmd); - - req->type = ACTIVE_PROFILE_TYPE; - req->hdr.domain = domain; - if (!lancer_chip(adapter)) - req->hdr.version = 1; - - status = be_mcc_notify_wait(adapter); - -err: - spin_unlock_bh(&adapter->mcc_lock); - return status; -} - -/* Uses sync mcc, if MCCQ is already created otherwise mbox */ +/* Will use MBOX only if MCCQ has not been created */ int be_cmd_get_profile_config(struct be_adapter *adapter, struct be_resources *res, u8 domain) { struct be_cmd_resp_get_profile_config *resp; + struct be_cmd_req_get_profile_config *req; struct be_pcie_res_desc *pcie; struct be_port_res_desc *port; struct be_nic_res_desc *nic; - struct be_queue_info *mccq = &adapter->mcc_obj.q; + struct be_mcc_wrb wrb = {0}; struct be_dma_mem cmd; u32 desc_count; int status; @@ -3520,10 +3460,17 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, if (!cmd.va) return -ENOMEM; - if (!mccq->created) - status = be_cmd_get_profile_config_mbox(adapter, domain, &cmd); - else - status = be_cmd_get_profile_config_mccq(adapter, domain, &cmd); + req = cmd.va; + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_PROFILE_CONFIG, + cmd.size, &wrb, &cmd); + + req->hdr.domain = domain; + if (!lancer_chip(adapter)) + req->hdr.version = 1; + req->type = ACTIVE_PROFILE_TYPE; + + status = be_cmd_notify_wait(adapter, &wrb); if (status) goto err; -- cgit v1.2.3 From 10cccf60fbd3dcf8045aac1a77508b90e18c94bd Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Mon, 30 Jun 2014 13:01:31 +0530 Subject: be2net: read VF's capabilities from GET_PROFILE_CONFIG cmd The PF driver must query the FW for VF's interface capabilities to know if the VF is RSS capable or not. This patch is in preparation for enabling RSS on VFs on Skyhawk-R. Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 1 + drivers/net/ethernet/emulex/benet/be_cmds.c | 37 +++++++++++++++++++++++++---- drivers/net/ethernet/emulex/benet/be_cmds.h | 1 + drivers/net/ethernet/emulex/benet/be_main.c | 1 + 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index c2f5d2d3b932..37477ee3638b 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -411,6 +411,7 @@ struct be_resources { u16 max_vlans; /* Number of vlans supported */ u16 max_evt_qs; u32 if_cap_flags; + u32 vf_if_cap_flags; /* VF if capability flags */ }; struct rss_info { diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 0e2f6e1930ba..68d200667aac 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -3313,15 +3313,28 @@ err: return status; } -static struct be_nic_res_desc *be_get_nic_desc(u8 *buf, u32 desc_count) +/* Descriptor type */ +enum { + FUNC_DESC = 1, + VFT_DESC = 2 +}; + +static struct be_nic_res_desc *be_get_nic_desc(u8 *buf, u32 desc_count, + int desc_type) { struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; + struct be_nic_res_desc *nic; int i; for (i = 0; i < desc_count; i++) { if (hdr->desc_type == NIC_RESOURCE_DESC_TYPE_V0 || - hdr->desc_type == NIC_RESOURCE_DESC_TYPE_V1) - return (struct be_nic_res_desc *)hdr; + hdr->desc_type == NIC_RESOURCE_DESC_TYPE_V1) { + nic = (struct be_nic_res_desc *)hdr; + if (desc_type == FUNC_DESC || + (desc_type == VFT_DESC && + nic->flags & (1 << VFT_SHIFT))) + return nic; + } hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0; hdr = (void *)hdr + hdr->desc_len; @@ -3329,6 +3342,16 @@ static struct be_nic_res_desc *be_get_nic_desc(u8 *buf, u32 desc_count) return NULL; } +static struct be_nic_res_desc *be_get_vft_desc(u8 *buf, u32 desc_count) +{ + return be_get_nic_desc(buf, desc_count, VFT_DESC); +} + +static struct be_nic_res_desc *be_get_func_nic_desc(u8 *buf, u32 desc_count) +{ + return be_get_nic_desc(buf, desc_count, FUNC_DESC); +} + static struct be_pcie_res_desc *be_get_pcie_desc(u8 devfn, u8 *buf, u32 desc_count) { @@ -3424,7 +3447,7 @@ int be_cmd_get_func_config(struct be_adapter *adapter, struct be_resources *res) u32 desc_count = le32_to_cpu(resp->desc_count); struct be_nic_res_desc *desc; - desc = be_get_nic_desc(resp->func_param, desc_count); + desc = be_get_func_nic_desc(resp->func_param, desc_count); if (!desc) { status = -EINVAL; goto err; @@ -3446,6 +3469,7 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, { struct be_cmd_resp_get_profile_config *resp; struct be_cmd_req_get_profile_config *req; + struct be_nic_res_desc *vf_res; struct be_pcie_res_desc *pcie; struct be_port_res_desc *port; struct be_nic_res_desc *nic; @@ -3486,10 +3510,13 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, if (port) adapter->mc_type = port->mc_type; - nic = be_get_nic_desc(resp->func_param, desc_count); + nic = be_get_func_nic_desc(resp->func_param, desc_count); if (nic) be_copy_nic_desc(res, nic); + vf_res = be_get_vft_desc(resp->func_param, desc_count); + if (vf_res) + res->vf_if_cap_flags = vf_res->cap_flags; err: if (cmd.va) pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 59b3c056f329..3c16e6c833ec 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1835,6 +1835,7 @@ struct be_cmd_req_set_ext_fat_caps { #define PORT_RESOURCE_DESC_TYPE_V1 0x55 #define MAX_RESOURCE_DESC 264 +#define VFT_SHIFT 3 /* VF template */ #define IMM_SHIFT 6 /* Immediate */ #define NOSV_SHIFT 7 /* No save */ diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 34a26e42f19d..75e6653128fc 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3379,6 +3379,7 @@ static int be_get_resources(struct be_adapter *adapter) if (status) return status; adapter->res.max_vfs = res.max_vfs; + adapter->res.vf_if_cap_flags = res.vf_if_cap_flags; } dev_info(dev, "Max: txqs %d, rxqs %d, rss %d, eqs %d, vfs %d\n", -- cgit v1.2.3 From bec84e6b2116b05acf9d1cb3479fc44f0a89236f Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Mon, 30 Jun 2014 13:01:32 +0530 Subject: be2net: create optimal number of queues on SR-IOV config If SR-IOV is enabled in the adapter, the FW distributes queue resources evenly across the PF and it's VFs. If the user is not interested in enabling VFs, the queues set aside for VFs are wasted. This patch adds support for the PF driver to re-configure the resource distribution in FW based on the number of VFs enabled by the user. This also allows for supporting RSS queues on VFs, when less number of VFs are enabled per PF. When maximum number of VFs are enabled, each VF typically gets only one RXQ. Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 8 +- drivers/net/ethernet/emulex/benet/be_cmds.c | 108 ++++++++++++++++++----- drivers/net/ethernet/emulex/benet/be_cmds.h | 8 +- drivers/net/ethernet/emulex/benet/be_main.c | 129 ++++++++++++++++++---------- 4 files changed, 178 insertions(+), 75 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 37477ee3638b..d3d871b28cad 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -501,6 +501,7 @@ struct be_adapter { u32 flash_status; struct completion et_cmd_compl; + struct be_resources pool_res; /* resources available for the port */ struct be_resources res; /* resources available for the func */ u16 num_vfs; /* Number of VFs provisioned by PF */ u8 virtfn; @@ -524,9 +525,8 @@ struct be_adapter { #define be_physfn(adapter) (!adapter->virtfn) #define be_virtfn(adapter) (adapter->virtfn) -#define sriov_enabled(adapter) (adapter->num_vfs > 0) -#define sriov_want(adapter) (be_physfn(adapter) && \ - (num_vfs || pci_num_vf(adapter->pdev))) +#define sriov_enabled(adapter) (adapter->num_vfs > 0) + #define for_all_vfs(adapter, vf_cfg, i) \ for (i = 0, vf_cfg = &adapter->vf_cfg[i]; i < adapter->num_vfs; \ i++, vf_cfg++) @@ -537,7 +537,7 @@ struct be_adapter { #define be_max_vlans(adapter) (adapter->res.max_vlans) #define be_max_uc(adapter) (adapter->res.max_uc_mac) #define be_max_mc(adapter) (adapter->res.max_mcast_mac) -#define be_max_vfs(adapter) (adapter->res.max_vfs) +#define be_max_vfs(adapter) (adapter->pool_res.max_vfs) #define be_max_rss(adapter) (adapter->res.max_rss_qs) #define be_max_txqs(adapter) (adapter->res.max_tx_qs) #define be_max_prio_txqs(adapter) (adapter->res.max_prio_tx_qs) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 68d200667aac..9904bbfd4e93 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -3523,38 +3523,39 @@ err: return status; } -int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc, - int size, u8 version, u8 domain) +/* Will use MBOX only if MCCQ has not been created */ +static int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc, + int size, int count, u8 version, u8 domain) { struct be_cmd_req_set_profile_config *req; - struct be_mcc_wrb *wrb; + struct be_mcc_wrb wrb = {0}; + struct be_dma_mem cmd; int status; - spin_lock_bh(&adapter->mcc_lock); - - wrb = wrb_from_mccq(adapter); - if (!wrb) { - status = -EBUSY; - goto err; - } + memset(&cmd, 0, sizeof(struct be_dma_mem)); + cmd.size = sizeof(struct be_cmd_req_set_profile_config); + cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma); + if (!cmd.va) + return -ENOMEM; - req = embedded_payload(wrb); + req = cmd.va; be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_SET_PROFILE_CONFIG, sizeof(*req), - wrb, NULL); + OPCODE_COMMON_SET_PROFILE_CONFIG, cmd.size, + &wrb, &cmd); req->hdr.version = version; req->hdr.domain = domain; - req->desc_count = cpu_to_le32(1); + req->desc_count = cpu_to_le32(count); memcpy(req->desc, desc, size); - status = be_mcc_notify_wait(adapter); -err: - spin_unlock_bh(&adapter->mcc_lock); + status = be_cmd_notify_wait(adapter, &wrb); + + if (cmd.va) + pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); return status; } /* Mark all fields invalid */ -void be_reset_nic_desc(struct be_nic_res_desc *nic) +static void be_reset_nic_desc(struct be_nic_res_desc *nic) { memset(nic, 0, sizeof(*nic)); nic->unicast_mac_count = 0xFFFF; @@ -3575,9 +3576,20 @@ void be_reset_nic_desc(struct be_nic_res_desc *nic) nic->wol_param = 0x0F; nic->tunnel_iface_count = 0xFFFF; nic->direct_tenant_iface_count = 0xFFFF; + nic->bw_min = 0xFFFFFFFF; nic->bw_max = 0xFFFFFFFF; } +/* Mark all fields invalid */ +static void be_reset_pcie_desc(struct be_pcie_res_desc *pcie) +{ + memset(pcie, 0, sizeof(*pcie)); + pcie->sriov_state = 0xFF; + pcie->pf_state = 0xFF; + pcie->pf_type = 0xFF; + pcie->num_vfs = 0xFFFF; +} + int be_cmd_config_qos(struct be_adapter *adapter, u32 max_rate, u16 link_speed, u8 domain) { @@ -3608,7 +3620,63 @@ int be_cmd_config_qos(struct be_adapter *adapter, u32 max_rate, u16 link_speed, return be_cmd_set_profile_config(adapter, &nic_desc, nic_desc.hdr.desc_len, - version, domain); + 1, version, domain); +} + +int be_cmd_set_sriov_config(struct be_adapter *adapter, + struct be_resources res, u16 num_vfs) +{ + struct { + struct be_pcie_res_desc pcie; + struct be_nic_res_desc nic_vft; + } __packed desc; + u16 vf_q_count; + + if (BEx_chip(adapter) || lancer_chip(adapter)) + return 0; + + /* PF PCIE descriptor */ + be_reset_pcie_desc(&desc.pcie); + desc.pcie.hdr.desc_type = PCIE_RESOURCE_DESC_TYPE_V1; + desc.pcie.hdr.desc_len = RESOURCE_DESC_SIZE_V1; + desc.pcie.flags = (1 << IMM_SHIFT) | (1 << NOSV_SHIFT); + desc.pcie.pf_num = adapter->pdev->devfn; + desc.pcie.sriov_state = num_vfs ? 1 : 0; + desc.pcie.num_vfs = cpu_to_le16(num_vfs); + + /* VF NIC Template descriptor */ + be_reset_nic_desc(&desc.nic_vft); + desc.nic_vft.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V1; + desc.nic_vft.hdr.desc_len = RESOURCE_DESC_SIZE_V1; + desc.nic_vft.flags = (1 << VFT_SHIFT) | (1 << IMM_SHIFT) | + (1 << NOSV_SHIFT); + desc.nic_vft.pf_num = adapter->pdev->devfn; + desc.nic_vft.vf_num = 0; + + if (num_vfs && res.vf_if_cap_flags & BE_IF_FLAGS_RSS) { + /* If number of VFs requested is 8 less than max supported, + * assign 8 queue pairs to the PF and divide the remaining + * resources evenly among the VFs + */ + if (num_vfs < (be_max_vfs(adapter) - 8)) + vf_q_count = (res.max_rss_qs - 8) / num_vfs; + else + vf_q_count = res.max_rss_qs / num_vfs; + + desc.nic_vft.rq_count = cpu_to_le16(vf_q_count); + desc.nic_vft.txq_count = cpu_to_le16(vf_q_count); + desc.nic_vft.rssq_count = cpu_to_le16(vf_q_count - 1); + desc.nic_vft.cq_count = cpu_to_le16(3 * vf_q_count); + } else { + desc.nic_vft.txq_count = cpu_to_le16(1); + desc.nic_vft.rq_count = cpu_to_le16(1); + desc.nic_vft.rssq_count = cpu_to_le16(0); + /* One CQ for each TX, RX and MCCQ */ + desc.nic_vft.cq_count = cpu_to_le16(3); + } + + return be_cmd_set_profile_config(adapter, &desc, + 2 * RESOURCE_DESC_SIZE_V1, 2, 1, 0); } int be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op) @@ -3660,7 +3728,7 @@ int be_cmd_set_vxlan_port(struct be_adapter *adapter, __be16 port) } return be_cmd_set_profile_config(adapter, &port_desc, - RESOURCE_DESC_SIZE_V1, 1, 0); + RESOURCE_DESC_SIZE_V1, 1, 1, 0); } int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg, diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 3c16e6c833ec..c0f7167049b7 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1963,8 +1963,8 @@ struct be_cmd_req_set_profile_config { struct be_cmd_req_hdr hdr; u32 rsvd; u32 desc_count; - u8 desc[RESOURCE_DESC_SIZE_V1]; -}; + u8 desc[2 * RESOURCE_DESC_SIZE_V1]; +} __packed; struct be_cmd_resp_set_profile_config { struct be_cmd_resp_hdr hdr; @@ -2158,8 +2158,6 @@ int be_cmd_get_func_config(struct be_adapter *adapter, struct be_resources *res); int be_cmd_get_profile_config(struct be_adapter *adapter, struct be_resources *res, u8 domain); -int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc, - int size, u8 version, u8 domain); int be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile); int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg, int vf_num); @@ -2169,3 +2167,5 @@ int be_cmd_set_logical_link_config(struct be_adapter *adapter, int link_state, u8 domain); int be_cmd_set_vxlan_port(struct be_adapter *adapter, __be16 port); int be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op); +int be_cmd_set_sriov_config(struct be_adapter *adapter, + struct be_resources res, u16 num_vfs); diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 75e6653128fc..a32dc4fbb73c 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3098,6 +3098,13 @@ static int be_clear(struct be_adapter *adapter) if (sriov_enabled(adapter)) be_vf_clear(adapter); + /* Re-configure FW to distribute resources evenly across max-supported + * number of VFs, only when VFs are not already enabled. + */ + if (be_physfn(adapter) && !pci_vfs_assigned(adapter->pdev)) + be_cmd_set_sriov_config(adapter, adapter->pool_res, + pci_sriov_get_totalvfs(adapter->pdev)); + #ifdef CONFIG_BE2NET_VXLAN be_disable_vxlan_offloads(adapter); #endif @@ -3170,19 +3177,6 @@ static int be_vf_setup(struct be_adapter *adapter) u32 privileges; old_vfs = pci_num_vf(adapter->pdev); - if (old_vfs) { - dev_info(dev, "%d VFs are already enabled\n", old_vfs); - if (old_vfs != num_vfs) - dev_warn(dev, "Ignoring num_vfs=%d setting\n", num_vfs); - adapter->num_vfs = old_vfs; - } else { - if (num_vfs > be_max_vfs(adapter)) - dev_info(dev, "Device supports %d VFs and not %d\n", - be_max_vfs(adapter), num_vfs); - adapter->num_vfs = min_t(u16, num_vfs, be_max_vfs(adapter)); - if (!adapter->num_vfs) - return 0; - } status = be_vf_setup_init(adapter); if (status) @@ -3194,17 +3188,15 @@ static int be_vf_setup(struct be_adapter *adapter) if (status) goto err; } - } else { - status = be_vfs_if_create(adapter); - if (status) - goto err; - } - if (old_vfs) { status = be_vfs_mac_query(adapter); if (status) goto err; } else { + status = be_vfs_if_create(adapter); + if (status) + goto err; + status = be_vf_eth_addr_config(adapter); if (status) goto err; @@ -3270,19 +3262,7 @@ static u8 be_convert_mc_type(u32 function_mode) static void BEx_get_resources(struct be_adapter *adapter, struct be_resources *res) { - struct pci_dev *pdev = adapter->pdev; - bool use_sriov = false; - int max_vfs = 0; - - if (be_physfn(adapter) && BE3_chip(adapter)) { - be_cmd_get_profile_config(adapter, res, 0); - /* Some old versions of BE3 FW don't report max_vfs value */ - if (res->max_vfs == 0) { - max_vfs = pci_sriov_get_totalvfs(pdev); - res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0; - } - use_sriov = res->max_vfs && sriov_want(adapter); - } + bool use_sriov = adapter->num_vfs ? 1 : 0; if (be_physfn(adapter)) res->max_uc_mac = BE_UC_PMAC_COUNT; @@ -3349,6 +3329,54 @@ static void be_setup_init(struct be_adapter *adapter) adapter->cmd_privileges = MIN_PRIVILEGES; } +static int be_get_sriov_config(struct be_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + struct be_resources res = {0}; + int status, max_vfs, old_vfs; + + status = be_cmd_get_profile_config(adapter, &res, 0); + if (status) + return status; + + adapter->pool_res = res; + + /* Some old versions of BE3 FW don't report max_vfs value */ + if (BE3_chip(adapter) && !res.max_vfs) { + max_vfs = pci_sriov_get_totalvfs(adapter->pdev); + res.max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0; + } + + adapter->pool_res.max_vfs = res.max_vfs; + pci_sriov_set_totalvfs(adapter->pdev, be_max_vfs(adapter)); + + if (!be_max_vfs(adapter)) { + if (num_vfs) + dev_warn(dev, "device doesn't support SRIOV\n"); + adapter->num_vfs = 0; + return 0; + } + + /* validate num_vfs module param */ + old_vfs = pci_num_vf(adapter->pdev); + if (old_vfs) { + dev_info(dev, "%d VFs are already enabled\n", old_vfs); + if (old_vfs != num_vfs) + dev_warn(dev, "Ignoring num_vfs=%d setting\n", num_vfs); + adapter->num_vfs = old_vfs; + } else { + if (num_vfs > be_max_vfs(adapter)) { + dev_info(dev, "Resources unavailable to init %d VFs\n", + num_vfs); + dev_info(dev, "Limiting to %d VFs\n", + be_max_vfs(adapter)); + } + adapter->num_vfs = min_t(u16, num_vfs, be_max_vfs(adapter)); + } + + return 0; +} + static int be_get_resources(struct be_adapter *adapter) { struct device *dev = &adapter->pdev->dev; @@ -3374,14 +3402,6 @@ static int be_get_resources(struct be_adapter *adapter) res.max_evt_qs /= 2; adapter->res = res; - if (be_physfn(adapter)) { - status = be_cmd_get_profile_config(adapter, &res, 0); - if (status) - return status; - adapter->res.max_vfs = res.max_vfs; - adapter->res.vf_if_cap_flags = res.vf_if_cap_flags; - } - dev_info(dev, "Max: txqs %d, rxqs %d, rss %d, eqs %d, vfs %d\n", be_max_txqs(adapter), be_max_rxqs(adapter), be_max_rss(adapter), be_max_eqs(adapter), @@ -3394,7 +3414,6 @@ static int be_get_resources(struct be_adapter *adapter) return 0; } -/* Routine to query per function resource limits */ static int be_get_config(struct be_adapter *adapter) { u16 profile_id; @@ -3412,6 +3431,26 @@ static int be_get_config(struct be_adapter *adapter) if (!status) dev_info(&adapter->pdev->dev, "Using profile 0x%x\n", profile_id); + + status = be_get_sriov_config(adapter); + if (status) + return status; + + /* When the HW is in SRIOV capable configuration, the PF-pool + * resources are equally distributed across the max-number of + * VFs. The user may request only a subset of the max-vfs to be + * enabled. Based on num_vfs, redistribute the resources across + * num_vfs so that each VF will have access to more number of + * resources. This facility is not available in BE3 FW. + * Also, this is done by FW in Lancer chip. + */ + if (!pci_num_vf(adapter->pdev)) { + status = be_cmd_set_sriov_config(adapter, + adapter->pool_res, + adapter->num_vfs); + if (status) + return status; + } } status = be_get_resources(adapter); @@ -3597,12 +3636,8 @@ static int be_setup(struct be_adapter *adapter) be_cmd_set_logical_link_config(adapter, IFLA_VF_LINK_STATE_AUTO, 0); - if (sriov_want(adapter)) { - if (be_max_vfs(adapter)) - be_vf_setup(adapter); - else - dev_warn(dev, "device doesn't support SRIOV\n"); - } + if (adapter->num_vfs) + be_vf_setup(adapter); status = be_cmd_get_phy_info(adapter); if (!status && be_pause_supported(adapter)) -- cgit v1.2.3 From 9d4dfe4ae370747bcab66531482013d7ff6857f1 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Mon, 30 Jun 2014 13:01:33 +0530 Subject: be2net: re-enable vlan filtering mode asap While adding vlans, when the HW limit of vlan filters is reached, the driver enables vlan promiscuous mode. Similarily, while removing vlans, the driver must re-enable HW filtering as soon as the number of vlan filters is within the HW limit. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index a32dc4fbb73c..6297e72b77e2 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1172,20 +1172,15 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid) static int be_vlan_rem_vid(struct net_device *netdev, __be16 proto, u16 vid) { struct be_adapter *adapter = netdev_priv(netdev); - int status = 0; /* Packets with VID 0 are always received by Lancer by default */ if (lancer_chip(adapter) && vid == 0) - goto ret; + return 0; clear_bit(vid, adapter->vids); - status = be_vid_config(adapter); - if (!status) - adapter->vlans_added--; - else - set_bit(vid, adapter->vids); -ret: - return status; + adapter->vlans_added--; + + return be_vid_config(adapter); } static void be_clear_promisc(struct be_adapter *adapter) -- cgit v1.2.3 From 8f61059a96c2a29c1cc5a39dfe23d06ef5b4b065 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 30 Jun 2014 13:52:08 +0200 Subject: net: sctp: improve timer slack calculation for transport HBs RFC4960, section 8.3 says: On an idle destination address that is allowed to heartbeat, it is recommended that a HEARTBEAT chunk is sent once per RTO of that destination address plus the protocol parameter 'HB.interval', with jittering of +/- 50% of the RTO value, and exponential backoff of the RTO if the previous HEARTBEAT is unanswered. Currently, we calculate jitter via sctp_jitter() function first, and then add its result to the current RTO for the new timeout: TMO = RTO + (RAND() % RTO) - (RTO / 2) `------------------------^-=> sctp_jitter() Instead, we can just simplify all this by directly calculating: TMO = (RTO / 2) + (RAND() % RTO) With the help of prandom_u32_max(), we don't need to open code our own global PRNG, but can instead just make use of the per CPU implementation of prandom with better quality numbers. Also, we can now spare us the conditional for divide by zero check since no div or mod operation needs to be used. Note that prandom_u32_max() won't emit the same result as a mod operation, but we really don't care here as we only want to have a random number scaled into RTO interval. Note, exponential RTO backoff is handeled elsewhere, namely in sctp_do_8_2_transport_strike(). Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/net/sctp/sctp.h | 21 --------------------- net/sctp/transport.c | 17 +++++++++-------- 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 8e4de46c052e..c2035c96a2ee 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -388,27 +388,6 @@ static inline int sctp_list_single_entry(struct list_head *head) return (head->next != head) && (head->next == head->prev); } -/* Generate a random jitter in the range of -50% ~ +50% of input RTO. */ -static inline __s32 sctp_jitter(__u32 rto) -{ - static __u32 sctp_rand; - __s32 ret; - - /* Avoid divide by zero. */ - if (!rto) - rto = 1; - - sctp_rand += jiffies; - sctp_rand ^= (sctp_rand << 12); - sctp_rand ^= (sctp_rand >> 20); - - /* Choose random number from 0 to rto, then move to -50% ~ +50% - * of rto. - */ - ret = sctp_rand % rto - (rto >> 1); - return ret; -} - /* Break down data chunks at this point. */ static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu) { diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 7dd672fa651f..b10e047bbd15 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -594,15 +594,16 @@ void sctp_transport_burst_reset(struct sctp_transport *t) } /* What is the next timeout value for this transport? */ -unsigned long sctp_transport_timeout(struct sctp_transport *t) +unsigned long sctp_transport_timeout(struct sctp_transport *trans) { - unsigned long timeout; - timeout = t->rto + sctp_jitter(t->rto); - if ((t->state != SCTP_UNCONFIRMED) && - (t->state != SCTP_PF)) - timeout += t->hbinterval; - timeout += jiffies; - return timeout; + /* RTO + timer slack +/- 50% of RTO */ + unsigned long timeout = (trans->rto >> 1) + prandom_u32_max(trans->rto); + + if (trans->state != SCTP_UNCONFIRMED && + trans->state != SCTP_PF) + timeout += trans->hbinterval; + + return timeout + jiffies; } /* Reset transport variables to their initial values */ -- cgit v1.2.3 From eaea2da7286ebc56d557b40ad7e59e715a84e4a0 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 30 Jun 2014 13:52:09 +0200 Subject: net: sctp: only warn in proc_sctp_do_alpha_beta if write Only warn if the value is written to alpha or beta. We don't care emitting a one-time warning when only reading it. Reported-by: Jiri Pirko Signed-off-by: Daniel Borkmann Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- net/sctp/sysctl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 12c7e01c2677..2e9ada10fd84 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -424,8 +424,9 @@ static int proc_sctp_do_alpha_beta(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - pr_warn_once("Changing rto_alpha or rto_beta may lead to " - "suboptimal rtt/srtt estimations!\n"); + if (write) + pr_warn_once("Changing rto_alpha or rto_beta may lead to " + "suboptimal rtt/srtt estimations!\n"); return proc_dointvec_minmax(ctl, write, buffer, lenp, ppos); } -- cgit v1.2.3 From 49d7d933316375665cea49473d563cb8447d8a06 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 4 Jun 2014 08:45:15 +0000 Subject: i40e/i40evf: Do not free the dummy packet buffer synchronously The HW still needs to consume it and freeing it in the function that created it would mean we will be racing with the HW. The i40e_clean_tx_ring() routine will free up the buffer attached once the HW has consumed it. The clean_fdir_tx_irq function had to be fixed to handle the freeing correctly. Cases where we program more than one filter per flow (Ipv4), the code had to be changed to allocate dummy buffer multiple times since it will be freed by the clean routine. This also fixes an issue where the filter program routine was not checking if there were descriptors available for programming a filter. Change-ID: Idf72028fd873221934e319d021ef65a1e51acaf7 Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 21 ++++- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 109 +++++++++++++++----------- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 6 +- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 6 +- drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 6 +- 5 files changed, 96 insertions(+), 52 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 31709b8cdd5a..440b671e5d01 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3087,16 +3087,33 @@ static bool i40e_clean_fdir_tx_irq(struct i40e_ring *tx_ring, int budget) /* clear next_to_watch to prevent false hangs */ tx_buf->next_to_watch = NULL; + tx_desc->buffer_addr = 0; + tx_desc->cmd_type_offset_bsz = 0; + /* move past filter desc */ + tx_buf++; + tx_desc++; + i++; + if (unlikely(!i)) { + i -= tx_ring->count; + tx_buf = tx_ring->tx_bi; + tx_desc = I40E_TX_DESC(tx_ring, 0); + } /* unmap skb header data */ dma_unmap_single(tx_ring->dev, dma_unmap_addr(tx_buf, dma), dma_unmap_len(tx_buf, len), DMA_TO_DEVICE); + if (tx_buf->tx_flags & I40E_TX_FLAGS_FD_SB) + kfree(tx_buf->raw_buf); + tx_buf->raw_buf = NULL; + tx_buf->tx_flags = 0; + tx_buf->next_to_watch = NULL; dma_unmap_len_set(tx_buf, len, 0); + tx_desc->buffer_addr = 0; + tx_desc->cmd_type_offset_bsz = 0; - - /* move to the next desc and buffer to clean */ + /* move us past the eop_desc for start of next FD desc */ tx_buf++; tx_desc++; i++; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 051e2136715f..2c686e2dfe1d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -39,6 +39,7 @@ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, } #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS) +#define I40E_FD_CLEAN_DELAY 10 /** * i40e_program_fdir_filter - Program a Flow Director filter * @fdir_data: Packet data that will be filter parameters @@ -50,7 +51,7 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, struct i40e_pf *pf, bool add) { struct i40e_filter_program_desc *fdir_desc; - struct i40e_tx_buffer *tx_buf; + struct i40e_tx_buffer *tx_buf, *first; struct i40e_tx_desc *tx_desc; struct i40e_ring *tx_ring; unsigned int fpt, dcc; @@ -58,6 +59,7 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, struct device *dev; dma_addr_t dma; u32 td_cmd = 0; + u16 delay = 0; u16 i; /* find existing FDIR VSI */ @@ -71,6 +73,17 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, tx_ring = vsi->tx_rings[0]; dev = tx_ring->dev; + /* we need two descriptors to add/del a filter and we can wait */ + do { + if (I40E_DESC_UNUSED(tx_ring) > 1) + break; + msleep_interruptible(1); + delay++; + } while (delay < I40E_FD_CLEAN_DELAY); + + if (!(I40E_DESC_UNUSED(tx_ring) > 1)) + return -EAGAIN; + dma = dma_map_single(dev, raw_packet, I40E_FDIR_MAX_RAW_PACKET_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma)) @@ -79,8 +92,10 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, /* grab the next descriptor */ i = tx_ring->next_to_use; fdir_desc = I40E_TX_FDIRDESC(tx_ring, i); + first = &tx_ring->tx_bi[i]; + memset(first, 0, sizeof(struct i40e_tx_buffer)); - tx_ring->next_to_use = (i + 1 < tx_ring->count) ? i + 1 : 0; + tx_ring->next_to_use = ((i + 1) < tx_ring->count) ? i + 1 : 0; fpt = (fdir_data->q_index << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & I40E_TXD_FLTR_QW0_QINDEX_MASK; @@ -132,7 +147,9 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, tx_desc = I40E_TX_DESC(tx_ring, i); tx_buf = &tx_ring->tx_bi[i]; - tx_ring->next_to_use = (i + 1 < tx_ring->count) ? i + 1 : 0; + tx_ring->next_to_use = ((i + 1) < tx_ring->count) ? i + 1 : 0; + + memset(tx_buf, 0, sizeof(struct i40e_tx_buffer)); /* record length, and DMA address */ dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_SIZE); @@ -141,6 +158,9 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, tx_desc->buffer_addr = cpu_to_le64(dma); td_cmd = I40E_TXD_CMD | I40E_TX_DESC_CMD_DUMMY; + tx_buf->tx_flags = I40E_TX_FLAGS_FD_SB; + tx_buf->raw_buf = (void *)raw_packet; + tx_desc->cmd_type_offset_bsz = build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_SIZE, 0); @@ -148,14 +168,12 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, tx_buf->time_stamp = jiffies; /* Force memory writes to complete before letting h/w - * know there are new descriptors to fetch. (Only - * applicable for weak-ordered memory model archs, - * such as IA-64). + * know there are new descriptors to fetch. */ wmb(); /* Mark the data descriptor to be watched */ - tx_buf->next_to_watch = tx_desc; + first->next_to_watch = tx_desc; writel(tx_ring->next_to_use, tx_ring->tail); return 0; @@ -170,24 +188,27 @@ dma_fail: * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 filters * @vsi: pointer to the targeted VSI * @fd_data: the flow director data required for the FDir descriptor - * @raw_packet: the pre-allocated packet buffer for FDir * @add: true adds a filter, false removes it * * Returns 0 if the filters were successfully added or removed **/ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi, struct i40e_fdir_filter *fd_data, - u8 *raw_packet, bool add) + bool add) { struct i40e_pf *pf = vsi->back; struct udphdr *udp; struct iphdr *ip; bool err = false; + u8 *raw_packet; int ret; static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); + if (!raw_packet) + return -ENOMEM; memcpy(raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN); ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); @@ -220,19 +241,19 @@ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi, * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 filters * @vsi: pointer to the targeted VSI * @fd_data: the flow director data required for the FDir descriptor - * @raw_packet: the pre-allocated packet buffer for FDir * @add: true adds a filter, false removes it * * Returns 0 if the filters were successfully added or removed **/ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, struct i40e_fdir_filter *fd_data, - u8 *raw_packet, bool add) + bool add) { struct i40e_pf *pf = vsi->back; struct tcphdr *tcp; struct iphdr *ip; bool err = false; + u8 *raw_packet; int ret; /* Dummy packet */ static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, @@ -240,6 +261,9 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0x11, 0x0, 0x72, 0, 0, 0, 0}; + raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); + if (!raw_packet) + return -ENOMEM; memcpy(raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN); ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); @@ -286,7 +310,7 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, **/ static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi, struct i40e_fdir_filter *fd_data, - u8 *raw_packet, bool add) + bool add) { return -EOPNOTSUPP; } @@ -297,33 +321,36 @@ static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi, * a specific flow spec * @vsi: pointer to the targeted VSI * @fd_data: the flow director data required for the FDir descriptor - * @raw_packet: the pre-allocated packet buffer for FDir * @add: true adds a filter, false removes it * * Returns 0 if the filters were successfully added or removed **/ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi, struct i40e_fdir_filter *fd_data, - u8 *raw_packet, bool add) + bool add) { struct i40e_pf *pf = vsi->back; struct iphdr *ip; bool err = false; + u8 *raw_packet; int ret; int i; static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - memcpy(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN); - ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); - - ip->saddr = fd_data->src_ip[0]; - ip->daddr = fd_data->dst_ip[0]; - ip->protocol = 0; - for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER; i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) { + raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); + if (!raw_packet) + return -ENOMEM; + memcpy(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN); + ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); + + ip->saddr = fd_data->src_ip[0]; + ip->daddr = fd_data->dst_ip[0]; + ip->protocol = 0; + fd_data->pctype = i; ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add); @@ -353,50 +380,34 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi, struct i40e_fdir_filter *input, bool add) { struct i40e_pf *pf = vsi->back; - u8 *raw_packet; int ret; - /* Populate the Flow Director that we have at the moment - * and allocate the raw packet buffer for the calling functions - */ - raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); - if (!raw_packet) - return -ENOMEM; - switch (input->flow_type & ~FLOW_EXT) { case TCP_V4_FLOW: - ret = i40e_add_del_fdir_tcpv4(vsi, input, raw_packet, - add); + ret = i40e_add_del_fdir_tcpv4(vsi, input, add); break; case UDP_V4_FLOW: - ret = i40e_add_del_fdir_udpv4(vsi, input, raw_packet, - add); + ret = i40e_add_del_fdir_udpv4(vsi, input, add); break; case SCTP_V4_FLOW: - ret = i40e_add_del_fdir_sctpv4(vsi, input, raw_packet, - add); + ret = i40e_add_del_fdir_sctpv4(vsi, input, add); break; case IPV4_FLOW: - ret = i40e_add_del_fdir_ipv4(vsi, input, raw_packet, - add); + ret = i40e_add_del_fdir_ipv4(vsi, input, add); break; case IP_USER_FLOW: switch (input->ip4_proto) { case IPPROTO_TCP: - ret = i40e_add_del_fdir_tcpv4(vsi, input, - raw_packet, add); + ret = i40e_add_del_fdir_tcpv4(vsi, input, add); break; case IPPROTO_UDP: - ret = i40e_add_del_fdir_udpv4(vsi, input, - raw_packet, add); + ret = i40e_add_del_fdir_udpv4(vsi, input, add); break; case IPPROTO_SCTP: - ret = i40e_add_del_fdir_sctpv4(vsi, input, - raw_packet, add); + ret = i40e_add_del_fdir_sctpv4(vsi, input, add); break; default: - ret = i40e_add_del_fdir_ipv4(vsi, input, - raw_packet, add); + ret = i40e_add_del_fdir_ipv4(vsi, input, add); break; } break; @@ -406,7 +417,7 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi, ret = -EINVAL; } - kfree(raw_packet); + /* The buffer allocated here is freed by the i40e_clean_tx_ring() */ return ret; } @@ -480,7 +491,11 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring, struct i40e_tx_buffer *tx_buffer) { if (tx_buffer->skb) { - dev_kfree_skb_any(tx_buffer->skb); + if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB) + kfree(tx_buffer->raw_buf); + else + dev_kfree_skb_any(tx_buffer->skb); + if (dma_unmap_len(tx_buffer, len)) dma_unmap_single(ring->dev, dma_unmap_addr(tx_buffer, dma), diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index f09fb3ef691d..c1c356984b17 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -131,6 +131,7 @@ enum i40e_dyn_idx_t { #define I40E_TX_FLAGS_FCCRC (u32)(1 << 6) #define I40E_TX_FLAGS_FSO (u32)(1 << 7) #define I40E_TX_FLAGS_TSYN (u32)(1 << 8) +#define I40E_TX_FLAGS_FD_SB (u32)(1 << 9) #define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 #define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 @@ -139,7 +140,10 @@ enum i40e_dyn_idx_t { struct i40e_tx_buffer { struct i40e_tx_desc *next_to_watch; unsigned long time_stamp; - struct sk_buff *skb; + union { + struct sk_buff *skb; + void *raw_buf; + }; unsigned int bytecount; unsigned short gso_segs; DEFINE_DMA_UNMAP_ADDR(dma); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index f2762f5927cc..b342f212e91f 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -50,7 +50,11 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring, struct i40e_tx_buffer *tx_buffer) { if (tx_buffer->skb) { - dev_kfree_skb_any(tx_buffer->skb); + if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB) + kfree(tx_buffer->raw_buf); + else + dev_kfree_skb_any(tx_buffer->skb); + if (dma_unmap_len(tx_buffer, len)) dma_unmap_single(ring->dev, dma_unmap_addr(tx_buffer, dma), diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h index acd3c12b8f6a..8bc6858163b0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h @@ -130,6 +130,7 @@ enum i40e_dyn_idx_t { #define I40E_TX_FLAGS_IPV6 (u32)(1 << 5) #define I40E_TX_FLAGS_FCCRC (u32)(1 << 6) #define I40E_TX_FLAGS_FSO (u32)(1 << 7) +#define I40E_TX_FLAGS_FD_SB (u32)(1 << 9) #define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 #define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 @@ -138,7 +139,10 @@ enum i40e_dyn_idx_t { struct i40e_tx_buffer { struct i40e_tx_desc *next_to_watch; unsigned long time_stamp; - struct sk_buff *skb; + union { + struct sk_buff *skb; + void *raw_buf; + }; unsigned int bytecount; unsigned short gso_segs; DEFINE_DMA_UNMAP_ADDR(dma); -- cgit v1.2.3 From 4334edf53a032f54403d1f367b501502a8c61e93 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 4 Jun 2014 08:45:16 +0000 Subject: i40evf: don't violate scope Move a declaration up one level so we don't dereference it out of scope. This didn't cause any panics, but the details->async field would mysteriously disappear, causing unnecessary delays when sending AQ commands. Also, the code is just plain wrong. Change-ID: I753f64f13c55e5d75ea4351e29b14fb53b2f0104 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40e_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index a43155afdbe2..4ea90bf239bb 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -551,6 +551,7 @@ i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, struct i40e_asq_cmd_details *cmd_details) { struct i40e_aq_desc desc; + struct i40e_asq_cmd_details details; i40e_status status; i40evf_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_send_msg_to_pf); @@ -565,7 +566,6 @@ i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, desc.datalen = cpu_to_le16(msglen); } if (!cmd_details) { - struct i40e_asq_cmd_details details; memset(&details, 0, sizeof(details)); details.async = true; cmd_details = &details; -- cgit v1.2.3 From 30fe8ad3667c9060a572e48ca4ada8f3161e5d2e Mon Sep 17 00:00:00 2001 From: Paul M Stillwell Jr Date: Wed, 4 Jun 2014 08:45:17 +0000 Subject: i40e/i40evf: Force a shifted '1' to be unsigned Force a shifted '1' to be unsiged to avoid shifting a signed int Change-ID: I688cbd082af0f2e1df548fda25847a5ca04babcf Signed-off-by: Paul M Stillwell Jr Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_hmc.h | 4 ++-- drivers/net/ethernet/intel/i40evf/i40e_hmc.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_hmc.h index b45d8fedc5e7..732a02660330 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.h @@ -127,7 +127,7 @@ struct i40e_hmc_info { ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) | \ (1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ - val3 = (sd_index) | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, val1); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ @@ -146,7 +146,7 @@ struct i40e_hmc_info { I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT); \ - val3 = (sd_index) | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, 0); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h index a2ad9a4e399d..931c88044300 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h @@ -127,7 +127,7 @@ struct i40e_hmc_info { ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) | \ (1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ - val3 = (sd_index) | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, val1); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ @@ -146,7 +146,7 @@ struct i40e_hmc_info { I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT); \ - val3 = (sd_index) | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, 0); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ -- cgit v1.2.3 From 56497978bcbcde7a310ebaf2b67a936c66397593 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 4 Jun 2014 08:45:18 +0000 Subject: i40e: tolerate lost interrupts If the AQ interrupt gets lost for some reason, VF communications will stall as the VFs have no way of reaching the PF, which is essentially deaf. The VFs end up waiting forever for a reply that will never come. To alleviate this condition, go ahead and check the ARQ every time we run the service task. Remove the check for a pending event, and get rid of a chatty error message that is now meaningless. Change-ID: I0fc9d18169cd45c98f60188aef872cd6cee9a027 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 440b671e5d01..88704c049275 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5314,9 +5314,6 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf) u32 oldval; u32 val; - if (!test_bit(__I40E_ADMINQ_EVENT_PENDING, &pf->state)) - return; - /* check for error indications */ val = rd32(&pf->hw, pf->hw.aq.arq.len); oldval = val; @@ -5360,10 +5357,9 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf) do { event.msg_size = I40E_MAX_AQ_BUF_SIZE; /* reinit each time */ ret = i40e_clean_arq_element(hw, &event, &pending); - if (ret == I40E_ERR_ADMIN_QUEUE_NO_WORK) { - dev_info(&pf->pdev->dev, "No ARQ event found\n"); + if (ret == I40E_ERR_ADMIN_QUEUE_NO_WORK) break; - } else if (ret) { + else if (ret) { dev_info(&pf->pdev->dev, "ARQ event error %d\n", ret); break; } -- cgit v1.2.3 From 164ec1bfa13d34834a72b2ace3ecb521234f444f Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 4 Jun 2014 08:45:19 +0000 Subject: i40evf: invite vector 0 to the interrupt party The i40evf_irq_enable and i40evf_fire_sw_interrupt functions were unfairly discriminating against MSI-X vector 0, just because it doesn't handle traffic. That doesn't mean it's not essential to the operation of the driver. This change allows the watchdog to fire vector 0 via software, which makes the driver tolerant of dropped interrupts on that vector. Buck up, vector 0! You can be part of our gang! Change-ID: I37131d955018a6b3e711e1732d21428acd0d767e Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 5f29e58bf5ea..6186149a279e 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -260,6 +260,12 @@ static void i40evf_fire_sw_int(struct i40evf_adapter *adapter, int i; uint32_t dyn_ctl; + if (mask & 1) { + dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTL01); + dyn_ctl |= I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK | + I40E_VFINT_DYN_CTLN_CLEARPBA_MASK; + wr32(hw, I40E_VFINT_DYN_CTL01, dyn_ctl); + } for (i = 1; i < adapter->num_msix_vectors; i++) { if (mask & (1 << i)) { dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTLN1(i - 1)); @@ -278,6 +284,7 @@ void i40evf_irq_enable(struct i40evf_adapter *adapter, bool flush) { struct i40e_hw *hw = &adapter->hw; + i40evf_misc_irq_enable(adapter); i40evf_irq_enable_queues(adapter, ~0); if (flush) -- cgit v1.2.3 From 8a4f34fbef029771f686ee93311fb2b488247b16 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 4 Jun 2014 08:45:20 +0000 Subject: i40e: Fix a boundary condition and turning off of ntuple When turning off ntuple with a FD table full situation, the driver would have auto disabled FD filter additions. Clear the auto disable flag for FD_SB so that when the feature is turned on again using "ethtool -K ethx ntuple on" we can start adding filters once again. Change-ID: I036a32e7331bcae765b657c8abb4fa070940b163 Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 88704c049275..d9dcb8c0d611 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6885,9 +6885,11 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features) i40e_fdir_filter_exit(pf); } pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; - /* if ATR was disabled it can be re-enabled. */ - if (!(pf->flags & I40E_FLAG_FD_ATR_ENABLED)) - pf->flags |= I40E_FLAG_FD_ATR_ENABLED; + pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED; + /* if ATR was auto disabled it can be re-enabled. */ + if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && + (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) + pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED; } return need_reset; } -- cgit v1.2.3 From f846c1a038641de7eb2542b8537b211bdd30dd1a Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 4 Jun 2014 08:45:21 +0000 Subject: i40e: disable TPH TPH is not currently enabled in this product, make sure it isn't enabled by default. Change-ID: Ibb1a10799c33c4c76dec06fcd53b1d6efa13c1f5 Signed-off-by: Jesse Brandeburg Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ---- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index d9dcb8c0d611..ac90d5f40652 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2401,10 +2401,6 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) rx_ctx.rxmax = min_t(u16, vsi->max_frame, (chain_len * ring->rx_buf_len)); - rx_ctx.tphrdesc_ena = 1; - rx_ctx.tphwdesc_ena = 1; - rx_ctx.tphdata_ena = 1; - rx_ctx.tphhead_ena = 1; if (hw->revision_id == 0) rx_ctx.lrxqthresh = 0; else diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index d2dabae5b40c..cafda0cfc1a9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -347,10 +347,6 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_idx, rx_ctx.dsize = 1; /* default values */ - rx_ctx.tphrdesc_ena = 1; - rx_ctx.tphwdesc_ena = 1; - rx_ctx.tphdata_ena = 1; - rx_ctx.tphhead_ena = 1; rx_ctx.lrxqthresh = 2; rx_ctx.crcstrip = 1; rx_ctx.prefena = 1; -- cgit v1.2.3 From 4e91bcd5d47a92aa52a0520cb2b0c6f93c80dd6b Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 4 Jun 2014 08:45:23 +0000 Subject: i40e: Finish implementation of ethtool get settings Finish the i40e implementation of get_settings for ethtool. Change-ID: Iec81835aa9380723ae9288bcb79b30a6a1ecd498 Signed-off-by: Jesse Brandeburg Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 150 +++++++++++++++++++++---- 1 file changed, 127 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index df89b6c3db41..b105e6f321d0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -215,52 +215,135 @@ static int i40e_get_settings(struct net_device *netdev, /* hardware is either in 40G mode or 10G mode * NOTE: this section initializes supported and advertising */ + if (!link_up) { + /* link is down and the driver needs to fall back on + * device ID to determine what kinds of info to display, + * it's mostly a guess that may change when link is up + */ + switch (hw->device_id) { + case I40E_DEV_ID_QSFP_A: + case I40E_DEV_ID_QSFP_B: + case I40E_DEV_ID_QSFP_C: + /* pluggable QSFP */ + ecmd->supported = SUPPORTED_40000baseSR4_Full | + SUPPORTED_40000baseCR4_Full | + SUPPORTED_40000baseLR4_Full; + ecmd->advertising = ADVERTISED_40000baseSR4_Full | + ADVERTISED_40000baseCR4_Full | + ADVERTISED_40000baseLR4_Full; + break; + case I40E_DEV_ID_KX_B: + /* backplane 40G */ + ecmd->supported = SUPPORTED_40000baseKR4_Full; + ecmd->advertising = ADVERTISED_40000baseKR4_Full; + break; + case I40E_DEV_ID_KX_C: + /* backplane 10G */ + ecmd->supported = SUPPORTED_10000baseKR_Full; + ecmd->advertising = ADVERTISED_10000baseKR_Full; + break; + default: + /* all the rest are 10G/1G */ + ecmd->supported = SUPPORTED_10000baseT_Full | + SUPPORTED_1000baseT_Full; + ecmd->advertising = ADVERTISED_10000baseT_Full | + ADVERTISED_1000baseT_Full; + break; + } + + /* skip phy_type use as it is zero when link is down */ + goto no_valid_phy_type; + } + switch (hw_link_info->phy_type) { case I40E_PHY_TYPE_40GBASE_CR4: case I40E_PHY_TYPE_40GBASE_CR4_CU: - ecmd->supported = SUPPORTED_40000baseCR4_Full; - ecmd->advertising = ADVERTISED_40000baseCR4_Full; + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_40000baseCR4_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_40000baseCR4_Full; break; case I40E_PHY_TYPE_40GBASE_KR4: - ecmd->supported = SUPPORTED_40000baseKR4_Full; - ecmd->advertising = ADVERTISED_40000baseKR4_Full; + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_40000baseKR4_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_40000baseKR4_Full; break; case I40E_PHY_TYPE_40GBASE_SR4: + case I40E_PHY_TYPE_XLPPI: + case I40E_PHY_TYPE_XLAUI: ecmd->supported = SUPPORTED_40000baseSR4_Full; - ecmd->advertising = ADVERTISED_40000baseSR4_Full; break; case I40E_PHY_TYPE_40GBASE_LR4: ecmd->supported = SUPPORTED_40000baseLR4_Full; - ecmd->advertising = ADVERTISED_40000baseLR4_Full; break; case I40E_PHY_TYPE_10GBASE_KX4: - ecmd->supported = SUPPORTED_10000baseKX4_Full; - ecmd->advertising = ADVERTISED_10000baseKX4_Full; + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_10000baseKX4_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_10000baseKX4_Full; break; case I40E_PHY_TYPE_10GBASE_KR: - ecmd->supported = SUPPORTED_10000baseKR_Full; - ecmd->advertising = ADVERTISED_10000baseKR_Full; + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_10000baseKR_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_10000baseKR_Full; break; - default: - if (i40e_is_40G_device(hw->device_id)) { - ecmd->supported = SUPPORTED_40000baseSR4_Full; - ecmd->advertising = ADVERTISED_40000baseSR4_Full; - } else { - ecmd->supported = SUPPORTED_10000baseT_Full; - ecmd->advertising = ADVERTISED_10000baseT_Full; - } + case I40E_PHY_TYPE_10GBASE_SR: + case I40E_PHY_TYPE_10GBASE_LR: + ecmd->supported = SUPPORTED_10000baseT_Full; + break; + case I40E_PHY_TYPE_10GBASE_CR1_CU: + case I40E_PHY_TYPE_10GBASE_CR1: + case I40E_PHY_TYPE_10GBASE_T: + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_10000baseT_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_10000baseT_Full; + break; + case I40E_PHY_TYPE_XAUI: + case I40E_PHY_TYPE_XFI: + case I40E_PHY_TYPE_SFI: + case I40E_PHY_TYPE_10GBASE_SFPP_CU: + ecmd->supported = SUPPORTED_10000baseT_Full; break; + case I40E_PHY_TYPE_1000BASE_KX: + case I40E_PHY_TYPE_1000BASE_T: + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_1000baseT_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_1000baseT_Full; + break; + case I40E_PHY_TYPE_100BASE_TX: + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_100baseT_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_100baseT_Full; + break; + case I40E_PHY_TYPE_SGMII: + ecmd->supported = SUPPORTED_Autoneg | + SUPPORTED_1000baseT_Full | + SUPPORTED_100baseT_Full; + ecmd->advertising = ADVERTISED_Autoneg | + ADVERTISED_1000baseT_Full | + ADVERTISED_100baseT_Full; + break; + default: + /* if we got here and link is up something bad is afoot */ + WARN_ON(link_up); } - ecmd->supported |= SUPPORTED_Autoneg; - ecmd->advertising |= ADVERTISED_Autoneg; +no_valid_phy_type: + /* this is if autoneg is enabled or disabled */ ecmd->autoneg = ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ? AUTONEG_ENABLE : AUTONEG_DISABLE); switch (hw->phy.media_type) { case I40E_MEDIA_TYPE_BACKPLANE: - ecmd->supported |= SUPPORTED_Backplane; - ecmd->advertising |= ADVERTISED_Backplane; + ecmd->supported |= SUPPORTED_Autoneg | + SUPPORTED_Backplane; + ecmd->advertising |= ADVERTISED_Autoneg | + ADVERTISED_Backplane; ecmd->port = PORT_NONE; break; case I40E_MEDIA_TYPE_BASET: @@ -276,7 +359,6 @@ static int i40e_get_settings(struct net_device *netdev, break; case I40E_MEDIA_TYPE_FIBER: ecmd->supported |= SUPPORTED_FIBRE; - ecmd->advertising |= ADVERTISED_FIBRE; ecmd->port = PORT_FIBRE; break; case I40E_MEDIA_TYPE_UNKNOWN: @@ -287,6 +369,25 @@ static int i40e_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_EXTERNAL; + ecmd->supported |= SUPPORTED_Pause; + + switch (hw->fc.current_mode) { + case I40E_FC_FULL: + ecmd->advertising |= ADVERTISED_Pause; + break; + case I40E_FC_TX_PAUSE: + ecmd->advertising |= ADVERTISED_Asym_Pause; + break; + case I40E_FC_RX_PAUSE: + ecmd->advertising |= (ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + break; + default: + ecmd->advertising &= ~(ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + break; + } + if (link_up) { switch (link_speed) { case I40E_LINK_SPEED_40GB: @@ -296,6 +397,9 @@ static int i40e_get_settings(struct net_device *netdev, case I40E_LINK_SPEED_10GB: ethtool_cmd_speed_set(ecmd, SPEED_10000); break; + case I40E_LINK_SPEED_1GB: + ethtool_cmd_speed_set(ecmd, SPEED_1000); + break; default: break; } -- cgit v1.2.3 From 8109e1232b3e5322415a9b5e09951617c5fae277 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 08:45:24 +0000 Subject: i40e/i40evf: Add new HW link info variable an_enabled and function update_link_info Add a new variable, hw.phy.link_info.an_enabled, to track whether autoneg is enabled. Also add a new function update_link_info that will update that variable as well as calling get_link_info to update the rest of the link info. Also add get_phy_capabilities to support this. Change-ID: I5157ef03492b6dd8ec5e608ba0cf9b0db9c01710 Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 75 ++++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_main.c | 4 +- drivers/net/ethernet/intel/i40e/i40e_prototype.h | 1 + drivers/net/ethernet/intel/i40e/i40e_type.h | 1 + drivers/net/ethernet/intel/i40evf/i40e_type.h | 1 + 5 files changed, 80 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 9d09ab31ec89..debca01e684f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1036,6 +1036,52 @@ void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink) /* Admin command wrappers */ +/** + * i40e_aq_get_phy_capabilities + * @hw: pointer to the hw struct + * @abilities: structure for PHY capabilities to be filled + * @qualified_modules: report Qualified Modules + * @report_init: report init capabilities (active are default) + * @cmd_details: pointer to command details structure or NULL + * + * Returns the various PHY abilities supported on the Port. + **/ +i40e_status i40e_aq_get_phy_capabilities(struct i40e_hw *hw, + bool qualified_modules, bool report_init, + struct i40e_aq_get_phy_abilities_resp *abilities, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + i40e_status status; + u16 abilities_size = sizeof(struct i40e_aq_get_phy_abilities_resp); + + if (!abilities) + return I40E_ERR_PARAM; + + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_get_phy_abilities); + + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF); + if (abilities_size > I40E_AQ_LARGE_BUF) + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB); + + if (qualified_modules) + desc.params.external.param0 |= + cpu_to_le32(I40E_AQ_PHY_REPORT_QUALIFIED_MODULES); + + if (report_init) + desc.params.external.param0 |= + cpu_to_le32(I40E_AQ_PHY_REPORT_INITIAL_VALUES); + + status = i40e_asq_send_command(hw, &desc, abilities, abilities_size, + cmd_details); + + if (hw->aq.asq_last_status == I40E_AQ_RC_EIO) + status = I40E_ERR_UNKNOWN_PHY; + + return status; +} + /** * i40e_aq_clear_pxe_mode * @hw: pointer to the hw struct @@ -1162,6 +1208,35 @@ aq_get_link_info_exit: return status; } +/** + * i40e_update_link_info + * @hw: pointer to the hw struct + * @enable_lse: enable/disable LinkStatusEvent reporting + * + * Returns the link status of the adapter + **/ +i40e_status i40e_update_link_info(struct i40e_hw *hw, bool enable_lse) +{ + struct i40e_aq_get_phy_abilities_resp abilities; + i40e_status status; + + status = i40e_aq_get_link_info(hw, enable_lse, NULL, NULL); + if (status) + return status; + + status = i40e_aq_get_phy_capabilities(hw, false, false, + &abilities, NULL); + if (status) + return status; + + if (abilities.abilities & I40E_AQ_PHY_AN_ENABLED) + hw->phy.link_info.an_enabled = true; + else + hw->phy.link_info.an_enabled = false; + + return status; +} + /** * i40e_aq_add_vsi * @hw: pointer to the hw struct diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index ac90d5f40652..71eff1676778 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5292,7 +5292,7 @@ static void i40e_handle_link_event(struct i40e_pf *pf, * then see if the status changed while processing the * initial event. */ - i40e_aq_get_link_info(&pf->hw, true, NULL, NULL); + i40e_update_link_info(&pf->hw, true); i40e_link_event(pf); } @@ -8337,7 +8337,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit) i40e_config_rss(pf); /* fill in link information and enable LSE reporting */ - i40e_aq_get_link_info(&pf->hw, true, NULL, NULL); + i40e_update_link_info(&pf->hw, true); i40e_link_event(pf); /* Initialize user-specific link properties */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 77c515d026be..679087867bd2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -82,6 +82,7 @@ i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw, i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, bool enable_lse, struct i40e_link_status *link, struct i40e_asq_cmd_details *cmd_details); +i40e_status i40e_update_link_info(struct i40e_hw *hw, bool enable_lse); i40e_status i40e_aq_set_local_advt_reg(struct i40e_hw *hw, u64 advt_reg, struct i40e_asq_cmd_details *cmd_details); diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 11dd2dcfb592..f1c58ab8f60d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -166,6 +166,7 @@ struct i40e_link_status { u8 an_info; u8 ext_info; u8 loopback; + bool an_enabled; /* is Link Status Event notification to SW enabled */ bool lse_enable; u16 max_frame_size; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 23cd18b66b71..5b6e955cfc66 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -166,6 +166,7 @@ struct i40e_link_status { u8 an_info; u8 ext_info; u8 loopback; + bool an_enabled; /* is Link Status Event notification to SW enabled */ bool lse_enable; u16 max_frame_size; -- cgit v1.2.3 From a65997215be9f54dbc927b05fc8eb2fe55912d11 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 4 Jun 2014 08:45:25 +0000 Subject: i40e: move nway reset Just move nway reset up, will be used in the next patch. Change-ID: Ice3b631fa2044debc5c4541b42872a48163f8452 Signed-off-by: Jesse Brandeburg Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 38 +++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index b105e6f321d0..6508a1b64a7e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -412,6 +412,25 @@ no_valid_phy_type: return 0; } +static int i40e_nway_reset(struct net_device *netdev) +{ + /* restart autonegotiation */ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + struct i40e_hw *hw = &pf->hw; + bool link_up = hw->phy.link_info.link_info & I40E_AQ_LINK_UP; + i40e_status ret = 0; + + ret = i40e_aq_set_link_restart_an(hw, link_up, NULL); + if (ret) { + netdev_info(netdev, "link restart failed, aq_err=%d\n", + pf->hw.aq.asq_last_status); + return -EIO; + } + + return 0; +} + /** * i40e_get_pauseparam - Get Flow Control status * Return tx/rx-pause status @@ -1125,25 +1144,6 @@ static int i40e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) return 0; } -static int i40e_nway_reset(struct net_device *netdev) -{ - /* restart autonegotiation */ - struct i40e_netdev_priv *np = netdev_priv(netdev); - struct i40e_pf *pf = np->vsi->back; - struct i40e_hw *hw = &pf->hw; - bool link_up = hw->phy.link_info.link_info & I40E_AQ_LINK_UP; - i40e_status ret = 0; - - ret = i40e_aq_set_link_restart_an(hw, link_up, NULL); - if (ret) { - netdev_info(netdev, "link restart failed, aq_err=%d\n", - pf->hw.aq.asq_last_status); - return -EIO; - } - - return 0; -} - static int i40e_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) { -- cgit v1.2.3 From c56999f94876b21cf18301076b9687ecdafdc9e5 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 08:45:26 +0000 Subject: i40e/i40evf: Add set_fc and init of FC settings Add function set_fc to set the requested FC mode. This patch also adds the init of FC setting to get_link_info and replaces the init code to set FC off by default in main. Also adds i40e_set_phy_config to support this. Change-ID: I7b25bbaec81f15777137ab324a095f916e44351d Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 125 +++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_main.c | 60 +---------- drivers/net/ethernet/intel/i40e/i40e_prototype.h | 9 ++ drivers/net/ethernet/intel/i40e/i40e_type.h | 8 ++ drivers/net/ethernet/intel/i40evf/i40e_type.h | 8 ++ 5 files changed, 154 insertions(+), 56 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index debca01e684f..bf808d4cb7b8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1082,6 +1082,118 @@ i40e_status i40e_aq_get_phy_capabilities(struct i40e_hw *hw, return status; } +/** + * i40e_aq_set_phy_config + * @hw: pointer to the hw struct + * @config: structure with PHY configuration to be set + * @cmd_details: pointer to command details structure or NULL + * + * Set the various PHY configuration parameters + * supported on the Port.One or more of the Set PHY config parameters may be + * ignored in an MFP mode as the PF may not have the privilege to set some + * of the PHY Config parameters. This status will be indicated by the + * command response. + **/ +enum i40e_status_code i40e_aq_set_phy_config(struct i40e_hw *hw, + struct i40e_aq_set_phy_config *config, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aq_set_phy_config *cmd = + (struct i40e_aq_set_phy_config *)&desc.params.raw; + enum i40e_status_code status; + + if (!config) + return I40E_ERR_PARAM; + + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_set_phy_config); + + *cmd = *config; + + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + + return status; +} + +/** + * i40e_set_fc + * @hw: pointer to the hw struct + * + * Set the requested flow control mode using set_phy_config. + **/ +enum i40e_status_code i40e_set_fc(struct i40e_hw *hw, u8 *aq_failures, + bool atomic_restart) +{ + enum i40e_fc_mode fc_mode = hw->fc.requested_mode; + struct i40e_aq_get_phy_abilities_resp abilities; + struct i40e_aq_set_phy_config config; + enum i40e_status_code status; + u8 pause_mask = 0x0; + + *aq_failures = 0x0; + + switch (fc_mode) { + case I40E_FC_FULL: + pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_TX; + pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_RX; + break; + case I40E_FC_RX_PAUSE: + pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_RX; + break; + case I40E_FC_TX_PAUSE: + pause_mask |= I40E_AQ_PHY_FLAG_PAUSE_TX; + break; + default: + break; + } + + /* Get the current phy config */ + status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities, + NULL); + if (status) { + *aq_failures |= I40E_SET_FC_AQ_FAIL_GET; + return status; + } + + memset(&config, 0, sizeof(struct i40e_aq_set_phy_config)); + /* clear the old pause settings */ + config.abilities = abilities.abilities & ~(I40E_AQ_PHY_FLAG_PAUSE_TX) & + ~(I40E_AQ_PHY_FLAG_PAUSE_RX); + /* set the new abilities */ + config.abilities |= pause_mask; + /* If the abilities have changed, then set the new config */ + if (config.abilities != abilities.abilities) { + /* Auto restart link so settings take effect */ + if (atomic_restart) + config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK; + /* Copy over all the old settings */ + config.phy_type = abilities.phy_type; + config.link_speed = abilities.link_speed; + config.eee_capability = abilities.eee_capability; + config.eeer = abilities.eeer_val; + config.low_power_ctrl = abilities.d3_lpan; + status = i40e_aq_set_phy_config(hw, &config, NULL); + + if (status) + *aq_failures |= I40E_SET_FC_AQ_FAIL_SET; + } + /* Update the link info */ + status = i40e_update_link_info(hw, true); + if (status) { + /* Wait a little bit (on 40G cards it sometimes takes a really + * long time for link to come back from the atomic reset) + * and try once more + */ + msleep(1000); + status = i40e_update_link_info(hw, true); + } + if (status) + *aq_failures |= I40E_SET_FC_AQ_FAIL_UPDATE; + + return status; +} + /** * i40e_aq_clear_pxe_mode * @hw: pointer to the hw struct @@ -1158,6 +1270,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, (struct i40e_aqc_get_link_status *)&desc.params.raw; struct i40e_link_status *hw_link_info = &hw->phy.link_info; i40e_status status; + bool tx_pause, rx_pause; u16 command_flags; i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_get_link_status); @@ -1187,6 +1300,18 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, hw_link_info->max_frame_size = le16_to_cpu(resp->max_frame_size); hw_link_info->pacing = resp->config & I40E_AQ_CONFIG_PACING_MASK; + /* update fc info */ + tx_pause = !!(resp->an_info & I40E_AQ_LINK_PAUSE_TX); + rx_pause = !!(resp->an_info & I40E_AQ_LINK_PAUSE_RX); + if (tx_pause & rx_pause) + hw->fc.current_mode = I40E_FC_FULL; + else if (tx_pause) + hw->fc.current_mode = I40E_FC_TX_PAUSE; + else if (rx_pause) + hw->fc.current_mode = I40E_FC_RX_PAUSE; + else + hw->fc.current_mode = I40E_FC_NONE; + if (resp->config & I40E_AQ_CONFIG_CRC_ENA) hw_link_info->crc_enable = true; else diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 71eff1676778..44cea6a854c2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4326,8 +4326,12 @@ static void i40e_print_link_message(struct i40e_vsi *vsi, bool isup) static int i40e_up_complete(struct i40e_vsi *vsi) { struct i40e_pf *pf = vsi->back; + u8 set_fc_aq_fail = 0; int err; + /* force flow control off */ + i40e_set_fc(&pf->hw, &set_fc_aq_fail, true); + if (pf->flags & I40E_FLAG_MSIX_ENABLED) i40e_vsi_configure_msix(vsi); else @@ -8277,7 +8281,6 @@ int i40e_fetch_switch_configuration(struct i40e_pf *pf, bool printconfig) **/ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit) { - u32 rxfc = 0, txfc = 0, rxfc_reg; int ret; /* find out what's out there already */ @@ -8343,62 +8346,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit) /* Initialize user-specific link properties */ pf->fc_autoneg_status = ((pf->hw.phy.link_info.an_info & I40E_AQ_AN_COMPLETED) ? true : false); - /* requested_mode is set in probe or by ethtool */ - if (!pf->fc_autoneg_status) - goto no_autoneg; - - if ((pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) && - (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)) - pf->hw.fc.current_mode = I40E_FC_FULL; - else if (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) - pf->hw.fc.current_mode = I40E_FC_TX_PAUSE; - else if (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) - pf->hw.fc.current_mode = I40E_FC_RX_PAUSE; - else - pf->hw.fc.current_mode = I40E_FC_NONE; - - /* sync the flow control settings with the auto-neg values */ - switch (pf->hw.fc.current_mode) { - case I40E_FC_FULL: - txfc = 1; - rxfc = 1; - break; - case I40E_FC_TX_PAUSE: - txfc = 1; - rxfc = 0; - break; - case I40E_FC_RX_PAUSE: - txfc = 0; - rxfc = 1; - break; - case I40E_FC_NONE: - case I40E_FC_DEFAULT: - txfc = 0; - rxfc = 0; - break; - case I40E_FC_PFC: - /* TBD */ - break; - /* no default case, we have to handle all possibilities here */ - } - - wr32(&pf->hw, I40E_PRTDCB_FCCFG, txfc << I40E_PRTDCB_FCCFG_TFCE_SHIFT); - - rxfc_reg = rd32(&pf->hw, I40E_PRTDCB_MFLCN) & - ~I40E_PRTDCB_MFLCN_RFCE_MASK; - rxfc_reg |= (rxfc << I40E_PRTDCB_MFLCN_RFCE_SHIFT); - - wr32(&pf->hw, I40E_PRTDCB_MFLCN, rxfc_reg); - - goto fc_complete; - -no_autoneg: - /* disable L2 flow control, user can turn it on if they wish */ - wr32(&pf->hw, I40E_PRTDCB_FCCFG, 0); - wr32(&pf->hw, I40E_PRTDCB_MFLCN, rd32(&pf->hw, I40E_PRTDCB_MFLCN) & - ~I40E_PRTDCB_MFLCN_RFCE_MASK); -fc_complete: i40e_ptp_init(pf); return ret; diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 679087867bd2..b6849fb47db7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -74,6 +74,15 @@ i40e_status i40e_aq_set_phy_debug(struct i40e_hw *hw, u8 cmd_flags, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_default_vsi(struct i40e_hw *hw, u16 vsi_id, struct i40e_asq_cmd_details *cmd_details); +enum i40e_status_code i40e_aq_get_phy_capabilities(struct i40e_hw *hw, + bool qualified_modules, bool report_init, + struct i40e_aq_get_phy_abilities_resp *abilities, + struct i40e_asq_cmd_details *cmd_details); +enum i40e_status_code i40e_aq_set_phy_config(struct i40e_hw *hw, + struct i40e_aq_set_phy_config *config, + struct i40e_asq_cmd_details *cmd_details); +enum i40e_status_code i40e_set_fc(struct i40e_hw *hw, u8 *aq_failures, + bool atomic_reset); i40e_status i40e_aq_clear_pxe_mode(struct i40e_hw *hw, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw, diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index f1c58ab8f60d..380eb53a83b3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -140,6 +140,14 @@ enum i40e_fc_mode { I40E_FC_DEFAULT }; +enum i40e_set_fc_aq_failures { + I40E_SET_FC_AQ_FAIL_NONE = 0, + I40E_SET_FC_AQ_FAIL_GET = 1, + I40E_SET_FC_AQ_FAIL_SET = 2, + I40E_SET_FC_AQ_FAIL_UPDATE = 4, + I40E_SET_FC_AQ_FAIL_SET_UPDATE = 6 +}; + enum i40e_vsi_type { I40E_VSI_MAIN = 0, I40E_VSI_VMDQ1, diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 5b6e955cfc66..6dd72ad58e7d 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -140,6 +140,14 @@ enum i40e_fc_mode { I40E_FC_DEFAULT }; +enum i40e_set_fc_aq_failures { + I40E_SET_FC_AQ_FAIL_NONE = 0, + I40E_SET_FC_AQ_FAIL_GET = 1, + I40E_SET_FC_AQ_FAIL_SET = 2, + I40E_SET_FC_AQ_FAIL_UPDATE = 4, + I40E_SET_FC_AQ_FAIL_SET_UPDATE = 6 +}; + enum i40e_vsi_type { I40E_VSI_MAIN = 0, I40E_VSI_VMDQ1, -- cgit v1.2.3 From 2becc35aa74cbaf9c84e6ae166faab7a321d25ca Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 08:45:27 +0000 Subject: i40e: Add set_pauseparam to ethtool Add i40e implementation of setpauseparam to ethtool. Change-ID: Ie7766b2091ec8f934737573c9ffd426081966718 Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 76 ++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 6508a1b64a7e..fc86761950d0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -457,6 +457,81 @@ static void i40e_get_pauseparam(struct net_device *netdev, } } +/** + * i40e_set_pauseparam - Set Flow Control parameter + * @netdev: network interface device structure + * @pause: return tx/rx flow control status + **/ +static int i40e_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + struct i40e_vsi *vsi = np->vsi; + struct i40e_hw *hw = &pf->hw; + struct i40e_link_status *hw_link_info = &hw->phy.link_info; + bool link_up = hw_link_info->link_info & I40E_AQ_LINK_UP; + i40e_status status; + u8 aq_failures; + int err; + + if (vsi != pf->vsi[pf->lan_vsi]) + return -EOPNOTSUPP; + + if (pause->autoneg != ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ? + AUTONEG_ENABLE : AUTONEG_DISABLE)) { + netdev_info(netdev, "To change autoneg please use: ethtool -s autoneg \n"); + return -EOPNOTSUPP; + } + + /* If we have link and don't have autoneg */ + if (!test_bit(__I40E_DOWN, &pf->state) && + !(hw_link_info->an_info & I40E_AQ_AN_COMPLETED)) { + /* Send message that it might not necessarily work*/ + netdev_info(netdev, "Autoneg did not complete so changing settings may not result in an actual change.\n"); + } + + if (hw->fc.current_mode == I40E_FC_PFC) { + netdev_info(netdev, "Priority flow control enabled. Cannot set link flow control.\n"); + return -EOPNOTSUPP; + } + + if (pause->rx_pause && pause->tx_pause) + hw->fc.requested_mode = I40E_FC_FULL; + else if (pause->rx_pause && !pause->tx_pause) + hw->fc.requested_mode = I40E_FC_RX_PAUSE; + else if (!pause->rx_pause && pause->tx_pause) + hw->fc.requested_mode = I40E_FC_TX_PAUSE; + else if (!pause->rx_pause && !pause->tx_pause) + hw->fc.requested_mode = I40E_FC_NONE; + else + return -EINVAL; + + /* Set the fc mode and only restart an if link is up*/ + status = i40e_set_fc(hw, &aq_failures, link_up); + + if (aq_failures & I40E_SET_FC_AQ_FAIL_GET) { + netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with error %d and status %d\n", + status, hw->aq.asq_last_status); + err = -EAGAIN; + } + if (aq_failures & I40E_SET_FC_AQ_FAIL_SET) { + netdev_info(netdev, "Set fc failed on the set_phy_config call with error %d and status %d\n", + status, hw->aq.asq_last_status); + err = -EAGAIN; + } + if (aq_failures & I40E_SET_FC_AQ_FAIL_UPDATE) { + netdev_info(netdev, "Set fc failed on the update_link_info call with error %d and status %d\n", + status, hw->aq.asq_last_status); + err = -EAGAIN; + } + + if (!test_bit(__I40E_DOWN, &pf->state)) + return i40e_nway_reset(netdev); + + return err; +} + static u32 i40e_get_msglevel(struct net_device *netdev) { struct i40e_netdev_priv *np = netdev_priv(netdev); @@ -1866,6 +1941,7 @@ static const struct ethtool_ops i40e_ethtool_ops = { .get_ringparam = i40e_get_ringparam, .set_ringparam = i40e_set_ringparam, .get_pauseparam = i40e_get_pauseparam, + .set_pauseparam = i40e_set_pauseparam, .get_msglevel = i40e_get_msglevel, .set_msglevel = i40e_set_msglevel, .get_rxnfc = i40e_get_rxnfc, -- cgit v1.2.3 From bf9c71417f721abf6853d0ae56be8cf228f92888 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 08:45:28 +0000 Subject: i40e: Implement set_settings for ethtool Implement set_settings for ethtool in i40e. Change-ID: Ie3c3fe18e8ff86c3f25b842844b3d9aabc9bba57 Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 158 +++++++++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index fc86761950d0..3abd3cbab75f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -412,6 +412,163 @@ no_valid_phy_type: return 0; } +/** + * i40e_set_settings - Set Speed and Duplex + * @netdev: network interface device structure + * @ecmd: ethtool command + * + * Set speed/duplex per media_types advertised/forced + **/ +static int i40e_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_aq_get_phy_abilities_resp abilities; + struct i40e_aq_set_phy_config config; + struct i40e_pf *pf = np->vsi->back; + struct i40e_vsi *vsi = np->vsi; + struct i40e_hw *hw = &pf->hw; + struct ethtool_cmd safe_ecmd; + i40e_status status = 0; + bool change = false; + int err = 0; + u8 autoneg; + u32 advertise; + + if (vsi != pf->vsi[pf->lan_vsi]) + return -EOPNOTSUPP; + + if (hw->phy.media_type != I40E_MEDIA_TYPE_BASET && + hw->phy.media_type != I40E_MEDIA_TYPE_FIBER && + hw->phy.media_type != I40E_MEDIA_TYPE_BACKPLANE) + return -EOPNOTSUPP; + + /* get our own copy of the bits to check against */ + memset(&safe_ecmd, 0, sizeof(struct ethtool_cmd)); + i40e_get_settings(netdev, &safe_ecmd); + + /* save autoneg and speed out of ecmd */ + autoneg = ecmd->autoneg; + advertise = ecmd->advertising; + + /* set autoneg and speed back to what they currently are */ + ecmd->autoneg = safe_ecmd.autoneg; + ecmd->advertising = safe_ecmd.advertising; + + ecmd->cmd = safe_ecmd.cmd; + /* If ecmd and safe_ecmd are not the same now, then they are + * trying to set something that we do not support + */ + if (memcmp(ecmd, &safe_ecmd, sizeof(struct ethtool_cmd))) + return -EOPNOTSUPP; + + while (test_bit(__I40E_CONFIG_BUSY, &vsi->state)) + usleep_range(1000, 2000); + + /* Get the current phy config */ + status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities, + NULL); + if (status) + return -EAGAIN; + + /* Copy link_speed and abilities to config in case they are not + * set below + */ + memset(&config, 0, sizeof(struct i40e_aq_set_phy_config)); + config.link_speed = abilities.link_speed; + config.abilities = abilities.abilities; + + /* Check autoneg */ + if (autoneg == AUTONEG_ENABLE) { + /* If autoneg is not supported, return error */ + if (!(safe_ecmd.supported & SUPPORTED_Autoneg)) { + netdev_info(netdev, "Autoneg not supported on this phy\n"); + return -EINVAL; + } + /* If autoneg was not already enabled */ + if (!(hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED)) { + config.abilities = abilities.abilities | + I40E_AQ_PHY_ENABLE_AN; + change = true; + } + } else { + /* If autoneg is supported 10GBASE_T is the only phy that + * can disable it, so otherwise return error + */ + if (safe_ecmd.supported & SUPPORTED_Autoneg && + hw->phy.link_info.phy_type != I40E_PHY_TYPE_10GBASE_T) { + netdev_info(netdev, "Autoneg cannot be disabled on this phy\n"); + return -EINVAL; + } + /* If autoneg is currently enabled */ + if (hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED) { + config.abilities = abilities.abilities | + ~I40E_AQ_PHY_ENABLE_AN; + change = true; + } + } + + if (advertise & ~safe_ecmd.supported) + return -EINVAL; + + if (advertise & ADVERTISED_100baseT_Full) + if (!(abilities.link_speed & I40E_LINK_SPEED_100MB)) { + config.link_speed |= I40E_LINK_SPEED_100MB; + change = true; + } + if (advertise & ADVERTISED_1000baseT_Full || + advertise & ADVERTISED_1000baseKX_Full) + if (!(abilities.link_speed & I40E_LINK_SPEED_1GB)) { + config.link_speed |= I40E_LINK_SPEED_1GB; + change = true; + } + if (advertise & ADVERTISED_10000baseT_Full || + advertise & ADVERTISED_10000baseKX4_Full || + advertise & ADVERTISED_10000baseKR_Full) + if (!(abilities.link_speed & I40E_LINK_SPEED_10GB)) { + config.link_speed |= I40E_LINK_SPEED_10GB; + change = true; + } + if (advertise & ADVERTISED_40000baseKR4_Full || + advertise & ADVERTISED_40000baseCR4_Full || + advertise & ADVERTISED_40000baseSR4_Full || + advertise & ADVERTISED_40000baseLR4_Full) + if (!(abilities.link_speed & I40E_LINK_SPEED_40GB)) { + config.link_speed |= I40E_LINK_SPEED_40GB; + change = true; + } + + if (change) { + /* copy over the rest of the abilities */ + config.phy_type = abilities.phy_type; + config.eee_capability = abilities.eee_capability; + config.eeer = abilities.eeer_val; + config.low_power_ctrl = abilities.d3_lpan; + + /* If link is up set link and an so changes take effect */ + if (hw->phy.link_info.link_info & I40E_AQ_LINK_UP) + config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK; + + /* make the aq call */ + status = i40e_aq_set_phy_config(hw, &config, NULL); + if (status) { + netdev_info(netdev, "Set phy config failed with error %d.\n", + status); + return -EAGAIN; + } + + status = i40e_update_link_info(hw, true); + if (status) + netdev_info(netdev, "Updating link info failed with error %d\n", + status); + + } else { + netdev_info(netdev, "Nothing changed, exiting without setting anything.\n"); + } + + return err; +} + static int i40e_nway_reset(struct net_device *netdev) { /* restart autonegotiation */ @@ -1929,6 +2086,7 @@ static int i40e_set_channels(struct net_device *dev, static const struct ethtool_ops i40e_ethtool_ops = { .get_settings = i40e_get_settings, + .set_settings = i40e_set_settings, .get_drvinfo = i40e_get_drvinfo, .get_regs_len = i40e_get_regs_len, .get_regs = i40e_get_regs, -- cgit v1.2.3 From 4e776381e0ea81500129ebaa213048e257d79e69 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 4 Jun 2014 08:45:29 +0000 Subject: i40e/i40evf: Bump i40e to 0.4.21 and i40evf to 0.9.40 Bump. Change-ID: Ie0c36583ffd9997679f46bdf89bc462d3e992995 Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 44cea6a854c2..e49352d68ede 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 4 -#define DRV_VERSION_BUILD 19 +#define DRV_VERSION_BUILD 21 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 6186149a279e..1b980fb88cdd 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710/X710 Virtual Function Network Driver"; -#define DRV_VERSION "0.9.38" +#define DRV_VERSION "0.9.40" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; -- cgit v1.2.3 From b0c3e138b467a5cc3b2eb44c6525227f66d1496d Mon Sep 17 00:00:00 2001 From: Adam Lee Date: Thu, 5 Jun 2014 21:47:44 +0800 Subject: Bluetooth: ath3k: reduce pipe setting times in ath3k_load_fwfile() Invoking usb_sndbulkpipe() on same pipe for same purpose only once is enough. Signed-off-by: Adam Lee Signed-off-by: Gustavo Padovan --- drivers/bluetooth/ath3k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index f50dffc0374f..abe6aecbabb2 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -288,10 +288,10 @@ static int ath3k_load_fwfile(struct usb_device *udev, sent += size; count -= size; + pipe = usb_sndbulkpipe(udev, 0x02); + while (count) { size = min_t(uint, count, BULK_SIZE); - pipe = usb_sndbulkpipe(udev, 0x02); - memcpy(send_buf, firmware->data + sent, size); err = usb_bulk_msg(udev, pipe, send_buf, size, -- cgit v1.2.3 From 67f86a45bb82091a2775561a1e498010afff54ee Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 8 Jun 2014 10:05:31 +0200 Subject: Bluetooth: Use const for struct l2cap_ops field The struct l2cap_ops field should not allow any modifications and thus it is better declared as const. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/a2mp.c | 2 +- net/bluetooth/l2cap_sock.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 4abdcb220e3a..cf67420616e5 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -579,7 +579,7 @@ struct l2cap_chan { struct list_head global_l; void *data; - struct l2cap_ops *ops; + const struct l2cap_ops *ops; struct mutex lock; }; diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 9514cc9e850c..1996b4c4dfd5 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -704,7 +704,7 @@ static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan, return skb; } -static struct l2cap_ops a2mp_chan_ops = { +static const struct l2cap_ops a2mp_chan_ops = { .name = "L2CAP A2MP channel", .recv = a2mp_chan_recv_cb, .close = a2mp_chan_close_cb, diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index e1378693cc90..11e2207717b6 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1375,7 +1375,7 @@ static void l2cap_sock_suspend_cb(struct l2cap_chan *chan) sk->sk_state_change(sk); } -static struct l2cap_ops l2cap_chan_ops = { +static const struct l2cap_ops l2cap_chan_ops = { .name = "L2CAP Socket Interface", .new_connection = l2cap_sock_new_connection_cb, .recv = l2cap_sock_recv_cb, -- cgit v1.2.3 From 8d46321c4f63f7c2be9e3ba0bb26cb437fc5eded Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 5 Jun 2014 15:22:51 +0200 Subject: Bluetooth: Assign L2CAP socket priority when allocating SKB The SKB for L2CAP sockets are all allocated in a central callback in the socket support. Instead of having to pass around the socket priority all the time, assign it to skb->priority when actually allocating the SKB. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 3 +-- net/bluetooth/a2mp.c | 2 +- net/bluetooth/l2cap_core.c | 23 +++++++---------------- net/bluetooth/l2cap_sock.c | 4 +++- 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index cf67420616e5..18f4f27e0f74 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -872,8 +872,7 @@ struct l2cap_chan *l2cap_chan_create(void); void l2cap_chan_close(struct l2cap_chan *chan, int reason); int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst, u8 dst_type); -int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, - u32 priority); +int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); int l2cap_chan_check_security(struct l2cap_chan *chan); void l2cap_chan_set_defaults(struct l2cap_chan *chan); diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 1996b4c4dfd5..1a5b1eb96d1a 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -63,7 +63,7 @@ void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data) msg.msg_iov = (struct iovec *) &iv; msg.msg_iovlen = 1; - l2cap_chan_send(chan, &msg, total_len, 0); + l2cap_chan_send(chan, &msg, total_len); kfree(cmd); } diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 323f23cd2c37..3dca28246cbe 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2141,8 +2141,6 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) return -EFAULT; - (*frag)->priority = skb->priority; - sent += count; len -= count; @@ -2156,16 +2154,15 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, } static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, - struct msghdr *msg, size_t len, - u32 priority) + struct msghdr *msg, size_t len) { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE; struct l2cap_hdr *lh; - BT_DBG("chan %p psm 0x%2.2x len %zu priority %u", chan, - __le16_to_cpu(chan->psm), len, priority); + BT_DBG("chan %p psm 0x%2.2x len %zu", chan, + __le16_to_cpu(chan->psm), len); count = min_t(unsigned int, (conn->mtu - hlen), len); @@ -2174,8 +2171,6 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, if (IS_ERR(skb)) return skb; - skb->priority = priority; - /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); @@ -2191,8 +2186,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, } static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, - struct msghdr *msg, size_t len, - u32 priority) + struct msghdr *msg, size_t len) { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; @@ -2208,8 +2202,6 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, if (IS_ERR(skb)) return skb; - skb->priority = priority; - /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); @@ -2430,8 +2422,7 @@ static int l2cap_segment_le_sdu(struct l2cap_chan *chan, return 0; } -int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, - u32 priority) +int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { struct sk_buff *skb; int err; @@ -2442,7 +2433,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, /* Connectionless channel */ if (chan->chan_type == L2CAP_CHAN_CONN_LESS) { - skb = l2cap_create_connless_pdu(chan, msg, len, priority); + skb = l2cap_create_connless_pdu(chan, msg, len); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -2499,7 +2490,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, return -EMSGSIZE; /* Create a basic PDU */ - skb = l2cap_create_basic_pdu(chan, msg, len, priority); + skb = l2cap_create_basic_pdu(chan, msg, len); if (IS_ERR(skb)) return PTR_ERR(skb); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 11e2207717b6..d95964c9f91e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -964,7 +964,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, return err; l2cap_chan_lock(chan); - err = l2cap_chan_send(chan, msg, len, sk->sk_priority); + err = l2cap_chan_send(chan, msg, len); l2cap_chan_unlock(chan); return err; @@ -1305,6 +1305,8 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, if (!skb) return ERR_PTR(err); + skb->priority = sk->sk_priority; + bt_cb(skb)->chan = chan; return skb; -- cgit v1.2.3 From 0775899158d0e1436316f3bf451d78bf34b88d17 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 8 Jun 2014 10:26:57 +0200 Subject: Bluetooth: Shrink size of struct l2cap_ctrl fields The struct l2cap_ctrl fields are wasting an unsigned int when all the bits can fit into an __u8 field. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 904777c1cd24..373000de610d 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -260,15 +260,15 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock); /* Skb helpers */ struct l2cap_ctrl { - unsigned int sframe:1, - poll:1, - final:1, - fcs:1, - sar:2, - super:2; - __u16 reqseq; - __u16 txseq; - __u8 retries; + __u8 sframe:1, + poll:1, + final:1, + fcs:1, + sar:2, + super:2; + __u16 reqseq; + __u16 txseq; + __u8 retries; }; struct hci_dev; -- cgit v1.2.3 From d9fbd02be5c201c1659ee0d79c0820bb68d95c8c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 8 Jun 2014 11:22:28 +0200 Subject: Bluetooth: Use explicit header and body length for L2CAP SKB allocation When allocating the L2CAP SKB for transmission, provide the upper layers with a clear distinction on what is the header and what is the body portion of the SKB. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/a2mp.c | 3 ++- net/bluetooth/l2cap_core.c | 10 +++++----- net/bluetooth/l2cap_sock.c | 3 ++- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 18f4f27e0f74..92511034d1d4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -600,6 +600,7 @@ struct l2cap_ops { void (*set_shutdown) (struct l2cap_chan *chan); long (*get_sndtimeo) (struct l2cap_chan *chan); struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, + unsigned long hdr_len, unsigned long len, int nb); }; diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 1a5b1eb96d1a..0fd8d1dda709 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -693,11 +693,12 @@ static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state, } static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan, + unsigned long hdr_len, unsigned long len, int nb) { struct sk_buff *skb; - skb = bt_skb_alloc(len, GFP_KERNEL); + skb = bt_skb_alloc(hdr_len + len, GFP_KERNEL); if (!skb) return ERR_PTR(-ENOMEM); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3dca28246cbe..ac2461442f21 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2131,7 +2131,7 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, count = min_t(unsigned int, conn->mtu, len); - tmp = chan->ops->alloc_skb(chan, count, + tmp = chan->ops->alloc_skb(chan, 0, count, msg->msg_flags & MSG_DONTWAIT); if (IS_ERR(tmp)) return PTR_ERR(tmp); @@ -2166,7 +2166,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); - skb = chan->ops->alloc_skb(chan, count + hlen, + skb = chan->ops->alloc_skb(chan, hlen, count, msg->msg_flags & MSG_DONTWAIT); if (IS_ERR(skb)) return skb; @@ -2197,7 +2197,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len); - skb = chan->ops->alloc_skb(chan, count + L2CAP_HDR_SIZE, + skb = chan->ops->alloc_skb(chan, L2CAP_HDR_SIZE, count, msg->msg_flags & MSG_DONTWAIT); if (IS_ERR(skb)) return skb; @@ -2239,7 +2239,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); - skb = chan->ops->alloc_skb(chan, count + hlen, + skb = chan->ops->alloc_skb(chan, hlen, count, msg->msg_flags & MSG_DONTWAIT); if (IS_ERR(skb)) return skb; @@ -2360,7 +2360,7 @@ static struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); - skb = chan->ops->alloc_skb(chan, count + hlen, + skb = chan->ops->alloc_skb(chan, hlen, count, msg->msg_flags & MSG_DONTWAIT); if (IS_ERR(skb)) return skb; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index d95964c9f91e..55215ebf6547 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1292,6 +1292,7 @@ static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state, } static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, + unsigned long hdr_len, unsigned long len, int nb) { struct sock *sk = chan->data; @@ -1299,7 +1300,7 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, int err; l2cap_chan_unlock(chan); - skb = bt_skb_send_alloc(sk, len, nb, &err); + skb = bt_skb_send_alloc(sk, hdr_len + len, nb, &err); l2cap_chan_lock(chan); if (!skb) -- cgit v1.2.3 From 65cc2b49db63adf1455a9783234383fbec5b8314 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 16 Jun 2014 12:30:56 +0200 Subject: Bluetooth: Use struct delayed_work for HCI command timeout Since the whole HCI command, event and data packet processing has been migrated to use workqueues instead of tasklets, it makes sense to use struct delayed_work instead of struct timer_list for the timeout handling. This patch converts the hdev->cmd_timer to use workqueue as well. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 17 +++++++++-------- net/bluetooth/hci_event.c | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b386bf17e6c2..de3bb22e83f9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -273,7 +273,7 @@ struct hci_dev { struct delayed_work service_cache; - struct timer_list cmd_timer; + struct delayed_work cmd_timer; struct work_struct rx_work; struct work_struct cmd_work; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 0a43cce9a914..9e0368b02a11 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2432,7 +2432,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) hci_req_lock(hdev); if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { - del_timer_sync(&hdev->cmd_timer); + cancel_delayed_work_sync(&hdev->cmd_timer); hci_req_unlock(hdev); return 0; } @@ -2488,7 +2488,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Drop last sent command */ if (hdev->sent_cmd) { - del_timer_sync(&hdev->cmd_timer); + cancel_delayed_work_sync(&hdev->cmd_timer); kfree_skb(hdev->sent_cmd); hdev->sent_cmd = NULL; } @@ -3205,9 +3205,10 @@ void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type) } /* HCI command timer function */ -static void hci_cmd_timeout(unsigned long arg) +static void hci_cmd_timeout(struct work_struct *work) { - struct hci_dev *hdev = (void *) arg; + struct hci_dev *hdev = container_of(work, struct hci_dev, + cmd_timer.work); if (hdev->sent_cmd) { struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data; @@ -3884,7 +3885,7 @@ struct hci_dev *hci_alloc_dev(void) init_waitqueue_head(&hdev->req_wait_q); - setup_timer(&hdev->cmd_timer, hci_cmd_timeout, (unsigned long) hdev); + INIT_DELAYED_WORK(&hdev->cmd_timer, hci_cmd_timeout); hci_init_sysfs(hdev); discovery_init(hdev); @@ -5287,10 +5288,10 @@ static void hci_cmd_work(struct work_struct *work) atomic_dec(&hdev->cmd_cnt); hci_send_frame(hdev, skb); if (test_bit(HCI_RESET, &hdev->flags)) - del_timer(&hdev->cmd_timer); + cancel_delayed_work(&hdev->cmd_timer); else - mod_timer(&hdev->cmd_timer, - jiffies + HCI_CMD_TIMEOUT); + schedule_delayed_work(&hdev->cmd_timer, + HCI_CMD_TIMEOUT); } else { skb_queue_head(&hdev->cmd_q, skb); queue_work(hdev->workqueue, &hdev->cmd_work); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 640c54ec1bd2..3d52be1d695d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2709,7 +2709,7 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) } if (opcode != HCI_OP_NOP) - del_timer(&hdev->cmd_timer); + cancel_delayed_work(&hdev->cmd_timer); hci_req_cmd_complete(hdev, opcode, status); @@ -2800,7 +2800,7 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) } if (opcode != HCI_OP_NOP) - del_timer(&hdev->cmd_timer); + cancel_delayed_work(&hdev->cmd_timer); if (ev->status || (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req.event)) -- cgit v1.2.3 From c29d2444170a4e0709331e357a2738a02666a633 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jun 2014 19:25:14 +0300 Subject: Bluetooth: Fix missing NULL check for smp_chan_create() return value The smp_chan_create function may return NULL, e.g. in the case of memory allocation failure, so we always need to check for this. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index e33a982161c1..1f4ed1e78e10 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -888,6 +888,8 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) return 0; smp = smp_chan_create(conn); + if (!smp) + return SMP_UNSPECIFIED; skb_pull(skb, sizeof(*rp)); -- cgit v1.2.3 From 7d5843b7b77cee26bd5e090bfa61780d75957648 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jun 2014 19:25:15 +0300 Subject: Bluetooth: Remove unnecessary SMP STK define We never store the "master" type of STKs since we request encryption directly with them so we only need one STK type (the one that's looked-up on the slave side). Simply remove the unnecessary define and rename the _SLAVE one to the shorter form. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 - net/bluetooth/hci_event.c | 2 +- net/bluetooth/smp.c | 6 +++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 16587dcd6a91..98f7520d2f57 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -349,7 +349,6 @@ enum { #define HCI_LK_AUTH_COMBINATION_P256 0x08 /* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */ #define HCI_SMP_STK 0x80 -#define HCI_SMP_STK_SLAVE 0x81 #define HCI_SMP_LTK 0x82 #define HCI_SMP_LTK_SLAVE 0x83 diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3d52be1d695d..8dde40430b5f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4241,7 +4241,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) * distribute the keys. Later, security can be re-established * using a distributed LTK. */ - if (ltk->type == HCI_SMP_STK_SLAVE) { + if (ltk->type == HCI_SMP_STK) { list_del(<k->list); kfree(ltk); } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1f4ed1e78e10..b9cac1deb19f 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -568,8 +568,12 @@ static u8 smp_random(struct smp_chan *smp) else auth = 0; + /* Even though there's no _SLAVE suffix this is the + * slave STK we're adding for later lookup (the master + * STK never needs to be stored). + */ hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, - HCI_SMP_STK_SLAVE, auth, stk, smp->enc_key_size, + HCI_SMP_STK, auth, stk, smp->enc_key_size, ediv, rand); } -- cgit v1.2.3 From 2ceba53936d6f2071659b87748d723021937d035 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jun 2014 19:25:16 +0300 Subject: Bluetooth: Remove HCI prefix from SMP LTK defines The LTK type has really nothing to do with HCI so it makes more sense to have these in smp.h than hci.h. This patch moves the defines to smp.h and removes the HCI_ prefix in the same go. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 4 ---- net/bluetooth/hci_core.c | 2 +- net/bluetooth/hci_event.c | 3 ++- net/bluetooth/mgmt.c | 6 +++--- net/bluetooth/smp.c | 7 +++---- net/bluetooth/smp.h | 7 +++++++ 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 98f7520d2f57..6ec5b3bd1f67 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -347,10 +347,6 @@ enum { #define HCI_LK_CHANGED_COMBINATION 0x06 #define HCI_LK_UNAUTH_COMBINATION_P256 0x07 #define HCI_LK_AUTH_COMBINATION_P256 0x08 -/* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */ -#define HCI_SMP_STK 0x80 -#define HCI_SMP_LTK 0x82 -#define HCI_SMP_LTK_SLAVE 0x83 /* Long Term Key types */ #define HCI_LTK_UNAUTH 0x00 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9e0368b02a11..6001b9293905 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2974,7 +2974,7 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, static bool ltk_type_master(u8 type) { - if (type == HCI_SMP_STK || type == HCI_SMP_LTK) + if (type == SMP_STK || type == SMP_LTK) return true; return false; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8dde40430b5f..15a0a65bf447 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -32,6 +32,7 @@ #include "a2mp.h" #include "amp.h" +#include "smp.h" /* Handle HCI Event packets */ @@ -4241,7 +4242,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) * distribute the keys. Later, security can be re-established * using a distributed LTK. */ - if (ltk->type == HCI_SMP_STK) { + if (ltk->type == SMP_STK) { list_del(<k->list); kfree(ltk); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index af8e0a6243b7..99eb845865ef 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4550,9 +4550,9 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, addr_type = ADDR_LE_DEV_RANDOM; if (key->master) - type = HCI_SMP_LTK; + type = SMP_LTK; else - type = HCI_SMP_LTK_SLAVE; + type = SMP_LTK_SLAVE; switch (key->type) { case MGMT_LTK_UNAUTHENTICATED: @@ -5279,7 +5279,7 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent) ev.key.ediv = key->ediv; ev.key.rand = key->rand; - if (key->type == HCI_SMP_LTK) + if (key->type == SMP_LTK) ev.key.master = 1; memcpy(ev.key.val, key->val, sizeof(key->val)); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index b9cac1deb19f..78b9573f4a73 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -573,8 +573,7 @@ static u8 smp_random(struct smp_chan *smp) * STK never needs to be stored). */ hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, - HCI_SMP_STK, auth, stk, smp->enc_key_size, - ediv, rand); + SMP_STK, auth, stk, smp->enc_key_size, ediv, rand); } return 0; @@ -1027,7 +1026,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) hci_dev_lock(hdev); authenticated = (hcon->sec_level == BT_SECURITY_HIGH); - ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, + ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, SMP_LTK, authenticated, smp->tk, smp->enc_key_size, rp->ediv, rp->rand); smp->ltk = ltk; @@ -1343,7 +1342,7 @@ int smp_distribute_keys(struct l2cap_conn *conn) authenticated = hcon->sec_level == BT_SECURITY_HIGH; ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, - HCI_SMP_LTK_SLAVE, authenticated, enc.ltk, + SMP_LTK_SLAVE, authenticated, enc.ltk, smp->enc_key_size, ediv, rand); smp->slave_ltk = ltk; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 5a8dc36460a1..796f4f45f92f 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -116,6 +116,13 @@ struct smp_cmd_security_req { #define SMP_MIN_ENC_KEY_SIZE 7 #define SMP_MAX_ENC_KEY_SIZE 16 +/* LTK types used in internal storage (struct smp_ltk) */ +enum { + SMP_STK, + SMP_LTK, + SMP_LTK_SLAVE, +}; + /* SMP Commands */ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); -- cgit v1.2.3 From ddf4ba078f80415a514e175768bf67631beee7eb Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jun 2014 19:25:17 +0300 Subject: Bluetooth: Remove unused LTK authentication defines These defines were probably put in to track authenticated vs unauthenticated LTKs, however since the LTK struct has a separate boolean authenticated member these were never used. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6ec5b3bd1f67..fe584d78008d 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -348,10 +348,6 @@ enum { #define HCI_LK_UNAUTH_COMBINATION_P256 0x07 #define HCI_LK_AUTH_COMBINATION_P256 0x08 -/* Long Term Key types */ -#define HCI_LTK_UNAUTH 0x00 -#define HCI_LTK_AUTH 0x01 - /* ---- HCI Error Codes ---- */ #define HCI_ERROR_AUTH_FAILURE 0x05 #define HCI_ERROR_MEMORY_EXCEEDED 0x07 -- cgit v1.2.3 From 533e35d40130c040e38ffa3ee0401c8c84da618d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jun 2014 19:25:18 +0300 Subject: Bluetooth: Convert SMP flags into an enum There's no reason to have explicit values for these flags. Convert them to an enum to be consistent with other similar flags. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 78b9573f4a73..72c5aa05a489 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -35,11 +35,13 @@ #define AUTH_REQ_MASK 0x07 -#define SMP_FLAG_TK_VALID 1 -#define SMP_FLAG_CFM_PENDING 2 -#define SMP_FLAG_MITM_AUTH 3 -#define SMP_FLAG_COMPLETE 4 -#define SMP_FLAG_INITIATOR 5 +enum { + SMP_FLAG_TK_VALID, + SMP_FLAG_CFM_PENDING, + SMP_FLAG_MITM_AUTH, + SMP_FLAG_COMPLETE, + SMP_FLAG_INITIATOR, +}; struct smp_chan { struct l2cap_conn *conn; -- cgit v1.2.3 From 8a2936f44ad53ce4e734a0a0cc5bedc57711e87c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Jun 2014 19:25:19 +0300 Subject: Bluetooth: Add flexible buffer byte order swapping function Since the SMP code needs to swap ordering of variable length buffers add a convenience function that can be used for any length buffer. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 72c5aa05a489..28f4ef48095b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -64,18 +64,12 @@ struct smp_chan { unsigned long flags; }; -static inline void swap128(const u8 src[16], u8 dst[16]) +static inline void swap_buf(const u8 *src, u8 *dst, size_t len) { - int i; - for (i = 0; i < 16; i++) - dst[15 - i] = src[i]; -} + size_t i; -static inline void swap56(const u8 src[7], u8 dst[7]) -{ - int i; - for (i = 0; i < 7; i++) - dst[6 - i] = src[i]; + for (i = 0; i < len; i++) + dst[len - 1 - i] = src[i]; } static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) @@ -94,7 +88,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) desc.flags = 0; /* The most significant octet of key corresponds to k[0] */ - swap128(k, tmp); + swap_buf(k, tmp, 16); err = crypto_blkcipher_setkey(tfm, tmp, 16); if (err) { @@ -103,7 +97,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) } /* Most significant octet of plaintextData corresponds to data[0] */ - swap128(r, data); + swap_buf(r, data, 16); sg_init_one(&sg, data, 16); @@ -112,7 +106,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) BT_ERR("Encrypt data error %d", err); /* Most significant octet of encryptedData corresponds to data[0] */ - swap128(data, r); + swap_buf(data, r, 16); return err; } -- cgit v1.2.3 From 8ba8b4c05c3562d771fbfd2e7ee5648b41f04a9d Mon Sep 17 00:00:00 2001 From: Stephan Gabert Date: Mon, 16 Jun 2014 18:52:25 +0200 Subject: Bluetooth: Remove trailing whitespaces from Kconfig Fixed a coding style issue. Removed trailing whitespaces in drivers/bluetooth/Kconfig. Signed-off-by: Stephan Gabert Signed-off-by: Nicolas Pfeiffer Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index f5ce64e03fd7..fa7fd62ddffa 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -30,8 +30,8 @@ config BT_HCIUART help Bluetooth HCI UART driver. This driver is required if you want to use Bluetooth devices with - serial port interface. You will also need this driver if you have - UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card + serial port interface. You will also need this driver if you have + UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card adapter and BrainBoxes Bluetooth PC Card. Say Y here to compile support for Bluetooth UART devices into the @@ -41,9 +41,9 @@ config BT_HCIUART_H4 bool "UART (H4) protocol support" depends on BT_HCIUART help - UART (H4) is serial protocol for communication between Bluetooth - device and host. This protocol is required for most Bluetooth devices - with UART interface, including PCMCIA and CF cards. + UART (H4) is serial protocol for communication between Bluetooth + device and host. This protocol is required for most Bluetooth devices + with UART interface, including PCMCIA and CF cards. Say Y here to compile support for HCI UART (H4) protocol. @@ -52,7 +52,7 @@ config BT_HCIUART_BCSP depends on BT_HCIUART select BITREVERSE help - BCSP (BlueCore Serial Protocol) is serial protocol for communication + BCSP (BlueCore Serial Protocol) is serial protocol for communication between Bluetooth device and host. This protocol is required for non USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and CF cards. -- cgit v1.2.3 From 4ec86d4c86fe563482f183243f15bcd5fd3e65c5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 17 Jun 2014 15:14:48 +0300 Subject: Bluetooth: Fix validating IO capability values in mgmt commands The valid range of IO capabilities for the Set IO Capability and Pair Device mgmt commands is 0-4 (4 being the KeyboarDisplay capability for SMP). We should return an invalid parameters error if user space gives us a value outside of this range. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 99eb845865ef..5bf032d9bce1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2766,6 +2766,10 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG(""); + if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY) + return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, + MGMT_STATUS_INVALID_PARAMS, NULL, 0); + hci_dev_lock(hdev); hdev->io_capability = cp->io_capability; @@ -2878,6 +2882,11 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, MGMT_STATUS_INVALID_PARAMS, &rp, sizeof(rp)); + if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY) + return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &rp, sizeof(rp)); + hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { -- cgit v1.2.3 From d97c9fb0c82afc6042004ed3f381d85ff31fadcc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 18 Jun 2014 14:09:40 +0300 Subject: Bluetooth: Fix checking for master LTKs When the rename of STK_SLAVE to simply STK happened we missed this place in the ltk_type_master function. Now, checking for master is as simple as checking whether the type is SMP_LTK. The helper function is kept around for better readability in the (right now three) callers and for simpler extension with new key types in the future. Signed-off-by: Johan Hedberg Tested-by: Lukasz Rymanowski Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6001b9293905..c3d184fd24de 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2974,10 +2974,7 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, static bool ltk_type_master(u8 type) { - if (type == SMP_STK || type == SMP_LTK) - return true; - - return false; + return (type == SMP_LTK); } struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, -- cgit v1.2.3 From 111902f7236ff8139c30c2b9709c999fcb931399 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 21 Jun 2014 04:53:17 +0200 Subject: Bluetooth: Use separate dbg_flags to special debugfs options All the special settings configured via debugfs are either developer only options or temporary solutions. To not clutter the standard flags, move them to their own dbg_flags entry. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 12 +++++++++--- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 24 ++++++++++++------------ net/bluetooth/mgmt.c | 4 ++-- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index fe584d78008d..3e12e27afca1 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -104,6 +104,15 @@ enum { HCI_RESET, }; +/* BR/EDR and/or LE controller flags: the flags defined here should represent + * states configured via debugfs for debugging and testing purposes only. + */ +enum { + HCI_DUT_MODE, + HCI_FORCE_SC, + HCI_FORCE_STATIC_ADDR, +}; + /* * BR/EDR and/or LE controller flags: the flags defined here should represent * states from the controller. @@ -116,9 +125,6 @@ enum { HCI_PAIRABLE, HCI_SERVICE_CACHE, HCI_DEBUG_KEYS, - HCI_DUT_MODE, - HCI_FORCE_SC, - HCI_FORCE_STATIC_ADDR, HCI_UNREGISTER, HCI_USER_CHANNEL, diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index de3bb22e83f9..bf41e992a618 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -318,6 +318,7 @@ struct hci_dev { struct rfkill *rfkill; + unsigned long dbg_flags; unsigned long dev_flags; struct delayed_work le_scan_disable; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c3d184fd24de..ddbb084250be 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -68,7 +68,7 @@ static ssize_t dut_mode_read(struct file *file, char __user *user_buf, struct hci_dev *hdev = file->private_data; char buf[3]; - buf[0] = test_bit(HCI_DUT_MODE, &hdev->dev_flags) ? 'Y': 'N'; + buf[0] = test_bit(HCI_DUT_MODE, &hdev->dbg_flags) ? 'Y': 'N'; buf[1] = '\n'; buf[2] = '\0'; return simple_read_from_buffer(user_buf, count, ppos, buf, 2); @@ -94,7 +94,7 @@ static ssize_t dut_mode_write(struct file *file, const char __user *user_buf, if (strtobool(buf, &enable)) return -EINVAL; - if (enable == test_bit(HCI_DUT_MODE, &hdev->dev_flags)) + if (enable == test_bit(HCI_DUT_MODE, &hdev->dbg_flags)) return -EALREADY; hci_req_lock(hdev); @@ -115,7 +115,7 @@ static ssize_t dut_mode_write(struct file *file, const char __user *user_buf, if (err < 0) return err; - change_bit(HCI_DUT_MODE, &hdev->dev_flags); + change_bit(HCI_DUT_MODE, &hdev->dbg_flags); return count; } @@ -407,7 +407,7 @@ static ssize_t force_sc_support_read(struct file *file, char __user *user_buf, struct hci_dev *hdev = file->private_data; char buf[3]; - buf[0] = test_bit(HCI_FORCE_SC, &hdev->dev_flags) ? 'Y': 'N'; + buf[0] = test_bit(HCI_FORCE_SC, &hdev->dbg_flags) ? 'Y': 'N'; buf[1] = '\n'; buf[2] = '\0'; return simple_read_from_buffer(user_buf, count, ppos, buf, 2); @@ -432,10 +432,10 @@ static ssize_t force_sc_support_write(struct file *file, if (strtobool(buf, &enable)) return -EINVAL; - if (enable == test_bit(HCI_FORCE_SC, &hdev->dev_flags)) + if (enable == test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) return -EALREADY; - change_bit(HCI_FORCE_SC, &hdev->dev_flags); + change_bit(HCI_FORCE_SC, &hdev->dbg_flags); return count; } @@ -719,7 +719,7 @@ static ssize_t force_static_address_read(struct file *file, struct hci_dev *hdev = file->private_data; char buf[3]; - buf[0] = test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) ? 'Y': 'N'; + buf[0] = test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) ? 'Y': 'N'; buf[1] = '\n'; buf[2] = '\0'; return simple_read_from_buffer(user_buf, count, ppos, buf, 2); @@ -744,10 +744,10 @@ static ssize_t force_static_address_write(struct file *file, if (strtobool(buf, &enable)) return -EINVAL; - if (enable == test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags)) + if (enable == test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags)) return -EALREADY; - change_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags); + change_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags); return count; } @@ -1752,7 +1752,7 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) /* Enable Secure Connections if supported and configured */ if ((lmp_sc_capable(hdev) || - test_bit(HCI_FORCE_SC, &hdev->dev_flags)) && + test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) && test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { u8 support = 0x01; hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT, @@ -3782,7 +3782,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, * the HCI command if the current random address is already the * static one. */ - if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || + if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) || !bacmp(&hdev->bdaddr, BDADDR_ANY)) { *own_addr_type = ADDR_LE_DEV_RANDOM; if (bacmp(&hdev->static_addr, &hdev->random_addr)) @@ -3811,7 +3811,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *bdaddr_type) { - if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || + if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) || !bacmp(&hdev->bdaddr, BDADDR_ANY)) { bacpy(bdaddr, &hdev->static_addr); *bdaddr_type = ADDR_LE_DEV_RANDOM; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5bf032d9bce1..e1651c3fc676 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -387,7 +387,7 @@ static u32 get_supported_settings(struct hci_dev *hdev) } if (lmp_sc_capable(hdev) || - test_bit(HCI_FORCE_SC, &hdev->dev_flags)) + test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) settings |= MGMT_SETTING_SECURE_CONN; } @@ -4261,7 +4261,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, status); if (!lmp_sc_capable(hdev) && - !test_bit(HCI_FORCE_SC, &hdev->dev_flags)) + !test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, MGMT_STATUS_NOT_SUPPORTED); -- cgit v1.2.3 From 0498878b18993891f7b71c75b6adcb7c157501db Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 18 Jun 2014 16:37:07 +0300 Subject: Bluetooth: Provide L2CAP ops callback for memcpy_fromiovec The highly optimized TX path for L2CAP channels and its fragmentation within the HCI ACL packets requires to copy data from user provided IO vectors and also kernel provided memory buffers. This patch allows channel clients to provide a memcpy_fromiovec callback to keep this optimized behavior, but adapt it to kernel vs user memory for the TX path. For all kernel internal L2CAP channels, a default implementation is provided that can be referenced. In case of A2MP, this fixes a long-standing issue with wrongly accessing kernel memory as user memory. This patch originally by Marcel Holtmann. Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 29 +++++++++++++++++++++++++++++ net/bluetooth/a2mp.c | 1 + net/bluetooth/l2cap_core.c | 6 ++++-- net/bluetooth/l2cap_sock.c | 34 +++++++++++++++++++++------------- 4 files changed, 55 insertions(+), 15 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 92511034d1d4..1ee6f00d7096 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -602,6 +602,10 @@ struct l2cap_ops { struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, unsigned long hdr_len, unsigned long len, int nb); + int (*memcpy_fromiovec) (struct l2cap_chan *chan, + unsigned char *kdata, + struct iovec *iov, + int len); }; struct l2cap_conn { @@ -857,6 +861,31 @@ static inline long l2cap_chan_no_get_sndtimeo(struct l2cap_chan *chan) return 0; } +static inline int l2cap_chan_no_memcpy_fromiovec(struct l2cap_chan *chan, + unsigned char *kdata, + struct iovec *iov, + int len) +{ + /* Following is safe since for compiler definitions of kvec and + * iovec are identical, yielding the same in-core layout and alignment + */ + struct kvec *vec = (struct kvec *)iov; + + while (len > 0) { + if (vec->iov_len) { + int copy = min_t(unsigned int, len, vec->iov_len); + memcpy(kdata, vec->iov_base, copy); + len -= copy; + kdata += copy; + vec->iov_base += copy; + vec->iov_len -= copy; + } + vec++; + } + + return 0; +} + extern bool disable_ertm; int l2cap_init_sockets(void); diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 0fd8d1dda709..5dcade511fdb 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -720,6 +720,7 @@ static const struct l2cap_ops a2mp_chan_ops = { .resume = l2cap_chan_no_resume, .set_shutdown = l2cap_chan_no_set_shutdown, .get_sndtimeo = l2cap_chan_no_get_sndtimeo, + .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, }; static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ac2461442f21..d0a5fde61a07 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2118,7 +2118,8 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct sk_buff **frag; int sent = 0; - if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) + if (chan->ops->memcpy_fromiovec(chan, skb_put(skb, count), + msg->msg_iov, count)) return -EFAULT; sent += count; @@ -2138,7 +2139,8 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, *frag = tmp; - if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) + if (chan->ops->memcpy_fromiovec(chan, skb_put(*frag, count), + msg->msg_iov, count)) return -EFAULT; sent += count; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 55215ebf6547..bf72886de6ef 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1313,6 +1313,13 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, return skb; } +static int l2cap_sock_memcpy_fromiovec_cb(struct l2cap_chan *chan, + unsigned char *kdata, + struct iovec *iov, int len) +{ + return memcpy_fromiovec(kdata, iov, len); +} + static void l2cap_sock_ready_cb(struct l2cap_chan *chan) { struct sock *sk = chan->data; @@ -1379,19 +1386,20 @@ static void l2cap_sock_suspend_cb(struct l2cap_chan *chan) } static const struct l2cap_ops l2cap_chan_ops = { - .name = "L2CAP Socket Interface", - .new_connection = l2cap_sock_new_connection_cb, - .recv = l2cap_sock_recv_cb, - .close = l2cap_sock_close_cb, - .teardown = l2cap_sock_teardown_cb, - .state_change = l2cap_sock_state_change_cb, - .ready = l2cap_sock_ready_cb, - .defer = l2cap_sock_defer_cb, - .resume = l2cap_sock_resume_cb, - .suspend = l2cap_sock_suspend_cb, - .set_shutdown = l2cap_sock_set_shutdown_cb, - .get_sndtimeo = l2cap_sock_get_sndtimeo_cb, - .alloc_skb = l2cap_sock_alloc_skb_cb, + .name = "L2CAP Socket Interface", + .new_connection = l2cap_sock_new_connection_cb, + .recv = l2cap_sock_recv_cb, + .close = l2cap_sock_close_cb, + .teardown = l2cap_sock_teardown_cb, + .state_change = l2cap_sock_state_change_cb, + .ready = l2cap_sock_ready_cb, + .defer = l2cap_sock_defer_cb, + .resume = l2cap_sock_resume_cb, + .suspend = l2cap_sock_suspend_cb, + .set_shutdown = l2cap_sock_set_shutdown_cb, + .get_sndtimeo = l2cap_sock_get_sndtimeo_cb, + .alloc_skb = l2cap_sock_alloc_skb_cb, + .memcpy_fromiovec = l2cap_sock_memcpy_fromiovec_cb, }; static void l2cap_sock_destruct(struct sock *sk) -- cgit v1.2.3 From 6b8d4a6a03144c5996f98db7f8256267b0d72a3a Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 18 Jun 2014 16:37:08 +0300 Subject: Bluetooth: 6LoWPAN: Use connected oriented channel instead of fixed one Create a CoC dynamically instead of one fixed channel for communication to peer devices. Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 - include/net/bluetooth/hci_core.h | 1 - include/net/bluetooth/l2cap.h | 1 - net/bluetooth/6lowpan.c | 787 +++++++++++++++++++++++++++++---------- net/bluetooth/6lowpan.h | 47 --- net/bluetooth/hci_core.c | 45 --- net/bluetooth/hci_event.c | 3 - net/bluetooth/l2cap_core.c | 20 +- 8 files changed, 588 insertions(+), 317 deletions(-) delete mode 100644 net/bluetooth/6lowpan.h diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 3e12e27afca1..3f3a3f1399fb 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -145,7 +145,6 @@ enum { HCI_PERIODIC_INQ, HCI_FAST_CONNECTABLE, HCI_BREDR_ENABLED, - HCI_6LOWPAN_ENABLED, HCI_LE_SCAN_INTERRUPTED, }; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bf41e992a618..c81de0d366df 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -521,7 +521,6 @@ enum { HCI_CONN_AES_CCM, HCI_CONN_POWER_SAVE, HCI_CONN_REMOTE_OOB, - HCI_CONN_6LOWPAN, }; static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 1ee6f00d7096..e0c6a9abdb62 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -137,7 +137,6 @@ struct l2cap_conninfo { #define L2CAP_FC_L2CAP 0x02 #define L2CAP_FC_CONNLESS 0x04 #define L2CAP_FC_A2MP 0x08 -#define L2CAP_FC_6LOWPAN 0x3e /* reserved and temporary value */ /* L2CAP Control Field bit masks */ #define L2CAP_CTRL_SAR 0xC000 diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 8796ffa08b43..bdb01eb3bfcc 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2013 Intel Corp. + Copyright (c) 2013-2014 Intel Corp. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 and @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -25,16 +26,20 @@ #include #include -#include "6lowpan.h" - #include /* for the compression support */ +#define VERSION "0.1" + +static struct dentry *lowpan_psm_debugfs; +static struct dentry *lowpan_control_debugfs; + #define IFACE_NAME_TEMPLATE "bt%d" #define EUI64_ADDR_LEN 8 struct skb_cb { struct in6_addr addr; - struct l2cap_conn *conn; + struct l2cap_chan *chan; + int status; }; #define lowpan_cb(skb) ((struct skb_cb *)((skb)->cb)) @@ -48,9 +53,19 @@ struct skb_cb { static LIST_HEAD(bt_6lowpan_devices); static DEFINE_RWLOCK(devices_lock); +/* If psm is set to 0 (default value), then 6lowpan is disabled. + * Other values are used to indicate a Protocol Service Multiplexer + * value for 6lowpan. + */ +static u16 psm_6lowpan; + +/* We are listening incoming connections via this channel + */ +static struct l2cap_chan *listen_chan; + struct lowpan_peer { struct list_head list; - struct l2cap_conn *conn; + struct l2cap_chan *chan; /* peer addresses in various formats */ unsigned char eui64_addr[EUI64_ADDR_LEN]; @@ -101,13 +116,26 @@ static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev, ba, type); list_for_each_entry_safe(peer, tmp, &dev->peers, list) { - BT_DBG("addr %pMR type %d", - &peer->conn->hcon->dst, peer->conn->hcon->dst_type); + BT_DBG("dst addr %pMR dst type %d", + &peer->chan->dst, peer->chan->dst_type); - if (bacmp(&peer->conn->hcon->dst, ba)) + if (bacmp(&peer->chan->dst, ba)) continue; - if (type == peer->conn->hcon->dst_type) + if (type == peer->chan->dst_type) + return peer; + } + + return NULL; +} + +static inline struct lowpan_peer *peer_lookup_chan(struct lowpan_dev *dev, + struct l2cap_chan *chan) +{ + struct lowpan_peer *peer, *tmp; + + list_for_each_entry_safe(peer, tmp, &dev->peers, list) { + if (peer->chan == chan) return peer; } @@ -120,7 +148,7 @@ static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev, struct lowpan_peer *peer, *tmp; list_for_each_entry_safe(peer, tmp, &dev->peers, list) { - if (peer->conn == conn) + if (peer->chan->conn == conn) return peer; } @@ -176,16 +204,16 @@ static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev) return -ENOMEM; ret = netif_rx(skb_cp); - - BT_DBG("receive skb %d", ret); - if (ret < 0) + if (ret < 0) { + BT_DBG("receive skb %d", ret); return NET_RX_DROP; + } return ret; } static int process_data(struct sk_buff *skb, struct net_device *netdev, - struct l2cap_conn *conn) + struct l2cap_chan *chan) { const u8 *saddr, *daddr; u8 iphc0, iphc1; @@ -196,7 +224,7 @@ static int process_data(struct sk_buff *skb, struct net_device *netdev, dev = lowpan_dev(netdev); read_lock_irqsave(&devices_lock, flags); - peer = peer_lookup_conn(dev, conn); + peer = peer_lookup_chan(dev, chan); read_unlock_irqrestore(&devices_lock, flags); if (!peer) goto drop; @@ -225,7 +253,7 @@ drop: } static int recv_pkt(struct sk_buff *skb, struct net_device *dev, - struct l2cap_conn *conn) + struct l2cap_chan *chan) { struct sk_buff *local_skb; int ret; @@ -269,7 +297,7 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, if (!local_skb) goto drop; - ret = process_data(local_skb, dev, conn); + ret = process_data(local_skb, dev, chan); if (ret != NET_RX_SUCCESS) goto drop; @@ -286,147 +314,39 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, return NET_RX_SUCCESS; drop: + dev->stats.rx_dropped++; kfree_skb(skb); return NET_RX_DROP; } /* Packet from BT LE device */ -int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb) +static int chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) { struct lowpan_dev *dev; struct lowpan_peer *peer; int err; - peer = lookup_peer(conn); + peer = lookup_peer(chan->conn); if (!peer) return -ENOENT; - dev = lookup_dev(conn); + dev = lookup_dev(chan->conn); if (!dev || !dev->netdev) return -ENOENT; - err = recv_pkt(skb, dev->netdev, conn); - BT_DBG("recv pkt %d", err); - - return err; -} - -static inline int skbuff_copy(void *msg, int len, int count, int mtu, - struct sk_buff *skb, struct net_device *dev) -{ - struct sk_buff **frag; - int sent = 0; - - memcpy(skb_put(skb, count), msg, count); - - sent += count; - msg += count; - len -= count; - - dev->stats.tx_bytes += count; - dev->stats.tx_packets++; - - raw_dump_table(__func__, "Sending", skb->data, skb->len); - - /* Continuation fragments (no L2CAP header) */ - frag = &skb_shinfo(skb)->frag_list; - while (len > 0) { - struct sk_buff *tmp; - - count = min_t(unsigned int, mtu, len); - - tmp = bt_skb_alloc(count, GFP_ATOMIC); - if (!tmp) - return -ENOMEM; - - *frag = tmp; - - memcpy(skb_put(*frag, count), msg, count); - - raw_dump_table(__func__, "Sending fragment", - (*frag)->data, count); - - (*frag)->priority = skb->priority; - - sent += count; - msg += count; - len -= count; - - skb->len += (*frag)->len; - skb->data_len += (*frag)->len; - - frag = &(*frag)->next; - - dev->stats.tx_bytes += count; - dev->stats.tx_packets++; - } - - return sent; -} - -static struct sk_buff *create_pdu(struct l2cap_conn *conn, void *msg, - size_t len, u32 priority, - struct net_device *dev) -{ - struct sk_buff *skb; - int err, count; - struct l2cap_hdr *lh; - - /* FIXME: This mtu check should be not needed and atm is only used for - * testing purposes - */ - if (conn->mtu > (L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE)) - conn->mtu = L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE; - - count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len); - - BT_DBG("conn %p len %zu mtu %d count %d", conn, len, conn->mtu, count); - - skb = bt_skb_alloc(count + L2CAP_HDR_SIZE, GFP_ATOMIC); - if (!skb) - return ERR_PTR(-ENOMEM); - - skb->priority = priority; - - lh = (struct l2cap_hdr *)skb_put(skb, L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(L2CAP_FC_6LOWPAN); - lh->len = cpu_to_le16(len); - - err = skbuff_copy(msg, len, count, conn->mtu, skb, dev); - if (unlikely(err < 0)) { - kfree_skb(skb); - BT_DBG("skbuff copy %d failed", err); - return ERR_PTR(err); + err = recv_pkt(skb, dev->netdev, chan); + if (err) { + BT_DBG("recv pkt %d", err); + err = -EAGAIN; } - return skb; -} - -static int conn_send(struct l2cap_conn *conn, - void *msg, size_t len, u32 priority, - struct net_device *dev) -{ - struct sk_buff *skb; - - skb = create_pdu(conn, msg, len, priority, dev); - if (IS_ERR(skb)) - return -EINVAL; - - BT_DBG("conn %p skb %p len %d priority %u", conn, skb, skb->len, - skb->priority); - - hci_send_acl(conn->hchan, skb, ACL_START); - - return 0; + return err; } static u8 get_addr_type_from_eui64(u8 byte) { - /* Is universal(0) or local(1) bit, */ - if (byte & 0x02) - return ADDR_LE_DEV_RANDOM; - - return ADDR_LE_DEV_PUBLIC; + /* Is universal(0) or local(1) bit */ + return ((byte & 0x02) ? BDADDR_LE_RANDOM : BDADDR_LE_PUBLIC); } static void copy_to_bdaddr(struct in6_addr *ip6_daddr, bdaddr_t *addr) @@ -475,7 +395,7 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, if (ipv6_addr_is_multicast(&hdr->daddr)) { memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, sizeof(struct in6_addr)); - lowpan_cb(skb)->conn = NULL; + lowpan_cb(skb)->chan = NULL; } else { unsigned long flags; @@ -484,9 +404,8 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, */ convert_dest_bdaddr(&hdr->daddr, &addr, &addr_type); - BT_DBG("dest addr %pMR type %s IP %pI6c", &addr, - addr_type == ADDR_LE_DEV_PUBLIC ? "PUBLIC" : "RANDOM", - &hdr->daddr); + BT_DBG("dest addr %pMR type %d IP %pI6c", &addr, + addr_type, &hdr->daddr); read_lock_irqsave(&devices_lock, flags); peer = peer_lookup_ba(dev, &addr, addr_type); @@ -501,7 +420,7 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, sizeof(struct in6_addr)); - lowpan_cb(skb)->conn = peer->conn; + lowpan_cb(skb)->chan = peer->chan; } saddr = dev->netdev->dev_addr; @@ -510,14 +429,42 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, } /* Packet to BT LE device */ -static int send_pkt(struct l2cap_conn *conn, const void *saddr, - const void *daddr, struct sk_buff *skb, +static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb, struct net_device *netdev) { - raw_dump_table(__func__, "raw skb data dump before fragmentation", - skb->data, skb->len); + struct msghdr msg; + struct kvec iv; + int err; + + /* Remember the skb so that we can send EAGAIN to the caller if + * we run out of credits. + */ + chan->data = skb; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = (struct iovec *) &iv; + msg.msg_iovlen = 1; + iv.iov_base = skb->data; + iv.iov_len = skb->len; + + err = l2cap_chan_send(chan, &msg, skb->len); + if (err > 0) { + netdev->stats.tx_bytes += err; + netdev->stats.tx_packets++; + return 0; + } + + if (!err) + err = lowpan_cb(skb)->status; + + if (err < 0) { + if (err == -EAGAIN) + netdev->stats.tx_dropped++; + else + netdev->stats.tx_errors++; + } - return conn_send(conn, skb->data, skb->len, 0, netdev); + return err; } static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) @@ -540,8 +487,7 @@ static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) { local_skb = skb_clone(skb, GFP_ATOMIC); - send_pkt(pentry->conn, netdev->dev_addr, - pentry->eui64_addr, local_skb, netdev); + send_pkt(pentry->chan, local_skb, netdev); kfree_skb(local_skb); } @@ -553,7 +499,6 @@ static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) { int err = 0; - unsigned char *eui64_addr; struct lowpan_dev *dev; struct lowpan_peer *peer; bdaddr_t addr; @@ -568,21 +513,20 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned long flags; convert_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type); - eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8; dev = lowpan_dev(netdev); read_lock_irqsave(&devices_lock, flags); peer = peer_lookup_ba(dev, &addr, addr_type); read_unlock_irqrestore(&devices_lock, flags); - BT_DBG("xmit %s to %pMR type %s IP %pI6c peer %p", - netdev->name, &addr, - addr_type == ADDR_LE_DEV_PUBLIC ? "PUBLIC" : "RANDOM", + BT_DBG("xmit %s to %pMR type %d IP %pI6c peer %p", + netdev->name, &addr, addr_type, &lowpan_cb(skb)->addr, peer); - if (peer && peer->conn) - err = send_pkt(peer->conn, netdev->dev_addr, - eui64_addr, skb, netdev); + if (peer && peer->chan) + err = send_pkt(peer->chan, skb, netdev); + else + err = -ENOENT; } dev_kfree_skb(skb); @@ -634,7 +578,7 @@ static void set_addr(u8 *eui, u8 *addr, u8 addr_type) eui[7] = addr[0]; /* Universal/local bit set, BT 6lowpan draft ch. 3.2.1 */ - if (addr_type == ADDR_LE_DEV_PUBLIC) + if (addr_type == BDADDR_LE_PUBLIC) eui[0] &= ~0x02; else eui[0] |= 0x02; @@ -673,26 +617,64 @@ static bool is_bt_6lowpan(struct hci_conn *hcon) if (hcon->type != LE_LINK) return false; - return test_bit(HCI_CONN_6LOWPAN, &hcon->flags); + if (!psm_6lowpan) + return false; + + return true; } -static int add_peer_conn(struct l2cap_conn *conn, struct lowpan_dev *dev) +static struct l2cap_chan *chan_create(void) +{ + struct l2cap_chan *chan; + + chan = l2cap_chan_create(); + if (!chan) + return NULL; + + l2cap_chan_set_defaults(chan); + + chan->chan_type = L2CAP_CHAN_CONN_ORIENTED; + chan->mode = L2CAP_MODE_LE_FLOWCTL; + chan->omtu = 65535; + chan->imtu = chan->omtu; + + return chan; +} + +static struct l2cap_chan *chan_open(struct l2cap_chan *pchan) +{ + struct l2cap_chan *chan; + + chan = chan_create(); + if (!chan) + return NULL; + + chan->remote_mps = chan->omtu; + chan->mps = chan->omtu; + + chan->state = BT_CONNECTED; + + return chan; +} + +static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan, + struct lowpan_dev *dev) { struct lowpan_peer *peer; unsigned long flags; peer = kzalloc(sizeof(*peer), GFP_ATOMIC); if (!peer) - return -ENOMEM; + return NULL; - peer->conn = conn; + peer->chan = chan; memset(&peer->peer_addr, 0, sizeof(struct in6_addr)); /* RFC 2464 ch. 5 */ peer->peer_addr.s6_addr[0] = 0xFE; peer->peer_addr.s6_addr[1] = 0x80; - set_addr((u8 *)&peer->peer_addr.s6_addr + 8, conn->hcon->dst.b, - conn->hcon->dst_type); + set_addr((u8 *)&peer->peer_addr.s6_addr + 8, chan->dst.b, + chan->dst_type); memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, EUI64_ADDR_LEN); @@ -706,40 +688,24 @@ static int add_peer_conn(struct l2cap_conn *conn, struct lowpan_dev *dev) INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers); schedule_delayed_work(&dev->notify_peers, msecs_to_jiffies(100)); - return 0; + return peer->chan; } -/* This gets called when BT LE 6LoWPAN device is connected. We then - * create network device that acts as a proxy between BT LE device - * and kernel network stack. - */ -int bt_6lowpan_add_conn(struct l2cap_conn *conn) +static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev) { - struct lowpan_peer *peer = NULL; - struct lowpan_dev *dev; struct net_device *netdev; int err = 0; unsigned long flags; - if (!is_bt_6lowpan(conn->hcon)) - return 0; - - peer = lookup_peer(conn); - if (peer) - return -EEXIST; - - dev = lookup_dev(conn); - if (dev) - return add_peer_conn(conn, dev); - - netdev = alloc_netdev(sizeof(*dev), IFACE_NAME_TEMPLATE, netdev_setup); + netdev = alloc_netdev(sizeof(struct lowpan_dev), IFACE_NAME_TEMPLATE, + netdev_setup); if (!netdev) return -ENOMEM; - set_dev_addr(netdev, &conn->hcon->src, conn->hcon->src_type); + set_dev_addr(netdev, &chan->src, chan->src_type); netdev->netdev_ops = &netdev_ops; - SET_NETDEV_DEV(netdev, &conn->hcon->dev); + SET_NETDEV_DEV(netdev, &chan->conn->hcon->dev); SET_NETDEV_DEVTYPE(netdev, &bt_type); err = register_netdev(netdev); @@ -749,28 +715,58 @@ int bt_6lowpan_add_conn(struct l2cap_conn *conn) goto out; } - BT_DBG("ifindex %d peer bdaddr %pMR my addr %pMR", - netdev->ifindex, &conn->hcon->dst, &conn->hcon->src); + BT_DBG("ifindex %d peer bdaddr %pMR type %d my addr %pMR type %d", + netdev->ifindex, &chan->dst, chan->dst_type, + &chan->src, chan->src_type); set_bit(__LINK_STATE_PRESENT, &netdev->state); - dev = netdev_priv(netdev); - dev->netdev = netdev; - dev->hdev = conn->hcon->hdev; - INIT_LIST_HEAD(&dev->peers); + *dev = netdev_priv(netdev); + (*dev)->netdev = netdev; + (*dev)->hdev = chan->conn->hcon->hdev; + INIT_LIST_HEAD(&(*dev)->peers); write_lock_irqsave(&devices_lock, flags); - INIT_LIST_HEAD(&dev->list); - list_add(&dev->list, &bt_6lowpan_devices); + INIT_LIST_HEAD(&(*dev)->list); + list_add(&(*dev)->list, &bt_6lowpan_devices); write_unlock_irqrestore(&devices_lock, flags); - ifup(netdev); - - return add_peer_conn(conn, dev); + return 0; out: return err; } +static inline void chan_ready_cb(struct l2cap_chan *chan) +{ + struct lowpan_dev *dev; + + dev = lookup_dev(chan->conn); + + BT_DBG("chan %p conn %p dev %p", chan, chan->conn, dev); + + if (!dev) { + if (setup_netdev(chan, &dev) < 0) { + l2cap_chan_del(chan, -ENOENT); + return; + } + } + + add_peer_chan(chan, dev); + ifup(dev->netdev); +} + +static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *chan) +{ + struct l2cap_chan *pchan; + + pchan = chan_open(chan); + pchan->ops = chan->ops; + + BT_DBG("chan %p pchan %p", chan, pchan); + + return pchan; +} + static void delete_netdev(struct work_struct *work) { struct lowpan_dev *entry = container_of(work, struct lowpan_dev, @@ -781,26 +777,43 @@ static void delete_netdev(struct work_struct *work) /* The entry pointer is deleted in device_event() */ } -int bt_6lowpan_del_conn(struct l2cap_conn *conn) +static void chan_close_cb(struct l2cap_chan *chan) { struct lowpan_dev *entry, *tmp; struct lowpan_dev *dev = NULL; struct lowpan_peer *peer; int err = -ENOENT; unsigned long flags; - bool last = false; + bool last = false, removed = true; - if (!conn || !is_bt_6lowpan(conn->hcon)) - return 0; + BT_DBG("chan %p conn %p", chan, chan->conn); + + if (chan->conn && chan->conn->hcon) { + if (!is_bt_6lowpan(chan->conn->hcon)) + return; + + /* If conn is set, then the netdev is also there and we should + * not remove it. + */ + removed = false; + } write_lock_irqsave(&devices_lock, flags); list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { dev = lowpan_dev(entry->netdev); - peer = peer_lookup_conn(dev, conn); + peer = peer_lookup_chan(dev, chan); if (peer) { last = peer_del(dev, peer); err = 0; + + BT_DBG("dev %p removing %speer %p", dev, + last ? "last " : "1 ", peer); + BT_DBG("chan %p orig refcnt %d", chan, + atomic_read(&chan->kref.refcount)); + + l2cap_chan_put(chan); + kfree(peer); break; } } @@ -810,18 +823,363 @@ int bt_6lowpan_del_conn(struct l2cap_conn *conn) cancel_delayed_work_sync(&dev->notify_peers); - /* bt_6lowpan_del_conn() is called with hci dev lock held which - * means that we must delete the netdevice in worker thread. - */ - INIT_WORK(&entry->delete_netdev, delete_netdev); - schedule_work(&entry->delete_netdev); + if (!removed) { + INIT_WORK(&entry->delete_netdev, delete_netdev); + schedule_work(&entry->delete_netdev); + } } else { write_unlock_irqrestore(&devices_lock, flags); } + return; +} + +static void chan_state_change_cb(struct l2cap_chan *chan, int state, int err) +{ + BT_DBG("chan %p conn %p state %s err %d", chan, chan->conn, + state_to_string(state), err); +} + +static struct sk_buff *chan_alloc_skb_cb(struct l2cap_chan *chan, + unsigned long hdr_len, + unsigned long len, int nb) +{ + /* Note that we must allocate using GFP_ATOMIC here as + * this function is called originally from netdev hard xmit + * function in atomic context. + */ + return bt_skb_alloc(hdr_len + len, GFP_ATOMIC); +} + +static void chan_suspend_cb(struct l2cap_chan *chan) +{ + struct sk_buff *skb = chan->data; + + BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb); + + lowpan_cb(skb)->status = -EAGAIN; +} + +static void chan_resume_cb(struct l2cap_chan *chan) +{ + struct sk_buff *skb = chan->data; + + BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb); + + lowpan_cb(skb)->status = 0; +} + +static long chan_get_sndtimeo_cb(struct l2cap_chan *chan) +{ + return msecs_to_jiffies(1000); +} + +static const struct l2cap_ops bt_6lowpan_chan_ops = { + .name = "L2CAP 6LoWPAN channel", + .new_connection = chan_new_conn_cb, + .recv = chan_recv_cb, + .close = chan_close_cb, + .state_change = chan_state_change_cb, + .ready = chan_ready_cb, + .resume = chan_resume_cb, + .suspend = chan_suspend_cb, + .get_sndtimeo = chan_get_sndtimeo_cb, + .alloc_skb = chan_alloc_skb_cb, + .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, + + .teardown = l2cap_chan_no_teardown, + .defer = l2cap_chan_no_defer, + .set_shutdown = l2cap_chan_no_set_shutdown, +}; + +static inline __u8 bdaddr_type(__u8 type) +{ + if (type == ADDR_LE_DEV_PUBLIC) + return BDADDR_LE_PUBLIC; + else + return BDADDR_LE_RANDOM; +} + +static struct l2cap_chan *chan_get(void) +{ + struct l2cap_chan *pchan; + + pchan = chan_create(); + if (!pchan) + return NULL; + + pchan->ops = &bt_6lowpan_chan_ops; + + return pchan; +} + +static int bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type) +{ + struct l2cap_chan *pchan; + int err; + + pchan = chan_get(); + if (!pchan) + return -EINVAL; + + err = l2cap_chan_connect(pchan, cpu_to_le16(psm_6lowpan), 0, + addr, dst_type); + + BT_DBG("chan %p err %d", pchan, err); + if (err < 0) + l2cap_chan_put(pchan); + return err; } +static int bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type) +{ + struct lowpan_peer *peer; + + BT_DBG("conn %p dst type %d", conn, dst_type); + + peer = lookup_peer(conn); + if (!peer) + return -ENOENT; + + BT_DBG("peer %p chan %p", peer, peer->chan); + + l2cap_chan_close(peer->chan, ENOENT); + + return 0; +} + +static struct l2cap_chan *bt_6lowpan_listen(void) +{ + bdaddr_t *addr = BDADDR_ANY; + struct l2cap_chan *pchan; + int err; + + if (psm_6lowpan == 0) + return NULL; + + pchan = chan_get(); + if (!pchan) + return NULL; + + pchan->state = BT_LISTEN; + pchan->src_type = BDADDR_LE_PUBLIC; + + BT_DBG("psm 0x%04x chan %p src type %d", psm_6lowpan, pchan, + pchan->src_type); + + err = l2cap_add_psm(pchan, addr, cpu_to_le16(psm_6lowpan)); + if (err) { + l2cap_chan_put(pchan); + BT_ERR("psm cannot be added err %d", err); + return NULL; + } + + return pchan; +} + +static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type, + struct l2cap_conn **conn) +{ + struct hci_conn *hcon; + struct hci_dev *hdev; + bdaddr_t *src = BDADDR_ANY; + int n; + + n = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu", + &addr->b[5], &addr->b[4], &addr->b[3], + &addr->b[2], &addr->b[1], &addr->b[0], + addr_type); + + if (n < 7) + return -EINVAL; + + hdev = hci_get_route(addr, src); + if (!hdev) + return -ENOENT; + + hci_dev_lock(hdev); + hcon = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr); + hci_dev_unlock(hdev); + + if (!hcon) + return -ENOENT; + + *conn = (struct l2cap_conn *)hcon->l2cap_data; + + BT_DBG("conn %p dst %pMR type %d", *conn, &hcon->dst, hcon->dst_type); + + return 0; +} + +static void disconnect_all_peers(void) +{ + struct lowpan_dev *entry, *tmp_dev; + struct lowpan_peer *peer, *tmp_peer, *new_peer; + struct list_head peers; + unsigned long flags; + + INIT_LIST_HEAD(&peers); + + /* We make a separate list of peers as the close_cb() will + * modify the device peers list so it is better not to mess + * with the same list at the same time. + */ + + read_lock_irqsave(&devices_lock, flags); + + list_for_each_entry_safe(entry, tmp_dev, &bt_6lowpan_devices, list) { + list_for_each_entry_safe(peer, tmp_peer, &entry->peers, list) { + new_peer = kmalloc(sizeof(*new_peer), GFP_ATOMIC); + if (!new_peer) + break; + + new_peer->chan = peer->chan; + INIT_LIST_HEAD(&new_peer->list); + + list_add(&new_peer->list, &peers); + } + } + + read_unlock_irqrestore(&devices_lock, flags); + + list_for_each_entry_safe(peer, tmp_peer, &peers, list) { + l2cap_chan_close(peer->chan, ENOENT); + kfree(peer); + } +} + +static int lowpan_psm_set(void *data, u64 val) +{ + u16 psm; + + psm = val; + if (psm == 0 || psm_6lowpan != psm) + /* Disconnect existing connections if 6lowpan is + * disabled (psm = 0), or if psm changes. + */ + disconnect_all_peers(); + + psm_6lowpan = psm; + + if (listen_chan) { + l2cap_chan_close(listen_chan, 0); + l2cap_chan_put(listen_chan); + } + + listen_chan = bt_6lowpan_listen(); + + return 0; +} + +static int lowpan_psm_get(void *data, u64 *val) +{ + *val = psm_6lowpan; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(lowpan_psm_fops, lowpan_psm_get, + lowpan_psm_set, "%llu\n"); + +static ssize_t lowpan_control_write(struct file *fp, + const char __user *user_buffer, + size_t count, + loff_t *position) +{ + char buf[32]; + size_t buf_size = min(count, sizeof(buf) - 1); + int ret; + bdaddr_t addr; + u8 addr_type; + struct l2cap_conn *conn = NULL; + + if (copy_from_user(buf, user_buffer, buf_size)) + return -EFAULT; + + buf[buf_size] = '\0'; + + if (memcmp(buf, "connect ", 8) == 0) { + ret = get_l2cap_conn(&buf[8], &addr, &addr_type, &conn); + if (ret == -EINVAL) + return ret; + + if (listen_chan) { + l2cap_chan_close(listen_chan, 0); + l2cap_chan_put(listen_chan); + listen_chan = NULL; + } + + if (conn) { + struct lowpan_peer *peer; + + if (!is_bt_6lowpan(conn->hcon)) + return -EINVAL; + + peer = lookup_peer(conn); + if (peer) { + BT_DBG("6LoWPAN connection already exists"); + return -EALREADY; + } + + BT_DBG("conn %p dst %pMR type %d user %d", conn, + &conn->hcon->dst, conn->hcon->dst_type, + addr_type); + } + + ret = bt_6lowpan_connect(&addr, addr_type); + if (ret < 0) + return ret; + + return count; + } + + if (memcmp(buf, "disconnect ", 11) == 0) { + ret = get_l2cap_conn(&buf[11], &addr, &addr_type, &conn); + if (ret < 0) + return ret; + + ret = bt_6lowpan_disconnect(conn, addr_type); + if (ret < 0) + return ret; + + return count; + } + + return count; +} + +static int lowpan_control_show(struct seq_file *f, void *ptr) +{ + struct lowpan_dev *entry, *tmp_dev; + struct lowpan_peer *peer, *tmp_peer; + unsigned long flags; + + read_lock_irqsave(&devices_lock, flags); + + list_for_each_entry_safe(entry, tmp_dev, &bt_6lowpan_devices, list) { + list_for_each_entry_safe(peer, tmp_peer, &entry->peers, list) + seq_printf(f, "%pMR (type %u)\n", + &peer->chan->dst, peer->chan->dst_type); + } + + read_unlock_irqrestore(&devices_lock, flags); + + return 0; +} + +static int lowpan_control_open(struct inode *inode, struct file *file) +{ + return single_open(file, lowpan_control_show, inode->i_private); +} + +static const struct file_operations lowpan_control_fops = { + .open = lowpan_control_open, + .read = seq_read, + .write = lowpan_control_write, + .llseek = seq_lseek, + .release = single_release, +}; + static int device_event(struct notifier_block *unused, unsigned long event, void *ptr) { @@ -856,10 +1214,25 @@ static struct notifier_block bt_6lowpan_dev_notifier = { int bt_6lowpan_init(void) { + lowpan_psm_debugfs = debugfs_create_file("6lowpan_psm", 0644, + bt_debugfs, NULL, + &lowpan_psm_fops); + lowpan_control_debugfs = debugfs_create_file("6lowpan_control", 0644, + bt_debugfs, NULL, + &lowpan_control_fops); + return register_netdevice_notifier(&bt_6lowpan_dev_notifier); } -void bt_6lowpan_cleanup(void) +void bt_6lowpan_exit(void) { + debugfs_remove(lowpan_psm_debugfs); + debugfs_remove(lowpan_control_debugfs); + + if (listen_chan) { + l2cap_chan_close(listen_chan, 0); + l2cap_chan_put(listen_chan); + } + unregister_netdevice_notifier(&bt_6lowpan_dev_notifier); } diff --git a/net/bluetooth/6lowpan.h b/net/bluetooth/6lowpan.h deleted file mode 100644 index 5d281f1eaf55..000000000000 --- a/net/bluetooth/6lowpan.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright (c) 2013 Intel Corp. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 and - only version 2 as published by the Free Software Foundation. - - 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. -*/ - -#ifndef __6LOWPAN_H -#define __6LOWPAN_H - -#include -#include -#include - -#if IS_ENABLED(CONFIG_BT_6LOWPAN) -int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb); -int bt_6lowpan_add_conn(struct l2cap_conn *conn); -int bt_6lowpan_del_conn(struct l2cap_conn *conn); -int bt_6lowpan_init(void); -void bt_6lowpan_cleanup(void); -#else -static int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb) -{ - return -EOPNOTSUPP; -} -static int bt_6lowpan_add_conn(struct l2cap_conn *conn) -{ - return -EOPNOTSUPP; -} -int bt_6lowpan_del_conn(struct l2cap_conn *conn) -{ - return -EOPNOTSUPP; -} -static int bt_6lowpan_init(void) -{ - return -EOPNOTSUPP; -} -static void bt_6lowpan_cleanup(void) { } -#endif - -#endif /* __6LOWPAN_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ddbb084250be..bbfc5455acec 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -928,49 +928,6 @@ static int adv_channel_map_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get, adv_channel_map_set, "%llu\n"); -static ssize_t lowpan_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct hci_dev *hdev = file->private_data; - char buf[3]; - - buf[0] = test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags) ? 'Y' : 'N'; - buf[1] = '\n'; - buf[2] = '\0'; - return simple_read_from_buffer(user_buf, count, ppos, buf, 2); -} - -static ssize_t lowpan_write(struct file *fp, const char __user *user_buffer, - size_t count, loff_t *position) -{ - struct hci_dev *hdev = fp->private_data; - bool enable; - char buf[32]; - size_t buf_size = min(count, (sizeof(buf)-1)); - - if (copy_from_user(buf, user_buffer, buf_size)) - return -EFAULT; - - buf[buf_size] = '\0'; - - if (strtobool(buf, &enable) < 0) - return -EINVAL; - - if (enable == test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags)) - return -EALREADY; - - change_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags); - - return count; -} - -static const struct file_operations lowpan_debugfs_fops = { - .open = simple_open, - .read = lowpan_read, - .write = lowpan_write, - .llseek = default_llseek, -}; - static int le_auto_conn_show(struct seq_file *sf, void *ptr) { struct hci_dev *hdev = sf->private; @@ -1881,8 +1838,6 @@ static int __hci_init(struct hci_dev *hdev) hdev, &conn_max_interval_fops); debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, hdev, &adv_channel_map_fops); - debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev, - &lowpan_debugfs_fops); debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev, &le_auto_conn_fops); debugfs_create_u16("discov_interleaved_timeout", 0644, diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 15a0a65bf447..e5b430113cfb 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4056,9 +4056,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->handle = __le16_to_cpu(ev->handle); conn->state = BT_CONNECTED; - if (test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags)) - set_bit(HCI_CONN_6LOWPAN, &conn->flags); - hci_conn_add_sysfs(conn); hci_proto_connect_cfm(conn, ev->status); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d0a5fde61a07..cbf6b9d1c404 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -40,7 +40,6 @@ #include "smp.h" #include "a2mp.h" #include "amp.h" -#include "6lowpan.h" #define LE_FLOWCTL_MAX_CREDITS 65535 @@ -205,6 +204,7 @@ done: write_unlock(&chan_list_lock); return err; } +EXPORT_SYMBOL_GPL(l2cap_add_psm); int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) { @@ -437,6 +437,7 @@ struct l2cap_chan *l2cap_chan_create(void) return chan; } +EXPORT_SYMBOL_GPL(l2cap_chan_create); static void l2cap_chan_destroy(struct kref *kref) { @@ -464,6 +465,7 @@ void l2cap_chan_put(struct l2cap_chan *c) kref_put(&c->kref, l2cap_chan_destroy); } +EXPORT_SYMBOL_GPL(l2cap_chan_put); void l2cap_chan_set_defaults(struct l2cap_chan *chan) { @@ -482,6 +484,7 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan) set_bit(FLAG_FORCE_ACTIVE, &chan->flags); } +EXPORT_SYMBOL_GPL(l2cap_chan_set_defaults); static void l2cap_le_flowctl_init(struct l2cap_chan *chan) { @@ -614,6 +617,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) return; } +EXPORT_SYMBOL_GPL(l2cap_chan_del); void l2cap_conn_update_id_addr(struct hci_conn *hcon) { @@ -717,6 +721,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) break; } } +EXPORT_SYMBOL(l2cap_chan_close); static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) { @@ -1460,8 +1465,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) BT_DBG(""); - bt_6lowpan_add_conn(conn); - /* Check if we have socket listening on cid */ pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT, &hcon->src, &hcon->dst); @@ -2555,6 +2558,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) return err; } +EXPORT_SYMBOL_GPL(l2cap_chan_send); static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq) { @@ -6933,10 +6937,6 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) l2cap_conn_del(conn->hcon, EACCES); break; - case L2CAP_FC_6LOWPAN: - bt_6lowpan_recv(conn, skb); - break; - default: l2cap_data_channel(conn, cid, skb); break; @@ -7183,6 +7183,7 @@ done: hci_dev_put(hdev); return err; } +EXPORT_SYMBOL_GPL(l2cap_chan_connect); /* ---- L2CAP interface with lower layer (HCI) ---- */ @@ -7245,8 +7246,6 @@ void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) { BT_DBG("hcon %p reason %d", hcon, reason); - bt_6lowpan_del_conn(hcon->l2cap_data); - l2cap_conn_del(hcon, bt_to_errno(reason)); } @@ -7529,14 +7528,11 @@ int __init l2cap_init(void) debugfs_create_u16("l2cap_le_default_mps", 0644, bt_debugfs, &le_default_mps); - bt_6lowpan_init(); - return 0; } void l2cap_exit(void) { - bt_6lowpan_cleanup(); debugfs_remove(l2cap_debugfs); l2cap_cleanup_sockets(); } -- cgit v1.2.3 From 5547e48c09d51ad21948c8090a34339939651450 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 18 Jun 2014 16:37:09 +0300 Subject: Bluetooth: 6LoWPAN: Create a kernel module Instead of adding the 6LoWPAN functionality to Bluetooth module, we create a separate kernel module for it. Usage: In the slave side do this: $ modprobe bluetooth_6lowpan $ echo 62 > /sys/kernel/debug/bluetooth/6lowpan_psm $ hciconfig hci0 leadv In the master side do this: $ modprobe bluetooth_6lowpan $ echo 62 > /sys/kernel/debug/bluetooth/6lowpan_psm $ echo 'connect E0:06:E6:B7:2A:73 1' > \ /sys/kernel/debug/bluetooth/6lowpan_control The 6LoWPAN functionality can be controlled by psm value. If it is left to 0, then the module is disabled and all the 6LoWPAN connections are dropped if there were any. In the above example, the psm value is just an example and not a real value for 6LoWPAN service. The real psm value is yet to be defined in Bluetooth specification. The 6lowpan controlling interface is a temporary solution until the specifications are ready. Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- net/bluetooth/6lowpan.c | 13 +++++++++++-- net/bluetooth/Kconfig | 6 +++--- net/bluetooth/Makefile | 4 +++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index bdb01eb3bfcc..ceffe20fcbaa 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -1212,7 +1213,7 @@ static struct notifier_block bt_6lowpan_dev_notifier = { .notifier_call = device_event, }; -int bt_6lowpan_init(void) +static int __init bt_6lowpan_init(void) { lowpan_psm_debugfs = debugfs_create_file("6lowpan_psm", 0644, bt_debugfs, NULL, @@ -1224,7 +1225,7 @@ int bt_6lowpan_init(void) return register_netdevice_notifier(&bt_6lowpan_dev_notifier); } -void bt_6lowpan_exit(void) +static void __exit bt_6lowpan_exit(void) { debugfs_remove(lowpan_psm_debugfs); debugfs_remove(lowpan_control_debugfs); @@ -1236,3 +1237,11 @@ void bt_6lowpan_exit(void) unregister_netdevice_notifier(&bt_6lowpan_dev_notifier); } + +module_init(bt_6lowpan_init); +module_exit(bt_6lowpan_exit); + +MODULE_AUTHOR("Jukka Rissanen "); +MODULE_DESCRIPTION("Bluetooth 6LoWPAN"); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 06ec14499ca1..f5afaa22f6ec 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -6,7 +6,6 @@ menuconfig BT tristate "Bluetooth subsystem support" depends on NET && !S390 depends on RFKILL || !RFKILL - select 6LOWPAN_IPHC if BT_6LOWPAN select CRC16 select CRYPTO select CRYPTO_BLKCIPHER @@ -41,10 +40,11 @@ menuconfig BT more information, see . config BT_6LOWPAN - bool "Bluetooth 6LoWPAN support" + tristate "Bluetooth 6LoWPAN support" depends on BT && IPV6 + select 6LOWPAN_IPHC if BT_6LOWPAN help - IPv6 compression over Bluetooth. + IPv6 compression over Bluetooth Low Energy. source "net/bluetooth/rfcomm/Kconfig" diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index ca51246b1016..886e9aa3ecf1 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -7,10 +7,12 @@ obj-$(CONFIG_BT_RFCOMM) += rfcomm/ obj-$(CONFIG_BT_BNEP) += bnep/ obj-$(CONFIG_BT_CMTP) += cmtp/ obj-$(CONFIG_BT_HIDP) += hidp/ +obj-$(CONFIG_BT_6LOWPAN) += bluetooth_6lowpan.o + +bluetooth_6lowpan-y := 6lowpan.o bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ a2mp.o amp.o -bluetooth-$(CONFIG_BT_6LOWPAN) += 6lowpan.o subdir-ccflags-y += -D__CHECK_ENDIAN__ -- cgit v1.2.3 From 18d93c176641cf7a3c0c452a6f03f46b5373d370 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 18 Jun 2014 16:37:10 +0300 Subject: Bluetooth: 6LoWPAN: Count module usage Count how many 6LoWPAN connections there exists so that we do not unload the module if there are still connections alive. Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- net/bluetooth/6lowpan.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index ceffe20fcbaa..ba6c64163685 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -100,6 +100,8 @@ static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer) { list_del(&peer->list); + module_put(THIS_MODULE); + if (atomic_dec_and_test(&dev->peer_count)) { BT_DBG("last peer"); return true; @@ -752,6 +754,9 @@ static inline void chan_ready_cb(struct l2cap_chan *chan) } } + if (!try_module_get(THIS_MODULE)) + return; + add_peer_chan(chan, dev); ifup(dev->netdev); } -- cgit v1.2.3 From 7f118253820fc3ad38659485adb3ebdfe64820e1 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 18 Jun 2014 16:37:11 +0300 Subject: Bluetooth: 6LoWPAN: Remove network devices when unloading When the module is unloaded, unregister the network device so that the system does not try to access non-existing device. Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- net/bluetooth/6lowpan.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index ba6c64163685..5a7f81df603c 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -607,6 +607,17 @@ static void ifup(struct net_device *netdev) rtnl_unlock(); } +static void ifdown(struct net_device *netdev) +{ + int err; + + rtnl_lock(); + err = dev_close(netdev); + if (err < 0) + BT_INFO("iface %s cannot be closed (%d)", netdev->name, err); + rtnl_unlock(); +} + static void do_notify_peers(struct work_struct *work) { struct lowpan_dev *dev = container_of(work, struct lowpan_dev, @@ -829,6 +840,8 @@ static void chan_close_cb(struct l2cap_chan *chan) cancel_delayed_work_sync(&dev->notify_peers); + ifdown(dev->netdev); + if (!removed) { INIT_WORK(&entry->delete_netdev, delete_netdev); schedule_work(&entry->delete_netdev); @@ -1186,6 +1199,43 @@ static const struct file_operations lowpan_control_fops = { .release = single_release, }; +static void disconnect_devices(void) +{ + struct lowpan_dev *entry, *tmp, *new_dev; + struct list_head devices; + unsigned long flags; + + INIT_LIST_HEAD(&devices); + + /* We make a separate list of devices because the unregister_netdev() + * will call device_event() which will also want to modify the same + * devices list. + */ + + read_lock_irqsave(&devices_lock, flags); + + list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { + new_dev = kmalloc(sizeof(*new_dev), GFP_ATOMIC); + if (!new_dev) + break; + + new_dev->netdev = entry->netdev; + INIT_LIST_HEAD(&new_dev->list); + + list_add(&new_dev->list, &devices); + } + + read_unlock_irqrestore(&devices_lock, flags); + + list_for_each_entry_safe(entry, tmp, &devices, list) { + ifdown(entry->netdev); + BT_DBG("Unregistering netdev %s %p", + entry->netdev->name, entry->netdev); + unregister_netdev(entry->netdev); + kfree(entry); + } +} + static int device_event(struct notifier_block *unused, unsigned long event, void *ptr) { @@ -1202,6 +1252,8 @@ static int device_event(struct notifier_block *unused, list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { if (entry->netdev == netdev) { + BT_DBG("Unregistered netdev %s %p", + netdev->name, netdev); list_del(&entry->list); kfree(entry); break; @@ -1240,6 +1292,8 @@ static void __exit bt_6lowpan_exit(void) l2cap_chan_put(listen_chan); } + disconnect_devices(); + unregister_netdevice_notifier(&bt_6lowpan_dev_notifier); } -- cgit v1.2.3 From e04fde60efabe27afdbe041e3e5a09ec752ec9d2 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 23 Jun 2014 11:40:04 +0200 Subject: Bluetooth: Store current LE connection parameters in hci_conn struct The LE connection parameters are needed later on to be able to decide if it is required to trigger connection update procedures. So when the connection has been established successfully, store the current used parameters in hci_conn struct. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 3 +++ net/bluetooth/hci_event.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c81de0d366df..cd73a82cc713 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -381,6 +381,9 @@ struct hci_conn { __u16 setting; __u16 le_conn_min_interval; __u16 le_conn_max_interval; + __u16 le_conn_interval; + __u16 le_conn_latency; + __u16 le_supv_timeout; __s8 rssi; __s8 tx_power; __s8 max_tx_power; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e5b430113cfb..3d4741d789d3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4056,6 +4056,10 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->handle = __le16_to_cpu(ev->handle); conn->state = BT_CONNECTED; + conn->le_conn_interval = le16_to_cpu(ev->interval); + conn->le_conn_latency = le16_to_cpu(ev->latency); + conn->le_supv_timeout = le16_to_cpu(ev->supervision_timeout); + hci_conn_add_sysfs(conn); hci_proto_connect_cfm(conn, ev->status); -- cgit v1.2.3 From 1855d92dce0dc0ed81a78eacae710529600513f4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 23 Jun 2014 11:40:05 +0200 Subject: Bluetooth: Track LE connection parameter update event When the LE controller changes its connection parameters, it will send a connection parameter update event. Make sure that the new set of parameters are stored in hci_conn struct and thus will properly update the previous values retrieved from the connection complete event. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 9 +++++++++ net/bluetooth/hci_event.c | 27 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 3f3a3f1399fb..6b8371d73d3d 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1666,6 +1666,15 @@ struct hci_ev_le_conn_complete { __u8 clk_accurancy; } __packed; +#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03 +struct hci_ev_le_conn_update_complete { + __u8 status; + __le16 handle; + __le16 interval; + __le16 latency; + __le16 supervision_timeout; +} __packed; + #define HCI_EV_LE_LTK_REQ 0x05 struct hci_ev_le_ltk_req { __le16 handle; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3d4741d789d3..e239435312dc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4070,6 +4070,29 @@ unlock: hci_dev_unlock(hdev); } +static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_ev_le_conn_update_complete *ev = (void *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); + + if (ev->status) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn) { + conn->le_conn_interval = le16_to_cpu(ev->interval); + conn->le_conn_latency = le16_to_cpu(ev->latency); + conn->le_supv_timeout = le16_to_cpu(ev->supervision_timeout); + } + + hci_dev_unlock(hdev); +} + /* This function requires the caller holds hdev->lock */ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) @@ -4269,6 +4292,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_le_conn_complete_evt(hdev, skb); break; + case HCI_EV_LE_CONN_UPDATE_COMPLETE: + hci_le_conn_update_complete_evt(hdev, skb); + break; + case HCI_EV_LE_ADVERTISING_REPORT: hci_le_adv_report_evt(hdev, skb); break; -- cgit v1.2.3 From a720d7351e2571bf7498681970b076e366a7d221 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 23 Jun 2014 12:14:51 +0200 Subject: Bluetooth: Set default min/max connection interval for LE slaves For all incoming LE connections, the minimum and maximum connection interval is a value that should be copied from the controller default values. This allows to properly check if the resulting connection interval of a newly established connection is in the range we are expecting. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e239435312dc..e1e1ecb4db10 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4026,6 +4026,14 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->init_addr_type = ev->bdaddr_type; bacpy(&conn->init_addr, &ev->bdaddr); + + /* For incoming connections, set the default minimum + * and maximum connection interval. They will be used + * to check if the parameters are in range and if not + * trigger the connection update procedure. + */ + conn->le_conn_min_interval = hdev->le_conn_min_interval; + conn->le_conn_max_interval = hdev->le_conn_max_interval; } /* Lookup the identity address from the stored connection -- cgit v1.2.3 From 80afeb6cec3739d3167e1fef6214224f0f588f13 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 23 Jun 2014 12:18:51 +0200 Subject: Bluetooth: Add support LE slave connection update procedure When the current LE connection parameters of a slave connection do not match up with the controller defined values, then trigger the connection update procedure to allow adjusting them. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cbf6b9d1c404..565afb78296a 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1481,6 +1481,25 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, dst_type)) return; + /* For LE slave connections, make sure the connection interval + * is in the range of the minium and maximum interval that has + * been configured for this connection. If not, then trigger + * the connection update procedure. + */ + if (!(hcon->link_mode & HCI_LM_MASTER) && + (hcon->le_conn_interval < hcon->le_conn_min_interval || + hcon->le_conn_interval > hcon->le_conn_max_interval)) { + struct l2cap_conn_param_update_req req; + + req.min = cpu_to_le16(hcon->le_conn_min_interval); + req.max = cpu_to_le16(hcon->le_conn_max_interval); + req.latency = cpu_to_le16(hcon->le_conn_latency); + req.to_multiplier = cpu_to_le16(hcon->le_supv_timeout); + + l2cap_send_cmd(conn, l2cap_get_ident(conn), + L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req); + } + l2cap_chan_lock(pchan); chan = pchan->ops->new_connection(pchan); -- cgit v1.2.3 From 37f468cd171c7d76d560b6bd5c09dc506ab9dbec Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Mon, 23 Jun 2014 15:49:46 +0200 Subject: Bluetooth: Remove redundant calls to h5_reset_rx h5_reset_rx is unconditionally called at the end of h5_complete_rx_pkt, no need to call it anymore after that. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_h5.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index fede8ca7147c..caacb422995d 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -355,10 +355,7 @@ static void h5_complete_rx_pkt(struct hci_uart *hu) static int h5_rx_crc(struct hci_uart *hu, unsigned char c) { - struct h5 *h5 = hu->priv; - h5_complete_rx_pkt(hu); - h5_reset_rx(h5); return 0; } @@ -373,7 +370,6 @@ static int h5_rx_payload(struct hci_uart *hu, unsigned char c) h5->rx_pending = 2; } else { h5_complete_rx_pkt(hu); - h5_reset_rx(h5); } return 0; -- cgit v1.2.3 From 567fa2aa3dfad9848c25a226927a4ca5f94229ac Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 24 Jun 2014 13:15:48 +0300 Subject: Bluetooth: Update hci_add_link_key() to return pointer to key By returning the added (or updated) key we pave the way for further refactoring (in subsequent patches) that allows moving the mgmt event sending out from this function (and thereby removal of the awkward new_key parameter). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 5 +++-- net/bluetooth/hci_core.c | 11 ++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index cd73a82cc713..7f81791a865d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -859,8 +859,9 @@ void hci_uuids_clear(struct hci_dev *hdev); void hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); -int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, - bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); +struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, + int new_key, bdaddr_t *bdaddr, u8 *val, + u8 type, u8 pin_len); struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, bool master); struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index bbfc5455acec..ee42788aed2c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3001,8 +3001,9 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, return NULL; } -int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, - bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) +struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, + int new_key, bdaddr_t *bdaddr, u8 *val, + u8 type, u8 pin_len) { struct link_key *key, *old_key; u8 old_key_type; @@ -3016,7 +3017,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, old_key_type = conn ? conn->key_type : 0xff; key = kzalloc(sizeof(*key), GFP_KERNEL); if (!key) - return -ENOMEM; + return NULL; list_add(&key->list, &hdev->link_keys); } @@ -3042,7 +3043,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, key->type = type; if (!new_key) - return 0; + return key; persistent = hci_persistent_key(hdev, conn, type, old_key_type); @@ -3051,7 +3052,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, if (conn) conn->flush_key = !persistent; - return 0; + return key; } struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, -- cgit v1.2.3 From 7652ff6aeaf0eeaec1f2e7e2f3ce0e588447dbd1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 24 Jun 2014 13:15:49 +0300 Subject: Bluetooth: Move mgmt event sending out from hci_add_link_key() There are two callers of hci_add_link_key(). The first one is the HCI Link Key Notification event and the second one the mgmt code that receives a list of link keys from user space. Previously we've had the hci_add_link_key() function being responsible for also emitting a mgmt signal but for the latter use case this should not happen. Because of this a rather awkward new_key paramter has been passed to the function. This patch moves the mgmt event sending out from the hci_add_link_key() function, thereby making the code a bit more understandable. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 4 ++-- net/bluetooth/hci_core.c | 17 +++++------------ net/bluetooth/hci_event.c | 18 +++++++++++++++--- net/bluetooth/mgmt.c | 4 ++-- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7f81791a865d..888911d205dc 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -860,8 +860,8 @@ void hci_uuids_clear(struct hci_dev *hdev); void hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, - int new_key, bdaddr_t *bdaddr, u8 *val, - u8 type, u8 pin_len); + bdaddr_t *bdaddr, u8 *val, u8 type, + u8 pin_len, bool *persistent); struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, bool master); struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ee42788aed2c..159783e746c0 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3002,12 +3002,11 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, } struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, - int new_key, bdaddr_t *bdaddr, u8 *val, - u8 type, u8 pin_len) + bdaddr_t *bdaddr, u8 *val, u8 type, + u8 pin_len, bool *persistent) { struct link_key *key, *old_key; u8 old_key_type; - bool persistent; old_key = hci_find_link_key(hdev, bdaddr); if (old_key) { @@ -3042,15 +3041,9 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, else key->type = type; - if (!new_key) - return key; - - persistent = hci_persistent_key(hdev, conn, type, old_key_type); - - mgmt_new_link_key(hdev, key, persistent); - - if (conn) - conn->flush_key = !persistent; + if (persistent) + *persistent = hci_persistent_key(hdev, conn, type, + old_key_type); return key; } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e1e1ecb4db10..47bd48a597bd 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3111,6 +3111,8 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_link_key_notify *ev = (void *) skb->data; struct hci_conn *conn; + struct link_key *key; + bool persistent; u8 pin_len = 0; BT_DBG("%s", hdev->name); @@ -3129,10 +3131,20 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_conn_drop(conn); } - if (test_bit(HCI_MGMT, &hdev->dev_flags)) - hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key, - ev->key_type, pin_len); + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + goto unlock; + + key = hci_add_link_key(hdev, conn, &ev->bdaddr, ev->link_key, + ev->key_type, pin_len, &persistent); + if (!key) + goto unlock; + + mgmt_new_link_key(hdev, key, persistent); + if (conn) + conn->flush_key = !persistent; + +unlock: hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e1651c3fc676..bb5b04191253 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2424,8 +2424,8 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, for (i = 0; i < key_count; i++) { struct mgmt_link_key_info *key = &cp->keys[i]; - hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val, - key->type, key->pin_len); + hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val, + key->type, key->pin_len, NULL); } cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0); -- cgit v1.2.3 From 0663b297f1953e5d84928722e44f71272f5ff058 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 24 Jun 2014 13:15:50 +0300 Subject: Bluetooth: Rename HCI_DEBUG_KEYS to HCI_KEEP_DEBUG_KEYS We're planning to add a flag to actively use debug keys in addition to simply just accepting them, which makes the current generically named DEBUG_KEYS flag a bit confusing. Since the flag in practice affects whether the kernel keeps debug keys around or not rename it to HCI_KEEP_DEBUG_KEYS. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 2 +- net/bluetooth/hci_event.c | 2 +- net/bluetooth/mgmt.c | 14 +++++++++----- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6b8371d73d3d..ffb489e3946d 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -124,7 +124,7 @@ enum { HCI_MGMT, HCI_PAIRABLE, HCI_SERVICE_CACHE, - HCI_DEBUG_KEYS, + HCI_KEEP_DEBUG_KEYS, HCI_UNREGISTER, HCI_USER_CHANNEL, diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 47bd48a597bd..b0fdeec2f2ca 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3066,7 +3066,7 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s found key type %u for %pMR", hdev->name, key->type, &ev->bdaddr); - if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) && + if (!test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags) && key->type == HCI_LK_DEBUG_COMBINATION) { BT_DBG("%s ignoring debug key", hdev->name); goto not_found; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bb5b04191253..634b44ddc9f9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -440,7 +440,7 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) settings |= MGMT_SETTING_SECURE_CONN; - if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags)) + if (test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags)) settings |= MGMT_SETTING_DEBUG_KEYS; if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) @@ -2414,9 +2414,11 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, hci_link_keys_clear(hdev); if (cp->debug_keys) - changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + changed = !test_and_set_bit(HCI_KEEP_DEBUG_KEYS, + &hdev->dev_flags); else - changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + changed = test_and_clear_bit(HCI_KEEP_DEBUG_KEYS, + &hdev->dev_flags); if (changed) new_settings(hdev, NULL); @@ -4349,9 +4351,11 @@ static int set_debug_keys(struct sock *sk, struct hci_dev *hdev, hci_dev_lock(hdev); if (cp->val) - changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + changed = !test_and_set_bit(HCI_KEEP_DEBUG_KEYS, + &hdev->dev_flags); else - changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + changed = test_and_clear_bit(HCI_KEEP_DEBUG_KEYS, + &hdev->dev_flags); err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev); if (err < 0) -- cgit v1.2.3 From 6d5650c4e519794fcc441635ea54f47d68140c93 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 24 Jun 2014 13:15:51 +0300 Subject: Bluetooth: Don't store debug keys if flag for them is not set Instead of waiting for a disconnection to occur to remove a debug key simply never store it in the list to begin with. This means we can also remove the debug keys check when looking up keys in hci_link_key_request_evt(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b0fdeec2f2ca..c92c5a020fe7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3066,12 +3066,6 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s found key type %u for %pMR", hdev->name, key->type, &ev->bdaddr); - if (!test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags) && - key->type == HCI_LK_DEBUG_COMBINATION) { - BT_DBG("%s ignoring debug key", hdev->name); - goto not_found; - } - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn) { if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 || @@ -3141,8 +3135,18 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) mgmt_new_link_key(hdev, key, persistent); - if (conn) + /* Keep debug keys around only if the HCI_KEEP_DEBUG_KEYS flag + * is set. If it's not set simply remove the key from the kernel + * list (we've still notified user space about it but with + * store_hint being 0). + */ + if (key->type == HCI_LK_DEBUG_COMBINATION && + !test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags)) { + list_del(&key->list); + kfree(key); + } else if (conn) { conn->flush_key = !persistent; + } unlock: hci_dev_unlock(hdev); -- cgit v1.2.3 From af6a9c321384400efab1726636e8189737bbbd09 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 24 Jun 2014 13:15:53 +0300 Subject: Bluetooth: Convert hcon->flush_key to a proper flag There's no point in having boolean variables in the hci_conn struct since it already has a flags member. This patch converts the flush_key member into a proper flag. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_event.c | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 888911d205dc..4f70605e0399 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -394,7 +394,6 @@ struct hci_conn { __u8 remote_cap; __u8 remote_auth; __u8 remote_id; - bool flush_key; unsigned int sent; @@ -524,6 +523,7 @@ enum { HCI_CONN_AES_CCM, HCI_CONN_POWER_SAVE, HCI_CONN_REMOTE_OOB, + HCI_CONN_FLUSH_KEY, }; static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c92c5a020fe7..90cba6a8293b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2159,7 +2159,8 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type, reason, mgmt_connected); - if (conn->type == ACL_LINK && conn->flush_key) + if (conn->type == ACL_LINK && + test_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) hci_remove_link_key(hdev, &conn->dst); params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); @@ -3145,7 +3146,10 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) list_del(&key->list); kfree(key); } else if (conn) { - conn->flush_key = !persistent; + if (persistent) + clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags); + else + set_bit(HCI_CONN_FLUSH_KEY, &conn->flags); } unlock: -- cgit v1.2.3 From 58e9293c4e18b9b5f52822e7cbce589c70920721 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 24 Jun 2014 14:00:26 +0300 Subject: Bluetooth: Fix ignoring debug keys in mgmt_load_link_keys We should never allow user space to feed back debug keys to the kernel. If the user desires to use debug keys require setting the appropriate debug keys mode and performing a new pairing. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 634b44ddc9f9..747746b0d2c4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2426,6 +2426,12 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, for (i = 0; i < key_count; i++) { struct mgmt_link_key_info *key = &cp->keys[i]; + /* Always ignore debug keys and require a new pairing if + * the user wants to use them. + */ + if (key->type == HCI_LK_DEBUG_COMBINATION) + continue; + hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val, key->type, key->pin_len, NULL); } -- cgit v1.2.3 From 3769972badcd542913c460ca2834312cdff9f16c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 24 Jun 2014 14:00:27 +0300 Subject: Bluetooth: Add a new HCI_USE_DEBUG_KEYS flag To pave the way for actively using debug keys for pairing this patch adds a new HCI_USE_DEBUG_KEYS flag for the purpose. When the flag is set we issue a HCI_Write_SSP_Debug mode whenever HCI_Write_SSP_Mode(0x01) has been issued as well as before issuing a HCI_Write_SSP_Mode(0x00) command. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + net/bluetooth/mgmt.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ffb489e3946d..cc2e88dd20ea 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -125,6 +125,7 @@ enum { HCI_PAIRABLE, HCI_SERVICE_CACHE, HCI_KEEP_DEBUG_KEYS, + HCI_USE_DEBUG_KEYS, HCI_UNREGISTER, HCI_USER_CHANNEL, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 747746b0d2c4..69afbb2df133 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1877,6 +1877,10 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) goto failed; } + if (!cp->val && test_bit(HCI_USE_DEBUG_KEYS, &hdev->dev_flags)) + hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE, + sizeof(cp->val), &cp->val); + err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val); if (err < 0) { mgmt_pending_remove(cmd); @@ -5784,10 +5788,14 @@ void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) hci_req_init(&req, hdev); - if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) + if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { + if (test_bit(HCI_USE_DEBUG_KEYS, &hdev->dev_flags)) + hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE, + sizeof(enable), &enable); update_eir(&req); - else + } else { clear_eir(&req); + } hci_req_run(&req, NULL); } -- cgit v1.2.3 From b97109790c1fcbe6b5da21c441ba336cf1ab9a3c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 24 Jun 2014 14:00:28 +0300 Subject: Bluetooth: Add support for mode 0x02 for mgmt_set_debug_keys This patch adds a new valid mode 0x02 for the mgmt_set_debug_keys command. The 0x02 mode sets the HCI_USE_DEBUG_KEYS flag which makes us always use debug keys for pairing. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 69afbb2df133..f75a090cd7e4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4349,12 +4349,12 @@ static int set_debug_keys(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_mode *cp = data; - bool changed; + bool changed, use_changed; int err; BT_DBG("request for %s", hdev->name); - if (cp->val != 0x00 && cp->val != 0x01) + if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02) return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS, MGMT_STATUS_INVALID_PARAMS); @@ -4367,6 +4367,20 @@ static int set_debug_keys(struct sock *sk, struct hci_dev *hdev, changed = test_and_clear_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags); + if (cp->val == 0x02) + use_changed = !test_and_set_bit(HCI_USE_DEBUG_KEYS, + &hdev->dev_flags); + else + use_changed = test_and_clear_bit(HCI_USE_DEBUG_KEYS, + &hdev->dev_flags); + + if (hdev_is_powered(hdev) && use_changed && + test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { + u8 mode = (cp->val == 0x02) ? 0x01 : 0x00; + hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE, + sizeof(mode), &mode); + } + err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev); if (err < 0) goto unlock; -- cgit v1.2.3 From 985d904902681d736924afe3f4dae212c0e5f6a4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 24 Jun 2014 13:13:04 +0200 Subject: Bluetooth: Remove ssp_debug_mode debugfs option The ssp_debug_mode debugfs option for developers is no longer needed. Support for using Secure Simple Pairing (SSP) debug mode is exposed by the management interface now. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 51 ------------------------------------------------ 1 file changed, 51 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 159783e746c0..9852449ac104 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -352,55 +352,6 @@ static int auto_accept_delay_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get, auto_accept_delay_set, "%llu\n"); -static int ssp_debug_mode_set(void *data, u64 val) -{ - struct hci_dev *hdev = data; - struct sk_buff *skb; - __u8 mode; - int err; - - if (val != 0 && val != 1) - return -EINVAL; - - if (!test_bit(HCI_UP, &hdev->flags)) - return -ENETDOWN; - - hci_req_lock(hdev); - mode = val; - skb = __hci_cmd_sync(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE, sizeof(mode), - &mode, HCI_CMD_TIMEOUT); - hci_req_unlock(hdev); - - if (IS_ERR(skb)) - return PTR_ERR(skb); - - err = -bt_to_errno(skb->data[0]); - kfree_skb(skb); - - if (err < 0) - return err; - - hci_dev_lock(hdev); - hdev->ssp_debug_mode = val; - hci_dev_unlock(hdev); - - return 0; -} - -static int ssp_debug_mode_get(void *data, u64 *val) -{ - struct hci_dev *hdev = data; - - hci_dev_lock(hdev); - *val = hdev->ssp_debug_mode; - hci_dev_unlock(hdev); - - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(ssp_debug_mode_fops, ssp_debug_mode_get, - ssp_debug_mode_set, "%llu\n"); - static ssize_t force_sc_support_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1787,8 +1738,6 @@ static int __hci_init(struct hci_dev *hdev) if (lmp_ssp_capable(hdev)) { debugfs_create_file("auto_accept_delay", 0644, hdev->debugfs, hdev, &auto_accept_delay_fops); - debugfs_create_file("ssp_debug_mode", 0644, hdev->debugfs, - hdev, &ssp_debug_mode_fops); debugfs_create_file("force_sc_support", 0644, hdev->debugfs, hdev, &force_sc_support_fops); debugfs_create_file("sc_only_mode", 0444, hdev->debugfs, -- cgit v1.2.3 From 4dae27983eaaee15c6867561eb2c8d7b2d28d6cc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 24 Jun 2014 17:03:50 +0300 Subject: Bluetooth: Convert hci_conn->link_mode into flags Since the link_mode member of the hci_conn struct is a bit field and we already have a flags member as well it makes sense to merge these two together. This patch moves all used link_mode bits into corresponding flags. To keep backwards compatibility with user space we still need to provide a get_link_mode() helper function for the ioctl's that expect a link_mode style value. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 10 +++++++--- net/bluetooth/hci_conn.c | 43 ++++++++++++++++++++++++++++++---------- net/bluetooth/hci_event.c | 28 +++++++++++++------------- net/bluetooth/l2cap_core.c | 4 ++-- net/bluetooth/smp.c | 12 +++++------ 5 files changed, 62 insertions(+), 35 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4f70605e0399..0b0597d81827 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -367,7 +367,6 @@ struct hci_conn { __u8 features[HCI_MAX_PAGES][8]; __u16 pkt_type; __u16 link_policy; - __u32 link_mode; __u8 key_type; __u8 auth_type; __u8 sec_level; @@ -524,6 +523,11 @@ enum { HCI_CONN_POWER_SAVE, HCI_CONN_REMOTE_OOB, HCI_CONN_FLUSH_KEY, + HCI_CONN_MASTER, + HCI_CONN_ENCRYPT, + HCI_CONN_AUTH, + HCI_CONN_SECURE, + HCI_CONN_FIPS, }; static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) @@ -1025,7 +1029,7 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return; - encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; + encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00; l2cap_security_cfm(conn, status, encrypt); if (conn->security_cfm_cb) @@ -1066,7 +1070,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status) if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return; - encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00; + encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00; read_lock(&hci_cb_list_lock); list_for_each_entry(cb, &hci_cb_list, list) { diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index a7a27bc2c0b1..626160c37103 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -67,7 +67,7 @@ static void hci_acl_create_connection(struct hci_conn *conn) conn->state = BT_CONNECT; conn->out = true; - conn->link_mode = HCI_LM_MASTER; + set_bit(HCI_CONN_MASTER, &conn->flags); conn->attempt++; @@ -743,7 +743,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, } conn->out = true; - conn->link_mode |= HCI_LM_MASTER; + set_bit(HCI_CONN_MASTER, &conn->flags); params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); if (params) { @@ -865,7 +865,8 @@ int hci_conn_check_link_mode(struct hci_conn *conn) return 0; } - if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT)) + if (hci_conn_ssp_enabled(conn) && + !test_bit(HCI_CONN_ENCRYPT, &conn->flags)) return 0; return 1; @@ -881,7 +882,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) if (sec_level > conn->sec_level) conn->pending_sec_level = sec_level; - else if (conn->link_mode & HCI_LM_AUTH) + else if (test_bit(HCI_CONN_AUTH, &conn->flags)) return 1; /* Make sure we preserve an existing MITM requirement*/ @@ -899,7 +900,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* If we're already encrypted set the REAUTH_PEND flag, * otherwise set the ENCRYPT_PEND. */ - if (conn->link_mode & HCI_LM_ENCRYPT) + if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) set_bit(HCI_CONN_REAUTH_PEND, &conn->flags); else set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); @@ -940,7 +941,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) return 1; /* For other security levels we need the link key. */ - if (!(conn->link_mode & HCI_LM_AUTH)) + if (!test_bit(HCI_CONN_AUTH, &conn->flags)) goto auth; /* An authenticated FIPS approved combination key has sufficient @@ -980,7 +981,7 @@ auth: return 0; encrypt: - if (conn->link_mode & HCI_LM_ENCRYPT) + if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) return 1; hci_conn_encrypt(conn); @@ -1027,7 +1028,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) { BT_DBG("hcon %p", conn); - if (!role && conn->link_mode & HCI_LM_MASTER) + if (!role && test_bit(HCI_CONN_MASTER, &conn->flags)) return 1; if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) { @@ -1101,6 +1102,28 @@ void hci_conn_check_pending(struct hci_dev *hdev) hci_dev_unlock(hdev); } +static u32 get_link_mode(struct hci_conn *conn) +{ + u32 link_mode = 0; + + if (test_bit(HCI_CONN_MASTER, &conn->flags)) + link_mode |= HCI_LM_MASTER; + + if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) + link_mode |= HCI_LM_ENCRYPT; + + if (test_bit(HCI_CONN_AUTH, &conn->flags)) + link_mode |= HCI_LM_AUTH; + + if (test_bit(HCI_CONN_SECURE, &conn->flags)) + link_mode |= HCI_LM_SECURE; + + if (test_bit(HCI_CONN_FIPS, &conn->flags)) + link_mode |= HCI_LM_FIPS; + + return link_mode; +} + int hci_get_conn_list(void __user *arg) { struct hci_conn *c; @@ -1136,7 +1159,7 @@ int hci_get_conn_list(void __user *arg) (ci + n)->type = c->type; (ci + n)->out = c->out; (ci + n)->state = c->state; - (ci + n)->link_mode = c->link_mode; + (ci + n)->link_mode = get_link_mode(c); if (++n >= req.conn_num) break; } @@ -1172,7 +1195,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg) ci.type = conn->type; ci.out = conn->out; ci.state = conn->state; - ci.link_mode = conn->link_mode; + ci.link_mode = get_link_mode(conn); } hci_dev_unlock(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 90cba6a8293b..7a23324eac39 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -103,9 +103,9 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle)); if (conn) { if (rp->role) - conn->link_mode &= ~HCI_LM_MASTER; + clear_bit(HCI_CONN_MASTER, &conn->flags); else - conn->link_mode |= HCI_LM_MASTER; + set_bit(HCI_CONN_MASTER, &conn->flags); } hci_dev_unlock(hdev); @@ -1346,7 +1346,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); if (conn) { conn->out = true; - conn->link_mode |= HCI_LM_MASTER; + set_bit(HCI_CONN_MASTER, &conn->flags); } else BT_ERR("No memory for new connection"); } @@ -1989,10 +1989,10 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_conn_add_sysfs(conn); if (test_bit(HCI_AUTH, &hdev->flags)) - conn->link_mode |= HCI_LM_AUTH; + set_bit(HCI_CONN_AUTH, &conn->flags); if (test_bit(HCI_ENCRYPT, &hdev->flags)) - conn->link_mode |= HCI_LM_ENCRYPT; + set_bit(HCI_CONN_ENCRYPT, &conn->flags); /* Get remote features */ if (conn->type == ACL_LINK) { @@ -2220,7 +2220,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { BT_INFO("re-auth of legacy device is not possible."); } else { - conn->link_mode |= HCI_LM_AUTH; + set_bit(HCI_CONN_AUTH, &conn->flags); conn->sec_level = conn->pending_sec_level; } } else { @@ -2323,19 +2323,19 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) if (!ev->status) { if (ev->encrypt) { /* Encryption implies authentication */ - conn->link_mode |= HCI_LM_AUTH; - conn->link_mode |= HCI_LM_ENCRYPT; + set_bit(HCI_CONN_AUTH, &conn->flags); + set_bit(HCI_CONN_ENCRYPT, &conn->flags); conn->sec_level = conn->pending_sec_level; /* P-256 authentication key implies FIPS */ if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256) - conn->link_mode |= HCI_LM_FIPS; + set_bit(HCI_CONN_FIPS, &conn->flags); if ((conn->type == ACL_LINK && ev->encrypt == 0x02) || conn->type == LE_LINK) set_bit(HCI_CONN_AES_CCM, &conn->flags); } else { - conn->link_mode &= ~HCI_LM_ENCRYPT; + clear_bit(HCI_CONN_ENCRYPT, &conn->flags); clear_bit(HCI_CONN_AES_CCM, &conn->flags); } } @@ -2386,7 +2386,7 @@ static void hci_change_link_key_complete_evt(struct hci_dev *hdev, conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) - conn->link_mode |= HCI_LM_SECURE; + set_bit(HCI_CONN_SECURE, &conn->flags); clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); @@ -2828,9 +2828,9 @@ static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) if (conn) { if (!ev->status) { if (ev->role) - conn->link_mode &= ~HCI_LM_MASTER; + clear_bit(HCI_CONN_MASTER, &conn->flags); else - conn->link_mode |= HCI_LM_MASTER; + set_bit(HCI_CONN_MASTER, &conn->flags); } clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags); @@ -4007,7 +4007,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) if (ev->role == LE_CONN_ROLE_MASTER) { conn->out = true; - conn->link_mode |= HCI_LM_MASTER; + set_bit(HCI_CONN_MASTER, &conn->flags); } /* If we didn't have a hci_conn object previously diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 565afb78296a..d015aa190fdc 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1486,7 +1486,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) * been configured for this connection. If not, then trigger * the connection update procedure. */ - if (!(hcon->link_mode & HCI_LM_MASTER) && + if (!test_bit(HCI_CONN_MASTER, &hcon->flags) && (hcon->le_conn_interval < hcon->le_conn_min_interval || hcon->le_conn_interval > hcon->le_conn_max_interval)) { struct l2cap_conn_param_update_req req; @@ -5244,7 +5244,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, u16 min, max, latency, to_multiplier; int err; - if (!(hcon->link_mode & HCI_LM_MASTER)) + if (!test_bit(HCI_CONN_MASTER, &hcon->flags)) return -EINVAL; if (cmd_len != sizeof(struct l2cap_conn_param_update_req)) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 28f4ef48095b..976fce2315fd 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -435,7 +435,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, * Confirms and the slave Enters the passkey. */ if (method == OVERLAP) { - if (hcon->link_mode & HCI_LM_MASTER) + if (test_bit(HCI_CONN_MASTER, &hcon->flags)) method = CFM_PASSKEY; else method = REQ_PASSKEY; @@ -683,7 +683,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*req)) return SMP_INVALID_PARAMS; - if (conn->hcon->link_mode & HCI_LM_MASTER) + if (test_bit(HCI_CONN_MASTER, &conn->hcon->flags)) return SMP_CMD_NOTSUPP; if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) @@ -750,7 +750,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rsp)) return SMP_INVALID_PARAMS; - if (!(conn->hcon->link_mode & HCI_LM_MASTER)) + if (!test_bit(HCI_CONN_MASTER, &conn->hcon->flags)) return SMP_CMD_NOTSUPP; skb_pull(skb, sizeof(*rsp)); @@ -873,7 +873,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rp)) return SMP_INVALID_PARAMS; - if (!(conn->hcon->link_mode & HCI_LM_MASTER)) + if (!test_bit(HCI_CONN_MASTER, &conn->hcon->flags)) return SMP_CMD_NOTSUPP; sec_level = authreq_to_seclevel(rp->auth_req); @@ -937,7 +937,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) if (sec_level > hcon->pending_sec_level) hcon->pending_sec_level = sec_level; - if (hcon->link_mode & HCI_LM_MASTER) + if (test_bit(HCI_CONN_MASTER, &hcon->flags)) if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) return 0; @@ -957,7 +957,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) hcon->pending_sec_level > BT_SECURITY_MEDIUM) authreq |= SMP_AUTH_MITM; - if (hcon->link_mode & HCI_LM_MASTER) { + if (test_bit(HCI_CONN_MASTER, &hcon->flags)) { struct smp_cmd_pairing cp; build_pairing_cmd(conn, &cp, NULL, authreq); -- cgit v1.2.3 From dbbfa2ab7a2a508fd6ad2ce08f7f34c3041f51ef Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 25 Jun 2014 16:44:45 -0300 Subject: Bluetooth: Use macro instead of hard-coded value This patch replaces the hard-coded value in hci_bdaddr_is_rpa() helper by the corresponding macro ADDR_LE_DEV_RANDOM. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0b0597d81827..dda7f00c07c5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1155,7 +1155,7 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type) { - if (addr_type != 0x01) + if (addr_type != ADDR_LE_DEV_RANDOM) return false; if ((bdaddr->b[5] & 0xc0) == 0x40) -- cgit v1.2.3 From 31dd624e1cf937655a06fa4eeec06f4bafa34ab7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 27 Jun 2014 14:23:02 +0300 Subject: Bluetooth: Fix missing hdev locking in smp_cmd_ident_addr_info The hdev lock must be held before calling into smp_distribute_keys. Also things such as hci_add_irk() require the lock. This patch fixes the issue by adding the necessary locking into the smp_cmd_ident_addr_info function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 976fce2315fd..a38941593e8b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1076,6 +1076,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, skb_pull(skb, sizeof(*info)); + hci_dev_lock(hcon->hdev); + /* Strictly speaking the Core Specification (4.1) allows sending * an empty address which would force us to rely on just the IRK * as "identity information". However, since such @@ -1085,8 +1087,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, */ if (!bacmp(&info->bdaddr, BDADDR_ANY)) { BT_ERR("Ignoring IRK with no identity address"); - smp_distribute_keys(conn); - return 0; + goto distribute; } bacpy(&smp->id_addr, &info->bdaddr); @@ -1100,8 +1101,11 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, smp->remote_irk = hci_add_irk(conn->hcon->hdev, &smp->id_addr, smp->id_addr_type, smp->irk, &rpa); +distribute: smp_distribute_keys(conn); + hci_dev_unlock(hcon->hdev); + return 0; } -- cgit v1.2.3 From 6a7bd103c8a4286ef6f7134bfe6f104f32f2c4d4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 27 Jun 2014 14:23:03 +0300 Subject: Bluetooth: Add dedicated AES instance for each SMP context Many places have to be extra careful to not hold the hdev lock when calling into the SMP code. This is because the SMP crypto functions use the crypto handle that's part of the hci_dev struct. Giving the SMP context its own handle helps simplifying the locking logic and removes the risk for deadlocks. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index a38941593e8b..39ca9616d2de 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -62,6 +62,8 @@ struct smp_chan { struct smp_ltk *slave_ltk; struct smp_irk *remote_irk; unsigned long flags; + + struct crypto_blkcipher *tfm_aes; }; static inline void swap_buf(const u8 *src, u8 *dst, size_t len) @@ -583,6 +585,13 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) if (!smp) return NULL; + smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(smp->tfm_aes)) { + BT_ERR("Unable to create ECB crypto context"); + kfree(smp); + return NULL; + } + smp->conn = conn; conn->smp_chan = smp; conn->hcon->smp_conn = conn; @@ -605,6 +614,8 @@ void smp_chan_destroy(struct l2cap_conn *conn) kfree(smp->csrk); kfree(smp->slave_csrk); + crypto_free_blkcipher(smp->tfm_aes); + /* If pairing failed clean up any keys we might have */ if (!complete) { if (smp->ltk) { -- cgit v1.2.3 From ec70f36f8b17dd21c0d64af4481aa3c898c1cec7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 27 Jun 2014 14:23:04 +0300 Subject: Bluetooth: Update SMP crypto functions to take the SMP context Passing the full SMP context instead of just the crypto context lets us use the crypto handle from the context which in turn removes the need to lock the hci_dev. Passing the SMP context instead of just the crypto handle allows a bit more detailed logging which is helpful in multi-adapter scenarios. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 48 +++++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 39ca9616d2de..2566a3e43bb5 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -172,13 +172,16 @@ int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa) return 0; } -static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16], - u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia, - u8 _rat, bdaddr_t *ra, u8 res[16]) +static int smp_c1(struct smp_chan *smp, u8 k[16], u8 r[16], u8 preq[7], + u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat, bdaddr_t *ra, + u8 res[16]) { + struct hci_dev *hdev = smp->conn->hcon->hdev; u8 p1[16], p2[16]; int err; + BT_DBG("%s", hdev->name); + memset(p1, 0, 16); /* p1 = pres || preq || _rat || _iat */ @@ -196,7 +199,7 @@ static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16], u128_xor((u128 *) res, (u128 *) r, (u128 *) p1); /* res = e(k, res) */ - err = smp_e(tfm, k, res); + err = smp_e(smp->tfm_aes, k, res); if (err) { BT_ERR("Encrypt data error"); return err; @@ -206,23 +209,26 @@ static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16], u128_xor((u128 *) res, (u128 *) res, (u128 *) p2); /* res = e(k, res) */ - err = smp_e(tfm, k, res); + err = smp_e(smp->tfm_aes, k, res); if (err) BT_ERR("Encrypt data error"); return err; } -static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16], u8 r1[16], - u8 r2[16], u8 _r[16]) +static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16], + u8 _r[16]) { + struct hci_dev *hdev = smp->conn->hcon->hdev; int err; + BT_DBG("%s", hdev->name); + /* Just least significant octets from r1 and r2 are considered */ memcpy(_r, r2, 8); memcpy(_r + 8, r1, 8); - err = smp_e(tfm, k, _r); + err = smp_e(smp->tfm_aes, k, _r); if (err) BT_ERR("Encrypt data error"); @@ -475,23 +481,15 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, static u8 smp_confirm(struct smp_chan *smp) { struct l2cap_conn *conn = smp->conn; - struct hci_dev *hdev = conn->hcon->hdev; - struct crypto_blkcipher *tfm = hdev->tfm_aes; struct smp_cmd_pairing_confirm cp; int ret; BT_DBG("conn %p", conn); - /* Prevent mutual access to hdev->tfm_aes */ - hci_dev_lock(hdev); - - ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, + ret = smp_c1(smp, smp->tk, smp->prnd, smp->preq, smp->prsp, conn->hcon->init_addr_type, &conn->hcon->init_addr, conn->hcon->resp_addr_type, &conn->hcon->resp_addr, cp.confirm_val); - - hci_dev_unlock(hdev); - if (ret) return SMP_UNSPECIFIED; @@ -506,25 +504,17 @@ static u8 smp_random(struct smp_chan *smp) { struct l2cap_conn *conn = smp->conn; struct hci_conn *hcon = conn->hcon; - struct hci_dev *hdev = hcon->hdev; - struct crypto_blkcipher *tfm = hdev->tfm_aes; u8 confirm[16]; int ret; - if (IS_ERR_OR_NULL(tfm)) + if (IS_ERR_OR_NULL(smp->tfm_aes)) return SMP_UNSPECIFIED; BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); - /* Prevent mutual access to hdev->tfm_aes */ - hci_dev_lock(hdev); - - ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, + ret = smp_c1(smp, smp->tk, smp->rrnd, smp->preq, smp->prsp, hcon->init_addr_type, &hcon->init_addr, hcon->resp_addr_type, &hcon->resp_addr, confirm); - - hci_dev_unlock(hdev); - if (ret) return SMP_UNSPECIFIED; @@ -538,7 +528,7 @@ static u8 smp_random(struct smp_chan *smp) __le64 rand = 0; __le16 ediv = 0; - smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, stk); + smp_s1(smp, smp->tk, smp->rrnd, smp->prnd, stk); memset(stk + smp->enc_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); @@ -556,7 +546,7 @@ static u8 smp_random(struct smp_chan *smp) smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), smp->prnd); - smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, stk); + smp_s1(smp, smp->tk, smp->prnd, smp->rrnd, stk); memset(stk + smp->enc_key_size, 0, SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); -- cgit v1.2.3 From a9999348e70ebaf5ceaad8f23611d40a6db1e3bc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 27 Jun 2014 14:23:05 +0300 Subject: Bluetooth: Remove unnecessary hci_dev_unlock for smp_user_confirm_reply Now that the SMP context has it's own crypto handle it doesn't need to lock the hci_dev anymore for most operations. This means that it is safe to call smp_user_confirm_reply with the lock already held. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f75a090cd7e4..d542f8af6a5d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3052,14 +3052,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, } if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) { - /* Continue with pairing via SMP. The hdev lock must be - * released as SMP may try to recquire it for crypto - * purposes. - */ - hci_dev_unlock(hdev); err = smp_user_confirm_reply(conn, mgmt_op, passkey); - hci_dev_lock(hdev); - if (!err) err = cmd_complete(sk, hdev->id, mgmt_op, MGMT_STATUS_SUCCESS, addr, -- cgit v1.2.3 From 642ac7745a45904d2a7c2463a3a3e60dc097be04 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 27 Jun 2014 14:23:06 +0300 Subject: Bluetooth: Fix missing check for SMP session in smp_user_confirm_reply The smp_user_confirm_reply() function is called whenever user space sends a user confirmation reply mgmt command. In case of a misbehaving user space, or if the SMP session was removed by the time the command comes it is important that we return an appropriate error and do not try to access the non-existent SMP context. This patch adds the appropriate check for the HCI_CONN_LE_SMP_PEND flag before proceeding further. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 2566a3e43bb5..641ce8b69d2a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -638,7 +638,7 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) BT_DBG(""); - if (!conn) + if (!conn || !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return -ENOTCONN; smp = conn->smp_chan; -- cgit v1.2.3 From b10e8017bd9d02a3c7975c06d8fa2fc39df1731c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 27 Jun 2014 14:23:07 +0300 Subject: Bluetooth: Remove unnecessary hcon->smp_conn variable The smp_conn member of struct hci_conn was simply a pointer to the l2cap_conn object. Since we already have hcon->l2cap_data that points to the same thing there's no need to have this second variable. This patch removes it and changes the single place that was using it to use hcon->l2cap_data instead. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/smp.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index dda7f00c07c5..ca2a99807615 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -409,7 +409,6 @@ struct hci_conn { struct hci_dev *hdev; void *l2cap_data; void *sco_data; - void *smp_conn; struct amp_mgr *amp_mgr; struct hci_conn *link; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 641ce8b69d2a..414c5151aa46 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -584,7 +584,6 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) smp->conn = conn; conn->smp_chan = smp; - conn->hcon->smp_conn = conn; hci_conn_hold(conn->hcon); @@ -626,13 +625,12 @@ void smp_chan_destroy(struct l2cap_conn *conn) kfree(smp); conn->smp_chan = NULL; - conn->hcon->smp_conn = NULL; hci_conn_drop(conn->hcon); } int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) { - struct l2cap_conn *conn = hcon->smp_conn; + struct l2cap_conn *conn = hcon->l2cap_data; struct smp_chan *smp; u32 value; -- cgit v1.2.3 From a2b1976b8e0184635a1119f8511fc3e68902e429 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 27 Jun 2014 13:45:08 +0200 Subject: Bluetooth: Remove reason parameter from hci_amp_disconn function The hci_amp_disconn function is a local function and there is no need for a reason parameter. That one can be retrieved from the hci_conn object easily. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 626160c37103..cc64fbe952fa 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -136,7 +136,7 @@ void hci_disconnect(struct hci_conn *conn, __u8 reason) hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp); } -static void hci_amp_disconn(struct hci_conn *conn, __u8 reason) +static void hci_amp_disconn(struct hci_conn *conn) { struct hci_cp_disconn_phy_link cp; @@ -145,7 +145,7 @@ static void hci_amp_disconn(struct hci_conn *conn, __u8 reason) conn->state = BT_DISCONN; cp.phy_handle = HCI_PHY_HANDLE(conn->handle); - cp.reason = reason; + cp.reason = hci_proto_disconn_ind(conn); hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHY_LINK, sizeof(cp), &cp); } @@ -273,13 +273,14 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status) static void hci_conn_disconnect(struct hci_conn *conn) { - __u8 reason = hci_proto_disconn_ind(conn); + __u8 reason; switch (conn->type) { case AMP_LINK: - hci_amp_disconn(conn, reason); + hci_amp_disconn(conn); break; default: + reason = hci_proto_disconn_ind(conn); hci_disconnect(conn, reason); break; } -- cgit v1.2.3 From 40051e4686d6fa8743a38933727604f75bef05cf Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 27 Jun 2014 13:45:09 +0200 Subject: Bluetooth: Remove unneeded hci_conn_disconnect abstraction The abstraction of disconnect operation via hci_conn_disconnect is not needed and it does not add any readability. Handle the difference of AMP physical channels and BR/EDR/LE connection in the timeout callback. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index cc64fbe952fa..6d0fe3df2fa5 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -271,21 +271,6 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status) } } -static void hci_conn_disconnect(struct hci_conn *conn) -{ - __u8 reason; - - switch (conn->type) { - case AMP_LINK: - hci_amp_disconn(conn); - break; - default: - reason = hci_proto_disconn_ind(conn); - hci_disconnect(conn, reason); - break; - } -} - static void hci_conn_timeout(struct work_struct *work) { struct hci_conn *conn = container_of(work, struct hci_conn, @@ -320,7 +305,12 @@ static void hci_conn_timeout(struct work_struct *work) break; case BT_CONFIG: case BT_CONNECTED: - hci_conn_disconnect(conn); + if (conn->type == AMP_LINK) { + hci_amp_disconn(conn); + } else { + __u8 reason = hci_proto_disconn_ind(conn); + hci_disconnect(conn, reason); + } break; default: conn->state = BT_CLOSED; -- cgit v1.2.3 From df935429be40b02568d4bcf9ebfacf8011b85a85 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 27 Jun 2014 14:32:16 +0200 Subject: Bluetooth: Send HCI_Read_Clock_Offset before disconnecting When the connection is in master role and it is going to be disconnected based on the disconnection timeout, then send the HCI_Read_Clock_Offset command in an attempt to update the clock offset value in the inquiry cache. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 5 +++++ net/bluetooth/hci_conn.c | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index cc2e88dd20ea..6933766e7215 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -533,6 +533,11 @@ struct hci_cp_read_remote_version { __le16 handle; } __packed; +#define HCI_OP_READ_CLOCK_OFFSET 0x041f +struct hci_cp_read_clock_offset { + __le16 handle; +} __packed; + #define HCI_OP_SETUP_SYNC_CONN 0x0428 struct hci_cp_setup_sync_conn { __le16 handle; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 6d0fe3df2fa5..8a0c7a0ac1b6 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -309,6 +309,25 @@ static void hci_conn_timeout(struct work_struct *work) hci_amp_disconn(conn); } else { __u8 reason = hci_proto_disconn_ind(conn); + + /* When we are master of an established connection + * and it enters the disconnect timeout, then go + * ahead and try to read the current clock offset. + * + * Processing of the result is done within the + * event handling and hci_clock_offset_evt function. + */ + if (conn->type == ACL_LINK && + test_bit(HCI_CONN_MASTER, &conn->flags)) { + struct hci_dev *hdev = conn->hdev; + struct hci_cp_read_clock_offset cp; + + cp.handle = cpu_to_le16(conn->handle); + + hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET, + sizeof(cp), &cp); + } + hci_disconnect(conn, reason); } break; -- cgit v1.2.3 From 730f091b056524df2cb1c5f345f2d24e44236c19 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 28 Jun 2014 12:36:10 +0200 Subject: Bluetooth: Increment management interface revision This patch increments the management interface revision due to the changes with the debug key command and other fixes. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d542f8af6a5d..d42c07d2a817 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -35,7 +35,7 @@ #include "smp.h" #define MGMT_VERSION 1 -#define MGMT_REVISION 6 +#define MGMT_REVISION 7 static const u16 mgmt_commands[] = { MGMT_OP_READ_INDEX_LIST, -- cgit v1.2.3 From fca20018e7b86a8716511c7681115baa47aca8e4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 28 Jun 2014 17:54:05 +0300 Subject: Bluetooth: Use kzalloc instead of kmalloc for pending mgmt commands By using kzalloc we ensure that there are no struct members, such as the user_data pointer, left uninitialized. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d42c07d2a817..727ae15f9c36 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -984,7 +984,7 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, { struct pending_cmd *cmd; - cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) return NULL; -- cgit v1.2.3 From 33f35721030185a2c5a1bb8afd4c3744709745b5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 28 Jun 2014 17:54:06 +0300 Subject: Bluetooth: Add tracking of local and piconet clock values This patch adds support for storing the local and piconet clock values from the HCI_Read_Clock command response to the hci_dev and hci_conn structs. This will be later used in another patch to implement support for the Get Clock Info mgmt command. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 12 ++++++++++++ include/net/bluetooth/hci_core.h | 4 ++++ net/bluetooth/hci_event.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6933766e7215..58c5930dea60 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1087,6 +1087,18 @@ struct hci_rp_read_rssi { __s8 rssi; } __packed; +#define HCI_OP_READ_CLOCK 0x1407 +struct hci_cp_read_clock { + __le16 handle; + __u8 which; +} __packed; +struct hci_rp_read_clock { + __u8 status; + __le16 handle; + __le32 clock; + __le16 accuracy; +} __packed; + #define HCI_OP_READ_LOCAL_AMP_INFO 0x1409 struct hci_rp_read_local_amp_info { __u8 status; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ca2a99807615..0906990dedd8 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -207,6 +207,7 @@ struct hci_dev { __u16 conn_info_min_age; __u16 conn_info_max_age; __u8 ssp_debug_mode; + __u32 clock; __u16 devid_source; __u16 devid_vendor; @@ -388,6 +389,9 @@ struct hci_conn { __s8 max_tx_power; unsigned long flags; + __u32 clock; + __u16 clock_accuracy; + unsigned long conn_info_timestamp; __u8 remote_cap; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7a23324eac39..315d615ca3f9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -721,6 +721,41 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev, hdev->block_cnt, hdev->block_len); } +static void hci_cc_read_clock(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_rp_read_clock *rp = (void *) skb->data; + struct hci_cp_read_clock *cp; + struct hci_conn *conn; + + BT_DBG("%s", hdev->name); + + if (skb->len < sizeof(*rp)) + return; + + if (rp->status) + return; + + hci_dev_lock(hdev); + + cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK); + if (!cp) + goto unlock; + + if (cp->which == 0x00) { + hdev->clock = le32_to_cpu(rp->clock); + goto unlock; + } + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle)); + if (conn) { + conn->clock = le32_to_cpu(rp->clock); + conn->clock_accuracy = le16_to_cpu(rp->accuracy); + } + +unlock: + hci_dev_unlock(hdev); +} + static void hci_cc_read_local_amp_info(struct hci_dev *hdev, struct sk_buff *skb) { @@ -2597,6 +2632,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_read_local_amp_info(hdev, skb); break; + case HCI_OP_READ_CLOCK: + hci_cc_read_clock(hdev, skb); + break; + case HCI_OP_READ_LOCAL_AMP_ASSOC: hci_cc_read_local_amp_assoc(hdev, skb); break; -- cgit v1.2.3 From 958684263d3efbc721fb2b86f94876893eb638d2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 28 Jun 2014 17:54:07 +0300 Subject: Bluetooth: Add support for Get Clock Info mgmt command This patch implements support for the Get Clock Information mgmt command. This is done by performing one or two HCI_Read_Clock commands and creating the response from the stored values in the hci_dev and hci_conn structs. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 12 ++++ net/bluetooth/mgmt.c | 144 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index bcffc9ae0c89..3109dec13409 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -424,6 +424,18 @@ struct mgmt_rp_get_conn_info { __s8 max_tx_power; } __packed; +#define MGMT_OP_GET_CLOCK_INFO 0x0032 +struct mgmt_cp_get_clock_info { + struct mgmt_addr_info addr; +} __packed; +#define MGMT_GET_CLOCK_INFO_SIZE MGMT_ADDR_INFO_SIZE +struct mgmt_rp_get_clock_info { + struct mgmt_addr_info addr; + __le32 local_clock; + __le32 piconet_clock; + __le16 accuracy; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 727ae15f9c36..6faa4616cbfe 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -85,6 +85,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_SET_PRIVACY, MGMT_OP_LOAD_IRKS, MGMT_OP_GET_CONN_INFO, + MGMT_OP_GET_CLOCK_INFO, }; static const u16 mgmt_events[] = { @@ -571,6 +572,22 @@ static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev) return NULL; } +static struct pending_cmd *mgmt_pending_find_data(u16 opcode, + struct hci_dev *hdev, + const void *data) +{ + struct pending_cmd *cmd; + + list_for_each_entry(cmd, &hdev->mgmt_pending, list) { + if (cmd->user_data != data) + continue; + if (cmd->opcode == opcode) + return cmd; + } + + return NULL; +} + static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr) { u8 ad_len = 0; @@ -4820,6 +4837,132 @@ unlock: return err; } +static void get_clock_info_complete(struct hci_dev *hdev, u8 status) +{ + struct mgmt_cp_get_clock_info *cp; + struct mgmt_rp_get_clock_info rp; + struct hci_cp_read_clock *hci_cp; + struct pending_cmd *cmd; + struct hci_conn *conn; + + BT_DBG("%s status %u", hdev->name, status); + + hci_dev_lock(hdev); + + hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK); + if (!hci_cp) + goto unlock; + + if (hci_cp->which) { + u16 handle = __le16_to_cpu(hci_cp->handle); + conn = hci_conn_hash_lookup_handle(hdev, handle); + } else { + conn = NULL; + } + + cmd = mgmt_pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn); + if (!cmd) + goto unlock; + + cp = cmd->param; + + memset(&rp, 0, sizeof(rp)); + memcpy(&rp.addr, &cp->addr, sizeof(rp.addr)); + + if (status) + goto send_rsp; + + rp.local_clock = cpu_to_le32(hdev->clock); + + if (conn) { + rp.piconet_clock = cpu_to_le32(conn->clock); + rp.accuracy = cpu_to_le16(conn->clock_accuracy); + } + +send_rsp: + cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status), + &rp, sizeof(rp)); + mgmt_pending_remove(cmd); + if (conn) + hci_conn_drop(conn); + +unlock: + hci_dev_unlock(hdev); +} + +static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) +{ + struct mgmt_cp_get_clock_info *cp = data; + struct mgmt_rp_get_clock_info rp; + struct hci_cp_read_clock hci_cp; + struct pending_cmd *cmd; + struct hci_request req; + struct hci_conn *conn; + int err; + + BT_DBG("%s", hdev->name); + + memset(&rp, 0, sizeof(rp)); + bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); + rp.addr.type = cp->addr.type; + + if (cp->addr.type != BDADDR_BREDR) + return cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO, + MGMT_STATUS_INVALID_PARAMS, + &rp, sizeof(rp)); + + hci_dev_lock(hdev); + + if (!hdev_is_powered(hdev)) { + err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO, + MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp)); + goto unlock; + } + + if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) { + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, + &cp->addr.bdaddr); + if (!conn || conn->state != BT_CONNECTED) { + err = cmd_complete(sk, hdev->id, + MGMT_OP_GET_CLOCK_INFO, + MGMT_STATUS_NOT_CONNECTED, + &rp, sizeof(rp)); + goto unlock; + } + } else { + conn = NULL; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } + + hci_req_init(&req, hdev); + + memset(&hci_cp, 0, sizeof(hci_cp)); + hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp); + + if (conn) { + hci_conn_hold(conn); + cmd->user_data = conn; + + hci_cp.handle = cpu_to_le16(conn->handle); + hci_cp.which = 0x01; /* Piconet clock */ + hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp); + } + + err = hci_req_run(&req, get_clock_info_complete); + if (err < 0) + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock(hdev); + return err; +} + static const struct mgmt_handler { int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len); @@ -4876,6 +5019,7 @@ static const struct mgmt_handler { { set_privacy, false, MGMT_SET_PRIVACY_SIZE }, { load_irks, true, MGMT_LOAD_IRKS_SIZE }, { get_conn_info, false, MGMT_GET_CONN_INFO_SIZE }, + { get_clock_info, false, MGMT_GET_CLOCK_INFO_SIZE }, }; -- cgit v1.2.3 From fee746b0babf128a50ece050ee6e63003ebb5ae1 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 29 Jun 2014 12:13:05 +0200 Subject: Bluetooth: Restrict access for raw-only controllers Bluetooth controllers that are marked for raw-only usage can only be used with user channel access. Any other operation should be rejected. This simplifies the whole raw-only support since it now depends on the fact that the controller is marked with HCI_QUIRK_RAW_DEVICE and runtime raw access is restricted to user channel operation. The kernel internal processing of HCI commands and events is designed around the case that either the kernel has full control over the device or that the device is driven from userspace. This now makes a clear distinction between these two possible operation modes. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 7 ----- net/bluetooth/hci_core.c | 74 +++++++++++++++++++++++++++++++++++++----------- net/bluetooth/hci_sock.c | 14 ++++++--- net/bluetooth/mgmt.c | 6 +++- 4 files changed, 72 insertions(+), 29 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 8a0c7a0ac1b6..25ee27ddc882 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -346,9 +346,6 @@ static void hci_conn_idle(struct work_struct *work) BT_DBG("hcon %p mode %d", conn, conn->mode); - if (test_bit(HCI_RAW, &hdev->flags)) - return; - if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn)) return; @@ -539,7 +536,6 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) list_for_each_entry(d, &hci_dev_list, list) { if (!test_bit(HCI_UP, &d->flags) || - test_bit(HCI_RAW, &d->flags) || test_bit(HCI_USER_CHANNEL, &d->dev_flags) || d->dev_type != HCI_BREDR) continue; @@ -1059,9 +1055,6 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) BT_DBG("hcon %p mode %d", conn, conn->mode); - if (test_bit(HCI_RAW, &hdev->flags)) - return; - if (conn->mode != HCI_CM_SNIFF) goto timer; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9852449ac104..50db0201213c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2117,6 +2117,11 @@ int hci_inquiry(void __user *arg) goto done; } + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { + err = -EOPNOTSUPP; + goto done; + } + if (hdev->dev_type != HCI_BREDR) { err = -EOPNOTSUPP; goto done; @@ -2246,10 +2251,7 @@ static int hci_dev_do_open(struct hci_dev *hdev) ret = hdev->setup(hdev); if (!ret) { - if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) - set_bit(HCI_RAW, &hdev->flags); - - if (!test_bit(HCI_RAW, &hdev->flags) && + if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks) && !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) ret = __hci_init(hdev); } @@ -2286,7 +2288,7 @@ static int hci_dev_do_open(struct hci_dev *hdev) } hdev->close(hdev); - hdev->flags = 0; + hdev->flags &= BIT(HCI_RAW); } done: @@ -2305,6 +2307,21 @@ int hci_dev_open(__u16 dev) if (!hdev) return -ENODEV; + /* Devices that are marked for raw-only usage can only be powered + * up as user channel. Trying to bring them up as normal devices + * will result into a failure. Only user channel operation is + * possible. + * + * When this function is called for a user channel, the flag + * HCI_USER_CHANNEL will be set first before attempting to + * open the device. + */ + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks) && + !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { + err = -EOPNOTSUPP; + goto done; + } + /* We need to ensure that no other power on/off work is pending * before proceeding to call hci_dev_do_open. This is * particularly important if the setup procedure has not yet @@ -2321,8 +2338,8 @@ int hci_dev_open(__u16 dev) err = hci_dev_do_open(hdev); +done: hci_dev_put(hdev); - return err; } @@ -2374,7 +2391,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Reset device */ skb_queue_purge(&hdev->cmd_q); atomic_set(&hdev->cmd_cnt, 1); - if (!test_bit(HCI_RAW, &hdev->flags) && + if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks) && !test_bit(HCI_AUTO_OFF, &hdev->dev_flags) && test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) { set_bit(HCI_INIT, &hdev->flags); @@ -2405,7 +2422,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) hdev->close(hdev); /* Clear flags */ - hdev->flags = 0; + hdev->flags &= BIT(HCI_RAW); hdev->dev_flags &= ~HCI_PERSISTENT_MASK; if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { @@ -2474,6 +2491,11 @@ int hci_dev_reset(__u16 dev) goto done; } + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { + ret = -EOPNOTSUPP; + goto done; + } + /* Drop queues */ skb_queue_purge(&hdev->rx_q); skb_queue_purge(&hdev->cmd_q); @@ -2489,8 +2511,7 @@ int hci_dev_reset(__u16 dev) atomic_set(&hdev->cmd_cnt, 1); hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0; - if (!test_bit(HCI_RAW, &hdev->flags)) - ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT); + ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT); done: hci_req_unlock(hdev); @@ -2512,6 +2533,11 @@ int hci_dev_reset_stat(__u16 dev) goto done; } + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { + ret = -EOPNOTSUPP; + goto done; + } + memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); done: @@ -2537,6 +2563,11 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) goto done; } + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { + err = -EOPNOTSUPP; + goto done; + } + if (hdev->dev_type != HCI_BREDR) { err = -EOPNOTSUPP; goto done; @@ -2760,8 +2791,10 @@ static void hci_power_on(struct work_struct *work) HCI_AUTO_OFF_TIMEOUT); } - if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) - mgmt_index_added(hdev); + if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) { + if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + mgmt_index_added(hdev); + } } static void hci_power_off(struct work_struct *work) @@ -3887,6 +3920,13 @@ int hci_register_dev(struct hci_dev *hdev) list_add(&hdev->list, &hci_dev_list); write_unlock(&hci_dev_list_lock); + /* Devices that are marked for raw-only usage need to set + * the HCI_RAW flag to indicate that only user channel is + * supported. + */ + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + set_bit(HCI_RAW, &hdev->flags); + hci_notify(hdev, HCI_DEV_REG); hci_dev_hold(hdev); @@ -3929,7 +3969,8 @@ void hci_unregister_dev(struct hci_dev *hdev) cancel_work_sync(&hdev->power_on); if (!test_bit(HCI_INIT, &hdev->flags) && - !test_bit(HCI_SETUP, &hdev->dev_flags)) { + !test_bit(HCI_SETUP, &hdev->dev_flags) && + !test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { hci_dev_lock(hdev); mgmt_index_removed(hdev); hci_dev_unlock(hdev); @@ -4694,7 +4735,7 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) static void __check_timeout(struct hci_dev *hdev, unsigned int cnt) { - if (!test_bit(HCI_RAW, &hdev->flags)) { + if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ if (!cnt && time_after(jiffies, hdev->acl_last_tx + @@ -4877,7 +4918,7 @@ static void hci_sched_le(struct hci_dev *hdev) if (!hci_conn_num(hdev, LE_LINK)) return; - if (!test_bit(HCI_RAW, &hdev->flags)) { + if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { /* LE tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ if (!hdev->le_cnt && hdev->le_pkts && @@ -5122,8 +5163,7 @@ static void hci_rx_work(struct work_struct *work) hci_send_to_sock(hdev, skb); } - if (test_bit(HCI_RAW, &hdev->flags) || - test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { + if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { kfree_skb(skb); continue; } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 80d25c150a65..54e4e8fd5d97 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -453,7 +453,8 @@ static int hci_sock_release(struct socket *sock) if (hdev) { if (hci_pi(sk)->channel == HCI_CHANNEL_USER) { - mgmt_index_added(hdev); + if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + mgmt_index_added(hdev); clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags); hci_dev_close(hdev->id); } @@ -517,6 +518,9 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) return -EBUSY; + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + return -EOPNOTSUPP; + if (hdev->dev_type != HCI_BREDR) return -EOPNOTSUPP; @@ -702,12 +706,14 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, goto done; } - mgmt_index_removed(hdev); + if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + mgmt_index_removed(hdev); err = hci_dev_open(hdev->id); if (err) { clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags); - mgmt_index_added(hdev); + if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + mgmt_index_added(hdev); hci_dev_put(hdev); goto done; } @@ -960,7 +966,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, goto drop; } - if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) { + if (ogf == 0x3f) { skb_queue_tail(&hdev->raw_q, skb); queue_work(hdev->workqueue, &hdev->tx_work); } else { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6faa4616cbfe..41b1aec0c5dc 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -347,6 +347,9 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, if (test_bit(HCI_USER_CHANNEL, &d->dev_flags)) continue; + if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) + continue; + if (d->dev_type == HCI_BREDR) { rp->index[count++] = cpu_to_le16(d->id); BT_DBG("Added hci%u", d->id); @@ -5066,7 +5069,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) } if (test_bit(HCI_SETUP, &hdev->dev_flags) || - test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { + test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) || + test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { err = cmd_status(sk, index, opcode, MGMT_STATUS_INVALID_INDEX); goto done; -- cgit v1.2.3 From 6ab535a777d76a2b1e5ad03119cd0c1e5a366b06 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 29 Jun 2014 12:20:15 +0200 Subject: Bluetooth: Don't use non-resolvable private address for passive scanning The usage of non-resovlable private addresses for passive scanning is a bad idea. Passive scanning will not send any SCAN_REQ and thus using your identity address for passive scanning is not a privacy issue. It is important to use the identity address during passive scanning since that is the only way devices using direct advertising will be reported correctly by the controller. This is overlooked detail in the Bluetooth specification that current controllers are not able to report direct advertising events for other than their current address. When remote peers are using direct advertising and scanning is done with non-resolvable private address these devices will not be found. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 50db0201213c..3ee2885dd9bc 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5250,12 +5250,13 @@ void hci_req_add_le_passive_scan(struct hci_request *req) struct hci_dev *hdev = req->hdev; u8 own_addr_type; - /* Set require_privacy to true to avoid identification from - * unknown peer devices. Since this is passive scanning, no - * SCAN_REQ using the local identity should be sent. Mandating - * privacy is just an extra precaution. + /* Set require_privacy to false since no SCAN_REQ are send + * during passive scanning. Not using an unresolvable address + * here is important so that peer devices using direct + * advertising with our address will be correctly reported + * by the controller. */ - if (hci_update_random_address(req, true, &own_addr_type)) + if (hci_update_random_address(req, false, &own_addr_type)) return; memset(¶m_cp, 0, sizeof(param_cp)); -- cgit v1.2.3 From 4b10966f0f204d80f087f955344cbf6074a5cf86 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 29 Jun 2014 13:41:49 +0200 Subject: Bluetooth: Move hci_pend_le_conn_* functions to different location The hci_pend_le_conn_* function should be placed before their actual users. So move them before hci_conn_params_* functions. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 144 +++++++++++++++++++++++------------------------ 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3ee2885dd9bc..ffee5f547506 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3414,6 +3414,78 @@ static bool is_identity_address(bdaddr_t *addr, u8 addr_type) return false; } +/* This function requires the caller holds hdev->lock */ +struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev, + bdaddr_t *addr, u8 addr_type) +{ + struct bdaddr_list *entry; + + list_for_each_entry(entry, &hdev->pend_le_conns, list) { + if (bacmp(&entry->bdaddr, addr) == 0 && + entry->bdaddr_type == addr_type) + return entry; + } + + return NULL; +} + +/* This function requires the caller holds hdev->lock */ +void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) +{ + struct bdaddr_list *entry; + + entry = hci_pend_le_conn_lookup(hdev, addr, addr_type); + if (entry) + goto done; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { + BT_ERR("Out of memory"); + return; + } + + bacpy(&entry->bdaddr, addr); + entry->bdaddr_type = addr_type; + + list_add(&entry->list, &hdev->pend_le_conns); + + BT_DBG("addr %pMR (type %u)", addr, addr_type); + +done: + hci_update_background_scan(hdev); +} + +/* This function requires the caller holds hdev->lock */ +void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) +{ + struct bdaddr_list *entry; + + entry = hci_pend_le_conn_lookup(hdev, addr, addr_type); + if (!entry) + goto done; + + list_del(&entry->list); + kfree(entry); + + BT_DBG("addr %pMR (type %u)", addr, addr_type); + +done: + hci_update_background_scan(hdev); +} + +/* This function requires the caller holds hdev->lock */ +void hci_pend_le_conns_clear(struct hci_dev *hdev) +{ + struct bdaddr_list *entry, *tmp; + + list_for_each_entry_safe(entry, tmp, &hdev->pend_le_conns, list) { + list_del(&entry->list); + kfree(entry); + } + + BT_DBG("All LE pending connections cleared"); +} + /* This function requires the caller holds hdev->lock */ int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, u8 auto_connect, u16 conn_min_interval, @@ -3492,78 +3564,6 @@ void hci_conn_params_clear(struct hci_dev *hdev) BT_DBG("All LE connection parameters were removed"); } -/* This function requires the caller holds hdev->lock */ -struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev, - bdaddr_t *addr, u8 addr_type) -{ - struct bdaddr_list *entry; - - list_for_each_entry(entry, &hdev->pend_le_conns, list) { - if (bacmp(&entry->bdaddr, addr) == 0 && - entry->bdaddr_type == addr_type) - return entry; - } - - return NULL; -} - -/* This function requires the caller holds hdev->lock */ -void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) -{ - struct bdaddr_list *entry; - - entry = hci_pend_le_conn_lookup(hdev, addr, addr_type); - if (entry) - goto done; - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) { - BT_ERR("Out of memory"); - return; - } - - bacpy(&entry->bdaddr, addr); - entry->bdaddr_type = addr_type; - - list_add(&entry->list, &hdev->pend_le_conns); - - BT_DBG("addr %pMR (type %u)", addr, addr_type); - -done: - hci_update_background_scan(hdev); -} - -/* This function requires the caller holds hdev->lock */ -void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) -{ - struct bdaddr_list *entry; - - entry = hci_pend_le_conn_lookup(hdev, addr, addr_type); - if (!entry) - goto done; - - list_del(&entry->list); - kfree(entry); - - BT_DBG("addr %pMR (type %u)", addr, addr_type); - -done: - hci_update_background_scan(hdev); -} - -/* This function requires the caller holds hdev->lock */ -void hci_pend_le_conns_clear(struct hci_dev *hdev) -{ - struct bdaddr_list *entry, *tmp; - - list_for_each_entry_safe(entry, tmp, &hdev->pend_le_conns, list) { - list_del(&entry->list); - kfree(entry); - } - - BT_DBG("All LE pending connections cleared"); -} - static void inquiry_complete(struct hci_dev *hdev, u8 status) { if (status) { -- cgit v1.2.3 From 1089b67d8eb7fcdfae837a91aae9af94e329361c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 29 Jun 2014 13:41:50 +0200 Subject: Bluetooth: Clear pending connections from hci_conn_params_clear When hci_conn_params_clear is called, it is always followed by a call to hci_pend_le_conns_clear. So instead of making this explicit just make sure it is always called. This makes this function similar on how hci_conn_params_add and hci_conn_params_del work. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ffee5f547506..8b206d0942aa 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -959,7 +959,6 @@ static ssize_t le_auto_conn_write(struct file *file, const char __user *data, } else if (memcmp(buf, "clr", 3) == 0) { hci_dev_lock(hdev); hci_conn_params_clear(hdev); - hci_pend_le_conns_clear(hdev); hci_update_background_scan(hdev); hci_dev_unlock(hdev); } else { @@ -3561,6 +3560,8 @@ void hci_conn_params_clear(struct hci_dev *hdev) kfree(params); } + hci_pend_le_conns_clear(hdev); + BT_DBG("All LE connection parameters were removed"); } @@ -4006,7 +4007,6 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_remote_oob_data_clear(hdev); hci_white_list_clear(hdev); hci_conn_params_clear(hdev); - hci_pend_le_conns_clear(hdev); hci_dev_unlock(hdev); hci_dev_put(hdev); -- cgit v1.2.3 From 1c1697c0cad41fa468e3cb6061ce74debb4f3733 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 29 Jun 2014 13:41:51 +0200 Subject: Bluetooth: Update background scanning from hci_conn_params_clear When calling hci_conn_params_clear function, it should update the background scanning properly and not require a separate call to update it. For the case when the function is used during unregister of a controller, an extra safe guard is but in place. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8b206d0942aa..c566b57610c9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -959,7 +959,6 @@ static ssize_t le_auto_conn_write(struct file *file, const char __user *data, } else if (memcmp(buf, "clr", 3) == 0) { hci_dev_lock(hdev); hci_conn_params_clear(hdev); - hci_update_background_scan(hdev); hci_dev_unlock(hdev); } else { err = -EINVAL; @@ -3483,6 +3482,8 @@ void hci_pend_le_conns_clear(struct hci_dev *hdev) } BT_DBG("All LE pending connections cleared"); + + hci_update_background_scan(hdev); } /* This function requires the caller holds hdev->lock */ @@ -5293,6 +5294,9 @@ void hci_update_background_scan(struct hci_dev *hdev) struct hci_conn *conn; int err; + if (test_bit(HCI_UNREGISTER, &hdev->dev_flags)) + return; + hci_req_init(&req, hdev); if (list_empty(&hdev->pend_le_conns)) { -- cgit v1.2.3 From f044eb0524a02ea7f921c9234fbdba43290da1e2 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 29 Jun 2014 16:43:26 +0200 Subject: Bluetooth: Store latency and supervision timeout in connection params When the slave updates the connection parameters, store also the connection latency and supervision timeout information in the internal list of connection parameters for known devices. Having these values available allowes the auto-connection procedure to use the correct values from the beginning without having to request an update on every connection establishment. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_conn.c | 16 ++++++++++++++-- net/bluetooth/hci_core.c | 2 ++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0906990dedd8..182044824495 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -439,6 +439,8 @@ struct hci_conn_params { u16 conn_min_interval; u16 conn_max_interval; + u16 conn_latency; + u16 supervision_timeout; enum { HCI_AUTO_CONN_DISABLED, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 25ee27ddc882..adb413d77637 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -216,11 +216,23 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle) void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier) { - struct hci_cp_le_conn_update cp; struct hci_dev *hdev = conn->hdev; + struct hci_conn_params *params; + struct hci_cp_le_conn_update cp; - memset(&cp, 0, sizeof(cp)); + hci_dev_lock(hdev); + + params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); + if (params) { + params->conn_min_interval = min; + params->conn_max_interval = max; + params->conn_latency = latency; + params->supervision_timeout = to_multiplier; + } + hci_dev_unlock(hdev); + + memset(&cp, 0, sizeof(cp)); cp.handle = cpu_to_le16(conn->handle); cp.conn_interval_min = cpu_to_le16(min); cp.conn_interval_max = cpu_to_le16(max); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c566b57610c9..97a6453bee30 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3514,6 +3514,8 @@ int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, update: params->conn_min_interval = conn_min_interval; params->conn_max_interval = conn_max_interval; + params->conn_latency = 0x0000; + params->supervision_timeout = 0x002a; params->auto_connect = auto_connect; switch (auto_connect) { -- cgit v1.2.3 From 037fc415bce5ac7604ac52216ec03d011f81e5b0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 29 Jun 2014 16:43:27 +0200 Subject: Bluetooth: Use LE connection parameters if known When the LE connection parameters for connection latency and supervision timeout are known, then use then. If they are not know fallback to defaults. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index adb413d77637..e7ee7267f846 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -645,7 +645,8 @@ static void hci_req_add_le_create_conn(struct hci_request *req, cp.own_address_type = own_addr_type; cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval); cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval); - cp.supervision_timeout = cpu_to_le16(0x002a); + cp.conn_latency = cpu_to_le16(conn->le_conn_latency); + cp.supervision_timeout = cpu_to_le16(conn->le_supv_timeout); cp.min_ce_len = cpu_to_le16(0x0000); cp.max_ce_len = cpu_to_le16(0x0000); @@ -767,9 +768,13 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, if (params) { conn->le_conn_min_interval = params->conn_min_interval; conn->le_conn_max_interval = params->conn_max_interval; + conn->le_conn_latency = params->conn_latency; + conn->le_supv_timeout = params->supervision_timeout; } else { conn->le_conn_min_interval = hdev->le_conn_min_interval; conn->le_conn_max_interval = hdev->le_conn_max_interval; + conn->le_conn_latency = 0x0000; + conn->le_supv_timeout = 0x002a; } /* If controller is scanning, we stop it since some controllers are -- cgit v1.2.3 From 2faade53e65f276cf1c30a885fb64808a083714e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 29 Jun 2014 19:44:03 +0200 Subject: Bluetooth: Add support for Add/Remove Device management commands This allows adding or removing devices from the background scanning list the kernel maintains. Device flagged for auto-connection will be automatically connected if they are found. The passive scanning required for auto-connection will be started and stopped on demand. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 13 ++++++ net/bluetooth/mgmt.c | 99 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 3109dec13409..bc9b105f2b50 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -436,6 +436,19 @@ struct mgmt_rp_get_clock_info { __le16 accuracy; } __packed; +#define MGMT_OP_ADD_DEVICE 0x0033 +struct mgmt_cp_add_device { + struct mgmt_addr_info addr; + __u8 action; +} __packed; +#define MGMT_ADD_DEVICE_SIZE (MGMT_ADDR_INFO_SIZE + 1) + +#define MGMT_OP_REMOVE_DEVICE 0x0034 +struct mgmt_cp_remove_device { + struct mgmt_addr_info addr; +} __packed; +#define MGMT_REMOVE_DEVICE_SIZE MGMT_ADDR_INFO_SIZE + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 41b1aec0c5dc..64b55c7881ee 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -86,6 +86,8 @@ static const u16 mgmt_commands[] = { MGMT_OP_LOAD_IRKS, MGMT_OP_GET_CONN_INFO, MGMT_OP_GET_CLOCK_INFO, + MGMT_OP_ADD_DEVICE, + MGMT_OP_REMOVE_DEVICE, }; static const u16 mgmt_events[] = { @@ -4966,6 +4968,100 @@ unlock: return err; } +static int add_device(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_add_device *cp = data; + u8 auto_conn, addr_type; + int err; + + BT_DBG("%s", hdev->name); + + if (!bdaddr_type_is_le(cp->addr.type) || + !bacmp(&cp->addr.bdaddr, BDADDR_ANY)) + return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); + + if (cp->action != 0x00 && cp->action != 0x01) + return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); + + hci_dev_lock(hdev); + + if (cp->addr.type == BDADDR_LE_PUBLIC) + addr_type = ADDR_LE_DEV_PUBLIC; + else + addr_type = ADDR_LE_DEV_RANDOM; + + if (cp->action) + auto_conn = HCI_AUTO_CONN_ALWAYS; + else + auto_conn = HCI_AUTO_CONN_DISABLED; + + if (hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type, auto_conn, + hdev->le_conn_min_interval, + hdev->le_conn_max_interval) < 0) { + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, + MGMT_STATUS_FAILED, + &cp->addr, sizeof(cp->addr)); + goto unlock; + } + + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, + MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr)); + +unlock: + hci_dev_unlock(hdev); + return err; +} + +static int remove_device(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_remove_device *cp = data; + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) { + u8 addr_type; + + if (!bdaddr_type_is_le(cp->addr.type)) { + err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); + goto unlock; + } + + if (cp->addr.type == BDADDR_LE_PUBLIC) + addr_type = ADDR_LE_DEV_PUBLIC; + else + addr_type = ADDR_LE_DEV_RANDOM; + + hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type); + } else { + if (cp->addr.type) { + err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); + goto unlock; + } + + hci_conn_params_clear(hdev); + } + + err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, + MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr)); + +unlock: + hci_dev_unlock(hdev); + return err; +} + static const struct mgmt_handler { int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len); @@ -5023,9 +5119,10 @@ static const struct mgmt_handler { { load_irks, true, MGMT_LOAD_IRKS_SIZE }, { get_conn_info, false, MGMT_GET_CONN_INFO_SIZE }, { get_clock_info, false, MGMT_GET_CLOCK_INFO_SIZE }, + { add_device, false, MGMT_ADD_DEVICE_SIZE }, + { remove_device, false, MGMT_REMOVE_DEVICE_SIZE }, }; - int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { void *buf; -- cgit v1.2.3 From 0b3c7d372b6a74531f1927a3962e41029e26d2d8 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 29 Jun 2014 16:15:49 +0200 Subject: Bluetooth: Replace le_auto_conn debugfs with device_list entry Since the auto-connection handling has gained offical management command support, remove the le_auto_conn debugfs entry. For debugging purposes replace it a simple device_list debugfs entry that allows listing of the current internal auto-connection list used for passive scanning. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 93 +++++------------------------------------------- 1 file changed, 9 insertions(+), 84 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 97a6453bee30..8d972023196b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -879,104 +879,29 @@ static int adv_channel_map_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get, adv_channel_map_set, "%llu\n"); -static int le_auto_conn_show(struct seq_file *sf, void *ptr) +static int device_list_show(struct seq_file *f, void *ptr) { - struct hci_dev *hdev = sf->private; + struct hci_dev *hdev = f->private; struct hci_conn_params *p; hci_dev_lock(hdev); - list_for_each_entry(p, &hdev->le_conn_params, list) { - seq_printf(sf, "%pMR %u %u\n", &p->addr, p->addr_type, + seq_printf(f, "%pMR %u %u\n", &p->addr, p->addr_type, p->auto_connect); } - hci_dev_unlock(hdev); return 0; } -static int le_auto_conn_open(struct inode *inode, struct file *file) -{ - return single_open(file, le_auto_conn_show, inode->i_private); -} - -static ssize_t le_auto_conn_write(struct file *file, const char __user *data, - size_t count, loff_t *offset) +static int device_list_open(struct inode *inode, struct file *file) { - struct seq_file *sf = file->private_data; - struct hci_dev *hdev = sf->private; - u8 auto_connect = 0; - bdaddr_t addr; - u8 addr_type; - char *buf; - int err = 0; - int n; - - /* Don't allow partial write */ - if (*offset != 0) - return -EINVAL; - - if (count < 3) - return -EINVAL; - - buf = memdup_user(data, count); - if (IS_ERR(buf)) - return PTR_ERR(buf); - - if (memcmp(buf, "add", 3) == 0) { - n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu", - &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2], - &addr.b[1], &addr.b[0], &addr_type, - &auto_connect); - - if (n < 7) { - err = -EINVAL; - goto done; - } - - hci_dev_lock(hdev); - err = hci_conn_params_add(hdev, &addr, addr_type, auto_connect, - hdev->le_conn_min_interval, - hdev->le_conn_max_interval); - hci_dev_unlock(hdev); - - if (err) - goto done; - } else if (memcmp(buf, "del", 3) == 0) { - n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu", - &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2], - &addr.b[1], &addr.b[0], &addr_type); - - if (n < 7) { - err = -EINVAL; - goto done; - } - - hci_dev_lock(hdev); - hci_conn_params_del(hdev, &addr, addr_type); - hci_dev_unlock(hdev); - } else if (memcmp(buf, "clr", 3) == 0) { - hci_dev_lock(hdev); - hci_conn_params_clear(hdev); - hci_dev_unlock(hdev); - } else { - err = -EINVAL; - } - -done: - kfree(buf); - - if (err) - return err; - else - return count; + return single_open(file, device_list_show, inode->i_private); } -static const struct file_operations le_auto_conn_fops = { - .open = le_auto_conn_open, +static const struct file_operations device_list_fops = { + .open = device_list_open, .read = seq_read, - .write = le_auto_conn_write, .llseek = seq_lseek, .release = single_release, }; @@ -1785,8 +1710,8 @@ static int __hci_init(struct hci_dev *hdev) hdev, &conn_max_interval_fops); debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, hdev, &adv_channel_map_fops); - debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev, - &le_auto_conn_fops); + debugfs_create_file("device_list", 0444, hdev->debugfs, hdev, + &device_list_fops); debugfs_create_u16("discov_interleaved_timeout", 0644, hdev->debugfs, &hdev->discov_interleaved_timeout); -- cgit v1.2.3 From 8afef092a192cb946393bb11cc95b59739c1e57b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 29 Jun 2014 22:28:34 +0200 Subject: Bluetooth: Add Device Added and Device Removed management events When devices are added or removed, then make sure that events are send out to all other clients so that the list of devices can be easily tracked. This is especially important when external clients are adding or removing devices within the auto-connection list. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 11 +++++++++++ net/bluetooth/mgmt.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index bc9b105f2b50..1f95ad4fce02 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -603,3 +603,14 @@ struct mgmt_ev_new_csrk { __u8 store_hint; struct mgmt_csrk_info key; } __packed; + +#define MGMT_EV_DEVICE_ADDED 0x001a +struct mgmt_ev_device_added { + struct mgmt_addr_info addr; + __u8 action; +} __packed; + +#define MGMT_EV_DEVICE_REMOVED 0x001b +struct mgmt_ev_device_removed { + struct mgmt_addr_info addr; +} __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 64b55c7881ee..d83197f9e727 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -114,6 +114,8 @@ static const u16 mgmt_events[] = { MGMT_EV_PASSKEY_NOTIFY, MGMT_EV_NEW_IRK, MGMT_EV_NEW_CSRK, + MGMT_EV_DEVICE_ADDED, + MGMT_EV_DEVICE_REMOVED, }; #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) @@ -4968,6 +4970,18 @@ unlock: return err; } +static void device_added(struct sock *sk, struct hci_dev *hdev, + bdaddr_t *bdaddr, u8 type, u8 action) +{ + struct mgmt_ev_device_added ev; + + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = type; + ev.action = action; + + mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk); +} + static int add_device(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { @@ -5009,6 +5023,8 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } + device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action); + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr)); @@ -5017,6 +5033,17 @@ unlock: return err; } +static void device_removed(struct sock *sk, struct hci_dev *hdev, + bdaddr_t *bdaddr, u8 type) +{ + struct mgmt_ev_device_removed ev; + + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = type; + + mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk); +} + static int remove_device(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { @@ -5043,6 +5070,8 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, addr_type = ADDR_LE_DEV_RANDOM; hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type); + + device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); } else { if (cp->addr.type) { err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, -- cgit v1.2.3 From 04fb7d9066dd9173ef0d4ccea8fe3bb59bd94605 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 30 Jun 2014 12:34:36 +0200 Subject: Bluetooth: Provide defaults for LE connection latency and timeout Store the connection latency and supervision timeout default values with all the other controller defaults. And when needed use them for new connections. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_conn.c | 4 ++-- net/bluetooth/hci_core.c | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 182044824495..ed842c7e5cf1 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -203,6 +203,8 @@ struct hci_dev { __u16 le_scan_window; __u16 le_conn_min_interval; __u16 le_conn_max_interval; + __u16 le_conn_latency; + __u16 le_supv_timeout; __u16 discov_interleaved_timeout; __u16 conn_info_min_age; __u16 conn_info_max_age; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index e7ee7267f846..d00aaf976efc 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -773,8 +773,8 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, } else { conn->le_conn_min_interval = hdev->le_conn_min_interval; conn->le_conn_max_interval = hdev->le_conn_max_interval; - conn->le_conn_latency = 0x0000; - conn->le_supv_timeout = 0x002a; + conn->le_conn_latency = hdev->le_conn_latency; + conn->le_supv_timeout = hdev->le_supv_timeout; } /* If controller is scanning, we stop it since some controllers are diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8d972023196b..94551c33c4c6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3439,8 +3439,8 @@ int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, update: params->conn_min_interval = conn_min_interval; params->conn_max_interval = conn_max_interval; - params->conn_latency = 0x0000; - params->supervision_timeout = 0x002a; + params->conn_latency = hdev->le_conn_latency; + params->supervision_timeout = hdev->le_supv_timeout; params->auto_connect = auto_connect; switch (auto_connect) { @@ -3706,6 +3706,8 @@ struct hci_dev *hci_alloc_dev(void) hdev->le_scan_window = 0x0030; hdev->le_conn_min_interval = 0x0028; hdev->le_conn_max_interval = 0x0038; + hdev->le_conn_latency = 0x0000; + hdev->le_supv_timeout = 0x002a; hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT; hdev->discov_interleaved_timeout = DISCOV_INTERLEAVED_TIMEOUT; -- cgit v1.2.3 From 816a93d10a2809f09ce81e9fef638380d68d2c6d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 30 Jun 2014 12:34:37 +0200 Subject: Bluetooth: Expose default connection latency setting via debugfs The controller has a default value for the connection latency. Expose this via debugfs for testing purposes. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 94551c33c4c6..79d292cfb867 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -851,6 +851,34 @@ static int conn_max_interval_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get, conn_max_interval_set, "%llu\n"); +static int conn_latency_set(void *data, u64 val) +{ + struct hci_dev *hdev = data; + + if (val > 0x01f3) + return -EINVAL; + + hci_dev_lock(hdev); + hdev->le_conn_latency = val; + hci_dev_unlock(hdev); + + return 0; +} + +static int conn_latency_get(void *data, u64 *val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock(hdev); + *val = hdev->le_conn_latency; + hci_dev_unlock(hdev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(conn_latency_fops, conn_latency_get, + conn_latency_set, "%llu\n"); + static int adv_channel_map_set(void *data, u64 val) { struct hci_dev *hdev = data; @@ -1708,6 +1736,8 @@ static int __hci_init(struct hci_dev *hdev) hdev, &conn_min_interval_fops); debugfs_create_file("conn_max_interval", 0644, hdev->debugfs, hdev, &conn_max_interval_fops); + debugfs_create_file("conn_latency", 0644, hdev->debugfs, + hdev, &conn_latency_fops); debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, hdev, &adv_channel_map_fops); debugfs_create_file("device_list", 0444, hdev->debugfs, hdev, -- cgit v1.2.3 From f1649577a6c20410335dbb4765e74e51fd5df585 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 30 Jun 2014 12:34:38 +0200 Subject: Bluetooth: Expose default supervision timeout setting via debugfs The controller has a default value for the supervision timeout. Expose this via debugfs for testing purposes. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 79d292cfb867..6c28687c9286 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -879,6 +879,34 @@ static int conn_latency_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(conn_latency_fops, conn_latency_get, conn_latency_set, "%llu\n"); +static int supervision_timeout_set(void *data, u64 val) +{ + struct hci_dev *hdev = data; + + if (val < 0x000a || val > 0x0c80) + return -EINVAL; + + hci_dev_lock(hdev); + hdev->le_supv_timeout = val; + hci_dev_unlock(hdev); + + return 0; +} + +static int supervision_timeout_get(void *data, u64 *val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock(hdev); + *val = hdev->le_supv_timeout; + hci_dev_unlock(hdev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(supervision_timeout_fops, supervision_timeout_get, + supervision_timeout_set, "%llu\n"); + static int adv_channel_map_set(void *data, u64 val) { struct hci_dev *hdev = data; @@ -1738,6 +1766,8 @@ static int __hci_init(struct hci_dev *hdev) hdev, &conn_max_interval_fops); debugfs_create_file("conn_latency", 0644, hdev->debugfs, hdev, &conn_latency_fops); + debugfs_create_file("supervision_timeout", 0644, hdev->debugfs, + hdev, &supervision_timeout_fops); debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, hdev, &adv_channel_map_fops); debugfs_create_file("device_list", 0444, hdev->debugfs, hdev, -- cgit v1.2.3 From bf5b3c8be07905c242bb7f751dcb890b94c22d93 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 30 Jun 2014 12:34:39 +0200 Subject: Bluetooth: Provide function to create and set connection parameters In some cases it is useful to not overwrite connection parametes and instead just create default ones if they don't exist. This function does exactly that. hci_conn_params_add will allow to create new default connection parameters. hci_conn_params_set will set the values and also create new parameters if they don't exist. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 3 ++- net/bluetooth/hci_core.c | 36 +++++++++++++++++++++++++++++++++++- net/bluetooth/mgmt.c | 5 ++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ed842c7e5cf1..c0d2506e2019 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -852,7 +852,8 @@ int hci_white_list_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); -int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, +int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); +int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, u8 auto_connect, u16 conn_min_interval, u16 conn_max_interval); void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6c28687c9286..adea7de95633 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3472,7 +3472,41 @@ void hci_pend_le_conns_clear(struct hci_dev *hdev) } /* This function requires the caller holds hdev->lock */ -int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, +int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) +{ + struct hci_conn_params *params; + + if (!is_identity_address(addr, addr_type)) + return -EINVAL; + + params = hci_conn_params_lookup(hdev, addr, addr_type); + if (params) + return 0; + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + BT_ERR("Out of memory"); + return -ENOMEM; + } + + bacpy(¶ms->addr, addr); + params->addr_type = addr_type; + + list_add(¶ms->list, &hdev->le_conn_params); + + params->conn_min_interval = hdev->le_conn_min_interval; + params->conn_max_interval = hdev->le_conn_max_interval; + params->conn_latency = hdev->le_conn_latency; + params->supervision_timeout = hdev->le_supv_timeout; + params->auto_connect = HCI_AUTO_CONN_DISABLED; + + BT_DBG("addr %pMR (type %u)", addr, addr_type); + + return 0; +} + +/* This function requires the caller holds hdev->lock */ +int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, u8 auto_connect, u16 conn_min_interval, u16 conn_max_interval) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d83197f9e727..e30d0ebb5018 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5014,7 +5014,10 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, else auto_conn = HCI_AUTO_CONN_DISABLED; - if (hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type, auto_conn, + /* If the connection parameters don't exist for this device, + * they will be created and configured with defaults. + */ + if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type, auto_conn, hdev->le_conn_min_interval, hdev->le_conn_max_interval) < 0) { err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, -- cgit v1.2.3 From 7c264b10006f3c10f7a9ef314a213f9784d9ca1f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 30 Jun 2014 12:34:40 +0200 Subject: Bluetooth: Add default connection parameters before pairing When trying to pair a new Bluetooth Low Energy device, then make sure that the default connections parameters are in place before trying to establish the first connection to that device. With the connection parameters structure allocated, the slave preferred values can now easily be tracked and all future connections will use the correct values from that start decreasing connection establishment time. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e30d0ebb5018..6baba309f9e2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2947,6 +2947,17 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, else addr_type = ADDR_LE_DEV_RANDOM; + /* When pairing a new device, it is expected to remember + * this device for future connections. Adding the connection + * parameter information ahead of time allows tracking + * of the slave preferred values and will speed up any + * further connection establishment. + * + * If connection parameters already exist, then they + * will be kept and this function does nothing. + */ + hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type); + conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type, sec_level, auth_type); } -- cgit v1.2.3 From c20c02d5c8d76f39be461c25bf5de3a1dc96885e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 30 Jun 2014 16:04:12 +0200 Subject: Bluetooth: Start background scanning only when controller is ready When the controller is not active or in init/setup phase, do not try to start or stop background scanning. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index adea7de95633..2312e77582b0 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5317,7 +5317,10 @@ void hci_update_background_scan(struct hci_dev *hdev) struct hci_conn *conn; int err; - if (test_bit(HCI_UNREGISTER, &hdev->dev_flags)) + if (!test_bit(HCI_UP, &hdev->flags) || + test_bit(HCI_INIT, &hdev->flags) || + test_bit(HCI_SETUP, &hdev->dev_flags) || + test_bit(HCI_UNREGISTER, &hdev->dev_flags)) return; hci_req_init(&req, hdev); -- cgit v1.2.3 From d4905f2453bd228d8ffc57f4e25bba0a8f52c805 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 25 Jun 2014 21:52:52 -0300 Subject: Bluetooth: Connection parameters check helper This patch renames l2cap_check_conn_param() to hci_check_conn_params() and moves it to hci_core.h so it can reused in others files. This helper will be reused in the next patch. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 21 +++++++++++++++++++++ net/bluetooth/l2cap_core.c | 23 +---------------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c0d2506e2019..ec830871b9b8 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1181,6 +1181,27 @@ static inline struct smp_irk *hci_get_irk(struct hci_dev *hdev, return hci_find_irk_by_rpa(hdev, bdaddr); } +static inline int hci_check_conn_params(u16 min, u16 max, u16 latency, + u16 to_multiplier) +{ + u16 max_latency; + + if (min > max || min < 6 || max > 3200) + return -EINVAL; + + if (to_multiplier < 10 || to_multiplier > 3200) + return -EINVAL; + + if (max >= to_multiplier * 8) + return -EINVAL; + + max_latency = (to_multiplier * 8 / max) - 1; + if (latency > 499 || latency > max_latency) + return -EINVAL; + + return 0; +} + int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d015aa190fdc..e203a5fdf874 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5213,27 +5213,6 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, return 0; } -static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency, - u16 to_multiplier) -{ - u16 max_latency; - - if (min > max || min < 6 || max > 3200) - return -EINVAL; - - if (to_multiplier < 10 || to_multiplier > 3200) - return -EINVAL; - - if (max >= to_multiplier * 8) - return -EINVAL; - - max_latency = (to_multiplier * 8 / max) - 1; - if (latency > 499 || latency > max_latency) - return -EINVAL; - - return 0; -} - static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) @@ -5261,7 +5240,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, memset(&rsp, 0, sizeof(rsp)); - err = l2cap_check_conn_param(min, max, latency, to_multiplier); + err = hci_check_conn_params(min, max, latency, to_multiplier); if (err) rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED); else -- cgit v1.2.3 From 26b0f4e2f9d022193039a72db09c048b9ae93459 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 30 Jun 2014 19:26:23 +0200 Subject: Bluetooth: constify seq_operations bt_seq_ops is only used with __seq_open_private as const struct seq_operations * Signed-off-by: Fabian Frederick Signed-off-by: Marcel Holtmann --- net/bluetooth/af_bluetooth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 2021c481cdb6..4dca0299ed96 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -639,7 +639,7 @@ static int bt_seq_show(struct seq_file *seq, void *v) return 0; } -static struct seq_operations bt_seq_ops = { +static const struct seq_operations bt_seq_ops = { .start = bt_seq_start, .next = bt_seq_next, .stop = bt_seq_stop, -- cgit v1.2.3 From bf19d51b768ceeccab12f932cac73b60b1d20bab Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 1 Jul 2014 12:07:23 +0300 Subject: Bluetooth: Allow L2CAP getpeername() for BT_CONFIG state We have all the necessary remote information for getpeername() when we are in the BT_CONFIG state so this should be allowed. This is particularly important for LE sockets where changing the security level will temporarily move the socket into BT_CONFIG state. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_sock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index bf72886de6ef..9bb4d1b3a483 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -361,7 +361,8 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, BT_DBG("sock %p, sk %p", sock, sk); if (peer && sk->sk_state != BT_CONNECTED && - sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2) + sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2 && + sk->sk_state != BT_CONFIG) return -ENOTCONN; memset(la, 0, sizeof(struct sockaddr_l2)); -- cgit v1.2.3 From 81218d2099e85542a57e266336db5e0585c9f2cc Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Mon, 30 Jun 2014 11:25:01 +0530 Subject: Bluetooth: Fallback to SCO on error code 0x10 (Connection Accept Timeout) This is to support the Motorola HF850 carkit which reports the error code 0x10 for an eSCO attempt, even though it advertises eSCO support. With this patch we will retry with a SCO connection, which succeeds. Signed-off-by: Nick Pelly Signed-off-by: Kiran Kumar Raparthy Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 315d615ca3f9..fe7a54b65e55 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3408,6 +3408,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, hci_conn_add_sysfs(conn); break; + case 0x10: /* Connection Accept Timeout */ case 0x0d: /* Connection Rejected due to Limited Resources */ case 0x11: /* Unsupported Feature or Parameter Value */ case 0x1c: /* SCO interval rejected */ -- cgit v1.2.3 From f81cd823a844c60349c40b53a1b84b5968113596 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 1 Jul 2014 10:59:24 +0200 Subject: Bluetooth: Use bool for smp_ltk_encrypt return value The return value of smp_ltk_encrypt is simple boolean, so just use bool and make the code a bit more readable. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 414c5151aa46..35f57090ddd0 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -837,7 +837,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) return smp_random(smp); } -static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) +static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) { struct smp_ltk *key; struct hci_conn *hcon = conn->hcon; @@ -845,18 +845,18 @@ static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, hcon->out); if (!key) - return 0; + return false; if (sec_level > BT_SECURITY_MEDIUM && !key->authenticated) - return 0; + return false; if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) - return 1; + return true; hci_le_start_enc(hcon, key->ediv, key->rand, key->val); hcon->enc_key_size = key->enc_size; - return 1; + return true; } static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) -- cgit v1.2.3 From 51d167c0972ef1496f2e6ab08aab602644d1f9bb Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 1 Jul 2014 12:11:04 +0200 Subject: Bluetooth: Change hci_conn_params_add to return the parameter struct When adding new connection parameters, it is useful to return either the existing struct or the newly created one. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 3 ++- net/bluetooth/hci_core.c | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ec830871b9b8..5a83621672bf 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -852,7 +852,8 @@ int hci_white_list_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); -int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); +struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, + bdaddr_t *addr, u8 addr_type); int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, u8 auto_connect, u16 conn_min_interval, u16 conn_max_interval); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2312e77582b0..883ddd52344d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3472,21 +3472,22 @@ void hci_pend_le_conns_clear(struct hci_dev *hdev) } /* This function requires the caller holds hdev->lock */ -int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) +struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, + bdaddr_t *addr, u8 addr_type) { struct hci_conn_params *params; if (!is_identity_address(addr, addr_type)) - return -EINVAL; + return NULL; params = hci_conn_params_lookup(hdev, addr, addr_type); if (params) - return 0; + return params; params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) { BT_ERR("Out of memory"); - return -ENOMEM; + return NULL; } bacpy(¶ms->addr, addr); @@ -3502,7 +3503,7 @@ int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) BT_DBG("addr %pMR (type %u)", addr, addr_type); - return 0; + return params; } /* This function requires the caller holds hdev->lock */ -- cgit v1.2.3 From 8c87aae1fa2ffa89e5e840b8e928fa0eb5c13157 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 1 Jul 2014 12:11:05 +0200 Subject: Bluetooth: Use hci_conn_params_add within hci_conn_params_set The hci_conn_params_add function provides the default allocation of connection parameters. To avoid code duplication, use that code from hci_conn_params_set to allocate or lookup parameter struct. As a benefit the connection latency and supervision timeout parameters are no longer reset to default when calling hci_conn_params_set. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 883ddd52344d..9ae945d8ad7e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3513,29 +3513,12 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, { struct hci_conn_params *params; - if (!is_identity_address(addr, addr_type)) - return -EINVAL; - - params = hci_conn_params_lookup(hdev, addr, addr_type); - if (params) - goto update; - - params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - BT_ERR("Out of memory"); - return -ENOMEM; - } - - bacpy(¶ms->addr, addr); - params->addr_type = addr_type; - - list_add(¶ms->list, &hdev->le_conn_params); + params = hci_conn_params_add(hdev, addr, addr_type); + if (!params) + return -EIO; -update: params->conn_min_interval = conn_min_interval; params->conn_max_interval = conn_max_interval; - params->conn_latency = hdev->le_conn_latency; - params->supervision_timeout = hdev->le_supv_timeout; params->auto_connect = auto_connect; switch (auto_connect) { -- cgit v1.2.3 From d06b50ce14119acb04773a9808ccff5d1767b7e4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 1 Jul 2014 12:11:06 +0200 Subject: Bluetooth: Remove connection interval parameters from hci_conn_params_set The connection interval parameter of hci_conn_params_set are always used with the controller defaults. So just let hci_conn_params_add set the controller default and not bother resetting them to controller defaults every time the hci_conn_params_set is called. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 3 +-- net/bluetooth/hci_core.c | 10 +++------- net/bluetooth/mgmt.c | 5 ++--- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5a83621672bf..61d4d265f42d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -855,8 +855,7 @@ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, - u8 auto_connect, u16 conn_min_interval, - u16 conn_max_interval); + u8 auto_connect); void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_conn_params_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9ae945d8ad7e..237963d5473c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3508,8 +3508,7 @@ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, /* This function requires the caller holds hdev->lock */ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, - u8 auto_connect, u16 conn_min_interval, - u16 conn_max_interval) + u8 auto_connect) { struct hci_conn_params *params; @@ -3517,8 +3516,6 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, if (!params) return -EIO; - params->conn_min_interval = conn_min_interval; - params->conn_max_interval = conn_max_interval; params->auto_connect = auto_connect; switch (auto_connect) { @@ -3532,9 +3529,8 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, break; } - BT_DBG("addr %pMR (type %u) auto_connect %u conn_min_interval 0x%.4x " - "conn_max_interval 0x%.4x", addr, addr_type, auto_connect, - conn_min_interval, conn_max_interval); + BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type, + auto_connect); return 0; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 6baba309f9e2..c6e9b551242b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5028,9 +5028,8 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, /* If the connection parameters don't exist for this device, * they will be created and configured with defaults. */ - if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type, auto_conn, - hdev->le_conn_min_interval, - hdev->le_conn_max_interval) < 0) { + if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type, + auto_conn) < 0) { err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, MGMT_STATUS_FAILED, &cp->addr, sizeof(cp->addr)); -- cgit v1.2.3 From 42bd6a56ed1ab4b2cb50f4d4e674874da9b47f46 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 1 Jul 2014 14:11:19 +0200 Subject: Bluetooth: Fix merge of advertising data and scan response data The advertising data and scan response data are merged in the wrong order. It should be advertsing data first and then scan response data and not the other way around. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg Cc: stable@vger.kernel.org # 3.16 --- net/bluetooth/hci_event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fe7a54b65e55..ea155183c1d6 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4270,8 +4270,8 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, * sending a merged device found event. */ mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, - d->last_adv_addr_type, NULL, rssi, 0, 1, data, len, - d->last_adv_data, d->last_adv_data_len); + d->last_adv_addr_type, NULL, rssi, 0, 1, + d->last_adv_data, d->last_adv_data_len, data, len); clear_pending_adv_report(hdev); } -- cgit v1.2.3 From af58925ca6175695e502fa792f43a946f7474765 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 1 Jul 2014 14:11:20 +0200 Subject: Bluetooth: Provide flags parameter direct to mgmt_device_found Providing the flags parameter directly to mgmt_device_found function makes the core simpler and more readable. With this it becomes a lot easier to add new flags in the future. This also changes hci_inquiry_cache_update to just return that flags needed for mgmt_device_found since that is its only use for the two return parameters anyway. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 9 ++++---- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/hci_core.c | 24 ++++++++++++-------- net/bluetooth/hci_event.c | 48 ++++++++++++++++++++++------------------ net/bluetooth/mgmt.c | 10 +++------ 5 files changed, 50 insertions(+), 42 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 61d4d265f42d..ab3d4dda071c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -510,8 +510,8 @@ struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, int state); void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, struct inquiry_entry *ie); -bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, - bool name_known, bool *ssp); +u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, + bool name_known); void hci_inquiry_cache_flush(struct hci_dev *hdev); /* ----- HCI Connections ----- */ @@ -1318,9 +1318,8 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, u8 *randomizer192, u8 *hash256, u8 *randomizer256, u8 status); void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, - u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp, - u8 scan_rsp_len); + u8 addr_type, u8 *dev_class, s8 rssi, u32 flags, + u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len); void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, s8 rssi, u8 *name, u8 name_len); void mgmt_discovering(struct hci_dev *hdev, u8 discovering); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 1f95ad4fce02..2d88f361a016 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -547,6 +547,7 @@ struct mgmt_ev_auth_failed { #define MGMT_DEV_FOUND_CONFIRM_NAME 0x01 #define MGMT_DEV_FOUND_LEGACY_PAIRING 0x02 +#define MGMT_DEV_FOUND_NOT_CONNECTABLE 0x04 #define MGMT_EV_DEVICE_FOUND 0x0012 struct mgmt_ev_device_found { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 237963d5473c..0aa392406629 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "smp.h" @@ -1970,22 +1971,24 @@ void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, list_add(&ie->list, pos); } -bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, - bool name_known, bool *ssp) +u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, + bool name_known) { struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *ie; + u32 flags = 0; BT_DBG("cache %p, %pMR", cache, &data->bdaddr); hci_remove_remote_oob_data(hdev, &data->bdaddr); - *ssp = data->ssp_mode; + if (!data->ssp_mode) + flags |= MGMT_DEV_FOUND_LEGACY_PAIRING; ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr); if (ie) { - if (ie->data.ssp_mode) - *ssp = true; + if (!ie->data.ssp_mode) + flags |= MGMT_DEV_FOUND_LEGACY_PAIRING; if (ie->name_state == NAME_NEEDED && data->rssi != ie->data.rssi) { @@ -1998,8 +2001,10 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, /* Entry not in the cache. Add new one. */ ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); - if (!ie) - return false; + if (!ie) { + flags |= MGMT_DEV_FOUND_CONFIRM_NAME; + goto done; + } list_add(&ie->all, &cache->all); @@ -2022,9 +2027,10 @@ update: cache->timestamp = jiffies; if (ie->name_state == NAME_NOT_KNOWN) - return false; + flags |= MGMT_DEV_FOUND_CONFIRM_NAME; - return true; +done: + return flags; } static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ea155183c1d6..a4854a5d9298 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1132,7 +1132,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, d->last_adv_addr_type, NULL, - d->last_adv_rssi, 0, 1, + d->last_adv_rssi, 0, d->last_adv_data, d->last_adv_data_len, NULL, 0); } @@ -1965,7 +1965,7 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { - bool name_known, ssp; + u32 flags; bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; @@ -1976,10 +1976,10 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) data.rssi = 0x00; data.ssp_mode = 0x00; - name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp); + flags = hci_inquiry_cache_update(hdev, &data, false); + mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, 0, !name_known, ssp, NULL, - 0, NULL, 0); + info->dev_class, 0, flags, NULL, 0, NULL, 0); } hci_dev_unlock(hdev); @@ -3257,7 +3257,6 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, { struct inquiry_data data; int num_rsp = *((__u8 *) skb->data); - bool name_known, ssp; BT_DBG("%s num_rsp %d", hdev->name, num_rsp); @@ -3274,6 +3273,8 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, info = (void *) (skb->data + 1); for (; num_rsp; num_rsp--, info++) { + u32 flags; + bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -3283,16 +3284,18 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, data.rssi = info->rssi; data.ssp_mode = 0x00; - name_known = hci_inquiry_cache_update(hdev, &data, - false, &ssp); + flags = hci_inquiry_cache_update(hdev, &data, false); + mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, ssp, NULL, 0, NULL, 0); + flags, NULL, 0, NULL, 0); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); for (; num_rsp; num_rsp--, info++) { + u32 flags; + bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -3301,11 +3304,12 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x00; - name_known = hci_inquiry_cache_update(hdev, &data, - false, &ssp); + + flags = hci_inquiry_cache_update(hdev, &data, false); + mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, - !name_known, ssp, NULL, 0, NULL, 0); + flags, NULL, 0, NULL, 0); } } @@ -3472,7 +3476,8 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev, hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { - bool name_known, ssp; + u32 flags; + bool name_known; bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; @@ -3490,12 +3495,13 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev, else name_known = true; - name_known = hci_inquiry_cache_update(hdev, &data, name_known, - &ssp); + flags = hci_inquiry_cache_update(hdev, &data, name_known); + eir_len = eir_get_length(info->data, sizeof(info->data)); + mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, - info->dev_class, info->rssi, !name_known, - ssp, info->data, eir_len, NULL, 0); + info->dev_class, info->rssi, + flags, info->data, eir_len, NULL, 0); } hci_dev_unlock(hdev); @@ -4226,7 +4232,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, } mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, - rssi, 0, 1, data, len, NULL, 0); + rssi, 0, data, len, NULL, 0); return; } @@ -4243,7 +4249,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, if (!match) mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, d->last_adv_addr_type, NULL, - d->last_adv_rssi, 0, 1, + d->last_adv_rssi, 0, d->last_adv_data, d->last_adv_data_len, NULL, 0); @@ -4261,7 +4267,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, */ clear_pending_adv_report(hdev); mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, - rssi, 0, 1, data, len, NULL, 0); + rssi, 0, data, len, NULL, 0); return; } @@ -4270,7 +4276,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, * sending a merged device found event. */ mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, - d->last_adv_addr_type, NULL, rssi, 0, 1, + d->last_adv_addr_type, NULL, rssi, 0, d->last_adv_data, d->last_adv_data_len, data, len); clear_pending_adv_report(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c6e9b551242b..336a2311bdca 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6233,9 +6233,8 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, } void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, - u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp, - u8 scan_rsp_len) + u8 addr_type, u8 *dev_class, s8 rssi, u32 flags, + u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len) { char buf[512]; struct mgmt_ev_device_found *ev = (void *) buf; @@ -6263,10 +6262,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, } ev->rssi = rssi; - if (cfm_name) - ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME); - if (!ssp) - ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING); + ev->flags = cpu_to_le32(flags); if (eir_len > 0) memcpy(ev->eir, eir, eir_len); -- cgit v1.2.3 From c70a7e4cc8d22cb1ce684637ef8a4bb3a80d15b7 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 1 Jul 2014 14:11:21 +0200 Subject: Bluetooth: Add support for Not Connectable flag for Device Found events The Device Found events of the management interface should indicate if it is possible to connect to a remote device or if it is broadcaster only advertising. To allow this differentation the Not Connectable flag is introduced that will be set when it is known that a device can not be connected. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ab3d4dda071c..eb0add396595 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -71,6 +71,7 @@ struct discovery_state { bdaddr_t last_adv_addr; u8 last_adv_addr_type; s8 last_adv_rssi; + u32 last_adv_flags; u8 last_adv_data[HCI_MAX_AD_LENGTH]; u8 last_adv_data_len; }; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a4854a5d9298..8097559ebb48 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1089,13 +1089,15 @@ static void clear_pending_adv_report(struct hci_dev *hdev) } static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 bdaddr_type, s8 rssi, u8 *data, u8 len) + u8 bdaddr_type, s8 rssi, u32 flags, + u8 *data, u8 len) { struct discovery_state *d = &hdev->discovery; bacpy(&d->last_adv_addr, bdaddr); d->last_adv_addr_type = bdaddr_type; d->last_adv_rssi = rssi; + d->last_adv_flags = flags; memcpy(d->last_adv_data, data, len); d->last_adv_data_len = len; } @@ -1132,7 +1134,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, d->last_adv_addr_type, NULL, - d->last_adv_rssi, 0, + d->last_adv_rssi, d->last_adv_flags, d->last_adv_data, d->last_adv_data_len, NULL, 0); } @@ -4209,6 +4211,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, { struct discovery_state *d = &hdev->discovery; bool match; + u32 flags; /* Passive scanning shouldn't trigger any device found events */ if (hdev->le_scan_type == LE_SCAN_PASSIVE) { @@ -4217,6 +4220,27 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, return; } + /* When receiving non-connectable or scannable undirected + * advertising reports, this means that the remote device is + * not connectable and then clearly indicate this in the + * device found event. + * + * When receiving a scan response, then there is no way to + * know if the remote device is connectable or not. However + * since scan responses are merged with a previously seen + * advertising report, the flags field from that report + * will be used. + * + * In the really unlikely case that a controller get confused + * and just sends a scan response event, then it is marked as + * not connectable as well. + */ + if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND || + type == LE_ADV_SCAN_RSP) + flags = MGMT_DEV_FOUND_NOT_CONNECTABLE; + else + flags = 0; + /* If there's nothing pending either store the data from this * event or send an immediate device found event if the data * should not be stored for later. @@ -4227,12 +4251,12 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, */ if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) { store_pending_adv_report(hdev, bdaddr, bdaddr_type, - rssi, data, len); + rssi, flags, data, len); return; } mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, - rssi, 0, data, len, NULL, 0); + rssi, flags, data, len, NULL, 0); return; } @@ -4249,7 +4273,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, if (!match) mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, d->last_adv_addr_type, NULL, - d->last_adv_rssi, 0, + d->last_adv_rssi, d->last_adv_flags, d->last_adv_data, d->last_adv_data_len, NULL, 0); @@ -4258,7 +4282,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, */ if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) { store_pending_adv_report(hdev, bdaddr, bdaddr_type, - rssi, data, len); + rssi, flags, data, len); return; } @@ -4267,7 +4291,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, */ clear_pending_adv_report(hdev); mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, - rssi, 0, data, len, NULL, 0); + rssi, flags, data, len, NULL, 0); return; } @@ -4276,7 +4300,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, * sending a merged device found event. */ mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK, - d->last_adv_addr_type, NULL, rssi, 0, + d->last_adv_addr_type, NULL, rssi, d->last_adv_flags, d->last_adv_data, d->last_adv_data_len, data, len); clear_pending_adv_report(hdev); } -- cgit v1.2.3 From 854f47278fb36f4904649b994acf559e13920232 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 1 Jul 2014 18:40:20 +0300 Subject: Bluetooth: Fix redundant encryption when receiving Security Request If we're already encrypted with a good enough LTK we should just ignore an incoming SMP Security Request. The code was already taking care of this in the smp_conn_security function before calling smp_ltk_encrypt but failed to do the same in smp_cmd_security_req. This patch fixes the issue by moving up the smp_sufficient_security function and using it in the Security Request handler before trying to request encryption. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 35f57090ddd0..6ce7785a2708 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -859,6 +859,17 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) return true; } +bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) +{ + if (sec_level == BT_SECURITY_LOW) + return true; + + if (hcon->sec_level >= sec_level) + return true; + + return false; +} + static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_security_req *rp = (void *) skb->data; @@ -876,6 +887,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) return SMP_CMD_NOTSUPP; sec_level = authreq_to_seclevel(rp->auth_req); + if (smp_sufficient_security(hcon, sec_level)) + return 0; + if (sec_level > hcon->pending_sec_level) hcon->pending_sec_level = sec_level; @@ -904,17 +918,6 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) return 0; } -bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) -{ - if (sec_level == BT_SECURITY_LOW) - return true; - - if (hcon->sec_level >= sec_level) - return true; - - return false; -} - int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) { struct l2cap_conn *conn = hcon->l2cap_data; -- cgit v1.2.3 From fe59a05f941dbeb14316449be42d059761bed62c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 1 Jul 2014 19:14:12 +0300 Subject: Bluetooth: Add flag to track STK encryption There are certain subtle differences in behavior when we're encrypted with the STK, such as allowing re-encryption even though the security level stays the same. Because of this, add a flag to track whether we're encrypted with an STK or not. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 3 +++ net/bluetooth/smp.c | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index eb0add396595..9078da681f16 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -536,6 +536,7 @@ enum { HCI_CONN_AUTH, HCI_CONN_SECURE, HCI_CONN_FIPS, + HCI_CONN_STK_ENCRYPT, }; static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8097559ebb48..b0b760dd66a3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4365,8 +4365,11 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) * using a distributed LTK. */ if (ltk->type == SMP_STK) { + set_bit(HCI_CONN_STK_ENCRYPT, &conn->flags); list_del(<k->list); kfree(ltk); + } else { + clear_bit(HCI_CONN_STK_ENCRYPT, &conn->flags); } hci_dev_unlock(hdev); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 6ce7785a2708..68e6f245581c 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -538,6 +538,7 @@ static u8 smp_random(struct smp_chan *smp) hci_le_start_enc(hcon, ediv, rand, stk); hcon->enc_key_size = smp->enc_key_size; + set_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags); } else { u8 stk[16], auth; __le64 rand = 0; @@ -856,6 +857,9 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) hci_le_start_enc(hcon, key->ediv, key->rand, key->val); hcon->enc_key_size = key->enc_size; + /* We never store STKs for master role, so clear this flag */ + clear_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags); + return true; } -- cgit v1.2.3 From 9ab65d60c212c23f1605f35aea229f4c94df2334 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 1 Jul 2014 19:14:13 +0300 Subject: Bluetooth: Allow re-encryption with LTK when STK is in use If we're encrypted with the STK we should allow re-encryption with an LTK even though the achieved security level is the same. This patch adds the necessary logic to the smp_sufficient_security function which is used to determine whether to proceed with encryption or not. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 68e6f245581c..55c41de2f5a0 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -868,6 +868,14 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) if (sec_level == BT_SECURITY_LOW) return true; + /* If we're encrypted with an STK always claim insufficient + * security. This way we allow the connection to be re-encrypted + * with an LTK, even if the LTK provides the same level of + * security. + */ + if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags)) + return false; + if (hcon->sec_level >= sec_level) return true; -- cgit v1.2.3 From b8221770c984bcd185c93cb3a31acab27b67c94a Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 1 Jul 2014 19:28:23 +0200 Subject: Bluetooth: Do not trigger background scanning when HCI_AUTO_OFF is set When a new controller is initialized, but not powered from userspace at the moment, the HCI_AUTO_OFF flag is still set. During this period, userspace might program device for auto-connection, but never power on the controller. In this case do not try to start background scanning and leave it for later to be started. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 0aa392406629..25ed6d3de410 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5306,6 +5306,7 @@ void hci_update_background_scan(struct hci_dev *hdev) if (!test_bit(HCI_UP, &hdev->flags) || test_bit(HCI_INIT, &hdev->flags) || test_bit(HCI_SETUP, &hdev->dev_flags) || + test_bit(HCI_AUTO_OFF, &hdev->dev_flags) || test_bit(HCI_UNREGISTER, &hdev->dev_flags)) return; -- cgit v1.2.3 From c83ed19d23909db10a4402d4c6c0164bab9a9cf0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 1 Jul 2014 19:28:24 +0200 Subject: Bluetooth: Ensure that background scanning gets enabled on power on The background scanning normally gets enabled during power on by adding devices to the pending connection list. However devices might be already on that list and the list of devices is empty, then it is better to trigger the background manually. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 336a2311bdca..408468c07a8a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5283,11 +5283,27 @@ void mgmt_index_removed(struct hci_dev *hdev) static void restart_le_auto_conns(struct hci_dev *hdev) { struct hci_conn_params *p; + bool added = false; list_for_each_entry(p, &hdev->le_conn_params, list) { - if (p->auto_connect == HCI_AUTO_CONN_ALWAYS) + if (p->auto_connect == HCI_AUTO_CONN_ALWAYS) { hci_pend_le_conn_add(hdev, &p->addr, p->addr_type); + added = true; + } } + + /* Calling hci_pend_le_conn_add will actually already trigger + * background scanning when needed. So no need to trigger it + * just another time. + * + * This check is here to avoid an unneeded restart of the + * passive scanning. Since this is during the controller + * power up phase the duplicate filtering is not an issue. + */ + if (added) + return; + + hci_update_background_scan(hdev); } static void powered_complete(struct hci_dev *hdev, u8 status) -- cgit v1.2.3 From 2a8357f2393d89a34b5a77051d29951af9646406 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 1 Jul 2014 22:09:47 +0300 Subject: Bluetooth: Fix redundant device (un)blocked events For the Block/Unblock Device mgmt commands we should only emit the Blocked/Unblocked events on any socket except for the one which received the command. The code was previously incorrectly trying to look up a non-existent pending command and thereby ending up not skipping the command socket for the event. We can simplify the code a lot by simply sending the event directly from the command handler functions. We have the reference to the command socket available there which makes it easy to pass to the mgmt_event function for skipping. The only notable side-effect of this is that the old blacklisting ioctl's no-longer cause mgmt events to be emitted, however as user space versions using these ioctl's are not mgmt-aware this is acceptable. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 -- net/bluetooth/hci_core.c | 4 ++-- net/bluetooth/mgmt.c | 50 +++++++++++++--------------------------- 3 files changed, 18 insertions(+), 38 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9078da681f16..3404f9bd2da0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1325,8 +1325,6 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, s8 rssi, u8 *name, u8 name_len); void mgmt_discovering(struct hci_dev *hdev, u8 discovering); -int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); -int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent); void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk); void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 25ed6d3de410..72eb41424d04 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3275,7 +3275,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) list_add(&entry->list, &hdev->blacklist); - return mgmt_device_blocked(hdev, bdaddr, type); + return 0; } int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) @@ -3294,7 +3294,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) list_del(&entry->list); kfree(entry); - return mgmt_device_unblocked(hdev, bdaddr, type); + return 0; } struct bdaddr_list *hci_white_list_lookup(struct hci_dev *hdev, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 408468c07a8a..ba5e215a7561 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3773,11 +3773,16 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, hci_dev_lock(hdev); err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); - if (err < 0) + if (err < 0) { status = MGMT_STATUS_FAILED; - else - status = MGMT_STATUS_SUCCESS; + goto done; + } + + mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr), + sk); + status = MGMT_STATUS_SUCCESS; +done: err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status, &cp->addr, sizeof(cp->addr)); @@ -3803,11 +3808,16 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, hci_dev_lock(hdev); err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); - if (err < 0) + if (err < 0) { status = MGMT_STATUS_INVALID_PARAMS; - else - status = MGMT_STATUS_SUCCESS; + goto done; + } + + mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr), + sk); + status = MGMT_STATUS_SUCCESS; +done: err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status, &cp->addr, sizeof(cp->addr)); @@ -6346,34 +6356,6 @@ void mgmt_discovering(struct hci_dev *hdev, u8 discovering) mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL); } -int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) -{ - struct pending_cmd *cmd; - struct mgmt_ev_device_blocked ev; - - cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev); - - bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = type; - - return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev), - cmd ? cmd->sk : NULL); -} - -int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) -{ - struct pending_cmd *cmd; - struct mgmt_ev_device_unblocked ev; - - cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev); - - bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = type; - - return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev), - cmd ? cmd->sk : NULL); -} - static void adv_enable_complete(struct hci_dev *hdev, u8 status) { BT_DBG("%s status %u", hdev->name, status); -- cgit v1.2.3 From 4df82b5911c0e380d8b308958f158c3e7b365467 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Mon, 31 Mar 2014 14:41:44 -0700 Subject: Bluetooth: btmrvl: indicate pscan scheduling instant in a debug event A vendor specific command is sent to firmware during initialization to enable this feature. This command is for SD8897 only. Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_drv.h | 1 + drivers/bluetooth/btmrvl_main.c | 19 +++++++++++++++++++ drivers/bluetooth/btmrvl_sdio.c | 5 +++++ drivers/bluetooth/btmrvl_sdio.h | 2 ++ 4 files changed, 27 insertions(+) diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index dc79f88f8717..4c313e73df83 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -89,6 +89,7 @@ struct btmrvl_private { #define MRVL_VENDOR_PKT 0xFE /* Vendor specific Bluetooth commands */ +#define BT_CMD_PSCAN_WIN_REPORT_ENABLE 0xFC03 #define BT_CMD_AUTO_SLEEP_MODE 0xFC23 #define BT_CMD_HOST_SLEEP_CONFIG 0xFC59 #define BT_CMD_HOST_SLEEP_ENABLE 0xFC5A diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index e9dbddb0b8f1..d35f2e189a6d 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -214,6 +214,23 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd) } EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); +int btmrvl_pscan_window_reporting(struct btmrvl_private *priv, u8 subcmd) +{ + struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; + int ret; + + if (!card->support_pscan_win_report) + return 0; + + ret = btmrvl_send_sync_cmd(priv, BT_CMD_PSCAN_WIN_REPORT_ENABLE, + &subcmd, 1); + if (ret) + BT_ERR("PSCAN_WIN_REPORT_ENABLE command failed: %#x", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(btmrvl_pscan_window_reporting); + int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv) { int ret; @@ -489,6 +506,8 @@ static int btmrvl_setup(struct hci_dev *hdev) btmrvl_cal_data_dt(priv); + btmrvl_pscan_window_reporting(priv, 0x01); + priv->btmrvl_dev.psmode = 1; btmrvl_enable_ps(priv); diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 9dedca516ff5..efff06438b02 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -108,6 +108,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { .helper = "mrvl/sd8688_helper.bin", .firmware = "mrvl/sd8688.bin", .reg = &btmrvl_reg_8688, + .support_pscan_win_report = false, .sd_blksz_fw_dl = 64, }; @@ -115,6 +116,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { .helper = NULL, .firmware = "mrvl/sd8787_uapsta.bin", .reg = &btmrvl_reg_87xx, + .support_pscan_win_report = false, .sd_blksz_fw_dl = 256, }; @@ -122,6 +124,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { .helper = NULL, .firmware = "mrvl/sd8797_uapsta.bin", .reg = &btmrvl_reg_87xx, + .support_pscan_win_report = false, .sd_blksz_fw_dl = 256, }; @@ -129,6 +132,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { .helper = NULL, .firmware = "mrvl/sd8897_uapsta.bin", .reg = &btmrvl_reg_88xx, + .support_pscan_win_report = true, .sd_blksz_fw_dl = 256, }; @@ -1067,6 +1071,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func, card->firmware = data->firmware; card->reg = data->reg; card->sd_blksz_fw_dl = data->sd_blksz_fw_dl; + card->support_pscan_win_report = data->support_pscan_win_report; } if (btmrvl_sdio_register_dev(card) < 0) { diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index d4dd3b0fa53d..453559f98a75 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -89,6 +89,7 @@ struct btmrvl_sdio_card { const char *helper; const char *firmware; const struct btmrvl_sdio_card_reg *reg; + bool support_pscan_win_report; u16 sd_blksz_fw_dl; u8 rx_unit; struct btmrvl_private *priv; @@ -98,6 +99,7 @@ struct btmrvl_sdio_device { const char *helper; const char *firmware; const struct btmrvl_sdio_card_reg *reg; + const bool support_pscan_win_report; u16 sd_blksz_fw_dl; }; -- cgit v1.2.3 From 396e04f4bb9afefb0744715dc76d9abe18ee5fb0 Mon Sep 17 00:00:00 2001 From: Chin-Ran Lo Date: Tue, 1 Jul 2014 14:00:14 -0700 Subject: Bluetooth: btmrvl: wait for HOST_SLEEP_ENABLE event in suspend After BT_CMD_HOST_SLEEP_ENABLE command finishes, driver should wait until getting BT_EVENT_HOST_SLEEP_ENABLE event to complete suspend procedure. Without this patch the suspend handler would return success earlier. By the time when the BT_EVENT_HOST_SLEEP_ENABLE event comes in the controller driver could have already turned off the bus clock. This causes kernel crash or system reboot eventually. Cc: # 3.13+ Signed-off-by: Chin-Ran Lo Signed-off-by: Jeff CF Chen Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_drv.h | 1 + drivers/bluetooth/btmrvl_main.c | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 4c313e73df83..a8a9d3380e59 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -68,6 +68,7 @@ struct btmrvl_adapter { u8 hs_state; u8 wakeup_tries; wait_queue_head_t cmd_wait_q; + wait_queue_head_t event_hs_wait_q; u8 cmd_complete; bool is_suspended; }; diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index d35f2e189a6d..cc65fd2fe856 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -114,6 +114,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) adapter->hs_state = HS_ACTIVATED; if (adapter->psmode) adapter->ps_state = PS_SLEEP; + wake_up_interruptible(&adapter->event_hs_wait_q); BT_DBG("HS ACTIVATED!"); } else { BT_DBG("HS Enable failed"); @@ -270,11 +271,31 @@ EXPORT_SYMBOL_GPL(btmrvl_enable_ps); int btmrvl_enable_hs(struct btmrvl_private *priv) { + struct btmrvl_adapter *adapter = priv->adapter; int ret; ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_ENABLE, NULL, 0); - if (ret) + if (ret) { BT_ERR("Host sleep enable command failed\n"); + return ret; + } + + ret = wait_event_interruptible_timeout(adapter->event_hs_wait_q, + adapter->hs_state, + msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED)); + if (ret < 0) { + BT_ERR("event_hs_wait_q terminated (%d): %d,%d,%d", + ret, adapter->hs_state, adapter->ps_state, + adapter->wakeup_tries); + } else if (!ret) { + BT_ERR("hs_enable timeout: %d,%d,%d", adapter->hs_state, + adapter->ps_state, adapter->wakeup_tries); + ret = -ETIMEDOUT; + } else { + BT_DBG("host sleep enabled: %d,%d,%d", adapter->hs_state, + adapter->ps_state, adapter->wakeup_tries); + ret = 0; + } return ret; } @@ -375,6 +396,7 @@ static void btmrvl_init_adapter(struct btmrvl_private *priv) } init_waitqueue_head(&priv->adapter->cmd_wait_q); + init_waitqueue_head(&priv->adapter->event_hs_wait_q); } static void btmrvl_free_adapter(struct btmrvl_private *priv) @@ -685,6 +707,7 @@ int btmrvl_remove_card(struct btmrvl_private *priv) hdev = priv->btmrvl_dev.hcidev; wake_up_interruptible(&priv->adapter->cmd_wait_q); + wake_up_interruptible(&priv->adapter->event_hs_wait_q); kthread_stop(priv->main_thread.task); -- cgit v1.2.3 From 8e75b46a4f5d2c71b2f3ea632df1b15502514948 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 1 Jul 2014 18:10:08 -0300 Subject: Bluetooth: Connection Parameter Update Procedure This patch adds support for LE Connection Parameters Request Link Layer control procedure introduced in Core spec 4.1. This procedure allows a Peripheral or Central to update the Link Layer connection parameters of an established connection. Regarding the acceptance of connection parameters, the LL procedure follows the same approach of L2CAP procedure (see l2cap_conn_param_ update_req function). We accept any connection parameters values as long as they are within the valid range. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 28 +++++++++++++++++++++++++ net/bluetooth/hci_event.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 58c5930dea60..95b754785a7d 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -355,6 +355,7 @@ enum { #define HCI_LK_AUTH_COMBINATION_P256 0x08 /* ---- HCI Error Codes ---- */ +#define HCI_ERROR_UNKNOWN_CONN_ID 0x02 #define HCI_ERROR_AUTH_FAILURE 0x05 #define HCI_ERROR_MEMORY_EXCEEDED 0x07 #define HCI_ERROR_CONNECTION_TIMEOUT 0x08 @@ -364,6 +365,7 @@ enum { #define HCI_ERROR_REMOTE_POWER_OFF 0x15 #define HCI_ERROR_LOCAL_HOST_TERM 0x16 #define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18 +#define HCI_ERROR_INVALID_LL_PARAMS 0x1E #define HCI_ERROR_ADVERTISING_TIMEOUT 0x3c /* Flow control modes */ @@ -1305,6 +1307,23 @@ struct hci_rp_le_read_supported_states { __u8 le_states[8]; } __packed; +#define HCI_OP_LE_CONN_PARAM_REQ_REPLY 0x2020 +struct hci_cp_le_conn_param_req_reply { + __le16 handle; + __le16 interval_min; + __le16 interval_max; + __le16 latency; + __le16 timeout; + __le16 min_ce_len; + __le16 max_ce_len; +} __packed; + +#define HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY 0x2021 +struct hci_cp_le_conn_param_req_neg_reply { + __le16 handle; + __u8 reason; +} __packed; + /* ---- HCI Events ---- */ #define HCI_EV_INQUIRY_COMPLETE 0x01 @@ -1700,6 +1719,15 @@ struct hci_ev_le_ltk_req { __le16 ediv; } __packed; +#define HCI_EV_LE_REMOTE_CONN_PARAM_REQ 0x06 +struct hci_ev_le_remote_conn_param_req { + __le16 handle; + __le16 interval_min; + __le16 interval_max; + __le16 latency; + __le16 timeout; +} __packed; + /* Advertising report event types */ #define LE_ADV_IND 0x00 #define LE_ADV_DIRECT_IND 0x01 diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b0b760dd66a3..544e2ef85d82 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4382,6 +4382,52 @@ not_found: hci_dev_unlock(hdev); } +static void send_conn_param_neg_reply(struct hci_dev *hdev, u16 handle, + u8 reason) +{ + struct hci_cp_le_conn_param_req_neg_reply cp; + + cp.handle = cpu_to_le16(handle); + cp.reason = reason; + + hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY, sizeof(cp), + &cp); +} + +static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_ev_le_remote_conn_param_req *ev = (void *) skb->data; + struct hci_cp_le_conn_param_req_reply cp; + struct hci_conn *hcon; + u16 handle, min, max, latency, timeout; + + handle = le16_to_cpu(ev->handle); + min = le16_to_cpu(ev->interval_min); + max = le16_to_cpu(ev->interval_max); + latency = le16_to_cpu(ev->latency); + timeout = le16_to_cpu(ev->timeout); + + hcon = hci_conn_hash_lookup_handle(hdev, handle); + if (!hcon || hcon->state != BT_CONNECTED) + return send_conn_param_neg_reply(hdev, handle, + HCI_ERROR_UNKNOWN_CONN_ID); + + if (hci_check_conn_params(min, max, latency, timeout)) + return send_conn_param_neg_reply(hdev, handle, + HCI_ERROR_INVALID_LL_PARAMS); + + cp.handle = ev->handle; + cp.interval_min = ev->interval_min; + cp.interval_max = ev->interval_max; + cp.latency = ev->latency; + cp.timeout = ev->timeout; + cp.min_ce_len = 0; + cp.max_ce_len = 0; + + hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(cp), &cp); +} + static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_le_meta *le_ev = (void *) skb->data; @@ -4405,6 +4451,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_le_ltk_request_evt(hdev, skb); break; + case HCI_EV_LE_REMOTE_CONN_PARAM_REQ: + hci_le_remote_conn_param_req_evt(hdev, skb); + break; + default: break; } -- cgit v1.2.3 From 9193c6e884ae1b403f53ca1370a4b7f8185c547b Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 1 Jul 2014 18:10:09 -0300 Subject: Bluetooth: Move LE event mask setting into init3 phase During init2 phase, the LE local features have not be read yet so we aren't able to rely on hdev->le_features to determine if the controller supports the Connection Parameters Request Procedure. For that reason, this patch moves LE event mask setting from init2 into init3 initialization phase. The hdev->le_features mask will be checked by the next patch in order to know if "LE Remote Connection Parameter Request Event" should be enabled. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 72eb41424d04..5788e031b869 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1437,13 +1437,6 @@ static void hci_setup_event_mask(struct hci_request *req) events[7] |= 0x20; /* LE Meta-Event */ hci_req_add(req, HCI_OP_SET_EVENT_MASK, sizeof(events), events); - - if (lmp_le_capable(hdev)) { - memset(events, 0, sizeof(events)); - events[0] = 0x1f; - hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, - sizeof(events), events); - } } static void hci_init2_req(struct hci_request *req, unsigned long opt) @@ -1613,8 +1606,16 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) if (hdev->commands[5] & 0x10) hci_setup_link_policy(req); - if (lmp_le_capable(hdev)) + if (lmp_le_capable(hdev)) { + u8 events[8]; + + memset(events, 0, sizeof(events)); + events[0] = 0x1f; + hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events), + events); + hci_set_le_support(req); + } /* Read features beyond page 1 if available */ for (p = 2; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) { -- cgit v1.2.3 From 662bc2e63de765bb701e3d3eca6af9fe553d72ac Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 1 Jul 2014 18:10:10 -0300 Subject: Bluetooth: Enable new LE meta event The Bluetooth 4.1 introduces a new LE meta event called "LE Remote Connection Parameter Request" event. In order to the controller sends this event to host, we should enable it during controller initialization. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 3 +++ net/bluetooth/hci_core.c | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 95b754785a7d..66358af6b1fc 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -307,6 +307,9 @@ enum { #define LMP_HOST_LE_BREDR 0x04 #define LMP_HOST_SC 0x08 +/* LE features */ +#define HCI_LE_CONN_PARAM_REQ_PROC 0x02 + /* Connection modes */ #define HCI_CM_ACTIVE 0x0000 #define HCI_CM_HOLD 0x0001 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5788e031b869..615d0cf5e511 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1611,6 +1611,15 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) memset(events, 0, sizeof(events)); events[0] = 0x1f; + + /* If controller supports the Connection Parameters Request + * Link Layer Procedure, enable the corresponding event. + */ + if (hdev->le_features[0] & HCI_LE_CONN_PARAM_REQ_PROC) + events[0] |= 0x20; /* LE Remote Connection + * Parameter Request + */ + hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events), events); -- cgit v1.2.3 From ffb5a827d5ca5aef3f3fe5d64e42f3cf7fed4fc8 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 1 Jul 2014 18:10:11 -0300 Subject: Bluetooth: Introduce "New Connection Parameter" Event This patch introduces a new Mgmt event called "New Connection Parameter". This event indicates to userspace the connection parameters values the remote device requested. The user may store these values and load them into kernel. This way, next time a connection is established to that device, the kernel will use those parameters values instead of the default ones. This event is sent when the remote device requests new connection parameters through connection parameter update procedure. This event is not sent for slave connections. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 +++ include/net/bluetooth/mgmt.h | 10 ++++++++++ net/bluetooth/hci_event.c | 4 ++++ net/bluetooth/l2cap_core.c | 6 +++++- net/bluetooth/mgmt.c | 19 +++++++++++++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3404f9bd2da0..01fbbe20defb 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1329,6 +1329,9 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent); void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk); void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk, bool persistent); +void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 bdaddr_type, u16 min_interval, u16 max_interval, + u16 latency, u16 timeout); void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_smp_complete(struct hci_conn *conn, bool complete); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 2d88f361a016..3c0f29614d1b 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -615,3 +615,13 @@ struct mgmt_ev_device_added { struct mgmt_ev_device_removed { struct mgmt_addr_info addr; } __packed; + +#define MGMT_EV_NEW_CONN_PARAM 0x001c +struct mgmt_ev_new_conn_param { + struct mgmt_addr_info addr; + __u8 store_hint; + __le16 min_interval; + __le16 max_interval; + __le16 latency; + __le16 timeout; +} __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 544e2ef85d82..b9d16e0ed661 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4417,6 +4417,10 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, return send_conn_param_neg_reply(hdev, handle, HCI_ERROR_INVALID_LL_PARAMS); + if (test_bit(HCI_CONN_MASTER, &hcon->flags)) + mgmt_new_conn_param(hdev, &hcon->dst, hcon->dst_type, min, max, + latency, timeout); + cp.handle = ev->handle; cp.interval_min = ev->interval_min; cp.interval_max = ev->interval_max; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e203a5fdf874..058b3b2b59b5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5249,8 +5249,12 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP, sizeof(rsp), &rsp); - if (!err) + if (!err) { + mgmt_new_conn_param(hcon->hdev, &hcon->dst, hcon->dst_type, + min, max, latency, to_multiplier); + hci_le_conn_update(hcon, min, max, latency, to_multiplier); + } return 0; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ba5e215a7561..93cfefa260d5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -116,6 +116,7 @@ static const u16 mgmt_events[] = { MGMT_EV_NEW_CSRK, MGMT_EV_DEVICE_ADDED, MGMT_EV_DEVICE_REMOVED, + MGMT_EV_NEW_CONN_PARAM, }; #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) @@ -5690,6 +5691,24 @@ void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk, mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL); } +void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 bdaddr_type, u16 min_interval, u16 max_interval, + u16 latency, u16 timeout) +{ + struct mgmt_ev_new_conn_param ev; + + memset(&ev, 0, sizeof(ev)); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type); + ev.store_hint = 0x00; + ev.min_interval = cpu_to_le16(min_interval); + ev.max_interval = cpu_to_le16(max_interval); + ev.latency = cpu_to_le16(latency); + ev.timeout = cpu_to_le16(timeout); + + mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL); +} + static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len) { -- cgit v1.2.3 From 24c457e27076beb2a85b4213642a6388eb88f240 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 2 Jul 2014 00:53:47 +0200 Subject: Bluetooth: Add support for hdev->set_bdaddr callback handling Some embedded controllers allow the programming of a public address and this adds vendor support for supporting OEM confguration of such addresses. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 01fbbe20defb..ee480a86e558 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -171,6 +171,7 @@ struct hci_dev { __u8 bus; __u8 dev_type; bdaddr_t bdaddr; + bdaddr_t public_addr; bdaddr_t random_addr; bdaddr_t static_addr; __u8 adv_addr_type; @@ -344,6 +345,7 @@ struct hci_dev { int (*setup)(struct hci_dev *hdev); int (*send)(struct hci_dev *hdev, struct sk_buff *skb); void (*notify)(struct hci_dev *hdev, unsigned int evt); + int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr); }; #define HCI_PHY_HANDLE(handle) (handle & 0xff) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 615d0cf5e511..63197d70d8eb 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2249,6 +2249,17 @@ static int hci_dev_do_open(struct hci_dev *hdev) if (hdev->setup && test_bit(HCI_SETUP, &hdev->dev_flags)) ret = hdev->setup(hdev); + /* If public address change is configured, ensure that the + * address gets programmed. If the driver does not support + * changing the public address, fail the power on procedure. + */ + if (!ret && bacmp(&hdev->public_addr, BDADDR_ANY)) { + if (hdev->set_bdaddr) + ret = hdev->set_bdaddr(hdev, &hdev->public_addr); + else + ret = -EADDRNOTAVAIL; + } + if (!ret) { if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks) && !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) -- cgit v1.2.3 From abbaf50e3bccbb6c254c530ff1478acb56a6fed7 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 2 Jul 2014 00:53:48 +0200 Subject: Bluetooth: Add public address configration for Broadcom USB devices For the Broadcom based USB devices add support for configuration of the public device address. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 6250fc2fb93a..e0e39cc1af31 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1530,6 +1530,23 @@ done: return ret; } +static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + long ret; + + skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: BCM: Change address command failed (%ld)", + hdev->name, ret); + return ret; + } + kfree_skb(skb); + + return 0; +} + static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1635,8 +1652,10 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BCM92035) hdev->setup = btusb_setup_bcm92035; - if (id->driver_info & BTUSB_BCM_PATCHRAM) + if (id->driver_info & BTUSB_BCM_PATCHRAM) { hdev->setup = btusb_setup_bcm_patchram; + hdev->set_bdaddr = btusb_set_bdaddr_bcm; + } if (id->driver_info & BTUSB_INTEL) hdev->setup = btusb_setup_intel; -- cgit v1.2.3 From e493150e363917bf7e86e8fa4316e915fc2cf40b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 09:36:21 +0300 Subject: Bluetooth: Centralize looking up blocked devices to l2cap_recv_frame The ATT channel isn't the only one that we should ensure doesn't receive data from blocked devices. SMP is another, and in general we don't want data packets going to any of the various handlers. Therefore, add a single check to the l2cap_recv_frame function. The patch fixes at the same time the use of a correct address type. The blacklist stores the values with the user space facing triple type wheras hci_conn->dst_type uses the HCI address type (0x00 or 0x01). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 058b3b2b59b5..a6e276204ae9 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6878,9 +6878,6 @@ static void l2cap_att_channel(struct l2cap_conn *conn, BT_DBG("chan %p, len %d", chan, skb->len); - if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, hcon->dst_type)) - goto drop; - if (chan->imtu < skb->len) goto drop; @@ -6913,6 +6910,12 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) return; } + if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, + bdaddr_type(hcon, hcon->dst_type))) { + kfree_skb(skb); + return; + } + BT_DBG("len %d, cid 0x%4.4x", len, cid); switch (cid) { -- cgit v1.2.3 From 837d502efc3fe9a088b943aa1a7279cee4d0e118 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 09:36:22 +0300 Subject: Bluetooth: Drop LE connections for blocked devices Unlike BR/EDR we cannot reject LE connections of blocked devices but have to do it as soon as we get a LE Connection Complete event. The patch adds a blacklist check to the hci_le_conn_complete_evt function and drops all connections for blocked devices. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b9d16e0ed661..ed49a065dd67 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4038,6 +4038,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) struct hci_ev_le_conn_complete *ev = (void *) skb->data; struct hci_conn *conn; struct smp_irk *irk; + u8 addr_type; BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); @@ -4119,6 +4120,17 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->dst_type = irk->addr_type; } + if (conn->dst_type == ADDR_LE_DEV_PUBLIC) + addr_type = BDADDR_LE_PUBLIC; + else + addr_type = BDADDR_LE_RANDOM; + + /* Drop the connection if he device is blocked */ + if (hci_blacklist_lookup(hdev, &conn->dst, addr_type)) { + hci_conn_drop(conn); + goto unlock; + } + if (ev->status) { hci_le_conn_failed(conn, ev->status); goto unlock; -- cgit v1.2.3 From cb8d65973b57edeec53cd219ddbcb646cfd73452 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 2 Jul 2014 11:25:25 +0200 Subject: Bluetooth: Add public address configration for Intel USB devices For the Intel based USB devices add support for configuration of the public device address. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e0e39cc1af31..66966b9c4244 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1382,6 +1382,23 @@ exit_mfg_deactivate: return 0; } +static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + long ret; + + skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: changing Intel device address failed (%ld)", + hdev->name, ret); + return ret; + } + kfree_skb(skb); + + return 0; +} + static int btusb_setup_bcm_patchram(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -1657,8 +1674,10 @@ static int btusb_probe(struct usb_interface *intf, hdev->set_bdaddr = btusb_set_bdaddr_bcm; } - if (id->driver_info & BTUSB_INTEL) + if (id->driver_info & BTUSB_INTEL) { hdev->setup = btusb_setup_intel; + hdev->set_bdaddr = btusb_set_bdaddr_intel; + } /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); -- cgit v1.2.3 From 96c2103a57c5c6498138f38df926af6b86ea4e86 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 2 Jul 2014 11:30:51 +0200 Subject: Bluetooth: Default to internal use manufacturer identifier When allocating a new controller structure, then default to the internal use value 0xffff first. Default to 0x0000 is a bad idea since that is the manufacturer identifier of Ericsson Technology Licensing. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 63197d70d8eb..21a4c8dfb874 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3796,6 +3796,7 @@ struct hci_dev *hci_alloc_dev(void) hdev->link_mode = (HCI_LM_ACCEPT); hdev->num_iac = 0x01; /* One IAC support is mandatory */ hdev->io_capability = 0x03; /* No Input No Output */ + hdev->manufacturer = 0xffff; /* Default to internal use */ hdev->inq_tx_power = HCI_TX_POWER_INVALID; hdev->adv_tx_power = HCI_TX_POWER_INVALID; -- cgit v1.2.3 From 40cb0984150e118141a1b1a42f67f6d921ea8e09 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 2 Jul 2014 12:06:45 +0200 Subject: Bluetooth: Check for default address of Intel USB controllers Some Intel Bluetooth controllers come with a default address. If this address is found, print an error to warn the user about it. The controller is fully operational, but the danger of duplicate Bluetooth addresses might causes issues. At least with a clear error it becomes easier to debug these cases. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 66966b9c4244..32aabea731f2 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1182,6 +1182,49 @@ static int btusb_setup_intel_patching(struct hci_dev *hdev, return 0; } +#define BDADDR_INTEL (&(bdaddr_t) {{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}}) + +static int btusb_check_bdaddr_intel(struct hci_dev *hdev) +{ + struct sk_buff *skb; + struct hci_rp_read_bd_addr *rp; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s reading Intel device address failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*rp)) { + BT_ERR("%s Intel device address length mismatch", hdev->name); + kfree_skb(skb); + return -EIO; + } + + rp = (struct hci_rp_read_bd_addr *) skb->data; + if (rp->status) { + BT_ERR("%s Intel device address result failed (%02x)", + hdev->name, rp->status); + kfree_skb(skb); + return -bt_to_errno(rp->status); + } + + /* For some Intel based controllers, the default Bluetooth device + * address 00:03:19:9E:8B:00 can be found. These controllers are + * fully operational, but have the danger of duplicate addresses + * and that in turn can cause problems with Bluetooth operation. + */ + if (!bacmp(&rp->bdaddr, BDADDR_INTEL)) + BT_ERR("%s found Intel default device address (%pMR)", + hdev->name, &rp->bdaddr); + + kfree_skb(skb); + + return 0; +} + static int btusb_setup_intel(struct hci_dev *hdev) { struct sk_buff *skb; @@ -1254,6 +1297,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) BT_INFO("%s: Intel device is already patched. patch num: %02x", hdev->name, ver->fw_patch_num); kfree_skb(skb); + btusb_check_bdaddr_intel(hdev); return 0; } @@ -1266,6 +1310,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) fw = btusb_setup_intel_get_fw(hdev, ver); if (!fw) { kfree_skb(skb); + btusb_check_bdaddr_intel(hdev); return 0; } fw_ptr = fw->data; @@ -1345,6 +1390,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) BT_INFO("%s: Intel Bluetooth firmware patch completed and activated", hdev->name); + btusb_check_bdaddr_intel(hdev); return 0; exit_mfg_disable: @@ -1359,6 +1405,8 @@ exit_mfg_disable: kfree_skb(skb); BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name); + + btusb_check_bdaddr_intel(hdev); return 0; exit_mfg_deactivate: @@ -1379,6 +1427,7 @@ exit_mfg_deactivate: BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated", hdev->name); + btusb_check_bdaddr_intel(hdev); return 0; } -- cgit v1.2.3 From c8abb73fb82b30ee736ada0f1ae50c9b4382713e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 2 Jul 2014 12:38:22 +0200 Subject: Bluetooth: Check for default address of Broadcom BCM20702A0 controllers The Broadcom BCM20702A0 USB controllers might come with the default address 00:20:70:02:A0:00 when booting up. If this happens, then warn about such address being used. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 32aabea731f2..3244e311ca29 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1448,6 +1448,8 @@ static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) return 0; } +#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) + static int btusb_setup_bcm_patchram(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -1461,6 +1463,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) u16 opcode; struct sk_buff *skb; struct hci_rp_read_local_version *ver; + struct hci_rp_read_bd_addr *bda; long ret; snprintf(fw_name, sizeof(fw_name), "brcm/%s-%04x-%04x.hcd", @@ -1470,8 +1473,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) ret = request_firmware(&fw, fw_name, &hdev->dev); if (ret < 0) { - BT_INFO("%s: BCM: patch %s not found", hdev->name, - fw_name); + BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name); return 0; } @@ -1590,6 +1592,42 @@ reset_fw: ver->lmp_ver, ver->lmp_subver); kfree_skb(skb); + /* Read BD Address */ + skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: HCI_OP_READ_BD_ADDR failed (%ld)", + hdev->name, ret); + goto done; + } + + if (skb->len != sizeof(*bda)) { + BT_ERR("%s: HCI_OP_READ_BD_ADDR event length mismatch", + hdev->name); + kfree_skb(skb); + ret = -EIO; + goto done; + } + + bda = (struct hci_rp_read_bd_addr *) skb->data; + if (bda->status) { + BT_ERR("%s: HCI_OP_READ_BD_ADDR error status (%02x)", + hdev->name, bda->status); + kfree_skb(skb); + ret = -bt_to_errno(bda->status); + goto done; + } + + /* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller + * with no configured address. + */ + if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) + BT_INFO("%s: BCM: using default device address (%pMR)", + hdev->name, &bda->bdaddr); + + kfree_skb(skb); + done: release_firmware(fw); -- cgit v1.2.3 From af96324312ed5b3d095d54b6d56b93f693f54c9f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 16:45:39 +0300 Subject: Bluetooth: Fix sparse warning with btmrvl driver This patch fixes the following sparse warning caused by a missing declaration in the header file: drivers/bluetooth/btmrvl_main.c:218:5: warning: symbol 'btmrvl_pscan_window_reporting' was not declared. Should it be static? Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_drv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index a8a9d3380e59..caf684119a4e 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -145,6 +145,7 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd); +int btmrvl_pscan_window_reporting(struct btmrvl_private *priv, u8 subcmd); int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv); int btmrvl_enable_ps(struct btmrvl_private *priv); int btmrvl_prepare_command(struct btmrvl_private *priv); -- cgit v1.2.3 From 373110c5d30b0944b47cddbe586069b7457f8845 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 17:37:25 +0300 Subject: Bluetooth: Rename hci_conn_params_clear to hci_conn_params_clear_all We'll soon have specific clear functions for clearing enabled or disabled entries, so rename the function that removes everything to clear_all(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 4 ++-- net/bluetooth/mgmt.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ee480a86e558..091934bcfd84 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -861,7 +861,7 @@ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, u8 auto_connect); void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); -void hci_conn_params_clear(struct hci_dev *hdev); +void hci_conn_params_clear_all(struct hci_dev *hdev); struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 21a4c8dfb874..e6e169007fd2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3580,7 +3580,7 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) } /* This function requires the caller holds hdev->lock */ -void hci_conn_params_clear(struct hci_dev *hdev) +void hci_conn_params_clear_all(struct hci_dev *hdev) { struct hci_conn_params *params, *tmp; @@ -4038,7 +4038,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_smp_irks_clear(hdev); hci_remote_oob_data_clear(hdev); hci_white_list_clear(hdev); - hci_conn_params_clear(hdev); + hci_conn_params_clear_all(hdev); hci_dev_unlock(hdev); hci_dev_put(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 93cfefa260d5..29850e76ea3c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5104,7 +5104,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } - hci_conn_params_clear(hdev); + hci_conn_params_clear_all(hdev); } err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, -- cgit v1.2.3 From 55af49a8fe85278ea244e72d2d264cf5e0941c61 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 17:37:26 +0300 Subject: Bluetooth: Add specific connection parameter clear functions In some circumstances we'll need to either clear only the enabled parameters or only the disabled ones. This patch adds convenience functions for this purpose. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 091934bcfd84..2091e0013b8c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -862,6 +862,8 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, u8 auto_connect); void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_conn_params_clear_all(struct hci_dev *hdev); +void hci_conn_params_clear_disabled(struct hci_dev *hdev); +void hci_conn_params_clear_enabled(struct hci_dev *hdev); struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e6e169007fd2..7e46a7c6092f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3579,6 +3579,38 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) BT_DBG("addr %pMR (type %u)", addr, addr_type); } +/* This function requires the caller holds hdev->lock */ +void hci_conn_params_clear_disabled(struct hci_dev *hdev) +{ + struct hci_conn_params *params, *tmp; + + list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { + if (params->auto_connect != HCI_AUTO_CONN_DISABLED) + continue; + list_del(¶ms->list); + kfree(params); + } + + BT_DBG("All LE disabled connection parameters were removed"); +} + +/* This function requires the caller holds hdev->lock */ +void hci_conn_params_clear_enabled(struct hci_dev *hdev) +{ + struct hci_conn_params *params, *tmp; + + list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { + if (params->auto_connect == HCI_AUTO_CONN_DISABLED) + continue; + list_del(¶ms->list); + kfree(params); + } + + hci_pend_le_conns_clear(hdev); + + BT_DBG("All enabled LE connection parameters were removed"); +} + /* This function requires the caller holds hdev->lock */ void hci_conn_params_clear_all(struct hci_dev *hdev) { -- cgit v1.2.3 From a3451d279f839d987cbcf25b0f3be666aef99d0b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 17:37:27 +0300 Subject: Bluetooth: Add new auto_conn value matching mgmt action 0x00 The 0x00 action value of mgmt means "scan and report" but do not connect. This is different from HCI_AUTO_CONN_DISABLED so we need a new value for it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 1 + net/bluetooth/mgmt.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2091e0013b8c..f4a2f50f30b5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -449,6 +449,7 @@ struct hci_conn_params { enum { HCI_AUTO_CONN_DISABLED, + HCI_AUTO_CONN_REPORT, HCI_AUTO_CONN_ALWAYS, HCI_AUTO_CONN_LINK_LOSS, } auto_connect; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7e46a7c6092f..a3cd0bbd3518 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3547,6 +3547,7 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, switch (auto_connect) { case HCI_AUTO_CONN_DISABLED: + case HCI_AUTO_CONN_REPORT: case HCI_AUTO_CONN_LINK_LOSS: hci_pend_le_conn_del(hdev, addr, addr_type); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 29850e76ea3c..f7217f9eda03 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5034,7 +5034,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, if (cp->action) auto_conn = HCI_AUTO_CONN_ALWAYS; else - auto_conn = HCI_AUTO_CONN_DISABLED; + auto_conn = HCI_AUTO_CONN_REPORT; /* If the connection parameters don't exist for this device, * they will be created and configured with defaults. -- cgit v1.2.3 From c71593dd34ae1fd46777662a522a32cfde86f073 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 17:37:28 +0300 Subject: Bluetooth: Remove only enabled entries with Remove Device command The Remove Device mgmt command is supposed to undo what the Add Device command does. An entry added by Add Device cannot have the HCI_AUTO_CONN_DISABLED auto_connect value, so we should treat this as an invalid entry to remove. This patch adds the necessary pieces to the Remove Device command handler so that it only removes entries which were added by Add Device. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f7217f9eda03..574dd9f7c39e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5079,6 +5079,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, hci_dev_lock(hdev); if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) { + struct hci_conn_params *params; u8 addr_type; if (!bdaddr_type_is_le(cp->addr.type)) { @@ -5093,7 +5094,25 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, else addr_type = ADDR_LE_DEV_RANDOM; - hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type); + params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, + addr_type); + if (!params) { + err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); + goto unlock; + } + + if (params->auto_connect == HCI_AUTO_CONN_DISABLED) { + err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); + goto unlock; + } + + hci_pend_le_conn_del(hdev, &cp->addr.bdaddr, addr_type); + list_del(¶ms->list); + kfree(params); device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); } else { @@ -5104,7 +5123,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } - hci_conn_params_clear_all(hdev); + hci_conn_params_clear_enabled(hdev); } err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, -- cgit v1.2.3 From a26f3dcff2cf5890f33d883c98d90cdfa51ed460 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 17:37:29 +0300 Subject: Bluetooth: Add Load Connection Parameters command This patch implements the new Load Connection Parameters mgmt command that's intended to load the desired connection parameters for LE devices. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 15 +++++++++ net/bluetooth/mgmt.c | 79 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 3c0f29614d1b..5b3e8009eddd 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -449,6 +449,21 @@ struct mgmt_cp_remove_device { } __packed; #define MGMT_REMOVE_DEVICE_SIZE MGMT_ADDR_INFO_SIZE +struct mgmt_conn_param { + struct mgmt_addr_info addr; + __le16 min_interval; + __le16 max_interval; + __le16 latency; + __le16 timeout; +} __packed; + +#define MGMT_OP_LOAD_CONN_PARAM 0x0035 +struct mgmt_cp_load_conn_param { + __le16 param_count; + struct mgmt_conn_param params[0]; +} __packed; +#define MGMT_LOAD_CONN_PARAM_SIZE 2 + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 574dd9f7c39e..59bf1ac41429 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -88,6 +88,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_GET_CLOCK_INFO, MGMT_OP_ADD_DEVICE, MGMT_OP_REMOVE_DEVICE, + MGMT_OP_LOAD_CONN_PARAM, }; static const u16 mgmt_events[] = { @@ -5134,6 +5135,83 @@ unlock: return err; } +static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) +{ + struct mgmt_cp_load_conn_param *cp = data; + u16 param_count, expected_len; + int i; + + if (!lmp_le_capable(hdev)) + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, + MGMT_STATUS_NOT_SUPPORTED); + + param_count = __le16_to_cpu(cp->param_count); + + expected_len = sizeof(*cp) + param_count * + sizeof(struct mgmt_conn_param); + if (expected_len != len) { + BT_ERR("load_conn_param: expected %u bytes, got %u bytes", + expected_len, len); + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, + MGMT_STATUS_INVALID_PARAMS); + } + + BT_DBG("%s param_count %u", hdev->name, param_count); + + hci_dev_lock(hdev); + + hci_conn_params_clear_disabled(hdev); + + for (i = 0; i < param_count; i++) { + struct mgmt_conn_param *param = &cp->params[i]; + struct hci_conn_params *hci_param; + u16 min, max, latency, timeout; + u8 addr_type; + + BT_DBG("Adding %pMR (type %u)", ¶m->addr.bdaddr, + param->addr.type); + + if (param->addr.type == BDADDR_LE_PUBLIC) { + addr_type = ADDR_LE_DEV_PUBLIC; + } else if (param->addr.type == BDADDR_LE_RANDOM) { + addr_type = ADDR_LE_DEV_RANDOM; + } else { + BT_ERR("Ignoring invalid connection parameters"); + continue; + } + + min = le16_to_cpu(param->min_interval); + max = le16_to_cpu(param->max_interval); + latency = le16_to_cpu(param->latency); + timeout = le16_to_cpu(param->timeout); + + BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x", + min, max, latency, timeout); + + if (hci_check_conn_params(min, max, latency, timeout) < 0) { + BT_ERR("Ignoring invalid connection parameters"); + continue; + } + + hci_param = hci_conn_params_add(hdev, ¶m->addr.bdaddr, + addr_type); + if (!hci_param) { + BT_ERR("Failed to add connection parameters"); + continue; + } + + hci_param->conn_min_interval = min; + hci_param->conn_max_interval = max; + hci_param->conn_latency = latency; + hci_param->supervision_timeout = timeout; + } + + hci_dev_unlock(hdev); + + return cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0, NULL, 0); +} + static const struct mgmt_handler { int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len); @@ -5193,6 +5271,7 @@ static const struct mgmt_handler { { get_clock_info, false, MGMT_GET_CLOCK_INFO_SIZE }, { add_device, false, MGMT_ADD_DEVICE_SIZE }, { remove_device, false, MGMT_REMOVE_DEVICE_SIZE }, + { load_conn_param, true, MGMT_LOAD_CONN_PARAM_SIZE }, }; int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) -- cgit v1.2.3 From 348d50b8e96c2c4630801e6e720c7c722ade83e8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 17:37:30 +0300 Subject: Bluetooth: Fix missing update of conn params We should update any stored connection parameters when we receive the LE Remote Connection Parameter Request HCI event. This patch adds the necessary code to the function that handles the event. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ed49a065dd67..3ad2576fd3f1 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4429,9 +4429,25 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, return send_conn_param_neg_reply(hdev, handle, HCI_ERROR_INVALID_LL_PARAMS); - if (test_bit(HCI_CONN_MASTER, &hcon->flags)) + if (test_bit(HCI_CONN_MASTER, &hcon->flags)) { + struct hci_conn_params *params; + + hci_dev_lock(hdev); + + params = hci_conn_params_lookup(hdev, &hcon->dst, + hcon->dst_type); + if (params) { + params->conn_min_interval = min; + params->conn_max_interval = max; + params->conn_latency = latency; + params->supervision_timeout = timeout; + } + + hci_dev_unlock(hdev); + mgmt_new_conn_param(hdev, &hcon->dst, hcon->dst_type, min, max, latency, timeout); + } cp.handle = ev->handle; cp.interval_min = ev->interval_min; -- cgit v1.2.3 From 7d6ca6939cb2f701204317cbab15af1b98f7f501 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 17:37:31 +0300 Subject: Bluetooth: Make hci_le_conn_update return the store hint The caller of hci_le_conn_update is directly interested in knowing what the best value is for the store_hint parameter of the corresponding mgmt event. Since hci_le_conn_update knows whether there were stored parameters that were updated or not we can have it return an initial store_hint value to the caller. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 4 ++-- net/bluetooth/hci_conn.c | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f4a2f50f30b5..32c8e51f6b26 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1368,8 +1368,8 @@ struct hci_sec_filter { #define hci_req_lock(d) mutex_lock(&d->req_lock) #define hci_req_unlock(d) mutex_unlock(&d->req_lock) -void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, - u16 latency, u16 to_multiplier); +u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, + u16 to_multiplier); void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, __u8 ltk[16]); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index d00aaf976efc..0d579d036833 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -213,8 +213,8 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle) return true; } -void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, - u16 latency, u16 to_multiplier) +u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, + u16 to_multiplier) { struct hci_dev *hdev = conn->hdev; struct hci_conn_params *params; @@ -242,6 +242,11 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, cp.max_ce_len = cpu_to_le16(0x0000); hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp); + + if (params) + return 0x01; + + return 0x00; } void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, -- cgit v1.2.3 From f4869e2adb7ab9d09a9335b4e26a63ec413f2c6f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 17:37:32 +0300 Subject: Bluetooth: Pass store hint to mgmt_new_conn_param The calling functions of mgmt_new_conn_param have more information about the parameters, such as whether the kernel is tracking them or not. It makes therefore sense to have them pass an initial store_hint value to the mgmt_new_conn_param function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 4 ++-- net/bluetooth/hci_event.c | 8 ++++++-- net/bluetooth/l2cap_core.c | 8 ++++++-- net/bluetooth/mgmt.c | 6 +++--- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 32c8e51f6b26..d0bca13843ce 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1335,8 +1335,8 @@ void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk); void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk, bool persistent); void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 bdaddr_type, u16 min_interval, u16 max_interval, - u16 latency, u16 timeout); + u8 bdaddr_type, u8 store_hint, u16 min_interval, + u16 max_interval, u16 latency, u16 timeout); void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_smp_complete(struct hci_conn *conn, bool complete); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3ad2576fd3f1..846f6a6af881 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4431,6 +4431,7 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, if (test_bit(HCI_CONN_MASTER, &hcon->flags)) { struct hci_conn_params *params; + u8 store_hint; hci_dev_lock(hdev); @@ -4441,12 +4442,15 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, params->conn_max_interval = max; params->conn_latency = latency; params->supervision_timeout = timeout; + store_hint = 0x01; + } else{ + store_hint = 0x00; } hci_dev_unlock(hdev); - mgmt_new_conn_param(hdev, &hcon->dst, hcon->dst_type, min, max, - latency, timeout); + mgmt_new_conn_param(hdev, &hcon->dst, hcon->dst_type, + store_hint, min, max, latency, timeout); } cp.handle = ev->handle; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a6e276204ae9..dbef22d644e2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5250,10 +5250,14 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, sizeof(rsp), &rsp); if (!err) { + u8 store_hint; + + store_hint = hci_le_conn_update(hcon, min, max, latency, + to_multiplier); mgmt_new_conn_param(hcon->hdev, &hcon->dst, hcon->dst_type, - min, max, latency, to_multiplier); + store_hint, min, max, latency, + to_multiplier); - hci_le_conn_update(hcon, min, max, latency, to_multiplier); } return 0; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 59bf1ac41429..fb1aa0cac137 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5790,15 +5790,15 @@ void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk, } void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 bdaddr_type, u16 min_interval, u16 max_interval, - u16 latency, u16 timeout) + u8 bdaddr_type, u8 store_hint, u16 min_interval, + u16 max_interval, u16 latency, u16 timeout) { struct mgmt_ev_new_conn_param ev; memset(&ev, 0, sizeof(ev)); bacpy(&ev.addr.bdaddr, bdaddr); ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type); - ev.store_hint = 0x00; + ev.store_hint = store_hint; ev.min_interval = cpu_to_le16(min_interval); ev.max_interval = cpu_to_le16(max_interval); ev.latency = cpu_to_le16(latency); -- cgit v1.2.3 From c46245b3efce80884acf65c01443582aec1f31ed Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 17:37:33 +0300 Subject: Bluetooth: Make is_identity_address a global function There are more places that can take advantage of is_identity_address() besides hci_core.c. This patch moves the function to hci_core.h and gives it the appropriate hci_ prefix. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 12 ++++++++++++ net/bluetooth/hci_core.c | 14 +------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index d0bca13843ce..92f1bad6e22d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1179,6 +1179,18 @@ static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type) return false; } +static inline bool hci_is_identity_address(bdaddr_t *addr, u8 addr_type) +{ + if (addr_type == ADDR_LE_DEV_PUBLIC) + return true; + + /* Check for Random Static address type */ + if ((addr->b[5] & 0xc0) == 0xc0) + return true; + + return false; +} + static inline struct smp_irk *hci_get_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type) { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a3cd0bbd3518..1fff3d890f41 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3412,18 +3412,6 @@ static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type) return true; } -static bool is_identity_address(bdaddr_t *addr, u8 addr_type) -{ - if (addr_type == ADDR_LE_DEV_PUBLIC) - return true; - - /* Check for Random Static address type */ - if ((addr->b[5] & 0xc0) == 0xc0) - return true; - - return false; -} - /* This function requires the caller holds hdev->lock */ struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) @@ -3504,7 +3492,7 @@ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, { struct hci_conn_params *params; - if (!is_identity_address(addr, addr_type)) + if (!hci_is_identity_address(addr, addr_type)) return NULL; params = hci_conn_params_lookup(hdev, addr, addr_type); -- cgit v1.2.3 From c103aea6f709c68916160eca4ed20224934e62d7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 17:37:34 +0300 Subject: Bluetooth: Don't send connection parameters without identity address If we don't have an identity address for connection parameters it doesn't really make sense to send them to user space. Instead just ignore them for now. Later we can add support for sending them when we eventually get the identity through pairing. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fb1aa0cac137..50a0a3ec50b0 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5795,6 +5795,9 @@ void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr, { struct mgmt_ev_new_conn_param ev; + if (!hci_is_identity_address(bdaddr, bdaddr_type)) + return; + memset(&ev, 0, sizeof(ev)); bacpy(&ev.addr.bdaddr, bdaddr); ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type); -- cgit v1.2.3 From 4a964404c08fed64d1afd8b0af1e7f2b8f7ae90e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 2 Jul 2014 19:10:33 +0200 Subject: Bluetooth: Introduce unconfigured controller state With the new unconfigured controller state it is possible to provide a fully functional HCI transport, but disable the higher level operations that would normally happen. This way userspace can try to configure the controller before releases the unconfigured state. The internal state is represented by HCI_UNCONFIGURED. This replaces the HCI_QUIRK_RAW_DEVICE quirk as internal state representation. This is now a real state and drivers can use the quirk to actually trigger this state. In the future this will allow a more fine grained switching from unconfigured state to configured state for controller inititialization. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 43 ++++++++++++++++++++++++++----------------- net/bluetooth/hci_sock.c | 8 ++++---- net/bluetooth/mgmt.c | 6 +++--- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 66358af6b1fc..606a9b1466a3 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -127,6 +127,7 @@ enum { HCI_KEEP_DEBUG_KEYS, HCI_USE_DEBUG_KEYS, HCI_UNREGISTER, + HCI_UNCONFIGURED, HCI_USER_CHANNEL, HCI_LE_SCAN, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1fff3d890f41..395b014ad0e8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2116,7 +2116,7 @@ int hci_inquiry(void __user *arg) goto done; } - if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { err = -EOPNOTSUPP; goto done; } @@ -2261,7 +2261,7 @@ static int hci_dev_do_open(struct hci_dev *hdev) } if (!ret) { - if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks) && + if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) ret = __hci_init(hdev); } @@ -2274,6 +2274,7 @@ static int hci_dev_do_open(struct hci_dev *hdev) set_bit(HCI_UP, &hdev->flags); hci_notify(hdev, HCI_DEV_UP); if (!test_bit(HCI_SETUP, &hdev->dev_flags) && + !test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && hdev->dev_type == HCI_BREDR) { hci_dev_lock(hdev); @@ -2317,7 +2318,7 @@ int hci_dev_open(__u16 dev) if (!hdev) return -ENODEV; - /* Devices that are marked for raw-only usage can only be powered + /* Devices that are marked as unconfigured can only be powered * up as user channel. Trying to bring them up as normal devices * will result into a failure. Only user channel operation is * possible. @@ -2326,7 +2327,7 @@ int hci_dev_open(__u16 dev) * HCI_USER_CHANNEL will be set first before attempting to * open the device. */ - if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks) && + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { err = -EOPNOTSUPP; goto done; @@ -2401,8 +2402,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Reset device */ skb_queue_purge(&hdev->cmd_q); atomic_set(&hdev->cmd_cnt, 1); - if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks) && - !test_bit(HCI_AUTO_OFF, &hdev->dev_flags) && + if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags) && + !test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) { set_bit(HCI_INIT, &hdev->flags); __hci_req_sync(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT); @@ -2501,7 +2502,7 @@ int hci_dev_reset(__u16 dev) goto done; } - if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { ret = -EOPNOTSUPP; goto done; } @@ -2543,7 +2544,7 @@ int hci_dev_reset_stat(__u16 dev) goto done; } - if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { ret = -EOPNOTSUPP; goto done; } @@ -2573,7 +2574,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) goto done; } - if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { err = -EOPNOTSUPP; goto done; } @@ -2791,6 +2792,7 @@ static void hci_power_on(struct work_struct *work) * valid, it is important to turn the device back off. */ if (test_bit(HCI_RFKILLED, &hdev->dev_flags) || + test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) || (hdev->dev_type == HCI_BREDR && !bacmp(&hdev->bdaddr, BDADDR_ANY) && !bacmp(&hdev->static_addr, BDADDR_ANY))) { @@ -2802,7 +2804,15 @@ static void hci_power_on(struct work_struct *work) } if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) { - if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + /* For unconfigured devices, set the HCI_RAW flag + * so that userspace can easily identify them. + * + * If the device is fully configured and ready for + * operation, announce it via management interface. + */ + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) + set_bit(HCI_RAW, &hdev->flags); + else mgmt_index_added(hdev); } } @@ -3974,12 +3984,11 @@ int hci_register_dev(struct hci_dev *hdev) list_add(&hdev->list, &hci_dev_list); write_unlock(&hci_dev_list_lock); - /* Devices that are marked for raw-only usage need to set - * the HCI_RAW flag to indicate that only user channel is - * supported. + /* Devices that are marked for raw-only usage are unconfigured + * and should not be included in normal operation. */ if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) - set_bit(HCI_RAW, &hdev->flags); + set_bit(HCI_UNCONFIGURED, &hdev->dev_flags); hci_notify(hdev, HCI_DEV_REG); hci_dev_hold(hdev); @@ -4024,7 +4033,7 @@ void hci_unregister_dev(struct hci_dev *hdev) if (!test_bit(HCI_INIT, &hdev->flags) && !test_bit(HCI_SETUP, &hdev->dev_flags) && - !test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { + !test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { hci_dev_lock(hdev); mgmt_index_removed(hdev); hci_dev_unlock(hdev); @@ -4788,7 +4797,7 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) static void __check_timeout(struct hci_dev *hdev, unsigned int cnt) { - if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { + if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ if (!cnt && time_after(jiffies, hdev->acl_last_tx + @@ -4971,7 +4980,7 @@ static void hci_sched_le(struct hci_dev *hdev) if (!hci_conn_num(hdev, LE_LINK)) return; - if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { + if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { /* LE tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ if (!hdev->le_cnt && hdev->le_pkts && diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 54e4e8fd5d97..db9610323d4d 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -453,7 +453,7 @@ static int hci_sock_release(struct socket *sock) if (hdev) { if (hci_pi(sk)->channel == HCI_CHANNEL_USER) { - if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) mgmt_index_added(hdev); clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags); hci_dev_close(hdev->id); @@ -518,7 +518,7 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) return -EBUSY; - if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) return -EOPNOTSUPP; if (hdev->dev_type != HCI_BREDR) @@ -706,13 +706,13 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, goto done; } - if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) mgmt_index_removed(hdev); err = hci_dev_open(hdev->id); if (err) { clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags); - if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) mgmt_index_added(hdev); hci_dev_put(hdev); goto done; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 50a0a3ec50b0..1ab98980054c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -353,7 +353,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, if (test_bit(HCI_USER_CHANNEL, &d->dev_flags)) continue; - if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) + if (test_bit(HCI_UNCONFIGURED, &d->dev_flags)) continue; if (d->dev_type == HCI_BREDR) { @@ -5317,8 +5317,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) } if (test_bit(HCI_SETUP, &hdev->dev_flags) || - test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) || - test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) { + test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) || + test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { err = cmd_status(sk, index, opcode, MGMT_STATUS_INVALID_INDEX); goto done; -- cgit v1.2.3 From 0602a8adc3ce3f592d03df426c92d1f36229403c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 2 Jul 2014 21:30:54 +0200 Subject: Bluetooth: Add support for Unconfigured Index Added events When a controller is in unconfigured state it is currently hidden from the management interface. This change now announces the new controller with an Unconfigured Index Added event and allows clients to easily detect the controller. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 2 ++ net/bluetooth/hci_core.c | 17 ++++++++++------- net/bluetooth/hci_sock.c | 9 +++------ net/bluetooth/mgmt.c | 12 +++++++++++- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 5b3e8009eddd..7da29fd748d8 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -640,3 +640,5 @@ struct mgmt_ev_new_conn_param { __le16 latency; __le16 timeout; } __packed; + +#define MGMT_EV_UNCONF_INDEX_ADDED 0x001d diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 395b014ad0e8..df25a8329ecc 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2806,14 +2806,18 @@ static void hci_power_on(struct work_struct *work) if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) { /* For unconfigured devices, set the HCI_RAW flag * so that userspace can easily identify them. - * - * If the device is fully configured and ready for - * operation, announce it via management interface. */ if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) set_bit(HCI_RAW, &hdev->flags); - else - mgmt_index_added(hdev); + + /* For fully configured devices, this will send + * the Index Added event. For unconfigured devices, + * it will send Unconfigued Index Added event. + * + * Devices with HCI_QUIRK_RAW_DEVICE are ignored + * and no event will be send. + */ + mgmt_index_added(hdev); } } @@ -4032,8 +4036,7 @@ void hci_unregister_dev(struct hci_dev *hdev) cancel_work_sync(&hdev->power_on); if (!test_bit(HCI_INIT, &hdev->flags) && - !test_bit(HCI_SETUP, &hdev->dev_flags) && - !test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { + !test_bit(HCI_SETUP, &hdev->dev_flags)) { hci_dev_lock(hdev); mgmt_index_removed(hdev); hci_dev_unlock(hdev); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index db9610323d4d..ba13ad8e25c6 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -453,8 +453,7 @@ static int hci_sock_release(struct socket *sock) if (hdev) { if (hci_pi(sk)->channel == HCI_CHANNEL_USER) { - if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) - mgmt_index_added(hdev); + mgmt_index_added(hdev); clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags); hci_dev_close(hdev->id); } @@ -706,14 +705,12 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, goto done; } - if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) - mgmt_index_removed(hdev); + mgmt_index_removed(hdev); err = hci_dev_open(hdev->id); if (err) { clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags); - if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) - mgmt_index_added(hdev); + mgmt_index_added(hdev); hci_dev_put(hdev); goto done; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1ab98980054c..ab70d5858db9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -118,6 +118,7 @@ static const u16 mgmt_events[] = { MGMT_EV_DEVICE_ADDED, MGMT_EV_DEVICE_REMOVED, MGMT_EV_NEW_CONN_PARAM, + MGMT_EV_UNCONF_INDEX_ADDED, }; #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) @@ -5373,7 +5374,13 @@ void mgmt_index_added(struct hci_dev *hdev) if (hdev->dev_type != HCI_BREDR) return; - mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL); + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + return; + + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) + mgmt_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev, NULL, 0, NULL); + else + mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL); } void mgmt_index_removed(struct hci_dev *hdev) @@ -5383,6 +5390,9 @@ void mgmt_index_removed(struct hci_dev *hdev) if (hdev->dev_type != HCI_BREDR) return; + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + return; + mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL); -- cgit v1.2.3 From edd3896bc41059fc064c4ec76da004a57203d88e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 2 Jul 2014 21:30:55 +0200 Subject: Bluetooth: Add support for Unconfigured Index Removed events When a controller in an unconfigured state gets removed, then send Unconfigured Index Removed events. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 2 ++ net/bluetooth/mgmt.c | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 7da29fd748d8..651993213bd9 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -642,3 +642,5 @@ struct mgmt_ev_new_conn_param { } __packed; #define MGMT_EV_UNCONF_INDEX_ADDED 0x001d + +#define MGMT_EV_UNCONF_INDEX_REMOVED 0x001e diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ab70d5858db9..1a78d26b0049 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -119,6 +119,7 @@ static const u16 mgmt_events[] = { MGMT_EV_DEVICE_REMOVED, MGMT_EV_NEW_CONN_PARAM, MGMT_EV_UNCONF_INDEX_ADDED, + MGMT_EV_UNCONF_INDEX_REMOVED, }; #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) @@ -5395,7 +5396,10 @@ void mgmt_index_removed(struct hci_dev *hdev) mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); - mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL); + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) + mgmt_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, NULL); + else + mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL); } /* This function requires the caller holds hdev->lock */ -- cgit v1.2.3 From 73d1df2a7a1036a1f000e5f0ece6ade3e082b854 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 2 Jul 2014 22:10:52 +0200 Subject: Bluetooth: Add support for Read Unconfigured Index List command This command allows to get the list of currently known controller that are in unconfigured state. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 7 ++++ net/bluetooth/mgmt.c | 91 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 88 insertions(+), 10 deletions(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 651993213bd9..e0786cfa5490 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -464,6 +464,13 @@ struct mgmt_cp_load_conn_param { } __packed; #define MGMT_LOAD_CONN_PARAM_SIZE 2 +#define MGMT_OP_READ_UNCONF_INDEX_LIST 0x0036 +#define MGMT_READ_UNCONF_INDEX_LIST_SIZE 0 +struct mgmt_rp_read_unconf_index_list { + __le16 num_controllers; + __le16 index[0]; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1a78d26b0049..325bb8136d2c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -89,6 +89,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_ADD_DEVICE, MGMT_OP_REMOVE_DEVICE, MGMT_OP_LOAD_CONN_PARAM, + MGMT_OP_READ_UNCONF_INDEX_LIST, }; static const u16 mgmt_events[] = { @@ -336,7 +337,8 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, count = 0; list_for_each_entry(d, &hci_dev_list, list) { - if (d->dev_type == HCI_BREDR) + if (d->dev_type == HCI_BREDR && + !test_bit(HCI_UNCONFIGURED, &d->dev_flags)) count++; } @@ -349,16 +351,18 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, count = 0; list_for_each_entry(d, &hci_dev_list, list) { - if (test_bit(HCI_SETUP, &d->dev_flags)) + if (test_bit(HCI_SETUP, &d->dev_flags) || + test_bit(HCI_USER_CHANNEL, &d->dev_flags)) continue; - if (test_bit(HCI_USER_CHANNEL, &d->dev_flags)) - continue; - - if (test_bit(HCI_UNCONFIGURED, &d->dev_flags)) + /* Devices marked as raw-only are neither configured + * nor unconfigured controllers. + */ + if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) continue; - if (d->dev_type == HCI_BREDR) { + if (d->dev_type == HCI_BREDR && + !test_bit(HCI_UNCONFIGURED, &d->dev_flags)) { rp->index[count++] = cpu_to_le16(d->id); BT_DBG("Added hci%u", d->id); } @@ -377,6 +381,65 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, return err; } +static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) +{ + struct mgmt_rp_read_unconf_index_list *rp; + struct hci_dev *d; + size_t rp_len; + u16 count; + int err; + + BT_DBG("sock %p", sk); + + read_lock(&hci_dev_list_lock); + + count = 0; + list_for_each_entry(d, &hci_dev_list, list) { + if (d->dev_type == HCI_BREDR && + test_bit(HCI_UNCONFIGURED, &d->dev_flags)) + count++; + } + + rp_len = sizeof(*rp) + (2 * count); + rp = kmalloc(rp_len, GFP_ATOMIC); + if (!rp) { + read_unlock(&hci_dev_list_lock); + return -ENOMEM; + } + + count = 0; + list_for_each_entry(d, &hci_dev_list, list) { + if (test_bit(HCI_SETUP, &d->dev_flags) || + test_bit(HCI_USER_CHANNEL, &d->dev_flags)) + continue; + + /* Devices marked as raw-only are neither configured + * nor unconfigured controllers. + */ + if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) + continue; + + if (d->dev_type == HCI_BREDR && + test_bit(HCI_UNCONFIGURED, &d->dev_flags)) { + rp->index[count++] = cpu_to_le16(d->id); + BT_DBG("Added hci%u", d->id); + } + } + + rp->num_controllers = cpu_to_le16(count); + rp_len = sizeof(*rp) + (2 * count); + + read_unlock(&hci_dev_list_lock); + + err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_UNCONF_INDEX_LIST, + 0, rp, rp_len); + + kfree(rp); + + return err; +} + static u32 get_supported_settings(struct hci_dev *hdev) { u32 settings = 0; @@ -5273,7 +5336,8 @@ static const struct mgmt_handler { { get_clock_info, false, MGMT_GET_CLOCK_INFO_SIZE }, { add_device, false, MGMT_ADD_DEVICE_SIZE }, { remove_device, false, MGMT_REMOVE_DEVICE_SIZE }, - { load_conn_param, true, MGMT_LOAD_CONN_PARAM_SIZE }, + { load_conn_param, true, MGMT_LOAD_CONN_PARAM_SIZE }, + { read_unconf_index_list, false, MGMT_READ_UNCONF_INDEX_LIST_SIZE }, }; int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) @@ -5335,8 +5399,15 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) goto done; } - if ((hdev && opcode < MGMT_OP_READ_INFO) || - (!hdev && opcode >= MGMT_OP_READ_INFO)) { + if (hdev && (opcode <= MGMT_OP_READ_INDEX_LIST || + opcode == MGMT_OP_READ_UNCONF_INDEX_LIST)) { + err = cmd_status(sk, index, opcode, + MGMT_STATUS_INVALID_INDEX); + goto done; + } + + if (!hdev && (opcode > MGMT_OP_READ_INDEX_LIST && + opcode != MGMT_OP_READ_UNCONF_INDEX_LIST)) { err = cmd_status(sk, index, opcode, MGMT_STATUS_INVALID_INDEX); goto done; -- cgit v1.2.3 From 82a30cfcb85538b677817815939306d20d5b8e61 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 3 Jul 2014 01:35:10 +0200 Subject: Bluetooth: Support HCI_QUIRK_RAW_DEVICE for hci_vhci driver This adds support for configuring the hci_vhci virtual controllers as a raw-only device using HCI_QUIRK_RAW_DEVICE. This is useful for testing the kernel internal infrastructure. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_vhci.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index add1c6a72063..aa446c7eb7e5 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -40,7 +40,7 @@ #include #include -#define VERSION "1.4" +#define VERSION "1.5" static bool amp; @@ -95,10 +95,21 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) return 0; } -static int vhci_create_device(struct vhci_data *data, __u8 dev_type) +static int vhci_create_device(struct vhci_data *data, __u8 opcode) { struct hci_dev *hdev; struct sk_buff *skb; + __u8 dev_type; + + /* bits 0-1 are dev_type (BR/EDR or AMP) */ + dev_type = opcode & 0x03; + + if (dev_type != HCI_BREDR && dev_type != HCI_AMP) + return -EINVAL; + + /* bits 2-6 are reserved (must be zero) */ + if (opcode & 0x7c) + return -EINVAL; skb = bt_skb_alloc(4, GFP_KERNEL); if (!skb) @@ -121,6 +132,10 @@ static int vhci_create_device(struct vhci_data *data, __u8 dev_type) hdev->flush = vhci_flush; hdev->send = vhci_send_frame; + /* bit 7 is for raw device */ + if (opcode & 0x80) + set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); + if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); hci_free_dev(hdev); @@ -132,7 +147,7 @@ static int vhci_create_device(struct vhci_data *data, __u8 dev_type) bt_cb(skb)->pkt_type = HCI_VENDOR_PKT; *skb_put(skb, 1) = 0xff; - *skb_put(skb, 1) = dev_type; + *skb_put(skb, 1) = opcode; put_unaligned_le16(hdev->id, skb_put(skb, 2)); skb_queue_tail(&data->readq, skb); @@ -146,7 +161,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data, { size_t len = iov_length(iov, count); struct sk_buff *skb; - __u8 pkt_type, dev_type; + __u8 pkt_type, opcode; unsigned long i; int ret; @@ -190,7 +205,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data, cancel_delayed_work_sync(&data->open_timeout); - dev_type = *((__u8 *) skb->data); + opcode = *((__u8 *) skb->data); skb_pull(skb, 1); if (skb->len > 0) { @@ -200,10 +215,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data, kfree_skb(skb); - if (dev_type != HCI_BREDR && dev_type != HCI_AMP) - return -EINVAL; - - ret = vhci_create_device(data, dev_type); + ret = vhci_create_device(data, opcode); break; default: -- cgit v1.2.3 From 851efca8387e10a25ca259f7efcc47819b19bff9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 22:42:00 +0300 Subject: Bluetooth: Track number of added devices with HCI_AUTO_CONN_REPORT To be able to make the right choice of whether to start passive scanning or to send out a mgmt_device_found event we need to know if there are any devices in the le_conn_params list with the auto_connect value set to HCI_AUTO_CONN_REPORT. This patch adds a counter for this kind of devices. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 92f1bad6e22d..b5f4405b41c2 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -312,6 +312,7 @@ struct hci_dev { struct list_head le_white_list; struct list_head le_conn_params; struct list_head pend_le_conns; + unsigned int pend_le_reports; struct hci_dev_stats stat; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index df25a8329ecc..8e0061f72dd1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3545,20 +3545,28 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, if (!params) return -EIO; - params->auto_connect = auto_connect; + if (params->auto_connect == HCI_AUTO_CONN_REPORT && + auto_connect != HCI_AUTO_CONN_REPORT) + hdev->pend_le_reports--; switch (auto_connect) { case HCI_AUTO_CONN_DISABLED: - case HCI_AUTO_CONN_REPORT: case HCI_AUTO_CONN_LINK_LOSS: hci_pend_le_conn_del(hdev, addr, addr_type); break; + case HCI_AUTO_CONN_REPORT: + if (params->auto_connect != HCI_AUTO_CONN_REPORT) + hdev->pend_le_reports++; + hci_pend_le_conn_del(hdev, addr, addr_type); + break; case HCI_AUTO_CONN_ALWAYS: if (!is_connected(hdev, addr, addr_type)) hci_pend_le_conn_add(hdev, addr, addr_type); break; } + params->auto_connect = auto_connect; + BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type, auto_connect); @@ -3574,6 +3582,9 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) if (!params) return; + if (params->auto_connect == HCI_AUTO_CONN_REPORT) + hdev->pend_le_reports--; + hci_pend_le_conn_del(hdev, addr, addr_type); list_del(¶ms->list); @@ -3605,6 +3616,8 @@ void hci_conn_params_clear_enabled(struct hci_dev *hdev) list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { if (params->auto_connect == HCI_AUTO_CONN_DISABLED) continue; + if (params->auto_connect == HCI_AUTO_CONN_REPORT) + hdev->pend_le_reports--; list_del(¶ms->list); kfree(params); } -- cgit v1.2.3 From 75ce208cc44938195f57c55f81c8e4447dd492fb Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 22:42:01 +0300 Subject: Bluetooth: Allow mgmt_device_found events for kernel-side scanning When the kernel is doing LE scanning because of one or more devices added with action 0x00 through the Add Device command we do want to let mgmt_device_found() to proceed with sending an event. This kind of devices are tracked with hdev->pend_le_reports, so check this value before bailing out from the function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 325bb8136d2c..0a82f08cd191 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6472,8 +6472,16 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, struct smp_irk *irk; size_t ev_size; - if (!hci_discovery_active(hdev)) - return; + /* Don't send events for a non-kernel initiated discovery. With + * LE one exception is if we have pend_le_reports > 0 in which + * case we're doing passive scanning and want these events. + */ + if (!hci_discovery_active(hdev)) { + if (link_type == ACL_LINK) + return; + if (link_type == LE_LINK && !hdev->pend_le_reports) + return; + } /* Make sure that the buffer is big enough. The 5 extra bytes * are for the potential CoD field. -- cgit v1.2.3 From 0d2bf13462732d3b2e11d8efb0545c1ed272298b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 22:42:02 +0300 Subject: Bluetooth: Add support for background LE scanning If we have one or more devices with HCI_AUTO_CONN_REPORT we should do background scanning and emit mgmt_device_found events. This patch modifies the hci_update_background_scan() function to extend the conditions needed to trigger scanning, and adds the necessary code to process_adv_report() to emit mgmt_device_found events. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 7 ++++--- net/bluetooth/hci_event.c | 25 +++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8e0061f72dd1..41cc64429ea1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5380,9 +5380,10 @@ void hci_update_background_scan(struct hci_dev *hdev) hci_req_init(&req, hdev); - if (list_empty(&hdev->pend_le_conns)) { - /* If there is no pending LE connections, we should stop - * the background scanning. + if (list_empty(&hdev->pend_le_conns) && !hdev->pend_le_reports) { + /* If there is no pending LE connections or devices + * to be scanned for, we should stop the background + * scanning. */ /* If controller is not scanning we are done. */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 846f6a6af881..87a704bd7eb7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4225,11 +4225,32 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, bool match; u32 flags; - /* Passive scanning shouldn't trigger any device found events */ + /* Passive scanning shouldn't trigger any device found events, + * except for devices marked as CONN_REPORT for which we do send + * device found events. + */ if (hdev->le_scan_type == LE_SCAN_PASSIVE) { + struct hci_conn_params *param; + if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND) check_pending_le_conn(hdev, bdaddr, bdaddr_type); - return; + + if (!hdev->pend_le_reports) + return; + + if (type == LE_ADV_DIRECT_IND) + return; + + param = hci_conn_params_lookup(hdev, bdaddr, bdaddr_type); + if (!param || param->auto_connect != HCI_AUTO_CONN_REPORT) + return; + + if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND) + flags = MGMT_DEV_FOUND_NOT_CONNECTABLE; + else + flags = 0; + mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, + rssi, flags, data, len, NULL, 0); } /* When receiving non-connectable or scannable undirected -- cgit v1.2.3 From 079446c8a254d65da0378a45c2106dbf1ff6a769 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 2 Jul 2014 23:09:24 +0300 Subject: Bluetooth: Support scanning for devices using RPA When we're scanning for specific devices that use an RPA we need to convert the RPA to the identity address before looking up the entry in the connection parameters. This patch adds the necessary code to do this in the process_adv_report() function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 87a704bd7eb7..dd70e3a4fea5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4231,6 +4231,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, */ if (hdev->le_scan_type == LE_SCAN_PASSIVE) { struct hci_conn_params *param; + struct smp_irk *irk; if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND) check_pending_le_conn(hdev, bdaddr, bdaddr_type); @@ -4241,6 +4242,17 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, if (type == LE_ADV_DIRECT_IND) return; + /* Check if we need to convert to identity address */ + irk = hci_get_irk(hdev, bdaddr, bdaddr_type); + if (irk) { + bdaddr = &irk->bdaddr; + bdaddr_type = irk->addr_type; + } + + /* The conn params list only contains identity addresses */ + if (!hci_is_identity_address(bdaddr, bdaddr_type)) + return; + param = hci_conn_params_lookup(hdev, bdaddr, bdaddr_type); if (!param || param->auto_connect != HCI_AUTO_CONN_REPORT) return; -- cgit v1.2.3 From ba1d6936f6f83927f17a28ecc9cbb989fa0a7e34 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 3 Jul 2014 13:52:27 +0300 Subject: Bluetooth: Fix buffer overflow with variable length commands The handler for variable length commands were trying to calculate the expected length of the command based on the given parameter count, and then comparing that with the received data. However, the expected count was stored in a u16 which can easily overflow. With a carefully crafted command this can then be made to match the given data even though the parameter count is actually way too big, resulting in a buffer overflow when parsing the parameters. This patch fixes the issue by calculating a per-command maximum parameter count and returns INVALID_PARAMS if it is exceeded. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0a82f08cd191..c01cc5e37a6f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2468,6 +2468,8 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_cp_load_link_keys *cp = data; + const u16 max_key_count = ((U16_MAX - sizeof(*cp)) / + sizeof(struct mgmt_link_key_info)); u16 key_count, expected_len; bool changed; int i; @@ -2479,6 +2481,12 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, MGMT_STATUS_NOT_SUPPORTED); key_count = __le16_to_cpu(cp->key_count); + if (key_count > max_key_count) { + BT_ERR("load_link_keys: too big key_count value %u", + key_count); + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, + MGMT_STATUS_INVALID_PARAMS); + } expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_link_key_info); @@ -4568,6 +4576,8 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data, u16 len) { struct mgmt_cp_load_irks *cp = cp_data; + const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) / + sizeof(struct mgmt_irk_info)); u16 irk_count, expected_len; int i, err; @@ -4578,6 +4588,11 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data, MGMT_STATUS_NOT_SUPPORTED); irk_count = __le16_to_cpu(cp->irk_count); + if (irk_count > max_irk_count) { + BT_ERR("load_irks: too big irk_count value %u", irk_count); + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS, + MGMT_STATUS_INVALID_PARAMS); + } expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info); if (expected_len != len) { @@ -4647,6 +4662,8 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, void *cp_data, u16 len) { struct mgmt_cp_load_long_term_keys *cp = cp_data; + const u16 max_key_count = ((U16_MAX - sizeof(*cp)) / + sizeof(struct mgmt_ltk_info)); u16 key_count, expected_len; int i, err; @@ -4657,6 +4674,11 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, MGMT_STATUS_NOT_SUPPORTED); key_count = __le16_to_cpu(cp->key_count); + if (key_count > max_key_count) { + BT_ERR("load_ltks: too big key_count value %u", key_count); + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, + MGMT_STATUS_INVALID_PARAMS); + } expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_ltk_info); @@ -5204,6 +5226,8 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_cp_load_conn_param *cp = data; + const u16 max_param_count = ((U16_MAX - sizeof(*cp)) / + sizeof(struct mgmt_conn_param)); u16 param_count, expected_len; int i; @@ -5212,6 +5236,12 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data, MGMT_STATUS_NOT_SUPPORTED); param_count = __le16_to_cpu(cp->param_count); + if (param_count > max_param_count) { + BT_ERR("load_conn_param: too big param_count value %u", + param_count); + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, + MGMT_STATUS_INVALID_PARAMS); + } expected_len = sizeof(*cp) + param_count * sizeof(struct mgmt_conn_param); -- cgit v1.2.3 From 617ca1bf11de84c23d1c83724fa89cfdc83b023a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 3 Jul 2014 19:33:47 +0300 Subject: Bluetooth: Fix missing update of pend_le_reports When calling Remove Device for an entry using HCI_AUTO_CONN_REPORT we need to decrement the pend_le_reports value correspondingly. This patch fixes one such missing action in the Remove Device command handler. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c01cc5e37a6f..02a4d31fee30 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5198,6 +5198,9 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } + if (params->auto_connect == HCI_AUTO_CONN_REPORT) + hdev->pend_le_reports--; + hci_pend_le_conn_del(hdev, &cp->addr.bdaddr, addr_type); list_del(¶ms->list); kfree(params); -- cgit v1.2.3 From 435a13d839abe8c8b9ebe1be635d1ab8f7352f56 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 3 Jul 2014 19:33:48 +0300 Subject: Bluetooth: Remove redundant IRK lookup When processing passive scanning results we need the resolved identity address both in check_pending_le_conn() as well as later in process_adv_report(). Since process_adv_report() calls check_pending_le_conn() we can simply resolve the IRK earlier in the function and thereby eliminate a second lookup. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index dd70e3a4fea5..643c5a8d4050 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4186,16 +4186,6 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) { struct hci_conn *conn; - struct smp_irk *irk; - - /* If this is a resolvable address, we should resolve it and then - * update address and address type variables. - */ - irk = hci_get_irk(hdev, addr, addr_type); - if (irk) { - addr = &irk->bdaddr; - addr_type = irk->addr_type; - } if (!hci_pend_le_conn_lookup(hdev, addr, addr_type)) return; @@ -4233,6 +4223,13 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, struct hci_conn_params *param; struct smp_irk *irk; + /* Check if we need to convert to identity address */ + irk = hci_get_irk(hdev, bdaddr, bdaddr_type); + if (irk) { + bdaddr = &irk->bdaddr; + bdaddr_type = irk->addr_type; + } + if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND) check_pending_le_conn(hdev, bdaddr, bdaddr_type); @@ -4242,13 +4239,6 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, if (type == LE_ADV_DIRECT_IND) return; - /* Check if we need to convert to identity address */ - irk = hci_get_irk(hdev, bdaddr, bdaddr_type); - if (irk) { - bdaddr = &irk->bdaddr; - bdaddr_type = irk->addr_type; - } - /* The conn params list only contains identity addresses */ if (!hci_is_identity_address(bdaddr, bdaddr_type)) return; -- cgit v1.2.3 From 912b42ef05a1e9f72a82c21d678a29c5055045d5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 3 Jul 2014 19:33:49 +0300 Subject: Bluetooth: Use hci_conn_params in pend_le_conns Since the connection parameters are always a basis for adding entries to hdev->pend_le_conns (so far of type bdaddr_list) it's simpler and more efficient to have the parameters themselves be the entries in the pend_le_conns list. We do this by adding another list_head to the hci_conn_params struct. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 9 +++--- net/bluetooth/hci_core.c | 68 +++++++++++++--------------------------- net/bluetooth/hci_event.c | 7 +++-- net/bluetooth/mgmt.c | 4 +-- 4 files changed, 33 insertions(+), 55 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b5f4405b41c2..09f9fb85d8fd 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -439,6 +439,7 @@ struct hci_chan { struct hci_conn_params { struct list_head list; + struct list_head pend_le_conn; bdaddr_t addr; u8 addr_type; @@ -867,10 +868,10 @@ void hci_conn_params_clear_all(struct hci_dev *hdev); void hci_conn_params_clear_disabled(struct hci_dev *hdev); void hci_conn_params_clear_enabled(struct hci_dev *hdev); -struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev, - bdaddr_t *addr, u8 addr_type); -void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); -void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); +struct hci_conn_params *hci_pend_le_conn_lookup(struct hci_dev *hdev, + bdaddr_t *addr, u8 addr_type); +void hci_pend_le_conn_add(struct hci_dev *hdev, struct hci_conn_params *params); +void hci_pend_le_conn_del(struct hci_dev *hdev, struct hci_conn_params *params); void hci_pend_le_conns_clear(struct hci_dev *hdev); void hci_update_background_scan(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 41cc64429ea1..8882a6cd2876 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3427,73 +3427,46 @@ static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type) } /* This function requires the caller holds hdev->lock */ -struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev, - bdaddr_t *addr, u8 addr_type) +struct hci_conn_params *hci_pend_le_conn_lookup(struct hci_dev *hdev, + bdaddr_t *addr, u8 addr_type) { - struct bdaddr_list *entry; + struct hci_conn_params *param; - list_for_each_entry(entry, &hdev->pend_le_conns, list) { - if (bacmp(&entry->bdaddr, addr) == 0 && - entry->bdaddr_type == addr_type) - return entry; + list_for_each_entry(param, &hdev->pend_le_conns, pend_le_conn) { + if (bacmp(¶m->addr, addr) == 0 && + param->addr_type == addr_type) + return param; } return NULL; } /* This function requires the caller holds hdev->lock */ -void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) +void hci_pend_le_conn_add(struct hci_dev *hdev, struct hci_conn_params *params) { - struct bdaddr_list *entry; - - entry = hci_pend_le_conn_lookup(hdev, addr, addr_type); - if (entry) - goto done; - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) { - BT_ERR("Out of memory"); - return; - } + list_del_init(¶ms->pend_le_conn); + list_add(¶ms->pend_le_conn, &hdev->pend_le_conns); - bacpy(&entry->bdaddr, addr); - entry->bdaddr_type = addr_type; - - list_add(&entry->list, &hdev->pend_le_conns); - - BT_DBG("addr %pMR (type %u)", addr, addr_type); + BT_DBG("addr %pMR (type %u)", ¶ms->addr, params->addr_type); -done: hci_update_background_scan(hdev); } /* This function requires the caller holds hdev->lock */ -void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) +void hci_pend_le_conn_del(struct hci_dev *hdev, struct hci_conn_params *params) { - struct bdaddr_list *entry; - - entry = hci_pend_le_conn_lookup(hdev, addr, addr_type); - if (!entry) - goto done; - - list_del(&entry->list); - kfree(entry); + list_del_init(¶ms->pend_le_conn); - BT_DBG("addr %pMR (type %u)", addr, addr_type); + BT_DBG("addr %pMR (type %u)", ¶ms->addr, params->addr_type); -done: hci_update_background_scan(hdev); } /* This function requires the caller holds hdev->lock */ void hci_pend_le_conns_clear(struct hci_dev *hdev) { - struct bdaddr_list *entry, *tmp; - - list_for_each_entry_safe(entry, tmp, &hdev->pend_le_conns, list) { - list_del(&entry->list); - kfree(entry); - } + while (!list_empty(&hdev->pend_le_conns)) + list_del_init(hdev->pend_le_conns.next); BT_DBG("All LE pending connections cleared"); @@ -3523,6 +3496,7 @@ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, params->addr_type = addr_type; list_add(¶ms->list, &hdev->le_conn_params); + INIT_LIST_HEAD(¶ms->pend_le_conn); params->conn_min_interval = hdev->le_conn_min_interval; params->conn_max_interval = hdev->le_conn_max_interval; @@ -3552,16 +3526,16 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, switch (auto_connect) { case HCI_AUTO_CONN_DISABLED: case HCI_AUTO_CONN_LINK_LOSS: - hci_pend_le_conn_del(hdev, addr, addr_type); + hci_pend_le_conn_del(hdev, params); break; case HCI_AUTO_CONN_REPORT: if (params->auto_connect != HCI_AUTO_CONN_REPORT) hdev->pend_le_reports++; - hci_pend_le_conn_del(hdev, addr, addr_type); + hci_pend_le_conn_del(hdev, params); break; case HCI_AUTO_CONN_ALWAYS: if (!is_connected(hdev, addr, addr_type)) - hci_pend_le_conn_add(hdev, addr, addr_type); + hci_pend_le_conn_add(hdev, params); break; } @@ -3585,7 +3559,7 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) if (params->auto_connect == HCI_AUTO_CONN_REPORT) hdev->pend_le_reports--; - hci_pend_le_conn_del(hdev, addr, addr_type); + hci_pend_le_conn_del(hdev, params); list_del(¶ms->list); kfree(params); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 643c5a8d4050..4ebfcedd9ae7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2209,7 +2209,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) /* Fall through */ case HCI_AUTO_CONN_ALWAYS: - hci_pend_le_conn_add(hdev, &conn->dst, conn->dst_type); + hci_pend_le_conn_add(hdev, params); break; default: @@ -4036,6 +4036,7 @@ static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev, static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_le_conn_complete *ev = (void *) skb->data; + struct hci_conn_params *params; struct hci_conn *conn; struct smp_irk *irk; u8 addr_type; @@ -4152,7 +4153,9 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_proto_connect_cfm(conn, ev->status); - hci_pend_le_conn_del(hdev, &conn->dst, conn->dst_type); + params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); + if (params) + hci_pend_le_conn_del(hdev, params); unlock: hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 02a4d31fee30..59ca4057955c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5201,7 +5201,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, if (params->auto_connect == HCI_AUTO_CONN_REPORT) hdev->pend_le_reports--; - hci_pend_le_conn_del(hdev, &cp->addr.bdaddr, addr_type); + hci_pend_le_conn_del(hdev, params); list_del(¶ms->list); kfree(params); @@ -5514,7 +5514,7 @@ static void restart_le_auto_conns(struct hci_dev *hdev) list_for_each_entry(p, &hdev->le_conn_params, list) { if (p->auto_connect == HCI_AUTO_CONN_ALWAYS) { - hci_pend_le_conn_add(hdev, &p->addr, p->addr_type); + hci_pend_le_conn_add(hdev, p); added = true; } } -- cgit v1.2.3 From bb5ce4d018f896403d7a394ec56a550e7890b563 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 3 Jul 2014 19:33:50 +0300 Subject: Bluetooth: Remove unnecessary checks for auto-connected devices If a device is in the pend_le_conns list it cannot at the same time also have the need to be notified through mgmt_device_found. By making check_pending_le_conn return whether it found an entry or not we can avoid unnecessary checks in process_adv_report(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 4ebfcedd9ae7..e0b439d4f958 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4185,18 +4185,18 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, } /* This function requires the caller holds hdev->lock */ -static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, +static bool check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) { struct hci_conn *conn; if (!hci_pend_le_conn_lookup(hdev, addr, addr_type)) - return; + return false; conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, HCI_AT_NO_BONDING); if (!IS_ERR(conn)) - return; + return true; switch (PTR_ERR(conn)) { case -EBUSY: @@ -4209,6 +4209,8 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, default: BT_DBG("Failed to connect: err %ld", PTR_ERR(conn)); } + + return true; } static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, @@ -4233,8 +4235,10 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, bdaddr_type = irk->addr_type; } - if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND) - check_pending_le_conn(hdev, bdaddr, bdaddr_type); + if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND) { + if (check_pending_le_conn(hdev, bdaddr, bdaddr_type)) + return; + } if (!hdev->pend_le_reports) return; -- cgit v1.2.3 From 738f61859d08771e12b552d043b48c8fc13708d1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 3 Jul 2014 19:33:51 +0300 Subject: Bluetooth: Add identity address check in param lookup functions Since we only store entries with identity addresses in the le_conn_params and pend_le_conns lists we can avoid unnecessary lookups by checking for an identity address before diving into the lists themselves. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 8 ++++++++ net/bluetooth/hci_event.c | 4 ---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8882a6cd2876..750f969df8db 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3399,6 +3399,10 @@ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, { struct hci_conn_params *params; + /* The conn params list only contains identity addresses */ + if (!hci_is_identity_address(addr, addr_type)) + return NULL; + list_for_each_entry(params, &hdev->le_conn_params, list) { if (bacmp(¶ms->addr, addr) == 0 && params->addr_type == addr_type) { @@ -3432,6 +3436,10 @@ struct hci_conn_params *hci_pend_le_conn_lookup(struct hci_dev *hdev, { struct hci_conn_params *param; + /* The list only contains identity addresses */ + if (!hci_is_identity_address(addr, addr_type)) + return NULL; + list_for_each_entry(param, &hdev->pend_le_conns, pend_le_conn) { if (bacmp(¶m->addr, addr) == 0 && param->addr_type == addr_type) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e0b439d4f958..20317e516e74 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4246,10 +4246,6 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, if (type == LE_ADV_DIRECT_IND) return; - /* The conn params list only contains identity addresses */ - if (!hci_is_identity_address(bdaddr, bdaddr_type)) - return; - param = hci_conn_params_lookup(hdev, bdaddr, bdaddr_type); if (!param || param->auto_connect != HCI_AUTO_CONN_REPORT) return; -- cgit v1.2.3 From 9fc3bfb681bdf59999f56072fff4632a5abea897 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 00:46:56 +0200 Subject: Bluetooth: Add support for controller configuration info command The Read Controller Configuration Information command allows retrieving details about possible configurations option. The supported options are returned and also the missing options (if any). Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 11 +++++++++++ net/bluetooth/mgmt.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index e0786cfa5490..0579eb3952e3 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -97,6 +97,7 @@ struct mgmt_rp_read_index_list { #define MGMT_SETTING_SECURE_CONN 0x00000800 #define MGMT_SETTING_DEBUG_KEYS 0x00001000 #define MGMT_SETTING_PRIVACY 0x00002000 +#define MGMT_SETTING_CONFIGURATION 0x00004000 #define MGMT_OP_READ_INFO 0x0004 #define MGMT_READ_INFO_SIZE 0 @@ -471,6 +472,16 @@ struct mgmt_rp_read_unconf_index_list { __le16 index[0]; } __packed; +#define MGMT_OPTION_PUBLIC_ADDRESS 0x00000001 + +#define MGMT_OP_READ_CONFIG_INFO 0x0037 +#define MGMT_READ_CONFIG_INFO_SIZE 0 +struct mgmt_rp_read_config_info { + __le16 manufacturer; + __le32 supported_options; + __le32 missing_options; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 59ca4057955c..474b6dcdf665 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -90,6 +90,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_REMOVE_DEVICE, MGMT_OP_LOAD_CONN_PARAM, MGMT_OP_READ_UNCONF_INDEX_LIST, + MGMT_OP_READ_CONFIG_INFO, }; static const u16 mgmt_events[] = { @@ -440,6 +441,29 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, return err; } +static int read_config_info(struct sock *sk, struct hci_dev *hdev, + void *data, u16 data_len) +{ + struct mgmt_rp_read_config_info rp; + + BT_DBG("sock %p %s", sk, hdev->name); + + hci_dev_lock(hdev); + + memset(&rp, 0, sizeof(rp)); + rp.manufacturer = cpu_to_le16(hdev->manufacturer); + if (hdev->set_bdaddr) + rp.supported_options = cpu_to_le32(MGMT_OPTION_PUBLIC_ADDRESS); + else + rp.supported_options = cpu_to_le32(0); + rp.missing_options = cpu_to_le32(0); + + hci_dev_unlock(hdev); + + return cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0, &rp, + sizeof(rp)); +} + static u32 get_supported_settings(struct hci_dev *hdev) { u32 settings = 0; @@ -472,6 +496,9 @@ static u32 get_supported_settings(struct hci_dev *hdev) settings |= MGMT_SETTING_PRIVACY; } + if (hdev->set_bdaddr) + settings |= MGMT_SETTING_CONFIGURATION; + return settings; } @@ -5371,6 +5398,7 @@ static const struct mgmt_handler { { remove_device, false, MGMT_REMOVE_DEVICE_SIZE }, { load_conn_param, true, MGMT_LOAD_CONN_PARAM_SIZE }, { read_unconf_index_list, false, MGMT_READ_UNCONF_INDEX_LIST_SIZE }, + { read_config_info, false, MGMT_READ_CONFIG_INFO_SIZE }, }; int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) -- cgit v1.2.3 From 97bf2e99934bdfd3f91914e6c935271b62567470 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 12:37:16 +0300 Subject: Bluetooth: Fix missing return statement in process_adv_report If we're doing passive scanning we shouldn't proceed with any of the code that deals with active scanning (pending reports, etc.). This patch fixes a missing return statement for the passive scanning section in the process_adv_report() function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 20317e516e74..e0407e674061 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4256,6 +4256,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, flags = 0; mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL, rssi, flags, data, len, NULL, 0); + return; } /* When receiving non-connectable or scannable undirected -- cgit v1.2.3 From 93450c75448e370659ce7ca9c192298596fb055e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 12:37:17 +0300 Subject: Bluetooth: Convert pend_le_conn list to a generic action list In preparation to store also HCI_AUTO_CONN_REPORT entries in a list it makes sense to convert the existing pend_le_conn list head of hci_conn_params into a more generically named "action". This makes sense because a parameter entry will never participate in more than one action list. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 09f9fb85d8fd..3b1143caa380 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -439,7 +439,7 @@ struct hci_chan { struct hci_conn_params { struct list_head list; - struct list_head pend_le_conn; + struct list_head action; bdaddr_t addr; u8 addr_type; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 750f969df8db..fed2a0648d3d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3440,7 +3440,7 @@ struct hci_conn_params *hci_pend_le_conn_lookup(struct hci_dev *hdev, if (!hci_is_identity_address(addr, addr_type)) return NULL; - list_for_each_entry(param, &hdev->pend_le_conns, pend_le_conn) { + list_for_each_entry(param, &hdev->pend_le_conns, action) { if (bacmp(¶m->addr, addr) == 0 && param->addr_type == addr_type) return param; @@ -3452,8 +3452,8 @@ struct hci_conn_params *hci_pend_le_conn_lookup(struct hci_dev *hdev, /* This function requires the caller holds hdev->lock */ void hci_pend_le_conn_add(struct hci_dev *hdev, struct hci_conn_params *params) { - list_del_init(¶ms->pend_le_conn); - list_add(¶ms->pend_le_conn, &hdev->pend_le_conns); + list_del_init(¶ms->action); + list_add(¶ms->action, &hdev->pend_le_conns); BT_DBG("addr %pMR (type %u)", ¶ms->addr, params->addr_type); @@ -3463,7 +3463,7 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, struct hci_conn_params *params) /* This function requires the caller holds hdev->lock */ void hci_pend_le_conn_del(struct hci_dev *hdev, struct hci_conn_params *params) { - list_del_init(¶ms->pend_le_conn); + list_del_init(¶ms->action); BT_DBG("addr %pMR (type %u)", ¶ms->addr, params->addr_type); @@ -3504,7 +3504,7 @@ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, params->addr_type = addr_type; list_add(¶ms->list, &hdev->le_conn_params); - INIT_LIST_HEAD(¶ms->pend_le_conn); + INIT_LIST_HEAD(¶ms->action); params->conn_min_interval = hdev->le_conn_min_interval; params->conn_max_interval = hdev->le_conn_max_interval; -- cgit v1.2.3 From 66f8455aeac3427110d451534567eb1b9aea6929 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 12:37:18 +0300 Subject: Bluetooth: Convert pend_le_reports into a list To simplify manipulation and lookup of hci_conn_params entries of the type HCI_AUTO_CONN_REPORT it makes sense to store them in their own list. The new action list_head in hci_conn_params is used for this purpose. Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 17 +++++++++++------ net/bluetooth/hci_event.c | 2 +- net/bluetooth/mgmt.c | 4 ++-- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3b1143caa380..9670f4c66ee3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -312,7 +312,7 @@ struct hci_dev { struct list_head le_white_list; struct list_head le_conn_params; struct list_head pend_le_conns; - unsigned int pend_le_reports; + struct list_head pend_le_reports; struct hci_dev_stats stat; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fed2a0648d3d..296f44748636 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3529,7 +3529,7 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, if (params->auto_connect == HCI_AUTO_CONN_REPORT && auto_connect != HCI_AUTO_CONN_REPORT) - hdev->pend_le_reports--; + list_del_init(¶ms->action); switch (auto_connect) { case HCI_AUTO_CONN_DISABLED: @@ -3537,8 +3537,11 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, hci_pend_le_conn_del(hdev, params); break; case HCI_AUTO_CONN_REPORT: - if (params->auto_connect != HCI_AUTO_CONN_REPORT) - hdev->pend_le_reports++; + if (params->auto_connect != HCI_AUTO_CONN_REPORT) { + list_del_init(¶ms->action); + list_add(¶ms->action, + &hdev->pend_le_reports); + } hci_pend_le_conn_del(hdev, params); break; case HCI_AUTO_CONN_ALWAYS: @@ -3565,7 +3568,7 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) return; if (params->auto_connect == HCI_AUTO_CONN_REPORT) - hdev->pend_le_reports--; + list_del_init(¶ms->action); hci_pend_le_conn_del(hdev, params); @@ -3599,7 +3602,7 @@ void hci_conn_params_clear_enabled(struct hci_dev *hdev) if (params->auto_connect == HCI_AUTO_CONN_DISABLED) continue; if (params->auto_connect == HCI_AUTO_CONN_REPORT) - hdev->pend_le_reports--; + list_del_init(¶ms->action); list_del(¶ms->list); kfree(params); } @@ -3859,6 +3862,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->le_white_list); INIT_LIST_HEAD(&hdev->le_conn_params); INIT_LIST_HEAD(&hdev->pend_le_conns); + INIT_LIST_HEAD(&hdev->pend_le_reports); INIT_LIST_HEAD(&hdev->conn_hash.list); INIT_WORK(&hdev->rx_work, hci_rx_work); @@ -5362,7 +5366,8 @@ void hci_update_background_scan(struct hci_dev *hdev) hci_req_init(&req, hdev); - if (list_empty(&hdev->pend_le_conns) && !hdev->pend_le_reports) { + if (list_empty(&hdev->pend_le_conns) && + list_empty(&hdev->pend_le_reports)) { /* If there is no pending LE connections or devices * to be scanned for, we should stop the background * scanning. diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e0407e674061..2a2ef698e851 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4240,7 +4240,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, return; } - if (!hdev->pend_le_reports) + if (list_empty(&hdev->pend_le_reports)) return; if (type == LE_ADV_DIRECT_IND) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 474b6dcdf665..a823cccf81f1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5226,7 +5226,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, } if (params->auto_connect == HCI_AUTO_CONN_REPORT) - hdev->pend_le_reports--; + list_del_init(¶ms->action); hci_pend_le_conn_del(hdev, params); list_del(¶ms->list); @@ -6540,7 +6540,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, if (!hci_discovery_active(hdev)) { if (link_type == ACL_LINK) return; - if (link_type == LE_LINK && !hdev->pend_le_reports) + if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports)) return; } -- cgit v1.2.3 From a2f41a8f370a940629a0e42258ab9e941b1dbc83 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 12:37:19 +0300 Subject: Bluetooth: Simplify use of hci_pend_le_conns_clear() Now that pend_le_connections is a list of hci_conn_params entries we can simply remove items from that list as we iterate through the global list of le_conn_params. This also moves the responsibility of calling hci_update_background_scan() to the functions that were previously calling hci_pend_le_conns_clear(). The only user that's left for hci_pend_le_conns_clear() is hci_dev_do_close() which anyway does not need to call hci_update_background_scan(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 296f44748636..dd8aa5f86810 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3477,8 +3477,6 @@ void hci_pend_le_conns_clear(struct hci_dev *hdev) list_del_init(hdev->pend_le_conns.next); BT_DBG("All LE pending connections cleared"); - - hci_update_background_scan(hdev); } /* This function requires the caller holds hdev->lock */ @@ -3601,13 +3599,12 @@ void hci_conn_params_clear_enabled(struct hci_dev *hdev) list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { if (params->auto_connect == HCI_AUTO_CONN_DISABLED) continue; - if (params->auto_connect == HCI_AUTO_CONN_REPORT) - list_del_init(¶ms->action); + list_del(¶ms->action); list_del(¶ms->list); kfree(params); } - hci_pend_le_conns_clear(hdev); + hci_update_background_scan(hdev); BT_DBG("All enabled LE connection parameters were removed"); } @@ -3618,11 +3615,12 @@ void hci_conn_params_clear_all(struct hci_dev *hdev) struct hci_conn_params *params, *tmp; list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { + list_del(¶ms->action); list_del(¶ms->list); kfree(params); } - hci_pend_le_conns_clear(hdev); + hci_update_background_scan(hdev); BT_DBG("All LE connection parameters were removed"); } -- cgit v1.2.3 From 42ce26de67e13c50885e7856ff91aaeedf07a81b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 12:37:20 +0300 Subject: Bluetooth: Don't bother doing anything if auto_connect doesn't change When hci_conn_params_set() is called if the new auto_connect value is the same as the old one we don't need to take any action. Simply return success from the function in this case. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index dd8aa5f86810..0601fcbd21eb 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3525,6 +3525,9 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, if (!params) return -EIO; + if (params->auto_connect == auto_connect) + return 0; + if (params->auto_connect == HCI_AUTO_CONN_REPORT && auto_connect != HCI_AUTO_CONN_REPORT) list_del_init(¶ms->action); -- cgit v1.2.3 From 95305baa779223060c7129100424da6c0d01045b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 12:37:21 +0300 Subject: Bluetooth: Simplify hci_conn_params->action list usage Since params->action is used for both the pend_le_conns and pend_le_reports lists we can simplify the adding and deleting of the lists considerably. For example, when deleting entries in most situations we no-longer need to check the auto_connect value but can directly proceed with calling list_del_init on param->action (which is safe even if the entry is not part of any list). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 28 +++++++++++----------------- net/bluetooth/hci_event.c | 6 ++++-- net/bluetooth/mgmt.c | 6 ++---- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 0601fcbd21eb..3b0da6eeb449 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3528,26 +3528,22 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, if (params->auto_connect == auto_connect) return 0; - if (params->auto_connect == HCI_AUTO_CONN_REPORT && - auto_connect != HCI_AUTO_CONN_REPORT) - list_del_init(¶ms->action); + list_del_init(¶ms->action); switch (auto_connect) { case HCI_AUTO_CONN_DISABLED: case HCI_AUTO_CONN_LINK_LOSS: - hci_pend_le_conn_del(hdev, params); + hci_update_background_scan(hdev); break; case HCI_AUTO_CONN_REPORT: - if (params->auto_connect != HCI_AUTO_CONN_REPORT) { - list_del_init(¶ms->action); - list_add(¶ms->action, - &hdev->pend_le_reports); - } - hci_pend_le_conn_del(hdev, params); + list_add(¶ms->action, &hdev->pend_le_reports); + hci_update_background_scan(hdev); break; case HCI_AUTO_CONN_ALWAYS: - if (!is_connected(hdev, addr, addr_type)) - hci_pend_le_conn_add(hdev, params); + if (!is_connected(hdev, addr, addr_type)) { + list_add(¶ms->action, &hdev->pend_le_conns); + hci_update_background_scan(hdev); + } break; } @@ -3568,14 +3564,12 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) if (!params) return; - if (params->auto_connect == HCI_AUTO_CONN_REPORT) - list_del_init(¶ms->action); - - hci_pend_le_conn_del(hdev, params); - + list_del(¶ms->action); list_del(¶ms->list); kfree(params); + hci_update_background_scan(hdev); + BT_DBG("addr %pMR (type %u)", addr, addr_type); } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 2a2ef698e851..0ccdf9df2188 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4154,8 +4154,10 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_proto_connect_cfm(conn, ev->status); params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); - if (params) - hci_pend_le_conn_del(hdev, params); + if (params) { + list_del_init(¶ms->action); + hci_update_background_scan(hdev); + } unlock: hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a823cccf81f1..77c64b8cb7e2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5225,12 +5225,10 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } - if (params->auto_connect == HCI_AUTO_CONN_REPORT) - list_del_init(¶ms->action); - - hci_pend_le_conn_del(hdev, params); + list_del_init(¶ms->action); list_del(¶ms->list); kfree(params); + hci_update_background_scan(hdev); device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); } else { -- cgit v1.2.3 From ae44e5d19e870385d1e73ce248c19ea4761bb40c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 12:37:22 +0300 Subject: Bluetooth: Remove unused hci_pend_le_conn_del() function Now that there are no-longer any users of the hci_pend_le_conn_del() function we can simply go ahead and remove it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_core.c | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9670f4c66ee3..758146c513d3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -871,7 +871,6 @@ void hci_conn_params_clear_enabled(struct hci_dev *hdev); struct hci_conn_params *hci_pend_le_conn_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_pend_le_conn_add(struct hci_dev *hdev, struct hci_conn_params *params); -void hci_pend_le_conn_del(struct hci_dev *hdev, struct hci_conn_params *params); void hci_pend_le_conns_clear(struct hci_dev *hdev); void hci_update_background_scan(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3b0da6eeb449..6eadde820333 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3460,16 +3460,6 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, struct hci_conn_params *params) hci_update_background_scan(hdev); } -/* This function requires the caller holds hdev->lock */ -void hci_pend_le_conn_del(struct hci_dev *hdev, struct hci_conn_params *params) -{ - list_del_init(¶ms->action); - - BT_DBG("addr %pMR (type %u)", ¶ms->addr, params->addr_type); - - hci_update_background_scan(hdev); -} - /* This function requires the caller holds hdev->lock */ void hci_pend_le_conns_clear(struct hci_dev *hdev) { -- cgit v1.2.3 From d7347f3cc2b63be0ea35b3239faf4b32fde2fb44 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 12:37:23 +0300 Subject: Bluetooth: Fix clearing and restarting all LE actions on power cycle When powering off (hci_dev_do_close) we should clear both the pend_le_reports and pend_le_conns types of entries. When powering on respectively we should populate both lists. This patch converts the hci_pend_le_conns_clear() function into hci_pend_le_actions_clear() (which can now be static) and converts the restart_le_auto_conns() function into restart_le_actions(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_core.c | 23 ++++++++++++----------- net/bluetooth/mgmt.c | 33 ++++++++++++++++----------------- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 758146c513d3..9208b18cb1e9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -871,7 +871,6 @@ void hci_conn_params_clear_enabled(struct hci_dev *hdev); struct hci_conn_params *hci_pend_le_conn_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_pend_le_conn_add(struct hci_dev *hdev, struct hci_conn_params *params); -void hci_pend_le_conns_clear(struct hci_dev *hdev); void hci_update_background_scan(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6eadde820333..3a1a25dcb2bc 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2354,6 +2354,17 @@ done: return err; } +/* This function requires the caller holds hdev->lock */ +static void hci_pend_le_actions_clear(struct hci_dev *hdev) +{ + struct hci_conn_params *p; + + list_for_each_entry(p, &hdev->le_conn_params, list) + list_del_init(&p->action); + + BT_DBG("All LE pending actions cleared"); +} + static int hci_dev_do_close(struct hci_dev *hdev) { BT_DBG("%s %p", hdev->name, hdev); @@ -2391,7 +2402,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) hci_dev_lock(hdev); hci_inquiry_cache_flush(hdev); hci_conn_hash_flush(hdev); - hci_pend_le_conns_clear(hdev); + hci_pend_le_actions_clear(hdev); hci_dev_unlock(hdev); hci_notify(hdev, HCI_DEV_DOWN); @@ -3460,16 +3471,6 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, struct hci_conn_params *params) hci_update_background_scan(hdev); } -/* This function requires the caller holds hdev->lock */ -void hci_pend_le_conns_clear(struct hci_dev *hdev) -{ - while (!list_empty(&hdev->pend_le_conns)) - list_del_init(hdev->pend_le_conns.next); - - BT_DBG("All LE pending connections cleared"); -} - -/* This function requires the caller holds hdev->lock */ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 77c64b8cb7e2..f1672b15c0f3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5533,29 +5533,28 @@ void mgmt_index_removed(struct hci_dev *hdev) } /* This function requires the caller holds hdev->lock */ -static void restart_le_auto_conns(struct hci_dev *hdev) +static void restart_le_actions(struct hci_dev *hdev) { struct hci_conn_params *p; - bool added = false; list_for_each_entry(p, &hdev->le_conn_params, list) { - if (p->auto_connect == HCI_AUTO_CONN_ALWAYS) { - hci_pend_le_conn_add(hdev, p); - added = true; + /* Needed for AUTO_OFF case where might not "really" + * have been powered off. + */ + list_del_init(&p->action); + + switch (p->auto_connect) { + case HCI_AUTO_CONN_ALWAYS: + list_add(&p->action, &hdev->pend_le_conns); + break; + case HCI_AUTO_CONN_REPORT: + list_add(&p->action, &hdev->pend_le_reports); + break; + default: + break; } } - /* Calling hci_pend_le_conn_add will actually already trigger - * background scanning when needed. So no need to trigger it - * just another time. - * - * This check is here to avoid an unneeded restart of the - * passive scanning. Since this is during the controller - * power up phase the duplicate filtering is not an issue. - */ - if (added) - return; - hci_update_background_scan(hdev); } @@ -5567,7 +5566,7 @@ static void powered_complete(struct hci_dev *hdev, u8 status) hci_dev_lock(hdev); - restart_le_auto_conns(hdev); + restart_le_actions(hdev); mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); -- cgit v1.2.3 From 418025d1c390b3979f0fd3bb639f0a15026d0530 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 12:37:24 +0300 Subject: Bluetooth: Remove unnecessary usage of hci_pend_le_conn_add This is the last place using hci_pend_le_conn_add() and we can more just as simply manipulate the list directly here. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0ccdf9df2188..9e0b2e888bba 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2209,7 +2209,9 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) /* Fall through */ case HCI_AUTO_CONN_ALWAYS: - hci_pend_le_conn_add(hdev, params); + list_del_init(¶ms->action); + list_add(¶ms->action, &hdev->pend_le_conns); + hci_update_background_scan(hdev); break; default: -- cgit v1.2.3 From d9b3ad7df101a6490272771f1aabbaa623a196f3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 12:37:25 +0300 Subject: Bluetooth: Remove unused hci_pend_le_conn_add function Since there are no more users of this function we can simply go ahead and remove it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_core.c | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9208b18cb1e9..c2bc9180cb79 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -870,7 +870,6 @@ void hci_conn_params_clear_enabled(struct hci_dev *hdev); struct hci_conn_params *hci_pend_le_conn_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); -void hci_pend_le_conn_add(struct hci_dev *hdev, struct hci_conn_params *params); void hci_update_background_scan(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3a1a25dcb2bc..38a0c5cd0ee4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3461,16 +3461,6 @@ struct hci_conn_params *hci_pend_le_conn_lookup(struct hci_dev *hdev, } /* This function requires the caller holds hdev->lock */ -void hci_pend_le_conn_add(struct hci_dev *hdev, struct hci_conn_params *params) -{ - list_del_init(¶ms->action); - list_add(¶ms->action, &hdev->pend_le_conns); - - BT_DBG("addr %pMR (type %u)", ¶ms->addr, params->addr_type); - - hci_update_background_scan(hdev); -} - struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) { -- cgit v1.2.3 From 501f882741b139da22bb3ba4bc615a6eadce5038 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 12:37:26 +0300 Subject: Bluetooth: Make hci_pend_le_conn_lookup more general purposed In some circumstances we need to look up entries in pend_le_conns and in other in pend_le_reports. This patch converts the existing lookup function for pend_le_conns to something that can be used for both lists. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 5 +++-- net/bluetooth/hci_core.c | 6 +++--- net/bluetooth/hci_event.c | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c2bc9180cb79..1cae4d3a629d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -868,8 +868,9 @@ void hci_conn_params_clear_all(struct hci_dev *hdev); void hci_conn_params_clear_disabled(struct hci_dev *hdev); void hci_conn_params_clear_enabled(struct hci_dev *hdev); -struct hci_conn_params *hci_pend_le_conn_lookup(struct hci_dev *hdev, - bdaddr_t *addr, u8 addr_type); +struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list, + bdaddr_t *addr, + u8 addr_type); void hci_update_background_scan(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 38a0c5cd0ee4..038b4748375b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3442,8 +3442,8 @@ static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type) } /* This function requires the caller holds hdev->lock */ -struct hci_conn_params *hci_pend_le_conn_lookup(struct hci_dev *hdev, - bdaddr_t *addr, u8 addr_type) +struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list, + bdaddr_t *addr, u8 addr_type) { struct hci_conn_params *param; @@ -3451,7 +3451,7 @@ struct hci_conn_params *hci_pend_le_conn_lookup(struct hci_dev *hdev, if (!hci_is_identity_address(addr, addr_type)) return NULL; - list_for_each_entry(param, &hdev->pend_le_conns, action) { + list_for_each_entry(param, list, action) { if (bacmp(¶m->addr, addr) == 0 && param->addr_type == addr_type) return param; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9e0b2e888bba..9274cd228995 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4194,7 +4194,7 @@ static bool check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, { struct hci_conn *conn; - if (!hci_pend_le_conn_lookup(hdev, addr, addr_type)) + if (!hci_pend_le_action_lookup(&hdev->pend_le_conns, addr, addr_type)) return false; conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, -- cgit v1.2.3 From a7545f2afcfc49fd5341fe51e943064eefe20ea1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 12:37:27 +0300 Subject: Bluetooth: Use hci_pend_le_action_lookup to look up report entries Instead of looking through the entire list of entries we can more efficiently use the new hci_pend_le_action_lookup() function to look up entries specifically in the pend_le_reports list. Since the search is now limited to the right list we can also remove an unnecessary check for list_empty() before the lookup. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9274cd228995..c380545f1e92 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4244,14 +4244,12 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, return; } - if (list_empty(&hdev->pend_le_reports)) - return; - if (type == LE_ADV_DIRECT_IND) return; - param = hci_conn_params_lookup(hdev, bdaddr, bdaddr_type); - if (!param || param->auto_connect != HCI_AUTO_CONN_REPORT) + param = hci_pend_le_action_lookup(&hdev->pend_le_reports, + bdaddr, bdaddr_type); + if (!param) return; if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND) -- cgit v1.2.3 From 46ebeb26cd976b9902d074c9a51f091a5744f9f3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 13:23:38 +0200 Subject: Bluetooth: Fix constant for public address configuration The public address configuration option is value 0x02 since the generic external configuration is value 0x01. So adjust this accordingly and also add the value 0x01 to the list. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 0579eb3952e3..3984678ffab1 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -472,7 +472,8 @@ struct mgmt_rp_read_unconf_index_list { __le16 index[0]; } __packed; -#define MGMT_OPTION_PUBLIC_ADDRESS 0x00000001 +#define MGMT_OPTION_EXTERNAL_CONFIG 0x00000001 +#define MGMT_OPTION_PUBLIC_ADDRESS 0x00000002 #define MGMT_OP_READ_CONFIG_INFO 0x0037 #define MGMT_READ_CONFIG_INFO_SIZE 0 -- cgit v1.2.3 From 99a6768e0e55d19a47934ccd653ff0f9b3236401 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 16:15:49 +0300 Subject: Bluetooth: Don't take actions on blocked devices when scanning If a found device is marked as blocked while doing passive LE scanning, neither report it nor try to connect to it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c380545f1e92..27c1d2edeebe 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4239,6 +4239,10 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, bdaddr_type = irk->addr_type; } + /* Ignore if the device is blocked */ + if (hci_blacklist_lookup(hdev, bdaddr, bdaddr_type)) + return; + if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND) { if (check_pending_le_conn(hdev, bdaddr, bdaddr_type)) return; -- cgit v1.2.3 From d1dbf12e3be0befcd3fd1f978202c5f72d2cc67b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 4 Jul 2014 16:17:23 +0300 Subject: Bluetooth: Use list_del when freeing the list entry It's wasteful to use list_del_init (which re-initializes the list_head) if we're just about to free the element and never use it again. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f1672b15c0f3..90eabcae3ed2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5225,7 +5225,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } - list_del_init(¶ms->action); + list_del(¶ms->action); list_del(¶ms->list); kfree(params); hci_update_background_scan(hdev); -- cgit v1.2.3 From 118305b50a73b46ff6c1c0453d7ae642b26dff82 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 16:08:02 +0200 Subject: Bluetooth: Document the existing device quirks The current existing device quirks are not documented. So instead of spreading bits and pieces somewhere in the code, add proper comments on where these quirks can be used and what behavior they change. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 606a9b1466a3..744713cd5335 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -81,9 +81,34 @@ /* HCI device quirks */ enum { + /* When this quirk is set, the HCI Reset command is send when + * closing the transport instead of when opening it. + * + * This quirk must be set before hci_register_dev is called. + */ HCI_QUIRK_RESET_ON_CLOSE, + + /* When this quirk is set, the device is turned into a raw-only + * device and it will stay in unconfigured state. + * + * This quirk must be set before hci_register_dev is called. + */ HCI_QUIRK_RAW_DEVICE, + + /* When this quirk is set, the buffer sizes reported by + * HCI Read Buffer Size command are corrected if invalid. + * + * This quirk must be set before hci_register_dev is called. + */ HCI_QUIRK_FIXUP_BUFFER_SIZE, + + /* When this quirk is set, then no stored link key handling + * is performed. This is mainly due to the fact that the + * HCI Delete Stored Link Key command is advertised, but + * not supported. + * + * This quirk must be set before hci_register_dev is called. + */ HCI_QUIRK_BROKEN_STORED_LINK_KEY, }; -- cgit v1.2.3 From 89bc22d23f63c2d437f677d7eae0fa922bedcdcb Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 16:54:37 +0200 Subject: Bluetooth: Add quirk for invalid controller address setting When a Bluetooth controller does not have a valid public Bluetooth address, then allow the driver to indicate this. If the quirk is set, the Bluetooth core will switch to unconfigured state first and will allow userspace to configure the address before starting the full initialization of the controller. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 10 ++++++++++ net/bluetooth/hci_core.c | 6 +++++- net/bluetooth/mgmt.c | 21 +++++++++++++++++---- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 744713cd5335..148b21699446 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -110,6 +110,16 @@ enum { * This quirk must be set before hci_register_dev is called. */ HCI_QUIRK_BROKEN_STORED_LINK_KEY, + + /* When this quirk is set, the public Bluetooth address + * initially reported by HCI Read BD Address command + * is considered invalid. Controller configuration is + * required before this device can be used. + * + * This quirk can be set before hci_register_dev is called or + * during the hdev->setup vendor callback. + */ + HCI_QUIRK_INVALID_BDADDR, }; /* HCI device flags */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 038b4748375b..c92bee84413f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2246,9 +2246,13 @@ static int hci_dev_do_open(struct hci_dev *hdev) atomic_set(&hdev->cmd_cnt, 1); set_bit(HCI_INIT, &hdev->flags); - if (hdev->setup && test_bit(HCI_SETUP, &hdev->dev_flags)) + if (hdev->setup && test_bit(HCI_SETUP, &hdev->dev_flags)) { ret = hdev->setup(hdev); + if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks)) + set_bit(HCI_UNCONFIGURED, &hdev->dev_flags); + } + /* If public address change is configured, ensure that the * address gets programmed. If the driver does not support * changing the public address, fail the power on procedure. diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 90eabcae3ed2..c7e5d4651021 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -441,10 +441,22 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, return err; } +static __le32 get_missing_options(struct hci_dev *hdev) +{ + u32 options = 0; + + if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) && + !bacmp(&hdev->public_addr, BDADDR_ANY)) + options |= MGMT_OPTION_PUBLIC_ADDRESS; + + return cpu_to_le32(options); +} + static int read_config_info(struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len) { struct mgmt_rp_read_config_info rp; + u32 options = 0; BT_DBG("sock %p %s", sk, hdev->name); @@ -452,11 +464,12 @@ static int read_config_info(struct sock *sk, struct hci_dev *hdev, memset(&rp, 0, sizeof(rp)); rp.manufacturer = cpu_to_le16(hdev->manufacturer); + if (hdev->set_bdaddr) - rp.supported_options = cpu_to_le32(MGMT_OPTION_PUBLIC_ADDRESS); - else - rp.supported_options = cpu_to_le32(0); - rp.missing_options = cpu_to_le32(0); + options |= MGMT_OPTION_PUBLIC_ADDRESS; + + rp.supported_options = cpu_to_le32(options); + rp.missing_options = get_missing_options(hdev); hci_dev_unlock(hdev); -- cgit v1.2.3 From 4739b5b185aad15b5c52c39e789ff582ec20796b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 16:54:38 +0200 Subject: Bluetooth: Set HCI_QUIRK_INVALID_BADDR for Intel USB default address When the Intel USB controller has a default address, then set the quirk so the Bluetooth core knows that controller configuration is required. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 3244e311ca29..825f3e16651f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1216,9 +1216,11 @@ static int btusb_check_bdaddr_intel(struct hci_dev *hdev) * fully operational, but have the danger of duplicate addresses * and that in turn can cause problems with Bluetooth operation. */ - if (!bacmp(&rp->bdaddr, BDADDR_INTEL)) + if (!bacmp(&rp->bdaddr, BDADDR_INTEL)) { BT_ERR("%s found Intel default device address (%pMR)", hdev->name, &rp->bdaddr); + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + } kfree_skb(skb); -- cgit v1.2.3 From 849e5086b9080d2408fd6223d27548032083b9e8 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 16:54:39 +0200 Subject: Bluetooth: Set HCI_QUIRK_INVALID_BADDR for BCM20702A0 default address When the Broadcom USB controller has a default address, then set the quirk so the Bluetooth core knows that controller configuration is required. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 825f3e16651f..61d8385666e9 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1624,9 +1624,11 @@ reset_fw: /* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller * with no configured address. */ - if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) + if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) { BT_INFO("%s: BCM: using default device address (%pMR)", hdev->name, &bda->bdaddr); + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + } kfree_skb(skb); -- cgit v1.2.3 From 42a9bc148960b2c85f9ec5ef1abe3a87e0155c60 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 16:54:40 +0200 Subject: Bluetooth: Allow reading configuration info when unconfigured Reading the controller configuration information is a valid management command when the controller is unconfigured. Allow this command, but return invalid index on all other commands. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c7e5d4651021..766411e11ac7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5455,12 +5455,18 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) } if (test_bit(HCI_SETUP, &hdev->dev_flags) || - test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) || test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { err = cmd_status(sk, index, opcode, MGMT_STATUS_INVALID_INDEX); goto done; } + + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && + opcode != MGMT_OP_READ_CONFIG_INFO) { + err = cmd_status(sk, index, opcode, + MGMT_STATUS_INVALID_INDEX); + goto done; + } } if (opcode >= ARRAY_SIZE(mgmt_handlers) || -- cgit v1.2.3 From eb1904f49d3e11468997e0667e6ec332a66697c9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 17:23:33 +0200 Subject: Bluetooth: Add quirk for external configuration requirement When a controller requires external configuration, then setting this quirk will allow indicating this. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 9 +++++++++ net/bluetooth/hci_core.c | 3 ++- net/bluetooth/mgmt.c | 9 ++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 148b21699446..4f1c4c7e2f00 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -111,6 +111,15 @@ enum { */ HCI_QUIRK_BROKEN_STORED_LINK_KEY, + /* When this quirk is set, an external configuration step + * is required and will be indicated with the controller + * configuation. + * + * This quirk can be set before hci_register_dev is called or + * during the hdev->setup vendor callback. + */ + HCI_QUIRK_EXTERNAL_CONFIG, + /* When this quirk is set, the public Bluetooth address * initially reported by HCI Read BD Address command * is considered invalid. Controller configuration is diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c92bee84413f..c007b3543e70 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2249,7 +2249,8 @@ static int hci_dev_do_open(struct hci_dev *hdev) if (hdev->setup && test_bit(HCI_SETUP, &hdev->dev_flags)) { ret = hdev->setup(hdev); - if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks)) + if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) || + test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks)) set_bit(HCI_UNCONFIGURED, &hdev->dev_flags); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 766411e11ac7..d2d0e051e4f2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -445,6 +445,9 @@ static __le32 get_missing_options(struct hci_dev *hdev) { u32 options = 0; + if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks)) + options |= MGMT_OPTION_EXTERNAL_CONFIG; + if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) && !bacmp(&hdev->public_addr, BDADDR_ANY)) options |= MGMT_OPTION_PUBLIC_ADDRESS; @@ -465,6 +468,9 @@ static int read_config_info(struct sock *sk, struct hci_dev *hdev, memset(&rp, 0, sizeof(rp)); rp.manufacturer = cpu_to_le16(hdev->manufacturer); + if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks)) + options |= MGMT_OPTION_EXTERNAL_CONFIG; + if (hdev->set_bdaddr) options |= MGMT_OPTION_PUBLIC_ADDRESS; @@ -509,7 +515,8 @@ static u32 get_supported_settings(struct hci_dev *hdev) settings |= MGMT_SETTING_PRIVACY; } - if (hdev->set_bdaddr) + if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) || + hdev->set_bdaddr) settings |= MGMT_SETTING_CONFIGURATION; return settings; -- cgit v1.2.3 From af202f84415a69b964a9ec371e11781f2a1e5396 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 17:23:34 +0200 Subject: Bluetooth: Fix quirks that are valid during setup driver callback For the quirks that are allow to be set during setup callback, the check needs to be modified so that they are applied even if no setup callback provided by the driver. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c007b3543e70..b29f3938e6b3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2246,9 +2246,16 @@ static int hci_dev_do_open(struct hci_dev *hdev) atomic_set(&hdev->cmd_cnt, 1); set_bit(HCI_INIT, &hdev->flags); - if (hdev->setup && test_bit(HCI_SETUP, &hdev->dev_flags)) { - ret = hdev->setup(hdev); + if (test_bit(HCI_SETUP, &hdev->dev_flags)) { + if (hdev->setup) + ret = hdev->setup(hdev); + /* The transport driver can set these quirks before + * creating the HCI device or in its setup callback. + * + * In case any of them is set, the controller has to + * start up as unconfigured. + */ if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) || test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks)) set_bit(HCI_UNCONFIGURED, &hdev->dev_flags); -- cgit v1.2.3 From 0ad184ef5828542e3e73cce8a875fb4e029725b7 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 17:23:35 +0200 Subject: Bluetooth: Support HCI_QUIRK_EXTERNAL_CONFIG for hci_vhci driver This adds support for configuring the hci_vhci virtual controllers to require a setup stage using HCI_QUIRK_EXTERNAL_CONFIG. With this option the virtual controller will start out as unconfigured. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_vhci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index aa446c7eb7e5..5bb5872ffee6 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -107,8 +107,8 @@ static int vhci_create_device(struct vhci_data *data, __u8 opcode) if (dev_type != HCI_BREDR && dev_type != HCI_AMP) return -EINVAL; - /* bits 2-6 are reserved (must be zero) */ - if (opcode & 0x7c) + /* bits 2-5 are reserved (must be zero) */ + if (opcode & 0x3c) return -EINVAL; skb = bt_skb_alloc(4, GFP_KERNEL); @@ -132,6 +132,10 @@ static int vhci_create_device(struct vhci_data *data, __u8 opcode) hdev->flush = vhci_flush; hdev->send = vhci_send_frame; + /* bit 6 is for external configuration */ + if (opcode & 0x40) + set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks); + /* bit 7 is for raw device */ if (opcode & 0x80) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); -- cgit v1.2.3 From dbece37a3233933ec89f77f04049e13ad9b29634 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 18:11:55 +0200 Subject: Bluetooth: Add support for Set External Configuration management command The Set External Configuration management command allows for switching between configured and unconfigured start if HCI_QURIK_EXTERNAL_CONFIG is set by the transport driver. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/mgmt.h | 6 ++++ net/bluetooth/mgmt.c | 77 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 4f1c4c7e2f00..80c5fc947fbc 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -173,6 +173,7 @@ enum { HCI_UNREGISTER, HCI_UNCONFIGURED, HCI_USER_CHANNEL, + HCI_EXT_CONFIGURED, HCI_LE_SCAN, HCI_SSP_ENABLED, diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 3984678ffab1..c7d537f1bd19 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -483,6 +483,12 @@ struct mgmt_rp_read_config_info { __le32 missing_options; } __packed; +#define MGMT_OP_SET_EXTERNAL_CONFIG 0x0038 +struct mgmt_cp_set_external_config { + __u8 config; +} __packed; +#define MGMT_SET_EXTERNAL_CONFIG_SIZE 1 + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d2d0e051e4f2..91bccef63f30 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -91,6 +91,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_LOAD_CONN_PARAM, MGMT_OP_READ_UNCONF_INDEX_LIST, MGMT_OP_READ_CONFIG_INFO, + MGMT_OP_SET_EXTERNAL_CONFIG, }; static const u16 mgmt_events[] = { @@ -441,11 +442,25 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, return err; } +static bool is_configured(struct hci_dev *hdev) +{ + if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) && + !test_bit(HCI_EXT_CONFIGURED, &hdev->dev_flags)) + return false; + + if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) && + !bacmp(&hdev->public_addr, BDADDR_ANY)) + return false; + + return true; +} + static __le32 get_missing_options(struct hci_dev *hdev) { u32 options = 0; - if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks)) + if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) && + !test_bit(HCI_EXT_CONFIGURED, &hdev->dev_flags)) options |= MGMT_OPTION_EXTERNAL_CONFIG; if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) && @@ -455,6 +470,14 @@ static __le32 get_missing_options(struct hci_dev *hdev) return cpu_to_le32(options); } +static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) +{ + __le32 options = get_missing_options(hdev); + + return cmd_complete(sk, hdev->id, opcode, 0, &options, + sizeof(options)); +} + static int read_config_info(struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len) { @@ -5355,6 +5378,54 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data, return cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0, NULL, 0); } +static int set_external_config(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_set_external_config *cp = data; + bool changed; + int err; + + BT_DBG("%s", hdev->name); + + if (hdev_is_powered(hdev)) + return cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG, + MGMT_STATUS_REJECTED); + + if (cp->config != 0x00 && cp->config != 0x01) + return cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG, + MGMT_STATUS_INVALID_PARAMS); + + if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks)) + return cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG, + MGMT_STATUS_NOT_SUPPORTED); + + hci_dev_lock(hdev); + + if (cp->config) + changed = !test_and_set_bit(HCI_EXT_CONFIGURED, + &hdev->dev_flags); + else + changed = test_and_clear_bit(HCI_EXT_CONFIGURED, + &hdev->dev_flags); + + err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev); + if (err < 0) + goto unlock; + + if (!changed) + goto unlock; + + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) == is_configured(hdev)) { + mgmt_index_removed(hdev); + change_bit(HCI_UNCONFIGURED, &hdev->dev_flags); + mgmt_index_added(hdev); + } + +unlock: + hci_dev_unlock(hdev); + return err; +} + static const struct mgmt_handler { int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len); @@ -5417,6 +5488,7 @@ static const struct mgmt_handler { { load_conn_param, true, MGMT_LOAD_CONN_PARAM_SIZE }, { read_unconf_index_list, false, MGMT_READ_UNCONF_INDEX_LIST_SIZE }, { read_config_info, false, MGMT_READ_CONFIG_INFO_SIZE }, + { set_external_config, false, MGMT_SET_EXTERNAL_CONFIG_SIZE }, }; int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) @@ -5469,7 +5541,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) } if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && - opcode != MGMT_OP_READ_CONFIG_INFO) { + opcode != MGMT_OP_READ_CONFIG_INFO && + opcode != MGMT_OP_SET_EXTERNAL_CONFIG) { err = cmd_status(sk, index, opcode, MGMT_STATUS_INVALID_INDEX); goto done; -- cgit v1.2.3 From 04c60f05a08aeb5ed412b08da037ed86419344a9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 19:06:22 +0200 Subject: Bluetooth: Move mgmt_event helper function to different location Move the mgmt_event function higher up in the code so that no forward declaration is needed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 60 ++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 91bccef63f30..4ef73523d95b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -212,6 +212,36 @@ static u8 mgmt_status(u8 hci_status) return MGMT_STATUS_FAILED; } +static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len, + struct sock *skip_sk) +{ + struct sk_buff *skb; + struct mgmt_hdr *hdr; + + skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + hdr = (void *) skb_put(skb, sizeof(*hdr)); + hdr->opcode = cpu_to_le16(event); + if (hdev) + hdr->index = cpu_to_le16(hdev->id); + else + hdr->index = cpu_to_le16(MGMT_INDEX_NONE); + hdr->len = cpu_to_le16(data_len); + + if (data) + memcpy(skb_put(skb, data_len), data, data_len); + + /* Time stamp */ + __net_timestamp(skb); + + hci_send_to_control(skb, skip_sk); + kfree_skb(skb); + + return 0; +} + static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) { struct sk_buff *skb; @@ -1364,36 +1394,6 @@ failed: return err; } -static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len, - struct sock *skip_sk) -{ - struct sk_buff *skb; - struct mgmt_hdr *hdr; - - skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL); - if (!skb) - return -ENOMEM; - - hdr = (void *) skb_put(skb, sizeof(*hdr)); - hdr->opcode = cpu_to_le16(event); - if (hdev) - hdr->index = cpu_to_le16(hdev->id); - else - hdr->index = cpu_to_le16(MGMT_INDEX_NONE); - hdr->len = cpu_to_le16(data_len); - - if (data) - memcpy(skb_put(skb, data_len), data, data_len); - - /* Time stamp */ - __net_timestamp(skb); - - hci_send_to_control(skb, skip_sk); - kfree_skb(skb); - - return 0; -} - static int new_settings(struct hci_dev *hdev, struct sock *skip) { __le32 ev; -- cgit v1.2.3 From f4537c04d387eda86ed89e0eafe0352f7fa0c9d0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 4 Jul 2014 19:06:23 +0200 Subject: Bluetooth: Add support for New Configuration Options management event When one or more of the missing configuration options change, then send this even to all the other management interface clients. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 2 ++ net/bluetooth/mgmt.c | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index c7d537f1bd19..80606d2fe086 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -669,3 +669,5 @@ struct mgmt_ev_new_conn_param { #define MGMT_EV_UNCONF_INDEX_ADDED 0x001d #define MGMT_EV_UNCONF_INDEX_REMOVED 0x001e + +#define MGMT_EV_NEW_CONFIG_OPTIONS 0x001f diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4ef73523d95b..f514eb15e0fb 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -123,6 +123,7 @@ static const u16 mgmt_events[] = { MGMT_EV_NEW_CONN_PARAM, MGMT_EV_UNCONF_INDEX_ADDED, MGMT_EV_UNCONF_INDEX_REMOVED, + MGMT_EV_NEW_CONFIG_OPTIONS, }; #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) @@ -500,6 +501,14 @@ static __le32 get_missing_options(struct hci_dev *hdev) return cpu_to_le32(options); } +static int new_options(struct hci_dev *hdev, struct sock *skip) +{ + __le32 options = get_missing_options(hdev); + + return mgmt_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options, + sizeof(options), skip); +} + static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) { __le32 options = get_missing_options(hdev); @@ -5415,6 +5424,8 @@ static int set_external_config(struct sock *sk, struct hci_dev *hdev, if (!changed) goto unlock; + err = new_options(hdev, sk); + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) == is_configured(hdev)) { mgmt_index_removed(hdev); change_bit(HCI_UNCONFIGURED, &hdev->dev_flags); -- cgit v1.2.3 From 45296acd91b14d32d7d023a08baaf285a0ea2193 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 5 Jul 2014 10:48:01 +0200 Subject: Bluetooth: Use a more simpler style for HCI event callbacks The HCI event callbacks have grown over the last years and some functions handle status checking different than others. For the simple ones, check the status at the beginning and exit if an error with the HCI command occured. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 142 ++++++++++++++++++++++++++++------------------ 1 file changed, 88 insertions(+), 54 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 27c1d2edeebe..013c371d3c87 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -175,12 +175,14 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, status); + if (status) + return; + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY); if (!sent) return; - if (!status) - hdev->link_policy = get_unaligned_le16(sent); + hdev->link_policy = get_unaligned_le16(sent); } static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) @@ -270,27 +272,30 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); + __u8 param; void *sent; BT_DBG("%s status 0x%2.2x", hdev->name, status); + if (status) + return; + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE); if (!sent) return; - if (!status) { - __u8 param = *((__u8 *) sent); + param = *((__u8 *) sent); - if (param) - set_bit(HCI_ENCRYPT, &hdev->flags); - else - clear_bit(HCI_ENCRYPT, &hdev->flags); - } + if (param) + set_bit(HCI_ENCRYPT, &hdev->flags); + else + clear_bit(HCI_ENCRYPT, &hdev->flags); } static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) { - __u8 param, status = *((__u8 *) skb->data); + __u8 status = *((__u8 *) skb->data); + __u8 param; int old_pscan, old_iscan; void *sent; @@ -602,8 +607,10 @@ static void hci_cc_read_flow_control_mode(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - if (!rp->status) - hdev->flow_ctl_mode = rp->mode; + if (rp->status) + return; + + hdev->flow_ctl_mode = rp->mode; } static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) @@ -649,7 +656,10 @@ static void hci_cc_read_page_scan_activity(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - if (test_bit(HCI_INIT, &hdev->flags) && !rp->status) { + if (rp->status) + return; + + if (test_bit(HCI_INIT, &hdev->flags)) { hdev->page_scan_interval = __le16_to_cpu(rp->interval); hdev->page_scan_window = __le16_to_cpu(rp->window); } @@ -681,7 +691,10 @@ static void hci_cc_read_page_scan_type(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - if (test_bit(HCI_INIT, &hdev->flags) && !rp->status) + if (rp->status) + return; + + if (test_bit(HCI_INIT, &hdev->flags)) hdev->page_scan_type = rp->type; } @@ -825,8 +838,10 @@ static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - if (!rp->status) - hdev->inq_tx_power = rp->tx_power; + if (rp->status) + return; + + hdev->inq_tx_power = rp->tx_power; } static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb) @@ -897,8 +912,10 @@ static void hci_cc_le_read_local_features(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - if (!rp->status) - memcpy(hdev->le_features, rp->features, 8); + if (rp->status) + return; + + memcpy(hdev->le_features, rp->features, 8); } static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, @@ -908,8 +925,10 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - if (!rp->status) - hdev->adv_tx_power = rp->tx_power; + if (rp->status) + return; + + hdev->adv_tx_power = rp->tx_power; } static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) @@ -1009,14 +1028,16 @@ static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%2.2x", hdev->name, status); + if (status) + return; + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_RANDOM_ADDR); if (!sent) return; hci_dev_lock(hdev); - if (!status) - bacpy(&hdev->random_addr, sent); + bacpy(&hdev->random_addr, sent); hci_dev_unlock(hdev); } @@ -1027,11 +1048,11 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%2.2x", hdev->name, status); - sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE); - if (!sent) + if (status) return; - if (status) + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE); + if (!sent) return; hci_dev_lock(hdev); @@ -1061,14 +1082,16 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%2.2x", hdev->name, status); + if (status) + return; + cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_PARAM); if (!cp) return; hci_dev_lock(hdev); - if (!status) - hdev->le_scan_type = cp->type; + hdev->le_scan_type = cp->type; hci_dev_unlock(hdev); } @@ -1110,11 +1133,11 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, status); - cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE); - if (!cp) + if (status) return; - if (status) + cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE); + if (!cp) return; switch (cp->enable) { @@ -1167,8 +1190,10 @@ static void hci_cc_le_read_white_list_size(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x size %u", hdev->name, rp->status, rp->size); - if (!rp->status) - hdev->le_white_list_size = rp->size; + if (rp->status) + return; + + hdev->le_white_list_size = rp->size; } static void hci_cc_le_clear_white_list(struct hci_dev *hdev, @@ -1178,8 +1203,10 @@ static void hci_cc_le_clear_white_list(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, status); - if (!status) - hci_white_list_clear(hdev); + if (status) + return; + + hci_white_list_clear(hdev); } static void hci_cc_le_add_to_white_list(struct hci_dev *hdev, @@ -1190,12 +1217,14 @@ static void hci_cc_le_add_to_white_list(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, status); + if (status) + return; + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_WHITE_LIST); if (!sent) return; - if (!status) - hci_white_list_add(hdev, &sent->bdaddr, sent->bdaddr_type); + hci_white_list_add(hdev, &sent->bdaddr, sent->bdaddr_type); } static void hci_cc_le_del_from_white_list(struct hci_dev *hdev, @@ -1206,12 +1235,14 @@ static void hci_cc_le_del_from_white_list(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, status); + if (status) + return; + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_WHITE_LIST); if (!sent) return; - if (!status) - hci_white_list_del(hdev, &sent->bdaddr, sent->bdaddr_type); + hci_white_list_del(hdev, &sent->bdaddr, sent->bdaddr_type); } static void hci_cc_le_read_supported_states(struct hci_dev *hdev, @@ -1221,8 +1252,10 @@ static void hci_cc_le_read_supported_states(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - if (!rp->status) - memcpy(hdev->le_states, rp->le_states, 8); + if (rp->status) + return; + + memcpy(hdev->le_states, rp->le_states, 8); } static void hci_cc_write_le_host_supported(struct hci_dev *hdev, @@ -1233,25 +1266,26 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev, BT_DBG("%s status 0x%2.2x", hdev->name, status); + if (status) + return; + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED); if (!sent) return; - if (!status) { - if (sent->le) { - hdev->features[1][0] |= LMP_HOST_LE; - set_bit(HCI_LE_ENABLED, &hdev->dev_flags); - } else { - hdev->features[1][0] &= ~LMP_HOST_LE; - clear_bit(HCI_LE_ENABLED, &hdev->dev_flags); - clear_bit(HCI_ADVERTISING, &hdev->dev_flags); - } - - if (sent->simul) - hdev->features[1][0] |= LMP_HOST_LE_BREDR; - else - hdev->features[1][0] &= ~LMP_HOST_LE_BREDR; + if (sent->le) { + hdev->features[1][0] |= LMP_HOST_LE; + set_bit(HCI_LE_ENABLED, &hdev->dev_flags); + } else { + hdev->features[1][0] &= ~LMP_HOST_LE; + clear_bit(HCI_LE_ENABLED, &hdev->dev_flags); + clear_bit(HCI_ADVERTISING, &hdev->dev_flags); } + + if (sent->simul) + hdev->features[1][0] |= LMP_HOST_LE_BREDR; + else + hdev->features[1][0] &= ~LMP_HOST_LE_BREDR; } static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3 From 0ebca7d6819a24b7518d518f89597cf7c7854094 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 5 Jul 2014 10:48:02 +0200 Subject: Bluetooth: Run special init procedure for unconfigured controllers For an unconfigured controller it is required to read at least the local version information. If the set_bdaddr driver callback is provideded, then also the local Bluetooth address will be read. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b29f3938e6b3..f996e2c4815c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1791,6 +1791,35 @@ static int __hci_init(struct hci_dev *hdev) return 0; } +static void hci_init0_req(struct hci_request *req, unsigned long opt) +{ + struct hci_dev *hdev = req->hdev; + + BT_DBG("%s %ld", hdev->name, opt); + + /* Reset */ + if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) + hci_reset_req(req, 0); + + /* Read Local Version */ + hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL); + + /* Read BD Address */ + if (hdev->set_bdaddr) + hci_req_add(req, HCI_OP_READ_BD_ADDR, 0, NULL); +} + +static int __hci_unconf_init(struct hci_dev *hdev) +{ + int err; + + err = __hci_req_sync(hdev, hci_init0_req, 0, HCI_INIT_TIMEOUT); + if (err < 0) + return err; + + return 0; +} + static void hci_scan_req(struct hci_request *req, unsigned long opt) { __u8 scan = opt; @@ -2259,6 +2288,17 @@ static int hci_dev_do_open(struct hci_dev *hdev) if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) || test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks)) set_bit(HCI_UNCONFIGURED, &hdev->dev_flags); + + /* For an unconfigured controller it is required to + * read at least the version information provided by + * the Read Local Version Information command. + * + * If the set_bdaddr driver callback is provided, then + * also the original Bluetooth public device address + * will be read using the Read BD Address command. + */ + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) + ret = __hci_unconf_init(hdev); } /* If public address change is configured, ensure that the -- cgit v1.2.3 From e30d3f5fef378cd14ba8c331a5c7a2f9239c2770 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 5 Jul 2014 10:48:03 +0200 Subject: Bluetooth: Store Bluetooth address from controller setup During the setup phase of a controller, the Bluetooth address will be read and to have that original address available for later use, store it as setup address. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 1cae4d3a629d..aff285698c85 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -171,6 +171,7 @@ struct hci_dev { __u8 bus; __u8 dev_type; bdaddr_t bdaddr; + bdaddr_t setup_addr; bdaddr_t public_addr; bdaddr_t random_addr; bdaddr_t static_addr; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 013c371d3c87..c2ba79c8fe51 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -645,8 +645,14 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - if (!rp->status) + if (rp->status) + return; + + if (test_bit(HCI_INIT, &hdev->flags)) bacpy(&hdev->bdaddr, &rp->bdaddr); + + if (test_bit(HCI_SETUP, &hdev->dev_flags)) + bacpy(&hdev->setup_addr, &rp->bdaddr); } static void hci_cc_read_page_scan_activity(struct hci_dev *hdev, -- cgit v1.2.3 From 9e1d7e15340b14bfb2ac86d77ca72fcebfe67d66 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 6 Jul 2014 11:03:36 +0300 Subject: Bluetooth: Restrict blocked device check in l2cap_recv_frame to LE BR/EDR has the connection request and connection request rejection, but LE doesn't have anything similar. We still request LE connections to blocked devices to be disconnected but it's possible that ACL data slips through before that. The check in l2cap_recv_frame really only needs to be for LE and not BR/EDR because of this. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index dbef22d644e2..f1f544a12c3c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6914,7 +6914,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) return; } - if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, + /* Since we can't actively block incoming LE connections we must + * at least ensure that we ignore incoming data from them. + */ + if (hcon->type == LE_LINK && + hci_blacklist_lookup(hcon->hdev, &hcon->dst, bdaddr_type(hcon, hcon->dst_type))) { kfree_skb(skb); return; -- cgit v1.2.3 From 6d6a47516390d8baa634eb589010f9e9d76b84a1 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 26 Jun 2014 09:13:26 +0300 Subject: iwlwifi: fix naming mistake for the fw_monitor module parameter Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index bb842f4732dd..77e3178040b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1407,5 +1407,5 @@ MODULE_PARM_DESC(power_level, "default power save level (range from 1 - 5, default: 1)"); module_param_named(fw_monitor, iwlwifi_mod_params.fw_monitor, bool, S_IRUGO); -MODULE_PARM_DESC(dbgm, +MODULE_PARM_DESC(fw_monitor, "firmware monitor - to debug FW (default: false - needs lots of memory)"); -- cgit v1.2.3 From d4849277f92a0bfa08a988545ea527fc8e0c9571 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 24 Jun 2014 14:34:28 +0300 Subject: iwlwifi: remove wrong comment about alignment in iwl-fw-error-dump.h The chunks of data do not need to be multipliers of 4 nor 4-bytes aligned. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index ced5ba95c23d..9fd860f82871 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -92,8 +92,8 @@ enum iwl_fw_error_dump_type { /** * struct iwl_fw_error_dump_data - data for one type * @type: %enum iwl_fw_error_dump_type - * @len: the length starting from %data - must be a multiplier of 4. - * @data: the data itself padded to be a multiplier of 4. + * @len: the length starting from %data + * @data: the data itself */ struct iwl_fw_error_dump_data { __le32 type; -- cgit v1.2.3 From 78dae98fab85f4cd2d38cfc3474dea6e87e7b53a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 25 Jun 2014 13:46:10 +0300 Subject: iwlwifi: mvm: don't collect logs in the interrupt thread Instead of reading all the data in the context of the interrupt thread, collect the data in the restart flow before the actual restart takes place so that the device still has all the information. Remove iwl_mvm_fw_error_sram_dump and move its content to iwl_mvm_fw_error_dump. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 --- drivers/net/wireless/iwlwifi/mvm/ops.c | 31 ++++++++++++------------------- drivers/net/wireless/iwlwifi/mvm/utils.c | 22 ---------------------- 3 files changed, 12 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index f7e54a57f46d..4cc6788c68fb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -595,8 +595,6 @@ struct iwl_mvm { /* -1 for always, 0 for never, >0 for that many times */ s8 restart_fw; void *fw_error_dump; - void *fw_error_sram; - u32 fw_error_sram_len; u32 *fw_error_rxf; u32 fw_error_rxf_len; @@ -734,7 +732,6 @@ u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); -void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm); void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm); #endif u8 first_antenna(u8 mask); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 7bb763f3052b..889374d04fb1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -550,7 +550,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) kfree(mvm->scan_cmd); vfree(mvm->fw_error_dump); - kfree(mvm->fw_error_sram); kfree(mvm->fw_error_rxf); kfree(mvm->mcast_filter_cmd); mvm->mcast_filter_cmd = NULL; @@ -828,6 +827,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; + const struct fw_img *img; + u32 sram_len, sram_ofs; u32 file_len; u32 trans_len; @@ -836,9 +837,13 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) if (mvm->fw_error_dump) return; + img = &mvm->fw->img[mvm->cur_ucode]; + sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; + sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; + file_len = sizeof(*dump_file) + sizeof(*dump_data) * 3 + - mvm->fw_error_sram_len + + sram_len + mvm->fw_error_rxf_len + sizeof(*dump_info); @@ -870,6 +875,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, sizeof(dump_info->bus_human_readable)); + iwl_mvm_fw_error_rxf_dump(mvm); + dump_data = iwl_fw_error_next_data(dump_data); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len); @@ -877,23 +884,14 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_data = iwl_fw_error_next_data(dump_data); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); - dump_data->len = cpu_to_le32(mvm->fw_error_sram_len); - - /* - * No need for lock since at the stage the FW isn't loaded. So it - * can't assert - we are the only one who can possibly be accessing - * mvm->fw_error_sram right now. - */ - memcpy(dump_data->data, mvm->fw_error_sram, mvm->fw_error_sram_len); + dump_data->len = cpu_to_le32(sram_len); + iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, + sram_len); kfree(mvm->fw_error_rxf); mvm->fw_error_rxf = NULL; mvm->fw_error_rxf_len = 0; - kfree(mvm->fw_error_sram); - mvm->fw_error_sram = NULL; - mvm->fw_error_sram_len = 0; - if (trans_len) { void *buf = iwl_fw_error_next_data(dump_data); u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, @@ -911,11 +909,6 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) iwl_mvm_dump_nic_error_log(mvm); -#ifdef CONFIG_IWLWIFI_DEBUGFS - iwl_mvm_fw_error_sram_dump(mvm); - iwl_mvm_fw_error_rxf_dump(mvm); -#endif - iwl_mvm_nic_restart(mvm); } diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index aa9fc77e8413..15db97c7d822 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -520,28 +520,6 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) } #ifdef CONFIG_IWLWIFI_DEBUGFS -void iwl_mvm_fw_error_sram_dump(struct iwl_mvm *mvm) -{ - const struct fw_img *img; - u32 ofs, sram_len; - void *sram; - - if (!mvm->ucode_loaded || mvm->fw_error_sram || mvm->fw_error_dump) - return; - - img = &mvm->fw->img[mvm->cur_ucode]; - ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; - sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; - - sram = kzalloc(sram_len, GFP_ATOMIC); - if (!sram) - return; - - iwl_trans_read_mem_bytes(mvm->trans, ofs, sram, sram_len); - mvm->fw_error_sram = sram; - mvm->fw_error_sram_len = sram_len; -} - void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm) { int i, reg_val; -- cgit v1.2.3 From 655e6d6db21b0c0d411aef9d816816fb68b0496c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 25 Jun 2014 14:08:58 +0300 Subject: iwlwifi: mvm: kill iwl_mvm_fw_error_rxf_dump Its content can move to the caller. While at it, move iwl_mvm_fw_error_rxf_dump to caller. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 100 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 6 -- drivers/net/wireless/iwlwifi/mvm/ops.c | 83 ----------------------- drivers/net/wireless/iwlwifi/mvm/utils.c | 43 ------------ 4 files changed, 100 insertions(+), 132 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 9feca4a6bacf..9661a526ed51 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -80,6 +80,8 @@ #include "fw-api-scan.h" #include "iwl-phy-db.h" #include "testmode.h" +#include "iwl-fw-error-dump.h" +#include "iwl-prph.h" static const struct ieee80211_iface_limit iwl_mvm_limits[] = { { @@ -645,6 +647,104 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, mvmvif->phy_ctxt = NULL; } +#ifdef CONFIG_IWLWIFI_DEBUGFS +static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) +{ + struct iwl_fw_error_dump_file *dump_file; + struct iwl_fw_error_dump_data *dump_data; + struct iwl_fw_error_dump_info *dump_info; + const struct fw_img *img; + u32 sram_len, sram_ofs; + u32 file_len, rxf_len; + unsigned long flags; + u32 trans_len; + int reg_val; + + lockdep_assert_held(&mvm->mutex); + + if (mvm->fw_error_dump) + return; + + img = &mvm->fw->img[mvm->cur_ucode]; + sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; + sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; + + /* reading buffer size */ + reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR); + rxf_len = (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS; + + /* the register holds the value divided by 128 */ + rxf_len = rxf_len << 7; + + file_len = sizeof(*dump_file) + + sizeof(*dump_data) * 3 + + sram_len + + rxf_len + + sizeof(*dump_info); + + trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0); + if (trans_len) + file_len += trans_len; + + dump_file = vmalloc(file_len); + if (!dump_file) + return; + + mvm->fw_error_dump = dump_file; + + dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); + dump_file->file_len = cpu_to_le32(file_len); + dump_data = (void *)dump_file->data; + + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); + dump_data->len = cpu_to_le32(sizeof(*dump_info)); + dump_info = (void *) dump_data->data; + dump_info->device_family = + mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? + cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) : + cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8); + memcpy(dump_info->fw_human_readable, mvm->fw->human_readable, + sizeof(dump_info->fw_human_readable)); + strncpy(dump_info->dev_human_readable, mvm->cfg->name, + sizeof(dump_info->dev_human_readable)); + strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, + sizeof(dump_info->bus_human_readable)); + + dump_data = iwl_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); + dump_data->len = cpu_to_le32(rxf_len); + + if (iwl_trans_grab_nic_access(mvm->trans, false, &flags)) { + u32 *rxf = (void *)dump_data->data; + int i; + + for (i = 0; i < (rxf_len / sizeof(u32)); i++) { + iwl_trans_write_prph(mvm->trans, + RXF_LD_FENCE_OFFSET_ADDR, + i * sizeof(u32)); + rxf[i] = iwl_trans_read_prph(mvm->trans, + RXF_FIFO_RD_FENCE_ADDR); + } + iwl_trans_release_nic_access(mvm->trans, &flags); + } + + dump_data = iwl_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); + dump_data->len = cpu_to_le32(sram_len); + iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, + sram_len); + + if (trans_len) { + void *buf = iwl_fw_error_next_data(dump_data); + u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, + trans_len); + dump_data = (void *)((u8 *)buf + real_trans_len); + dump_file->file_len = + cpu_to_le32(file_len - trans_len + real_trans_len); + } +} +#endif + static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) { #ifdef CONFIG_IWLWIFI_DEBUGFS diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 4cc6788c68fb..e067d9762603 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -595,8 +595,6 @@ struct iwl_mvm { /* -1 for always, 0 for never, >0 for that many times */ s8 restart_fw; void *fw_error_dump; - u32 *fw_error_rxf; - u32 fw_error_rxf_len; #ifdef CONFIG_IWLWIFI_LEDS struct led_classdev led; @@ -730,10 +728,6 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags, struct ieee80211_tx_rate *r); u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); -#ifdef CONFIG_IWLWIFI_DEBUGFS -void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); -void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm); -#endif u8 first_antenna(u8 mask); u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 889374d04fb1..15c13a722a93 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -550,7 +550,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) kfree(mvm->scan_cmd); vfree(mvm->fw_error_dump); - kfree(mvm->fw_error_rxf); kfree(mvm->mcast_filter_cmd); mvm->mcast_filter_cmd = NULL; @@ -821,88 +820,6 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) } } -#ifdef CONFIG_IWLWIFI_DEBUGFS -void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) -{ - struct iwl_fw_error_dump_file *dump_file; - struct iwl_fw_error_dump_data *dump_data; - struct iwl_fw_error_dump_info *dump_info; - const struct fw_img *img; - u32 sram_len, sram_ofs; - u32 file_len; - u32 trans_len; - - lockdep_assert_held(&mvm->mutex); - - if (mvm->fw_error_dump) - return; - - img = &mvm->fw->img[mvm->cur_ucode]; - sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; - sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; - - file_len = sizeof(*dump_file) + - sizeof(*dump_data) * 3 + - sram_len + - mvm->fw_error_rxf_len + - sizeof(*dump_info); - - trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0); - if (trans_len) - file_len += trans_len; - - dump_file = vmalloc(file_len); - if (!dump_file) - return; - - mvm->fw_error_dump = dump_file; - - dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); - dump_file->file_len = cpu_to_le32(file_len); - dump_data = (void *)dump_file->data; - - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); - dump_data->len = cpu_to_le32(sizeof(*dump_info)); - dump_info = (void *) dump_data->data; - dump_info->device_family = - mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? - cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) : - cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8); - memcpy(dump_info->fw_human_readable, mvm->fw->human_readable, - sizeof(dump_info->fw_human_readable)); - strncpy(dump_info->dev_human_readable, mvm->cfg->name, - sizeof(dump_info->dev_human_readable)); - strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, - sizeof(dump_info->bus_human_readable)); - - iwl_mvm_fw_error_rxf_dump(mvm); - - dump_data = iwl_fw_error_next_data(dump_data); - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); - dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len); - memcpy(dump_data->data, mvm->fw_error_rxf, mvm->fw_error_rxf_len); - - dump_data = iwl_fw_error_next_data(dump_data); - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); - dump_data->len = cpu_to_le32(sram_len); - iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, - sram_len); - - kfree(mvm->fw_error_rxf); - mvm->fw_error_rxf = NULL; - mvm->fw_error_rxf_len = 0; - - if (trans_len) { - void *buf = iwl_fw_error_next_data(dump_data); - u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, - trans_len); - dump_data = (void *)((u8 *)buf + real_trans_len); - dump_file->file_len = - cpu_to_le32(file_len - trans_len + real_trans_len); - } -} -#endif - static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 15db97c7d822..ac249da8a22b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -519,49 +519,6 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) iwl_mvm_dump_umac_error_log(mvm); } -#ifdef CONFIG_IWLWIFI_DEBUGFS -void iwl_mvm_fw_error_rxf_dump(struct iwl_mvm *mvm) -{ - int i, reg_val; - unsigned long flags; - - if (!mvm->ucode_loaded || mvm->fw_error_rxf || mvm->fw_error_dump) - return; - - /* reading buffer size */ - reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR); - mvm->fw_error_rxf_len = - (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS; - - /* the register holds the value divided by 128 */ - mvm->fw_error_rxf_len = mvm->fw_error_rxf_len << 7; - - if (!mvm->fw_error_rxf_len) - return; - - mvm->fw_error_rxf = kzalloc(mvm->fw_error_rxf_len, GFP_ATOMIC); - if (!mvm->fw_error_rxf) { - mvm->fw_error_rxf_len = 0; - return; - } - - if (!iwl_trans_grab_nic_access(mvm->trans, false, &flags)) { - kfree(mvm->fw_error_rxf); - mvm->fw_error_rxf = NULL; - mvm->fw_error_rxf_len = 0; - return; - } - - for (i = 0; i < (mvm->fw_error_rxf_len / sizeof(u32)); i++) { - iwl_trans_write_prph(mvm->trans, RXF_LD_FENCE_OFFSET_ADDR, - i * sizeof(u32)); - mvm->fw_error_rxf[i] = - iwl_trans_read_prph(mvm->trans, RXF_FIFO_RD_FENCE_ADDR); - } - iwl_trans_release_nic_access(mvm->trans, &flags); -} -#endif - /** * iwl_mvm_send_lq_cmd() - Send link quality command * @init: This command is sent as part of station initialization right -- cgit v1.2.3 From 5bfe6f53283de44855ee45a102210abbfac995f9 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 25 Jun 2014 16:21:43 +0300 Subject: iwlwifi: mvm: update layout of firmware error dump The memory was not zeroed - fix that. Also update the iwl_fw_error_dump_info structure. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 9661a526ed51..5e425d3fddeb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -686,7 +686,7 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) if (trans_len) file_len += trans_len; - dump_file = vmalloc(file_len); + dump_file = vzalloc(file_len); if (!dump_file) return; -- cgit v1.2.3 From d40fc489f308951f6361742e8b9689326c831f41 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Wed, 25 Jun 2014 14:08:50 +0200 Subject: iwlwifi: mvm: wait for d0i3 exit in add interface flow This patch makes sure there're no target accesses in the add interface flow before d0i3 exit completes. Signed-off-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 40 ++++++++++++++++++++++------- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 5e425d3fddeb..7dde944a68fb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -243,6 +243,21 @@ iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref) } } +static int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) +{ + iwl_mvm_ref(mvm, ref_type); + + if (!wait_event_timeout(mvm->d0i3_exit_waitq, + !test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status), + HZ)) { + WARN_ON_ONCE(1); + iwl_mvm_unref(mvm, ref_type); + return -EIO; + } + + return 0; +} + static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) { int i; @@ -559,9 +574,6 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: case IEEE80211_AMPDU_TX_OPERATIONAL: - iwl_mvm_ref(mvm, IWL_MVM_REF_TX_AGG); - tx_agg_ref = true; - /* * for tx start, wait synchronously until D0i3 exit to * get the correct sequence number for the tid. @@ -570,12 +582,11 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, * by the trans layer (unlike commands), so wait for * d0i3 exit in these cases as well. */ - if (!wait_event_timeout(mvm->d0i3_exit_waitq, - !test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status), HZ)) { - WARN_ON_ONCE(1); - iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG); - return -EIO; - } + ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_TX_AGG); + if (ret) + return ret; + + tx_agg_ref = true; break; default: break; @@ -903,6 +914,15 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; + /* + * make sure D0i3 exit is completed, otherwise a target access + * during tx queue configuration could be done when still in + * D0i3 state. + */ + ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_ADD_IF); + if (ret) + return ret; + /* * Not much to do here. The stack will not allow interface * types or combinations that we didn't advertise, so we @@ -1017,6 +1037,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, out_unlock: mutex_unlock(&mvm->mutex); + iwl_mvm_unref(mvm, IWL_MVM_REF_ADD_IF); + return ret; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index e067d9762603..6fe93a7335c1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -230,6 +230,7 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_USER, IWL_MVM_REF_TX, IWL_MVM_REF_TX_AGG, + IWL_MVM_REF_ADD_IF, IWL_MVM_REF_EXIT_WORK, IWL_MVM_REF_COUNT, -- cgit v1.2.3 From 1e0b393a4478fdce0e39a5b7fe7d05ee4ab46105 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Wed, 11 Jun 2014 11:37:09 +0300 Subject: iwlwifi: mvm: read the mac address in family 8000 In family 8000 products the MAC address in the OTP could be in either: - WFPM address - PCIE address In sdio product we should read it from the WFPM, in pcie product we should read it from the PCIe location. This is relevant only from otp version 0xE08 and above. While at it, fix the bytes order in version 0xE08. Signed-off-by: Eran Harary Reviewed-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 60 ++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index f0ae038f3339..dd76ed28884d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -63,6 +63,7 @@ #include #include #include +#include #include "iwl-drv.h" #include "iwl-modparams.h" #include "iwl-nvm-parse.h" @@ -87,8 +88,10 @@ enum wkp_nvm_offsets { enum family_8000_nvm_offsets { /* NVM HW-Section offset (in words) definitions */ - HW_ADDR0_FAMILY_8000 = 0x12, - HW_ADDR1_FAMILY_8000 = 0x16, + HW_ADDR0_WFPM_FAMILY_8000 = 0x12, + HW_ADDR1_WFPM_FAMILY_8000 = 0x16, + HW_ADDR0_PCIE_FAMILY_8000 = 0x8A, + HW_ADDR1_PCIE_FAMILY_8000 = 0x8E, MAC_ADDRESS_OVERRIDE_FAMILY_8000 = 1, /* NVM SW-Section offset (in words) definitions */ @@ -504,16 +507,49 @@ static void iwl_set_hw_address_family_8000(struct device *dev, } if (nvm_hw) { - /* take the MAC address from the OTP */ - hw_addr = (const u8 *)(nvm_hw + HW_ADDR0_FAMILY_8000); - data->hw_addr[0] = hw_addr[3]; - data->hw_addr[1] = hw_addr[2]; - data->hw_addr[2] = hw_addr[1]; - data->hw_addr[3] = hw_addr[0]; - - hw_addr = (const u8 *)(nvm_hw + HW_ADDR1_FAMILY_8000); - data->hw_addr[4] = hw_addr[1]; - data->hw_addr[5] = hw_addr[0]; + /* read the MAC address from OTP */ + if (!dev_is_pci(dev) || (data->nvm_version < 0xE08)) { + /* read the mac address from the WFPM location */ + hw_addr = (const u8 *)(nvm_hw + + HW_ADDR0_WFPM_FAMILY_8000); + data->hw_addr[0] = hw_addr[3]; + data->hw_addr[1] = hw_addr[2]; + data->hw_addr[2] = hw_addr[1]; + data->hw_addr[3] = hw_addr[0]; + + hw_addr = (const u8 *)(nvm_hw + + HW_ADDR1_WFPM_FAMILY_8000); + data->hw_addr[4] = hw_addr[1]; + data->hw_addr[5] = hw_addr[0]; + } else if ((data->nvm_version >= 0xE08) && + (data->nvm_version < 0xE0B)) { + /* read "reverse order" from the PCIe location */ + hw_addr = (const u8 *)(nvm_hw + + HW_ADDR0_PCIE_FAMILY_8000); + data->hw_addr[5] = hw_addr[2]; + data->hw_addr[4] = hw_addr[1]; + data->hw_addr[3] = hw_addr[0]; + + hw_addr = (const u8 *)(nvm_hw + + HW_ADDR1_PCIE_FAMILY_8000); + data->hw_addr[2] = hw_addr[3]; + data->hw_addr[1] = hw_addr[2]; + data->hw_addr[0] = hw_addr[1]; + } else { + /* read from the PCIe location */ + hw_addr = (const u8 *)(nvm_hw + + HW_ADDR0_PCIE_FAMILY_8000); + data->hw_addr[5] = hw_addr[0]; + data->hw_addr[4] = hw_addr[1]; + data->hw_addr[3] = hw_addr[2]; + + hw_addr = (const u8 *)(nvm_hw + + HW_ADDR1_PCIE_FAMILY_8000); + data->hw_addr[2] = hw_addr[1]; + data->hw_addr[1] = hw_addr[2]; + data->hw_addr[0] = hw_addr[3]; + } + return; } -- cgit v1.2.3 From c544e9c4c32acb222782aeff2f24e55e7497e4bc Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 26 Jun 2014 09:54:23 +0300 Subject: iwlwifi: rename iwl_fw_error_fw_mon to iwl_fw_error_dump_fw_mon This is matches the convention of the other structures. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 4 ++-- drivers/net/wireless/iwlwifi/pcie/trans.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index 9fd860f82871..c39a0b899e83 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -147,14 +147,14 @@ struct iwl_fw_error_dump_info { } __packed; /** - * struct iwl_fw_error_fw_mon - FW monitor data + * struct iwl_fw_error_dump_fw_mon - FW monitor data * @fw_mon_wr_ptr: the position of the write pointer in the cyclic buffer * @fw_mon_base_ptr: base pointer of the data * @fw_mon_cycle_cnt: number of wrap arounds * @reserved: for future use * @data: captured data */ -struct iwl_fw_error_fw_mon { +struct iwl_fw_error_dump_fw_mon { __le32 fw_mon_wr_ptr; __le32 fw_mon_base_ptr; __le32 fw_mon_cycle_cnt; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 5703a3d7799b..5b5b0d8c6f60 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1787,7 +1787,7 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); if (trans_pcie->fw_mon_page) - len += sizeof(*data) + sizeof(struct iwl_fw_error_fw_mon) + + len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + trans_pcie->fw_mon_size; if (!buf) @@ -1822,7 +1822,7 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, len += sizeof(*data); if (trans_pcie->fw_mon_page) { - struct iwl_fw_error_fw_mon *fw_mon_data; + struct iwl_fw_error_dump_fw_mon *fw_mon_data; data = iwl_fw_error_next_data(data); data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); -- cgit v1.2.3 From 7f514f5c8767b20dbd8706985cdc00a56a9fd280 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 2 Jul 2014 12:00:51 +0300 Subject: iwlwifi: mvm: remove unused flags from TX command These flags are not used by the firmware anyway. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | 16 ++-------------- drivers/net/wireless/iwlwifi/mvm/tx.c | 1 - 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index bdd6ff648626..d6073f67b212 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h @@ -69,10 +69,8 @@ * @TX_CMD_FLG_ACK: expect ACK from receiving station * @TX_CMD_FLG_STA_RATE: use RS table with initial index from the TX command. * Otherwise, use rate_n_flags from the TX command - * @TX_CMD_FLG_BA: this frame is a block ack * @TX_CMD_FLG_BAR: this frame is a BA request, immediate BAR is expected * Must set TX_CMD_FLG_ACK with this flag. - * @TX_CMD_FLG_TXOP_PROT: protect frame with full TXOP protection * @TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence * @TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence * @TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC) @@ -82,12 +80,10 @@ * @TX_CMD_FLG_SEQ_CTL: set if FW should override the sequence control. * Should be set for mgmt, non-QOS data, mcast, bcast and in scan command * @TX_CMD_FLG_MORE_FRAG: this frame is non-last MPDU - * @TX_CMD_FLG_NEXT_FRAME: this frame includes information of the next frame * @TX_CMD_FLG_TSF: FW should calculate and insert TSF in the frame * Should be set for beacons and probe responses * @TX_CMD_FLG_CALIB: activate PA TX power calibrations * @TX_CMD_FLG_KEEP_SEQ_CTL: if seq_ctl is set, don't increase inner seq count - * @TX_CMD_FLG_AGG_START: allow this frame to start aggregation * @TX_CMD_FLG_MH_PAD: driver inserted 2 byte padding after MAC header. * Should be set for 26/30 length MAC headers * @TX_CMD_FLG_RESP_TO_DRV: zero this if the response should go only to FW @@ -103,7 +99,6 @@ enum iwl_tx_flags { TX_CMD_FLG_PROT_REQUIRE = BIT(0), TX_CMD_FLG_ACK = BIT(3), TX_CMD_FLG_STA_RATE = BIT(4), - TX_CMD_FLG_BA = BIT(5), TX_CMD_FLG_BAR = BIT(6), TX_CMD_FLG_TXOP_PROT = BIT(7), TX_CMD_FLG_VHT_NDPA = BIT(8), @@ -113,11 +108,9 @@ enum iwl_tx_flags { TX_CMD_FLG_BT_DIS = BIT(12), TX_CMD_FLG_SEQ_CTL = BIT(13), TX_CMD_FLG_MORE_FRAG = BIT(14), - TX_CMD_FLG_NEXT_FRAME = BIT(15), TX_CMD_FLG_TSF = BIT(16), TX_CMD_FLG_CALIB = BIT(17), TX_CMD_FLG_KEEP_SEQ_CTL = BIT(18), - TX_CMD_FLG_AGG_START = BIT(19), TX_CMD_FLG_MH_PAD = BIT(20), TX_CMD_FLG_RESP_TO_DRV = BIT(21), TX_CMD_FLG_CCMP_AGG = BIT(22), @@ -191,8 +184,6 @@ enum iwl_tx_flags { * struct iwl_tx_cmd - TX command struct to FW * ( TX_CMD = 0x1c ) * @len: in bytes of the payload, see below for details - * @next_frame_len: same as len, but for next frame (0 if not applicable) - * Used for fragmentation and bursting, but not in 11n aggregation. * @tx_flags: combination of TX_CMD_FLG_* * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of RATE_MCS_* @@ -210,8 +201,6 @@ enum iwl_tx_flags { * @data_retry_limit: max attempts to send the data packet * @tid_spec: TID/tspec * @pm_frame_timeout: PM TX frame timeout - * @driver_txop: duration od EDCA TXOP, in 32-usec units. Set this if not - * specified by HCCA protocol * * The byte count (both len and next_frame_len) includes MAC header * (24/26/30/32 bytes) @@ -241,8 +230,7 @@ struct iwl_tx_cmd { u8 initial_rate_index; u8 reserved2; u8 key[16]; - __le16 next_frame_flags; - __le16 reserved3; + __le32 reserved3; __le32 life_time; __le32 dram_lsb_ptr; u8 dram_msb_ptr; @@ -250,7 +238,7 @@ struct iwl_tx_cmd { u8 data_retry_limit; u8 tid_tspec; __le16 pm_frame_timeout; - __le16 driver_txop; + __le16 reserved4; u8 payload[0]; struct ieee80211_hdr hdr[0]; } __packed; /* TX_CMD_API_S_VER_3 */ diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 4f7cff506ee7..fa87a4ba25ec 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -131,7 +131,6 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, !is_multicast_ether_addr(ieee80211_get_DA(hdr))) tx_flags |= TX_CMD_FLG_PROT_REQUIRE; - tx_cmd->driver_txop = 0; tx_cmd->tx_flags = cpu_to_le32(tx_flags); /* Total # bytes to be transmitted */ tx_cmd->len = cpu_to_le16((u16)skb->len); -- cgit v1.2.3 From 19de0825cd8acb1de6fa6a135b1f059446781049 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 6 Jul 2014 13:06:51 +0300 Subject: Bluetooth: Fix sending Device Removed when clearing all parameters When calling Device Remove with BDADDR_ANY we should in a similar way emit Device Removed events as we do when removing a single device. Since we have to iterate the list and call device_removed() the dedicated hci_conn_params_clear_enabled() is not really useful anymore. This patch removes the helper function and does the event emission and list item removal in a single loop. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_core.c | 18 ------------------ net/bluetooth/mgmt.c | 15 ++++++++++++++- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index aff285698c85..9d838a072db4 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -867,7 +867,6 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_conn_params_clear_all(struct hci_dev *hdev); void hci_conn_params_clear_disabled(struct hci_dev *hdev); -void hci_conn_params_clear_enabled(struct hci_dev *hdev); struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list, bdaddr_t *addr, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f996e2c4815c..d01bd043c231 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3621,24 +3621,6 @@ void hci_conn_params_clear_disabled(struct hci_dev *hdev) BT_DBG("All LE disabled connection parameters were removed"); } -/* This function requires the caller holds hdev->lock */ -void hci_conn_params_clear_enabled(struct hci_dev *hdev) -{ - struct hci_conn_params *params, *tmp; - - list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { - if (params->auto_connect == HCI_AUTO_CONN_DISABLED) - continue; - list_del(¶ms->action); - list_del(¶ms->list); - kfree(params); - } - - hci_update_background_scan(hdev); - - BT_DBG("All enabled LE connection parameters were removed"); -} - /* This function requires the caller holds hdev->lock */ void hci_conn_params_clear_all(struct hci_dev *hdev) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f514eb15e0fb..04a66429ad4d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5284,6 +5284,8 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); } else { + struct hci_conn_params *p, *tmp; + if (cp->addr.type) { err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, MGMT_STATUS_INVALID_PARAMS, @@ -5291,7 +5293,18 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } - hci_conn_params_clear_enabled(hdev); + list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) { + if (p->auto_connect == HCI_AUTO_CONN_DISABLED) + continue; + device_removed(sk, hdev, &p->addr, p->addr_type); + list_del(&p->action); + list_del(&p->list); + kfree(p); + } + + BT_DBG("All LE connection parameters were removed"); + + hci_update_background_scan(hdev); } err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, -- cgit v1.2.3 From d603b76b0c18c5adf4a3164dff50bb15948cd7bd Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 6 Jul 2014 12:11:14 +0200 Subject: Bluetooth: Run controller setup after external configuration When the external configuration triggers the switch to a configured controller, it means the setup needs to be run. Controllers that start out unconfigured have only run limited set of HCI commands. This is not enough for complete operation and thus run the setup procedure before announcing the new controller index. This introduces HCI_CONFIG flag as companion to HCI_SETUP flag. The HCI_SETUP flag is only used once for the initial setup procedure. And during that procedure hdev->setup driver callback is called. With the new HCI_CONFIG the switch from unconfigured to configured state is triggering the same setup procedure just without hdev->setup. This is required since bringing a controller back to unconfigured state from configured state is possible. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 17 ++++++++++++++--- net/bluetooth/hci_sock.c | 3 ++- net/bluetooth/mgmt.c | 14 ++++++++++++-- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 80c5fc947fbc..46f2458e4bc9 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -163,6 +163,7 @@ enum { */ enum { HCI_SETUP, + HCI_CONFIG, HCI_AUTO_OFF, HCI_RFKILLED, HCI_MGMT, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d01bd043c231..bf7cf512df88 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2232,7 +2232,8 @@ static int hci_dev_do_open(struct hci_dev *hdev) goto done; } - if (!test_bit(HCI_SETUP, &hdev->dev_flags)) { + if (!test_bit(HCI_SETUP, &hdev->dev_flags) && + !test_bit(HCI_CONFIG, &hdev->dev_flags)) { /* Check for rfkill but allow the HCI setup stage to * proceed (which in itself doesn't cause any RF activity). */ @@ -2326,6 +2327,7 @@ static int hci_dev_do_open(struct hci_dev *hdev) set_bit(HCI_UP, &hdev->flags); hci_notify(hdev, HCI_DEV_UP); if (!test_bit(HCI_SETUP, &hdev->dev_flags) && + !test_bit(HCI_CONFIG, &hdev->dev_flags) && !test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && hdev->dev_type == HCI_BREDR) { @@ -2824,7 +2826,8 @@ static int hci_rfkill_set_block(void *data, bool blocked) if (blocked) { set_bit(HCI_RFKILLED, &hdev->dev_flags); - if (!test_bit(HCI_SETUP, &hdev->dev_flags)) + if (!test_bit(HCI_SETUP, &hdev->dev_flags) && + !test_bit(HCI_CONFIG, &hdev->dev_flags)) hci_dev_do_close(hdev); } else { clear_bit(HCI_RFKILLED, &hdev->dev_flags); @@ -2881,6 +2884,12 @@ static void hci_power_on(struct work_struct *work) * and no event will be send. */ mgmt_index_added(hdev); + } else if (test_and_clear_bit(HCI_CONFIG, &hdev->dev_flags)) { + /* Powering on the controller with HCI_CONFIG set only + * happens with the transition from unconfigured to + * configured. This will send the Index Added event. + */ + mgmt_index_added(hdev); } } @@ -4045,7 +4054,8 @@ void hci_unregister_dev(struct hci_dev *hdev) cancel_work_sync(&hdev->power_on); if (!test_bit(HCI_INIT, &hdev->flags) && - !test_bit(HCI_SETUP, &hdev->dev_flags)) { + !test_bit(HCI_SETUP, &hdev->dev_flags) && + !test_bit(HCI_CONFIG, &hdev->dev_flags)) { hci_dev_lock(hdev); mgmt_index_removed(hdev); hci_dev_unlock(hdev); @@ -5370,6 +5380,7 @@ void hci_update_background_scan(struct hci_dev *hdev) if (!test_bit(HCI_UP, &hdev->flags) || test_bit(HCI_INIT, &hdev->flags) || test_bit(HCI_SETUP, &hdev->dev_flags) || + test_bit(HCI_CONFIG, &hdev->dev_flags) || test_bit(HCI_AUTO_OFF, &hdev->dev_flags) || test_bit(HCI_UNREGISTER, &hdev->dev_flags)) return; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index ba13ad8e25c6..802665751cc4 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -693,7 +693,8 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, if (test_bit(HCI_UP, &hdev->flags) || test_bit(HCI_INIT, &hdev->flags) || - test_bit(HCI_SETUP, &hdev->dev_flags)) { + test_bit(HCI_SETUP, &hdev->dev_flags) || + test_bit(HCI_CONFIG, &hdev->dev_flags)) { err = -EBUSY; hci_dev_put(hdev); goto done; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 04a66429ad4d..d66463a52280 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -385,6 +385,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, count = 0; list_for_each_entry(d, &hci_dev_list, list) { if (test_bit(HCI_SETUP, &d->dev_flags) || + test_bit(HCI_CONFIG, &d->dev_flags) || test_bit(HCI_USER_CHANNEL, &d->dev_flags)) continue; @@ -444,6 +445,7 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, count = 0; list_for_each_entry(d, &hci_dev_list, list) { if (test_bit(HCI_SETUP, &d->dev_flags) || + test_bit(HCI_CONFIG, &d->dev_flags) || test_bit(HCI_USER_CHANNEL, &d->dev_flags)) continue; @@ -5441,8 +5443,15 @@ static int set_external_config(struct sock *sk, struct hci_dev *hdev, if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) == is_configured(hdev)) { mgmt_index_removed(hdev); - change_bit(HCI_UNCONFIGURED, &hdev->dev_flags); - mgmt_index_added(hdev); + + if (test_and_change_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) { + set_bit(HCI_CONFIG, &hdev->dev_flags); + set_bit(HCI_AUTO_OFF, &hdev->dev_flags); + + queue_work(hdev->req_workqueue, &hdev->power_on); + } else { + mgmt_index_added(hdev); + } } unlock: @@ -5558,6 +5567,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) } if (test_bit(HCI_SETUP, &hdev->dev_flags) || + test_bit(HCI_CONFIG, &hdev->dev_flags) || test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { err = cmd_status(sk, index, opcode, MGMT_STATUS_INVALID_INDEX); -- cgit v1.2.3 From 9713c17b086c1ebfe34ea4d34147a778276e2dab Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 6 Jul 2014 12:11:15 +0200 Subject: Bluetooth: Add support for changing the public device address This adds support for changing the public device address. This feature is required by controllers that do not provide a public address and have HCI_QUIRK_INVALID_BDADDR set. Even if a controller has a public device address, this is useful when an embedded system wants to use its own value. As long as the driver provides the set_bdaddr callback, this allows changing the device address before powering on the controller. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 6 +++++ net/bluetooth/hci_core.c | 14 ++++++----- net/bluetooth/mgmt.c | 57 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 80606d2fe086..623d5203c592 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -489,6 +489,12 @@ struct mgmt_cp_set_external_config { } __packed; #define MGMT_SET_EXTERNAL_CONFIG_SIZE 1 +#define MGMT_OP_SET_PUBLIC_ADDRESS 0x0039 +struct mgmt_cp_set_public_address { + bdaddr_t bdaddr; +} __packed; +#define MGMT_SET_PUBLIC_ADDRESS_SIZE 6 + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index bf7cf512df88..c96b96ca41ac 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2302,12 +2302,14 @@ static int hci_dev_do_open(struct hci_dev *hdev) ret = __hci_unconf_init(hdev); } - /* If public address change is configured, ensure that the - * address gets programmed. If the driver does not support - * changing the public address, fail the power on procedure. - */ - if (!ret && bacmp(&hdev->public_addr, BDADDR_ANY)) { - if (hdev->set_bdaddr) + if (test_bit(HCI_CONFIG, &hdev->dev_flags)) { + /* If public address change is configured, ensure that + * the address gets programmed. If the driver does not + * support changing the public address, fail the power + * on procedure. + */ + if (bacmp(&hdev->public_addr, BDADDR_ANY) && + hdev->set_bdaddr) ret = hdev->set_bdaddr(hdev, &hdev->public_addr); else ret = -EADDRNOTAVAIL; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d66463a52280..8275316ae099 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -92,6 +92,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_READ_UNCONF_INDEX_LIST, MGMT_OP_READ_CONFIG_INFO, MGMT_OP_SET_EXTERNAL_CONFIG, + MGMT_OP_SET_PUBLIC_ADDRESS, }; static const u16 mgmt_events[] = { @@ -5459,6 +5460,58 @@ unlock: return err; } +static int set_public_address(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_set_public_address *cp = data; + bool changed; + int err; + + BT_DBG("%s", hdev->name); + + if (hdev_is_powered(hdev)) + return cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS, + MGMT_STATUS_REJECTED); + + if (!bacmp(&cp->bdaddr, BDADDR_ANY)) + return cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS, + MGMT_STATUS_INVALID_PARAMS); + + if (!hdev->set_bdaddr) + return cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS, + MGMT_STATUS_NOT_SUPPORTED); + + hci_dev_lock(hdev); + + changed = !!bacmp(&hdev->public_addr, &cp->bdaddr); + bacpy(&hdev->public_addr, &cp->bdaddr); + + err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev); + if (err < 0) + goto unlock; + + if (!changed) + goto unlock; + + if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) + err = new_options(hdev, sk); + + if (is_configured(hdev)) { + mgmt_index_removed(hdev); + + clear_bit(HCI_UNCONFIGURED, &hdev->dev_flags); + + set_bit(HCI_CONFIG, &hdev->dev_flags); + set_bit(HCI_AUTO_OFF, &hdev->dev_flags); + + queue_work(hdev->req_workqueue, &hdev->power_on); + } + +unlock: + hci_dev_unlock(hdev); + return err; +} + static const struct mgmt_handler { int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len); @@ -5522,6 +5575,7 @@ static const struct mgmt_handler { { read_unconf_index_list, false, MGMT_READ_UNCONF_INDEX_LIST_SIZE }, { read_config_info, false, MGMT_READ_CONFIG_INFO_SIZE }, { set_external_config, false, MGMT_SET_EXTERNAL_CONFIG_SIZE }, + { set_public_address, false, MGMT_SET_PUBLIC_ADDRESS_SIZE }, }; int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) @@ -5576,7 +5630,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) && opcode != MGMT_OP_READ_CONFIG_INFO && - opcode != MGMT_OP_SET_EXTERNAL_CONFIG) { + opcode != MGMT_OP_SET_EXTERNAL_CONFIG && + opcode != MGMT_OP_SET_PUBLIC_ADDRESS) { err = cmd_status(sk, index, opcode, MGMT_STATUS_INVALID_INDEX); goto done; -- cgit v1.2.3 From 5ea234d3e5ff9b6e5c82bde5979307213dde249d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 6 Jul 2014 12:11:16 +0200 Subject: Bluetooth: Clear HCI_RAW flag when controller becomes configured When an unconfigured controllers reaches the configured state, it is important to change the HCI_RAW flag. It indicates to userspace that the controller is fully operational. External configuration allows to bring the controller back into an unconfigured state. In that case make sure HCI_RAW flag is set again. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 6 ++++++ net/bluetooth/mgmt.c | 1 + 2 files changed, 7 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c96b96ca41ac..b1d423efa109 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2887,6 +2887,12 @@ static void hci_power_on(struct work_struct *work) */ mgmt_index_added(hdev); } else if (test_and_clear_bit(HCI_CONFIG, &hdev->dev_flags)) { + /* When the controller is now configured, then it + * is important to clear the HCI_RAW flag. + */ + if (!test_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) + clear_bit(HCI_RAW, &hdev->flags); + /* Powering on the controller with HCI_CONFIG set only * happens with the transition from unconfigured to * configured. This will send the Index Added event. diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8275316ae099..e253f8e1fa47 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5451,6 +5451,7 @@ static int set_external_config(struct sock *sk, struct hci_dev *hdev, queue_work(hdev->req_workqueue, &hdev->power_on); } else { + set_bit(HCI_RAW, &hdev->flags); mgmt_index_added(hdev); } } -- cgit v1.2.3 From 09ae260ba452c2ed36ec295941a58cb75db213ed Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 6 Jul 2014 13:41:15 +0300 Subject: Bluetooth: Use lower timeout for LE auto-connections When we establish connections as a consequence of receiving an advertising report it makes no sense to wait the normal 20 second LE connection timeout. This patch modifies the hci_connect_le function to take an extra timeout value and uses a lower 2 second timeout for the auto-connection case. This timeout is intentionally chosen to be just a bit higher than the 1.28 second timeout that High Duty Cycle Advertising uses. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 4 +++- net/bluetooth/hci_conn.c | 4 +++- net/bluetooth/hci_event.c | 6 +++--- net/bluetooth/l2cap_core.c | 2 +- net/bluetooth/mgmt.c | 3 ++- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 46f2458e4bc9..5481d1c8badb 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -238,6 +238,7 @@ enum { #define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ #define HCI_POWER_OFF_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */ #define HCI_LE_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */ +#define HCI_LE_AUTOCONN_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ /* HCI data types */ #define HCI_COMMAND_PKT 0x01 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9d838a072db4..06039aae3010 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -385,6 +385,7 @@ struct hci_conn { __u32 passkey_notify; __u8 passkey_entered; __u16 disc_timeout; + __u16 conn_timeout; __u16 setting; __u16 le_conn_min_interval; __u16 le_conn_max_interval; @@ -703,7 +704,8 @@ void hci_chan_list_flush(struct hci_conn *conn); struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle); struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, - u8 dst_type, u8 sec_level, u8 auth_type); + u8 dst_type, u8 sec_level, u8 auth_type, + u16 conn_timeout); struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, u8 sec_level, u8 auth_type); struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 0d579d036833..faa032fcdaee 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -700,7 +700,8 @@ static void hci_req_directed_advertising(struct hci_request *req, } struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, - u8 dst_type, u8 sec_level, u8 auth_type) + u8 dst_type, u8 sec_level, u8 auth_type, + u16 conn_timeout) { struct hci_conn_params *params; struct hci_conn *conn; @@ -758,6 +759,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, conn->sec_level = BT_SECURITY_LOW; conn->pending_sec_level = sec_level; conn->auth_type = auth_type; + conn->conn_timeout = conn_timeout; hci_req_init(&req, hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c2ba79c8fe51..f452e44eff3c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1073,7 +1073,7 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) if (conn) queue_delayed_work(hdev->workqueue, &conn->le_conn_timeout, - HCI_LE_CONN_TIMEOUT); + conn->conn_timeout); } mgmt_advertising(hdev, *sent); @@ -1913,7 +1913,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status) if (cp->filter_policy == HCI_LE_USE_PEER_ADDR) queue_delayed_work(conn->hdev->workqueue, &conn->le_conn_timeout, - HCI_LE_CONN_TIMEOUT); + conn->conn_timeout); unlock: hci_dev_unlock(hdev); @@ -4238,7 +4238,7 @@ static bool check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, return false; conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, - HCI_AT_NO_BONDING); + HCI_AT_NO_BONDING, HCI_LE_AUTOCONN_TIMEOUT); if (!IS_ERR(conn)) return true; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index f1f544a12c3c..a219276d9f92 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7135,7 +7135,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, dst_type = ADDR_LE_DEV_RANDOM; hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level, - auth_type); + auth_type, HCI_LE_CONN_TIMEOUT); } else { hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e253f8e1fa47..be91d55c258b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3116,7 +3116,8 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type); conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type, - sec_level, auth_type); + sec_level, auth_type, + HCI_LE_CONN_TIMEOUT); } if (IS_ERR(conn)) { -- cgit v1.2.3 From 40df783d1ef1989ac454e3dfcda017270b8950e6 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 6 Jul 2014 13:29:58 +0200 Subject: Bluetooth: Add support for Intel bootloader devices Intel Bluetooth devices that boot up in bootloader mode can not be used as generic HCI devices, but their HCI transport is still valuable and so bring that up as raw-only devices. T: Bus=02 Lev=02 Prnt=03 Port=00 Cnt=01 Dev#= 14 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=ff(vend.) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=8087 ProdID=0a5a Rev= 0.00 S: Manufacturer=Intel(R) Corporation S: Product=Intel(R) Wilkins Peak 2x2 S: SerialNumber=001122334455 WP_A0 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=81(I) Atr=03(Int.) MxPS= 64 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=(none) E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 61d8385666e9..21f10cac4fac 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -49,7 +49,8 @@ static struct usb_driver btusb_driver; #define BTUSB_WRONG_SCO_MTU 0x40 #define BTUSB_ATH3012 0x80 #define BTUSB_INTEL 0x100 -#define BTUSB_BCM_PATCHRAM 0x200 +#define BTUSB_INTEL_BOOT 0x200 +#define BTUSB_BCM_PATCHRAM 0x400 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -121,6 +122,9 @@ static const struct usb_device_id btusb_table[] = { /* IMC Networks - Broadcom based */ { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) }, + /* Intel Bluetooth USB Bootloader (RAM module) */ + { USB_DEVICE(0x8087, 0x0a5a), .driver_info = BTUSB_INTEL_BOOT }, + { } /* Terminating entry */ }; @@ -1770,6 +1774,9 @@ static int btusb_probe(struct usb_interface *intf, hdev->set_bdaddr = btusb_set_bdaddr_intel; } + if (id->driver_info & BTUSB_INTEL_BOOT) + set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); + /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); -- cgit v1.2.3 From cc78b44ba2231d6a92707407cd199b2e05fe3528 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 6 Jul 2014 13:43:20 +0200 Subject: Bluetooth: Skip unconfigured init procedure for raw-only devices When the driver sets HCI_QUIRK_RAW_DEVICE, the controller will be set as unconfigured. However running the unconfigured init procecure is not useful since raw-only devices are not allowed to change its configuration. This change skips the init procedure and just allows user channel operation for this device. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b1d423efa109..fc7abd3c012d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1813,6 +1813,9 @@ static int __hci_unconf_init(struct hci_dev *hdev) { int err; + if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) + return 0; + err = __hci_req_sync(hdev, hci_init0_req, 0, HCI_INIT_TIMEOUT); if (err < 0) return err; -- cgit v1.2.3 From 01bb75ed2696d4f5b252ca773a53474d6d533f68 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 6 Jul 2014 14:27:39 +0200 Subject: Bluetooth: Remove module parameters for ignoring USB devices The module parameters to ignore devices based on USB VID/PID are not needed at all. So just remove them. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 21f10cac4fac..14314a12babe 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -30,9 +30,6 @@ #define VERSION "0.6" -static bool ignore_dga; -static bool ignore_csr; -static bool ignore_sniffer; static bool disable_scofix; static bool force_scofix; @@ -1683,15 +1680,6 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info == BTUSB_IGNORE) return -ENODEV; - if (ignore_dga && id->driver_info & BTUSB_DIGIANSWER) - return -ENODEV; - - if (ignore_csr && id->driver_info & BTUSB_CSR) - return -ENODEV; - - if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER) - return -ENODEV; - if (id->driver_info & BTUSB_ATH3012) { struct usb_device *udev = interface_to_usbdev(intf); @@ -1981,15 +1969,6 @@ static struct usb_driver btusb_driver = { module_usb_driver(btusb_driver); -module_param(ignore_dga, bool, 0644); -MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001"); - -module_param(ignore_csr, bool, 0644); -MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001"); - -module_param(ignore_sniffer, bool, 0644); -MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002"); - module_param(disable_scofix, bool, 0644); MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size"); -- cgit v1.2.3 From 223683a54bf3f371683c401b9a759c54e1452fa3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 6 Jul 2014 15:44:23 +0300 Subject: Bluetooth: Fix updating background scan for LE connect complete When we get an LE connection complete event we should restart background scanning if there are any devices needing it. So far the code was only making the decision based on whether the completed connection had any stored parameters or not. This patch ensures that we trigger background scanning always when necessary. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f452e44eff3c..57837cad9919 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4196,12 +4196,11 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_proto_connect_cfm(conn, ev->status); params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); - if (params) { + if (params) list_del_init(¶ms->action); - hci_update_background_scan(hdev); - } unlock: + hci_update_background_scan(hdev); hci_dev_unlock(hdev); } -- cgit v1.2.3 From 3a5ef20c979c0f33b6fb2582d04957397a6bf51f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 6 Jul 2014 14:53:54 +0200 Subject: Bluetooth: Handle Intel USB bootloader with buggy interrupt The interrupt interface for the Intel USB bootloader devices is only enabled after receiving SetInterface(0, AltSetting=0). When this USB command is not send, then no HCI events will be received. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 14314a12babe..fe24f600ed65 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1807,6 +1807,18 @@ static int btusb_probe(struct usb_interface *intf, data->isoc = NULL; } + if (id->driver_info & BTUSB_INTEL_BOOT) { + /* A bug in the bootloader causes that interrupt interface is + * only enabled after receiving SetInterface(0, AltSetting=0). + */ + err = usb_set_interface(data->udev, 0, 0); + if (err < 0) { + BT_ERR("failed to set interface 0, alt 0 %d", err); + hci_free_dev(hdev); + return err; + } + } + if (data->isoc) { err = usb_driver_claim_interface(&btusb_driver, data->isoc, data); -- cgit v1.2.3 From d92f2df0565ea04101d6ac04bdc10feeb1d93c94 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 6 Jul 2014 14:53:55 +0200 Subject: Bluetooth: Ignore isochronous endpoints for Intel USB bootloader The isochronous endpoints are not valid when the Intel Bluetooth controller boots up in bootloader mode. So just mark these endpoints as broken and then they will not be configured. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index fe24f600ed65..b7d0fed3417f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -120,7 +120,8 @@ static const struct usb_device_id btusb_table[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) }, /* Intel Bluetooth USB Bootloader (RAM module) */ - { USB_DEVICE(0x8087, 0x0a5a), .driver_info = BTUSB_INTEL_BOOT }, + { USB_DEVICE(0x8087, 0x0a5a), + .driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC }, { } /* Terminating entry */ }; -- cgit v1.2.3 From cdc52faac5f341beaff036828b9459f7c8dd7296 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 6 Jul 2014 15:36:15 +0200 Subject: Bluetooth: Fix memory leaking when hdev->send returns an error The drivers are allowed to just return an error from hdev->send callback and in that case the driver does not own the SKB. Which means that the caller has to free the SKB. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fc7abd3c012d..b02454ab07ee 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -4339,6 +4339,8 @@ EXPORT_SYMBOL(hci_unregister_cb); static void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { + int err; + BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len); /* Time stamp */ @@ -4355,8 +4357,11 @@ static void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) /* Get rid of skb owner, prior to sending to the driver. */ skb_orphan(skb); - if (hdev->send(hdev, skb) < 0) - BT_ERR("%s sending frame failed", hdev->name); + err = hdev->send(hdev, skb); + if (err < 0) { + BT_ERR("%s sending frame failed (%d)", hdev->name, err); + kfree_skb(skb); + } } void hci_req_init(struct hci_request *req, struct hci_dev *hdev) -- cgit v1.2.3 From 74292d5ac289ff5ec8b565889aaeab332e709099 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 6 Jul 2014 15:50:27 +0200 Subject: Bluetooth: Enforce providing hdev->send driver callback The hdev->send driver callback is mandatory to be provided by a driver before calling hci_register_dev. So enforce it and return EINVAL in case it is not available. All existing drivers are providing this callback anyway, so this is just an extra sanity check. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b02454ab07ee..623ffe0da4a6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3932,7 +3932,7 @@ int hci_register_dev(struct hci_dev *hdev) { int id, error; - if (!hdev->open || !hdev->close) + if (!hdev->open || !hdev->close || !hdev->send) return -EINVAL; /* Do not allow HCI_AMP devices to register at index 0, -- cgit v1.2.3 From 4f64fa807a9da14abfa329ae9f16c5ea11ef99ea Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 7 Jul 2014 00:12:04 +0200 Subject: Bluetooth: Use BTUSB_BROKEN_ISOC flag for CSR USB sniffer devices Instead of setting data->isoc manually, use BTUSB_BROKEN_ISOC to indicate that isochronous endpoints are not needed for CSR USB sniffer devices. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b7d0fed3417f..ef4375d5c4ed 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -230,10 +230,12 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE }, /* CSR BlueCore Bluetooth Sniffer */ - { USB_DEVICE(0x0a12, 0x0002), .driver_info = BTUSB_SNIFFER }, + { USB_DEVICE(0x0a12, 0x0002), + .driver_info = BTUSB_SNIFFER | BTUSB_BROKEN_ISOC }, /* Frontline ComProbe Bluetooth Sniffer */ - { USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER }, + { USB_DEVICE(0x16d3, 0x0002), + .driver_info = BTUSB_SNIFFER | BTUSB_BROKEN_ISOC }, /* Intel Bluetooth device */ { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, @@ -1804,8 +1806,6 @@ static int btusb_probe(struct usb_interface *intf, /* New sniffer firmware has crippled HCI interface */ if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); - - data->isoc = NULL; } if (id->driver_info & BTUSB_INTEL_BOOT) { -- cgit v1.2.3 From 1c1abcabfa229b4b3d688d0a1f677d0ca7a1c624 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 7 Jul 2014 12:45:53 +0300 Subject: Bluetooth: Fix connecting devices during LE device discovery If we have devices set as to be connected we should connect to them even during normal discovery if we get a connectable advertising event. If we also have HCI_CONNECTABLE set we should connect ADV_DIRECT_IND events even to devices that we don't have in our pend_le_conns list. This patch implements such behavior by passing the advertising report type to check_pending_le_conn() and calls that function regardless of what type of scanning we are doing. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 57837cad9919..8a36abb3cb06 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4229,13 +4229,30 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, /* This function requires the caller holds hdev->lock */ static bool check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, - u8 addr_type) + u8 addr_type, u8 adv_type) { struct hci_conn *conn; + /* If the event is not connectable don't proceed further */ + if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND) + return false; + + /* Ignore if the device is blocked */ + if (hci_blacklist_lookup(hdev, addr, addr_type)) + return false; + + /* If we're connectable, always connect any ADV_DIRECT_IND event */ + if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && + adv_type == LE_ADV_DIRECT_IND) + goto connect; + + /* If we're not connectable only connect devices that we have in + * our pend_le_conns list. + */ if (!hci_pend_le_action_lookup(&hdev->pend_le_conns, addr, addr_type)) return false; +connect: conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, HCI_AT_NO_BONDING, HCI_LE_AUTOCONN_TIMEOUT); if (!IS_ERR(conn)) @@ -4260,32 +4277,26 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, u8 bdaddr_type, s8 rssi, u8 *data, u8 len) { struct discovery_state *d = &hdev->discovery; + struct smp_irk *irk; bool match; u32 flags; + /* Check if we need to convert to identity address */ + irk = hci_get_irk(hdev, bdaddr, bdaddr_type); + if (irk) { + bdaddr = &irk->bdaddr; + bdaddr_type = irk->addr_type; + } + + /* Check if we have been requested to connect to this device */ + check_pending_le_conn(hdev, bdaddr, bdaddr_type, type); + /* Passive scanning shouldn't trigger any device found events, * except for devices marked as CONN_REPORT for which we do send * device found events. */ if (hdev->le_scan_type == LE_SCAN_PASSIVE) { struct hci_conn_params *param; - struct smp_irk *irk; - - /* Check if we need to convert to identity address */ - irk = hci_get_irk(hdev, bdaddr, bdaddr_type); - if (irk) { - bdaddr = &irk->bdaddr; - bdaddr_type = irk->addr_type; - } - - /* Ignore if the device is blocked */ - if (hci_blacklist_lookup(hdev, bdaddr, bdaddr_type)) - return; - - if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND) { - if (check_pending_le_conn(hdev, bdaddr, bdaddr_type)) - return; - } if (type == LE_ADV_DIRECT_IND) return; -- cgit v1.2.3 From 841c564499dca9f4819ae2a5f5beb31694f9634e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 7 Jul 2014 12:45:54 +0300 Subject: Bluetooth: Remove redundant IRK lookup in mgmt_device_found() Now that we have the process_adv_report() function doing the IRK lookup and updating the bdaddr we don't need to do this anymore in mgmt.c in the mgmt_device_found() function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index be91d55c258b..40244fc0e326 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6717,7 +6717,6 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, { char buf[512]; struct mgmt_ev_device_found *ev = (void *) buf; - struct smp_irk *irk; size_t ev_size; /* Don't send events for a non-kernel initiated discovery. With @@ -6739,15 +6738,8 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, memset(buf, 0, sizeof(buf)); - irk = hci_get_irk(hdev, bdaddr, addr_type); - if (irk) { - bacpy(&ev->addr.bdaddr, &irk->bdaddr); - ev->addr.type = link_to_bdaddr(link_type, irk->addr_type); - } else { - bacpy(&ev->addr.bdaddr, bdaddr); - ev->addr.type = link_to_bdaddr(link_type, addr_type); - } - + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = link_to_bdaddr(link_type, addr_type); ev->rssi = rssi; ev->flags = cpu_to_le32(flags); -- cgit v1.2.3 From 7e899c94939b928173d76d1e5a7c0675f44813f5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 7 Jul 2014 12:45:55 +0300 Subject: Bluetooth: Remove unnecessary return value from check_pending_le_conn Since the only caller of this function doesn't care about the return value anymore let's just remove it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8a36abb3cb06..84f4659f136e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4228,18 +4228,18 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, } /* This function requires the caller holds hdev->lock */ -static bool check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, +static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, u8 adv_type) { struct hci_conn *conn; /* If the event is not connectable don't proceed further */ if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND) - return false; + return; /* Ignore if the device is blocked */ if (hci_blacklist_lookup(hdev, addr, addr_type)) - return false; + return; /* If we're connectable, always connect any ADV_DIRECT_IND event */ if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && @@ -4250,13 +4250,13 @@ static bool check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, * our pend_le_conns list. */ if (!hci_pend_le_action_lookup(&hdev->pend_le_conns, addr, addr_type)) - return false; + return; connect: conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, HCI_AT_NO_BONDING, HCI_LE_AUTOCONN_TIMEOUT); if (!IS_ERR(conn)) - return true; + return; switch (PTR_ERR(conn)) { case -EBUSY: @@ -4269,8 +4269,6 @@ connect: default: BT_DBG("Failed to connect: err %ld", PTR_ERR(conn)); } - - return true; } static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, -- cgit v1.2.3 From bb3e0a336ae683332c1282d1e84b371b65aba1b4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 7 Jul 2014 13:24:58 +0300 Subject: Bluetooth: Update discovery state earlier in hci_discovery_set_state In a subsequent patch the hci_update_background_scan() function will depend on being able to know the current discovery state. For this to be possible we need to set the new state early in the function. Since we also need to check what the old state was this patch introduces an extra variable for tracking it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 623ffe0da4a6..6a0e39f69e03 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1903,16 +1903,20 @@ bool hci_discovery_active(struct hci_dev *hdev) void hci_discovery_set_state(struct hci_dev *hdev, int state) { + int old_state = hdev->discovery.state; + BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state); - if (hdev->discovery.state == state) + if (old_state == state) return; + hdev->discovery.state = state; + switch (state) { case DISCOVERY_STOPPED: hci_update_background_scan(hdev); - if (hdev->discovery.state != DISCOVERY_STARTING) + if (old_state != DISCOVERY_STARTING) mgmt_discovering(hdev, 0); break; case DISCOVERY_STARTING: @@ -1925,8 +1929,6 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) case DISCOVERY_STOPPING: break; } - - hdev->discovery.state = state; } void hci_inquiry_cache_flush(struct hci_dev *hdev) -- cgit v1.2.3 From ae23ada43d7d644e563a23d4c2cd2aa828be1431 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 7 Jul 2014 13:24:59 +0300 Subject: Bluetooth: Don't let background scanning interfering with discovery If we have an active discovery going on we shouldn't do any changes to LE scanning when hci_update_background_scan() is called (a call which can happen for many different reasons). This patch fixes the issue by returning from the function if the discovery state is anything else except DISCOVERY_STOPPED. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6a0e39f69e03..4f8ba49ac49d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5403,6 +5403,10 @@ void hci_update_background_scan(struct hci_dev *hdev) test_bit(HCI_UNREGISTER, &hdev->dev_flags)) return; + /* If discovery is active don't interfere with it */ + if (hdev->discovery.state != DISCOVERY_STOPPED) + return; + hci_req_init(&req, hdev); if (list_empty(&hdev->pend_le_conns) && -- cgit v1.2.3 From 2b7be33e60c631b3080099baf14c43505fa8017d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 7 Jul 2014 14:40:22 +0300 Subject: Bluetooth: Enable passive scanning whenever we're connectable Enabling passive scanning always when we're connectable aligns us with the BR/EDR page scanning. This is also consistent with the fact that the code dealing with passive scanning results will actively try to connect any direct advertising event when we're connectable. This patch implements the feature by adding the connectable condition to hci_update_background_scan() checks for starting scanning and by calling hci_update_background_scan() whenever the connectable state changes. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 3 ++- net/bluetooth/mgmt.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 4f8ba49ac49d..6790dc8cff99 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5409,7 +5409,8 @@ void hci_update_background_scan(struct hci_dev *hdev) hci_req_init(&req, hdev); - if (list_empty(&hdev->pend_le_conns) && + if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && + list_empty(&hdev->pend_le_conns) && list_empty(&hdev->pend_le_reports)) { /* If there is no pending LE connections or devices * to be scanned for, we should stop the background diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 40244fc0e326..ef675acbcfce 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1750,8 +1750,10 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status) send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev); - if (changed) + if (changed) { new_settings(hdev, cmd->sk); + hci_update_background_scan(hdev); + } remove_cmd: mgmt_pending_remove(cmd); -- cgit v1.2.3 From d93375a82da10cb023afc945fa18471bf3c41704 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 7 Jul 2014 15:02:27 +0300 Subject: Bluetooth: Remove auth_type parameter from hci_connect_le() The auth_type value which gets assigned to hci_conn->auth_type is something that's only used for BR/EDR connections and is of no value for LE connections. It makes therefore little sense to pass it to the hci_connect_le() function. This patch removes the parameter from the function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 +-- net/bluetooth/hci_conn.c | 5 +---- net/bluetooth/hci_event.c | 2 +- net/bluetooth/l2cap_core.c | 6 ++---- net/bluetooth/mgmt.c | 3 +-- 5 files changed, 6 insertions(+), 13 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 06039aae3010..8752ac674db1 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -704,8 +704,7 @@ void hci_chan_list_flush(struct hci_conn *conn); struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle); struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, - u8 dst_type, u8 sec_level, u8 auth_type, - u16 conn_timeout); + u8 dst_type, u8 sec_level, u16 conn_timeout); struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, u8 sec_level, u8 auth_type); struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index faa032fcdaee..9323044f01cd 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -700,8 +700,7 @@ static void hci_req_directed_advertising(struct hci_request *req, } struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, - u8 dst_type, u8 sec_level, u8 auth_type, - u16 conn_timeout) + u8 dst_type, u8 sec_level, u16 conn_timeout) { struct hci_conn_params *params; struct hci_conn *conn; @@ -721,7 +720,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); if (conn) { conn->pending_sec_level = sec_level; - conn->auth_type = auth_type; goto done; } @@ -758,7 +756,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, conn->dst_type = dst_type; conn->sec_level = BT_SECURITY_LOW; conn->pending_sec_level = sec_level; - conn->auth_type = auth_type; conn->conn_timeout = conn_timeout; hci_req_init(&req, hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 84f4659f136e..ad39d9ad6fbc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4254,7 +4254,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, connect: conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, - HCI_AT_NO_BONDING, HCI_LE_AUTOCONN_TIMEOUT); + HCI_LE_AUTOCONN_TIMEOUT); if (!IS_ERR(conn)) return; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a219276d9f92..3daab4588522 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7048,7 +7048,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, struct l2cap_conn *conn; struct hci_conn *hcon; struct hci_dev *hdev; - __u8 auth_type; int err; BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst, @@ -7124,8 +7123,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, chan->psm = psm; chan->dcid = cid; - auth_type = l2cap_get_auth_type(chan); - if (bdaddr_type_is_le(dst_type)) { /* Convert from L2CAP channel address type to HCI address type */ @@ -7135,8 +7132,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, dst_type = ADDR_LE_DEV_RANDOM; hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level, - auth_type, HCI_LE_CONN_TIMEOUT); + HCI_LE_CONN_TIMEOUT); } else { + u8 auth_type = l2cap_get_auth_type(chan); hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ef675acbcfce..e7047de1ba11 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3118,8 +3118,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type); conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type, - sec_level, auth_type, - HCI_LE_CONN_TIMEOUT); + sec_level, HCI_LE_CONN_TIMEOUT); } if (IS_ERR(conn)) { -- cgit v1.2.3 From cdd6275e510bd86c44d3fc85a78306f514bbac9a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 7 Jul 2014 15:02:28 +0300 Subject: Bluetooth: Pass desired connection role to hci_connect_le() If we have both LE scanning and advertising simultaneously enabled we need a way to tell hci_connect_le() in which role to initiate a connection. This patch adds a new parameter to the function to give it the necessary information. For auto-connect and mgmt_pair_device we always use master role, whereas for L2CAP users (in practice sockets) we use slave role whenever HCI_ADVERTISING is set and master role otherwise. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 ++- net/bluetooth/hci_conn.c | 6 ++++-- net/bluetooth/hci_event.c | 3 ++- net/bluetooth/l2cap_core.c | 6 +++++- net/bluetooth/mgmt.c | 3 ++- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8752ac674db1..5701d15779dd 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -704,7 +704,8 @@ void hci_chan_list_flush(struct hci_conn *conn); struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle); struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, - u8 dst_type, u8 sec_level, u16 conn_timeout); + u8 dst_type, u8 sec_level, u16 conn_timeout, + bool master); struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, u8 sec_level, u8 auth_type); struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 9323044f01cd..16fd55da9c1d 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -700,7 +700,8 @@ static void hci_req_directed_advertising(struct hci_request *req, } struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, - u8 dst_type, u8 sec_level, u16 conn_timeout) + u8 dst_type, u8 sec_level, u16 conn_timeout, + bool master) { struct hci_conn_params *params; struct hci_conn *conn; @@ -760,7 +761,8 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, hci_req_init(&req, hdev); - if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) { + /* If requested to connect as slave use directed advertising */ + if (!master) { hci_req_directed_advertising(&req, conn); goto create_conn; } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ad39d9ad6fbc..a6816498b0b9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4253,8 +4253,9 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, return; connect: + /* Request connection in master = true role */ conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, - HCI_LE_AUTOCONN_TIMEOUT); + HCI_LE_AUTOCONN_TIMEOUT, true); if (!IS_ERR(conn)) return; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3daab4588522..bf379a379fa0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7124,6 +7124,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, chan->dcid = cid; if (bdaddr_type_is_le(dst_type)) { + bool master; + /* Convert from L2CAP channel address type to HCI address type */ if (dst_type == BDADDR_LE_PUBLIC) @@ -7131,8 +7133,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, else dst_type = ADDR_LE_DEV_RANDOM; + master = !test_bit(HCI_ADVERTISING, &hdev->dev_flags); + hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level, - HCI_LE_CONN_TIMEOUT); + HCI_LE_CONN_TIMEOUT, master); } else { u8 auth_type = l2cap_get_auth_type(chan); hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e7047de1ba11..b391e2fef4b6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3117,8 +3117,9 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, */ hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type); + /* Request a connection with master = true role */ conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type, - sec_level, HCI_LE_CONN_TIMEOUT); + sec_level, HCI_LE_CONN_TIMEOUT, true); } if (IS_ERR(conn)) { -- cgit v1.2.3 From a70f4b5f14a029c14c3901f429e4d3d7e5477b4f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 7 Jul 2014 15:19:50 +0300 Subject: Bluetooth: Don't try background scanning if LE is not enabled For adapters that do not support LE and ones where LE hasn't been enabled we shouldn't be trying to initiate background scanning. This patch adds an extra check to the hci_update_background_scan() to ensure that we bail out if HCI_LE_ENABLED is not set. Since we do allow user space to feed the kernel with LE connection parameters even when LE is not enabled we now need to also call hci_update_background_scan() as soon as LE gets enabled so that scanning gets started if necessary. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 4 ++++ net/bluetooth/mgmt.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6790dc8cff99..f1c5a077e558 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5403,6 +5403,10 @@ void hci_update_background_scan(struct hci_dev *hdev) test_bit(HCI_UNREGISTER, &hdev->dev_flags)) return; + /* No point in doing scanning if LE support hasn't been enabled */ + if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) + return; + /* If discovery is active don't interfere with it */ if (hdev->discovery.state != DISCOVERY_STOPPED) return; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b391e2fef4b6..9cc7108f4c45 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2152,6 +2152,8 @@ static void le_enable_complete(struct hci_dev *hdev, u8 status) update_scan_rsp_data(&req); hci_req_run(&req, NULL); + hci_update_background_scan(hdev); + hci_dev_unlock(hdev); } } -- cgit v1.2.3 From 0ea8d0432c09f240b8dfdec0dc0e4abaf422b838 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 2 Apr 2014 09:31:36 +0300 Subject: iwlwifi: mvm: BT Coex - prepare towards new API A new API is coming. This new API is not backward compatible. So we need to keep the old commands to be able to work with the former API. Move all the current code into a new file: coex_legacy. If a firmware with the new API is detected, we currently just bail out since the implementation of the new API will come in future patches. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw.h | 2 + drivers/net/wireless/iwlwifi/mvm/Makefile | 2 +- drivers/net/wireless/iwlwifi/mvm/coex.c | 84 +- drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 1332 ++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 4 +- drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | 36 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 26 +- 7 files changed, 1448 insertions(+), 38 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/mvm/coex_legacy.c diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 92d5e75a6b1f..79b0508fddef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -121,12 +121,14 @@ enum iwl_ucode_tlv_flag { * enum iwl_ucode_tlv_api - ucode api * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. * @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification + * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1), + IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), }; diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index c30d7f64ec1e..a28235913c2c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o iwlmvm-y += scan.o time-event.o rs.o -iwlmvm-y += power.o coex.o +iwlmvm-y += power.o coex.o coex_legacy.o iwlmvm-y += tt.o offloading.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 7e0388a32912..f471de3373c9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -561,7 +561,7 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) int iwl_send_bt_init_conf(struct iwl_mvm *mvm) { - struct iwl_bt_coex_cmd *bt_cmd; + struct iwl_bt_coex_cmd_old *bt_cmd; struct iwl_host_cmd cmd = { .id = BT_CONFIG, .len = { sizeof(*bt_cmd), }, @@ -570,6 +570,12 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) int ret; u32 flags; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_send_bt_init_conf_old(mvm); + + /* TODO */ + return 0; + ret = iwl_send_bt_prio_tbl(mvm); if (ret) return ret; @@ -584,13 +590,13 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) { switch (mvm->bt_force_ant_mode) { case BT_FORCE_ANT_AUTO: - flags = BT_COEX_AUTO; + flags = BT_COEX_AUTO_OLD; break; case BT_FORCE_ANT_BT: - flags = BT_COEX_BT; + flags = BT_COEX_BT_OLD; break; case BT_FORCE_ANT_WIFI: - flags = BT_COEX_WIFI; + flags = BT_COEX_WIFI_OLD; break; default: WARN_ON(1); @@ -611,7 +617,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) bt_cmd->override_secondary_lut = BT_COEX_INVALID_LUT; flags = iwlwifi_mod_params.bt_coex_active ? - BT_COEX_NW : BT_COEX_DISABLE; + BT_COEX_NW_OLD : BT_COEX_DISABLE_OLD; bt_cmd->flags = cpu_to_le32(flags); bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE | @@ -680,8 +686,8 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, bool reduced_tx_power) { enum iwl_bt_kill_msk bt_kill_msk; - struct iwl_bt_coex_cmd *bt_cmd; - struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; + struct iwl_bt_coex_cmd_old *bt_cmd; + struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif; struct iwl_host_cmd cmd = { .id = BT_CONFIG, .data[0] = &bt_cmd, @@ -722,7 +728,7 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, if (!bt_cmd) return -ENOMEM; cmd.data[0] = bt_cmd; - bt_cmd->flags = cpu_to_le32(BT_COEX_NW); + bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); @@ -743,7 +749,7 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable) { - struct iwl_bt_coex_cmd *bt_cmd; + struct iwl_bt_coex_cmd_old *bt_cmd; /* Send ASYNC since this can be sent from an atomic context */ struct iwl_host_cmd cmd = { .id = BT_CONFIG, @@ -766,7 +772,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, if (!bt_cmd) return -ENOMEM; cmd.data[0] = bt_cmd; - bt_cmd->flags = cpu_to_le32(BT_COEX_NW); + bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE | BT_VALID_REDUCED_TX_POWER); @@ -787,7 +793,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, } struct iwl_bt_iterator_data { - struct iwl_bt_coex_profile_notif *notif; + struct iwl_bt_coex_profile_notif_old *notif; struct iwl_mvm *mvm; u32 num_bss_ifaces; bool reduced_tx_power; @@ -977,7 +983,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) .notif = &mvm->last_bt_notif, .reduced_tx_power = true, }; - struct iwl_bt_coex_ci_cmd cmd = {}; + struct iwl_bt_coex_ci_cmd_old cmd = {}; u8 ci_bw_idx; /* Ignore updates if we are in force mode */ @@ -1063,8 +1069,13 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, struct iwl_device_cmd *dev_cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; + struct iwl_bt_coex_profile_notif_old *notif = (void *)pkt->data; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_mvm_rx_bt_coex_notif_old(mvm, rxb, dev_cmd); + + /* TODO */ + return 0; IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); IWL_DEBUG_COEX(mvm, "\tBT status: %s\n", @@ -1148,6 +1159,14 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, }; int ret; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { + iwl_mvm_bt_rssi_event_old(mvm, vif, rssi_event); + return; + } + + /* TODO */ + return; + lockdep_assert_held(&mvm->mutex); /* Ignore updates if we are in force mode */ @@ -1206,6 +1225,12 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); enum iwl_bt_coex_lut_type lut_type; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_mvm_coex_agg_time_limit_old(mvm, sta); + + /* TODO */ + return LINK_QUAL_AGG_TIME_LIMIT_DEF; + if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC) return LINK_QUAL_AGG_TIME_LIMIT_DEF; @@ -1228,6 +1253,12 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); enum iwl_bt_coex_lut_type lut_type; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_mvm_coex_agg_time_limit_old(mvm, sta); + + return true; + + /* TODO */ if (mvm->last_bt_notif.ttc_enabled) return true; @@ -1248,6 +1279,9 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) { + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm); + return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF; } @@ -1256,6 +1290,12 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, { u32 bt_activity = le32_to_cpu(mvm->last_bt_notif.bt_activity_grading); + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_mvm_bt_coex_is_tpc_allowed_old(mvm, band); + + /* TODO */ + return false; + if (band != IEEE80211_BAND_2GHZ) return false; @@ -1296,6 +1336,14 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) { + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { + iwl_mvm_bt_coex_vif_change_old(mvm); + return; + } + + /* TODO */ + return; + iwl_mvm_bt_coex_notif_handle(mvm); } @@ -1309,13 +1357,19 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, int ret; u8 lut; - struct iwl_bt_coex_cmd *bt_cmd; + struct iwl_bt_coex_cmd_old *bt_cmd; struct iwl_host_cmd cmd = { .id = BT_CONFIG, .len = { sizeof(*bt_cmd), }, .dataflags = { IWL_HCMD_DFL_NOCOPY, }, }; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) + return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd); + + /* TODO */ + return 0; + if (!IWL_MVM_BT_COEX_CORUNNING) return 0; @@ -1354,7 +1408,7 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, return 0; cmd.data[0] = bt_cmd; - bt_cmd->flags = cpu_to_le32(BT_COEX_NW); + bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | BT_VALID_CORUN_LUT_20 | BT_VALID_CORUN_LUT_40); diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c new file mode 100644 index 000000000000..ce50363d314b --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -0,0 +1,1332 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include +#include +#include + +#include "fw-api-coex.h" +#include "iwl-modparams.h" +#include "mvm.h" +#include "iwl-debug.h" + +#define EVENT_PRIO_ANT(_evt, _prio, _shrd_ant) \ + [(_evt)] = (((_prio) << BT_COEX_PRIO_TBL_PRIO_POS) | \ + ((_shrd_ant) << BT_COEX_PRIO_TBL_SHRD_ANT_POS)) + +static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { + EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB1, + BT_COEX_PRIO_TBL_PRIO_BYPASS, 0), + EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB2, + BT_COEX_PRIO_TBL_PRIO_BYPASS, 1), + EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1, + BT_COEX_PRIO_TBL_PRIO_LOW, 0), + EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2, + BT_COEX_PRIO_TBL_PRIO_LOW, 1), + EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1, + BT_COEX_PRIO_TBL_PRIO_HIGH, 0), + EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2, + BT_COEX_PRIO_TBL_PRIO_HIGH, 1), + EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_DTIM, + BT_COEX_PRIO_TBL_DISABLED, 0), + EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN52, + BT_COEX_PRIO_TBL_PRIO_COEX_OFF, 0), + EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN24, + BT_COEX_PRIO_TBL_PRIO_COEX_ON, 0), + EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_IDLE, + BT_COEX_PRIO_TBL_PRIO_COEX_IDLE, 0), + 0, 0, 0, 0, 0, 0, +}; + +#undef EVENT_PRIO_ANT + +#define BT_ANTENNA_COUPLING_THRESHOLD (30) + +static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) +{ + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) + return 0; + + return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, 0, + sizeof(struct iwl_bt_coex_prio_tbl_cmd), + &iwl_bt_prio_tbl); +} + +static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = { + cpu_to_le32(0xf0f0f0f0), /* 50% */ + cpu_to_le32(0xc0c0c0c0), /* 25% */ + cpu_to_le32(0xfcfcfcfc), /* 75% */ + cpu_to_le32(0xfefefefe), /* 87.5% */ +}; + +static const __le32 iwl_single_shared_ant[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = { + { + cpu_to_le32(0x40000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0x44000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0x40000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0x44000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0xc0004000), + cpu_to_le32(0xf0005000), + cpu_to_le32(0xc0004000), + cpu_to_le32(0xf0005000), + }, + { + cpu_to_le32(0x40000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0x44000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0x40000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0x44000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0xc0004000), + cpu_to_le32(0xf0005000), + cpu_to_le32(0xc0004000), + cpu_to_le32(0xf0005000), + }, + { + cpu_to_le32(0x40000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0x44000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0x40000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0x44000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0xc0004000), + cpu_to_le32(0xf0005000), + cpu_to_le32(0xc0004000), + cpu_to_le32(0xf0005000), + }, +}; + +static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = { + { + /* Tight */ + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xaeaaaaaa), + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xcc00ff28), + cpu_to_le32(0x0000aaaa), + cpu_to_le32(0xcc00aaaa), + cpu_to_le32(0x0000aaaa), + cpu_to_le32(0xc0004000), + cpu_to_le32(0x00004000), + cpu_to_le32(0xf0005000), + cpu_to_le32(0xf0005000), + }, + { + /* Loose */ + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xcc00ff28), + cpu_to_le32(0x0000aaaa), + cpu_to_le32(0xcc00aaaa), + cpu_to_le32(0x0000aaaa), + cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0xf0005000), + cpu_to_le32(0xf0005000), + }, + { + /* Tx Tx disabled */ + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xeeaaaaaa), + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xcc00ff28), + cpu_to_le32(0x0000aaaa), + cpu_to_le32(0xcc00aaaa), + cpu_to_le32(0x0000aaaa), + cpu_to_le32(0xc0004000), + cpu_to_le32(0xc0004000), + cpu_to_le32(0xf0005000), + cpu_to_le32(0xf0005000), + }, +}; + +/* 20MHz / 40MHz below / 40Mhz above*/ +static const __le64 iwl_ci_mask[][3] = { + /* dummy entry for channel 0 */ + {cpu_to_le64(0), cpu_to_le64(0), cpu_to_le64(0)}, + { + cpu_to_le64(0x0000001FFFULL), + cpu_to_le64(0x0ULL), + cpu_to_le64(0x00007FFFFFULL), + }, + { + cpu_to_le64(0x000000FFFFULL), + cpu_to_le64(0x0ULL), + cpu_to_le64(0x0003FFFFFFULL), + }, + { + cpu_to_le64(0x000003FFFCULL), + cpu_to_le64(0x0ULL), + cpu_to_le64(0x000FFFFFFCULL), + }, + { + cpu_to_le64(0x00001FFFE0ULL), + cpu_to_le64(0x0ULL), + cpu_to_le64(0x007FFFFFE0ULL), + }, + { + cpu_to_le64(0x00007FFF80ULL), + cpu_to_le64(0x00007FFFFFULL), + cpu_to_le64(0x01FFFFFF80ULL), + }, + { + cpu_to_le64(0x0003FFFC00ULL), + cpu_to_le64(0x0003FFFFFFULL), + cpu_to_le64(0x0FFFFFFC00ULL), + }, + { + cpu_to_le64(0x000FFFF000ULL), + cpu_to_le64(0x000FFFFFFCULL), + cpu_to_le64(0x3FFFFFF000ULL), + }, + { + cpu_to_le64(0x007FFF8000ULL), + cpu_to_le64(0x007FFFFFE0ULL), + cpu_to_le64(0xFFFFFF8000ULL), + }, + { + cpu_to_le64(0x01FFFE0000ULL), + cpu_to_le64(0x01FFFFFF80ULL), + cpu_to_le64(0xFFFFFE0000ULL), + }, + { + cpu_to_le64(0x0FFFF00000ULL), + cpu_to_le64(0x0FFFFFFC00ULL), + cpu_to_le64(0x0ULL), + }, + { + cpu_to_le64(0x3FFFC00000ULL), + cpu_to_le64(0x3FFFFFF000ULL), + cpu_to_le64(0x0) + }, + { + cpu_to_le64(0xFFFE000000ULL), + cpu_to_le64(0xFFFFFF8000ULL), + cpu_to_le64(0x0) + }, + { + cpu_to_le64(0xFFF8000000ULL), + cpu_to_le64(0xFFFFFE0000ULL), + cpu_to_le64(0x0) + }, + { + cpu_to_le64(0xFFC0000000ULL), + cpu_to_le64(0x0ULL), + cpu_to_le64(0x0ULL) + }, +}; + +static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = { + cpu_to_le32(0x28412201), + cpu_to_le32(0x11118451), +}; + +struct corunning_block_luts { + u8 range; + __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; +}; + +/* + * Ranges for the antenna coupling calibration / co-running block LUT: + * LUT0: [ 0, 12[ + * LUT1: [12, 20[ + * LUT2: [20, 21[ + * LUT3: [21, 23[ + * LUT4: [23, 27[ + * LUT5: [27, 30[ + * LUT6: [30, 32[ + * LUT7: [32, 33[ + * LUT8: [33, - [ + */ +static const struct corunning_block_luts antenna_coupling_ranges[] = { + { + .range = 0, + .lut20 = { + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 12, + .lut20 = { + cpu_to_le32(0x00000001), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 20, + .lut20 = { + cpu_to_le32(0x00000002), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 21, + .lut20 = { + cpu_to_le32(0x00000003), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 23, + .lut20 = { + cpu_to_le32(0x00000004), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 27, + .lut20 = { + cpu_to_le32(0x00000005), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 30, + .lut20 = { + cpu_to_le32(0x00000006), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 32, + .lut20 = { + cpu_to_le32(0x00000007), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, + { + .range = 33, + .lut20 = { + cpu_to_le32(0x00000008), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), + }, + }, +}; + +static enum iwl_bt_coex_lut_type +iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) +{ + struct ieee80211_chanctx_conf *chanctx_conf; + enum iwl_bt_coex_lut_type ret; + u16 phy_ctx_id; + + /* + * Checking that we hold mvm->mutex is a good idea, but the rate + * control can't acquire the mutex since it runs in Tx path. + * So this is racy in that case, but in the worst case, the AMPDU + * size limit will be wrong for a short time which is not a big + * issue. + */ + + rcu_read_lock(); + + chanctx_conf = rcu_dereference(vif->chanctx_conf); + + if (!chanctx_conf || + chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) { + rcu_read_unlock(); + return BT_COEX_INVALID_LUT; + } + + ret = BT_COEX_TX_DIS_LUT; + + if (mvm->cfg->bt_shared_single_ant) { + rcu_read_unlock(); + return ret; + } + + phy_ctx_id = *((u16 *)chanctx_conf->drv_priv); + + if (mvm->last_bt_ci_cmd_old.primary_ch_phy_id == phy_ctx_id) + ret = le32_to_cpu(mvm->last_bt_notif_old.primary_ch_lut); + else if (mvm->last_bt_ci_cmd_old.secondary_ch_phy_id == phy_ctx_id) + ret = le32_to_cpu(mvm->last_bt_notif_old.secondary_ch_lut); + /* else - default = TX TX disallowed */ + + rcu_read_unlock(); + + return ret; +} + +int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) +{ + struct iwl_bt_coex_cmd_old *bt_cmd; + struct iwl_host_cmd cmd = { + .id = BT_CONFIG, + .len = { sizeof(*bt_cmd), }, + .dataflags = { IWL_HCMD_DFL_NOCOPY, }, + }; + int ret; + u32 flags; + + ret = iwl_send_bt_prio_tbl(mvm); + if (ret) + return ret; + + bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); + if (!bt_cmd) + return -ENOMEM; + cmd.data[0] = bt_cmd; + + lockdep_assert_held(&mvm->mutex); + + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) { + switch (mvm->bt_force_ant_mode) { + case BT_FORCE_ANT_AUTO: + flags = BT_COEX_AUTO_OLD; + break; + case BT_FORCE_ANT_BT: + flags = BT_COEX_BT_OLD; + break; + case BT_FORCE_ANT_WIFI: + flags = BT_COEX_WIFI_OLD; + break; + default: + WARN_ON(1); + flags = 0; + } + + bt_cmd->flags = cpu_to_le32(flags); + bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE); + goto send_cmd; + } + + bt_cmd->max_kill = 5; + bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD; + bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling; + bt_cmd->bt4_tx_tx_delta_freq_thr = 15; + bt_cmd->bt4_tx_rx_max_freq0 = 15; + bt_cmd->override_primary_lut = BT_COEX_INVALID_LUT; + bt_cmd->override_secondary_lut = BT_COEX_INVALID_LUT; + + flags = iwlwifi_mod_params.bt_coex_active ? + BT_COEX_NW_OLD : BT_COEX_DISABLE_OLD; + bt_cmd->flags = cpu_to_le32(flags); + + bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE | + BT_VALID_BT_PRIO_BOOST | + BT_VALID_MAX_KILL | + BT_VALID_3W_TMRS | + BT_VALID_KILL_ACK | + BT_VALID_KILL_CTS | + BT_VALID_REDUCED_TX_POWER | + BT_VALID_LUT | + BT_VALID_WIFI_RX_SW_PRIO_BOOST | + BT_VALID_WIFI_TX_SW_PRIO_BOOST | + BT_VALID_ANT_ISOLATION | + BT_VALID_ANT_ISOLATION_THRS | + BT_VALID_TXTX_DELTA_FREQ_THRS | + BT_VALID_TXRX_MAX_FREQ_0 | + BT_VALID_SYNC_TO_SCO); + + if (IWL_MVM_BT_COEX_SYNC2SCO) + bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); + + if (IWL_MVM_BT_COEX_CORUNNING) { + bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_CORUN_LUT_20 | + BT_VALID_CORUN_LUT_40); + bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING); + } + + if (IWL_MVM_BT_COEX_MPLUT) { + bt_cmd->flags |= cpu_to_le32(BT_COEX_MPLUT); + bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); + } + + if (mvm->cfg->bt_shared_single_ant) + memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, + sizeof(iwl_single_shared_ant)); + else + memcpy(&bt_cmd->decision_lut, iwl_combined_lookup, + sizeof(iwl_combined_lookup)); + + /* Take first Co-running block LUT to get started */ + memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[0].lut20, + sizeof(bt_cmd->bt4_corun_lut20)); + memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[0].lut20, + sizeof(bt_cmd->bt4_corun_lut40)); + + memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost, + sizeof(iwl_bt_prio_boost)); + memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, + sizeof(iwl_bt_mprio_lut)); + bt_cmd->kill_ack_msk = + cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); + bt_cmd->kill_cts_msk = + cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); + +send_cmd: + memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); + memset(&mvm->last_bt_ci_cmd_old, 0, sizeof(mvm->last_bt_ci_cmd_old)); + + ret = iwl_mvm_send_cmd(mvm, &cmd); + + kfree(bt_cmd); + return ret; +} + +static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, + bool reduced_tx_power) +{ + enum iwl_bt_kill_msk bt_kill_msk; + struct iwl_bt_coex_cmd_old *bt_cmd; + struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif_old; + struct iwl_host_cmd cmd = { + .id = BT_CONFIG, + .data[0] = &bt_cmd, + .len = { sizeof(*bt_cmd), }, + .dataflags = { IWL_HCMD_DFL_NOCOPY, }, + }; + int ret = 0; + + lockdep_assert_held(&mvm->mutex); + + if (reduced_tx_power) { + /* Reduced Tx power has precedence on the type of the profile */ + bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW; + } else { + /* Low latency BT profile is active: give higher prio to BT */ + if (BT_MBOX_MSG(notif, 3, SCO_STATE) || + BT_MBOX_MSG(notif, 3, A2DP_STATE) || + BT_MBOX_MSG(notif, 3, SNIFF_STATE)) + bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP; + else + bt_kill_msk = BT_KILL_MSK_DEFAULT; + } + + IWL_DEBUG_COEX(mvm, + "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n", + bt_kill_msk, + BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in", + BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in", + BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in"); + + /* Don't send HCMD if there is no update */ + if (bt_kill_msk == mvm->bt_kill_msk) + return 0; + + mvm->bt_kill_msk = bt_kill_msk; + + bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); + if (!bt_cmd) + return -ENOMEM; + cmd.data[0] = bt_cmd; + bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); + + bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); + bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); + bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | + BT_VALID_KILL_ACK | + BT_VALID_KILL_CTS); + + IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n", + iwl_bt_ack_kill_msk[bt_kill_msk], + iwl_bt_cts_kill_msk[bt_kill_msk]); + + ret = iwl_mvm_send_cmd(mvm, &cmd); + + kfree(bt_cmd); + return ret; +} + +static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, + bool enable) +{ + struct iwl_bt_coex_cmd_old *bt_cmd; + /* Send ASYNC since this can be sent from an atomic context */ + struct iwl_host_cmd cmd = { + .id = BT_CONFIG, + .len = { sizeof(*bt_cmd), }, + .dataflags = { IWL_HCMD_DFL_NOCOPY, }, + .flags = CMD_ASYNC, + }; + struct iwl_mvm_sta *mvmsta; + int ret; + + mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); + if (!mvmsta) + return 0; + + /* nothing to do */ + if (mvmsta->bt_reduced_txpower == enable) + return 0; + + bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC); + if (!bt_cmd) + return -ENOMEM; + cmd.data[0] = bt_cmd; + bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); + + bt_cmd->valid_bit_msk = + cpu_to_le32(BT_VALID_ENABLE | BT_VALID_REDUCED_TX_POWER); + bt_cmd->bt_reduced_tx_power = sta_id; + + if (enable) + bt_cmd->bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT; + + IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", + enable ? "en" : "dis", sta_id); + + mvmsta->bt_reduced_txpower = enable; + + ret = iwl_mvm_send_cmd(mvm, &cmd); + + kfree(bt_cmd); + return ret; +} + +struct iwl_bt_iterator_data { + struct iwl_bt_coex_profile_notif_old *notif; + struct iwl_mvm *mvm; + u32 num_bss_ifaces; + bool reduced_tx_power; + struct ieee80211_chanctx_conf *primary; + struct ieee80211_chanctx_conf *secondary; + bool primary_ll; +}; + +static inline +void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + bool enable, int rssi) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + mvmvif->bf_data.last_bt_coex_event = rssi; + mvmvif->bf_data.bt_coex_max_thold = + enable ? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH : 0; + mvmvif->bf_data.bt_coex_min_thold = + enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0; +} + +/* must be called under rcu_read_lock */ +static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_bt_iterator_data *data = _data; + struct iwl_mvm *mvm = data->mvm; + struct ieee80211_chanctx_conf *chanctx_conf; + enum ieee80211_smps_mode smps_mode; + u32 bt_activity_grading; + int ave_rssi; + + lockdep_assert_held(&mvm->mutex); + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + /* Count BSSes vifs */ + data->num_bss_ifaces++; + /* default smps_mode for BSS / P2P client is AUTOMATIC */ + smps_mode = IEEE80211_SMPS_AUTOMATIC; + break; + case NL80211_IFTYPE_AP: + /* default smps_mode for AP / GO is OFF */ + smps_mode = IEEE80211_SMPS_OFF; + if (!mvmvif->ap_ibss_active) { + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, + smps_mode); + return; + } + + /* the Ack / Cts kill mask must be default if AP / GO */ + data->reduced_tx_power = false; + break; + default: + return; + } + + chanctx_conf = rcu_dereference(vif->chanctx_conf); + + /* If channel context is invalid or not on 2.4GHz .. */ + if ((!chanctx_conf || + chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { + /* ... relax constraints and disable rssi events */ + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, + smps_mode); + data->reduced_tx_power = false; + if (vif->type == NL80211_IFTYPE_STATION) { + iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, + false); + iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); + } + return; + } + + bt_activity_grading = le32_to_cpu(data->notif->bt_activity_grading); + if (bt_activity_grading >= BT_HIGH_TRAFFIC) + smps_mode = IEEE80211_SMPS_STATIC; + else if (bt_activity_grading >= BT_LOW_TRAFFIC) + smps_mode = vif->type == NL80211_IFTYPE_AP ? + IEEE80211_SMPS_OFF : + IEEE80211_SMPS_DYNAMIC; + + /* relax SMPS contraints for next association */ + if (!vif->bss_conf.assoc) + smps_mode = IEEE80211_SMPS_AUTOMATIC; + + IWL_DEBUG_COEX(data->mvm, + "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", + mvmvif->id, data->notif->bt_status, bt_activity_grading, + smps_mode); + + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); + + /* low latency is always primary */ + if (iwl_mvm_vif_low_latency(mvmvif)) { + data->primary_ll = true; + + data->secondary = data->primary; + data->primary = chanctx_conf; + } + + if (vif->type == NL80211_IFTYPE_AP) { + if (!mvmvif->ap_ibss_active) + return; + + if (chanctx_conf == data->primary) + return; + + if (!data->primary_ll) { + /* + * downgrade the current primary no matter what its + * type is. + */ + data->secondary = data->primary; + data->primary = chanctx_conf; + } else { + /* there is low latency vif - we will be secondary */ + data->secondary = chanctx_conf; + } + return; + } + + /* + * STA / P2P Client, try to be primary if first vif. If we are in low + * latency mode, we are already in primary and just don't do much + */ + if (!data->primary || data->primary == chanctx_conf) + data->primary = chanctx_conf; + else if (!data->secondary) + /* if secondary is not NULL, it might be a GO */ + data->secondary = chanctx_conf; + + /* + * don't reduce the Tx power if one of these is true: + * we are in LOOSE + * single share antenna product + * BT is active + * we are associated + */ + if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || + mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || + !data->notif->bt_status) { + data->reduced_tx_power = false; + iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); + iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); + return; + } + + /* try to get the avg rssi from fw */ + ave_rssi = mvmvif->bf_data.ave_beacon_signal; + + /* if the RSSI isn't valid, fake it is very low */ + if (!ave_rssi) + ave_rssi = -100; + if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) { + if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) + IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); + + /* + * bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the + * BSS / P2P clients have rssi above threshold. + * We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before + * the iteration, if one interface's rssi isn't good enough, + * bt_kill_msk will be set to default values. + */ + } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) { + if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) + IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); + + /* + * One interface hasn't rssi above threshold, bt_kill_msk must + * be set to default values. + */ + data->reduced_tx_power = false; + } + + /* Begin to monitor the RSSI: it may influence the reduced Tx power */ + iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi); +} + +static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) +{ + struct iwl_bt_iterator_data data = { + .mvm = mvm, + .notif = &mvm->last_bt_notif_old, + .reduced_tx_power = true, + }; + struct iwl_bt_coex_ci_cmd_old cmd = {}; + u8 ci_bw_idx; + + /* Ignore updates if we are in force mode */ + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) + return; + + rcu_read_lock(); + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_bt_notif_iterator, &data); + + if (data.primary) { + struct ieee80211_chanctx_conf *chan = data.primary; + + if (WARN_ON(!chan->def.chan)) { + rcu_read_unlock(); + return; + } + + if (chan->def.width < NL80211_CHAN_WIDTH_40) { + ci_bw_idx = 0; + cmd.co_run_bw_primary = 0; + } else { + cmd.co_run_bw_primary = 1; + if (chan->def.center_freq1 > + chan->def.chan->center_freq) + ci_bw_idx = 2; + else + ci_bw_idx = 1; + } + + cmd.bt_primary_ci = + iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; + cmd.primary_ch_phy_id = *((u16 *)data.primary->drv_priv); + } + + if (data.secondary) { + struct ieee80211_chanctx_conf *chan = data.secondary; + + if (WARN_ON(!data.secondary->def.chan)) { + rcu_read_unlock(); + return; + } + + if (chan->def.width < NL80211_CHAN_WIDTH_40) { + ci_bw_idx = 0; + cmd.co_run_bw_secondary = 0; + } else { + cmd.co_run_bw_secondary = 1; + if (chan->def.center_freq1 > + chan->def.chan->center_freq) + ci_bw_idx = 2; + else + ci_bw_idx = 1; + } + + cmd.bt_secondary_ci = + iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; + cmd.secondary_ch_phy_id = *((u16 *)data.secondary->drv_priv); + } + + rcu_read_unlock(); + + /* Don't spam the fw with the same command over and over */ + if (memcmp(&cmd, &mvm->last_bt_ci_cmd_old, sizeof(cmd))) { + if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_CI, 0, + sizeof(cmd), &cmd)) + IWL_ERR(mvm, "Failed to send BT_CI cmd\n"); + memcpy(&mvm->last_bt_ci_cmd_old, &cmd, sizeof(cmd)); + } + + /* + * If there are no BSS / P2P client interfaces, reduced Tx Power is + * irrelevant since it is based on the RSSI coming from the beacon. + * Use BT_KILL_MSK_DEFAULT in that case. + */ + data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; + + if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) + IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); +} + +int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *dev_cmd) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_bt_coex_profile_notif_old *notif = (void *)pkt->data; + + IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); + IWL_DEBUG_COEX(mvm, "\tBT status: %s\n", + notif->bt_status ? "ON" : "OFF"); + IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn); + IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); + IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n", + le32_to_cpu(notif->primary_ch_lut)); + IWL_DEBUG_COEX(mvm, "\tBT secondary_ch_lut %d\n", + le32_to_cpu(notif->secondary_ch_lut)); + IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n", + le32_to_cpu(notif->bt_activity_grading)); + IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n", + notif->bt_agg_traffic_load); + + /* remember this notification for future use: rssi fluctuations */ + memcpy(&mvm->last_bt_notif_old, notif, sizeof(mvm->last_bt_notif_old)); + + iwl_mvm_bt_coex_notif_handle(mvm); + + /* + * This is an async handler for a notification, returning anything other + * than 0 doesn't make sense even if HCMD failed. + */ + return 0; +} + +static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_bt_iterator_data *data = _data; + struct iwl_mvm *mvm = data->mvm; + + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + + struct ieee80211_chanctx_conf *chanctx_conf; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(vif->chanctx_conf); + /* If channel context is invalid or not on 2.4GHz - don't count it */ + if (!chanctx_conf || + chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) { + rcu_read_unlock(); + return; + } + rcu_read_unlock(); + + if (vif->type != NL80211_IFTYPE_STATION || + mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) + return; + + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], + lockdep_is_held(&mvm->mutex)); + + /* This can happen if the station has been removed right now */ + if (IS_ERR_OR_NULL(sta)) + return; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + + data->num_bss_ifaces++; + + /* + * This interface doesn't support reduced Tx power (because of low + * RSSI probably), then set bt_kill_msk to default values. + */ + if (!mvmsta->bt_reduced_txpower) + data->reduced_tx_power = false; + /* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */ +} + +void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + enum ieee80211_rssi_event rssi_event) +{ + struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_bt_iterator_data data = { + .mvm = mvm, + .reduced_tx_power = true, + }; + int ret; + + lockdep_assert_held(&mvm->mutex); + + /* Ignore updates if we are in force mode */ + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) + return; + + /* + * Rssi update while not associated - can happen since the statistics + * are handled asynchronously + */ + if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) + return; + + /* No BT - reports should be disabled */ + if (!mvm->last_bt_notif_old.bt_status) + return; + + IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid, + rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW"); + + /* + * Check if rssi is good enough for reduced Tx power, but not in loose + * scheme. + */ + if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant || + iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT) + ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, + false); + else + ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true); + + if (ret) + IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n"); + + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_bt_rssi_iterator, &data); + + /* + * If there are no BSS / P2P client interfaces, reduced Tx Power is + * irrelevant since it is based on the RSSI coming from the beacon. + * Use BT_KILL_MSK_DEFAULT in that case. + */ + data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; + + if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) + IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); +} + +#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) +#define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200) + +u16 iwl_mvm_coex_agg_time_limit_old(struct iwl_mvm *mvm, + struct ieee80211_sta *sta) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + enum iwl_bt_coex_lut_type lut_type; + + if (le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading) < + BT_HIGH_TRAFFIC) + return LINK_QUAL_AGG_TIME_LIMIT_DEF; + + if (mvm->last_bt_notif_old.ttc_enabled) + return LINK_QUAL_AGG_TIME_LIMIT_DEF; + + lut_type = iwl_get_coex_type(mvm, mvmsta->vif); + + if (lut_type == BT_COEX_LOOSE_LUT || lut_type == BT_COEX_INVALID_LUT) + return LINK_QUAL_AGG_TIME_LIMIT_DEF; + + /* tight coex, high bt traffic, reduce AGG time limit */ + return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT; +} + +bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm, + struct ieee80211_sta *sta) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + enum iwl_bt_coex_lut_type lut_type; + + if (mvm->last_bt_notif_old.ttc_enabled) + return true; + + if (le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading) < + BT_HIGH_TRAFFIC) + return true; + + /* + * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas + * since BT is already killed. + * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while + * we Tx. + * When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO. + */ + lut_type = iwl_get_coex_type(mvm, mvmsta->vif); + return lut_type != BT_COEX_LOOSE_LUT; +} + +bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm) +{ + u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading); + return ag == BT_OFF; +} + +bool iwl_mvm_bt_coex_is_tpc_allowed_old(struct iwl_mvm *mvm, + enum ieee80211_band band) +{ + u32 bt_activity = + le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading); + + if (band != IEEE80211_BAND_2GHZ) + return false; + + return bt_activity >= BT_LOW_TRAFFIC; +} + +void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm) +{ + iwl_mvm_bt_coex_notif_handle(mvm); +} + +int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *dev_cmd) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + u32 ant_isolation = le32_to_cpup((void *)pkt->data); + u8 __maybe_unused lower_bound, upper_bound; + int ret; + u8 lut; + + struct iwl_bt_coex_cmd_old *bt_cmd; + struct iwl_host_cmd cmd = { + .id = BT_CONFIG, + .len = { sizeof(*bt_cmd), }, + .dataflags = { IWL_HCMD_DFL_NOCOPY, }, + }; + + if (!IWL_MVM_BT_COEX_CORUNNING) + return 0; + + lockdep_assert_held(&mvm->mutex); + + /* Ignore updates if we are in force mode */ + if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) + return 0; + + if (ant_isolation == mvm->last_ant_isol) + return 0; + + for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++) + if (ant_isolation < antenna_coupling_ranges[lut + 1].range) + break; + + lower_bound = antenna_coupling_ranges[lut].range; + + if (lut < ARRAY_SIZE(antenna_coupling_ranges) - 1) + upper_bound = antenna_coupling_ranges[lut + 1].range; + else + upper_bound = antenna_coupling_ranges[lut].range; + + IWL_DEBUG_COEX(mvm, "Antenna isolation=%d in range [%d,%d[, lut=%d\n", + ant_isolation, lower_bound, upper_bound, lut); + + mvm->last_ant_isol = ant_isolation; + + if (mvm->last_corun_lut == lut) + return 0; + + mvm->last_corun_lut = lut; + + bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); + if (!bt_cmd) + return 0; + cmd.data[0] = bt_cmd; + + bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); + bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | + BT_VALID_CORUN_LUT_20 | + BT_VALID_CORUN_LUT_40); + + /* For the moment, use the same LUT for 20GHz and 40GHz */ + memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[lut].lut20, + sizeof(bt_cmd->bt4_corun_lut20)); + + memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20, + sizeof(bt_cmd->bt4_corun_lut40)); + + ret = iwl_mvm_send_cmd(mvm, &cmd); + + kfree(bt_cmd); + return ret; +} diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 602bbd29ec5a..b2c751e71581 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -316,7 +316,7 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; + struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif; char *buf; int ret, pos = 0, bufsz = sizeof(char) * 1024; @@ -411,7 +411,7 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; + struct iwl_bt_coex_ci_cmd_old *cmd = &mvm->last_bt_ci_cmd; char buf[256]; int bufsz = sizeof(buf); int pos = 0; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index 39cb33a19862..b3626cc69052 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h @@ -72,13 +72,13 @@ * enum iwl_bt_coex_flags - flags for BT_COEX command * @BT_COEX_MODE_POS: * @BT_COEX_MODE_MSK: - * @BT_COEX_DISABLE: - * @BT_COEX_2W: - * @BT_COEX_3W: - * @BT_COEX_NW: - * @BT_COEX_AUTO: - * @BT_COEX_BT: Antenna is for BT (manufacuring tests) - * @BT_COEX_WIFI: Antenna is for BT (manufacuring tests) + * @BT_COEX_DISABLE_OLD: + * @BT_COEX_2W_OLD: + * @BT_COEX_3W_OLD: + * @BT_COEX_NW_OLD: + * @BT_COEX_AUTO_OLD: + * @BT_COEX_BT_OLD: Antenna is for BT (manufacuring tests) + * @BT_COEX_WIFI_OLD: Antenna is for BT (manufacuring tests) * @BT_COEX_SYNC2SCO: * @BT_COEX_CORUNNING: * @BT_COEX_MPLUT: @@ -88,13 +88,13 @@ enum iwl_bt_coex_flags { BT_COEX_MODE_POS = 3, BT_COEX_MODE_MSK = BITS(3) << BT_COEX_MODE_POS, - BT_COEX_DISABLE = 0x0 << BT_COEX_MODE_POS, - BT_COEX_2W = 0x1 << BT_COEX_MODE_POS, - BT_COEX_3W = 0x2 << BT_COEX_MODE_POS, - BT_COEX_NW = 0x3 << BT_COEX_MODE_POS, - BT_COEX_AUTO = 0x5 << BT_COEX_MODE_POS, - BT_COEX_BT = 0x6 << BT_COEX_MODE_POS, - BT_COEX_WIFI = 0x7 << BT_COEX_MODE_POS, + BT_COEX_DISABLE_OLD = 0x0 << BT_COEX_MODE_POS, + BT_COEX_2W_OLD = 0x1 << BT_COEX_MODE_POS, + BT_COEX_3W_OLD = 0x2 << BT_COEX_MODE_POS, + BT_COEX_NW_OLD = 0x3 << BT_COEX_MODE_POS, + BT_COEX_AUTO_OLD = 0x5 << BT_COEX_MODE_POS, + BT_COEX_BT_OLD = 0x6 << BT_COEX_MODE_POS, + BT_COEX_WIFI_OLD = 0x7 << BT_COEX_MODE_POS, BT_COEX_SYNC2SCO = BIT(7), BT_COEX_CORUNNING = BIT(8), BT_COEX_MPLUT = BIT(9), @@ -157,7 +157,7 @@ enum iwl_bt_coex_lut_type { #define BT_REDUCED_TX_POWER_BIT BIT(7) /** - * struct iwl_bt_coex_cmd - bt coex configuration command + * struct iwl_bt_coex_cmd_old - bt coex configuration command * @flags:&enum iwl_bt_coex_flags * @max_kill: * @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power @@ -182,7 +182,7 @@ enum iwl_bt_coex_lut_type { * * The structure is used for the BT_COEX command. */ -struct iwl_bt_coex_cmd { +struct iwl_bt_coex_cmd_old { __le32 flags; u8 max_kill; u8 bt_reduced_tx_power; @@ -219,7 +219,7 @@ struct iwl_bt_coex_cmd { * * Used for BT_COEX_CI command */ -struct iwl_bt_coex_ci_cmd { +struct iwl_bt_coex_ci_cmd_old { __le64 bt_primary_ci; __le64 bt_secondary_ci; @@ -310,7 +310,7 @@ enum iwl_bt_activity_grading { * @secondary_ch_lut: LUT used for secondary channel * @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading */ -struct iwl_bt_coex_profile_notif { +struct iwl_bt_coex_profile_notif_old { __le32 mbox_msg[4]; __le32 msg_idx; u8 bt_status; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 6fe93a7335c1..0b52d0ae4a0d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -630,8 +630,12 @@ struct iwl_mvm { /* BT-Coex */ u8 bt_kill_msk; - struct iwl_bt_coex_profile_notif last_bt_notif; - struct iwl_bt_coex_ci_cmd last_bt_ci_cmd; + + struct iwl_bt_coex_profile_notif_old last_bt_notif_old; + struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd_old; + struct iwl_bt_coex_profile_notif_old last_bt_notif; + struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd; + u32 last_ant_isol; u8 last_corun_lut; u8 bt_tx_prio; @@ -974,6 +978,24 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *info, u8 ac); +bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm); +void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm); +int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm); +int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd); +void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + enum ieee80211_rssi_event rssi_event); +u16 iwl_mvm_coex_agg_time_limit_old(struct iwl_mvm *mvm, + struct ieee80211_sta *sta); +bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm, + struct ieee80211_sta *sta); +bool iwl_mvm_bt_coex_is_tpc_allowed_old(struct iwl_mvm *mvm, + enum ieee80211_band band); +int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd); + enum iwl_bt_kill_msk { BT_KILL_MSK_DEFAULT, BT_KILL_MSK_SCO_HID_A2DP, -- cgit v1.2.3 From 430a3bbafdc78e30307e6eacb90980f29719d91c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 2 Apr 2014 09:55:16 +0300 Subject: iwlwifi: mvm: BT Coex - new API Start the new BT Coex implementation. Don't react to notifications for now - only the initial configuration is implemented. The rest will happen in next patches. Since coex.c now uses the new the new structures in all functions, we need to adapt the code to compile, even if it doesn't run yet. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 181 +++++++---------------- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 22 +-- drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | 193 +++++++++++++++++++++---- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 5 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 +- drivers/net/wireless/iwlwifi/mvm/ops.c | 3 + 6 files changed, 233 insertions(+), 175 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index f471de3373c9..f8c293e54b5e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -70,48 +70,8 @@ #include "mvm.h" #include "iwl-debug.h" -#define EVENT_PRIO_ANT(_evt, _prio, _shrd_ant) \ - [(_evt)] = (((_prio) << BT_COEX_PRIO_TBL_PRIO_POS) | \ - ((_shrd_ant) << BT_COEX_PRIO_TBL_SHRD_ANT_POS)) - -static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB1, - BT_COEX_PRIO_TBL_PRIO_BYPASS, 0), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB2, - BT_COEX_PRIO_TBL_PRIO_BYPASS, 1), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1, - BT_COEX_PRIO_TBL_PRIO_LOW, 0), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2, - BT_COEX_PRIO_TBL_PRIO_LOW, 1), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1, - BT_COEX_PRIO_TBL_PRIO_HIGH, 0), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2, - BT_COEX_PRIO_TBL_PRIO_HIGH, 1), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_DTIM, - BT_COEX_PRIO_TBL_DISABLED, 0), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN52, - BT_COEX_PRIO_TBL_PRIO_COEX_OFF, 0), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN24, - BT_COEX_PRIO_TBL_PRIO_COEX_ON, 0), - EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_IDLE, - BT_COEX_PRIO_TBL_PRIO_COEX_IDLE, 0), - 0, 0, 0, 0, 0, 0, -}; - -#undef EVENT_PRIO_ANT - #define BT_ANTENNA_COUPLING_THRESHOLD (30) -static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) -{ - if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) - return 0; - - return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, 0, - sizeof(struct iwl_bt_coex_prio_tbl_cmd), - &iwl_bt_prio_tbl); -} - const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = { [BT_KILL_MSK_DEFAULT] = 0xffff0000, [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, @@ -520,6 +480,7 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) struct ieee80211_chanctx_conf *chanctx_conf; enum iwl_bt_coex_lut_type ret; u16 phy_ctx_id; + u32 primary_ch_phy_id, secondary_ch_phy_id; /* * Checking that we hold mvm->mutex is a good idea, but the rate @@ -547,10 +508,13 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) } phy_ctx_id = *((u16 *)chanctx_conf->drv_priv); + primary_ch_phy_id = le32_to_cpu(mvm->last_bt_ci_cmd.primary_ch_phy_id); + secondary_ch_phy_id = + le32_to_cpu(mvm->last_bt_ci_cmd.secondary_ch_phy_id); - if (mvm->last_bt_ci_cmd.primary_ch_phy_id == phy_ctx_id) + if (primary_ch_phy_id == phy_ctx_id) ret = le32_to_cpu(mvm->last_bt_notif.primary_ch_lut); - else if (mvm->last_bt_ci_cmd.secondary_ch_phy_id == phy_ctx_id) + else if (secondary_ch_phy_id == phy_ctx_id) ret = le32_to_cpu(mvm->last_bt_notif.secondary_ch_lut); /* else - default = TX TX disallowed */ @@ -561,25 +525,18 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) int iwl_send_bt_init_conf(struct iwl_mvm *mvm) { - struct iwl_bt_coex_cmd_old *bt_cmd; + struct iwl_bt_coex_cmd *bt_cmd; struct iwl_host_cmd cmd = { .id = BT_CONFIG, .len = { sizeof(*bt_cmd), }, .dataflags = { IWL_HCMD_DFL_NOCOPY, }, }; int ret; - u32 flags; + u32 mode; if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) return iwl_send_bt_init_conf_old(mvm); - /* TODO */ - return 0; - - ret = iwl_send_bt_prio_tbl(mvm); - if (ret) - return ret; - bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); if (!bt_cmd) return -ENOMEM; @@ -588,66 +545,46 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) { + u32 mode; + switch (mvm->bt_force_ant_mode) { - case BT_FORCE_ANT_AUTO: - flags = BT_COEX_AUTO_OLD; - break; case BT_FORCE_ANT_BT: - flags = BT_COEX_BT_OLD; + mode = BT_COEX_BT; break; case BT_FORCE_ANT_WIFI: - flags = BT_COEX_WIFI_OLD; + mode = BT_COEX_WIFI; break; default: WARN_ON(1); - flags = 0; + mode = 0; } - bt_cmd->flags = cpu_to_le32(flags); - bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE); + bt_cmd->mode = cpu_to_le32(mode); goto send_cmd; } - bt_cmd->max_kill = 5; - bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD; - bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling; - bt_cmd->bt4_tx_tx_delta_freq_thr = 15; - bt_cmd->bt4_tx_rx_max_freq0 = 15; - bt_cmd->override_primary_lut = BT_COEX_INVALID_LUT; - bt_cmd->override_secondary_lut = BT_COEX_INVALID_LUT; - - flags = iwlwifi_mod_params.bt_coex_active ? - BT_COEX_NW_OLD : BT_COEX_DISABLE_OLD; - bt_cmd->flags = cpu_to_le32(flags); - - bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE | - BT_VALID_BT_PRIO_BOOST | - BT_VALID_MAX_KILL | - BT_VALID_3W_TMRS | - BT_VALID_KILL_ACK | - BT_VALID_KILL_CTS | - BT_VALID_REDUCED_TX_POWER | - BT_VALID_LUT | - BT_VALID_WIFI_RX_SW_PRIO_BOOST | - BT_VALID_WIFI_TX_SW_PRIO_BOOST | - BT_VALID_ANT_ISOLATION | - BT_VALID_ANT_ISOLATION_THRS | - BT_VALID_TXTX_DELTA_FREQ_THRS | - BT_VALID_TXRX_MAX_FREQ_0 | - BT_VALID_SYNC_TO_SCO); + bt_cmd->max_kill = cpu_to_le32(5); + bt_cmd->bt4_antenna_isolation_thr = + cpu_to_le32(BT_ANTENNA_COUPLING_THRESHOLD); + bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15); + bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15); + bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT); + bt_cmd->override_secondary_lut = cpu_to_le32(BT_COEX_INVALID_LUT); + + mode = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE; + bt_cmd->mode = cpu_to_le32(mode); if (IWL_MVM_BT_COEX_SYNC2SCO) - bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO); + bt_cmd->enabled_modules |= + cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED); - if (IWL_MVM_BT_COEX_CORUNNING) { - bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_CORUN_LUT_20 | - BT_VALID_CORUN_LUT_40); - bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING); - } + if (IWL_MVM_BT_COEX_CORUNNING) + bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_CORUN_ENABLED); if (IWL_MVM_BT_COEX_MPLUT) { - bt_cmd->flags |= cpu_to_le32(BT_COEX_MPLUT); - bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_MULTI_PRIO_LUT); + bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_MPLUT_ENABLED); + bt_cmd->enabled_modules |= + cpu_to_le32(BT_COEX_MPLUT_BOOST_ENABLED); } if (mvm->cfg->bt_shared_single_ant) @@ -657,20 +594,10 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) memcpy(&bt_cmd->decision_lut, iwl_combined_lookup, sizeof(iwl_combined_lookup)); - /* Take first Co-running block LUT to get started */ - memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[0].lut20, - sizeof(bt_cmd->bt4_corun_lut20)); - memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[0].lut20, - sizeof(bt_cmd->bt4_corun_lut40)); - - memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost, + memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost, sizeof(iwl_bt_prio_boost)); - memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, + memcpy(&bt_cmd->multiprio_lut, iwl_bt_mprio_lut, sizeof(iwl_bt_mprio_lut)); - bt_cmd->kill_ack_msk = - cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); - bt_cmd->kill_cts_msk = - cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); send_cmd: memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); @@ -687,7 +614,7 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, { enum iwl_bt_kill_msk bt_kill_msk; struct iwl_bt_coex_cmd_old *bt_cmd; - struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif; + struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; struct iwl_host_cmd cmd = { .id = BT_CONFIG, .data[0] = &bt_cmd, @@ -760,6 +687,8 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, struct iwl_mvm_sta *mvmsta; int ret; + return 0; + mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); if (!mvmsta) return 0; @@ -793,7 +722,7 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, } struct iwl_bt_iterator_data { - struct iwl_bt_coex_profile_notif_old *notif; + struct iwl_bt_coex_profile_notif *notif; struct iwl_mvm *mvm; u32 num_bss_ifaces; bool reduced_tx_power; @@ -883,9 +812,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, smps_mode = IEEE80211_SMPS_AUTOMATIC; IWL_DEBUG_COEX(data->mvm, - "mac %d: bt_status %d bt_activity_grading %d smps_req %d\n", - mvmvif->id, data->notif->bt_status, bt_activity_grading, - smps_mode); + "mac %d: bt_activity_grading %d smps_req %d\n", + mvmvif->id, bt_activity_grading, smps_mode); iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); @@ -937,7 +865,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, */ if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || - !data->notif->bt_status) { + le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) { data->reduced_tx_power = false; iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); @@ -983,7 +911,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) .notif = &mvm->last_bt_notif, .reduced_tx_power = true, }; - struct iwl_bt_coex_ci_cmd_old cmd = {}; + struct iwl_bt_coex_ci_cmd cmd = {}; u8 ci_bw_idx; /* Ignore updates if we are in force mode */ @@ -1004,9 +932,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) if (chan->def.width < NL80211_CHAN_WIDTH_40) { ci_bw_idx = 0; - cmd.co_run_bw_primary = 0; } else { - cmd.co_run_bw_primary = 1; if (chan->def.center_freq1 > chan->def.chan->center_freq) ci_bw_idx = 2; @@ -1016,7 +942,8 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) cmd.bt_primary_ci = iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; - cmd.primary_ch_phy_id = *((u16 *)data.primary->drv_priv); + cmd.primary_ch_phy_id = + cpu_to_le32(*((u16 *)data.primary->drv_priv)); } if (data.secondary) { @@ -1028,9 +955,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) if (chan->def.width < NL80211_CHAN_WIDTH_40) { ci_bw_idx = 0; - cmd.co_run_bw_secondary = 0; } else { - cmd.co_run_bw_secondary = 1; if (chan->def.center_freq1 > chan->def.chan->center_freq) ci_bw_idx = 2; @@ -1040,7 +965,8 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) cmd.bt_secondary_ci = iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx]; - cmd.secondary_ch_phy_id = *((u16 *)data.secondary->drv_priv); + cmd.secondary_ch_phy_id = + cpu_to_le32(*((u16 *)data.secondary->drv_priv)); } rcu_read_unlock(); @@ -1078,9 +1004,6 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, return 0; IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); - IWL_DEBUG_COEX(mvm, "\tBT status: %s\n", - notif->bt_status ? "ON" : "OFF"); - IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn); IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n", le32_to_cpu(notif->primary_ch_lut)); @@ -1088,8 +1011,6 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, le32_to_cpu(notif->secondary_ch_lut)); IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n", le32_to_cpu(notif->bt_activity_grading)); - IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n", - notif->bt_agg_traffic_load); /* remember this notification for future use: rssi fluctuations */ memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif)); @@ -1181,7 +1102,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return; /* No BT - reports should be disabled */ - if (!mvm->last_bt_notif.bt_status) + if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) return; IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid, @@ -1234,9 +1155,11 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC) return LINK_QUAL_AGG_TIME_LIMIT_DEF; - +/* + TODO if (mvm->last_bt_notif.ttc_enabled) return LINK_QUAL_AGG_TIME_LIMIT_DEF; +*/ lut_type = iwl_get_coex_type(mvm, mvmsta->vif); @@ -1256,11 +1179,11 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) return iwl_mvm_coex_agg_time_limit_old(mvm, sta); - return true; - - /* TODO */ +/* + TODO if (mvm->last_bt_notif.ttc_enabled) return true; +*/ if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index b2c751e71581..e66c659b264a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -316,7 +316,7 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif; + struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; char *buf; int ret, pos = 0, bufsz = sizeof(char) * 1024; @@ -378,14 +378,6 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, BT_MBOX_PRINT(3, SSN_2, false); BT_MBOX_PRINT(3, UPDATE_REQUEST, true); - pos += scnprintf(buf+pos, bufsz-pos, "bt_status = %d\n", - notif->bt_status); - pos += scnprintf(buf+pos, bufsz-pos, "bt_open_conn = %d\n", - notif->bt_open_conn); - pos += scnprintf(buf+pos, bufsz-pos, "bt_traffic_load = %d\n", - notif->bt_traffic_load); - pos += scnprintf(buf+pos, bufsz-pos, "bt_agg_traffic_load = %d\n", - notif->bt_agg_traffic_load); pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n", notif->bt_ci_compliance); pos += scnprintf(buf+pos, bufsz-pos, "primary_ch_lut = %d\n", @@ -411,7 +403,7 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - struct iwl_bt_coex_ci_cmd_old *cmd = &mvm->last_bt_ci_cmd; + struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; char buf[256]; int bufsz = sizeof(buf); int pos = 0; @@ -420,13 +412,11 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, pos += scnprintf(buf+pos, bufsz-pos, "Channel inhibition CMD\n"); pos += scnprintf(buf+pos, bufsz-pos, - "\tPrimary Channel Bitmap 0x%016llx Fat: %d\n", - le64_to_cpu(cmd->bt_primary_ci), - !!cmd->co_run_bw_primary); + "\tPrimary Channel Bitmap 0x%016llx\n", + le64_to_cpu(cmd->bt_primary_ci)); pos += scnprintf(buf+pos, bufsz-pos, - "\tSecondary Channel Bitmap 0x%016llx Fat: %d\n", - le64_to_cpu(cmd->bt_secondary_ci), - !!cmd->co_run_bw_secondary); + "\tSecondary Channel Bitmap 0x%016llx\n", + le64_to_cpu(cmd->bt_secondary_ci)); pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index b3626cc69052..98becb9c90fa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h @@ -208,26 +208,116 @@ struct iwl_bt_coex_cmd_old { __le32 valid_bit_msk; } __packed; /* BT_COEX_CMD_API_S_VER_5 */ +enum iwl_bt_coex_mode { + BT_COEX_DISABLE = 0x0, + BT_COEX_NW = 0x1, + BT_COEX_BT = 0x2, + BT_COEX_WIFI = 0x3, +}; /* BT_COEX_MODES_E */ + +enum iwl_bt_coex_enabled_modules { + BT_COEX_MPLUT_ENABLED = BIT(0), + BT_COEX_MPLUT_BOOST_ENABLED = BIT(1), + BT_COEX_SYNC2SCO_ENABLED = BIT(2), + BT_COEX_CORUN_ENABLED = BIT(3), +}; /* BT_COEX_MODULES_ENABLE_E_VER_1 */ + +/** + * struct iwl_bt_coex_cmd - bt coex configuration command + * @mode: enum %iwl_bt_coex_mode + * @enabled_modules: enum %iwl_bt_coex_enabled_modules + * @max_kill: max count of Tx retries due to kill from PTA + * @override_primary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT + * should be set by default + * @override_secondary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT + * should be set by default + * @bt4_antenna_isolation_thr: antenna threshold value + * @bt4_tx_tx_delta_freq_thr: TxTx delta frequency + * @bt4_tx_rx_max_freq0: TxRx max frequency + * @multiprio_lut: multi priority LUT configuration + * @mplut_prio_boost: BT priority boost registers + * @decision_lut: PTA decision LUT, per Prio-Ch + * + * The structure is used for the BT_COEX command. + */ +struct iwl_bt_coex_cmd { + __le32 mode; + __le32 enabled_modules; + + __le32 max_kill; + __le32 override_primary_lut; + __le32 override_secondary_lut; + __le32 bt4_antenna_isolation_thr; + + __le32 bt4_tx_tx_delta_freq_thr; + __le32 bt4_tx_rx_max_freq0; + + __le32 multiprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE]; + __le32 mplut_prio_boost[BT_COEX_BOOST_SIZE]; + + __le32 decision_lut[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE]; +} __packed; /* BT_COEX_CMD_API_S_VER_6 */ + +/** + * struct iwl_bt_coex_corun_lut_update - bt coex update the corun lut + * @corun_lut20: co-running 20 MHz LUT configuration + * @corun_lut40: co-running 40 MHz LUT configuration + * + * The structure is used for the BT_COEX_UPDATE_CORUN_LUT command. + */ +struct iwl_bt_coex_corun_lut_update_cmd { + __le32 corun_lut20[BT_COEX_CORUN_LUT_SIZE]; + __le32 corun_lut40[BT_COEX_CORUN_LUT_SIZE]; +} __packed; /* BT_COEX_UPDATE_CORUN_LUT_API_S_VER_1 */ + +/** + * struct iwl_bt_coex_sw_boost - SW boost values + * @wifi_tx_prio_boost: SW boost of wifi tx priority + * @wifi_rx_prio_boost: SW boost of wifi rx priority + * @kill_ack_msk: kill ACK mask. 1 - Tx ACK, 0 - kill Tx of ACK. + * @kill_cts_msk: kill CTS mask. 1 - Tx CTS, 0 - kill Tx of CTS. + */ +struct iwl_bt_coex_sw_boost { + __le32 wifi_tx_prio_boost; + __le32 wifi_rx_prio_boost; + __le32 kill_ack_msk; + __le32 kill_cts_msk; +}; + +/** + * struct iwl_bt_coex_sw_boost_update_cmd - command to update the SW boost + * @boost_values: check struct %iwl_bt_coex_sw_boost - one for each channel + * primary / secondary / low priority + */ +struct iwl_bt_coex_sw_boost_update_cmd { + struct iwl_bt_coex_sw_boost boost_values[3]; +} __packed; /* BT_COEX_UPDATE_SW_BOOST_S_VER_1 */ + +/** + * struct iwl_bt_coex_reduced_txp_update_cmd + * @reduced_txp: bit BT_REDUCED_TX_POWER_BIT to enable / disable, rest of the + * bits are the sta_id (value) + */ +struct iwl_bt_coex_reduced_txp_update_cmd { + __le32 reduced_txp; +} __packed; /* BT_COEX_UPDATE_REDUCED_TX_POWER_API_S_VER_1 */ + /** * struct iwl_bt_coex_ci_cmd - bt coex channel inhibition command * @bt_primary_ci: - * @bt_secondary_ci: - * @co_run_bw_primary: - * @co_run_bw_secondary: * @primary_ch_phy_id: + * @bt_secondary_ci: * @secondary_ch_phy_id: * * Used for BT_COEX_CI command */ -struct iwl_bt_coex_ci_cmd_old { +struct iwl_bt_coex_ci_cmd { __le64 bt_primary_ci; - __le64 bt_secondary_ci; + __le32 primary_ch_phy_id; - u8 co_run_bw_primary; - u8 co_run_bw_secondary; - u8 primary_ch_phy_id; - u8 secondary_ch_phy_id; -} __packed; /* BT_CI_MSG_API_S_VER_1 */ + __le64 bt_secondary_ci; + __le32 secondary_ch_phy_id; +} __packed; /* BT_CI_MSG_API_S_VER_2 */ #define BT_MBOX(n_dw, _msg, _pos, _nbits) \ BT_MBOX##n_dw##_##_msg##_POS = (_pos), \ @@ -296,35 +386,34 @@ enum iwl_bt_activity_grading { BT_HIGH_TRAFFIC = 3, }; /* BT_COEX_BT_ACTIVITY_GRADING_API_E_VER_1 */ +enum iwl_bt_ci_compliance { + BT_CI_COMPLIANCE_NONE = 0, + BT_CI_COMPLIANCE_PRIMARY = 1, + BT_CI_COMPLIANCE_SECONDARY = 2, + BT_CI_COMPLIANCE_BOTH = 3, +}; /* BT_COEX_CI_COMPLIENCE_E_VER_1 */ + /** * struct iwl_bt_coex_profile_notif - notification about BT coex * @mbox_msg: message from BT to WiFi * @msg_idx: the index of the message - * @bt_status: 0 - off, 1 - on - * @bt_open_conn: number of BT connections open - * @bt_traffic_load: load of BT traffic - * @bt_agg_traffic_load: aggregated load of BT traffic - * @bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant - * @ttc_enabled: true if ttc has been enabled by the firmware - * @primary_ch_lut: LUT used for primary channel - * @secondary_ch_lut: LUT used for secondary channel + * @bt_ci_compliance: enum %iwl_bt_ci_compliance + * @primary_ch_lut: LUT used for primary channel enum %iwl_bt_coex_lut_type + * @secondary_ch_lut: LUT used for secondary channel enume %iwl_bt_coex_lut_type * @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading + * @ttc_rrc_status: is TTC or RRC enabled - one bit per PHY */ -struct iwl_bt_coex_profile_notif_old { +struct iwl_bt_coex_profile_notif { __le32 mbox_msg[4]; __le32 msg_idx; - u8 bt_status; - u8 bt_open_conn; - u8 bt_traffic_load; - u8 bt_agg_traffic_load; - u8 bt_ci_compliance; - u8 ttc_enabled; - __le16 reserved; + __le32 bt_ci_compliance; __le32 primary_ch_lut; __le32 secondary_ch_lut; __le32 bt_activity_grading; -} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_3 */ + u8 ttc_rrc_status; + u8 reserved[3]; +} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_4 */ enum iwl_bt_coex_prio_table_event { BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0, @@ -363,4 +452,54 @@ struct iwl_bt_coex_prio_tbl_cmd { u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX]; } __packed; +/** + * struct iwl_bt_coex_ci_cmd_old - bt coex channel inhibition command + * @bt_primary_ci: + * @bt_secondary_ci: + * @co_run_bw_primary: + * @co_run_bw_secondary: + * @primary_ch_phy_id: + * @secondary_ch_phy_id: + * + * Used for BT_COEX_CI command + */ +struct iwl_bt_coex_ci_cmd_old { + __le64 bt_primary_ci; + __le64 bt_secondary_ci; + + u8 co_run_bw_primary; + u8 co_run_bw_secondary; + u8 primary_ch_phy_id; + u8 secondary_ch_phy_id; +} __packed; /* BT_CI_MSG_API_S_VER_1 */ + +/** + * struct iwl_bt_coex_profile_notif_old - notification about BT coex + * @mbox_msg: message from BT to WiFi + * @msg_idx: the index of the message + * @bt_status: 0 - off, 1 - on + * @bt_open_conn: number of BT connections open + * @bt_traffic_load: load of BT traffic + * @bt_agg_traffic_load: aggregated load of BT traffic + * @bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant + * @primary_ch_lut: LUT used for primary channel + * @secondary_ch_lut: LUT used for secondary channel + * @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading + */ +struct iwl_bt_coex_profile_notif_old { + __le32 mbox_msg[4]; + __le32 msg_idx; + u8 bt_status; + u8 bt_open_conn; + u8 bt_traffic_load; + u8 bt_agg_traffic_load; + u8 bt_ci_compliance; + u8 ttc_enabled; + __le16 reserved; + + __le32 primary_ch_lut; + __le32 secondary_ch_lut; + __le32 bt_activity_grading; +} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_3 */ + #endif /* __fw_api_bt_coex_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 309a9b9a94fe..3983a2beb246 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -163,7 +163,6 @@ enum { BEACON_NOTIFICATION = 0x90, BEACON_TEMPLATE_CMD = 0x91, TX_ANT_CONFIGURATION_CMD = 0x98, - BT_CONFIG = 0x9b, STATISTICS_NOTIFICATION = 0x9d, EOSP_NOTIFICATION = 0x9e, REDUCE_TX_POWER_CMD = 0x9f, @@ -185,6 +184,10 @@ enum { BT_COEX_PRIO_TABLE = 0xcc, BT_COEX_PROT_ENV = 0xcd, BT_PROFILE_NOTIFICATION = 0xce, + BT_CONFIG = 0x9b, + BT_COEX_UPDATE_SW_BOOST = 0x5a, + BT_COEX_UPDATE_CORUN_LUT = 0x5b, + BT_COEX_UPDATE_REDUCED_TXP = 0x5c, BT_COEX_CI = 0x5d, REPLY_SF_CFG_CMD = 0xd1, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 0b52d0ae4a0d..fbe93a1df93a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -633,8 +633,8 @@ struct iwl_mvm { struct iwl_bt_coex_profile_notif_old last_bt_notif_old; struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd_old; - struct iwl_bt_coex_profile_notif_old last_bt_notif; - struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd; + struct iwl_bt_coex_profile_notif last_bt_notif; + struct iwl_bt_coex_ci_cmd last_bt_ci_cmd; u32 last_ant_isol; u8 last_corun_lut; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 15c13a722a93..b843870be8b7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -324,6 +324,9 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(REPLY_THERMAL_MNG_BACKOFF), CMD(MAC_PM_POWER_TABLE), CMD(BT_COEX_CI), + CMD(BT_COEX_UPDATE_SW_BOOST), + CMD(BT_COEX_UPDATE_CORUN_LUT), + CMD(BT_COEX_UPDATE_REDUCED_TXP), CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), CMD(ANTENNA_COUPLING_NOTIFICATION), }; -- cgit v1.2.3 From df878f38edc660e9626247724a8671c54fb6cbf7 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 2 Apr 2014 12:23:09 +0300 Subject: iwlwifi: mvm: BT Coex - convert the sw boost update to new API No need to send the big BT_COEX_CMD command, we have now a much thiner command that updates only what is needed. Adapt the code to that, and open the patch to the updates. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 58 +++++++++------------------------ 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index f8c293e54b5e..aa3e83f27f0e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -609,19 +609,12 @@ send_cmd: return ret; } -static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, - bool reduced_tx_power) +static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm, + bool reduced_tx_power) { enum iwl_bt_kill_msk bt_kill_msk; - struct iwl_bt_coex_cmd_old *bt_cmd; + struct iwl_bt_coex_sw_boost_update_cmd cmd = {}; struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; - struct iwl_host_cmd cmd = { - .id = BT_CONFIG, - .data[0] = &bt_cmd, - .len = { sizeof(*bt_cmd), }, - .dataflags = { IWL_HCMD_DFL_NOCOPY, }, - }; - int ret = 0; lockdep_assert_held(&mvm->mutex); @@ -651,26 +644,22 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, mvm->bt_kill_msk = bt_kill_msk; - bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); - if (!bt_cmd) - return -ENOMEM; - cmd.data[0] = bt_cmd; - bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); + cmd.boost_values[0].kill_ack_msk = + cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); + cmd.boost_values[0].kill_cts_msk = + cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); - bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); - bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); - bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | - BT_VALID_KILL_ACK | - BT_VALID_KILL_CTS); + cmd.boost_values[1].kill_ack_msk = cmd.boost_values[0].kill_ack_msk; + cmd.boost_values[2].kill_cts_msk = cmd.boost_values[0].kill_cts_msk; + cmd.boost_values[1].kill_ack_msk = cmd.boost_values[0].kill_ack_msk; + cmd.boost_values[2].kill_cts_msk = cmd.boost_values[0].kill_cts_msk; IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n", iwl_bt_ack_kill_msk[bt_kill_msk], iwl_bt_cts_kill_msk[bt_kill_msk]); - ret = iwl_mvm_send_cmd(mvm, &cmd); - - kfree(bt_cmd); - return ret; + return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_SW_BOOST, 0, + sizeof(cmd), &cmd); } static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, @@ -986,7 +975,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) */ data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; - if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) + if (iwl_mvm_bt_udpate_sw_boost(mvm, data.reduced_tx_power)) IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); } @@ -995,14 +984,11 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, struct iwl_device_cmd *dev_cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_bt_coex_profile_notif_old *notif = (void *)pkt->data; + struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) return iwl_mvm_rx_bt_coex_notif_old(mvm, rxb, dev_cmd); - /* TODO */ - return 0; - IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n", @@ -1085,9 +1071,6 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return; } - /* TODO */ - return; - lockdep_assert_held(&mvm->mutex); /* Ignore updates if we are in force mode */ @@ -1133,7 +1116,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, */ data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; - if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) + if (iwl_mvm_bt_udpate_sw_boost(mvm, data.reduced_tx_power)) IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); } @@ -1149,9 +1132,6 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) return iwl_mvm_coex_agg_time_limit_old(mvm, sta); - /* TODO */ - return LINK_QUAL_AGG_TIME_LIMIT_DEF; - if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC) return LINK_QUAL_AGG_TIME_LIMIT_DEF; @@ -1216,9 +1196,6 @@ bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwl_mvm *mvm, if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) return iwl_mvm_bt_coex_is_tpc_allowed_old(mvm, band); - /* TODO */ - return false; - if (band != IEEE80211_BAND_2GHZ) return false; @@ -1264,9 +1241,6 @@ void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) return; } - /* TODO */ - return; - iwl_mvm_bt_coex_notif_handle(mvm); } -- cgit v1.2.3 From 704602a1537e3593bb46aa3a6d9b415c868f25e3 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 2 Apr 2014 12:23:09 +0300 Subject: iwlwifi: mvm: BT Coex - convert the co-running update to new API No need to send the big BT_COEX_CMD command, we have now a much thiner command that updates only what is needed. Adapt the code to that. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 36 +++++++-------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index aa3e83f27f0e..c876c95f7b23 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -1250,23 +1250,13 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, { struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 ant_isolation = le32_to_cpup((void *)pkt->data); + struct iwl_bt_coex_corun_lut_update_cmd cmd = {}; u8 __maybe_unused lower_bound, upper_bound; - int ret; u8 lut; - struct iwl_bt_coex_cmd_old *bt_cmd; - struct iwl_host_cmd cmd = { - .id = BT_CONFIG, - .len = { sizeof(*bt_cmd), }, - .dataflags = { IWL_HCMD_DFL_NOCOPY, }, - }; - if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd); - /* TODO */ - return 0; - if (!IWL_MVM_BT_COEX_CORUNNING) return 0; @@ -1300,25 +1290,13 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, mvm->last_corun_lut = lut; - bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); - if (!bt_cmd) - return 0; - cmd.data[0] = bt_cmd; - - bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); - bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | - BT_VALID_CORUN_LUT_20 | - BT_VALID_CORUN_LUT_40); - /* For the moment, use the same LUT for 20GHz and 40GHz */ - memcpy(bt_cmd->bt4_corun_lut20, antenna_coupling_ranges[lut].lut20, - sizeof(bt_cmd->bt4_corun_lut20)); + memcpy(&cmd.corun_lut20, antenna_coupling_ranges[lut].lut20, + sizeof(cmd.corun_lut20)); - memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20, - sizeof(bt_cmd->bt4_corun_lut40)); + memcpy(&cmd.corun_lut40, antenna_coupling_ranges[lut].lut20, + sizeof(cmd.corun_lut40)); - ret = iwl_mvm_send_cmd(mvm, &cmd); - - kfree(bt_cmd); - return ret; + return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_CORUN_LUT, 0, + sizeof(cmd), &cmd); } -- cgit v1.2.3 From 455e7ac578a7bb325c7f09dd8386c3b347bb3e4b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 22 May 2014 12:48:27 +0300 Subject: iwlwifi: mvm: BT Coex - convert reduced Tx power to new API No need to send the big BT_COEX_CMD command, we have now a much thiner command that updates only what is needed. Adapt the code to that. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index c876c95f7b23..3395df1c5b75 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -665,19 +665,11 @@ static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm, static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable) { - struct iwl_bt_coex_cmd_old *bt_cmd; - /* Send ASYNC since this can be sent from an atomic context */ - struct iwl_host_cmd cmd = { - .id = BT_CONFIG, - .len = { sizeof(*bt_cmd), }, - .dataflags = { IWL_HCMD_DFL_NOCOPY, }, - .flags = CMD_ASYNC, - }; + struct iwl_bt_coex_reduced_txp_update_cmd cmd = {}; struct iwl_mvm_sta *mvmsta; + u32 value; int ret; - return 0; - mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); if (!mvmsta) return 0; @@ -686,27 +678,20 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, if (mvmsta->bt_reduced_txpower == enable) return 0; - bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC); - if (!bt_cmd) - return -ENOMEM; - cmd.data[0] = bt_cmd; - bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); - - bt_cmd->valid_bit_msk = - cpu_to_le32(BT_VALID_ENABLE | BT_VALID_REDUCED_TX_POWER); - bt_cmd->bt_reduced_tx_power = sta_id; + value = mvmsta->sta_id; if (enable) - bt_cmd->bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT; + value |= BT_REDUCED_TX_POWER_BIT; IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", enable ? "en" : "dis", sta_id); + cmd.reduced_txp = cpu_to_le32(value); mvmsta->bt_reduced_txpower = enable; - ret = iwl_mvm_send_cmd(mvm, &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_REDUCED_TXP, CMD_ASYNC, + sizeof(cmd), &cmd); - kfree(bt_cmd); return ret; } -- cgit v1.2.3 From 261c0ec07ecf1cc555a600315d687a94f2ee0660 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 11 Jun 2014 15:37:25 +0300 Subject: iwlwifi: mvm: BT Coex - add High Band retention Tell the firmware if TTC should be enabled when switching to High Band. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 3395df1c5b75..64325b60c0ff 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -587,6 +587,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) cpu_to_le32(BT_COEX_MPLUT_BOOST_ENABLED); } + bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET); + if (mvm->cfg->bt_shared_single_ant) memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, sizeof(iwl_single_shared_ant)); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index 98becb9c90fa..fea817d6a9be 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h @@ -220,6 +220,7 @@ enum iwl_bt_coex_enabled_modules { BT_COEX_MPLUT_BOOST_ENABLED = BIT(1), BT_COEX_SYNC2SCO_ENABLED = BIT(2), BT_COEX_CORUN_ENABLED = BIT(3), + BT_COEX_HIGH_BAND_RET = BIT(4), }; /* BT_COEX_MODULES_ENABLE_E_VER_1 */ /** -- cgit v1.2.3 From 160be5719bbcb97b46f008a0f9f23e80139f1e2c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 2 Jul 2014 17:33:52 +0300 Subject: iwlwifi: mvm: BT Coex - fix debugfs with old API Fix the debugfs hook to make it able to display the data with the old firmware API. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 183 +++++++++++++++++++++++------ 1 file changed, 148 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index e66c659b264a..f131ef0ec5b3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -312,20 +312,69 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf, BT_MBOX_MSG(notif, _num, _field), \ true ? "\n" : ", "); -static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static +int iwl_mvm_coex_dump_mbox(struct iwl_bt_coex_profile_notif *notif, char *buf, + int pos, int bufsz) { - struct iwl_mvm *mvm = file->private_data; - struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; - char *buf; - int ret, pos = 0, bufsz = sizeof(char) * 1024; + pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n"); - buf = kmalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; + BT_MBOX_PRINT(0, LE_SLAVE_LAT, false); + BT_MBOX_PRINT(0, LE_PROF1, false); + BT_MBOX_PRINT(0, LE_PROF2, false); + BT_MBOX_PRINT(0, LE_PROF_OTHER, false); + BT_MBOX_PRINT(0, CHL_SEQ_N, false); + BT_MBOX_PRINT(0, INBAND_S, false); + BT_MBOX_PRINT(0, LE_MIN_RSSI, false); + BT_MBOX_PRINT(0, LE_SCAN, false); + BT_MBOX_PRINT(0, LE_ADV, false); + BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false); + BT_MBOX_PRINT(0, OPEN_CON_1, true); - mutex_lock(&mvm->mutex); + pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n"); + + BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false); + BT_MBOX_PRINT(1, IP_SR, false); + BT_MBOX_PRINT(1, LE_MSTR, false); + BT_MBOX_PRINT(1, AGGR_TRFC_LD, false); + BT_MBOX_PRINT(1, MSG_TYPE, false); + BT_MBOX_PRINT(1, SSN, true); + + pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n"); + + BT_MBOX_PRINT(2, SNIFF_ACT, false); + BT_MBOX_PRINT(2, PAG, false); + BT_MBOX_PRINT(2, INQUIRY, false); + BT_MBOX_PRINT(2, CONN, false); + BT_MBOX_PRINT(2, SNIFF_INTERVAL, false); + BT_MBOX_PRINT(2, DISC, false); + BT_MBOX_PRINT(2, SCO_TX_ACT, false); + BT_MBOX_PRINT(2, SCO_RX_ACT, false); + BT_MBOX_PRINT(2, ESCO_RE_TX, false); + BT_MBOX_PRINT(2, SCO_DURATION, true); + pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n"); + + BT_MBOX_PRINT(3, SCO_STATE, false); + BT_MBOX_PRINT(3, SNIFF_STATE, false); + BT_MBOX_PRINT(3, A2DP_STATE, false); + BT_MBOX_PRINT(3, ACL_STATE, false); + BT_MBOX_PRINT(3, MSTR_STATE, false); + BT_MBOX_PRINT(3, OBX_STATE, false); + BT_MBOX_PRINT(3, OPEN_CON_2, false); + BT_MBOX_PRINT(3, TRAFFIC_LOAD, false); + BT_MBOX_PRINT(3, CHL_SEQN_LSB, false); + BT_MBOX_PRINT(3, INBAND_P, false); + BT_MBOX_PRINT(3, MSG_TYPE_2, false); + BT_MBOX_PRINT(3, SSN_2, false); + BT_MBOX_PRINT(3, UPDATE_REQUEST, true); + + return pos; +} + +static +int iwl_mvm_coex_dump_mbox_old(struct iwl_bt_coex_profile_notif_old *notif, + char *buf, int pos, int bufsz) +{ pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n"); BT_MBOX_PRINT(0, LE_SLAVE_LAT, false); @@ -378,17 +427,59 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, BT_MBOX_PRINT(3, SSN_2, false); BT_MBOX_PRINT(3, UPDATE_REQUEST, true); - pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n", - notif->bt_ci_compliance); - pos += scnprintf(buf+pos, bufsz-pos, "primary_ch_lut = %d\n", - le32_to_cpu(notif->primary_ch_lut)); - pos += scnprintf(buf+pos, bufsz-pos, "secondary_ch_lut = %d\n", - le32_to_cpu(notif->secondary_ch_lut)); - pos += scnprintf(buf+pos, bufsz-pos, "bt_activity_grading = %d\n", - le32_to_cpu(notif->bt_activity_grading)); - pos += scnprintf(buf+pos, bufsz-pos, - "antenna isolation = %d CORUN LUT index = %d\n", - mvm->last_ant_isol, mvm->last_corun_lut); + return pos; +} + +static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + char *buf; + int ret, pos = 0, bufsz = sizeof(char) * 1024; + + buf = kmalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&mvm->mutex); + + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { + struct iwl_bt_coex_profile_notif_old *notif = + &mvm->last_bt_notif_old; + + pos += iwl_mvm_coex_dump_mbox_old(notif, buf, pos, bufsz); + + pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n", + notif->bt_ci_compliance); + pos += scnprintf(buf+pos, bufsz-pos, "primary_ch_lut = %d\n", + le32_to_cpu(notif->primary_ch_lut)); + pos += scnprintf(buf+pos, bufsz-pos, "secondary_ch_lut = %d\n", + le32_to_cpu(notif->secondary_ch_lut)); + pos += scnprintf(buf+pos, + bufsz-pos, "bt_activity_grading = %d\n", + le32_to_cpu(notif->bt_activity_grading)); + pos += scnprintf(buf+pos, bufsz-pos, + "antenna isolation = %d CORUN LUT index = %d\n", + mvm->last_ant_isol, mvm->last_corun_lut); + } else { + struct iwl_bt_coex_profile_notif *notif = + &mvm->last_bt_notif; + + pos += iwl_mvm_coex_dump_mbox(notif, buf, pos, bufsz); + + pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n", + notif->bt_ci_compliance); + pos += scnprintf(buf+pos, bufsz-pos, "primary_ch_lut = %d\n", + le32_to_cpu(notif->primary_ch_lut)); + pos += scnprintf(buf+pos, bufsz-pos, "secondary_ch_lut = %d\n", + le32_to_cpu(notif->secondary_ch_lut)); + pos += scnprintf(buf+pos, + bufsz-pos, "bt_activity_grading = %d\n", + le32_to_cpu(notif->bt_activity_grading)); + pos += scnprintf(buf+pos, bufsz-pos, + "antenna isolation = %d CORUN LUT index = %d\n", + mvm->last_ant_isol, mvm->last_corun_lut); + } mutex_unlock(&mvm->mutex); @@ -403,26 +494,48 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; char buf[256]; int bufsz = sizeof(buf); int pos = 0; mutex_lock(&mvm->mutex); - pos += scnprintf(buf+pos, bufsz-pos, "Channel inhibition CMD\n"); - pos += scnprintf(buf+pos, bufsz-pos, - "\tPrimary Channel Bitmap 0x%016llx\n", - le64_to_cpu(cmd->bt_primary_ci)); - pos += scnprintf(buf+pos, bufsz-pos, - "\tSecondary Channel Bitmap 0x%016llx\n", - le64_to_cpu(cmd->bt_secondary_ci)); - - pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); - pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", - iwl_bt_ack_kill_msk[mvm->bt_kill_msk]); - pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", - iwl_bt_cts_kill_msk[mvm->bt_kill_msk]); + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { + struct iwl_bt_coex_ci_cmd_old *cmd = &mvm->last_bt_ci_cmd_old; + + pos += scnprintf(buf+pos, bufsz-pos, + "Channel inhibition CMD\n"); + pos += scnprintf(buf+pos, bufsz-pos, + "\tPrimary Channel Bitmap 0x%016llx\n", + le64_to_cpu(cmd->bt_primary_ci)); + pos += scnprintf(buf+pos, bufsz-pos, + "\tSecondary Channel Bitmap 0x%016llx\n", + le64_to_cpu(cmd->bt_secondary_ci)); + + pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); + pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", + iwl_bt_ack_kill_msk[mvm->bt_kill_msk]); + pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", + iwl_bt_cts_kill_msk[mvm->bt_kill_msk]); + + } else { + struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; + + pos += scnprintf(buf+pos, bufsz-pos, + "Channel inhibition CMD\n"); + pos += scnprintf(buf+pos, bufsz-pos, + "\tPrimary Channel Bitmap 0x%016llx\n", + le64_to_cpu(cmd->bt_primary_ci)); + pos += scnprintf(buf+pos, bufsz-pos, + "\tSecondary Channel Bitmap 0x%016llx\n", + le64_to_cpu(cmd->bt_secondary_ci)); + + pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); + pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", + iwl_bt_ack_kill_msk[mvm->bt_kill_msk]); + pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", + iwl_bt_cts_kill_msk[mvm->bt_kill_msk]); + } mutex_unlock(&mvm->mutex); -- cgit v1.2.3 From 4c86f938d359f30a52134d3fc9945f95a3e621e2 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 30 Jun 2014 10:26:02 +0300 Subject: iwlwifi: mvm: BT Coex - relax constraints when TTC / RRC is active When TxTxCo-Running is active, we can relax the constraints on the rate control. When RxRxCo-Running is active, we can relax the constrains on SMPS. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 21 ++++++++++++--------- drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | 6 ++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 64325b60c0ff..8110fe00bf55 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -787,6 +787,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, if (!vif->bss_conf.assoc) smps_mode = IEEE80211_SMPS_AUTOMATIC; + if (IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status, + mvmvif->phy_ctxt->id)) + smps_mode = IEEE80211_SMPS_AUTOMATIC; + IWL_DEBUG_COEX(data->mvm, "mac %d: bt_activity_grading %d smps_req %d\n", mvmvif->id, bt_activity_grading, smps_mode); @@ -1114,19 +1118,19 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); + struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt; enum iwl_bt_coex_lut_type lut_type; if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) return iwl_mvm_coex_agg_time_limit_old(mvm, sta); + if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id)) + return LINK_QUAL_AGG_TIME_LIMIT_DEF; + if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC) return LINK_QUAL_AGG_TIME_LIMIT_DEF; -/* - TODO - if (mvm->last_bt_notif.ttc_enabled) - return LINK_QUAL_AGG_TIME_LIMIT_DEF; -*/ lut_type = iwl_get_coex_type(mvm, mvmsta->vif); @@ -1141,16 +1145,15 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); + struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt; enum iwl_bt_coex_lut_type lut_type; if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) return iwl_mvm_coex_agg_time_limit_old(mvm, sta); -/* - TODO - if (mvm->last_bt_notif.ttc_enabled) + if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id)) return true; -*/ if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index fea817d6a9be..ab12aaa43034 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h @@ -394,6 +394,12 @@ enum iwl_bt_ci_compliance { BT_CI_COMPLIANCE_BOTH = 3, }; /* BT_COEX_CI_COMPLIENCE_E_VER_1 */ +#define IWL_COEX_IS_TTC_ON(_ttc_rrc_status, _phy_id) \ + (_ttc_rrc_status & BIT(_phy_id)) + +#define IWL_COEX_IS_RRC_ON(_ttc_rrc_status, _phy_id) \ + ((_ttc_rrc_status >> 4) & BIT(_phy_id)) + /** * struct iwl_bt_coex_profile_notif - notification about BT coex * @mbox_msg: message from BT to WiFi -- cgit v1.2.3 From bdce40f006dc53bfdeeba4a4ff200d4c0cf5aac8 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Tue, 1 Jul 2014 17:31:38 +0300 Subject: iwlwifi: mvm: warn about empty OTP Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/nvm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 1f1a550828fa..b04805ccb443 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -530,6 +530,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) } #endif } + if (!size_read) + IWL_ERR(mvm, "OTP is blank\n"); kfree(nvm_buffer); } -- cgit v1.2.3 From ae969afe43273c9bc8d22629efd9c51627837615 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 11 Jun 2014 15:51:33 +0300 Subject: iwlwifi: mvm: rs: don't clear persistent fields iwl_mvm_rs_rate_init() is called multiple times to re-init the rate scaling statistics (e.g. after some idle time). It clears all the lq_sta sta, including some fields that shouldn't be cleared (e.g. debugfs pointers). Fix it by adding a new 'persistent' sub-struct, and avoid clearing it on (re-)init. Move the initialization of the persistent fields to rs_alloc_sta instead. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 87 ++++++++++++++++++----------------- drivers/net/wireless/iwlwifi/mvm/rs.h | 24 ++++++---- 2 files changed, 59 insertions(+), 52 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 306a6caa4868..67bd8d79c9d3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -927,7 +927,7 @@ static bool rs_get_lower_rate_in_column(struct iwl_lq_sta *lq_sta, u8 low; u16 high_low; u16 rate_mask; - struct iwl_mvm *mvm = lq_sta->drv; + struct iwl_mvm *mvm = lq_sta->pers.drv; rate_mask = rs_get_supported_rates(lq_sta, rate); high_low = rs_get_adjacent_rate(mvm, rate->index, rate_mask, @@ -946,7 +946,7 @@ static bool rs_get_lower_rate_in_column(struct iwl_lq_sta *lq_sta, static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, struct rs_rate *rate) { - struct iwl_mvm *mvm = lq_sta->drv; + struct iwl_mvm *mvm = lq_sta->pers.drv; if (is_legacy(rate)) { /* No column to downgrade from Legacy */ @@ -1026,14 +1026,14 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, if (!lq_sta) { IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n"); return; - } else if (!lq_sta->drv) { + } else if (!lq_sta->pers.drv) { IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n"); return; } #ifdef CONFIG_MAC80211_DEBUGFS /* Disable last tx check if we are debugging with fixed rate */ - if (lq_sta->dbg_fixed_rate) { + if (lq_sta->pers.dbg_fixed_rate) { IWL_DEBUG_RATE(mvm, "Fixed rate. avoid rate scaling\n"); return; } @@ -1405,7 +1405,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) int flush_interval_passed = 0; struct iwl_mvm *mvm; - mvm = lq_sta->drv; + mvm = lq_sta->pers.drv; active_tbl = lq_sta->active_tbl; tbl = &(lq_sta->lq_info[active_tbl]); @@ -1865,11 +1865,11 @@ static bool rs_tpc_perform(struct iwl_mvm *mvm, int weak_tpt = IWL_INVALID_VALUE, strong_tpt = IWL_INVALID_VALUE; #ifdef CONFIG_MAC80211_DEBUGFS - if (lq_sta->dbg_fixed_txp_reduction <= TPC_MAX_REDUCTION) { + if (lq_sta->pers.dbg_fixed_txp_reduction <= TPC_MAX_REDUCTION) { IWL_DEBUG_RATE(mvm, "fixed tpc: %d\n", - lq_sta->dbg_fixed_txp_reduction); - lq_sta->lq.reduced_tpc = lq_sta->dbg_fixed_txp_reduction; - return cur != lq_sta->dbg_fixed_txp_reduction; + lq_sta->pers.dbg_fixed_txp_reduction); + lq_sta->lq.reduced_tpc = lq_sta->pers.dbg_fixed_txp_reduction; + return cur != lq_sta->pers.dbg_fixed_txp_reduction; } #endif @@ -2382,7 +2382,7 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, } /* Treat uninitialized rate scaling data same as non-existing. */ - if (lq_sta && !lq_sta->drv) { + if (lq_sta && !lq_sta->pers.drv) { IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n"); mvm_sta = NULL; } @@ -2401,12 +2401,18 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, gfp_t gfp) { struct iwl_mvm_sta *sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; - struct iwl_op_mode *op_mode __maybe_unused = - (struct iwl_op_mode *)mvm_rate; - struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); + struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_rate; + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + struct iwl_lq_sta *lq_sta = &sta_priv->lq_sta; IWL_DEBUG_RATE(mvm, "create station rate scale window\n"); + lq_sta->pers.drv = mvm; +#ifdef CONFIG_MAC80211_DEBUGFS + lq_sta->pers.dbg_fixed_rate = 0; + lq_sta->pers.dbg_fixed_txp_reduction = TPC_INVALID; +#endif + return &sta_priv->lq_sta; } @@ -2552,7 +2558,9 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; lq_sta = &sta_priv->lq_sta; - memset(lq_sta, 0, sizeof(*lq_sta)); + + /* clear all non-persistent lq data */ + memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers)); sband = hw->wiphy->bands[band]; @@ -2630,17 +2638,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, /* as default allow aggregation for all tids */ lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; - lq_sta->drv = mvm; /* Set last_txrate_idx to lowest rate */ lq_sta->last_txrate_idx = rate_lowest_index(sband, sta); if (sband->band == IEEE80211_BAND_5GHZ) lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; lq_sta->is_agg = 0; -#ifdef CONFIG_MAC80211_DEBUGFS - lq_sta->dbg_fixed_rate = 0; - lq_sta->dbg_fixed_txp_reduction = TPC_INVALID; -#endif #ifdef CONFIG_IWLWIFI_DEBUGFS iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats); #endif @@ -2811,12 +2814,12 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, u8 ant = initial_rate->ant; #ifdef CONFIG_MAC80211_DEBUGFS - if (lq_sta->dbg_fixed_rate) { + if (lq_sta->pers.dbg_fixed_rate) { rs_build_rates_table_from_fixed(mvm, lq_cmd, lq_sta->band, - lq_sta->dbg_fixed_rate); + lq_sta->pers.dbg_fixed_rate); lq_cmd->reduced_tpc = 0; - ant = (lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) >> + ant = (lq_sta->pers.dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS; } else #endif @@ -2926,14 +2929,14 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ IWL_DEBUG_RATE(mvm, "sta_id %d rate 0x%X\n", - lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate); + lq_sta->lq.sta_id, lq_sta->pers.dbg_fixed_rate); - if (lq_sta->dbg_fixed_rate) { + if (lq_sta->pers.dbg_fixed_rate) { struct rs_rate rate; - rs_rate_from_ucode_rate(lq_sta->dbg_fixed_rate, + rs_rate_from_ucode_rate(lq_sta->pers.dbg_fixed_rate, lq_sta->band, &rate); rs_fill_lq_cmd(mvm, NULL, lq_sta, &rate); - iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, false); + iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq, false); } } @@ -2946,16 +2949,16 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, size_t buf_size; u32 parsed_rate; - mvm = lq_sta->drv; + mvm = lq_sta->pers.drv; memset(buf, 0, sizeof(buf)); buf_size = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; if (sscanf(buf, "%x", &parsed_rate) == 1) - lq_sta->dbg_fixed_rate = parsed_rate; + lq_sta->pers.dbg_fixed_rate = parsed_rate; else - lq_sta->dbg_fixed_rate = 0; + lq_sta->pers.dbg_fixed_rate = 0; rs_program_fix_rate(mvm, lq_sta); @@ -2974,7 +2977,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, struct iwl_mvm *mvm; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct rs_rate *rate = &tbl->rate; - mvm = lq_sta->drv; + mvm = lq_sta->pers.drv; buff = kmalloc(2048, GFP_KERNEL); if (!buff) return -ENOMEM; @@ -2984,7 +2987,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, lq_sta->total_failed, lq_sta->total_success, lq_sta->active_legacy_rate); desc += sprintf(buff+desc, "fixed rate 0x%X\n", - lq_sta->dbg_fixed_rate); + lq_sta->pers.dbg_fixed_rate); desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", (mvm->fw->valid_tx_ant & ANT_A) ? "ANT_A," : "", (mvm->fw->valid_tx_ant & ANT_B) ? "ANT_B," : "", @@ -3182,31 +3185,31 @@ static const struct file_operations rs_sta_dbgfs_drv_tx_stats_ops = { static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) { struct iwl_lq_sta *lq_sta = mvm_sta; - lq_sta->rs_sta_dbgfs_scale_table_file = + lq_sta->pers.rs_sta_dbgfs_scale_table_file = debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, lq_sta, &rs_sta_dbgfs_scale_table_ops); - lq_sta->rs_sta_dbgfs_stats_table_file = + lq_sta->pers.rs_sta_dbgfs_stats_table_file = debugfs_create_file("rate_stats_table", S_IRUSR, dir, lq_sta, &rs_sta_dbgfs_stats_table_ops); - lq_sta->rs_sta_dbgfs_drv_tx_stats_file = + lq_sta->pers.rs_sta_dbgfs_drv_tx_stats_file = debugfs_create_file("drv_tx_stats", S_IRUSR | S_IWUSR, dir, lq_sta, &rs_sta_dbgfs_drv_tx_stats_ops); - lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = + lq_sta->pers.rs_sta_dbgfs_tx_agg_tid_en_file = debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, &lq_sta->tx_agg_tid_en); - lq_sta->rs_sta_dbgfs_reduced_txp_file = + lq_sta->pers.rs_sta_dbgfs_reduced_txp_file = debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir, - &lq_sta->dbg_fixed_txp_reduction); + &lq_sta->pers.dbg_fixed_txp_reduction); } static void rs_remove_debugfs(void *mvm, void *mvm_sta) { struct iwl_lq_sta *lq_sta = mvm_sta; - debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file); - debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); - debugfs_remove(lq_sta->rs_sta_dbgfs_drv_tx_stats_file); - debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file); - debugfs_remove(lq_sta->rs_sta_dbgfs_reduced_txp_file); + debugfs_remove(lq_sta->pers.rs_sta_dbgfs_scale_table_file); + debugfs_remove(lq_sta->pers.rs_sta_dbgfs_stats_table_file); + debugfs_remove(lq_sta->pers.rs_sta_dbgfs_drv_tx_stats_file); + debugfs_remove(lq_sta->pers.rs_sta_dbgfs_tx_agg_tid_en_file); + debugfs_remove(lq_sta->pers.rs_sta_dbgfs_reduced_txp_file); } #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 374a83d7db25..2e1a683d0162 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -349,16 +349,6 @@ struct iwl_lq_sta { struct iwl_lq_cmd lq; struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ u8 tx_agg_tid_en; -#ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *rs_sta_dbgfs_scale_table_file; - struct dentry *rs_sta_dbgfs_stats_table_file; - struct dentry *rs_sta_dbgfs_drv_tx_stats_file; - struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; - struct dentry *rs_sta_dbgfs_reduced_txp_file; - u32 dbg_fixed_rate; - u8 dbg_fixed_txp_reduction; -#endif - struct iwl_mvm *drv; /* used to be in sta_info */ int last_txrate_idx; @@ -369,6 +359,20 @@ struct iwl_lq_sta { /* tx power reduce for this sta */ int tpc_reduce; + + /* persistent fields - initialized only once - keep last! */ + struct { +#ifdef CONFIG_MAC80211_DEBUGFS + struct dentry *rs_sta_dbgfs_scale_table_file; + struct dentry *rs_sta_dbgfs_stats_table_file; + struct dentry *rs_sta_dbgfs_drv_tx_stats_file; + struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; + struct dentry *rs_sta_dbgfs_reduced_txp_file; + u32 dbg_fixed_rate; + u8 dbg_fixed_txp_reduction; +#endif + struct iwl_mvm *drv; + } pers; }; /* Initialize station's rate scaling information after adding station */ -- cgit v1.2.3 From c6e1faad7500c07b75d11d339414cead0d57534b Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 15 Jun 2014 12:02:20 +0300 Subject: iwlwifi: mvm: rs: don't save debugfs files These file are removed recursively anyway, so there's no point saving them just to redundantly remove them later. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 31 ++++++++++--------------------- drivers/net/wireless/iwlwifi/mvm/rs.h | 5 ----- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 67bd8d79c9d3..c70e959bf0e3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -3185,31 +3185,20 @@ static const struct file_operations rs_sta_dbgfs_drv_tx_stats_ops = { static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) { struct iwl_lq_sta *lq_sta = mvm_sta; - lq_sta->pers.rs_sta_dbgfs_scale_table_file = - debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, - lq_sta, &rs_sta_dbgfs_scale_table_ops); - lq_sta->pers.rs_sta_dbgfs_stats_table_file = - debugfs_create_file("rate_stats_table", S_IRUSR, dir, - lq_sta, &rs_sta_dbgfs_stats_table_ops); - lq_sta->pers.rs_sta_dbgfs_drv_tx_stats_file = - debugfs_create_file("drv_tx_stats", S_IRUSR | S_IWUSR, dir, - lq_sta, &rs_sta_dbgfs_drv_tx_stats_ops); - lq_sta->pers.rs_sta_dbgfs_tx_agg_tid_en_file = - debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, - &lq_sta->tx_agg_tid_en); - lq_sta->pers.rs_sta_dbgfs_reduced_txp_file = - debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir, - &lq_sta->pers.dbg_fixed_txp_reduction); + debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, + lq_sta, &rs_sta_dbgfs_scale_table_ops); + debugfs_create_file("rate_stats_table", S_IRUSR, dir, + lq_sta, &rs_sta_dbgfs_stats_table_ops); + debugfs_create_file("drv_tx_stats", S_IRUSR | S_IWUSR, dir, + lq_sta, &rs_sta_dbgfs_drv_tx_stats_ops); + debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, + &lq_sta->tx_agg_tid_en); + debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir, + &lq_sta->pers.dbg_fixed_txp_reduction); } static void rs_remove_debugfs(void *mvm, void *mvm_sta) { - struct iwl_lq_sta *lq_sta = mvm_sta; - debugfs_remove(lq_sta->pers.rs_sta_dbgfs_scale_table_file); - debugfs_remove(lq_sta->pers.rs_sta_dbgfs_stats_table_file); - debugfs_remove(lq_sta->pers.rs_sta_dbgfs_drv_tx_stats_file); - debugfs_remove(lq_sta->pers.rs_sta_dbgfs_tx_agg_tid_en_file); - debugfs_remove(lq_sta->pers.rs_sta_dbgfs_reduced_txp_file); } #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 2e1a683d0162..f27b9d687a25 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -363,11 +363,6 @@ struct iwl_lq_sta { /* persistent fields - initialized only once - keep last! */ struct { #ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *rs_sta_dbgfs_scale_table_file; - struct dentry *rs_sta_dbgfs_stats_table_file; - struct dentry *rs_sta_dbgfs_drv_tx_stats_file; - struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; - struct dentry *rs_sta_dbgfs_reduced_txp_file; u32 dbg_fixed_rate; u8 dbg_fixed_txp_reduction; #endif -- cgit v1.2.3 From fb98be5e94194ba76b507770dc96f744fed8e4c5 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Sun, 4 May 2014 12:51:10 +0300 Subject: iwlwifi: mvm: add unified LMAC scan API Add new scan API that uses the same command 0x51 for both regular and sched scan. Signed-off-by: David Spinadel Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw.h | 2 + drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 207 ++++++++++++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 1 + drivers/net/wireless/iwlwifi/mvm/mac80211.c | 29 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 19 +- drivers/net/wireless/iwlwifi/mvm/ops.c | 18 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 447 ++++++++++++++++++++++--- 7 files changed, 653 insertions(+), 70 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 79b0508fddef..1bb5193c5b1b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -124,6 +124,7 @@ enum iwl_ucode_tlv_flag { * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. + * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), @@ -131,6 +132,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), + IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), }; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 1d586923d5b7..48a1d8f5675d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -582,4 +582,211 @@ struct iwl_sched_scan_results { u8 reserved; }; +/* Unified LMAC scan API */ + +#define IWL_MVM_BASIC_PASSIVE_DWELL 110 + +/** + * iwl_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S + * @tx_flags: combination of TX_CMD_FLG_* + * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is + * cleared. Combination of RATE_MCS_* + * @sta_id: index of destination station in FW station table + * @reserved: for alignment and future use + */ +struct iwl_scan_req_tx_cmd { + __le32 tx_flags; + __le32 rate_n_flags; + u8 sta_id; + u8 reserved[3]; +} __packed; + +enum iwl_scan_channel_flags_lmac { + IWL_UNIFIED_SCAN_CHANNEL_FULL = BIT(27), + IWL_UNIFIED_SCAN_CHANNEL_PARTIAL = BIT(28), +}; + +/** + * iwl_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2 + * @flags: bits 1-20: directed scan to i'th ssid + * other bits &enum iwl_scan_channel_flags_lmac + * @channel_number: channel number 1-13 etc + * @iter_count: scan iteration on this channel + * @iter_interval: interval in seconds between iterations on one channel + */ +struct iwl_scan_channel_cfg_lmac { + __le32 flags; + __le16 channel_num; + __le16 iter_count; + __le32 iter_interval; +} __packed; + +/* + * iwl_scan_probe_segment - PROBE_SEGMENT_API_S_VER_1 + * @offset: offset in the data block + * @len: length of the segment + */ +struct iwl_scan_probe_segment { + __le16 offset; + __le16 len; +} __packed; + +/* iwl_scan_probe_req - PROBE_REQUEST_FRAME_API_S_VER_2 + * @mac_header: first (and common) part of the probe + * @band_data: band specific data + * @common_data: last (and common) part of the probe + * @buf: raw data block + */ +struct iwl_scan_probe_req { + struct iwl_scan_probe_segment mac_header; + struct iwl_scan_probe_segment band_data[2]; + struct iwl_scan_probe_segment common_data; + u8 buf[SCAN_OFFLOAD_PROBE_REQ_SIZE]; +} __packed; + +enum iwl_scan_channel_flags { + IWL_SCAN_CHANNEL_FLAG_EBS = BIT(0), + IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE = BIT(1), + IWL_SCAN_CHANNEL_FLAG_CACHE_ADD = BIT(2), +}; + +/* iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S + * @flags: enum iwl_scan_channel_flgs + * @non_ebs_ratio: how many regular scan iteration before EBS + */ +struct iwl_scan_channel_opt { + __le16 flags; + __le16 non_ebs_ratio; +} __packed; + +/** + * iwl_mvm_lmac_scan_flags + * @IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL: pass all beacons and probe responses + * without filtering. + * @IWL_MVM_LMAC_SCAN_FLAG_PASSIVE: force passive scan on all channels + * @IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION: single channel scan + * @IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE: send iteration complete notification + * @IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS multiple SSID matching + * @IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented + */ +enum iwl_mvm_lmac_scan_flags { + IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL = BIT(0), + IWL_MVM_LMAC_SCAN_FLAG_PASSIVE = BIT(1), + IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION = BIT(2), + IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE = BIT(3), + IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS = BIT(4), + IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED = BIT(5), +}; + +enum iwl_scan_priority { + IWL_SCAN_PRIORITY_LOW, + IWL_SCAN_PRIORITY_MEDIUM, + IWL_SCAN_PRIORITY_HIGH, +}; + +/** + * iwl_scan_req_unified_lmac - SCAN_REQUEST_CMD_API_S_VER_1 + * @reserved1: for alignment and future use + * @channel_num: num of channels to scan + * @active-dwell: dwell time for active channels + * @passive-dwell: dwell time for passive channels + * @fragmented-dwell: dwell time for fragmented passive scan + * @reserved2: for alignment and future use + * @rx_chain_selct: PHY_RX_CHAIN_* flags + * @scan_flags: &enum iwl_mvm_lmac_scan_flags + * @max_out_time: max time (in TU) to be out of associated channel + * @suspend_time: pause scan this long (TUs) when returning to service channel + * @flags: RXON flags + * @filter_flags: RXON filter + * @tx_cmd: tx command for active scan; for 2GHz and for 5GHz + * @direct_scan: list of SSIDs for directed active scan + * @scan_prio: enum iwl_scan_priority + * @iter_num: number of scan iterations + * @delay: delay in seconds before first iteration + * @schedule: two scheduling plans. The first one is finite, the second one can + * be infinite. + * @channel_opt: channel optimization options, for full and partial scan + * @data: channel configuration and probe request packet. + */ +struct iwl_scan_req_unified_lmac { + /* SCAN_REQUEST_FIXED_PART_API_S_VER_7 */ + __le32 reserved1; + u8 n_channels; + u8 active_dwell; + u8 passive_dwell; + u8 fragmented_dwell; + __le16 reserved2; + __le16 rx_chain_select; + __le32 scan_flags; + __le32 max_out_time; + __le32 suspend_time; + /* RX_ON_FLAGS_API_S_VER_1 */ + __le32 flags; + __le32 filter_flags; + struct iwl_scan_req_tx_cmd tx_cmd[2]; + struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; + __le32 scan_prio; + /* SCAN_REQ_PERIODIC_PARAMS_API_S */ + __le32 iter_num; + __le32 delay; + struct iwl_scan_offload_schedule schedule[2]; + struct iwl_scan_channel_opt channel_opt[2]; + u8 data[]; +} __packed; + +/** + * struct iwl_lmac_scan_results_notif - scan results for one channel - + * SCAN_RESULT_NTF_API_S_VER_3 + * @channel: which channel the results are from + * @band: 0 for 5.2 GHz, 1 for 2.4 GHz + * @probe_status: SCAN_PROBE_STATUS_*, indicates success of probe request + * @num_probe_not_sent: # of request that weren't sent due to not enough time + * @duration: duration spent in channel, in usecs + */ +struct iwl_lmac_scan_results_notif { + u8 channel; + u8 band; + u8 probe_status; + u8 num_probe_not_sent; + __le32 duration; +} __packed; + +/** + * struct iwl_lmac_scan_complete_notif - notifies end of scanning (all channels) + * SCAN_COMPLETE_NTF_API_S_VER_3 + * @scanned_channels: number of channels scanned (and number of valid results) + * @status: one of SCAN_COMP_STATUS_* + * @bt_status: BT on/off status + * @last_channel: last channel that was scanned + * @tsf_low: TSF timer (lower half) in usecs + * @tsf_high: TSF timer (higher half) in usecs + * @results: an array of scan results, only "scanned_channels" of them are valid + */ +struct iwl_lmac_scan_complete_notif { + u8 scanned_channels; + u8 status; + u8 bt_status; + u8 last_channel; + __le32 tsf_low; + __le32 tsf_high; + struct iwl_scan_results_notif results[]; +} __packed; + +/** + * iwl_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2 + * @last_schedule_line: last schedule line executed (fast or regular) + * @last_schedule_iteration: last scan iteration executed before scan abort + * @status: enum iwl_scan_offload_complete_status + * @ebs_status: EBS success status &enum iwl_scan_ebs_status + * @time_after_last_iter; time in seconds elapsed after last iteration + */ +struct iwl_periodic_scan_complete { + u8 last_schedule_line; + u8 last_schedule_iteration; + u8 status; + u8 ebs_status; + __le32 time_after_last_iter; + __le32 reserved; +} __packed; + #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 3983a2beb246..6c479de3b8d4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -135,6 +135,7 @@ enum { SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, SCAN_OFFLOAD_CONFIG_CMD = 0x6f, MATCH_FOUND_NOTIFICATION = 0xd9, + SCAN_ITERATION_COMPLETE = 0xe7, /* Phy */ PHY_CONFIGURATION_CMD = 0x6a, diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 7dde944a68fb..522aa039a490 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -327,6 +327,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; } + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) + hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; + hw->sta_data_size = sizeof(struct iwl_mvm_sta); hw->vif_data_size = sizeof(struct iwl_mvm_vif); hw->chanctx_data_size = sizeof(u16); @@ -1658,7 +1661,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); if (changes & BSS_CHANGED_IDLE && !bss_conf->idle) - iwl_mvm_sched_scan_stop(mvm, true); + iwl_mvm_scan_offload_stop(mvm, true); switch (vif->type) { case NL80211_IFTYPE_STATION: @@ -1692,7 +1695,7 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, switch (mvm->scan_status) { case IWL_MVM_SCAN_SCHED: - ret = iwl_mvm_sched_scan_stop(mvm, true); + ret = iwl_mvm_scan_offload_stop(mvm, true); if (ret) { ret = -EBUSY; goto out; @@ -1707,7 +1710,11 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); - ret = iwl_mvm_scan_request(mvm, vif, req); + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) + ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req); + else + ret = iwl_mvm_scan_request(mvm, vif, req); + if (ret) iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); out: @@ -2008,15 +2015,21 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, mvm->scan_status = IWL_MVM_SCAN_SCHED; - ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); - if (ret) - goto err; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { + ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); + if (ret) + goto err; + } ret = iwl_mvm_config_sched_scan_profiles(mvm, req); if (ret) goto err; - ret = iwl_mvm_sched_scan_start(mvm, req); + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) + ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies); + else + ret = iwl_mvm_sched_scan_start(mvm, req); + if (!ret) goto out; err: @@ -2035,7 +2048,7 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, int ret; mutex_lock(&mvm->mutex); - ret = iwl_mvm_sched_scan_stop(mvm, false); + ret = iwl_mvm_scan_offload_stop(mvm, false); mutex_unlock(&mvm->mutex); iwl_mvm_wait_for_async_handlers(mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fbe93a1df93a..927346e1a6e5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -533,7 +533,7 @@ struct iwl_mvm { /* Scan status, cmd (pre-allocated) and auxiliary station */ enum iwl_scan_status scan_status; - struct iwl_scan_cmd *scan_cmd; + void *scan_cmd; struct iwl_mcast_filter_cmd *mcast_filter_cmd; /* rx chain antennas set through debugfs for the scan command */ @@ -868,10 +868,19 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, struct cfg80211_sched_scan_request *req); int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, struct cfg80211_sched_scan_request *req); -int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm, bool notify); -int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify); +int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd); + +/* Unified scan */ +int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_scan_request *req); +int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_scan_ies *ies); /* MVM debugfs */ #ifdef CONFIG_IWLWIFI_DEBUGFS diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index b843870be8b7..4e2823faa5b9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -233,7 +233,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, true), RX_HANDLER(SCAN_OFFLOAD_COMPLETE, iwl_mvm_rx_scan_offload_complete_notif, true), - RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_sched_scan_results, + RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results, false), RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), @@ -284,6 +284,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(SCAN_OFFLOAD_ABORT_CMD), CMD(SCAN_OFFLOAD_COMPLETE), CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), + CMD(SCAN_ITERATION_COMPLETE), CMD(POWER_TABLE_CMD), CMD(WEP_KEY), CMD(REPLY_RX_PHY_CMD), @@ -505,10 +506,17 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, } } - scan_size = sizeof(struct iwl_scan_cmd) + - mvm->fw->ucode_capa.max_probe_length + - (mvm->fw->ucode_capa.n_scan_channels * - sizeof(struct iwl_scan_channel)); + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) + scan_size = sizeof(struct iwl_scan_req_unified_lmac) + + sizeof(struct iwl_scan_channel_cfg_lmac) * + mvm->fw->ucode_capa.n_scan_channels + + sizeof(struct iwl_scan_probe_req); + else + scan_size = sizeof(struct iwl_scan_cmd) + + mvm->fw->ucode_capa.max_probe_length + + mvm->fw->ucode_capa.n_scan_channels * + sizeof(struct iwl_scan_channel); + mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); if (!mvm->scan_cmd) goto out_free; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index f2dde5604a80..919ed0e18bb0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -97,10 +97,9 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) return cpu_to_le16(rx_chain); } -static inline __le32 -iwl_mvm_scan_rxon_flags(struct cfg80211_scan_request *req) +static __le32 iwl_mvm_scan_rxon_flags(enum ieee80211_band band) { - if (req->channels[0]->band == IEEE80211_BAND_2GHZ) + if (band == IEEE80211_BAND_2GHZ) return cpu_to_le32(PHY_BAND_24); else return cpu_to_le32(PHY_BAND_5); @@ -130,19 +129,19 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band, * request list, is not copied here, but inserted directly to the probe * request. */ -static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd, - struct cfg80211_scan_request *req, - int first) +static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid, + struct cfg80211_ssid *ssids, + int n_ssids, int first) { int fw_idx, req_idx; - for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx >= first; + for (req_idx = n_ssids - 1, fw_idx = 0; req_idx >= first; 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, - req->ssids[req_idx].ssid, - req->ssids[req_idx].ssid_len); + cmd_ssid[fw_idx].id = WLAN_EID_SSID; + cmd_ssid[fw_idx].len = ssids[req_idx].ssid_len; + memcpy(cmd_ssid[fw_idx].ssid, + ssids[req_idx].ssid, + ssids[req_idx].ssid_len); } } @@ -349,7 +348,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, if (params.passive_fragmented) cmd->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN; - cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req); + cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band); cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | MAC_FILTER_IN_BEACON); @@ -376,7 +375,8 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, cmd->scan_flags &= ~SCAN_FLAGS_PASSIVE2ACTIVE; } - iwl_mvm_scan_fill_ssids(cmd, req, basic_ssid ? 1 : 0); + iwl_mvm_scan_fill_ssids(cmd->direct_scan, req->ssids, req->n_ssids, + basic_ssid ? 1 : 0); cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_BT_DIS); @@ -450,16 +450,27 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, return 0; } -int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_sched_scan_results *notif = (void *)pkt->data; + u8 client_bitmap = 0; + + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { + struct iwl_sched_scan_results *notif = (void *)pkt->data; - if (notif->client_bitmap & SCAN_CLIENT_SCHED_SCAN) { - IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); - ieee80211_sched_scan_results(mvm->hw); + client_bitmap = notif->client_bitmap; + } + + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN || + client_bitmap & SCAN_CLIENT_SCHED_SCAN) { + if (mvm->scan_status == IWL_MVM_SCAN_SCHED) { + IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); + ieee80211_sched_scan_results(mvm->hw); + } else { + IWL_DEBUG_SCAN(mvm, "Scan results\n"); + } } return 0; @@ -503,7 +514,7 @@ static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait, }; } -int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) +static int iwl_mvm_cancel_regular_scan(struct iwl_mvm *mvm) { struct iwl_notification_wait wait_scan_abort; static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD, @@ -544,26 +555,45 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_scan_offload_complete *scan_notif = (void *)pkt->data; + u8 status, ebs_status; + + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) { + struct iwl_periodic_scan_complete *scan_notif; + scan_notif = (void *)pkt->data; + status = scan_notif->status; + ebs_status = scan_notif->ebs_status; + } else { + struct iwl_scan_offload_complete *scan_notif; + + scan_notif = (void *)pkt->data; + status = scan_notif->status; + ebs_status = scan_notif->ebs_status; + } /* scan status must be locked for proper checking */ lockdep_assert_held(&mvm->mutex); IWL_DEBUG_SCAN(mvm, - "Scheduled scan completed, status %s EBS status %s:%d\n", - scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? - "completed" : "aborted", scan_notif->ebs_status == - IWL_SCAN_EBS_SUCCESS ? "success" : "failed", - scan_notif->ebs_status); + "%s completed, status %s, EBS status %s\n", + mvm->scan_status == IWL_MVM_SCAN_SCHED ? + "Scheduled scan" : "Scan", + status == IWL_SCAN_OFFLOAD_COMPLETED ? + "completed" : "aborted", + ebs_status == IWL_SCAN_EBS_SUCCESS ? + "success" : "failed"); /* only call mac80211 completion if the stop was initiated by FW */ if (mvm->scan_status == IWL_MVM_SCAN_SCHED) { mvm->scan_status = IWL_MVM_SCAN_NONE; ieee80211_sched_scan_stopped(mvm->hw); + } else if (mvm->scan_status == IWL_MVM_SCAN_OS) { + mvm->scan_status = IWL_MVM_SCAN_NONE; + ieee80211_scan_completed(mvm->hw, + status == IWL_SCAN_OFFLOAD_ABORTED); } - mvm->last_ebs_successful = !scan_notif->ebs_status; + mvm->last_ebs_successful = !ebs_status; return 0; } @@ -631,8 +661,8 @@ static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list) } static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req, - struct iwl_scan_offload_cmd *scan, - u32 *ssid_bitmap) + struct iwl_ssid_ie *direct_scan, + u32 *ssid_bitmap, bool basic_ssid) { int i, j; int index; @@ -646,10 +676,10 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req, /* skip empty SSID matchsets */ if (!req->match_sets[i].ssid.ssid_len) continue; - scan->direct_scan[i].id = WLAN_EID_SSID; - scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len; - memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid, - scan->direct_scan[i].len); + direct_scan[i].id = WLAN_EID_SSID; + direct_scan[i].len = req->match_sets[i].ssid.ssid_len; + memcpy(direct_scan[i].ssid, req->match_sets[i].ssid.ssid, + direct_scan[i].len); } /* add SSIDs from scan SSID list */ @@ -657,14 +687,14 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req, for (j = 0; j < req->n_ssids && i < PROBE_OPTION_MAX; j++) { index = iwl_ssid_exist(req->ssids[j].ssid, req->ssids[j].ssid_len, - scan->direct_scan); + direct_scan); if (index < 0) { - if (!req->ssids[j].ssid_len) + if (!req->ssids[j].ssid_len && basic_ssid) continue; - scan->direct_scan[i].id = WLAN_EID_SSID; - scan->direct_scan[i].len = req->ssids[j].ssid_len; - memcpy(scan->direct_scan[i].ssid, req->ssids[j].ssid, - scan->direct_scan[i].len); + direct_scan[i].id = WLAN_EID_SSID; + direct_scan[i].len = req->ssids[j].ssid_len; + memcpy(direct_scan[i].ssid, req->ssids[j].ssid, + direct_scan[i].len); *ssid_bitmap |= BIT(i + 1); i++; } else { @@ -734,6 +764,8 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, int cmd_len; int ret; u8 *probes; + bool basic_ssid = !(mvm->fw->ucode_capa.flags & + IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID); struct iwl_scan_offload_cfg *scan_cfg; struct iwl_host_cmd cmd = { @@ -758,7 +790,8 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, ¶ms); scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len); - iwl_scan_offload_build_ssid(req, &scan_cfg->scan_cmd, &ssid_bitmap); + iwl_scan_offload_build_ssid(req, scan_cfg->scan_cmd.direct_scan, + &ssid_bitmap, basic_ssid); /* build tx frames for supported bands */ if (band_2ghz) { iwl_scan_offload_build_tx_cmd(mvm, vif, ies, @@ -893,7 +926,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, sizeof(scan_req), &scan_req); } -static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm) +static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm) { int ret; struct iwl_host_cmd cmd = { @@ -904,7 +937,9 @@ static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm) /* Exit instantly with error when device is not ready * to receive scan abort command or it does not perform * scheduled scan currently */ - if (mvm->scan_status != IWL_MVM_SCAN_SCHED) + if (mvm->scan_status != IWL_MVM_SCAN_SCHED && + (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) || + mvm->scan_status != IWL_MVM_SCAN_OS)) return -EIO; ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status); @@ -926,16 +961,19 @@ static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm) return ret; } -int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm, bool notify) +int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify) { int ret; struct iwl_notification_wait wait_scan_done; static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, }; + bool sched = mvm->scan_status == IWL_MVM_SCAN_SCHED; lockdep_assert_held(&mvm->mutex); - if (mvm->scan_status != IWL_MVM_SCAN_SCHED) { - IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n"); + if (mvm->scan_status != IWL_MVM_SCAN_SCHED && + (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) || + mvm->scan_status != IWL_MVM_SCAN_OS)) { + IWL_DEBUG_SCAN(mvm, "No scan to stop\n"); return 0; } @@ -944,14 +982,16 @@ int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm, bool notify) ARRAY_SIZE(scan_done_notif), NULL, NULL); - ret = iwl_mvm_send_sched_scan_abort(mvm); + ret = iwl_mvm_send_scan_offload_abort(mvm); if (ret) { - IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret); + IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n", + sched ? "offloaded " : "", ret); iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); return ret; } - IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n"); + IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n", + sched ? "offloaded " : ""); ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ); if (ret) @@ -964,8 +1004,311 @@ int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm, bool notify) */ mvm->scan_status = IWL_MVM_SCAN_NONE; - if (notify) - ieee80211_sched_scan_stopped(mvm->hw); + if (notify) { + if (sched) + ieee80211_sched_scan_stopped(mvm->hw); + else + ieee80211_scan_completed(mvm->hw, true); + } return 0; } + +static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm, + struct iwl_scan_req_tx_cmd *tx_cmd, + bool no_cck) +{ + tx_cmd[0].tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | + TX_CMD_FLG_BT_DIS); + tx_cmd[0].rate_n_flags = iwl_mvm_scan_rate_n_flags(mvm, + IEEE80211_BAND_2GHZ, + no_cck); + tx_cmd[0].sta_id = mvm->aux_sta.sta_id; + + tx_cmd[1].tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | + TX_CMD_FLG_BT_DIS); + tx_cmd[1].rate_n_flags = iwl_mvm_scan_rate_n_flags(mvm, + IEEE80211_BAND_5GHZ, + no_cck); + tx_cmd[1].sta_id = mvm->aux_sta.sta_id; +} + +static void +iwl_mvm_lmac_scan_cfg_channels(struct iwl_mvm *mvm, + struct ieee80211_channel **channels, + int n_channels, u32 ssid_bitmap, + struct iwl_scan_req_unified_lmac *cmd) +{ + struct iwl_scan_channel_cfg_lmac *channel_cfg = (void *)&cmd->data; + int i; + + for (i = 0; i < n_channels; i++) { + channel_cfg[i].channel_num = + cpu_to_le16(channels[i]->hw_value); + channel_cfg[i].iter_count = cpu_to_le16(1); + channel_cfg[i].iter_interval = 0; + channel_cfg[i].flags = + cpu_to_le32(IWL_UNIFIED_SCAN_CHANNEL_PARTIAL | + ssid_bitmap); + } +} + +static void +iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct ieee80211_scan_ies *ies, + struct iwl_scan_req_unified_lmac *cmd) +{ + struct iwl_scan_probe_req *preq = (void *)(cmd->data + + sizeof(struct iwl_scan_channel_cfg_lmac) * + mvm->fw->ucode_capa.n_scan_channels); + struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf; + u8 *pos; + + frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); + eth_broadcast_addr(frame->da); + memcpy(frame->sa, vif->addr, ETH_ALEN); + eth_broadcast_addr(frame->bssid); + frame->seq_ctrl = 0; + + pos = frame->u.probe_req.variable; + *pos++ = WLAN_EID_SSID; + *pos++ = 0; + + preq->mac_header.offset = 0; + preq->mac_header.len = cpu_to_le16(24 + 2); + + memcpy(pos, ies->ies[IEEE80211_BAND_2GHZ], + ies->len[IEEE80211_BAND_2GHZ]); + preq->band_data[0].offset = cpu_to_le16(pos - preq->buf); + preq->band_data[0].len = cpu_to_le16(ies->len[IEEE80211_BAND_2GHZ]); + pos += ies->len[IEEE80211_BAND_2GHZ]; + + memcpy(pos, ies->ies[IEEE80211_BAND_5GHZ], + ies->len[IEEE80211_BAND_5GHZ]); + preq->band_data[1].offset = cpu_to_le16(pos - preq->buf); + preq->band_data[1].len = cpu_to_le16(ies->len[IEEE80211_BAND_5GHZ]); + pos += ies->len[IEEE80211_BAND_5GHZ]; + + memcpy(pos, ies->common_ies, ies->common_ie_len); + preq->common_data.offset = cpu_to_le16(pos - preq->buf); + preq->common_data.len = cpu_to_le16(ies->common_ie_len); +} + +static void +iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm, + struct iwl_scan_req_unified_lmac *cmd, + struct iwl_mvm_scan_params *params) +{ + cmd->active_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].active; + cmd->passive_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].passive; + /* TODO: Use params; now fragmented isn't used. */ + cmd->fragmented_dwell = 0; + cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm); + cmd->max_out_time = cpu_to_le32(params->max_out_time); + cmd->suspend_time = cpu_to_le32(params->suspend_time); + cmd->scan_prio = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH); + cmd->channel_opt[0].flags = mvm->last_ebs_successful ? + cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS & + IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE & + IWL_SCAN_CHANNEL_FLAG_CACHE_ADD) : + 0; + cmd->channel_opt[0].non_ebs_ratio = 0; + cmd->iter_num = cpu_to_le32(1); + cmd->delay = 0; +} + +int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_scan_request *req) +{ + struct iwl_host_cmd hcmd = { + .id = SCAN_OFFLOAD_REQUEST_CMD, + .len = { sizeof(struct iwl_scan_req_unified_lmac) + + sizeof(struct iwl_scan_channel_cfg_lmac) * + mvm->fw->ucode_capa.n_scan_channels + + sizeof(struct iwl_scan_probe_req), }, + .data = { mvm->scan_cmd, }, + .dataflags = { IWL_HCMD_DFL_NOCOPY, }, + }; + struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; + struct iwl_mvm_scan_params params = {}; + u32 flags; + int ssid_bitmap = 0; + int ret, i; + + lockdep_assert_held(&mvm->mutex); + + /* we should have failed registration if scan_cmd was NULL */ + if (WARN_ON(mvm->scan_cmd == NULL)) + return -ENOMEM; + + if (WARN_ON_ONCE(req->req.n_ssids > PROBE_OPTION_MAX || + req->ies.common_ie_len + req->ies.len[0] + + req->ies.len[1] + 24 + 2 > + SCAN_OFFLOAD_PROBE_REQ_SIZE || + req->req.n_channels > + mvm->fw->ucode_capa.n_scan_channels)) + return -1; + + mvm->scan_status = IWL_MVM_SCAN_OS; + + iwl_mvm_scan_calc_params(mvm, vif, req->req.n_ssids, req->req.flags, + ¶ms); + + iwl_mvm_build_generic_unified_scan_cmd(mvm, cmd, ¶ms); + + cmd->n_channels = (u8)req->req.n_channels; + + flags = IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL; + + if (req->req.n_ssids == 1 && req->req.ssids[0].ssid_len != 0) + flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; + + if (params.passive_fragmented) + flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED; + + if (req->req.n_ssids == 0) + flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE; + + cmd->scan_flags = cpu_to_le32(flags); + + cmd->flags = iwl_mvm_scan_rxon_flags(req->req.channels[0]->band); + cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | + MAC_FILTER_IN_BEACON); + iwl_mvm_unified_scan_fill_tx_cmd(mvm, cmd->tx_cmd, req->req.no_cck); + iwl_mvm_scan_fill_ssids(cmd->direct_scan, req->req.ssids, + req->req.n_ssids, 0); + + cmd->schedule[0].delay = 0; + cmd->schedule[0].iterations = 1; + cmd->schedule[0].full_scan_mul = 0; + cmd->schedule[1].delay = 0; + cmd->schedule[1].iterations = 0; + cmd->schedule[1].full_scan_mul = 0; + + for (i = 1; i <= req->req.n_ssids; i++) + ssid_bitmap |= BIT(i); + + iwl_mvm_lmac_scan_cfg_channels(mvm, req->req.channels, + req->req.n_channels, ssid_bitmap, + cmd); + + iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, cmd); + + ret = iwl_mvm_send_cmd(mvm, &hcmd); + if (!ret) { + IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n"); + } else { + /* + * If the scan failed, it usually means that the FW was unable + * to allocate the time events. Warn on it, but maybe we + * should try to send the command again with different params. + */ + IWL_ERR(mvm, "Scan failed! ret %d\n", ret); + mvm->scan_status = IWL_MVM_SCAN_NONE; + ret = -EIO; + } + return ret; +} + +int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_scan_ies *ies) +{ + struct iwl_host_cmd hcmd = { + .id = SCAN_OFFLOAD_REQUEST_CMD, + .len = { sizeof(struct iwl_scan_req_unified_lmac) + + sizeof(struct iwl_scan_channel_cfg_lmac) * + mvm->fw->ucode_capa.n_scan_channels + + sizeof(struct iwl_scan_probe_req), }, + .data = { mvm->scan_cmd, }, + .dataflags = { IWL_HCMD_DFL_NOCOPY, }, + }; + struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; + struct iwl_mvm_scan_params params = {}; + int ret; + u32 flags = 0, ssid_bitmap = 0; + + lockdep_assert_held(&mvm->mutex); + + /* we should have failed registration if scan_cmd was NULL */ + if (WARN_ON(mvm->scan_cmd == NULL)) + return -ENOMEM; + + if (WARN_ON_ONCE(req->n_ssids > PROBE_OPTION_MAX || + ies->common_ie_len + ies->len[0] + ies->len[1] + 24 + 2 + > SCAN_OFFLOAD_PROBE_REQ_SIZE || + req->n_channels > mvm->fw->ucode_capa.n_scan_channels)) + return -ENOBUFS; + + iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, ¶ms); + + iwl_mvm_build_generic_unified_scan_cmd(mvm, cmd, ¶ms); + + cmd->n_channels = (u8)req->n_channels; + + if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { + IWL_DEBUG_SCAN(mvm, + "Sending scheduled scan with filtering, n_match_sets %d\n", + req->n_match_sets); + } else { + IWL_DEBUG_SCAN(mvm, + "Sending Scheduled scan without filtering\n"); + flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL; + } + + if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0) + flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; + + if (params.passive_fragmented) + flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED; + + if (req->n_ssids == 0) + flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE; + + cmd->scan_flags = cpu_to_le32(flags); + + cmd->flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band); + cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | + MAC_FILTER_IN_BEACON); + iwl_mvm_unified_scan_fill_tx_cmd(mvm, cmd->tx_cmd, false); + iwl_scan_offload_build_ssid(req, cmd->direct_scan, &ssid_bitmap, false); + + cmd->schedule[0].delay = req->interval / MSEC_PER_SEC; + cmd->schedule[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS; + cmd->schedule[0].full_scan_mul = 1; + + cmd->schedule[1].delay = req->interval / MSEC_PER_SEC; + cmd->schedule[1].iterations = 0xff; + cmd->schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER; + + iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels, + ssid_bitmap, cmd); + + iwl_mvm_build_unified_scan_probe(mvm, vif, ies, cmd); + + ret = iwl_mvm_send_cmd(mvm, &hcmd); + if (!ret) { + IWL_DEBUG_SCAN(mvm, + "Sched scan request was sent successfully\n"); + } else { + /* + * If the scan failed, it usually means that the FW was unable + * to allocate the time events. Warn on it, but maybe we + * should try to send the command again with different params. + */ + IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret); + mvm->scan_status = IWL_MVM_SCAN_NONE; + ret = -EIO; + } + return ret; +} + + +int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) +{ + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) + return iwl_mvm_scan_offload_stop(mvm, true); + return iwl_mvm_cancel_regular_scan(mvm); +} -- cgit v1.2.3 From af91344c23fd23be44bc6e3dfb2c7b47bb9e6e11 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Thu, 12 Jun 2014 19:29:40 +0300 Subject: iwlwifi: mvm: init lmac scan command Initialize LMAC scan command. Fix EBS flag to be dependant on TLV flg and fix other bugs. Signed-off-by: David Spinadel Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 919ed0e18bb0..14fc6adc963a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -1099,6 +1099,7 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm, struct iwl_scan_req_unified_lmac *cmd, struct iwl_mvm_scan_params *params) { + memset(cmd, 0, ksize(cmd)); cmd->active_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].active; cmd->passive_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].passive; /* TODO: Use params; now fragmented isn't used. */ @@ -1107,14 +1108,19 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm, cmd->max_out_time = cpu_to_le32(params->max_out_time); cmd->suspend_time = cpu_to_le32(params->suspend_time); cmd->scan_prio = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH); - cmd->channel_opt[0].flags = mvm->last_ebs_successful ? - cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS & - IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE & - IWL_SCAN_CHANNEL_FLAG_CACHE_ADD) : - 0; - cmd->channel_opt[0].non_ebs_ratio = 0; cmd->iter_num = cpu_to_le32(1); - cmd->delay = 0; + + if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT && + mvm->last_ebs_successful) { + cmd->channel_opt[0].flags = + cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS | + IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | + IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); + cmd->channel_opt[1].flags = + cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS | + IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | + IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); + } } int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, -- cgit v1.2.3 From b14fc2befb3bdd01d05d2e399b05c9c8ead6a5ca Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Wed, 25 Jun 2014 13:17:53 +0300 Subject: iwlwifi: mvm: fix endianity in scan command Signed-off-by: David Spinadel Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 2 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 48a1d8f5675d..c02a9e45ec5e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -509,7 +509,7 @@ struct iwl_scan_offload_profile_cfg { * @full_scan_mul: number of partial scans before each full scan */ struct iwl_scan_offload_schedule { - u16 delay; + __le16 delay; u8 iterations; u8 full_scan_mul; } __packed; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 14fc6adc963a..004b1f5d0314 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -899,11 +899,11 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, .watchdog = IWL_SCHED_SCAN_WATCHDOG, .schedule_line[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS, - .schedule_line[0].delay = req->interval / 1000, + .schedule_line[0].delay = cpu_to_le16(req->interval / 1000), .schedule_line[0].full_scan_mul = 1, .schedule_line[1].iterations = 0xff, - .schedule_line[1].delay = req->interval / 1000, + .schedule_line[1].delay = cpu_to_le16(req->interval / 1000), .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER, }; @@ -1281,11 +1281,11 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, iwl_mvm_unified_scan_fill_tx_cmd(mvm, cmd->tx_cmd, false); iwl_scan_offload_build_ssid(req, cmd->direct_scan, &ssid_bitmap, false); - cmd->schedule[0].delay = req->interval / MSEC_PER_SEC; + cmd->schedule[0].delay = cpu_to_le16(req->interval / MSEC_PER_SEC); cmd->schedule[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS; cmd->schedule[0].full_scan_mul = 1; - cmd->schedule[1].delay = req->interval / MSEC_PER_SEC; + cmd->schedule[1].delay = cpu_to_le16(req->interval / MSEC_PER_SEC); cmd->schedule[1].iterations = 0xff; cmd->schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER; -- cgit v1.2.3 From ca55eb47822560e56b126eeb05b3cd0b8415acfd Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Sun, 29 Jun 2014 11:53:06 +0300 Subject: iwlwifi: 8000: drop a print when the address is invalid when driver takes the MAC address from the HW section and it isn't valid - print an error. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index dd76ed28884d..018af2957d3b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -549,6 +549,9 @@ static void iwl_set_hw_address_family_8000(struct device *dev, data->hw_addr[1] = hw_addr[2]; data->hw_addr[0] = hw_addr[3]; } + if (!is_valid_ether_addr(data->hw_addr)) + IWL_ERR_DEV(dev, + "mac address from hw section is not valid\n"); return; } -- cgit v1.2.3 From 63cbe180f8bfcf355516b09849c71fed19e035b3 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 13 May 2014 22:28:35 +0300 Subject: iwlwifi: mvm: let iwl_mvm_update_quotas disregard a disabled vif In some cases (e.g. when we're doing a channel switch), we may need to disable the quota of a vif temporarily. In order to do so, add an argument to the iwl_mvm_update_quotas() function to tell if the passed vif is a new one or if it should be disregarded. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 28 +++++++++++++++++----------- drivers/net/wireless/iwlwifi/mvm/mvm.h | 24 +++++++++++++++++++++++- drivers/net/wireless/iwlwifi/mvm/quota.c | 26 +++++++++++++++++++------- drivers/net/wireless/iwlwifi/mvm/utils.c | 3 ++- 4 files changed, 61 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 522aa039a490..71353bd03a70 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -834,7 +834,8 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); iwl_mvm_d0i3_enable_tx(mvm, NULL); - ret = iwl_mvm_update_quotas(mvm, NULL); + ret = iwl_mvm_update_quotas(mvm, NULL, + IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); if (ret) IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", ret); @@ -1421,7 +1422,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, if (changes & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { /* add quota for this interface */ - ret = iwl_mvm_update_quotas(mvm, vif); + ret = iwl_mvm_update_quotas(mvm, vif, + IWL_MVM_QUOTA_UPDATE_TYPE_NEW); if (ret) { IWL_ERR(mvm, "failed to update quotas\n"); return; @@ -1469,7 +1471,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; /* remove quota for this interface */ - ret = iwl_mvm_update_quotas(mvm, NULL); + ret = iwl_mvm_update_quotas(mvm, NULL, + IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); if (ret) IWL_ERR(mvm, "failed to update quotas\n"); @@ -1568,7 +1571,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, /* power updated needs to be done before quotas */ iwl_mvm_power_update_mac(mvm); - ret = iwl_mvm_update_quotas(mvm, vif); + ret = iwl_mvm_update_quotas(mvm, vif, IWL_MVM_QUOTA_UPDATE_TYPE_NEW); if (ret) goto out_quota_failed; @@ -1617,7 +1620,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, if (vif->p2p && mvm->p2p_device_vif) iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false); - iwl_mvm_update_quotas(mvm, NULL); + iwl_mvm_update_quotas(mvm, NULL, IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); iwl_mvm_binding_remove_vif(mvm, vif); @@ -2403,14 +2406,15 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, */ if (vif->type == NL80211_IFTYPE_MONITOR) { mvmvif->monitor_active = true; - ret = iwl_mvm_update_quotas(mvm, vif); + ret = iwl_mvm_update_quotas(mvm, vif, + IWL_MVM_QUOTA_UPDATE_TYPE_NEW); if (ret) goto out_remove_binding; } /* Handle binding during CSA */ if (vif->type == NL80211_IFTYPE_AP) { - iwl_mvm_update_quotas(mvm, vif); + iwl_mvm_update_quotas(mvm, vif, IWL_MVM_QUOTA_UPDATE_TYPE_NEW); iwl_mvm_mac_ctxt_changed(mvm, vif, false); } @@ -2442,7 +2446,8 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, goto out_unlock; case NL80211_IFTYPE_MONITOR: mvmvif->monitor_active = false; - iwl_mvm_update_quotas(mvm, NULL); + iwl_mvm_update_quotas(mvm, NULL, + IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); break; case NL80211_IFTYPE_AP: /* This part is triggered only during CSA */ @@ -2450,8 +2455,8 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, goto out_unlock; mvmvif->ap_ibss_active = false; - iwl_mvm_update_quotas(mvm, NULL); - /*TODO: bt_coex notification here? */ + iwl_mvm_update_quotas(mvm, NULL, + IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); default: break; } @@ -2515,7 +2520,8 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, mvm->noa_duration = noa_duration; mvm->noa_vif = vif; - return iwl_mvm_update_quotas(mvm, NULL); + return iwl_mvm_update_quotas(mvm, NULL, + IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); case IWL_MVM_TM_CMD_SET_BEACON_FILTER: /* must be associated client vif - ignore authorized */ if (!vif || vif->type != NL80211_IFTYPE_STATION || diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 927346e1a6e5..55e42f4d6cce 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -844,7 +844,29 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); /* Quota management */ -int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif); + +/** + * enum iwl_mvm_quota_update_type - quota update type + + * @IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR: regular quota update, use the + * existing vifs (ie. no new vif nor a disabled vif is passed). + * @IWL_MVM_QUOTA_UPDATE_TYPE_NEW: a new vif is being added to the + * quota calculation and needs to be treated differently. + * @IWL_MVM_QUOTA_UPDATE_TYPE_DISABLED: temporarily disable a vif from + * the quota calculation. The mvm mutex must remain held for the + * entire time during which the vif is to remain disabled, + * otherwise there is no guarantee that another code flow will + * not reenable it accidentally (by updating the quotas without + * marking the vif as disabled). + */ +enum iwl_mvm_quota_update_type { + IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR, + IWL_MVM_QUOTA_UPDATE_TYPE_NEW, + IWL_MVM_QUOTA_UPDATE_TYPE_DISABLED, +}; + +int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + enum iwl_mvm_quota_update_type type); /* Scanning */ int iwl_mvm_scan_request(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index ba68d7b84505..75d2c95b4076 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -73,7 +73,8 @@ struct iwl_mvm_quota_iterator_data { int colors[MAX_BINDINGS]; int low_latency[MAX_BINDINGS]; int n_low_latency_bindings; - struct ieee80211_vif *new_vif; + struct ieee80211_vif *vif; + enum iwl_mvm_quota_update_type type; }; static void iwl_mvm_quota_iterator(void *_data, u8 *mac, @@ -89,7 +90,7 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, * the add_interface callback (otherwise it won't show * up in iteration) */ - if (vif == data->new_vif) + if (data->type == IWL_MVM_QUOTA_UPDATE_TYPE_NEW && vif == data->vif) return; if (!mvmvif->phy_ctxt) @@ -109,6 +110,10 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, else WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color); + if (data->type == IWL_MVM_QUOTA_UPDATE_TYPE_DISABLED && + vif == data->vif) + return; + switch (vif->type) { case NL80211_IFTYPE_STATION: if (vif->bss_conf.assoc) @@ -171,14 +176,16 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, #endif } -int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) +int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + enum iwl_mvm_quota_update_type type) { struct iwl_time_quota_cmd cmd = {}; int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat; struct iwl_mvm_quota_iterator_data data = { .n_interfaces = {}, .colors = { -1, -1, -1, -1 }, - .new_vif = newvif, + .vif = vif, + .type = type, }; lockdep_assert_held(&mvm->mutex); @@ -190,12 +197,17 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) /* iterator data above must match */ BUILD_BUG_ON(MAX_BINDINGS != 4); + if (WARN_ON_ONCE((type != IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR && !vif) || + (type == IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR && vif))) + return -EINVAL; + ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_quota_iterator, &data); - if (newvif) { - data.new_vif = NULL; - iwl_mvm_quota_iterator(&data, newvif->addr, newvif); + if (type == IWL_MVM_QUOTA_UPDATE_TYPE_NEW) { + data.vif = NULL; + data.type = IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR; + iwl_mvm_quota_iterator(&data, vif->addr, vif); } /* diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index ac249da8a22b..98ff64961896 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -631,7 +631,8 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvmvif->low_latency = value; - res = iwl_mvm_update_quotas(mvm, NULL); + res = iwl_mvm_update_quotas(mvm, NULL, + IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); if (res) return res; -- cgit v1.2.3 From 63faceb60b8e026d62db228ff04038e8089fa74a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 23 May 2014 16:15:11 +0200 Subject: iwlwifi: mvm: don't send zero quota to the firmware There are some cases where we can currently send zero quota for a valid binding, e.g. if we update while an interface is bound to a channel context but not yet acting as an AP. Avoid this by reordering the checks. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/quota.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 75d2c95b4076..8bb2fced0811 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -105,11 +105,6 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, if (WARN_ON_ONCE(id >= MAX_BINDINGS)) return; - if (data->colors[id] < 0) - data->colors[id] = mvmvif->phy_ctxt->color; - else - WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color); - if (data->type == IWL_MVM_QUOTA_UPDATE_TYPE_DISABLED && vif == data->vif) return; @@ -135,6 +130,11 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, return; } + if (data->colors[id] < 0) + data->colors[id] = mvmvif->phy_ctxt->color; + else + WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color); + data->n_interfaces[id]++; if (iwl_mvm_vif_low_latency(mvmvif) && !data->low_latency[id]) { -- cgit v1.2.3 From 99a1230d9d1cb5d52bb37b8c03f3931502f0e44d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 23 May 2014 16:13:57 +0200 Subject: iwlwifi: mvm: validate that we don't send zero quota The firmware currently deals with zero quota for a given binding, but it seems odd to send that down. Make sure that we don't do that. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/quota.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 8bb2fced0811..3f18786311f4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -297,6 +297,14 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_adjust_quota_for_noa(mvm, &cmd); + /* check that we have non-zero quota for all valid bindings */ + for (i = 0; i < MAX_BINDINGS; i++) { + if (cmd.quotas[i].id_and_color == cpu_to_le32(FW_CTXT_INVALID)) + continue; + WARN_ONCE(cmd.quotas[i].quota == 0, + "zero quota on binding %d\n", i); + } + ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd); if (ret) -- cgit v1.2.3 From 494983e0e7ae24de7ad3eaa2edc1e31a6a0d7502 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 23 May 2014 16:17:13 +0200 Subject: iwlwifi: mvm: don't pass update type to quota iterator Simplify the quota iterator by not passing the update type, it only needs to know whether or not to skip an interface. Signed-off-by: Johannes Berg Reviewed-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/quota.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 3f18786311f4..6de0c6352943 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -73,8 +73,7 @@ struct iwl_mvm_quota_iterator_data { int colors[MAX_BINDINGS]; int low_latency[MAX_BINDINGS]; int n_low_latency_bindings; - struct ieee80211_vif *vif; - enum iwl_mvm_quota_update_type type; + struct ieee80211_vif *skip_vif; }; static void iwl_mvm_quota_iterator(void *_data, u8 *mac, @@ -89,8 +88,9 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, * skip it here in case we're not called from within * the add_interface callback (otherwise it won't show * up in iteration) + * Also skip disabled interfaces here immediately. */ - if (data->type == IWL_MVM_QUOTA_UPDATE_TYPE_NEW && vif == data->vif) + if (vif == data->skip_vif) return; if (!mvmvif->phy_ctxt) @@ -105,10 +105,6 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, if (WARN_ON_ONCE(id >= MAX_BINDINGS)) return; - if (data->type == IWL_MVM_QUOTA_UPDATE_TYPE_DISABLED && - vif == data->vif) - return; - switch (vif->type) { case NL80211_IFTYPE_STATION: if (vif->bss_conf.assoc) @@ -184,8 +180,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_quota_iterator_data data = { .n_interfaces = {}, .colors = { -1, -1, -1, -1 }, - .vif = vif, - .type = type, + .skip_vif = vif, }; lockdep_assert_held(&mvm->mutex); @@ -205,8 +200,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_quota_iterator, &data); if (type == IWL_MVM_QUOTA_UPDATE_TYPE_NEW) { - data.vif = NULL; - data.type = IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR; + data.skip_vif = NULL; iwl_mvm_quota_iterator(&data, vif->addr, vif); } -- cgit v1.2.3 From 0166230c6c696d501a2d2616a30e295b71e39d43 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 6 Jun 2014 15:18:45 +0200 Subject: iwlwifi: mvm: remove update type argument from quota update It turns out that adding the update type argument was pointless as quota update is never called from the add_interface() callback. Therefore, IWL_MVM_QUOTA_UPDATE_TYPE_NEW isn't actually needed and then only a "disabled_vif" argument is needed for the upcoming CSA work. Remove the whole enum iwl_mvm_quota_update_type and pass the right arguments (always NULL for disabled vif right now) to the function in all current call sites. Signed-off-by: Johannes Berg Reviewed-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 27 ++++++++++----------------- drivers/net/wireless/iwlwifi/mvm/mvm.h | 25 ++----------------------- drivers/net/wireless/iwlwifi/mvm/quota.c | 26 ++++++-------------------- drivers/net/wireless/iwlwifi/mvm/utils.c | 3 +-- 4 files changed, 19 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 71353bd03a70..72f82a33856c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -834,8 +834,7 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); iwl_mvm_d0i3_enable_tx(mvm, NULL); - ret = iwl_mvm_update_quotas(mvm, NULL, - IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); + ret = iwl_mvm_update_quotas(mvm, NULL); if (ret) IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", ret); @@ -1422,8 +1421,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, if (changes & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { /* add quota for this interface */ - ret = iwl_mvm_update_quotas(mvm, vif, - IWL_MVM_QUOTA_UPDATE_TYPE_NEW); + ret = iwl_mvm_update_quotas(mvm, NULL); if (ret) { IWL_ERR(mvm, "failed to update quotas\n"); return; @@ -1471,8 +1469,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; /* remove quota for this interface */ - ret = iwl_mvm_update_quotas(mvm, NULL, - IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); + ret = iwl_mvm_update_quotas(mvm, NULL); if (ret) IWL_ERR(mvm, "failed to update quotas\n"); @@ -1571,7 +1568,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, /* power updated needs to be done before quotas */ iwl_mvm_power_update_mac(mvm); - ret = iwl_mvm_update_quotas(mvm, vif, IWL_MVM_QUOTA_UPDATE_TYPE_NEW); + ret = iwl_mvm_update_quotas(mvm, NULL); if (ret) goto out_quota_failed; @@ -1620,7 +1617,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, if (vif->p2p && mvm->p2p_device_vif) iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false); - iwl_mvm_update_quotas(mvm, NULL, IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); + iwl_mvm_update_quotas(mvm, NULL); iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta); iwl_mvm_binding_remove_vif(mvm, vif); @@ -2406,15 +2403,14 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, */ if (vif->type == NL80211_IFTYPE_MONITOR) { mvmvif->monitor_active = true; - ret = iwl_mvm_update_quotas(mvm, vif, - IWL_MVM_QUOTA_UPDATE_TYPE_NEW); + ret = iwl_mvm_update_quotas(mvm, NULL); if (ret) goto out_remove_binding; } /* Handle binding during CSA */ if (vif->type == NL80211_IFTYPE_AP) { - iwl_mvm_update_quotas(mvm, vif, IWL_MVM_QUOTA_UPDATE_TYPE_NEW); + iwl_mvm_update_quotas(mvm, NULL); iwl_mvm_mac_ctxt_changed(mvm, vif, false); } @@ -2446,8 +2442,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, goto out_unlock; case NL80211_IFTYPE_MONITOR: mvmvif->monitor_active = false; - iwl_mvm_update_quotas(mvm, NULL, - IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); + iwl_mvm_update_quotas(mvm, NULL); break; case NL80211_IFTYPE_AP: /* This part is triggered only during CSA */ @@ -2455,8 +2450,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, goto out_unlock; mvmvif->ap_ibss_active = false; - iwl_mvm_update_quotas(mvm, NULL, - IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); + iwl_mvm_update_quotas(mvm, NULL); default: break; } @@ -2520,8 +2514,7 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, mvm->noa_duration = noa_duration; mvm->noa_vif = vif; - return iwl_mvm_update_quotas(mvm, NULL, - IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); + return iwl_mvm_update_quotas(mvm, NULL); case IWL_MVM_TM_CMD_SET_BEACON_FILTER: /* must be associated client vif - ignore authorized */ if (!vif || vif->type != NL80211_IFTYPE_STATION || diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 55e42f4d6cce..5fedd5521432 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -844,29 +844,8 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); /* Quota management */ - -/** - * enum iwl_mvm_quota_update_type - quota update type - - * @IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR: regular quota update, use the - * existing vifs (ie. no new vif nor a disabled vif is passed). - * @IWL_MVM_QUOTA_UPDATE_TYPE_NEW: a new vif is being added to the - * quota calculation and needs to be treated differently. - * @IWL_MVM_QUOTA_UPDATE_TYPE_DISABLED: temporarily disable a vif from - * the quota calculation. The mvm mutex must remain held for the - * entire time during which the vif is to remain disabled, - * otherwise there is no guarantee that another code flow will - * not reenable it accidentally (by updating the quotas without - * marking the vif as disabled). - */ -enum iwl_mvm_quota_update_type { - IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR, - IWL_MVM_QUOTA_UPDATE_TYPE_NEW, - IWL_MVM_QUOTA_UPDATE_TYPE_DISABLED, -}; - -int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_quota_update_type type); +int iwl_mvm_update_quotas(struct iwl_mvm *mvm, + struct ieee80211_vif *disabled_vif); /* Scanning */ int iwl_mvm_scan_request(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 6de0c6352943..4e20b3ce2b6a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -73,7 +73,7 @@ struct iwl_mvm_quota_iterator_data { int colors[MAX_BINDINGS]; int low_latency[MAX_BINDINGS]; int n_low_latency_bindings; - struct ieee80211_vif *skip_vif; + struct ieee80211_vif *disabled_vif; }; static void iwl_mvm_quota_iterator(void *_data, u8 *mac, @@ -83,14 +83,8 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); u16 id; - /* - * We'll account for the new interface (if any) below, - * skip it here in case we're not called from within - * the add_interface callback (otherwise it won't show - * up in iteration) - * Also skip disabled interfaces here immediately. - */ - if (vif == data->skip_vif) + /* skip disabled interfaces here immediately */ + if (vif == data->disabled_vif) return; if (!mvmvif->phy_ctxt) @@ -172,15 +166,15 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, #endif } -int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_quota_update_type type) +int iwl_mvm_update_quotas(struct iwl_mvm *mvm, + struct ieee80211_vif *disabled_vif) { struct iwl_time_quota_cmd cmd = {}; int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat; struct iwl_mvm_quota_iterator_data data = { .n_interfaces = {}, .colors = { -1, -1, -1, -1 }, - .skip_vif = vif, + .disabled_vif = disabled_vif, }; lockdep_assert_held(&mvm->mutex); @@ -192,17 +186,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* iterator data above must match */ BUILD_BUG_ON(MAX_BINDINGS != 4); - if (WARN_ON_ONCE((type != IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR && !vif) || - (type == IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR && vif))) - return -EINVAL; - ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_quota_iterator, &data); - if (type == IWL_MVM_QUOTA_UPDATE_TYPE_NEW) { - data.skip_vif = NULL; - iwl_mvm_quota_iterator(&data, vif->addr, vif); - } /* * The FW's scheduling session consists of diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 98ff64961896..ac249da8a22b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -631,8 +631,7 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvmvif->low_latency = value; - res = iwl_mvm_update_quotas(mvm, NULL, - IWL_MVM_QUOTA_UPDATE_TYPE_REGULAR); + res = iwl_mvm_update_quotas(mvm, NULL); if (res) return res; -- cgit v1.2.3 From b08c1d972a3b9135a0ccc5432309ee635841f466 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 20 May 2014 23:31:05 +0300 Subject: iwlwifi: mvm: add switch_vif_chanctx operation Implement the switch_vif_chanctx operation with support for a single-vif and SWAP mode. The REASSIGN mode and multi-vifs are not supported yet. This operation needs to implement 4 steps, namely unassign, remove, add and assign the chanctx. In order to do this, split out these operations into locked and non-locked parts, thus allowing us to call them while locked. Additionally, in order to allow us to restart the hardware when something fails, add a boolean to the iwl_mvm_nic_restart() function that tells whether the restart was triggered by a FW error or something else. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 154 +++++++++++++++++++++++----- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 + drivers/net/wireless/iwlwifi/mvm/ops.c | 11 +- 3 files changed, 135 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 72f82a33856c..24cc56957339 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2282,17 +2282,17 @@ static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw) return 0; } -static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx) +static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm, + struct ieee80211_chanctx_conf *ctx) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; struct iwl_mvm_phy_ctxt *phy_ctxt; int ret; + lockdep_assert_held(&mvm->mutex); + IWL_DEBUG_MAC80211(mvm, "Add channel context\n"); - mutex_lock(&mvm->mutex); phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); if (!phy_ctxt) { ret = -ENOSPC; @@ -2310,19 +2310,40 @@ static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw, iwl_mvm_phy_ctxt_ref(mvm, phy_ctxt); *phy_ctxt_id = phy_ctxt->id; out: + return ret; +} + +static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; + + mutex_lock(&mvm->mutex); + ret = __iwl_mvm_add_chanctx(mvm, ctx); mutex_unlock(&mvm->mutex); + return ret; } +static void __iwl_mvm_remove_chanctx(struct iwl_mvm *mvm, + struct ieee80211_chanctx_conf *ctx) +{ + u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; + struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; + + lockdep_assert_held(&mvm->mutex); + + iwl_mvm_phy_ctxt_unref(mvm, phy_ctxt); +} + static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; - struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; mutex_lock(&mvm->mutex); - iwl_mvm_phy_ctxt_unref(mvm, phy_ctxt); + __iwl_mvm_remove_chanctx(mvm, ctx); mutex_unlock(&mvm->mutex); } @@ -2351,17 +2372,16 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } -static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *ctx) +static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; - mutex_lock(&mvm->mutex); + lockdep_assert_held(&mvm->mutex); mvmvif->phy_ctxt = phy_ctxt; @@ -2378,18 +2398,18 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, * (in bss_info_changed), similarly for IBSS. */ ret = 0; - goto out_unlock; + goto out; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_MONITOR: break; default: ret = -EINVAL; - goto out_unlock; + goto out; } ret = iwl_mvm_binding_add_vif(mvm, vif); if (ret) - goto out_unlock; + goto out; /* * Power state must be updated before quotas, @@ -2414,32 +2434,43 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, iwl_mvm_mac_ctxt_changed(mvm, vif, false); } - goto out_unlock; + goto out; - out_remove_binding: +out_remove_binding: iwl_mvm_binding_remove_vif(mvm, vif); iwl_mvm_power_update_mac(mvm); - out_unlock: - mutex_unlock(&mvm->mutex); +out: if (ret) mvmvif->phy_ctxt = NULL; return ret; } - -static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *ctx) +static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int ret; mutex_lock(&mvm->mutex); + ret = __iwl_mvm_assign_vif_chanctx(mvm, vif, ctx); + mutex_unlock(&mvm->mutex); + + return ret; +} + +static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + lockdep_assert_held(&mvm->mutex); iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); switch (vif->type) { case NL80211_IFTYPE_ADHOC: - goto out_unlock; + goto out; case NL80211_IFTYPE_MONITOR: mvmvif->monitor_active = false; iwl_mvm_update_quotas(mvm, NULL); @@ -2447,7 +2478,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, case NL80211_IFTYPE_AP: /* This part is triggered only during CSA */ if (!vif->csa_active || !mvmvif->ap_ibss_active) - goto out_unlock; + goto out; mvmvif->ap_ibss_active = false; iwl_mvm_update_quotas(mvm, NULL); @@ -2457,12 +2488,80 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, iwl_mvm_binding_remove_vif(mvm, vif); -out_unlock: +out: mvmvif->phy_ctxt = NULL; iwl_mvm_power_update_mac(mvm); +} + +static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + mutex_lock(&mvm->mutex); + __iwl_mvm_unassign_vif_chanctx(mvm, vif, ctx); mutex_unlock(&mvm->mutex); } +static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; + + /* we only support SWAP_CONTEXTS and with a single-vif right now */ + if (mode != CHANCTX_SWMODE_SWAP_CONTEXTS || n_vifs > 1) + return -EOPNOTSUPP; + + mutex_lock(&mvm->mutex); + __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx); + __iwl_mvm_remove_chanctx(mvm, vifs[0].old_ctx); + + ret = __iwl_mvm_add_chanctx(mvm, vifs[0].new_ctx); + if (ret) { + IWL_ERR(mvm, "failed to add new_ctx during channel switch\n"); + goto out_reassign; + } + + ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].new_ctx); + if (ret) { + IWL_ERR(mvm, + "failed to assign new_ctx during channel switch\n"); + goto out_remove; + } + + goto out; + +out_remove: + __iwl_mvm_remove_chanctx(mvm, vifs[0].new_ctx); + +out_reassign: + ret = __iwl_mvm_add_chanctx(mvm, vifs[0].old_ctx); + if (ret) { + IWL_ERR(mvm, "failed to add old_ctx back after failure.\n"); + goto out_restart; + } + + ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx); + if (ret) { + IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n"); + goto out_restart; + } + + goto out; + +out_restart: + /* things keep failing, better restart the hw */ + iwl_mvm_nic_restart(mvm, false); + +out: + mutex_unlock(&mvm->mutex); + return ret; +} + static int iwl_mvm_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) @@ -2627,6 +2726,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .change_chanctx = iwl_mvm_change_chanctx, .assign_vif_chanctx = iwl_mvm_assign_vif_chanctx, .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx, + .switch_vif_chanctx = iwl_mvm_switch_vif_chanctx, .start_ap = iwl_mvm_start_ap_ibss, .stop_ap = iwl_mvm_stop_ap_ibss, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 5fedd5521432..fa8fcbcceb23 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1077,4 +1077,6 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool added_vif); +void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); + #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 4e2823faa5b9..89a095691507 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -764,7 +764,7 @@ static void iwl_mvm_reprobe_wk(struct work_struct *wk) module_put(THIS_MODULE); } -static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) +void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) { iwl_abort_notification_waits(&mvm->notif_wait); @@ -821,11 +821,12 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm) reprobe->dev = mvm->trans->dev; INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); schedule_work(&reprobe->work); - } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && mvm->restart_fw) { + } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && + (!fw_error || mvm->restart_fw)) { /* don't let the transport/FW power down */ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); - if (mvm->restart_fw > 0) + if (fw_error && mvm->restart_fw > 0) mvm->restart_fw--; ieee80211_restart_hw(mvm->hw); } @@ -837,7 +838,7 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode) iwl_mvm_dump_nic_error_log(mvm); - iwl_mvm_nic_restart(mvm); + iwl_mvm_nic_restart(mvm, true); } static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) @@ -845,7 +846,7 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); WARN_ON(1); - iwl_mvm_nic_restart(mvm); + iwl_mvm_nic_restart(mvm, true); } struct iwl_d0i3_iter_data { -- cgit v1.2.3 From f0c977839611369958bb545c741f897f5141bb30 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 5 Mar 2014 15:41:48 +0200 Subject: iwlwifi: mvm: CSA unbind-bind flow support for client Implement support for unbind-bind flow for the client roles. This includes telling the firmware that we are not associated, removing time-events, removing quotas and updating power management during the actual switch, and redoing everything in the new channel. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 35 ++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 24cc56957339..78a78c02dda5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -293,6 +293,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_TIMING_BEACON_ONLY | IEEE80211_HW_CONNECTION_MONITOR | + IEEE80211_HW_CHANCTX_STA_CSA | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_SUPPORTS_STATIC_SMPS; @@ -2374,7 +2375,8 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *ctx) + struct ieee80211_chanctx_conf *ctx, + bool switching_chanctx) { u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; @@ -2429,7 +2431,8 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, } /* Handle binding during CSA */ - if (vif->type == NL80211_IFTYPE_AP) { + if ((vif->type == NL80211_IFTYPE_AP) || + (switching_chanctx && (vif->type == NL80211_IFTYPE_STATION))) { iwl_mvm_update_quotas(mvm, NULL); iwl_mvm_mac_ctxt_changed(mvm, vif, false); } @@ -2452,7 +2455,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, int ret; mutex_lock(&mvm->mutex); - ret = __iwl_mvm_assign_vif_chanctx(mvm, vif, ctx); + ret = __iwl_mvm_assign_vif_chanctx(mvm, vif, ctx, false); mutex_unlock(&mvm->mutex); return ret; @@ -2460,9 +2463,11 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *ctx) + struct ieee80211_chanctx_conf *ctx, + bool switching_chanctx) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_vif *disabled_vif = NULL; lockdep_assert_held(&mvm->mutex); @@ -2473,7 +2478,6 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, goto out; case NL80211_IFTYPE_MONITOR: mvmvif->monitor_active = false; - iwl_mvm_update_quotas(mvm, NULL); break; case NL80211_IFTYPE_AP: /* This part is triggered only during CSA */ @@ -2481,11 +2485,20 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, goto out; mvmvif->ap_ibss_active = false; - iwl_mvm_update_quotas(mvm, NULL); + break; + case NL80211_IFTYPE_STATION: + if (!switching_chanctx) + break; + + disabled_vif = vif; + + iwl_mvm_mac_ctxt_changed(mvm, vif, true); + break; default: break; } + iwl_mvm_update_quotas(mvm, disabled_vif); iwl_mvm_binding_remove_vif(mvm, vif); out: @@ -2500,7 +2513,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); mutex_lock(&mvm->mutex); - __iwl_mvm_unassign_vif_chanctx(mvm, vif, ctx); + __iwl_mvm_unassign_vif_chanctx(mvm, vif, ctx, false); mutex_unlock(&mvm->mutex); } @@ -2517,7 +2530,7 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, return -EOPNOTSUPP; mutex_lock(&mvm->mutex); - __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx); + __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, true); __iwl_mvm_remove_chanctx(mvm, vifs[0].old_ctx); ret = __iwl_mvm_add_chanctx(mvm, vifs[0].new_ctx); @@ -2526,7 +2539,8 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, goto out_reassign; } - ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].new_ctx); + ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].new_ctx, + true); if (ret) { IWL_ERR(mvm, "failed to assign new_ctx during channel switch\n"); @@ -2545,7 +2559,8 @@ out_reassign: goto out_restart; } - ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx); + ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, + true); if (ret) { IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n"); goto out_restart; -- cgit v1.2.3 From fe887665a87b4c45be21253c4a6904ad1334be85 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Thu, 10 Apr 2014 21:46:16 +0300 Subject: iwlwifi: mvm: Use beacon_get_template instead of beacon_get Call ieee80211_beacon_get_template instead of ieee80211_beacon_get and sync the CSA counters with mac80211 after each beacon transmission. Signed-off-by: Andrei Otcheretianski Reviewed-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 549817d46bfc..6d094721a20e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -969,7 +969,7 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, WARN_ON(vif->type != NL80211_IFTYPE_AP && vif->type != NL80211_IFTYPE_ADHOC); - beacon = ieee80211_beacon_get(mvm->hw, vif); + beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL); if (!beacon) return -ENOMEM; @@ -1233,6 +1233,7 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, if (unlikely(mvm->csa_vif && mvm->csa_vif->csa_active)) { if (!ieee80211_csa_is_complete(mvm->csa_vif)) { + ieee80211_csa_update_counter(mvm->csa_vif); iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm->csa_vif); } else { ieee80211_csa_finish(mvm->csa_vif); -- cgit v1.2.3 From 664322fa43b7a52a9e8be9a3874c024412c24a50 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Thu, 5 Jun 2014 16:40:36 +0300 Subject: iwlwifi: mvm: Protect mvm->csa_vif with RCU Currently mvm->csa_vif is protected with mvm mutex. The RCU protection is required for "iwlwifi: mvm: Reflect GO channel switch in NoA" patch. Signed-off-by: Andrei Otcheretianski Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 15 +++++++++------ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 12 ++++++++++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 +- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 6d094721a20e..19bd696bd6f8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -1206,6 +1206,7 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mvm_tx_resp *beacon_notify_hdr; + struct ieee80211_vif *csa_vif; u64 tsf; lockdep_assert_held(&mvm->mutex); @@ -1231,13 +1232,15 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, mvm->ap_last_beacon_gp2, le32_to_cpu(beacon_notify_hdr->initial_rate)); - if (unlikely(mvm->csa_vif && mvm->csa_vif->csa_active)) { - if (!ieee80211_csa_is_complete(mvm->csa_vif)) { - ieee80211_csa_update_counter(mvm->csa_vif); - iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm->csa_vif); + csa_vif = rcu_dereference_protected(mvm->csa_vif, + lockdep_is_held(&mvm->mutex)); + if (unlikely(csa_vif && csa_vif->csa_active)) { + if (!ieee80211_csa_is_complete(csa_vif)) { + ieee80211_csa_update_counter(csa_vif); + iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif); } else { - ieee80211_csa_finish(mvm->csa_vif); - mvm->csa_vif = NULL; + ieee80211_csa_finish(csa_vif); + RCU_INIT_POINTER(mvm->csa_vif, NULL); } } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 78a78c02dda5..984a1e75aad0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1607,6 +1607,10 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); + /* Handle AP stop while in CSA */ + if (rcu_access_pointer(mvm->csa_vif) == vif) + RCU_INIT_POINTER(mvm->csa_vif, NULL); + mvmvif->ap_ibss_active = false; mvm->ap_last_beacon_gp2 = 0; @@ -2664,15 +2668,19 @@ static void iwl_mvm_channel_switch_beacon(struct ieee80211_hw *hw, struct cfg80211_chan_def *chandef) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct ieee80211_vif *csa_vif; mutex_lock(&mvm->mutex); - if (WARN(mvm->csa_vif && mvm->csa_vif->csa_active, + + csa_vif = rcu_dereference_protected(mvm->csa_vif, + lockdep_is_held(&mvm->mutex)); + if (WARN(csa_vif && csa_vif->csa_active, "Another CSA is already in progress")) goto out_unlock; IWL_DEBUG_MAC80211(mvm, "CSA started to freq %d\n", chandef->center_freq1); - mvm->csa_vif = vif; + rcu_assign_pointer(mvm->csa_vif, vif); out_unlock: mutex_unlock(&mvm->mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fa8fcbcceb23..5bb42af8886b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -658,7 +658,7 @@ struct iwl_mvm { /* Indicate if device power save is allowed */ bool ps_disabled; - struct ieee80211_vif *csa_vif; + struct ieee80211_vif __rcu *csa_vif; /* system time of last beacon (for AP/GO interface) */ u32 ap_last_beacon_gp2; -- cgit v1.2.3 From 7f0a7c671cdc0396f99b60b77bd02e2dee7c4838 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Sun, 4 May 2014 11:48:12 +0300 Subject: iwlwifi: mvm: Reflect GO channel switch in NoA According to the spec, GO/AP should perform the channel switch just before "beacon 0". However, since the exact timing isn't defined, it may result in a sudden GO disappearance from the channel. Prevent potential packet loss when performing the CS by scheduling NoA time event and executing the channel switch flow when a notification from fw is received. Signed-off-by: Andrei Otcheretianski Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 3 ++ drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 41 +++++++++++---- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 5 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 12 +++++ drivers/net/wireless/iwlwifi/mvm/time-event.c | 73 +++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/time-event.h | 29 +++++++++++ 6 files changed, 153 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 6c479de3b8d4..99329edcd99f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -538,6 +538,9 @@ enum iwl_time_event_type { /* WiDi Sync Events */ TE_WIDI_TX_SYNC, + /* Channel Switch NoA */ + TE_P2P_GO_CSA_NOA, + TE_MAX }; /* MAC_EVENT_TYPE_API_E_VER_1 */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 19bd696bd6f8..a176d008dab1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -67,6 +67,7 @@ #include "iwl-prph.h" #include "fw-api.h" #include "mvm.h" +#include "time-event.h" const u8 iwl_mvm_ac_to_tx_fifo[] = { IWL_MVM_TX_FIFO_VO, @@ -1200,6 +1201,35 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return 0; } +static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, + struct ieee80211_vif *csa_vif, u32 gp2) +{ + struct iwl_mvm_vif *mvmvif = + iwl_mvm_vif_from_mac80211(csa_vif); + + if (!ieee80211_csa_is_complete(csa_vif)) { + int c = ieee80211_csa_update_counter(csa_vif); + + iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif); + if (csa_vif->p2p && + !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) { + u32 rel_time = (c + 1) * + csa_vif->bss_conf.beacon_int - + IWL_MVM_CHANNEL_SWITCH_TIME; + u32 apply_time = gp2 + rel_time * 1024; + + iwl_mvm_schedule_csa_noa(mvm, csa_vif, + IWL_MVM_CHANNEL_SWITCH_TIME - + IWL_MVM_CHANNEL_SWITCH_MARGIN, + apply_time); + } + } else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) { + /* we don't have CSA NoA scheduled yet, switch now */ + ieee80211_csa_finish(csa_vif); + RCU_INIT_POINTER(mvm->csa_vif, NULL); + } +} + int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd) @@ -1234,15 +1264,8 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, csa_vif = rcu_dereference_protected(mvm->csa_vif, lockdep_is_held(&mvm->mutex)); - if (unlikely(csa_vif && csa_vif->csa_active)) { - if (!ieee80211_csa_is_complete(csa_vif)) { - ieee80211_csa_update_counter(csa_vif); - iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif); - } else { - ieee80211_csa_finish(csa_vif); - RCU_INIT_POINTER(mvm->csa_vif, NULL); - } - } + if (unlikely(csa_vif && csa_vif->csa_active)) + iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2); return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 984a1e75aad0..4a0350fc4b4e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1608,8 +1608,11 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); /* Handle AP stop while in CSA */ - if (rcu_access_pointer(mvm->csa_vif) == vif) + if (rcu_access_pointer(mvm->csa_vif) == vif) { + iwl_mvm_remove_time_event(mvm, mvmvif, + &mvmvif->time_event_data); RCU_INIT_POINTER(mvm->csa_vif, NULL); + } mvmvif->ap_ibss_active = false; mvm->ap_last_beacon_gp2 = 0; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 5bb42af8886b..db496c5c73fc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -83,6 +83,18 @@ #define IWL_RSSI_OFFSET 50 #define IWL_MVM_MISSED_BEACONS_THRESHOLD 8 +/* + * The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0" + * TBTT. This value should be big enough to ensure that we switch in time. + */ +#define IWL_MVM_CHANNEL_SWITCH_TIME 40 + +/* + * This value (in TUs) is used to fine tune the CSA NoA end time which should + * be just before "beacon 0" TBTT. + */ +#define IWL_MVM_CHANNEL_SWITCH_MARGIN 4 + enum iwl_mvm_tx_fifo { IWL_MVM_TX_FIFO_BK = 0, IWL_MVM_TX_FIFO_BE, diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 80100f6cc12a..ae52613b97f2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -138,6 +138,41 @@ static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) schedule_work(&mvm->roc_done_wk); } +static void iwl_mvm_csa_noa_start(struct iwl_mvm *mvm) +{ + struct ieee80211_vif *csa_vif; + + rcu_read_lock(); + + csa_vif = rcu_dereference(mvm->csa_vif); + if (!csa_vif || !csa_vif->csa_active) + goto out_unlock; + + IWL_DEBUG_TE(mvm, "CSA NOA started\n"); + + /* + * CSA NoA is started but we still have beacons to + * transmit on the current channel. + * So we just do nothing here and the switch + * will be performed on the last TBTT. + */ + if (!ieee80211_csa_is_complete(csa_vif)) { + IWL_WARN(mvm, "CSA NOA started too early\n"); + goto out_unlock; + } + + ieee80211_csa_finish(csa_vif); + + rcu_read_unlock(); + + RCU_INIT_POINTER(mvm->csa_vif, NULL); + + return; + +out_unlock: + rcu_read_unlock(); +} + static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, struct ieee80211_vif *vif, const char *errmsg) @@ -213,6 +248,14 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); iwl_mvm_ref(mvm, IWL_MVM_REF_ROC); ieee80211_ready_on_channel(mvm->hw); + } else if (te_data->vif->type == NL80211_IFTYPE_AP) { + if (le32_to_cpu(notif->status)) + iwl_mvm_csa_noa_start(mvm); + else + IWL_DEBUG_TE(mvm, "CSA NOA failed to start\n"); + + /* we don't need it anymore */ + iwl_mvm_te_clear_data(mvm, te_data); } } else { IWL_WARN(mvm, "Got TE with unknown action\n"); @@ -538,3 +581,33 @@ void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) iwl_mvm_roc_finished(mvm); } + +int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 apply_time) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; + struct iwl_time_event_cmd time_cmd = {}; + + lockdep_assert_held(&mvm->mutex); + + if (te_data->running) { + IWL_DEBUG_TE(mvm, "CS NOA is already scheduled\n"); + return -EBUSY; + } + + time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); + time_cmd.id_and_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); + time_cmd.id = cpu_to_le32(TE_P2P_GO_CSA_NOA); + time_cmd.apply_time = cpu_to_le32(apply_time); + time_cmd.max_frags = TE_V2_FRAG_NONE; + time_cmd.duration = cpu_to_le32(duration); + time_cmd.repeat = 1; + time_cmd.interval = cpu_to_le32(1); + time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START | + TE_V2_ABSENCE); + + return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); +} diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index 4a61c8c02372..2f48a90d4ad3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h @@ -214,4 +214,33 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, void iwl_mvm_roc_done_wk(struct work_struct *wk); +/** + * iwl_mvm_schedule_csa_noa - request NoA for channel switch + * @mvm: the mvm component + * @vif: the virtual interface for which the channel switch is issued + * @duration: the duration of the NoA in TU. + * @apply_time: NoA start time in GP2. + * + * This function is used to schedule NoA time event and is used to perform + * the channel switch flow. + */ +int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 apply_time); + +/** + * iwl_mvm_te_scheduled - check if the fw received the TE cmd + * @te_data: the time event data that corresponds to that time event + * + * This function returns true iff this TE is added to the fw. + */ +static inline bool +iwl_mvm_te_scheduled(struct iwl_mvm_time_event_data *te_data) +{ + if (!te_data) + return false; + + return !!te_data->uid; +} + #endif /* __time_event_h__ */ -- cgit v1.2.3 From 003e5236a1fcab3fc4576fe643e31a3d83027256 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Sun, 25 May 2014 17:24:22 +0300 Subject: iwlwifi: mvm: Use CS tx block bit for AP/GO An AP/GO may perform the channel switch slightly before its stations. This scenario may result in packet loss, since the transmission may start before the client is actually on a new channel. In order to prevent potential packet loss disable tx to all the stations when the channel switch flow starts. Clear the disable_tx bit when a station is seen on a target channel, or after IWL_MVM_CS_UNBLOCK_TX_TIMEOUT beacons on a new channel. In addition call ieee80211_sta_block_awake in order to inform mac80211 that the frames for this station should be buffered. Signed-off-by: Andrei Otcheretianski Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 25 +++++++++++++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 11 ++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 8 +++++ drivers/net/wireless/iwlwifi/mvm/rx.c | 17 +++++++++ drivers/net/wireless/iwlwifi/mvm/sta.c | 54 +++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/sta.h | 10 ++++++ drivers/net/wireless/iwlwifi/mvm/tx.c | 14 ++++++-- 7 files changed, 136 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index a176d008dab1..96b9cf8137e7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -1237,6 +1237,7 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mvm_tx_resp *beacon_notify_hdr; struct ieee80211_vif *csa_vif; + struct ieee80211_vif *tx_blocked_vif; u64 tsf; lockdep_assert_held(&mvm->mutex); @@ -1267,6 +1268,30 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, if (unlikely(csa_vif && csa_vif->csa_active)) iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2); + tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif, + lockdep_is_held(&mvm->mutex)); + if (unlikely(tx_blocked_vif)) { + struct iwl_mvm_vif *mvmvif = + iwl_mvm_vif_from_mac80211(tx_blocked_vif); + + /* + * The channel switch is started and we have blocked the + * stations. If this is the first beacon (the timeout wasn't + * set), set the unblock timeout, otherwise countdown + */ + if (!mvm->csa_tx_block_bcn_timeout) + mvm->csa_tx_block_bcn_timeout = + IWL_MVM_CS_UNBLOCK_TX_TIMEOUT; + else + mvm->csa_tx_block_bcn_timeout--; + + /* Check if the timeout is expired, and unblock tx */ + if (mvm->csa_tx_block_bcn_timeout == 0) { + iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, false); + RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL); + } + } + return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 4a0350fc4b4e..5ed6fb32087c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1614,6 +1614,11 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, RCU_INIT_POINTER(mvm->csa_vif, NULL); } + if (rcu_access_pointer(mvm->csa_tx_blocked_vif) == vif) { + RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL); + mvm->csa_tx_block_bcn_timeout = 0; + } + mvmvif->ap_ibss_active = false; mvm->ap_last_beacon_gp2 = 0; @@ -2491,6 +2496,12 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, if (!vif->csa_active || !mvmvif->ap_ibss_active) goto out; + /* Set CS bit on all the stations */ + iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true); + + /* Save blocked iface, the timeout is set on the next beacon */ + rcu_assign_pointer(mvm->csa_tx_blocked_vif, vif); + mvmvif->ap_ibss_active = false; break; case NL80211_IFTYPE_STATION: diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index db496c5c73fc..7b308c4834f6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -95,6 +95,12 @@ */ #define IWL_MVM_CHANNEL_SWITCH_MARGIN 4 +/* + * Number of beacons to transmit on a new channel until we unblock tx to + * the stations, even if we didn't identify them on a new channel + */ +#define IWL_MVM_CS_UNBLOCK_TX_TIMEOUT 3 + enum iwl_mvm_tx_fifo { IWL_MVM_TX_FIFO_BK = 0, IWL_MVM_TX_FIFO_BE, @@ -671,6 +677,8 @@ struct iwl_mvm { bool ps_disabled; struct ieee80211_vif __rcu *csa_vif; + struct ieee80211_vif __rcu *csa_tx_blocked_vif; + u8 csa_tx_block_bcn_timeout; /* system time of last beacon (for AP/GO interface) */ u32 ap_last_beacon_gp2; diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index cf7276967acd..4b98987fc413 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -258,6 +258,23 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, memset(&rx_status, 0, sizeof(rx_status)); + /* + * We have tx blocked stations (with CS bit). If we heard frames from + * a blocked station on a new channel we can TX to it again. + */ + if (unlikely(mvm->csa_tx_block_bcn_timeout)) { + struct ieee80211_sta *sta; + + rcu_read_lock(); + + sta = ieee80211_find_sta( + rcu_dereference(mvm->csa_tx_blocked_vif), hdr->addr2); + if (sta) + iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false); + + rcu_read_unlock(); + } + /* * drop the packet if it has failed being decrypted by HW */ diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index d3a6cf7558eb..812813964847 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1468,3 +1468,57 @@ void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, if (ret) IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); } + +void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + bool disable) +{ + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); + + spin_lock_bh(&mvm_sta->lock); + + if (mvm_sta->disable_tx == disable) { + spin_unlock_bh(&mvm_sta->lock); + return; + } + + mvm_sta->disable_tx = disable; + + /* + * Tell mac80211 to start/stop queueing tx for this station, + * but don't stop queueing if there are still pending frames + * for this station. + */ + if (disable || !atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) + ieee80211_sta_block_awake(mvm->hw, sta, disable); + + iwl_mvm_sta_modify_disable_tx(mvm, mvm_sta, disable); + + spin_unlock_bh(&mvm_sta->lock); +} + +void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, + struct iwl_mvm_vif *mvmvif, + bool disable) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvm_sta; + int i; + + lockdep_assert_held(&mvm->mutex); + + /* Block/unblock all the stations of the given mvmvif */ + for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], + lockdep_is_held(&mvm->mutex)); + if (IS_ERR_OR_NULL(sta)) + continue; + + mvm_sta = iwl_mvm_sta_from_mac80211(sta); + if (mvm_sta->mac_id_n_color != + FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)) + continue; + + iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, disable); + } +} diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 10c1a5352651..3b1c8bd6cb54 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -73,6 +73,7 @@ #include "rs.h" struct iwl_mvm; +struct iwl_mvm_vif; /** * DOC: station table - introduction @@ -295,6 +296,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) * @tid_data: per tid data. Look at %iwl_mvm_tid_data. * @tx_protection: reference counter for controlling the Tx protection. * @tt_tx_protection: is thermal throttling enable Tx protection? + * @disable_tx: is tx to this STA disabled? * * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is placed in that @@ -317,6 +319,8 @@ struct iwl_mvm_sta { /* Temporary, until the new TLC will control the Tx protection */ s8 tx_protection; bool tt_tx_protection; + + bool disable_tx; }; static inline struct iwl_mvm_sta * @@ -406,5 +410,11 @@ int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool drain); void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool disable); +void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + bool disable); +void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, + struct iwl_mvm_vif *mvmvif, + bool disable); #endif /* __sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index fa87a4ba25ec..f5c0982d297c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -727,13 +727,21 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, goto out; if (mvmsta && mvmsta->vif->type == NL80211_IFTYPE_AP) { + /* - * If there are no pending frames for this STA, notify - * mac80211 that this station can go to sleep in its + * If there are no pending frames for this STA and + * the tx to this station is not disabled, notify + * mac80211 that this station can now wake up in its * STA table. * If mvmsta is not NULL, sta is valid. */ - ieee80211_sta_block_awake(mvm->hw, sta, false); + + spin_lock_bh(&mvmsta->lock); + + if (!mvmsta->disable_tx) + ieee80211_sta_block_awake(mvm->hw, sta, false); + + spin_unlock_bh(&mvmsta->lock); } if (PTR_ERR(sta) == -EBUSY || PTR_ERR(sta) == -ENOENT) { -- cgit v1.2.3 From cf7b491dbbac0e25f24265b005bc0ceff622d387 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 15 May 2014 11:44:40 +0300 Subject: iwlwifi: mvm: disallow new TDLS stations when appropriate HW/FW constraints dictate that TDLS should only be used when a single phy ctx is active. We also support at most 4 TDLS peers. We don't support TDLS on a P2P vif. Unify and move a phy-ctx counting implementation from the power-mgmt code in order to simplify implementation. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 30 +++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | 26 +++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/power.c | 22 +-------------------- 5 files changed, 60 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 99329edcd99f..b8e4e78d601b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -86,6 +86,8 @@ enum { #define IWL_MVM_STATION_COUNT 16 +#define IWL_MVM_TDLS_STA_COUNT 4 + /* commands */ enum { MVM_ALIVE = 0x1, diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 5ed6fb32087c..57945fe06216 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1843,6 +1843,26 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } +static int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm) +{ + struct ieee80211_sta *sta; + int count = 0; + int i; + + lockdep_assert_held(&mvm->mutex); + + for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], + lockdep_is_held(&mvm->mutex)); + if (!sta || IS_ERR(sta) || !sta->tdls) + continue; + + count++; + } + + return count; +} + static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -1881,6 +1901,16 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, ret = -EINVAL; goto out_unlock; } + + if (sta->tdls && + (vif->p2p || + iwl_mvm_tdls_sta_count(mvm) == IWL_MVM_TDLS_STA_COUNT || + iwl_mvm_phy_ctx_count(mvm) > 1)) { + IWL_DEBUG_MAC80211(mvm, "refusing TDLS sta\n"); + ret = -EBUSY; + goto out_unlock; + } + ret = iwl_mvm_add_sta(mvm, vif, sta); } else if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_AUTH) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 7b308c4834f6..c75b958736bc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -838,6 +838,7 @@ void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt); void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt); +int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm); /* MAC (virtual interface) programming */ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index 539f3a942d43..6cc243f7cf60 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c @@ -261,3 +261,29 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) ctxt->ref--; } + +static void iwl_mvm_binding_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + unsigned long *data = _data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + if (!mvmvif->phy_ctxt) + return; + + if (vif->type == NL80211_IFTYPE_STATION || + vif->type == NL80211_IFTYPE_AP) + __set_bit(mvmvif->phy_ctxt->id, data); +} + +int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm) +{ + unsigned long phy_ctxt_counter = 0; + + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_binding_iterator, + &phy_ctxt_counter); + + return hweight8(phy_ctxt_counter); +} diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index c182a8baf685..3b582dd6d77f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -246,30 +246,10 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm, IWL_MVM_PS_HEAVY_RX_THLD_PERCENT; } -static void iwl_mvm_binding_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - unsigned long *data = _data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - if (!mvmvif->phy_ctxt) - return; - - if (vif->type == NL80211_IFTYPE_STATION || - vif->type == NL80211_IFTYPE_AP) - __set_bit(mvmvif->phy_ctxt->id, data); -} - static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - unsigned long phy_ctxt_counter = 0; - - ieee80211_iterate_active_interfaces_atomic(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_binding_iterator, - &phy_ctxt_counter); if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid, ETH_ALEN)) @@ -291,7 +271,7 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, * Avoid using uAPSD if client is in DCM - * low latency issue in Miracast */ - if (hweight8(phy_ctxt_counter) >= 2) + if (iwl_mvm_phy_ctx_count(mvm) >= 2) return false; return true; -- cgit v1.2.3 From 07ecd897b1634e0f34a9ba9d0d1b9263bc05d90b Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 20 May 2014 18:16:42 +0300 Subject: iwlwifi: mvm: protect TDLS discovery session Use the new mac80211 callback to protect a TDLS discovery session so we can hear the discovery-response packet. Signed-off-by: Arik Nemtsov Reviewed-by: Ilan Peer Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 57945fe06216..1acad838fc5c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2017,6 +2017,18 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } +static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; + + mutex_lock(&mvm->mutex); + /* Protect the session to hear the TDLS setup response on the channel */ + iwl_mvm_protect_session(mvm, vif, duration, duration, 100); + mutex_unlock(&mvm->mutex); +} + static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, @@ -2781,6 +2793,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .sta_rc_update = iwl_mvm_sta_rc_update, .conf_tx = iwl_mvm_mac_conf_tx, .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, + .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover, .flush = iwl_mvm_mac_flush, .sched_scan_start = iwl_mvm_mac_sched_scan_start, .sched_scan_stop = iwl_mvm_mac_sched_scan_stop, -- cgit v1.2.3 From fa3d07e47f2411aa9ccb54192c4f978c60a9e111 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 15 May 2014 18:59:32 +0300 Subject: iwlwifi: disable PSM on vifs with associated TDLS peers The FW does not support PSM on a vif with associated TDLS peers. Disable PSM when the first peer joins and re-enable it when the last leaves. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 31 +++++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/power.c | 17 +++++++++++++--- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 1acad838fc5c..8aa6fa46c628 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1843,9 +1843,10 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } -static int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm) +int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; int count = 0; int i; @@ -1857,12 +1858,33 @@ static int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm) if (!sta || IS_ERR(sta) || !sta->tdls) continue; + if (vif) { + mvmsta = iwl_mvm_sta_from_mac80211(sta); + if (mvmsta->vif != vif) + continue; + } + count++; } return count; } +static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + bool sta_added) +{ + int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); + + /* + * Disable ps when the first TDLS sta is added and re-enable it + * when the last TDLS sta is removed + */ + if ((tdls_sta_cnt == 1 && sta_added) || + (tdls_sta_cnt == 0 && !sta_added)) + iwl_mvm_power_update_mac(mvm); +} + static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -1904,7 +1926,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, if (sta->tdls && (vif->p2p || - iwl_mvm_tdls_sta_count(mvm) == IWL_MVM_TDLS_STA_COUNT || + iwl_mvm_tdls_sta_count(mvm, NULL) == + IWL_MVM_TDLS_STA_COUNT || iwl_mvm_phy_ctx_count(mvm) > 1)) { IWL_DEBUG_MAC80211(mvm, "refusing TDLS sta\n"); ret = -EBUSY; @@ -1912,6 +1935,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, } ret = iwl_mvm_add_sta(mvm, vif, sta); + if (sta->tdls && ret == 0) + iwl_mvm_recalc_tdls_state(mvm, vif, true); } else if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_AUTH) { /* @@ -1946,6 +1971,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, } else if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST) { ret = iwl_mvm_rm_sta(mvm, vif, sta); + if (sta->tdls) + iwl_mvm_recalc_tdls_state(mvm, vif, false); } else { ret = -EIO; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index c75b958736bc..785e5232c757 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1098,6 +1098,9 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool added_vif); +/* TDLS */ +int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif); + void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 3b582dd6d77f..2b2d10800a55 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -483,6 +483,7 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, } struct iwl_power_vifs { + struct iwl_mvm *mvm; struct ieee80211_vif *bf_vif; struct ieee80211_vif *bss_vif; struct ieee80211_vif *p2p_vif; @@ -492,6 +493,8 @@ struct iwl_power_vifs { bool bss_active; bool ap_active; bool monitor_active; + bool bss_tdls; + bool p2p_tdls; }; static void iwl_mvm_power_iterator(void *_data, u8 *mac, @@ -528,6 +531,8 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac, /* only a single MAC of the same type */ WARN_ON(power_iterator->p2p_vif); power_iterator->p2p_vif = vif; + power_iterator->p2p_tdls = + !!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif); if (mvmvif->phy_ctxt) if (mvmvif->phy_ctxt->id < MAX_PHYS) power_iterator->p2p_active = true; @@ -537,6 +542,8 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac, /* only a single MAC of the same type */ WARN_ON(power_iterator->bss_vif); power_iterator->bss_vif = vif; + power_iterator->bss_tdls = + !!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif); if (mvmvif->phy_ctxt) if (mvmvif->phy_ctxt->id < MAX_PHYS) power_iterator->bss_active = true; @@ -579,13 +586,15 @@ iwl_mvm_power_set_pm(struct iwl_mvm *mvm, ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif); /* enable PM on bss if bss stand alone */ - if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) { + if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active && + !vifs->bss_tdls) { bss_mvmvif->pm_enabled = true; return; } /* enable PM on p2p if p2p stand alone */ - if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) { + if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active && + !vifs->p2p_tdls) { if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM) p2p_mvmvif->pm_enabled = true; return; @@ -811,7 +820,9 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, int iwl_mvm_power_update_mac(struct iwl_mvm *mvm) { struct iwl_mvm_vif *mvmvif; - struct iwl_power_vifs vifs = {}; + struct iwl_power_vifs vifs = { + .mvm = mvm, + }; bool ba_enable; int ret; -- cgit v1.2.3 From f59e0e3cd8c1d57a1e5e94607b54221eccd3fdf3 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 10 Jun 2014 19:56:27 +0300 Subject: iwlwifi: mvm: teardown TDLS peers when initiating DCM The FW currently doesn't optimally support TDLS in DCM mode. Teardown all TDLS peers when we have more than a single phy context. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 8aa6fa46c628..2eb6ebee4467 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1885,6 +1885,28 @@ static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, iwl_mvm_power_update_mac(mvm); } +static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + int i; + + lockdep_assert_held(&mvm->mutex); + + for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], + lockdep_is_held(&mvm->mutex)); + if (!sta || IS_ERR(sta) || !sta->tdls) + continue; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, + NL80211_TDLS_TEARDOWN, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, + GFP_KERNEL); + } +} + static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -1954,6 +1976,11 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, true); } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTHORIZED) { + + /* we don't support TDLS during DCM */ + if (iwl_mvm_phy_ctx_count(mvm) > 1) + iwl_mvm_teardown_tdls_peers(mvm); + /* enable beacon filtering */ WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); ret = 0; -- cgit v1.2.3 From 9b1fcc11a83504a20de3aa4ef7d300f17e225245 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Thu, 8 May 2014 16:30:24 +0300 Subject: iwlwifi: mvm: remove 8000 HW family setting of adc sampling on nic config This patch removes the setting of the ADC sampling bits in the mvm nic configuration. This setting is not required by the firmware, and furthermore - it interferes with the DBGC when it is running in DRAM mode on PCIe. Signed-off-by: Liad Kaufman Reviewed-by: Dor Shaish Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 89a095691507..7d7b2fbe7cd1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -166,8 +166,15 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) WARN_ON((radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE) & ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE); - /* silicon bits */ - reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; + /* + * TODO: Bits 7-8 of CSR in 8000 HW family set the ADC sampling, and + * shouldn't be set to any non-zero value. The same is supposed to be + * true of the other HW, but unsetting them (such as the 7260) causes + * automatic tests to fail on seemingly unrelated errors. Need to + * further investigate this, but for now we'll separate cases. + */ + if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | -- cgit v1.2.3 From 589a6ba46bdf9a4a4817fef011ff61905a1aa244 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 5 Jun 2014 11:32:41 +0300 Subject: iwlwifi: mvm: minor fix in comment The comment was not accurate, we are talking about the frames *for* the station and not from the station. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index f5c0982d297c..e9ff38635c21 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -722,7 +722,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, /* We can't free more than one frame at once on a shared queue */ WARN_ON(skb_freed > 1); - /* If we have still frames from this STA nothing to do here */ + /* If we have still frames for this STA nothing to do here */ if (!atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) goto out; -- cgit v1.2.3 From f5c35e15f940a1580c62715adc3e88710753de4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 2 Jul 2014 17:05:35 +0200 Subject: b43: N-PHY: initialize hardware tables on new devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/tables_nphy.c | 288 +++++++++++++++++++++++++++++++-- drivers/net/wireless/b43/tables_nphy.h | 4 + 2 files changed, 281 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index b22171592926..dd876857969e 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2146,6 +2146,192 @@ static const u16 b43_ntab_antswctl_r3[4][32] = { } }; +/* static tables, PHY revision >= 7 */ + +/* Copied from brcmsmac (5.75.11) */ +static const u32 b43_ntab_tmap_r7[] = { + 0x8a88aa80, 0x8aaaaa8a, 0x8a8a8aa8, 0x00000888, + 0x88000000, 0x8a8a88aa, 0x8aa88888, 0x8888a8a8, + 0xf1111110, 0x11111111, 0x11f11111, 0x00000111, + 0x11000000, 0x1111f111, 0x11111111, 0x111111f1, + 0x8a88aa80, 0x8aaaaa8a, 0x8a8a8aa8, 0x000aa888, + 0x88880000, 0x8a8a88aa, 0x8aa88888, 0x8888a8a8, + 0xa1111110, 0x11111111, 0x11c11111, 0x00000111, + 0x11000000, 0x1111a111, 0x11111111, 0x111111a1, + 0xa2222220, 0x22222222, 0x22c22222, 0x00000222, + 0x22000000, 0x2222a222, 0x22222222, 0x222222a2, + 0xf1111110, 0x11111111, 0x11f11111, 0x00011111, + 0x11110000, 0x1111f111, 0x11111111, 0x111111f1, + 0xa8aa88a0, 0xa88888a8, 0xa8a8a88a, 0x00088aaa, + 0xaaaa0000, 0xa8a8aa88, 0xa88aaaaa, 0xaaaa8a8a, + 0xaaa8aaa0, 0x8aaa8aaa, 0xaa8a8a8a, 0x000aaa88, + 0x8aaa0000, 0xaaa8a888, 0x8aa88a8a, 0x8a88a888, + 0x08080a00, 0x0a08080a, 0x080a0a08, 0x00080808, + 0x080a0000, 0x080a0808, 0x080a0808, 0x0a0a0a08, + 0xa0a0a0a0, 0x80a0a080, 0x8080a0a0, 0x00008080, + 0x80a00000, 0x80a080a0, 0xa080a0a0, 0x8080a0a0, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x99999000, 0x9b9b99bb, 0x9bb99999, 0x9999b9b9, + 0x9b99bb90, 0x9bbbbb9b, 0x9b9b9bb9, 0x00000999, + 0x88000000, 0x8a8a88aa, 0x8aa88888, 0x8888a8a8, + 0x8a88aa80, 0x8aaaaa8a, 0x8a8a8aa8, 0x00aaa888, + 0x22000000, 0x2222b222, 0x22222222, 0x222222b2, + 0xb2222220, 0x22222222, 0x22d22222, 0x00000222, + 0x11000000, 0x1111a111, 0x11111111, 0x111111a1, + 0xa1111110, 0x11111111, 0x11c11111, 0x00000111, + 0x33000000, 0x3333b333, 0x33333333, 0x333333b3, + 0xb3333330, 0x33333333, 0x33d33333, 0x00000333, + 0x22000000, 0x2222a222, 0x22222222, 0x222222a2, + 0xa2222220, 0x22222222, 0x22c22222, 0x00000222, + 0x99b99b00, 0x9b9b99bb, 0x9bb99999, 0x9999b9b9, + 0x9b99bb99, 0x9bbbbb9b, 0x9b9b9bb9, 0x00000999, + 0x88000000, 0x8a8a88aa, 0x8aa88888, 0x8888a8a8, + 0x8a88aa88, 0x8aaaaa8a, 0x8a8a8aa8, 0x08aaa888, + 0x22222200, 0x2222f222, 0x22222222, 0x222222f2, + 0x22222222, 0x22222222, 0x22f22222, 0x00000222, + 0x11000000, 0x1111f111, 0x11111111, 0x11111111, + 0xf1111111, 0x11111111, 0x11f11111, 0x01111111, + 0xbb9bb900, 0xb9b9bb99, 0xb99bbbbb, 0xbbbb9b9b, + 0xb9bb99bb, 0xb99999b9, 0xb9b9b99b, 0x00000bbb, + 0xaa000000, 0xa8a8aa88, 0xa88aaaaa, 0xaaaa8a8a, + 0xa8aa88aa, 0xa88888a8, 0xa8a8a88a, 0x0a888aaa, + 0xaa000000, 0xa8a8aa88, 0xa88aaaaa, 0xaaaa8a8a, + 0xa8aa88a0, 0xa88888a8, 0xa8a8a88a, 0x00000aaa, + 0x88000000, 0x8a8a88aa, 0x8aa88888, 0x8888a8a8, + 0x8a88aa80, 0x8aaaaa8a, 0x8a8a8aa8, 0x00000888, + 0xbbbbbb00, 0x999bbbbb, 0x9bb99b9b, 0xb9b9b9bb, + 0xb9b99bbb, 0xb9b9b9bb, 0xb9bb9b99, 0x00000999, + 0x8a000000, 0xaa88a888, 0xa88888aa, 0xa88a8a88, + 0xa88aa88a, 0x88a8aaaa, 0xa8aa8aaa, 0x0888a88a, + 0x0b0b0b00, 0x090b0b0b, 0x0b090b0b, 0x0909090b, + 0x09090b0b, 0x09090b0b, 0x09090b09, 0x00000909, + 0x0a000000, 0x0a080808, 0x080a080a, 0x080a0a08, + 0x080a080a, 0x0808080a, 0x0a0a0a08, 0x0808080a, + 0xb0b0b000, 0x9090b0b0, 0x90b09090, 0xb0b0b090, + 0xb0b090b0, 0x90b0b0b0, 0xb0b09090, 0x00000090, + 0x80000000, 0xa080a080, 0xa08080a0, 0xa0808080, + 0xa080a080, 0x80a0a0a0, 0xa0a080a0, 0x00a0a0a0, + 0x22000000, 0x2222f222, 0x22222222, 0x222222f2, + 0xf2222220, 0x22222222, 0x22f22222, 0x00000222, + 0x11000000, 0x1111f111, 0x11111111, 0x111111f1, + 0xf1111110, 0x11111111, 0x11f11111, 0x00000111, + 0x33000000, 0x3333f333, 0x33333333, 0x333333f3, + 0xf3333330, 0x33333333, 0x33f33333, 0x00000333, + 0x22000000, 0x2222f222, 0x22222222, 0x222222f2, + 0xf2222220, 0x22222222, 0x22f22222, 0x00000222, + 0x99000000, 0x9b9b99bb, 0x9bb99999, 0x9999b9b9, + 0x9b99bb90, 0x9bbbbb9b, 0x9b9b9bb9, 0x00000999, + 0x88000000, 0x8a8a88aa, 0x8aa88888, 0x8888a8a8, + 0x8a88aa80, 0x8aaaaa8a, 0x8a8a8aa8, 0x00000888, + 0x88888000, 0x8a8a88aa, 0x8aa88888, 0x8888a8a8, + 0x8a88aa80, 0x8aaaaa8a, 0x8a8a8aa8, 0x00000888, + 0x88000000, 0x8a8a88aa, 0x8aa88888, 0x8888a8a8, + 0x8a88aa80, 0x8aaaaa8a, 0x8a8a8aa8, 0x00aaa888, + 0x88a88a00, 0x8a8a88aa, 0x8aa88888, 0x8888a8a8, + 0x8a88aa88, 0x8aaaaa8a, 0x8a8a8aa8, 0x000aa888, + 0x88880000, 0x8a8a88aa, 0x8aa88888, 0x8888a8a8, + 0x8a88aa88, 0x8aaaaa8a, 0x8a8a8aa8, 0x08aaa888, + 0x11000000, 0x1111a111, 0x11111111, 0x111111a1, + 0xa1111110, 0x11111111, 0x11c11111, 0x00000111, + 0x11000000, 0x1111a111, 0x11111111, 0x111111a1, + 0xa1111110, 0x11111111, 0x11c11111, 0x00000111, + 0x88000000, 0x8a8a88aa, 0x8aa88888, 0x8888a8a8, + 0x8a88aa80, 0x8aaaaa8a, 0x8a8a8aa8, 0x00000888, + 0x88000000, 0x8a8a88aa, 0x8aa88888, 0x8888a8a8, + 0x8a88aa80, 0x8aaaaa8a, 0x8a8a8aa8, 0x00000888, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +/* Extracted from MMIO dump of 6.30.223.141 */ +static const u32 b43_ntab_noisevar_r7[] = { + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, + 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, +}; + /* TX gain tables */ static const u32 b43_ntab_tx_gain_rev0_1_2[] = { 0x03cc2b44, 0x03cc2b42, 0x03cc2a44, 0x03cc2a42, @@ -3031,6 +3217,91 @@ void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset, b43_ntab_write_bulk(dev, offset, ARRAY_SIZE(data), data); \ } while (0) +static void b43_nphy_tables_init_shared_lut(struct b43_wldev *dev) +{ + ntab_upload(dev, B43_NTAB_C0_ESTPLT_R3, b43_ntab_estimatepowerlt0_r3); + ntab_upload(dev, B43_NTAB_C1_ESTPLT_R3, b43_ntab_estimatepowerlt1_r3); + ntab_upload(dev, B43_NTAB_C0_ADJPLT_R3, b43_ntab_adjustpower0_r3); + ntab_upload(dev, B43_NTAB_C1_ADJPLT_R3, b43_ntab_adjustpower1_r3); + ntab_upload(dev, B43_NTAB_C0_GAINCTL_R3, b43_ntab_gainctl0_r3); + ntab_upload(dev, B43_NTAB_C1_GAINCTL_R3, b43_ntab_gainctl1_r3); + ntab_upload(dev, B43_NTAB_C0_IQLT_R3, b43_ntab_iqlt0_r3); + ntab_upload(dev, B43_NTAB_C1_IQLT_R3, b43_ntab_iqlt1_r3); + ntab_upload(dev, B43_NTAB_C0_LOFEEDTH_R3, b43_ntab_loftlt0_r3); + ntab_upload(dev, B43_NTAB_C1_LOFEEDTH_R3, b43_ntab_loftlt1_r3); +} + +static void b43_nphy_tables_init_rev7_volatile(struct b43_wldev *dev) +{ + struct ssb_sprom *sprom = dev->dev->bus_sprom; + u8 antswlut; + int core, offset, i; + + const int antswlut0_offsets[] = { 0, 4, 8, }; /* Offsets for values */ + const u8 antswlut0_values[][3] = { + { 0x2, 0x12, 0x8 }, /* Core 0 */ + { 0x2, 0x18, 0x2 }, /* Core 1 */ + }; + + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + antswlut = sprom->fem.ghz5.antswlut; + else + antswlut = sprom->fem.ghz2.antswlut; + + switch (antswlut) { + case 0: + for (core = 0; core < 2; core++) { + for (i = 0; i < ARRAY_SIZE(antswlut0_values[0]); i++) { + offset = core ? 0x20 : 0x00; + offset += antswlut0_offsets[i]; + b43_ntab_write(dev, B43_NTAB8(9, offset), + antswlut0_values[core][i]); + } + } + break; + default: + b43err(dev->wl, "Unsupported antswlut: %d\n", antswlut); + break; + } +} + +static void b43_nphy_tables_init_rev16(struct b43_wldev *dev) +{ + /* Static tables */ + if (dev->phy.do_full_init) { + ntab_upload(dev, B43_NTAB_NOISEVAR_R7, b43_ntab_noisevar_r7); + b43_nphy_tables_init_shared_lut(dev); + } + + /* Volatile tables */ + b43_nphy_tables_init_rev7_volatile(dev); +} + +static void b43_nphy_tables_init_rev7(struct b43_wldev *dev) +{ + /* Static tables */ + if (dev->phy.do_full_init) { + ntab_upload(dev, B43_NTAB_FRAMESTRUCT_R3, b43_ntab_framestruct_r3); + ntab_upload(dev, B43_NTAB_PILOT_R3, b43_ntab_pilot_r3); + ntab_upload(dev, B43_NTAB_TMAP_R7, b43_ntab_tmap_r7); + ntab_upload(dev, B43_NTAB_INTLEVEL_R3, b43_ntab_intlevel_r3); + ntab_upload(dev, B43_NTAB_TDTRN_R3, b43_ntab_tdtrn_r3); + ntab_upload(dev, B43_NTAB_NOISEVAR_R7, b43_ntab_noisevar_r7); + ntab_upload(dev, B43_NTAB_MCS_R3, b43_ntab_mcs_r3); + ntab_upload(dev, B43_NTAB_TDI20A0_R3, b43_ntab_tdi20a0_r3); + ntab_upload(dev, B43_NTAB_TDI20A1_R3, b43_ntab_tdi20a1_r3); + ntab_upload(dev, B43_NTAB_TDI40A0_R3, b43_ntab_tdi40a0_r3); + ntab_upload(dev, B43_NTAB_TDI40A1_R3, b43_ntab_tdi40a1_r3); + ntab_upload(dev, B43_NTAB_PILOTLT_R3, b43_ntab_pilotlt_r3); + ntab_upload(dev, B43_NTAB_CHANEST_R3, b43_ntab_channelest_r3); + ntab_upload(dev, B43_NTAB_FRAMELT_R3, b43_ntab_framelookup_r3); + b43_nphy_tables_init_shared_lut(dev); + } + + /* Volatile tables */ + b43_nphy_tables_init_rev7_volatile(dev); +} + static void b43_nphy_tables_init_rev3(struct b43_wldev *dev) { struct ssb_sprom *sprom = dev->dev->bus_sprom; @@ -3057,16 +3328,7 @@ static void b43_nphy_tables_init_rev3(struct b43_wldev *dev) ntab_upload(dev, B43_NTAB_PILOTLT_R3, b43_ntab_pilotlt_r3); ntab_upload(dev, B43_NTAB_CHANEST_R3, b43_ntab_channelest_r3); ntab_upload(dev, B43_NTAB_FRAMELT_R3, b43_ntab_framelookup_r3); - ntab_upload(dev, B43_NTAB_C0_ESTPLT_R3, b43_ntab_estimatepowerlt0_r3); - ntab_upload(dev, B43_NTAB_C1_ESTPLT_R3, b43_ntab_estimatepowerlt1_r3); - ntab_upload(dev, B43_NTAB_C0_ADJPLT_R3, b43_ntab_adjustpower0_r3); - ntab_upload(dev, B43_NTAB_C1_ADJPLT_R3, b43_ntab_adjustpower1_r3); - ntab_upload(dev, B43_NTAB_C0_GAINCTL_R3, b43_ntab_gainctl0_r3); - ntab_upload(dev, B43_NTAB_C1_GAINCTL_R3, b43_ntab_gainctl1_r3); - ntab_upload(dev, B43_NTAB_C0_IQLT_R3, b43_ntab_iqlt0_r3); - ntab_upload(dev, B43_NTAB_C1_IQLT_R3, b43_ntab_iqlt1_r3); - ntab_upload(dev, B43_NTAB_C0_LOFEEDTH_R3, b43_ntab_loftlt0_r3); - ntab_upload(dev, B43_NTAB_C1_LOFEEDTH_R3, b43_ntab_loftlt1_r3); + b43_nphy_tables_init_shared_lut(dev); } /* Volatile tables */ @@ -3115,7 +3377,11 @@ static void b43_nphy_tables_init_rev0(struct b43_wldev *dev) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables */ void b43_nphy_tables_init(struct b43_wldev *dev) { - if (dev->phy.rev >= 3) + if (dev->phy.rev >= 16) + b43_nphy_tables_init_rev16(dev); + else if (dev->phy.rev >= 7) + b43_nphy_tables_init_rev7(dev); + else if (dev->phy.rev >= 3) b43_nphy_tables_init_rev3(dev); else b43_nphy_tables_init_rev0(dev); diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 3a58aee4c4cf..3ce2e6f3a278 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -165,6 +165,10 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent( #define B43_NTAB_C1_LOFEEDTH_R3 B43_NTAB16(27, 448) /* Local Oscillator Feed Through lookup 1 */ #define B43_NTAB_C1_PAPD_COMP_R3 B43_NTAB16(27, 576) +/* Static N-PHY tables, PHY revision >= 7 */ +#define B43_NTAB_TMAP_R7 B43_NTAB32(12, 0) /* TM AP */ +#define B43_NTAB_NOISEVAR_R7 B43_NTAB32(16, 0) /* noise variance */ + #define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_40_SIZE 18 #define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_20_SIZE 18 #define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_40_SIZE 18 -- cgit v1.2.3 From 7ef5cd240a133efd506c2e80c060b89406700bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 2 Jul 2014 22:42:45 +0200 Subject: b43: N-PHY: rework names & picking of TX gain tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows adding more revisions support, spotting lacking tables and unifies naming schema. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 12 +++- drivers/net/wireless/b43/tables_nphy.c | 102 +++++++++++++++++++++++---------- 2 files changed, 84 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 0a6f04be9073..50ca6f87d5e8 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -3369,7 +3369,11 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) */ for (i = 0; i < 2; i++) { - txgain = *(b43_nphy_get_tx_gain_table(dev) + txpi[i]); + const u32 *table = b43_nphy_get_tx_gain_table(dev); + + if (!table) + break; + txgain = *(table + txpi[i]); if (dev->phy.rev >= 3) radio_gain = (txgain >> 16) & 0x1FFFF; @@ -3783,6 +3787,9 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev) int i; table = b43_nphy_get_tx_gain_table(dev); + if (!table) + return; + b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128, table); b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128, table); @@ -4488,6 +4495,9 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) for (i = 0; i < 2; ++i) { table = b43_nphy_get_tx_gain_table(dev); + if (!table) + break; + if (dev->phy.rev >= 3) { target.ipa[i] = (table[index[i]] >> 16) & 0xF; target.pad[i] = (table[index[i]] >> 20) & 0xF; diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index dd876857969e..3d6dda7c4fe8 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2332,7 +2332,10 @@ static const u32 b43_ntab_noisevar_r7[] = { 0x020c020c, 0x0000014d, 0x020c020c, 0x0000014d, }; -/* TX gain tables */ +/************************************************** + * TX gain tables + **************************************************/ + static const u32 b43_ntab_tx_gain_rev0_1_2[] = { 0x03cc2b44, 0x03cc2b42, 0x03cc2a44, 0x03cc2a42, 0x03cc2944, 0x03c82b44, 0x03c82b42, 0x03c82a44, @@ -2368,7 +2371,9 @@ static const u32 b43_ntab_tx_gain_rev0_1_2[] = { 0x03801442, 0x03801344, 0x03801342, 0x00002b00, }; -static const u32 b43_ntab_tx_gain_rev3plus_2ghz[] = { +/* EPA 2 GHz */ + +static const u32 b43_ntab_tx_gain_epa_rev3_2g[] = { 0x1f410044, 0x1f410042, 0x1f410040, 0x1f41003e, 0x1f41003c, 0x1f41003b, 0x1f410039, 0x1f410037, 0x1e410044, 0x1e410042, 0x1e410040, 0x1e41003e, @@ -2403,7 +2408,9 @@ static const u32 b43_ntab_tx_gain_rev3plus_2ghz[] = { 0x1041003c, 0x1041003b, 0x10410039, 0x10410037, }; -static const u32 b43_ntab_tx_gain_rev3_5ghz[] = { +/* EPA 5 GHz */ + +static const u32 b43_ntab_tx_gain_epa_rev3_5g[] = { 0xcff70044, 0xcff70042, 0xcff70040, 0xcff7003e, 0xcff7003c, 0xcff7003b, 0xcff70039, 0xcff70037, 0xcef70044, 0xcef70042, 0xcef70040, 0xcef7003e, @@ -2438,7 +2445,7 @@ static const u32 b43_ntab_tx_gain_rev3_5ghz[] = { 0xc0f7003c, 0xc0f7003b, 0xc0f70039, 0xc0f70037, }; -static const u32 b43_ntab_tx_gain_rev4_5ghz[] = { +static const u32 b43_ntab_tx_gain_epa_rev4_5g[] = { 0x2ff20044, 0x2ff20042, 0x2ff20040, 0x2ff2003e, 0x2ff2003c, 0x2ff2003b, 0x2ff20039, 0x2ff20037, 0x2ef20044, 0x2ef20042, 0x2ef20040, 0x2ef2003e, @@ -2473,7 +2480,7 @@ static const u32 b43_ntab_tx_gain_rev4_5ghz[] = { 0x20d2003a, 0x20d20038, 0x20d20036, 0x20d20034, }; -static const u32 b43_ntab_tx_gain_rev5plus_5ghz[] = { +static const u32 b43_ntab_tx_gain_epa_rev5_5g[] = { 0x0f62004a, 0x0f620048, 0x0f620046, 0x0f620044, 0x0f620042, 0x0f620040, 0x0f62003e, 0x0f62003c, 0x0e620044, 0x0e620042, 0x0e620040, 0x0e62003e, @@ -2508,7 +2515,9 @@ static const u32 b43_ntab_tx_gain_rev5plus_5ghz[] = { 0x0062003b, 0x00620039, 0x00620037, 0x00620035, }; -static const u32 txpwrctrl_tx_gain_ipa[] = { +/* IPA 2 GHz */ + +static const u32 b43_ntab_tx_gain_ipa_rev3_2g[] = { 0x5ff7002d, 0x5ff7002b, 0x5ff7002a, 0x5ff70029, 0x5ff70028, 0x5ff70027, 0x5ff70026, 0x5ff70025, 0x5ef7002d, 0x5ef7002b, 0x5ef7002a, 0x5ef70029, @@ -2543,7 +2552,7 @@ static const u32 txpwrctrl_tx_gain_ipa[] = { 0x50f70028, 0x50f70027, 0x50f70026, 0x50f70025, }; -static const u32 txpwrctrl_tx_gain_ipa_rev5[] = { +static const u32 b43_ntab_tx_gain_ipa_rev5_2g[] = { 0x1ff7002d, 0x1ff7002b, 0x1ff7002a, 0x1ff70029, 0x1ff70028, 0x1ff70027, 0x1ff70026, 0x1ff70025, 0x1ef7002d, 0x1ef7002b, 0x1ef7002a, 0x1ef70029, @@ -2578,7 +2587,7 @@ static const u32 txpwrctrl_tx_gain_ipa_rev5[] = { 0x10f70028, 0x10f70027, 0x10f70026, 0x10f70025, }; -static const u32 txpwrctrl_tx_gain_ipa_rev6[] = { +static const u32 b43_ntab_tx_gain_ipa_rev6_2g[] = { 0x0ff7002d, 0x0ff7002b, 0x0ff7002a, 0x0ff70029, 0x0ff70028, 0x0ff70027, 0x0ff70026, 0x0ff70025, 0x0ef7002d, 0x0ef7002b, 0x0ef7002a, 0x0ef70029, @@ -2613,7 +2622,9 @@ static const u32 txpwrctrl_tx_gain_ipa_rev6[] = { 0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025, }; -static const u32 txpwrctrl_tx_gain_ipa_5g[] = { +/* IPA 2 5Hz */ + +static const u32 b43_ntab_tx_gain_ipa_rev3_5g[] = { 0x7ff70035, 0x7ff70033, 0x7ff70032, 0x7ff70031, 0x7ff7002f, 0x7ff7002e, 0x7ff7002d, 0x7ff7002b, 0x7ff7002a, 0x7ff70029, 0x7ff70028, 0x7ff70027, @@ -3390,23 +3401,39 @@ void b43_nphy_tables_init(struct b43_wldev *dev) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) { + struct b43_phy *phy = &dev->phy; + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - if (dev->phy.rev >= 6) { - if (dev->dev->chip_id == 47162) - return txpwrctrl_tx_gain_ipa_rev5; - return txpwrctrl_tx_gain_ipa_rev6; - } else if (dev->phy.rev >= 5) { - return txpwrctrl_tx_gain_ipa_rev5; - } else { - return txpwrctrl_tx_gain_ipa; + switch (phy->rev) { + case 6: + if (dev->dev->chip_id == BCMA_CHIP_ID_BCM47162) + return b43_ntab_tx_gain_ipa_rev5_2g; + return b43_ntab_tx_gain_ipa_rev6_2g; + case 5: + return b43_ntab_tx_gain_ipa_rev5_2g; + case 4: + case 3: + return b43_ntab_tx_gain_ipa_rev3_2g; + default: + b43err(dev->wl, + "No 2GHz IPA gain table available for this device\n"); + return NULL; } } else { - return txpwrctrl_tx_gain_ipa_5g; + switch (phy->rev) { + case 3 ... 6: + return b43_ntab_tx_gain_ipa_rev3_5g; + default: + b43err(dev->wl, + "No 5GHz IPA gain table available for this device\n"); + return NULL; + } } } const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev) { + struct b43_phy *phy = &dev->phy; enum ieee80211_band band = b43_current_band(dev->wl); struct ssb_sprom *sprom = dev->dev->bus_sprom; @@ -3418,19 +3445,36 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev) (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ)) { return b43_nphy_get_ipa_gain_table(dev); } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { - if (dev->phy.rev == 3) - return b43_ntab_tx_gain_rev3_5ghz; - if (dev->phy.rev == 4) + switch (phy->rev) { + case 6: + case 5: + return b43_ntab_tx_gain_epa_rev5_5g; + case 4: return sprom->fem.ghz5.extpa_gain == 3 ? - b43_ntab_tx_gain_rev4_5ghz : - b43_ntab_tx_gain_rev4_5ghz; /* FIXME */ - else - return b43_ntab_tx_gain_rev5plus_5ghz; + b43_ntab_tx_gain_epa_rev4_5g : + b43_ntab_tx_gain_epa_rev4_5g; /* FIXME */ + case 3: + return b43_ntab_tx_gain_epa_rev3_5g; + default: + b43err(dev->wl, + "No 5GHz EPA gain table available for this device\n"); + return NULL; + } } else { - if (dev->phy.rev >= 5 && sprom->fem.ghz5.extpa_gain == 3) - return b43_ntab_tx_gain_rev3plus_2ghz; /* FIXME */ - else - return b43_ntab_tx_gain_rev3plus_2ghz; + switch (phy->rev) { + case 6: + case 5: + if (sprom->fem.ghz5.extpa_gain == 3) + return b43_ntab_tx_gain_epa_rev3_2g; /* FIXME */ + /* fall through */ + case 4: + case 3: + return b43_ntab_tx_gain_epa_rev3_2g; + default: + b43err(dev->wl, + "No 2GHz EPA gain table available for this device\n"); + return NULL; + } } } -- cgit v1.2.3 From c4e197195a0c38b2c0928a03ed1de1a4a32f52c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 2 Jul 2014 22:42:46 +0200 Subject: b43: N-PHY: add TX gains tables for radio 0x2057 rev 9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/tables_nphy.c | 78 ++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 3d6dda7c4fe8..b28dce950e1f 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2622,6 +2622,42 @@ static const u32 b43_ntab_tx_gain_ipa_rev6_2g[] = { 0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025, }; +/* Extracted from MMIO dump of 6.30.223.141 */ +static const u32 b43_ntab_tx_gain_ipa_2057_rev9_2g[] = { + 0x60ff0031, 0x60e7002c, 0x60cf002a, 0x60c70029, + 0x60b70029, 0x60a70029, 0x609f002a, 0x6097002b, + 0x6087002e, 0x60770031, 0x606f0032, 0x60670034, + 0x60670031, 0x605f0033, 0x605f0031, 0x60570033, + 0x60570030, 0x6057002d, 0x6057002b, 0x604f002d, + 0x604f002b, 0x604f0029, 0x604f0026, 0x60470029, + 0x60470027, 0x603f0029, 0x603f0027, 0x603f0025, + 0x60370029, 0x60370027, 0x60370024, 0x602f002a, + 0x602f0028, 0x602f0026, 0x602f0024, 0x6027002a, + 0x60270028, 0x60270026, 0x60270024, 0x60270022, + 0x601f002b, 0x601f0029, 0x601f0027, 0x601f0024, + 0x601f0022, 0x601f0020, 0x601f001f, 0x601f001d, + 0x60170029, 0x60170027, 0x60170025, 0x60170023, + 0x60170021, 0x6017001f, 0x6017001d, 0x6017001c, + 0x6017001a, 0x60170018, 0x60170018, 0x60170016, + 0x60170015, 0x600f0029, 0x600f0027, 0x600f0025, + 0x600f0023, 0x600f0021, 0x600f001f, 0x600f001d, + 0x600f001c, 0x600f001a, 0x600f0019, 0x600f0018, + 0x600f0016, 0x600f0015, 0x600f0115, 0x600f0215, + 0x600f0315, 0x600f0415, 0x600f0515, 0x600f0615, + 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, + 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, + 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, + 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, + 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, + 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, + 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, + 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, + 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, + 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, + 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, + 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, +}; + /* IPA 2 5Hz */ static const u32 b43_ntab_tx_gain_ipa_rev3_5g[] = { @@ -2659,6 +2695,42 @@ static const u32 b43_ntab_tx_gain_ipa_rev3_5g[] = { 0x70f70021, 0x70f70020, 0x70f70020, 0x70f7001f, }; +/* Extracted from MMIO dump of 6.30.223.141 */ +static const u32 b43_ntab_tx_gain_ipa_2057_rev9_5g[] = { + 0x7f7f0053, 0x7f7f004b, 0x7f7f0044, 0x7f7f003f, + 0x7f7f0039, 0x7f7f0035, 0x7f7f0032, 0x7f7f0030, + 0x7f7f002d, 0x7e7f0030, 0x7e7f002d, 0x7d7f0032, + 0x7d7f002f, 0x7d7f002c, 0x7c7f0032, 0x7c7f0030, + 0x7c7f002d, 0x7b7f0030, 0x7b7f002e, 0x7b7f002b, + 0x7a7f0032, 0x7a7f0030, 0x7a7f002d, 0x7a7f002b, + 0x797f0030, 0x797f002e, 0x797f002b, 0x797f0029, + 0x787f0030, 0x787f002d, 0x787f002b, 0x777f0032, + 0x777f0030, 0x777f002d, 0x777f002b, 0x767f0031, + 0x767f002f, 0x767f002c, 0x767f002a, 0x757f0031, + 0x757f002f, 0x757f002c, 0x757f002a, 0x747f0030, + 0x747f002d, 0x747f002b, 0x737f0032, 0x737f002f, + 0x737f002c, 0x737f002a, 0x727f0030, 0x727f002d, + 0x727f002b, 0x727f0029, 0x717f0030, 0x717f002d, + 0x717f002b, 0x707f0031, 0x707f002f, 0x707f002c, + 0x707f002a, 0x707f0027, 0x707f0025, 0x707f0023, + 0x707f0021, 0x707f001f, 0x707f001d, 0x707f001c, + 0x707f001a, 0x707f0019, 0x707f0017, 0x707f0016, + 0x707f0015, 0x707f0014, 0x707f0012, 0x707f0012, + 0x707f0011, 0x707f0010, 0x707f000f, 0x707f000e, + 0x707f000d, 0x707f000d, 0x707f000c, 0x707f000b, + 0x707f000a, 0x707f000a, 0x707f0009, 0x707f0008, + 0x707f0008, 0x707f0008, 0x707f0008, 0x707f0007, + 0x707f0007, 0x707f0006, 0x707f0006, 0x707f0006, + 0x707f0005, 0x707f0005, 0x707f0005, 0x707f0004, + 0x707f0004, 0x707f0004, 0x707f0003, 0x707f0003, + 0x707f0003, 0x707f0003, 0x707f0003, 0x707f0003, + 0x707f0003, 0x707f0003, 0x707f0003, 0x707f0003, + 0x707f0002, 0x707f0002, 0x707f0002, 0x707f0002, + 0x707f0002, 0x707f0002, 0x707f0002, 0x707f0002, + 0x707f0002, 0x707f0001, 0x707f0001, 0x707f0001, + 0x707f0001, 0x707f0001, 0x707f0001, 0x707f0001, +}; + const s8 b43_ntab_papd_pga_gain_delta_ipa_2g[] = { -114, -108, -98, -91, -84, -78, -70, -62, -54, -46, -39, -31, -23, -15, -8, 0 @@ -3405,6 +3477,9 @@ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { switch (phy->rev) { + case 16: + if (phy->radio_rev == 9) + return b43_ntab_tx_gain_ipa_2057_rev9_2g; case 6: if (dev->dev->chip_id == BCMA_CHIP_ID_BCM47162) return b43_ntab_tx_gain_ipa_rev5_2g; @@ -3421,6 +3496,9 @@ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) } } else { switch (phy->rev) { + case 16: + if (phy->radio_rev == 9) + return b43_ntab_tx_gain_ipa_2057_rev9_5g; case 3 ... 6: return b43_ntab_tx_gain_ipa_rev3_5g; default: -- cgit v1.2.3 From fe5e499f427dadbeeb079e0a796702f4a3da78a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 4 Jul 2014 09:21:56 +0200 Subject: b43: fix reading info about radio for new devices (cores 40 & 42) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes b43-phy0: Found Radio: Manuf 0x17F, Version 0x7769, Revision 4 to the b43-phy0: Found Radio: Manuf 0x17F, Version 0x2069, Revision 4 which matches what closed source driver reports: $ wl revinfo radiorev 0x42069000 Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ca4a19077d7e..b2bc593a6513 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4329,6 +4329,7 @@ static char *b43_phy_name(struct b43_wldev *dev, u8 phy_type) static int b43_phy_versioning(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + const u8 core_rev = dev->dev->core_rev; u32 tmp; u8 analog_type; u8 phy_type; @@ -4394,7 +4395,15 @@ static int b43_phy_versioning(struct b43_wldev *dev) analog_type, phy_type, b43_phy_name(dev, phy_type), phy_rev); /* Get RADIO versioning */ - if (dev->dev->core_rev >= 24) { + if (core_rev == 40 || core_rev == 42) { + radio_manuf = 0x17F; + + b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 0); + radio_rev = b43_read16(dev, B43_MMIO_RADIO24_DATA); + + b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 1); + radio_ver = b43_read16(dev, B43_MMIO_RADIO24_DATA); + } else if (core_rev >= 24) { u16 radio24[3]; for (tmp = 0; tmp < 3; tmp++) { -- cgit v1.2.3 From f473832fece16611520bf54ad52b16c3f6db0a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 5 Jul 2014 01:10:41 +0200 Subject: bcma: add driver for PCIe Gen 2 core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New Broadcom PCIe devices (802.11ac ones?) use Gen2 and have to be initialized differently. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/bcma/Makefile | 1 + drivers/bcma/driver_pcie2.c | 175 +++++++++++++++++++++++++++++++++ drivers/bcma/main.c | 8 ++ include/linux/bcma/bcma.h | 2 + include/linux/bcma/bcma_driver_pcie2.h | 158 +++++++++++++++++++++++++++++ 5 files changed, 344 insertions(+) create mode 100644 drivers/bcma/driver_pcie2.c create mode 100644 include/linux/bcma/bcma_driver_pcie2.h diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile index 734b32f09c0a..91290f7f61b8 100644 --- a/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile @@ -3,6 +3,7 @@ bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o bcma-y += driver_pci.o +bcma-y += driver_pcie2.o bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o diff --git a/drivers/bcma/driver_pcie2.c b/drivers/bcma/driver_pcie2.c new file mode 100644 index 000000000000..e4be537b0c66 --- /dev/null +++ b/drivers/bcma/driver_pcie2.c @@ -0,0 +1,175 @@ +/* + * Broadcom specific AMBA + * PCIe Gen 2 Core + * + * Copyright 2014, Broadcom Corporation + * Copyright 2014, Rafał Miłecki + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include + +/************************************************** + * R/W ops. + **************************************************/ + +#if 0 +static u32 bcma_core_pcie2_cfg_read(struct bcma_drv_pcie2 *pcie2, u32 addr) +{ + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, addr); + pcie2_read32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR); + return pcie2_read32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA); +} +#endif + +static void bcma_core_pcie2_cfg_write(struct bcma_drv_pcie2 *pcie2, u32 addr, + u32 val) +{ + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, addr); + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, val); +} + +/************************************************** + * Init. + **************************************************/ + +static u32 bcma_core_pcie2_war_delay_perst_enab(struct bcma_drv_pcie2 *pcie2, + bool enable) +{ + u32 val; + + /* restore back to default */ + val = pcie2_read32(pcie2, BCMA_CORE_PCIE2_CLK_CONTROL); + val |= PCIE2_CLKC_DLYPERST; + val &= ~PCIE2_CLKC_DISSPROMLD; + if (enable) { + val &= ~PCIE2_CLKC_DLYPERST; + val |= PCIE2_CLKC_DISSPROMLD; + } + pcie2_write32(pcie2, (BCMA_CORE_PCIE2_CLK_CONTROL), val); + /* flush */ + return pcie2_read32(pcie2, BCMA_CORE_PCIE2_CLK_CONTROL); +} + +static void bcma_core_pcie2_set_ltr_vals(struct bcma_drv_pcie2 *pcie2) +{ + /* LTR0 */ + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, 0x844); + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 0x883c883c); + /* LTR1 */ + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, 0x848); + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 0x88648864); + /* LTR2 */ + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, 0x84C); + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 0x90039003); +} + +static void bcma_core_pcie2_hw_ltr_war(struct bcma_drv_pcie2 *pcie2) +{ + u8 core_rev = pcie2->core->id.rev; + u32 devstsctr2; + + if (core_rev < 2 || core_rev == 10 || core_rev > 13) + return; + + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, + PCIE2_CAP_DEVSTSCTRL2_OFFSET); + devstsctr2 = pcie2_read32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA); + if (devstsctr2 & PCIE2_CAP_DEVSTSCTRL2_LTRENAB) { + /* force the right LTR values */ + bcma_core_pcie2_set_ltr_vals(pcie2); + + /* TODO: + si_core_wrapperreg(pcie2, 3, 0x60, 0x8080, 0); */ + + /* enable the LTR */ + devstsctr2 |= PCIE2_CAP_DEVSTSCTRL2_LTRENAB; + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, + PCIE2_CAP_DEVSTSCTRL2_OFFSET); + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, devstsctr2); + + /* set the LTR state to be active */ + pcie2_write32(pcie2, BCMA_CORE_PCIE2_LTR_STATE, + PCIE2_LTR_ACTIVE); + usleep_range(1000, 2000); + + /* set the LTR state to be sleep */ + pcie2_write32(pcie2, BCMA_CORE_PCIE2_LTR_STATE, + PCIE2_LTR_SLEEP); + usleep_range(1000, 2000); + } +} + +static void pciedev_crwlpciegen2(struct bcma_drv_pcie2 *pcie2) +{ + u8 core_rev = pcie2->core->id.rev; + bool pciewar160, pciewar162; + + pciewar160 = core_rev == 7 || core_rev == 9 || core_rev == 11; + pciewar162 = core_rev == 5 || core_rev == 7 || core_rev == 8 || + core_rev == 9 || core_rev == 11; + + if (!pciewar160 && !pciewar162) + return; + +/* TODO */ +#if 0 + pcie2_set32(pcie2, BCMA_CORE_PCIE2_CLK_CONTROL, + PCIE_DISABLE_L1CLK_GATING); +#if 0 + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, + PCIEGEN2_COE_PVT_TL_CTRL_0); + pcie2_mask32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, + ~(1 << COE_PVT_TL_CTRL_0_PM_DIS_L1_REENTRY_BIT)); +#endif +#endif +} + +static void pciedev_crwlpciegen2_180(struct bcma_drv_pcie2 *pcie2) +{ + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, PCIE2_PMCR_REFUP); + pcie2_set32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 0x1f); +} + +static void pciedev_crwlpciegen2_182(struct bcma_drv_pcie2 *pcie2) +{ + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, PCIE2_SBMBX); + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, 1 << 0); +} + +static void pciedev_reg_pm_clk_period(struct bcma_drv_pcie2 *pcie2) +{ + struct bcma_drv_cc *drv_cc = &pcie2->core->bus->drv_cc; + u8 core_rev = pcie2->core->id.rev; + u32 alp_khz, pm_value; + + if (core_rev <= 13) { + alp_khz = bcma_pmu_get_alp_clock(drv_cc) / 1000; + pm_value = (1000000 * 2) / alp_khz; + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDADDR, + PCIE2_PVT_REG_PM_CLK_PERIOD); + pcie2_write32(pcie2, BCMA_CORE_PCIE2_CONFIGINDDATA, pm_value); + } +} + +void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2) +{ + struct bcma_chipinfo *ci = &pcie2->core->bus->chipinfo; + u32 tmp; + + tmp = pcie2_read32(pcie2, BCMA_CORE_PCIE2_SPROM(54)); + if ((tmp & 0xe) >> 1 == 2) + bcma_core_pcie2_cfg_write(pcie2, 0x4e0, 0x17); + + /* TODO: Do we need pcie_reqsize? */ + + if (ci->id == BCMA_CHIP_ID_BCM4360 && ci->rev > 3) + bcma_core_pcie2_war_delay_perst_enab(pcie2, true); + bcma_core_pcie2_hw_ltr_war(pcie2); + pciedev_crwlpciegen2(pcie2); + pciedev_reg_pm_clk_period(pcie2); + pciedev_crwlpciegen2_180(pcie2); + pciedev_crwlpciegen2_182(pcie2); +} diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 34ea4c588d36..0ff8d58831ef 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -132,6 +132,7 @@ static int bcma_register_cores(struct bcma_bus *bus) case BCMA_CORE_CHIPCOMMON: case BCMA_CORE_PCI: case BCMA_CORE_PCIE: + case BCMA_CORE_PCIE2: case BCMA_CORE_MIPS_74K: case BCMA_CORE_4706_MAC_GBIT_COMMON: continue; @@ -281,6 +282,13 @@ int bcma_bus_register(struct bcma_bus *bus) bcma_core_pci_init(&bus->drv_pci[1]); } + /* Init PCIe Gen 2 core */ + core = bcma_find_core_unit(bus, BCMA_CORE_PCIE2, 0); + if (core) { + bus->drv_pcie2.core = core; + bcma_core_pcie2_init(&bus->drv_pcie2); + } + /* Init GBIT MAC COMMON core */ core = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON); if (core) { diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 0b3bb16c705a..452286a38b2b 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include /* SPROM sharing */ @@ -333,6 +334,7 @@ struct bcma_bus { struct bcma_drv_cc drv_cc; struct bcma_drv_pci drv_pci[2]; + struct bcma_drv_pcie2 drv_pcie2; struct bcma_drv_mips drv_mips; struct bcma_drv_gmac_cmn drv_gmac_cmn; diff --git a/include/linux/bcma/bcma_driver_pcie2.h b/include/linux/bcma/bcma_driver_pcie2.h new file mode 100644 index 000000000000..5988b05781c3 --- /dev/null +++ b/include/linux/bcma/bcma_driver_pcie2.h @@ -0,0 +1,158 @@ +#ifndef LINUX_BCMA_DRIVER_PCIE2_H_ +#define LINUX_BCMA_DRIVER_PCIE2_H_ + +#define BCMA_CORE_PCIE2_CLK_CONTROL 0x0000 +#define PCIE2_CLKC_RST_OE 0x0001 /* When set, drives PCI_RESET out to pin */ +#define PCIE2_CLKC_RST 0x0002 /* Value driven out to pin */ +#define PCIE2_CLKC_SPERST 0x0004 /* SurvivePeRst */ +#define PCIE2_CLKC_DISABLE_L1CLK_GATING 0x0010 +#define PCIE2_CLKC_DLYPERST 0x0100 /* Delay PeRst to CoE Core */ +#define PCIE2_CLKC_DISSPROMLD 0x0200 /* DisableSpromLoadOnPerst */ +#define PCIE2_CLKC_WAKE_MODE_L2 0x1000 /* Wake on L2 */ +#define BCMA_CORE_PCIE2_RC_PM_CONTROL 0x0004 +#define BCMA_CORE_PCIE2_RC_PM_STATUS 0x0008 +#define BCMA_CORE_PCIE2_EP_PM_CONTROL 0x000C +#define BCMA_CORE_PCIE2_EP_PM_STATUS 0x0010 +#define BCMA_CORE_PCIE2_EP_LTR_CONTROL 0x0014 +#define BCMA_CORE_PCIE2_EP_LTR_STATUS 0x0018 +#define BCMA_CORE_PCIE2_EP_OBFF_STATUS 0x001C +#define BCMA_CORE_PCIE2_PCIE_ERR_STATUS 0x0020 +#define BCMA_CORE_PCIE2_RC_AXI_CONFIG 0x0100 +#define BCMA_CORE_PCIE2_EP_AXI_CONFIG 0x0104 +#define BCMA_CORE_PCIE2_RXDEBUG_STATUS0 0x0108 +#define BCMA_CORE_PCIE2_RXDEBUG_CONTROL0 0x010C +#define BCMA_CORE_PCIE2_CONFIGINDADDR 0x0120 +#define BCMA_CORE_PCIE2_CONFIGINDDATA 0x0124 +#define BCMA_CORE_PCIE2_MDIOCONTROL 0x0128 +#define BCMA_CORE_PCIE2_MDIOWRDATA 0x012C +#define BCMA_CORE_PCIE2_MDIORDDATA 0x0130 +#define BCMA_CORE_PCIE2_DATAINTF 0x0180 +#define BCMA_CORE_PCIE2_D2H_INTRLAZY_0 0x0188 +#define BCMA_CORE_PCIE2_H2D_INTRLAZY_0 0x018c +#define BCMA_CORE_PCIE2_H2D_INTSTAT_0 0x0190 +#define BCMA_CORE_PCIE2_H2D_INTMASK_0 0x0194 +#define BCMA_CORE_PCIE2_D2H_INTSTAT_0 0x0198 +#define BCMA_CORE_PCIE2_D2H_INTMASK_0 0x019c +#define BCMA_CORE_PCIE2_LTR_STATE 0x01A0 /* Latency Tolerance Reporting */ +#define PCIE2_LTR_ACTIVE 2 +#define PCIE2_LTR_ACTIVE_IDLE 1 +#define PCIE2_LTR_SLEEP 0 +#define PCIE2_LTR_FINAL_MASK 0x300 +#define PCIE2_LTR_FINAL_SHIFT 8 +#define BCMA_CORE_PCIE2_PWR_INT_STATUS 0x01A4 +#define BCMA_CORE_PCIE2_PWR_INT_MASK 0x01A8 +#define BCMA_CORE_PCIE2_CFG_ADDR 0x01F8 +#define BCMA_CORE_PCIE2_CFG_DATA 0x01FC +#define BCMA_CORE_PCIE2_SYS_EQ_PAGE 0x0200 +#define BCMA_CORE_PCIE2_SYS_MSI_PAGE 0x0204 +#define BCMA_CORE_PCIE2_SYS_MSI_INTREN 0x0208 +#define BCMA_CORE_PCIE2_SYS_MSI_CTRL0 0x0210 +#define BCMA_CORE_PCIE2_SYS_MSI_CTRL1 0x0214 +#define BCMA_CORE_PCIE2_SYS_MSI_CTRL2 0x0218 +#define BCMA_CORE_PCIE2_SYS_MSI_CTRL3 0x021C +#define BCMA_CORE_PCIE2_SYS_MSI_CTRL4 0x0220 +#define BCMA_CORE_PCIE2_SYS_MSI_CTRL5 0x0224 +#define BCMA_CORE_PCIE2_SYS_EQ_HEAD0 0x0250 +#define BCMA_CORE_PCIE2_SYS_EQ_TAIL0 0x0254 +#define BCMA_CORE_PCIE2_SYS_EQ_HEAD1 0x0258 +#define BCMA_CORE_PCIE2_SYS_EQ_TAIL1 0x025C +#define BCMA_CORE_PCIE2_SYS_EQ_HEAD2 0x0260 +#define BCMA_CORE_PCIE2_SYS_EQ_TAIL2 0x0264 +#define BCMA_CORE_PCIE2_SYS_EQ_HEAD3 0x0268 +#define BCMA_CORE_PCIE2_SYS_EQ_TAIL3 0x026C +#define BCMA_CORE_PCIE2_SYS_EQ_HEAD4 0x0270 +#define BCMA_CORE_PCIE2_SYS_EQ_TAIL4 0x0274 +#define BCMA_CORE_PCIE2_SYS_EQ_HEAD5 0x0278 +#define BCMA_CORE_PCIE2_SYS_EQ_TAIL5 0x027C +#define BCMA_CORE_PCIE2_SYS_RC_INTX_EN 0x0330 +#define BCMA_CORE_PCIE2_SYS_RC_INTX_CSR 0x0334 +#define BCMA_CORE_PCIE2_SYS_MSI_REQ 0x0340 +#define BCMA_CORE_PCIE2_SYS_HOST_INTR_EN 0x0344 +#define BCMA_CORE_PCIE2_SYS_HOST_INTR_CSR 0x0348 +#define BCMA_CORE_PCIE2_SYS_HOST_INTR0 0x0350 +#define BCMA_CORE_PCIE2_SYS_HOST_INTR1 0x0354 +#define BCMA_CORE_PCIE2_SYS_HOST_INTR2 0x0358 +#define BCMA_CORE_PCIE2_SYS_HOST_INTR3 0x035C +#define BCMA_CORE_PCIE2_SYS_EP_INT_EN0 0x0360 +#define BCMA_CORE_PCIE2_SYS_EP_INT_EN1 0x0364 +#define BCMA_CORE_PCIE2_SYS_EP_INT_CSR0 0x0370 +#define BCMA_CORE_PCIE2_SYS_EP_INT_CSR1 0x0374 +#define BCMA_CORE_PCIE2_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) +#define BCMA_CORE_PCIE2_FUNC0_IMAP0_0 0x0C00 +#define BCMA_CORE_PCIE2_FUNC0_IMAP0_1 0x0C04 +#define BCMA_CORE_PCIE2_FUNC0_IMAP0_2 0x0C08 +#define BCMA_CORE_PCIE2_FUNC0_IMAP0_3 0x0C0C +#define BCMA_CORE_PCIE2_FUNC0_IMAP0_4 0x0C10 +#define BCMA_CORE_PCIE2_FUNC0_IMAP0_5 0x0C14 +#define BCMA_CORE_PCIE2_FUNC0_IMAP0_6 0x0C18 +#define BCMA_CORE_PCIE2_FUNC0_IMAP0_7 0x0C1C +#define BCMA_CORE_PCIE2_FUNC1_IMAP0_0 0x0C20 +#define BCMA_CORE_PCIE2_FUNC1_IMAP0_1 0x0C24 +#define BCMA_CORE_PCIE2_FUNC1_IMAP0_2 0x0C28 +#define BCMA_CORE_PCIE2_FUNC1_IMAP0_3 0x0C2C +#define BCMA_CORE_PCIE2_FUNC1_IMAP0_4 0x0C30 +#define BCMA_CORE_PCIE2_FUNC1_IMAP0_5 0x0C34 +#define BCMA_CORE_PCIE2_FUNC1_IMAP0_6 0x0C38 +#define BCMA_CORE_PCIE2_FUNC1_IMAP0_7 0x0C3C +#define BCMA_CORE_PCIE2_FUNC0_IMAP1 0x0C80 +#define BCMA_CORE_PCIE2_FUNC1_IMAP1 0x0C88 +#define BCMA_CORE_PCIE2_FUNC0_IMAP2 0x0CC0 +#define BCMA_CORE_PCIE2_FUNC1_IMAP2 0x0CC8 +#define BCMA_CORE_PCIE2_IARR0_LOWER 0x0D00 +#define BCMA_CORE_PCIE2_IARR0_UPPER 0x0D04 +#define BCMA_CORE_PCIE2_IARR1_LOWER 0x0D08 +#define BCMA_CORE_PCIE2_IARR1_UPPER 0x0D0C +#define BCMA_CORE_PCIE2_IARR2_LOWER 0x0D10 +#define BCMA_CORE_PCIE2_IARR2_UPPER 0x0D14 +#define BCMA_CORE_PCIE2_OARR0 0x0D20 +#define BCMA_CORE_PCIE2_OARR1 0x0D28 +#define BCMA_CORE_PCIE2_OARR2 0x0D30 +#define BCMA_CORE_PCIE2_OMAP0_LOWER 0x0D40 +#define BCMA_CORE_PCIE2_OMAP0_UPPER 0x0D44 +#define BCMA_CORE_PCIE2_OMAP1_LOWER 0x0D48 +#define BCMA_CORE_PCIE2_OMAP1_UPPER 0x0D4C +#define BCMA_CORE_PCIE2_OMAP2_LOWER 0x0D50 +#define BCMA_CORE_PCIE2_OMAP2_UPPER 0x0D54 +#define BCMA_CORE_PCIE2_FUNC1_IARR1_SIZE 0x0D58 +#define BCMA_CORE_PCIE2_FUNC1_IARR2_SIZE 0x0D5C +#define BCMA_CORE_PCIE2_MEM_CONTROL 0x0F00 +#define BCMA_CORE_PCIE2_MEM_ECC_ERRLOG0 0x0F04 +#define BCMA_CORE_PCIE2_MEM_ECC_ERRLOG1 0x0F08 +#define BCMA_CORE_PCIE2_LINK_STATUS 0x0F0C +#define BCMA_CORE_PCIE2_STRAP_STATUS 0x0F10 +#define BCMA_CORE_PCIE2_RESET_STATUS 0x0F14 +#define BCMA_CORE_PCIE2_RESETEN_IN_LINKDOWN 0x0F18 +#define BCMA_CORE_PCIE2_MISC_INTR_EN 0x0F1C +#define BCMA_CORE_PCIE2_TX_DEBUG_CFG 0x0F20 +#define BCMA_CORE_PCIE2_MISC_CONFIG 0x0F24 +#define BCMA_CORE_PCIE2_MISC_STATUS 0x0F28 +#define BCMA_CORE_PCIE2_INTR_EN 0x0F30 +#define BCMA_CORE_PCIE2_INTR_CLEAR 0x0F34 +#define BCMA_CORE_PCIE2_INTR_STATUS 0x0F38 + +/* PCIE gen2 config regs */ +#define PCIE2_INTSTATUS 0x090 +#define PCIE2_INTMASK 0x094 +#define PCIE2_SBMBX 0x098 + +#define PCIE2_PMCR_REFUP 0x1814 /* Trefup time */ + +#define PCIE2_CAP_DEVSTSCTRL2_OFFSET 0xD4 +#define PCIE2_CAP_DEVSTSCTRL2_LTRENAB 0x400 +#define PCIE2_PVT_REG_PM_CLK_PERIOD 0x184c + +struct bcma_drv_pcie2 { + struct bcma_device *core; +}; + +#define pcie2_read16(pcie2, offset) bcma_read16((pcie2)->core, offset) +#define pcie2_read32(pcie2, offset) bcma_read32((pcie2)->core, offset) +#define pcie2_write16(pcie2, offset, val) bcma_write16((pcie2)->core, offset, val) +#define pcie2_write32(pcie2, offset, val) bcma_write32((pcie2)->core, offset, val) + +#define pcie2_set32(pcie2, offset, set) bcma_set32((pcie2)->core, offset, set) +#define pcie2_mask32(pcie2, offset, mask) bcma_mask32((pcie2)->core, offset, mask) + +void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2); + +#endif /* LINUX_BCMA_DRIVER_PCIE2_H_ */ -- cgit v1.2.3 From b9c701edc7ff6ddd522497b0194b0bc3ec1b51a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Fri, 27 Jun 2014 11:59:09 +0200 Subject: net: Simplify ptp class checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace two switch statements enumerating all valid ptp classes with an if statement matching for not PTP_CLASS_NONE. Signed-off-by: Stefan Sørensen Signed-off-by: David S. Miller --- net/core/timestamping.c | 57 +++++++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/net/core/timestamping.c b/net/core/timestamping.c index 6521dfd8b7c8..a8770391ea5b 100644 --- a/net/core/timestamping.c +++ b/net/core/timestamping.c @@ -43,31 +43,22 @@ void skb_clone_tx_timestamp(struct sk_buff *skb) return; type = classify(skb); + if (type == PTP_CLASS_NONE) + return; + + phydev = skb->dev->phydev; + if (likely(phydev->drv->txtstamp)) { + if (!atomic_inc_not_zero(&sk->sk_refcnt)) + return; - switch (type) { - case PTP_CLASS_V1_IPV4: - case PTP_CLASS_V1_IPV6: - case PTP_CLASS_V2_IPV4: - case PTP_CLASS_V2_IPV6: - case PTP_CLASS_V2_L2: - case PTP_CLASS_V2_VLAN: - phydev = skb->dev->phydev; - if (likely(phydev->drv->txtstamp)) { - if (!atomic_inc_not_zero(&sk->sk_refcnt)) - return; - - clone = skb_clone(skb, GFP_ATOMIC); - if (!clone) { - sock_put(sk); - return; - } - - clone->sk = sk; - phydev->drv->txtstamp(phydev, clone, type); + clone = skb_clone(skb, GFP_ATOMIC); + if (!clone) { + sock_put(sk); + return; } - break; - default: - break; + + clone->sk = sk; + phydev->drv->txtstamp(phydev, clone, type); } } EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp); @@ -114,20 +105,12 @@ bool skb_defer_rx_timestamp(struct sk_buff *skb) __skb_pull(skb, ETH_HLEN); - switch (type) { - case PTP_CLASS_V1_IPV4: - case PTP_CLASS_V1_IPV6: - case PTP_CLASS_V2_IPV4: - case PTP_CLASS_V2_IPV6: - case PTP_CLASS_V2_L2: - case PTP_CLASS_V2_VLAN: - phydev = skb->dev->phydev; - if (likely(phydev->drv->rxtstamp)) - return phydev->drv->rxtstamp(phydev, skb, type); - break; - default: - break; - } + if (type == PTP_CLASS_NONE) + return false; + + phydev = skb->dev->phydev; + if (likely(phydev->drv->rxtstamp)) + return phydev->drv->rxtstamp(phydev, skb, type); return false; } -- cgit v1.2.3 From ae5c6c6d7bcadfbedefb5fc8ff0ebe2bfa83a0a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Fri, 27 Jun 2014 11:59:10 +0200 Subject: ptp: Classify ptp over ip over vlan packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This extends the ptp bpf to also match ptp over ip over vlan packets. The ptp classes are changed to orthogonal bitfields representing version, transport and vlan values to simplify matching. Signed-off-by: Stefan Sørensen Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpts.c | 24 ++++++++-------- drivers/net/phy/dp83640.c | 46 ++++++++++++++---------------- include/linux/ptp_classify.h | 5 ++-- net/core/ptp_classifier.c | 64 ++++++++++++++++++++++++++++++++++++++---- 4 files changed, 92 insertions(+), 47 deletions(-) diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c index 6b56f85951e5..ab92f67da035 100644 --- a/drivers/net/ethernet/ti/cpts.c +++ b/drivers/net/ethernet/ti/cpts.c @@ -256,23 +256,21 @@ static int cpts_match(struct sk_buff *skb, unsigned int ptp_class, u16 ts_seqid, u8 ts_msgtype) { u16 *seqid; - unsigned int offset; + unsigned int offset = 0; u8 *msgtype, *data = skb->data; - switch (ptp_class) { - case PTP_CLASS_V1_IPV4: - case PTP_CLASS_V2_IPV4: - offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; - break; - case PTP_CLASS_V1_IPV6: - case PTP_CLASS_V2_IPV6: - offset = OFF_PTP6; + if (ptp_class & PTP_CLASS_VLAN) + offset += VLAN_HLEN; + + switch (ptp_class & PTP_CLASS_PMASK) { + case PTP_CLASS_IPV4: + offset += ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; break; - case PTP_CLASS_V2_L2: - offset = ETH_HLEN; + case PTP_CLASS_IPV6: + offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; break; - case PTP_CLASS_V2_VLAN: - offset = ETH_HLEN + VLAN_HLEN; + case PTP_CLASS_L2: + offset += ETH_HLEN; break; default: return 0; diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 293ad064905d..53bd1af68422 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -856,20 +856,18 @@ static int is_sync(struct sk_buff *skb, int type) u8 *data = skb->data, *msgtype; unsigned int offset = 0; - switch (type) { - case PTP_CLASS_V1_IPV4: - case PTP_CLASS_V2_IPV4: - offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; - break; - case PTP_CLASS_V1_IPV6: - case PTP_CLASS_V2_IPV6: - offset = OFF_PTP6; + if (type & PTP_CLASS_VLAN) + offset += VLAN_HLEN; + + switch (type & PTP_CLASS_PMASK) { + case PTP_CLASS_IPV4: + offset += ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; break; - case PTP_CLASS_V2_L2: - offset = ETH_HLEN; + case PTP_CLASS_IPV6: + offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; break; - case PTP_CLASS_V2_VLAN: - offset = ETH_HLEN + VLAN_HLEN; + case PTP_CLASS_L2: + offset += ETH_HLEN; break; default: return 0; @@ -889,25 +887,23 @@ static int is_sync(struct sk_buff *skb, int type) static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts) { u16 *seqid; - unsigned int offset; + unsigned int offset = 0; u8 *msgtype, *data = skb_mac_header(skb); /* check sequenceID, messageType, 12 bit hash of offset 20-29 */ - switch (type) { - case PTP_CLASS_V1_IPV4: - case PTP_CLASS_V2_IPV4: - offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; - break; - case PTP_CLASS_V1_IPV6: - case PTP_CLASS_V2_IPV6: - offset = OFF_PTP6; + if (type & PTP_CLASS_VLAN) + offset += VLAN_HLEN; + + switch (type & PTP_CLASS_PMASK) { + case PTP_CLASS_IPV4: + offset += ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; break; - case PTP_CLASS_V2_L2: - offset = ETH_HLEN; + case PTP_CLASS_IPV6: + offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; break; - case PTP_CLASS_V2_VLAN: - offset = ETH_HLEN + VLAN_HLEN; + case PTP_CLASS_L2: + offset += ETH_HLEN; break; default: return 0; diff --git a/include/linux/ptp_classify.h b/include/linux/ptp_classify.h index 7dfed71d76a6..159c987b1853 100644 --- a/include/linux/ptp_classify.h +++ b/include/linux/ptp_classify.h @@ -33,8 +33,8 @@ #define PTP_CLASS_IPV4 0x10 /* event in an IPV4 UDP packet */ #define PTP_CLASS_IPV6 0x20 /* event in an IPV6 UDP packet */ #define PTP_CLASS_L2 0x30 /* event in a L2 packet */ -#define PTP_CLASS_VLAN 0x40 /* event in a VLAN tagged L2 packet */ -#define PTP_CLASS_PMASK 0xf0 /* mask for the packet type field */ +#define PTP_CLASS_PMASK 0x30 /* mask for the packet type field */ +#define PTP_CLASS_VLAN 0x40 /* event in a VLAN tagged packet */ #define PTP_CLASS_V1_IPV4 (PTP_CLASS_V1 | PTP_CLASS_IPV4) #define PTP_CLASS_V1_IPV6 (PTP_CLASS_V1 | PTP_CLASS_IPV6) /* probably DNE */ @@ -54,7 +54,6 @@ #define IP6_HLEN 40 #define UDP_HLEN 8 #define OFF_IHL 14 -#define OFF_PTP6 (ETH_HLEN + IP6_HLEN + UDP_HLEN) #define IPV4_HLEN(data) (((struct iphdr *)(data + OFF_IHL))->ihl << 2) #if defined(CONFIG_NET_PTP_CLASSIFY) diff --git a/net/core/ptp_classifier.c b/net/core/ptp_classifier.c index d3027a73fd4b..12ab7b4be609 100644 --- a/net/core/ptp_classifier.c +++ b/net/core/ptp_classifier.c @@ -52,14 +52,43 @@ * test_8021q: * jneq #0x8100, test_ieee1588 ; ETH_P_8021Q ? * ldh [16] ; load inner type - * jneq #0x88f7, drop_ieee1588 ; ETH_P_1588 ? + * jneq #0x88f7, test_8021q_ipv4 ; ETH_P_1588 ? * ldb [18] ; load payload * and #0x8 ; as we don't have ports here, test * jneq #0x0, drop_ieee1588 ; for PTP_GEN_BIT and drop these * ldh [18] ; reload payload * and #0xf ; mask PTP_CLASS_VMASK - * or #0x40 ; PTP_CLASS_V2_VLAN + * or #0x70 ; PTP_CLASS_VLAN|PTP_CLASS_L2 + * ret a ; return PTP class + * + * ; PTP over UDP over IPv4 over 802.1Q over Ethernet + * test_8021q_ipv4: + * jneq #0x800, test_8021q_ipv6 ; ETH_P_IP ? + * ldb [27] ; load proto + * jneq #17, drop_8021q_ipv4 ; IPPROTO_UDP ? + * ldh [24] ; load frag offset field + * jset #0x1fff, drop_8021q_ipv4; don't allow fragments + * ldxb 4*([18]&0xf) ; load IP header len + * ldh [x + 20] ; load UDP dst port + * jneq #319, drop_8021q_ipv4 ; is port PTP_EV_PORT ? + * ldh [x + 26] ; load payload + * and #0xf ; mask PTP_CLASS_VMASK + * or #0x50 ; PTP_CLASS_VLAN|PTP_CLASS_IPV4 + * ret a ; return PTP class + * drop_8021q_ipv4: ret #0x0 ; PTP_CLASS_NONE + * + * ; PTP over UDP over IPv6 over 802.1Q over Ethernet + * test_8021q_ipv6: + * jneq #0x86dd, drop_8021q_ipv6 ; ETH_P_IPV6 ? + * ldb [24] ; load proto + * jneq #17, drop_8021q_ipv6 ; IPPROTO_UDP ? + * ldh [60] ; load UDP dst port + * jneq #319, drop_8021q_ipv6 ; is port PTP_EV_PORT ? + * ldh [66] ; load payload + * and #0xf ; mask PTP_CLASS_VMASK + * or #0x60 ; PTP_CLASS_VLAN|PTP_CLASS_IPV6 * ret a ; return PTP class + * drop_8021q_ipv6: ret #0x0 ; PTP_CLASS_NONE * * ; PTP over Ethernet * test_ieee1588: @@ -113,16 +142,39 @@ void __init ptp_classifier_init(void) { 0x44, 0, 0, 0x00000020 }, { 0x16, 0, 0, 0x00000000 }, { 0x06, 0, 0, 0x00000000 }, - { 0x15, 0, 9, 0x00008100 }, + { 0x15, 0, 32, 0x00008100 }, { 0x28, 0, 0, 0x00000010 }, - { 0x15, 0, 15, 0x000088f7 }, + { 0x15, 0, 7, 0x000088f7 }, { 0x30, 0, 0, 0x00000012 }, { 0x54, 0, 0, 0x00000008 }, - { 0x15, 0, 12, 0x00000000 }, + { 0x15, 0, 35, 0x00000000 }, { 0x28, 0, 0, 0x00000012 }, { 0x54, 0, 0, 0x0000000f }, - { 0x44, 0, 0, 0x00000040 }, + { 0x44, 0, 0, 0x00000070 }, + { 0x16, 0, 0, 0x00000000 }, + { 0x15, 0, 12, 0x00000800 }, + { 0x30, 0, 0, 0x0000001b }, + { 0x15, 0, 9, 0x00000011 }, + { 0x28, 0, 0, 0x00000018 }, + { 0x45, 7, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x00000012 }, + { 0x48, 0, 0, 0x00000014 }, + { 0x15, 0, 4, 0x0000013f }, + { 0x48, 0, 0, 0x0000001a }, + { 0x54, 0, 0, 0x0000000f }, + { 0x44, 0, 0, 0x00000050 }, + { 0x16, 0, 0, 0x00000000 }, + { 0x06, 0, 0, 0x00000000 }, + { 0x15, 0, 8, 0x000086dd }, + { 0x30, 0, 0, 0x00000018 }, + { 0x15, 0, 6, 0x00000011 }, + { 0x28, 0, 0, 0x0000003c }, + { 0x15, 0, 4, 0x0000013f }, + { 0x28, 0, 0, 0x00000042 }, + { 0x54, 0, 0, 0x0000000f }, + { 0x44, 0, 0, 0x00000060 }, { 0x16, 0, 0, 0x00000000 }, + { 0x06, 0, 0, 0x00000000 }, { 0x15, 0, 7, 0x000088f7 }, { 0x30, 0, 0, 0x0000000e }, { 0x54, 0, 0, 0x00000008 }, -- cgit v1.2.3 From a6111d3c93d05bfaf3fbf70ed2a0b84cb0d65406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Fri, 27 Jun 2014 11:59:11 +0200 Subject: vlan: Pass SIOC[SG]HWTSTAMP ioctls to real device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows applications to enable hardware timestamping without being aware of it being a vlan device and figuring out the real device. Signed-off-by: Stefan Sørensen Signed-off-by: David S. Miller --- net/8021q/vlan_dev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index ad2ac3c00398..9d0223b16b46 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -385,6 +385,8 @@ static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCGMIIPHY: case SIOCGMIIREG: case SIOCSMIIREG: + case SIOCSHWTSTAMP: + case SIOCGHWTSTAMP: if (netif_device_present(real_dev) && ops->ndo_do_ioctl) err = ops->ndo_do_ioctl(real_dev, &ifrr, cmd); break; -- cgit v1.2.3 From b98fe24ca7d0effdd4c47a9f681d9e4f10442827 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sun, 29 Jun 2014 00:06:29 +0530 Subject: batman-adv: Use kasprintf kasprintf combines kmalloc and sprintf, and takes care of the size calculation itself. The semantic patch that makes this change is as follows: // @@ expression a,flag; expression list args; statement S; @@ a = - \(kmalloc\|kzalloc\)(...,flag) + kasprintf(flag,args) <... when != a if (a == NULL || ...) S ...> - sprintf(a,args); // Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- net/batman-adv/sysfs.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index fc47baa888c5..f40cb0436eba 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c @@ -900,32 +900,24 @@ int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type, bat_kobj = &bat_priv->soft_iface->dev.kobj; - uevent_env[0] = kmalloc(strlen(BATADV_UEV_TYPE_VAR) + - strlen(batadv_uev_type_str[type]) + 1, - GFP_ATOMIC); + uevent_env[0] = kasprintf(GFP_ATOMIC, + "%s%s", BATADV_UEV_TYPE_VAR, + batadv_uev_type_str[type]); if (!uevent_env[0]) goto out; - sprintf(uevent_env[0], "%s%s", BATADV_UEV_TYPE_VAR, - batadv_uev_type_str[type]); - - uevent_env[1] = kmalloc(strlen(BATADV_UEV_ACTION_VAR) + - strlen(batadv_uev_action_str[action]) + 1, - GFP_ATOMIC); + uevent_env[1] = kasprintf(GFP_ATOMIC, + "%s%s", BATADV_UEV_ACTION_VAR, + batadv_uev_action_str[action]); if (!uevent_env[1]) goto out; - sprintf(uevent_env[1], "%s%s", BATADV_UEV_ACTION_VAR, - batadv_uev_action_str[action]); - /* If the event is DEL, ignore the data field */ if (action != BATADV_UEV_DEL) { - uevent_env[2] = kmalloc(strlen(BATADV_UEV_DATA_VAR) + - strlen(data) + 1, GFP_ATOMIC); + uevent_env[2] = kasprintf(GFP_ATOMIC, + "%s%s", BATADV_UEV_DATA_VAR, data); if (!uevent_env[2]) goto out; - - sprintf(uevent_env[2], "%s%s", BATADV_UEV_DATA_VAR, data); } ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env); -- cgit v1.2.3 From eb522bb4e0dc4800d3cd2eedc4288f90022293fa Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 30 Jun 2014 18:38:27 +0200 Subject: tlan: Enable activity LED on Olicom OC-2325 and OC-2326 Olicom OC-2325 and OC-2326 ethernet cards have an activity LED but it does not work with tlan driver as it's not enabled. Enable it. Tested with OC-2326. Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index 62b19be5183d..2199fc8e5003 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -107,8 +107,10 @@ static struct board { { "Compaq Netelligent 10/100 TX Embedded UTP", TLAN_ADAPTER_NONE, 0x83 }, { "Olicom OC-2183/2185", TLAN_ADAPTER_USE_INTERN_10, 0x83 }, - { "Olicom OC-2325", TLAN_ADAPTER_UNMANAGED_PHY, 0xf8 }, - { "Olicom OC-2326", TLAN_ADAPTER_USE_INTERN_10, 0xf8 }, + { "Olicom OC-2325", TLAN_ADAPTER_ACTIVITY_LED | + TLAN_ADAPTER_UNMANAGED_PHY, 0xf8 }, + { "Olicom OC-2326", TLAN_ADAPTER_ACTIVITY_LED | + TLAN_ADAPTER_USE_INTERN_10, 0xf8 }, { "Compaq Netelligent 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, { "Compaq Netelligent 10 T/2 PCI UTP/coax", TLAN_ADAPTER_NONE, 0x83 }, { "Compaq NetFlex-3/E", -- cgit v1.2.3 From c0a87c22d3f098517473c60c709478db80fcc544 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 30 Jun 2014 18:38:28 +0200 Subject: tlan: Enable link monitoring Enable old link monitoring code and modify it: - control LINK LED - use separate timer so it does not interfere with ACT LED Tested with Olicom OC-2326. Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 115 +++++++++++++++++------------------------ drivers/net/ethernet/ti/tlan.h | 3 +- 2 files changed, 49 insertions(+), 69 deletions(-) diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index 2199fc8e5003..ccde7482d404 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -69,10 +69,6 @@ MODULE_AUTHOR("Maintainer: Samuel Chessman "); MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters"); MODULE_LICENSE("GPL"); - -/* Define this to enable Link beat monitoring */ -#undef MONITOR - /* Turn on debugging. See Documentation/networking/tlan.txt for details */ static int debug; module_param(debug, int, 0); @@ -194,9 +190,7 @@ static void tlan_phy_power_up(struct net_device *); static void tlan_phy_reset(struct net_device *); static void tlan_phy_start_link(struct net_device *); static void tlan_phy_finish_auto_neg(struct net_device *); -#ifdef MONITOR -static void tlan_phy_monitor(struct net_device *); -#endif +static void tlan_phy_monitor(unsigned long); /* static int tlan_phy_nop(struct net_device *); @@ -339,6 +333,7 @@ static void tlan_stop(struct net_device *dev) { struct tlan_priv *priv = netdev_priv(dev); + del_timer_sync(&priv->media_timer); tlan_read_and_clear_stats(dev, TLAN_RECORD); outl(TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD); /* Reset and power down phy */ @@ -888,6 +883,7 @@ static int tlan_open(struct net_device *dev) } init_timer(&priv->timer); + init_timer(&priv->media_timer); tlan_start(dev); @@ -1810,11 +1806,6 @@ static void tlan_timer(unsigned long data) priv->timer.function = NULL; switch (priv->timer_type) { -#ifdef MONITOR - case TLAN_TIMER_LINK_BEAT: - tlan_phy_monitor(dev); - break; -#endif case TLAN_TIMER_PHY_PDOWN: tlan_phy_power_down(dev); break; @@ -1858,8 +1849,6 @@ static void tlan_timer(unsigned long data) } - - /***************************************************************************** ****************************************************************************** @@ -2257,42 +2246,39 @@ tlan_finish_reset(struct net_device *dev) tlan_mii_read_reg(dev, phy, MII_GEN_STS, &status); udelay(1000); tlan_mii_read_reg(dev, phy, MII_GEN_STS, &status); - if ((status & MII_GS_LINK) && - /* We only support link info on Nat.Sem. PHY's */ - (tlphy_id1 == NAT_SEM_ID1) && - (tlphy_id2 == NAT_SEM_ID2)) { - tlan_mii_read_reg(dev, phy, MII_AN_LPA, &partner); - tlan_mii_read_reg(dev, phy, TLAN_TLPHY_PAR, &tlphy_par); - - netdev_info(dev, - "Link active with %s %uMbps %s-Duplex\n", - !(tlphy_par & TLAN_PHY_AN_EN_STAT) - ? "forced" : "Autonegotiation enabled,", - tlphy_par & TLAN_PHY_SPEED_100 - ? 100 : 10, - tlphy_par & TLAN_PHY_DUPLEX_FULL - ? "Full" : "Half"); - - if (tlphy_par & TLAN_PHY_AN_EN_STAT) { - netdev_info(dev, "Partner capability:"); - for (i = 5; i < 10; i++) - if (partner & (1 << i)) - pr_cont(" %s", media[i-5]); - pr_cont("\n"); - } - - tlan_dio_write8(dev->base_addr, TLAN_LED_REG, - TLAN_LED_LINK); -#ifdef MONITOR - /* We have link beat..for now anyway */ - priv->link = 1; - /*Enabling link beat monitoring */ - tlan_set_timer(dev, (10*HZ), TLAN_TIMER_LINK_BEAT); -#endif - } else if (status & MII_GS_LINK) { - netdev_info(dev, "Link active\n"); - tlan_dio_write8(dev->base_addr, TLAN_LED_REG, - TLAN_LED_LINK); + if (status & MII_GS_LINK) { + /* We only support link info on Nat.Sem. PHY's */ + if ((tlphy_id1 == NAT_SEM_ID1) && + (tlphy_id2 == NAT_SEM_ID2)) { + tlan_mii_read_reg(dev, phy, MII_AN_LPA, + &partner); + tlan_mii_read_reg(dev, phy, TLAN_TLPHY_PAR, + &tlphy_par); + + netdev_info(dev, + "Link active, %s %uMbps %s-Duplex\n", + !(tlphy_par & TLAN_PHY_AN_EN_STAT) + ? "forced" : "Autonegotiation enabled,", + tlphy_par & TLAN_PHY_SPEED_100 + ? 100 : 10, + tlphy_par & TLAN_PHY_DUPLEX_FULL + ? "Full" : "Half"); + + if (tlphy_par & TLAN_PHY_AN_EN_STAT) { + netdev_info(dev, "Partner capability:"); + for (i = 5; i < 10; i++) + if (partner & (1 << i)) + pr_cont(" %s", + media[i-5]); + pr_cont("\n"); + } + } else + netdev_info(dev, "Link active\n"); + /* Enabling link beat monitoring */ + priv->media_timer.function = tlan_phy_monitor; + priv->media_timer.data = (unsigned long) dev; + priv->media_timer.expires = jiffies + HZ; + add_timer(&priv->media_timer); } } @@ -2314,6 +2300,7 @@ tlan_finish_reset(struct net_device *dev) dev->base_addr + TLAN_HOST_CMD + 1); outl(priv->rx_list_dma, dev->base_addr + TLAN_CH_PARM); outl(TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD); + tlan_dio_write8(dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK); netif_carrier_on(dev); } else { netdev_info(dev, "Link inactive, will retry in 10 secs...\n"); @@ -2719,7 +2706,6 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev) } -#ifdef MONITOR /********************************************************************* * @@ -2729,18 +2715,18 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev) * None * * Params: - * dev The device structure of this device. + * data The device structure of this device. * * * This function monitors PHY condition by reading the status - * register via the MII bus. This can be used to give info - * about link changes (up/down), and possible switch to alternate - * media. + * register via the MII bus, controls LINK LED and notifies the + * kernel about link state. * *******************************************************************/ -void tlan_phy_monitor(struct net_device *dev) +static void tlan_phy_monitor(unsigned long data) { + struct net_device *dev = (struct net_device *) data; struct tlan_priv *priv = netdev_priv(dev); u16 phy; u16 phy_status; @@ -2752,30 +2738,25 @@ void tlan_phy_monitor(struct net_device *dev) /* Check if link has been lost */ if (!(phy_status & MII_GS_LINK)) { - if (priv->link) { - priv->link = 0; + if (netif_carrier_ok(dev)) { printk(KERN_DEBUG "TLAN: %s has lost link\n", dev->name); + tlan_dio_write8(dev->base_addr, TLAN_LED_REG, 0); netif_carrier_off(dev); - tlan_set_timer(dev, (2*HZ), TLAN_TIMER_LINK_BEAT); - return; } } /* Link restablished? */ - if ((phy_status & MII_GS_LINK) && !priv->link) { - priv->link = 1; + if ((phy_status & MII_GS_LINK) && !netif_carrier_ok(dev)) { + tlan_dio_write8(dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK); printk(KERN_DEBUG "TLAN: %s has reestablished link\n", dev->name); netif_carrier_on(dev); } - - /* Setup a new monitor */ - tlan_set_timer(dev, (2*HZ), TLAN_TIMER_LINK_BEAT); + priv->media_timer.expires = jiffies + HZ; + add_timer(&priv->media_timer); } -#endif /* MONITOR */ - /***************************************************************************** ****************************************************************************** diff --git a/drivers/net/ethernet/ti/tlan.h b/drivers/net/ethernet/ti/tlan.h index 2eb33a250788..4ced9053d9f4 100644 --- a/drivers/net/ethernet/ti/tlan.h +++ b/drivers/net/ethernet/ti/tlan.h @@ -195,6 +195,7 @@ struct tlan_priv { u32 timer_set_at; u32 timer_type; struct timer_list timer; + struct timer_list media_timer; struct board *adapter; u32 adapter_rev; u32 aui; @@ -206,7 +207,6 @@ struct tlan_priv { u8 tlan_rev; u8 tlan_full_duplex; spinlock_t lock; - u8 link; struct work_struct tlan_tqueue; u8 neg_be_verbose; }; @@ -219,7 +219,6 @@ struct tlan_priv { * ****************************************************************/ -#define TLAN_TIMER_LINK_BEAT 1 #define TLAN_TIMER_ACTIVITY 2 #define TLAN_TIMER_PHY_PDOWN 3 #define TLAN_TIMER_PHY_PUP 4 -- cgit v1.2.3 From e36124d464d5ba74a171385ac1ba93acf4343de4 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 30 Jun 2014 18:38:29 +0200 Subject: tlan: Add ethtool support Add basic ethtool support to tlan driver: - driver info - link detect (this allows NetworkManager to detect carrier) - EEPROM read Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/net/ethernet/ti/tlan.h | 1 + 2 files changed, 38 insertions(+) diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index ccde7482d404..00ec926084ea 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -778,7 +778,43 @@ static const struct net_device_ops tlan_netdev_ops = { #endif }; +static void tlan_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct tlan_priv *priv = netdev_priv(dev); + + strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); + if (priv->pci_dev) + strlcpy(info->bus_info, pci_name(priv->pci_dev), + sizeof(info->bus_info)); + else + strlcpy(info->bus_info, "EISA", sizeof(info->bus_info)); + info->eedump_len = TLAN_EEPROM_SIZE; +} + +static int tlan_get_eeprom_len(struct net_device *dev) +{ + return TLAN_EEPROM_SIZE; +} +static int tlan_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + int i; + + for (i = 0; i < TLAN_EEPROM_SIZE; i++) + if (tlan_ee_read_byte(dev, i, &data[i])) + return -EIO; + + return 0; +} + +static const struct ethtool_ops tlan_ethtool_ops = { + .get_drvinfo = tlan_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_eeprom_len = tlan_get_eeprom_len, + .get_eeprom = tlan_get_eeprom, +}; /*************************************************************** * tlan_init @@ -841,6 +877,7 @@ static int tlan_init(struct net_device *dev) /* Device methods */ dev->netdev_ops = &tlan_netdev_ops; + dev->ethtool_ops = &tlan_ethtool_ops; dev->watchdog_timeo = TX_TIMEOUT; return 0; diff --git a/drivers/net/ethernet/ti/tlan.h b/drivers/net/ethernet/ti/tlan.h index 4ced9053d9f4..b6ceebaa2185 100644 --- a/drivers/net/ethernet/ti/tlan.h +++ b/drivers/net/ethernet/ti/tlan.h @@ -240,6 +240,7 @@ struct tlan_priv { #define TLAN_EEPROM_ACK 0 #define TLAN_EEPROM_STOP 1 +#define TLAN_EEPROM_SIZE 256 -- cgit v1.2.3 From 59be4ad6bb01fa80b6ad2cf15163ccb617f7d603 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 30 Jun 2014 18:38:30 +0200 Subject: tlan: Fix MAC address byte order on OC-2325/OC-2326 Olicom OC-2325 and OC-2326 cards have the MAC address byte-swapped in EEPROM. Byte-swap the MAC address if it's located at offset 0xF8. Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index 00ec926084ea..cacc76da91a2 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -863,7 +863,7 @@ static int tlan_init(struct net_device *dev) priv->rx_list_dma + sizeof(struct tlan_list)*TLAN_NUM_RX_LISTS; err = 0; - for (i = 0; i < 6 ; i++) + for (i = 0; i < ETH_ALEN; i++) err |= tlan_ee_read_byte(dev, (u8) priv->adapter->addr_ofs + i, (u8 *) &dev->dev_addr[i]); @@ -871,7 +871,14 @@ static int tlan_init(struct net_device *dev) pr_err("%s: Error reading MAC from eeprom: %d\n", dev->name, err); } - dev->addr_len = 6; + /* Olicom OC-2325/OC-2326 have the address byte-swapped */ + if (priv->adapter->addr_ofs == 0xf8) { + for (i = 0; i < ETH_ALEN; i += 2) { + char tmp = dev->dev_addr[i]; + dev->dev_addr[i] = dev->dev_addr[i + 1]; + dev->dev_addr[i + 1] = tmp; + } + } netif_carrier_off(dev); -- cgit v1.2.3 From 36bbe2f4b4c81a2857d9c8f0443a86f42911336b Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 30 Jun 2014 18:38:31 +0200 Subject: tlan: Restart autonegotiation on link loss When link is lost on a card which uses internal PHY for 10 Mbit speeds, restart autonegotiation to allow switching between 10 and 100 Mbps speeds. Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index cacc76da91a2..3b8364568a6a 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -2720,6 +2720,7 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev) else if (!(mode & 0x0080) && (mode & 0x0040)) priv->tlan_full_duplex = true; + /* switch to internal PHY for 10 Mbps */ if ((!(mode & 0x0180)) && (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10) && (priv->phy_num != 0)) { @@ -2787,6 +2788,21 @@ static void tlan_phy_monitor(unsigned long data) dev->name); tlan_dio_write8(dev->base_addr, TLAN_LED_REG, 0); netif_carrier_off(dev); + if (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10) { + /* power down internal PHY */ + u16 data = MII_GC_PDOWN | MII_GC_LOOPBK | + MII_GC_ISOLATE; + + tlan_mii_sync(dev->base_addr); + tlan_mii_write_reg(dev, priv->phy[0], + MII_GEN_CTL, data); + /* set to external PHY */ + priv->phy_num = 1; + /* restart autonegotiation */ + tlan_set_timer(dev, 4 * HZ / 10, + TLAN_TIMER_PHY_PDOWN); + return; + } } } -- cgit v1.2.3 From 8e62d670488282eed56bbdd0216691ababb0f6e9 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 30 Jun 2014 18:38:32 +0200 Subject: tlan: Don't scream if no link Remove excess printks when the link is down. Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 9 --------- drivers/net/ethernet/ti/tlan.h | 1 - 2 files changed, 10 deletions(-) diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index 3b8364568a6a..872f94c7f1cf 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -1198,9 +1198,6 @@ static irqreturn_t tlan_handle_interrupt(int irq, void *dev_id) static int tlan_close(struct net_device *dev) { - struct tlan_priv *priv = netdev_priv(dev); - - priv->neg_be_verbose = 0; tlan_stop(dev); free_irq(dev->irq, dev); @@ -2701,12 +2698,6 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev) /* Wait for 8 sec to give the process * more time. Perhaps we should fail after a while. */ - if (!priv->neg_be_verbose++) { - pr_info("Giving autonegotiation more time.\n"); - pr_info("Please check that your adapter has\n"); - pr_info("been properly connected to a HUB or Switch.\n"); - pr_info("Trying to establish link in the background...\n"); - } tlan_set_timer(dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN); return; } diff --git a/drivers/net/ethernet/ti/tlan.h b/drivers/net/ethernet/ti/tlan.h index b6ceebaa2185..e9928411827e 100644 --- a/drivers/net/ethernet/ti/tlan.h +++ b/drivers/net/ethernet/ti/tlan.h @@ -208,7 +208,6 @@ struct tlan_priv { u8 tlan_full_duplex; spinlock_t lock; struct work_struct tlan_tqueue; - u8 neg_be_verbose; }; -- cgit v1.2.3 From 278e48b0c4152e600e2ed8328ba4347bc499d3f9 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 30 Jun 2014 18:38:33 +0200 Subject: tlan: Make autonegotiation faster Reduce the autonegotiation poll interval from 8 seconds to 2. This greatly reduces the time needed to detect link presence, especially on Olicom cards at 10 Mbps (two autonegoatiations required). Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index 872f94c7f1cf..c4021de7ebea 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -2698,7 +2698,7 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev) /* Wait for 8 sec to give the process * more time. Perhaps we should fail after a while. */ - tlan_set_timer(dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN); + tlan_set_timer(dev, 2 * HZ, TLAN_TIMER_PHY_FINISH_AN); return; } -- cgit v1.2.3 From 9cff441ed64a44db7cd15d187030f2f9c1bb6465 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 30 Jun 2014 18:38:34 +0200 Subject: tlan: Add PHY reset timeout Add a timeout to prevent infinite loop waiting for PHY to reset. Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index c4021de7ebea..8278150119d5 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -2568,6 +2568,7 @@ static void tlan_phy_reset(struct net_device *dev) struct tlan_priv *priv = netdev_priv(dev); u16 phy; u16 value; + unsigned long timeout = jiffies + HZ; phy = priv->phy[priv->phy_num]; @@ -2575,9 +2576,13 @@ static void tlan_phy_reset(struct net_device *dev) tlan_mii_sync(dev->base_addr); value = MII_GC_LOOPBK | MII_GC_RESET; tlan_mii_write_reg(dev, phy, MII_GEN_CTL, value); - tlan_mii_read_reg(dev, phy, MII_GEN_CTL, &value); - while (value & MII_GC_RESET) + do { tlan_mii_read_reg(dev, phy, MII_GEN_CTL, &value); + if (time_after(jiffies, timeout)) { + netdev_err(dev, "PHY reset timeout\n"); + return; + } + } while (value & MII_GC_RESET); /* Wait for 500 ms and initialize. * I don't remember why I wait this long. -- cgit v1.2.3 From 7a72eddc8e943a96afc86264e095f5b1d037ed4a Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 30 Jun 2014 18:38:35 +0200 Subject: tlan: Don't disable internal PHY on cards that use it in 10 Mbps mode In tlan_reset_adapter, we disable internal PHY when an external one is used. On cards which use internal PHY in 10 Mbps mode, we enable it later when setting 10 Mbps mode but it does not really work (PHY fails to reset). Leave it enabled instead. Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index 8278150119d5..50ac9e7b927f 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -2237,7 +2237,9 @@ tlan_reset_adapter(struct net_device *dev) } } - if (priv->phy_num == 0) + /* don't power down internal PHY if we're going to use it */ + if (priv->phy_num == 0 || + (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10)) data |= TLAN_NET_CFG_PHY_EN; tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, (u16) data); @@ -2688,7 +2690,6 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev) struct tlan_priv *priv = netdev_priv(dev); u16 an_adv; u16 an_lpa; - u16 data; u16 mode; u16 phy; u16 status; @@ -2721,9 +2722,6 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev) (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10) && (priv->phy_num != 0)) { priv->phy_num = 0; - data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN - | TLAN_NET_CFG_PHY_EN; - tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, data); tlan_set_timer(dev, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN); return; } -- cgit v1.2.3 From e697b16b47d1c6d63859cfd44cecb888c7dde92f Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 30 Jun 2014 18:38:36 +0200 Subject: tlan: Enable device at resume pci_disable_device() is called in _suspend but there's no corresponding pci_enable_device() in _resume. This causes "disabling already-disabled device" warning on 2nd suspend. Add pci_enable_device() call to _resume to fix this problem. Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index 50ac9e7b927f..1f21764fea53 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -365,8 +365,10 @@ static int tlan_suspend(struct pci_dev *pdev, pm_message_t state) static int tlan_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); + int rc = pci_enable_device(pdev); - pci_set_power_state(pdev, PCI_D0); + if (rc) + return rc; pci_restore_state(pdev); pci_enable_wake(pdev, PCI_D0, 0); netif_device_attach(dev); -- cgit v1.2.3 From 9162e7e5197e14c7488c54980d7cbdc2071f8085 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 30 Jun 2014 18:38:37 +0200 Subject: tlan: Isolate external PHY when using internal PHY When using internal 10 Mbps PHY, isolate the external PHY from MII bus. External PHY must be kept powered up because it passes TX from tlan chip to network. This fixes weird link-loss problems under load with OC-2326 card at 10 Mbps. Signed-off-by: Ondrej Zary Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/tlan.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index 1f21764fea53..6078342fe3f2 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -2528,9 +2528,10 @@ static void tlan_phy_power_down(struct net_device *dev) value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE; tlan_mii_sync(dev->base_addr); tlan_mii_write_reg(dev, priv->phy[priv->phy_num], MII_GEN_CTL, value); - if ((priv->phy_num == 0) && - (priv->phy[1] != TLAN_PHY_NONE) && - (!(priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10))) { + if ((priv->phy_num == 0) && (priv->phy[1] != TLAN_PHY_NONE)) { + /* if using internal PHY, the external PHY must be powered on */ + if (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10) + value = MII_GC_ISOLATE; /* just isolate it from MII */ tlan_mii_sync(dev->base_addr); tlan_mii_write_reg(dev, priv->phy[1], MII_GEN_CTL, value); } -- cgit v1.2.3 From 86c6a2c75ab97fe31844985169e26aea335432f9 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Mon, 30 Jun 2014 15:09:49 -0400 Subject: tcp: switch snt_synack back to measuring transmit time of first SYNACK Always store in snt_synack the time at which the server received the first client SYN and attempted to send the first SYNACK. Recent commit aa27fc501 ("tcp: tcp_v[46]_conn_request: fix snt_synack initialization") resolved an inconsistency between IPv4 and IPv6 in the initialization of snt_synack. This commit brings back the idea from 843f4a55e (tcp: use tcp_v4_send_synack on first SYN-ACK), which was going for the original behavior of snt_synack from the commit where it was added in 9ad7c049f0f79 ("tcp: RFC2988bis + taking RTT sample from 3WHS for the passive open side") in v3.1. In addition to being simpler (and probably a tiny bit faster), unconditionally storing the time of the first SYNACK attempt has been useful because it allows calculating a performance metric quantifying how long it took to establish a passive TCP connection. Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Cc: Octavian Purdila Cc: Jerry Chu Acked-by: Octavian Purdila Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- net/ipv4/tcp_ipv4.c | 2 -- net/ipv6/tcp_ipv6.c | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 0d5389aecf18..c9a75dbba0c7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1093,7 +1093,7 @@ static inline void tcp_openreq_init(struct request_sock *req, req->cookie_ts = 0; tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq; tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; - tcp_rsk(req)->snt_synack = 0; + tcp_rsk(req)->snt_synack = tcp_time_stamp; req->mss = rx_opt->mss_clamp; req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0; ireq->tstamp_ok = rx_opt->tstamp_ok; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 5dfebd2f2e38..52d0f6a1ec2c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -838,8 +838,6 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, ireq->ir_rmt_addr, ireq->opt); err = net_xmit_eval(err); - if (!tcp_rsk(req)->snt_synack && !err) - tcp_rsk(req)->snt_synack = tcp_time_stamp; } return err; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index bc24ee21339a..a97c95585da8 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -498,8 +498,6 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, skb_set_queue_mapping(skb, queue_mapping); err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass); err = net_xmit_eval(err); - if (!tcp_rsk(req)->snt_synack && !err) - tcp_rsk(req)->snt_synack = tcp_time_stamp; } done: -- cgit v1.2.3 From 7ae934bebe289362e5b1f5ea50e4c347863ae202 Mon Sep 17 00:00:00 2001 From: Erik Hugne Date: Tue, 1 Jul 2014 10:22:40 +0200 Subject: tipc: refactor message delivery out of tipc_rcv This is a cosmetic change, separating message delivery from the link state processing. Signed-off-by: Erik Hugne Reviewed-by: Ying Xue Reviewed-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 124 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 44 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index a081e7d08d22..18b1524098c6 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -88,6 +88,8 @@ static void link_print(struct tipc_link *l_ptr, const char *str); static int tipc_link_frag_xmit(struct tipc_link *l_ptr, struct sk_buff *buf); static void tipc_link_sync_xmit(struct tipc_link *l); static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf); +static int tipc_link_input(struct tipc_link *l, struct sk_buff *buf); +static int tipc_link_prepare_input(struct tipc_link *l, struct sk_buff **buf); /* * Simple link routines @@ -1458,54 +1460,14 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) if (unlikely(l_ptr->oldest_deferred_in)) head = link_insert_deferred_queue(l_ptr, head); - /* Deliver packet/message to correct user: */ - if (unlikely(msg_user(msg) == CHANGEOVER_PROTOCOL)) { - if (!tipc_link_tunnel_rcv(n_ptr, &buf)) { - tipc_node_unlock(n_ptr); - continue; - } - msg = buf_msg(buf); - } else if (msg_user(msg) == MSG_FRAGMENTER) { - l_ptr->stats.recv_fragments++; - if (tipc_buf_append(&l_ptr->reasm_buf, &buf)) { - l_ptr->stats.recv_fragmented++; - msg = buf_msg(buf); - } else { - if (!l_ptr->reasm_buf) - tipc_link_reset(l_ptr); - tipc_node_unlock(n_ptr); - continue; - } - } - - switch (msg_user(msg)) { - case TIPC_LOW_IMPORTANCE: - case TIPC_MEDIUM_IMPORTANCE: - case TIPC_HIGH_IMPORTANCE: - case TIPC_CRITICAL_IMPORTANCE: - case CONN_MANAGER: - tipc_node_unlock(n_ptr); - tipc_sk_rcv(buf); - continue; - case MSG_BUNDLER: - l_ptr->stats.recv_bundles++; - l_ptr->stats.recv_bundled += msg_msgcnt(msg); + if (tipc_link_prepare_input(l_ptr, &buf)) { tipc_node_unlock(n_ptr); - tipc_link_bundle_rcv(buf); continue; - case NAME_DISTRIBUTOR: - n_ptr->bclink.recv_permitted = true; - tipc_node_unlock(n_ptr); - tipc_named_rcv(buf); - continue; - case BCAST_PROTOCOL: - tipc_link_sync_rcv(n_ptr, buf); - break; - default: - kfree_skb(buf); - break; } tipc_node_unlock(n_ptr); + msg = buf_msg(buf); + if (tipc_link_input(l_ptr, buf) != 0) + goto discard; continue; unlock_discard: tipc_node_unlock(n_ptr); @@ -1514,6 +1476,80 @@ discard: } } +/** + * tipc_link_prepare_input - process TIPC link messages + * + * returns nonzero if the message was consumed + * + * Node lock must be held + */ +static int tipc_link_prepare_input(struct tipc_link *l, struct sk_buff **buf) +{ + struct tipc_node *n; + struct tipc_msg *msg; + int res = -EINVAL; + + n = l->owner; + msg = buf_msg(*buf); + switch (msg_user(msg)) { + case CHANGEOVER_PROTOCOL: + if (tipc_link_tunnel_rcv(n, buf)) + res = 0; + break; + case MSG_FRAGMENTER: + l->stats.recv_fragments++; + if (tipc_buf_append(&l->reasm_buf, buf)) { + l->stats.recv_fragmented++; + res = 0; + } else if (!l->reasm_buf) { + tipc_link_reset(l); + } + break; + case MSG_BUNDLER: + l->stats.recv_bundles++; + l->stats.recv_bundled += msg_msgcnt(msg); + res = 0; + break; + case NAME_DISTRIBUTOR: + n->bclink.recv_permitted = true; + res = 0; + break; + case BCAST_PROTOCOL: + tipc_link_sync_rcv(n, *buf); + break; + default: + res = 0; + } + return res; +} +/** + * tipc_link_input - Deliver message too higher layers + */ +static int tipc_link_input(struct tipc_link *l, struct sk_buff *buf) +{ + struct tipc_msg *msg = buf_msg(buf); + int res = 0; + + switch (msg_user(msg)) { + case TIPC_LOW_IMPORTANCE: + case TIPC_MEDIUM_IMPORTANCE: + case TIPC_HIGH_IMPORTANCE: + case TIPC_CRITICAL_IMPORTANCE: + case CONN_MANAGER: + tipc_sk_rcv(buf); + break; + case NAME_DISTRIBUTOR: + tipc_named_rcv(buf); + break; + case MSG_BUNDLER: + tipc_link_bundle_rcv(buf); + break; + default: + res = -EINVAL; + } + return res; +} + /** * tipc_link_defer_pkt - Add out-of-sequence message to deferred reception queue * -- cgit v1.2.3 From 3f53bd8f8b563cc6024d25c1665d8358745f48b2 Mon Sep 17 00:00:00 2001 From: Erik Hugne Date: Tue, 1 Jul 2014 10:22:41 +0200 Subject: tipc: fix link acknowledge logic in receive path Link state acks triggered from the receive path is done before the last received packet have been processed by the link layer. The effect of this is that the last received packet will not be included in the ack. This causes problems if the link window is set to TIPC_MIN_LINK_WIN, where the ack interval will be equal to the link tolerance, and the link enters a stop-and-go behavior. We move the ack logic to after link state processing, just before the packet is delivered to higher layers. Signed-off-by: Erik Hugne Signed-off-by: Carl Sigurjonsson Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/link.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 18b1524098c6..a235b245f682 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1422,11 +1422,6 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) if (unlikely(!list_empty(&l_ptr->waiting_ports))) tipc_link_wakeup_ports(l_ptr, 0); - if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) { - l_ptr->stats.sent_acks++; - tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); - } - /* Process the incoming packet */ if (unlikely(!link_working_working(l_ptr))) { if (msg_user(msg) == LINK_PROTOCOL) { @@ -1460,6 +1455,11 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) if (unlikely(l_ptr->oldest_deferred_in)) head = link_insert_deferred_queue(l_ptr, head); + if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) { + l_ptr->stats.sent_acks++; + tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); + } + if (tipc_link_prepare_input(l_ptr, &buf)) { tipc_node_unlock(n_ptr); continue; -- cgit v1.2.3 From 46c9521fc245d91ff5b14cf246f28cee3f99a670 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Tue, 1 Jul 2014 21:17:35 +0300 Subject: netlink: Fix do_one_broadcast() prototype. This patch changes the prototype of the do_one_broadcast() method so that it will return void. Signed-off-by: Rami Rosen Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 15c731f03fa6..e8c9f9704216 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1961,25 +1961,25 @@ struct netlink_broadcast_data { void *tx_data; }; -static int do_one_broadcast(struct sock *sk, - struct netlink_broadcast_data *p) +static void do_one_broadcast(struct sock *sk, + struct netlink_broadcast_data *p) { struct netlink_sock *nlk = nlk_sk(sk); int val; if (p->exclude_sk == sk) - goto out; + return; if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups || !test_bit(p->group - 1, nlk->groups)) - goto out; + return; if (!net_eq(sock_net(sk), p->net)) - goto out; + return; if (p->failure) { netlink_overrun(sk); - goto out; + return; } sock_hold(sk); @@ -2017,9 +2017,6 @@ static int do_one_broadcast(struct sock *sk, p->skb2 = NULL; } sock_put(sk); - -out: - return 0; } int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 portid, -- cgit v1.2.3 From 4710d806fcb825156e0a7b3a81104915c5e90f5d Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 2 Jul 2014 09:01:09 +0530 Subject: 6lowpan: mac802154: fix coding style issues This patch fixed the coding style issues reported by checkpatch.pl following issues fixed: CHECK: Alignment should match open parenthesis WARNING: line over 80 characters CHECK: Blank lines aren't necessary before a close brace '}' WARNING: networking block comments don't use an empty /* line, use /* Comment... WARNING: Missing a blank line after declarations WARNING: networking block comments start with * on subsequent lines CHECK: braces {} should be used on all arms of this statement Signed-off-by: Varka Bhadram Tested-by: Alexander Aring Signed-off-by: David S. Miller --- net/ieee802154/6lowpan_iphc.c | 113 +++++++++++++++++++---------------------- net/ieee802154/6lowpan_rtnl.c | 16 +++--- net/ieee802154/af_ieee802154.c | 26 +++++----- net/ieee802154/dgram.c | 28 +++++----- net/ieee802154/ieee802154.h | 2 +- net/ieee802154/netlink.c | 4 +- net/ieee802154/nl-mac.c | 48 +++++++++-------- net/ieee802154/nl-phy.c | 23 ++++----- net/ieee802154/raw.c | 14 +++-- net/ieee802154/reassembly.c | 1 + net/ieee802154/wpan-class.c | 10 ++-- net/mac802154/ieee802154_dev.c | 4 +- net/mac802154/llsec.c | 1 + net/mac802154/mib.c | 7 +-- net/mac802154/tx.c | 1 + 15 files changed, 153 insertions(+), 145 deletions(-) diff --git a/net/ieee802154/6lowpan_iphc.c b/net/ieee802154/6lowpan_iphc.c index 211b5686d719..511ddeee7353 100644 --- a/net/ieee802154/6lowpan_iphc.c +++ b/net/ieee802154/6lowpan_iphc.c @@ -3,8 +3,7 @@ * written by Alexander Smirnov */ -/* - * Based on patches from Jon Smirl +/* Based on patches from Jon Smirl * Copyright (c) 2011 Jon Smirl * * This program is free software; you can redistribute it and/or modify @@ -58,16 +57,15 @@ #include #include -/* - * Uncompress address function for source and +/* Uncompress address function for source and * destination address(non-multicast). * * address_mode is sam value or dam value. */ static int uncompress_addr(struct sk_buff *skb, - struct in6_addr *ipaddr, const u8 address_mode, - const u8 *lladdr, const u8 addr_type, - const u8 addr_len) + struct in6_addr *ipaddr, const u8 address_mode, + const u8 *lladdr, const u8 addr_type, + const u8 addr_len) { bool fail; @@ -140,13 +138,12 @@ static int uncompress_addr(struct sk_buff *skb, return 0; } -/* - * Uncompress address function for source context +/* Uncompress address function for source context * based address(non-multicast). */ static int uncompress_context_based_src_addr(struct sk_buff *skb, - struct in6_addr *ipaddr, - const u8 sam) + struct in6_addr *ipaddr, + const u8 sam) { switch (sam) { case LOWPAN_IPHC_ADDR_00: @@ -175,13 +172,13 @@ static int uncompress_context_based_src_addr(struct sk_buff *skb, } static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, - struct net_device *dev, skb_delivery_cb deliver_skb) + struct net_device *dev, skb_delivery_cb deliver_skb) { struct sk_buff *new; int stat; - new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), - GFP_ATOMIC); + new = skb_copy_expand(skb, sizeof(struct ipv6hdr), + skb_tailroom(skb), GFP_ATOMIC); kfree_skb(skb); if (!new) @@ -196,7 +193,7 @@ static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, new->dev = dev; raw_dump_table(__func__, "raw skb data dump before receiving", - new->data, new->len); + new->data, new->len); stat = deliver_skb(new, dev); @@ -210,8 +207,8 @@ static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, */ static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb, - struct in6_addr *ipaddr, - const u8 dam) + struct in6_addr *ipaddr, + const u8 dam) { bool fail; @@ -314,8 +311,7 @@ uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) fail |= lowpan_fetch_skb(skb, &uh->check, 2); } - /* - * UDP lenght needs to be infered from the lower layers + /* UDP lenght needs to be infered from the lower layers * here, we obtain the hint from the remaining size of the * frame */ @@ -338,16 +334,17 @@ err: static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, - const u8 *saddr, const u8 saddr_type, const u8 saddr_len, - const u8 *daddr, const u8 daddr_type, const u8 daddr_len, - u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) + const u8 *saddr, const u8 saddr_type, + const u8 saddr_len, const u8 *daddr, + const u8 daddr_type, const u8 daddr_len, + u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) { struct ipv6hdr hdr = {}; u8 tmp, num_context = 0; int err; raw_dump_table(__func__, "raw skb data dump uncompressed", - skb->data, skb->len); + skb->data, skb->len); /* another if the CID flag is set */ if (iphc1 & LOWPAN_IPHC_CID) { @@ -360,8 +357,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, /* Traffic Class and Flow Label */ switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) { - /* - * Traffic Class and FLow Label carried in-line + /* Traffic Class and FLow Label carried in-line * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) */ case 0: /* 00b */ @@ -374,8 +370,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | (hdr.flow_lbl[0] & 0x0f); break; - /* - * Traffic class carried in-line + /* Traffic class carried in-line * ECN + DSCP (1 byte), Flow Label is elided */ case 2: /* 10b */ @@ -385,8 +380,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, hdr.priority = ((tmp >> 2) & 0x0f); hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); break; - /* - * Flow Label carried in-line + /* Flow Label carried in-line * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided */ case 1: /* 01b */ @@ -415,9 +409,9 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, } /* Hop Limit */ - if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) + if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) { hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; - else { + } else { if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit))) goto drop; } @@ -429,12 +423,12 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, /* Source address context based uncompression */ pr_debug("SAC bit is set. Handle context based source address.\n"); err = uncompress_context_based_src_addr( - skb, &hdr.saddr, tmp); + skb, &hdr.saddr, tmp); } else { /* Source address uncompression */ pr_debug("source address stateless compression\n"); err = uncompress_addr(skb, &hdr.saddr, tmp, saddr, - saddr_type, saddr_len); + saddr_type, saddr_len); } /* Check on error of previous branch */ @@ -457,9 +451,9 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, } } else { err = uncompress_addr(skb, &hdr.daddr, tmp, daddr, - daddr_type, daddr_len); + daddr_type, daddr_len); pr_debug("dest: stateless compression mode %d dest %pI6c\n", - tmp, &hdr.daddr); + tmp, &hdr.daddr); if (err) goto drop; } @@ -468,11 +462,11 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, if (iphc0 & LOWPAN_IPHC_NH_C) { struct udphdr uh; struct sk_buff *new; + if (uncompress_udp_header(skb, &uh)) goto drop; - /* - * replace the compressed UDP head by the uncompressed UDP + /* replace the compressed UDP head by the uncompressed UDP * header */ new = skb_copy_expand(skb, sizeof(struct udphdr), @@ -489,7 +483,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); raw_dump_table(__func__, "raw UDP header dump", - (u8 *)&uh, sizeof(uh)); + (u8 *)&uh, sizeof(uh)); hdr.nexthdr = UIP_PROTO_UDP; } @@ -504,8 +498,8 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, hdr.hop_limit, &hdr.daddr); - raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, - sizeof(hdr)); + raw_dump_table(__func__, "raw header dump", + (u8 *)&hdr, sizeof(hdr)); return skb_deliver(skb, &hdr, dev, deliver_skb); @@ -516,8 +510,8 @@ drop: EXPORT_SYMBOL_GPL(lowpan_process_data); static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, - const struct in6_addr *ipaddr, - const unsigned char *lladdr) + const struct in6_addr *ipaddr, + const unsigned char *lladdr) { u8 val = 0; @@ -530,14 +524,14 @@ static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, *hc06_ptr += 2; val = 2; /* 16-bits */ raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", - *hc06_ptr - 2, 2); + *hc06_ptr - 2, 2); } else { /* do not compress IID => xxxx::IID */ memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8); *hc06_ptr += 8; val = 1; /* 64-bits */ raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", - *hc06_ptr - 8, 8); + *hc06_ptr - 8, 8); } return rol8(val, shift); @@ -601,8 +595,8 @@ static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) } int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *_daddr, - const void *_saddr, unsigned int len) + unsigned short type, const void *_daddr, + const void *_saddr, unsigned int len) { u8 tmp, iphc0, iphc1, *hc06_ptr; struct ipv6hdr *hdr; @@ -616,14 +610,13 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", - hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, - hdr->hop_limit, &hdr->daddr); + hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, + hdr->hop_limit, &hdr->daddr); raw_dump_table(__func__, "raw skb network header dump", - skb_network_header(skb), sizeof(struct ipv6hdr)); + skb_network_header(skb), sizeof(struct ipv6hdr)); - /* - * As we copy some bit-length fields, in the IPHC encoding bytes, + /* As we copy some bit-length fields, in the IPHC encoding bytes, * we sometimes use |= * If the field is 0, and the current bit value in memory is 1, * this does not work. We therefore reset the IPHC encoding here @@ -639,11 +632,10 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, (unsigned char *)_daddr, IEEE802154_ADDR_LEN); raw_dump_table(__func__, - "sending raw skb network uncompressed packet", - skb->data, skb->len); + "sending raw skb network uncompressed packet", + skb->data, skb->len); - /* - * Traffic class, flow label + /* Traffic class, flow label * If flow label is 0, compress it. If traffic class is 0, compress it * We have to process both in the same time as the offset of traffic * class depends on the presence of version and flow label @@ -654,11 +646,11 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, tmp = ((tmp & 0x03) << 6) | (tmp >> 2); if (((hdr->flow_lbl[0] & 0x0F) == 0) && - (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { + (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { /* flow label can be compressed */ iphc0 |= LOWPAN_IPHC_FL_C; if ((hdr->priority == 0) && - ((hdr->flow_lbl[0] & 0xF0) == 0)) { + ((hdr->flow_lbl[0] & 0xF0) == 0)) { /* compress (elide) all */ iphc0 |= LOWPAN_IPHC_TC_C; } else { @@ -669,7 +661,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, } else { /* Flow label cannot be compressed */ if ((hdr->priority == 0) && - ((hdr->flow_lbl[0] & 0xF0) == 0)) { + ((hdr->flow_lbl[0] & 0xF0) == 0)) { /* compress only traffic class */ iphc0 |= LOWPAN_IPHC_TC_C; *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); @@ -695,8 +687,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, hc06_ptr += 1; } - /* - * Hop limit + /* Hop limit * if 1: compress, encoding is 01 * if 64: compress, encoding is 10 * if 255: compress, encoding is 11 @@ -793,7 +784,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len); raw_dump_table(__func__, "raw skb data dump compressed", - skb->data, skb->len); + skb->data, skb->len); return 0; } EXPORT_SYMBOL_GPL(lowpan_header_compress); diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index fe6bd7a71081..016b77ee88f0 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -80,14 +80,14 @@ lowpan_dev_info *lowpan_dev_info(const struct net_device *dev) static inline void lowpan_address_flip(u8 *src, u8 *dest) { int i; + for (i = 0; i < IEEE802154_ADDR_LEN; i++) (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i]; } -static int lowpan_header_create(struct sk_buff *skb, - struct net_device *dev, - unsigned short type, const void *_daddr, - const void *_saddr, unsigned int len) +static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *_daddr, + const void *_saddr, unsigned int len) { const u8 *saddr = _saddr; const u8 *daddr = _daddr; @@ -144,7 +144,7 @@ static int lowpan_header_create(struct sk_buff *skb, } static int lowpan_give_skb_to_devices(struct sk_buff *skb, - struct net_device *dev) + struct net_device *dev) { struct lowpan_dev_record *entry; struct sk_buff *skb_cp; @@ -368,24 +368,28 @@ static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev) static struct wpan_phy *lowpan_get_phy(const struct net_device *dev) { struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; + return ieee802154_mlme_ops(real_dev)->get_phy(real_dev); } static __le16 lowpan_get_pan_id(const struct net_device *dev) { struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; + return ieee802154_mlme_ops(real_dev)->get_pan_id(real_dev); } static __le16 lowpan_get_short_addr(const struct net_device *dev) { struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; + return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev); } static u8 lowpan_get_dsn(const struct net_device *dev) { struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; + return ieee802154_mlme_ops(real_dev)->get_dsn(real_dev); } @@ -454,7 +458,7 @@ static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[]) } static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev) + struct packet_type *pt, struct net_device *orig_dev) { struct ieee802154_hdr hdr; int ret; diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index 351d9a94ec2f..29e0de63001b 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c @@ -40,9 +40,7 @@ #include "af802154.h" -/* - * Utility function for families - */ +/* Utility function for families */ struct net_device* ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr) { @@ -87,8 +85,8 @@ ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr) rtnl_unlock(); break; default: - pr_warning("Unsupported ieee802154 address type: %d\n", - addr->mode); + pr_warn("Unsupported ieee802154 address type: %d\n", + addr->mode); break; } @@ -106,7 +104,7 @@ static int ieee802154_sock_release(struct socket *sock) return 0; } static int ieee802154_sock_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t len) + struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; @@ -114,7 +112,7 @@ static int ieee802154_sock_sendmsg(struct kiocb *iocb, struct socket *sock, } static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr, - int addr_len) + int addr_len) { struct sock *sk = sock->sk; @@ -125,7 +123,7 @@ static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr, } static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags) + int addr_len, int flags) { struct sock *sk = sock->sk; @@ -139,7 +137,7 @@ static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr, } static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg, - unsigned int cmd) + unsigned int cmd) { struct ifreq ifr; int ret = -ENOIOCTLCMD; @@ -167,7 +165,7 @@ static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg, } static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd, - unsigned long arg) + unsigned long arg) { struct sock *sk = sock->sk; @@ -238,8 +236,7 @@ static const struct proto_ops ieee802154_dgram_ops = { }; -/* - * Create a socket. Initialise the socket, blank the addresses +/* Create a socket. Initialise the socket, blank the addresses * set the state. */ static int ieee802154_create(struct net *net, struct socket *sock, @@ -301,13 +298,14 @@ static const struct net_proto_family ieee802154_family_ops = { }; static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev) + struct packet_type *pt, struct net_device *orig_dev) { if (!netif_running(dev)) goto drop; pr_debug("got frame, type %d, dev %p\n", dev->type, dev); #ifdef DEBUG - print_hex_dump_bytes("ieee802154_rcv ", DUMP_PREFIX_NONE, skb->data, skb->len); + print_hex_dump_bytes("ieee802154_rcv ", + DUMP_PREFIX_NONE, skb->data, skb->len); #endif if (!net_eq(dev_net(dev), &init_net)) diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 4f0ed8780194..ef2ad8aaef13 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -149,8 +149,7 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) spin_lock_bh(&sk->sk_receive_queue.lock); skb = skb_peek(&sk->sk_receive_queue); if (skb != NULL) { - /* - * We will only return the amount + /* We will only return the amount * of this packet since that is all * that will be read. */ @@ -161,12 +160,13 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) } } + return -ENOIOCTLCMD; } /* FIXME: autobind */ static int dgram_connect(struct sock *sk, struct sockaddr *uaddr, - int len) + int len) { struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; struct dgram_sock *ro = dgram_sk(sk); @@ -205,7 +205,7 @@ static int dgram_disconnect(struct sock *sk, int flags) } static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, - struct msghdr *msg, size_t size) + struct msghdr *msg, size_t size) { struct net_device *dev; unsigned int mtu; @@ -248,8 +248,8 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, hlen = LL_RESERVED_SPACE(dev); tlen = dev->needed_tailroom; skb = sock_alloc_send_skb(sk, hlen + tlen + size, - msg->msg_flags & MSG_DONTWAIT, - &err); + msg->msg_flags & MSG_DONTWAIT, + &err); if (!skb) goto out_dev; @@ -262,7 +262,8 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, cb->ackreq = ro->want_ack; if (msg->msg_name) { - DECLARE_SOCKADDR(struct sockaddr_ieee802154*, daddr, msg->msg_name); + DECLARE_SOCKADDR(struct sockaddr_ieee802154*, + daddr, msg->msg_name); ieee802154_addr_from_sa(&dst_addr, &daddr->addr); } else { @@ -304,8 +305,8 @@ out: } static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, - struct msghdr *msg, size_t len, int noblock, int flags, - int *addr_len) + struct msghdr *msg, size_t len, int noblock, + int flags, int *addr_len) { size_t copied = 0; int err = -EOPNOTSUPP; @@ -398,6 +399,7 @@ int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) dgram_sk(sk))) { if (prev) { struct sk_buff *clone; + clone = skb_clone(skb, GFP_ATOMIC); if (clone) dgram_rcv_skb(prev, clone); @@ -407,9 +409,9 @@ int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) } } - if (prev) + if (prev) { dgram_rcv_skb(prev, skb); - else { + } else { kfree_skb(skb); ret = NET_RX_DROP; } @@ -419,7 +421,7 @@ int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) } static int dgram_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) + char __user *optval, int __user *optlen) { struct dgram_sock *ro = dgram_sk(sk); @@ -463,7 +465,7 @@ static int dgram_getsockopt(struct sock *sk, int level, int optname, } static int dgram_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) + char __user *optval, unsigned int optlen) { struct dgram_sock *ro = dgram_sk(sk); struct net *net = sock_net(sk); diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h index 8b83a231299e..5d352f86979e 100644 --- a/net/ieee802154/ieee802154.h +++ b/net/ieee802154/ieee802154.h @@ -43,7 +43,7 @@ struct genl_info; struct sk_buff *ieee802154_nl_create(int flags, u8 req); int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group); struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info, - int flags, u8 req); + int flags, u8 req); int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info); extern struct genl_family nl802154_family; diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 26efcf4fd2ff..9222966f5e6d 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -52,7 +52,7 @@ struct sk_buff *ieee802154_nl_create(int flags, u8 req) spin_lock_irqsave(&ieee802154_seq_lock, f); hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, - &nl802154_family, flags, req); + &nl802154_family, flags, req); spin_unlock_irqrestore(&ieee802154_seq_lock, f); if (!hdr) { nlmsg_free(msg); @@ -86,7 +86,7 @@ struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info, return NULL; hdr = genlmsg_put_reply(msg, info, - &nl802154_family, flags, req); + &nl802154_family, flags, req); if (!hdr) { nlmsg_free(msg); return NULL; diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index a3281b8bfd5b..c6bfe22bfa5e 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -60,7 +60,8 @@ static __le16 nla_get_shortaddr(const struct nlattr *nla) } int ieee802154_nl_assoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, u8 cap) + struct ieee802154_addr *addr, + u8 cap) { struct sk_buff *msg; @@ -93,7 +94,7 @@ nla_put_failure: EXPORT_SYMBOL(ieee802154_nl_assoc_indic); int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr, - u8 status) + u8 status) { struct sk_buff *msg; @@ -119,7 +120,8 @@ nla_put_failure: EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); int ieee802154_nl_disassoc_indic(struct net_device *dev, - struct ieee802154_addr *addr, u8 reason) + struct ieee802154_addr *addr, + u8 reason) { struct sk_buff *msg; @@ -205,8 +207,9 @@ nla_put_failure: EXPORT_SYMBOL(ieee802154_nl_beacon_indic); int ieee802154_nl_scan_confirm(struct net_device *dev, - u8 status, u8 scan_type, u32 unscanned, u8 page, - u8 *edl/* , struct list_head *pan_desc_list */) + u8 status, u8 scan_type, + u32 unscanned, u8 page, + u8 *edl/* , struct list_head *pan_desc_list */) { struct sk_buff *msg; @@ -260,7 +263,7 @@ nla_put_failure: EXPORT_SYMBOL(ieee802154_nl_start_confirm); static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, - u32 seq, int flags, struct net_device *dev) + u32 seq, int flags, struct net_device *dev) { void *hdr; struct wpan_phy *phy; @@ -270,7 +273,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, pr_debug("%s\n", __func__); hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags, - IEEE802154_LIST_IFACE); + IEEE802154_LIST_IFACE); if (!hdr) goto out; @@ -330,14 +333,16 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { char name[IFNAMSIZ + 1]; + nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], - sizeof(name)); + sizeof(name)); dev = dev_get_by_name(&init_net, name); - } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) + } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) { dev = dev_get_by_index(&init_net, nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); - else + } else { return NULL; + } if (!dev) return NULL; @@ -435,7 +440,7 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info) int ret = -EOPNOTSUPP; if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && - !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || + !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || !info->attrs[IEEE802154_ATTR_REASON]) return -EINVAL; @@ -464,8 +469,7 @@ out: return ret; } -/* - * PANid, channel, beacon_order = 15, superframe_order = 15, +/* PANid, channel, beacon_order = 15, superframe_order = 15, * PAN_coordinator, battery_life_extension = 0, * coord_realignment = 0, security_enable = 0 */ @@ -559,8 +563,8 @@ int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) page = 0; - ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page, - duration); + ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, + page, duration); out: dev_put(dev); @@ -570,7 +574,8 @@ out: int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info) { /* Request for interface name, index, type, IEEE address, - PAN Id, short address */ + * PAN Id, short address + */ struct sk_buff *msg; struct net_device *dev = NULL; int rc = -ENOBUFS; @@ -586,7 +591,7 @@ int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info) goto out_dev; rc = ieee802154_nl_fill_iface(msg, info->snd_portid, info->snd_seq, - 0, dev); + 0, dev); if (rc < 0) goto out_free; @@ -598,7 +603,6 @@ out_free: out_dev: dev_put(dev); return rc; - } int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb) @@ -616,7 +620,8 @@ int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb) goto cont; if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0) + cb->nlh->nlmsg_seq, + NLM_F_MULTI, dev) < 0) break; cont: idx++; @@ -765,6 +770,7 @@ ieee802154_llsec_parse_key_id(struct genl_info *info, case IEEE802154_SCF_KEY_SHORT_INDEX: { u32 source = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT]); + desc->short_source = cpu_to_le32(source); break; } @@ -842,7 +848,7 @@ int ieee802154_llsec_getparams(struct sk_buff *skb, struct genl_info *info) goto out_dev; hdr = genlmsg_put(msg, 0, info->snd_seq, &nl802154_family, 0, - IEEE802154_LLSEC_GETPARAMS); + IEEE802154_LLSEC_GETPARAMS); if (!hdr) goto out_free; @@ -946,7 +952,7 @@ struct llsec_dump_data { static int ieee802154_llsec_dump_table(struct sk_buff *skb, struct netlink_callback *cb, - int (*step)(struct llsec_dump_data*)) + int (*step)(struct llsec_dump_data *)) { struct net *net = sock_net(skb->sk); struct net_device *dev; diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 89b265aea151..972baf83411a 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -36,7 +36,7 @@ #include "ieee802154.h" static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, - u32 seq, int flags, struct wpan_phy *phy) + u32 seq, int flags, struct wpan_phy *phy) { void *hdr; int i, pages = 0; @@ -48,7 +48,7 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, return -EMSGSIZE; hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags, - IEEE802154_LIST_PHY); + IEEE802154_LIST_PHY); if (!hdr) goto out; @@ -80,7 +80,8 @@ out: int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info) { /* Request for interface name, index, type, IEEE address, - PAN Id, short address */ + * PAN Id, short address + */ struct sk_buff *msg; struct wpan_phy *phy; const char *name; @@ -105,7 +106,7 @@ int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info) goto out_dev; rc = ieee802154_nl_fill_phy(msg, info->snd_portid, info->snd_seq, - 0, phy); + 0, phy); if (rc < 0) goto out_free; @@ -117,7 +118,6 @@ out_free: out_dev: wpan_phy_put(phy); return rc; - } struct dump_phy_data { @@ -137,10 +137,10 @@ static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data) return 0; rc = ieee802154_nl_fill_phy(data->skb, - NETLINK_CB(data->cb->skb).portid, - data->cb->nlh->nlmsg_seq, - NLM_F_MULTI, - phy); + NETLINK_CB(data->cb->skb).portid, + data->cb->nlh->nlmsg_seq, + NLM_F_MULTI, + phy); if (rc < 0) { data->idx--; @@ -238,10 +238,9 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) addr.sa_family = ARPHRD_IEEE802154; nla_memcpy(&addr.sa_data, info->attrs[IEEE802154_ATTR_HW_ADDR], - IEEE802154_ADDR_LEN); + IEEE802154_ADDR_LEN); - /* - * strangely enough, some callbacks (inetdev_event) from + /* strangely enough, some callbacks (inetdev_event) from * dev_set_mac_address require RTNL_LOCK */ rtnl_lock(); diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c index 74d54fae33d7..9d1f64806f02 100644 --- a/net/ieee802154/raw.c +++ b/net/ieee802154/raw.c @@ -96,7 +96,7 @@ out: } static int raw_connect(struct sock *sk, struct sockaddr *uaddr, - int addr_len) + int addr_len) { return -ENOTSUPP; } @@ -106,8 +106,8 @@ static int raw_disconnect(struct sock *sk, int flags) return 0; } -static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - size_t size) +static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t size) { struct net_device *dev; unsigned int mtu; @@ -145,7 +145,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, hlen = LL_RESERVED_SPACE(dev); tlen = dev->needed_tailroom; skb = sock_alloc_send_skb(sk, hlen + tlen + size, - msg->msg_flags & MSG_DONTWAIT, &err); + msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) goto out_dev; @@ -235,7 +235,6 @@ void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb) bh_lock_sock(sk); if (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dev->ifindex) { - struct sk_buff *clone; clone = skb_clone(skb, GFP_ATOMIC); @@ -248,13 +247,13 @@ void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb) } static int raw_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) + char __user *optval, int __user *optlen) { return -EOPNOTSUPP; } static int raw_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) + char __user *optval, unsigned int optlen) { return -EOPNOTSUPP; } @@ -274,4 +273,3 @@ struct proto ieee802154_raw_prot = { .getsockopt = raw_getsockopt, .setsockopt = raw_setsockopt, }; - diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index 6f1428c4870b..b85bd3f7048e 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -378,6 +378,7 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type) fq = fq_find(net, frag_info, &source, &dest); if (fq != NULL) { int ret; + spin_lock(&fq->q.lock); ret = lowpan_frag_queue(fq, skb, frag_type); spin_unlock(&fq->q.lock); diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c index 8d6f6704da84..4955e0fe5883 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/wpan-class.c @@ -48,7 +48,8 @@ MASTER_SHOW(transmit_power, "%d +- 1 dB"); MASTER_SHOW(cca_mode, "%d"); static ssize_t channels_supported_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); int ret; @@ -57,7 +58,7 @@ static ssize_t channels_supported_show(struct device *dev, mutex_lock(&phy->pib_lock); for (i = 0; i < 32; i++) { ret = snprintf(buf + len, PAGE_SIZE - len, - "%#09x\n", phy->channels_supported[i]); + "%#09x\n", phy->channels_supported[i]); if (ret < 0) break; len += ret; @@ -80,6 +81,7 @@ ATTRIBUTE_GROUPS(pmib); static void wpan_phy_release(struct device *d) { struct wpan_phy *phy = container_of(d, struct wpan_phy, dev); + kfree(phy); } @@ -121,11 +123,12 @@ static int wpan_phy_iter(struct device *dev, void *_data) { struct wpan_phy_iter_data *wpid = _data; struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); + return wpid->fn(phy, wpid->data); } int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), - void *data) + void *data) { struct wpan_phy_iter_data wpid = { .fn = fn, @@ -197,6 +200,7 @@ EXPORT_SYMBOL(wpan_phy_free); static int __init wpan_phy_class_init(void) { int rc; + rc = class_register(&wpan_phy_class); if (rc) goto err; diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c index 2cf66d885e68..c4d4568611ca 100644 --- a/net/mac802154/ieee802154_dev.c +++ b/net/mac802154/ieee802154_dev.c @@ -143,6 +143,7 @@ static void mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev) { struct mac802154_sub_if_data *sdata; + ASSERT_RTNL(); sdata = netdev_priv(dev); @@ -276,7 +277,8 @@ ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops) } priv = wpan_phy_priv(phy); - priv->hw.phy = priv->phy = phy; + priv->phy = phy; + priv->hw.phy = priv->phy; priv->hw.priv = (char *)priv + ALIGN(sizeof(*priv), NETDEV_ALIGN); priv->ops = ops; diff --git a/net/mac802154/llsec.c b/net/mac802154/llsec.c index 1456f73b02b9..457058142098 100644 --- a/net/mac802154/llsec.c +++ b/net/mac802154/llsec.c @@ -538,6 +538,7 @@ static int llsec_recover_addr(struct mac802154_llsec *sec, struct ieee802154_addr *addr) { __le16 caddr = sec->params.coord_shortaddr; + addr->pan_id = sec->params.pan_id; if (caddr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) { diff --git a/net/mac802154/mib.c b/net/mac802154/mib.c index 15aa2f2b03a7..868a040fd422 100644 --- a/net/mac802154/mib.c +++ b/net/mac802154/mib.c @@ -175,9 +175,9 @@ static void phy_chan_notify(struct work_struct *work) mutex_lock(&priv->hw->phy->pib_lock); res = hw->ops->set_channel(&hw->hw, priv->page, priv->chan); - if (res) + if (res) { pr_debug("set_channel failed\n"); - else { + } else { priv->hw->phy->current_channel = priv->chan; priv->hw->phy->current_page = priv->page; } @@ -210,8 +210,9 @@ void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan) INIT_WORK(&work->work, phy_chan_notify); work->dev = dev; queue_work(priv->hw->dev_workqueue, &work->work); - } else + } else { mutex_unlock(&priv->hw->phy->pib_lock); + } } diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c index 6d1647399d4f..8124353646ae 100644 --- a/net/mac802154/tx.c +++ b/net/mac802154/tx.c @@ -98,6 +98,7 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) { u16 crc = crc_ccitt(0, skb->data, skb->len); u8 *data = skb_put(skb, 2); + data[0] = crc & 0xff; data[1] = crc >> 8; } -- cgit v1.2.3 From 18e21b01fb94d8f6125cf73a477fdb3f88820608 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 1 Jul 2014 21:08:36 -0700 Subject: net: systemport: update umac_enable_set to take a bitmask Quite often we need to enable either the transmitter or the receiver bits in UMAC_CMD, use umac_enable_set() to do that for us. This is a preliminary change to introduce suspend/resume support in the driver. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 141160ef249a..bbe74494c629 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1236,15 +1236,15 @@ static void bcm_sysport_set_rx_mode(struct net_device *dev) } static inline void umac_enable_set(struct bcm_sysport_priv *priv, - unsigned int enable) + u32 mask, unsigned int enable) { u32 reg; reg = umac_readl(priv, UMAC_CMD); if (enable) - reg |= CMD_RX_EN | CMD_TX_EN; + reg |= mask; else - reg &= ~(CMD_RX_EN | CMD_TX_EN); + reg &= ~mask; umac_writel(priv, reg, UMAC_CMD); /* UniMAC stops on a packet boundary, wait for a full-sized packet @@ -1313,7 +1313,7 @@ static int bcm_sysport_open(struct net_device *dev) topctrl_flush(priv); /* Disable the UniMAC RX/TX */ - umac_enable_set(priv, 0); + umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 0); /* Enable RBUF 2bytes alignment and Receive Status Block */ reg = rbuf_readl(priv, RBUF_CONTROL); @@ -1398,7 +1398,7 @@ static int bcm_sysport_open(struct net_device *dev) napi_enable(&priv->napi); /* Turn on UniMAC TX/RX */ - umac_enable_set(priv, 1); + umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 1); phy_start(priv->phydev); @@ -1429,7 +1429,6 @@ static int bcm_sysport_stop(struct net_device *dev) { struct bcm_sysport_priv *priv = netdev_priv(dev); unsigned int i; - u32 reg; int ret; /* stop all software from updating hardware */ @@ -1444,9 +1443,7 @@ static int bcm_sysport_stop(struct net_device *dev) intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); /* Disable UniMAC RX */ - reg = umac_readl(priv, UMAC_CMD); - reg &= ~CMD_RX_EN; - umac_writel(priv, reg, UMAC_CMD); + umac_enable_set(priv, CMD_RX_EN, 0); ret = tdma_enable_set(priv, 0); if (ret) { @@ -1464,9 +1461,7 @@ static int bcm_sysport_stop(struct net_device *dev) } /* Disable UniMAC TX */ - reg = umac_readl(priv, UMAC_CMD); - reg &= ~CMD_TX_EN; - umac_writel(priv, reg, UMAC_CMD); + umac_enable_set(priv, CMD_TX_EN, 0); /* Free RX/TX rings SW structures */ for (i = 0; i < dev->num_tx_queues; i++) -- cgit v1.2.3 From b02e6d9ba7adf95c4d1999755aa35124d262b4f7 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 1 Jul 2014 21:08:37 -0700 Subject: net: systemport: add bcm_sysport_netif_{enable,stop} Factor common code that either enables or disables the network interface with the networking stack. We are going to reuse these functions for suspend/resume callbacks. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 40 ++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index bbe74494c629..8f6ab266b178 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1295,6 +1295,22 @@ static void topctrl_flush(struct bcm_sysport_priv *priv) topctrl_writel(priv, 0, TX_FLUSH_CNTL); } +static void bcm_sysport_netif_start(struct net_device *dev) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + + /* Enable NAPI */ + napi_enable(&priv->napi); + + phy_start(priv->phydev); + + /* Enable TX interrupts for the 32 TXQs */ + intrl2_1_mask_clear(priv, 0xffffffff); + + /* Last call before we start the real business */ + netif_tx_start_all_queues(dev); +} + static int bcm_sysport_open(struct net_device *dev) { struct bcm_sysport_priv *priv = netdev_priv(dev); @@ -1394,19 +1410,10 @@ static int bcm_sysport_open(struct net_device *dev) if (ret) goto out_clear_rx_int; - /* Enable NAPI */ - napi_enable(&priv->napi); - /* Turn on UniMAC TX/RX */ umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 1); - phy_start(priv->phydev); - - /* Enable TX interrupts for the 32 TXQs */ - intrl2_1_mask_clear(priv, 0xffffffff); - - /* Last call before we start the real business */ - netif_tx_start_all_queues(dev); + bcm_sysport_netif_start(dev); return 0; @@ -1425,11 +1432,9 @@ out_phy_disconnect: return ret; } -static int bcm_sysport_stop(struct net_device *dev) +static void bcm_sysport_netif_stop(struct net_device *dev) { struct bcm_sysport_priv *priv = netdev_priv(dev); - unsigned int i; - int ret; /* stop all software from updating hardware */ netif_tx_stop_all_queues(dev); @@ -1441,6 +1446,15 @@ static int bcm_sysport_stop(struct net_device *dev) intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); intrl2_1_mask_set(priv, 0xffffffff); intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); +} + +static int bcm_sysport_stop(struct net_device *dev) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + unsigned int i; + int ret; + + bcm_sysport_netif_stop(dev); /* Disable UniMAC RX */ umac_enable_set(priv, CMD_RX_EN, 0); -- cgit v1.2.3 From 40755a0fce17c39557fd55b634024082671074ed Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 1 Jul 2014 21:08:38 -0700 Subject: net: systemport: add suspend and resume support Implement the hardware recommended suspend/resume procedure for SYSTEMPORT. We leverage the previous factoring work such that we can logically break all suspend/resume operations into disctint RX and TX code paths. When the system enters S3, we will loose all register contents, so make sure that we correctly re-program all the hardware and software views of the RX & TX rings as well. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 164 ++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 8f6ab266b178..9dabcfbfc23a 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1311,11 +1311,19 @@ static void bcm_sysport_netif_start(struct net_device *dev) netif_tx_start_all_queues(dev); } +static void rbuf_init(struct bcm_sysport_priv *priv) +{ + u32 reg; + + reg = rbuf_readl(priv, RBUF_CONTROL); + reg |= RBUF_4B_ALGN | RBUF_RSB_EN; + rbuf_writel(priv, reg, RBUF_CONTROL); +} + static int bcm_sysport_open(struct net_device *dev) { struct bcm_sysport_priv *priv = netdev_priv(dev); unsigned int i; - u32 reg; int ret; /* Reset UniMAC */ @@ -1332,9 +1340,7 @@ static int bcm_sysport_open(struct net_device *dev) umac_enable_set(priv, CMD_RX_EN | CMD_TX_EN, 0); /* Enable RBUF 2bytes alignment and Receive Status Block */ - reg = rbuf_readl(priv, RBUF_CONTROL); - reg |= RBUF_4B_ALGN | RBUF_RSB_EN; - rbuf_writel(priv, reg, RBUF_CONTROL); + rbuf_init(priv); /* Set maximum frame length */ umac_writel(priv, UMAC_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN); @@ -1640,6 +1646,155 @@ static int bcm_sysport_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int bcm_sysport_suspend(struct device *d) +{ + struct net_device *dev = dev_get_drvdata(d); + struct bcm_sysport_priv *priv = netdev_priv(dev); + unsigned int i; + int ret; + u32 reg; + + if (!netif_running(dev)) + return 0; + + bcm_sysport_netif_stop(dev); + + phy_suspend(priv->phydev); + + netif_device_detach(dev); + + /* Disable UniMAC RX */ + umac_enable_set(priv, CMD_RX_EN, 0); + + ret = rdma_enable_set(priv, 0); + if (ret) { + netdev_err(dev, "RDMA timeout!\n"); + return ret; + } + + /* Disable RXCHK if enabled */ + if (priv->rx_csum_en) { + reg = rxchk_readl(priv, RXCHK_CONTROL); + reg &= ~RXCHK_EN; + rxchk_writel(priv, reg, RXCHK_CONTROL); + } + + /* Flush RX pipe */ + topctrl_writel(priv, RX_FLUSH, RX_FLUSH_CNTL); + + ret = tdma_enable_set(priv, 0); + if (ret) { + netdev_err(dev, "TDMA timeout!\n"); + return ret; + } + + /* Wait for a packet boundary */ + usleep_range(2000, 3000); + + umac_enable_set(priv, CMD_TX_EN, 0); + + topctrl_writel(priv, TX_FLUSH, TX_FLUSH_CNTL); + + /* Free RX/TX rings SW structures */ + for (i = 0; i < dev->num_tx_queues; i++) + bcm_sysport_fini_tx_ring(priv, i); + bcm_sysport_fini_rx_ring(priv); + + return 0; +} + +static int bcm_sysport_resume(struct device *d) +{ + struct net_device *dev = dev_get_drvdata(d); + struct bcm_sysport_priv *priv = netdev_priv(dev); + unsigned int i; + u32 reg; + int ret; + + if (!netif_running(dev)) + return 0; + + /* Initialize both hardware and software ring */ + for (i = 0; i < dev->num_tx_queues; i++) { + ret = bcm_sysport_init_tx_ring(priv, i); + if (ret) { + netdev_err(dev, "failed to initialize TX ring %d\n", + i); + goto out_free_tx_rings; + } + } + + /* Initialize linked-list */ + tdma_writel(priv, TDMA_LL_RAM_INIT_BUSY, TDMA_STATUS); + + /* Initialize RX ring */ + ret = bcm_sysport_init_rx_ring(priv); + if (ret) { + netdev_err(dev, "failed to initialize RX ring\n"); + goto out_free_rx_ring; + } + + netif_device_attach(dev); + + /* Enable RX interrupt and TX ring full interrupt */ + intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE | INTRL2_0_TX_RING_FULL); + + /* RX pipe enable */ + topctrl_writel(priv, 0, RX_FLUSH_CNTL); + + ret = rdma_enable_set(priv, 1); + if (ret) { + netdev_err(dev, "failed to enable RDMA\n"); + goto out_free_rx_ring; + } + + /* Enable rxhck */ + if (priv->rx_csum_en) { + reg = rxchk_readl(priv, RXCHK_CONTROL); + reg |= RXCHK_EN; + rxchk_writel(priv, reg, RXCHK_CONTROL); + } + + rbuf_init(priv); + + /* Set maximum frame length */ + umac_writel(priv, UMAC_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN); + + /* Set MAC address */ + umac_set_hw_addr(priv, dev->dev_addr); + + umac_enable_set(priv, CMD_RX_EN, 1); + + /* TX pipe enable */ + topctrl_writel(priv, 0, TX_FLUSH_CNTL); + + umac_enable_set(priv, CMD_TX_EN, 1); + + ret = tdma_enable_set(priv, 1); + if (ret) { + netdev_err(dev, "TDMA timeout!\n"); + goto out_free_rx_ring; + } + + phy_resume(priv->phydev); + + bcm_sysport_netif_start(dev); + + return 0; + +out_free_rx_ring: + bcm_sysport_fini_rx_ring(priv); +out_free_tx_rings: + for (i = 0; i < dev->num_tx_queues; i++) + bcm_sysport_fini_tx_ring(priv, i); + return ret; +} +#endif + +static SIMPLE_DEV_PM_OPS(bcm_sysport_pm_ops, + bcm_sysport_suspend, bcm_sysport_resume); + static const struct of_device_id bcm_sysport_of_match[] = { { .compatible = "brcm,systemport-v1.00" }, { .compatible = "brcm,systemport" }, @@ -1653,6 +1808,7 @@ static struct platform_driver bcm_sysport_driver = { .name = "brcm-systemport", .owner = THIS_MODULE, .of_match_table = bcm_sysport_of_match, + .pm = &bcm_sysport_pm_ops, }, }; module_platform_driver(bcm_sysport_driver); -- cgit v1.2.3 From 9d34c1cb01ddef8e99c7855513a578c066f8300f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 1 Jul 2014 21:08:39 -0700 Subject: net: systemport: rename rx_csum_en to rx_chk_en This boolean tells us whether we are using the RXCHK hardware block, so use a variable name that reflects that. RXCHK might be used in the future to implement Wake-on-LAN using ARP or unicast packets. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 10 +++++----- drivers/net/ethernet/broadcom/bcmsysport.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 9dabcfbfc23a..f00793e45330 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -124,9 +124,9 @@ static int bcm_sysport_set_rx_csum(struct net_device *dev, struct bcm_sysport_priv *priv = netdev_priv(dev); u32 reg; - priv->rx_csum_en = !!(wanted & NETIF_F_RXCSUM); + priv->rx_chk_en = !!(wanted & NETIF_F_RXCSUM); reg = rxchk_readl(priv, RXCHK_CONTROL); - if (priv->rx_csum_en) + if (priv->rx_chk_en) reg |= RXCHK_EN; else reg &= ~RXCHK_EN; @@ -134,7 +134,7 @@ static int bcm_sysport_set_rx_csum(struct net_device *dev, /* If UniMAC forwards CRC, we need to skip over it to get * a valid CHK bit to be set in the per-packet status word */ - if (priv->rx_csum_en && priv->crc_fwd) + if (priv->rx_chk_en && priv->crc_fwd) reg |= RXCHK_SKIP_FCS; else reg &= ~RXCHK_SKIP_FCS; @@ -1674,7 +1674,7 @@ static int bcm_sysport_suspend(struct device *d) } /* Disable RXCHK if enabled */ - if (priv->rx_csum_en) { + if (priv->rx_chk_en) { reg = rxchk_readl(priv, RXCHK_CONTROL); reg &= ~RXCHK_EN; rxchk_writel(priv, reg, RXCHK_CONTROL); @@ -1750,7 +1750,7 @@ static int bcm_sysport_resume(struct device *d) } /* Enable rxhck */ - if (priv->rx_csum_en) { + if (priv->rx_chk_en) { reg = rxchk_readl(priv, RXCHK_CONTROL); reg |= RXCHK_EN; rxchk_writel(priv, reg, RXCHK_CONTROL); diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h index 281c08246037..20ea7162478f 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.h +++ b/drivers/net/ethernet/broadcom/bcmsysport.h @@ -664,7 +664,7 @@ struct bcm_sysport_priv { int old_duplex; /* Misc fields */ - unsigned int rx_csum_en:1; + unsigned int rx_chk_en:1; unsigned int tsb_en:1; unsigned int crc_fwd:1; u16 rev; -- cgit v1.2.3 From 83e82f4c706bbca3e2d9d7962e63605cc7a5fbd8 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 1 Jul 2014 21:08:40 -0700 Subject: net: systemport: add Wake-on-LAN support Support for Wake-on-LAN using Magic Packet with or without SecureOn password is implemented doing the following: - setting the password to the relevant UniMAC registers - flagging the device as a wakeup source for the system, as well as its Wake-on-LAN interrupt - prepare the hardware for entering WoL mode - enabling the MPD interrupt to wake us The Device Tree binding documentation is also reflected to specify the third optional Wake-on-LAN interrupt line. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- .../bindings/net/broadcom-systemport.txt | 3 +- drivers/net/ethernet/broadcom/bcmsysport.c | 155 ++++++++++++++++++++- drivers/net/ethernet/broadcom/bcmsysport.h | 12 ++ 3 files changed, 166 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/net/broadcom-systemport.txt b/Documentation/devicetree/bindings/net/broadcom-systemport.txt index c183ea90d9bc..aa7ad622259d 100644 --- a/Documentation/devicetree/bindings/net/broadcom-systemport.txt +++ b/Documentation/devicetree/bindings/net/broadcom-systemport.txt @@ -4,7 +4,8 @@ Required properties: - compatible: should be one of "brcm,systemport-v1.00" or "brcm,systemport" - reg: address and length of the register set for the device. - interrupts: interrupts for the device, first cell must be for the the rx - interrupts, and the second cell should be for the transmit queues + interrupts, and the second cell should be for the transmit queues. An + optional third interrupt cell for Wake-on-LAN can be specified - local-mac-address: Ethernet MAC address (48 bits) of this adapter - phy-mode: Should be a string describing the PHY interface to the Ethernet switch/PHY, see Documentation/devicetree/bindings/net/ethernet.txt diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index f00793e45330..7a1bd2b3bc26 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -384,6 +384,64 @@ static void bcm_sysport_get_stats(struct net_device *dev, } } +static void bcm_sysport_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + u32 reg; + + wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE; + wol->wolopts = priv->wolopts; + + if (!(priv->wolopts & WAKE_MAGICSECURE)) + return; + + /* Return the programmed SecureOn password */ + reg = umac_readl(priv, UMAC_PSW_MS); + put_unaligned_be16(reg, &wol->sopass[0]); + reg = umac_readl(priv, UMAC_PSW_LS); + put_unaligned_be32(reg, &wol->sopass[2]); +} + +static int bcm_sysport_set_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + struct device *kdev = &priv->pdev->dev; + u32 supported = WAKE_MAGIC | WAKE_MAGICSECURE; + + if (!device_can_wakeup(kdev)) + return -ENOTSUPP; + + if (wol->wolopts & ~supported) + return -EINVAL; + + /* Program the SecureOn password */ + if (wol->wolopts & WAKE_MAGICSECURE) { + umac_writel(priv, get_unaligned_be16(&wol->sopass[0]), + UMAC_PSW_MS); + umac_writel(priv, get_unaligned_be32(&wol->sopass[2]), + UMAC_PSW_LS); + } + + /* Flag the device and relevant IRQ as wakeup capable */ + if (wol->wolopts) { + device_set_wakeup_enable(kdev, 1); + enable_irq_wake(priv->wol_irq); + priv->wol_irq_disabled = 0; + } else { + device_set_wakeup_enable(kdev, 0); + /* Avoid unbalanced disable_irq_wake calls */ + if (!priv->wol_irq_disabled) + disable_irq_wake(priv->wol_irq); + priv->wol_irq_disabled = 1; + } + + priv->wolopts = wol->wolopts; + + return 0; +} + static void bcm_sysport_free_cb(struct bcm_sysport_cb *cb) { dev_kfree_skb_any(cb->skb); @@ -692,6 +750,20 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget) return work_done; } +static void bcm_sysport_resume_from_wol(struct bcm_sysport_priv *priv) +{ + u32 reg; + + /* Stop monitoring MPD interrupt */ + intrl2_0_mask_set(priv, INTRL2_0_MPD); + + /* Clear the MagicPacket detection logic */ + reg = umac_readl(priv, UMAC_MPD_CTRL); + reg &= ~MPD_EN; + umac_writel(priv, reg, UMAC_MPD_CTRL); + + netif_dbg(priv, wol, priv->netdev, "resumed from WOL\n"); +} /* RX and misc interrupt routine */ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id) @@ -722,6 +794,11 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id) if (priv->irq0_stat & INTRL2_0_TX_RING_FULL) bcm_sysport_tx_reclaim_all(priv); + if (priv->irq0_stat & INTRL2_0_MPD) { + netdev_info(priv->netdev, "Wake-on-LAN interrupt!\n"); + bcm_sysport_resume_from_wol(priv); + } + return IRQ_HANDLED; } @@ -757,6 +834,15 @@ static irqreturn_t bcm_sysport_tx_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t bcm_sysport_wol_isr(int irq, void *dev_id) +{ + struct bcm_sysport_priv *priv = dev_id; + + pm_wakeup_event(&priv->pdev->dev, 0); + + return IRQ_HANDLED; +} + static int bcm_sysport_insert_tsb(struct sk_buff *skb, struct net_device *dev) { struct sk_buff *nskb; @@ -1507,6 +1593,8 @@ static struct ethtool_ops bcm_sysport_ethtool_ops = { .get_strings = bcm_sysport_get_strings, .get_ethtool_stats = bcm_sysport_get_stats, .get_sset_count = bcm_sysport_get_sset_count, + .get_wol = bcm_sysport_get_wol, + .set_wol = bcm_sysport_set_wol, }; static const struct net_device_ops bcm_sysport_netdev_ops = { @@ -1548,6 +1636,7 @@ static int bcm_sysport_probe(struct platform_device *pdev) priv->irq0 = platform_get_irq(pdev, 0); priv->irq1 = platform_get_irq(pdev, 1); + priv->wol_irq = platform_get_irq(pdev, 2); if (priv->irq0 <= 0 || priv->irq1 <= 0) { dev_err(&pdev->dev, "invalid interrupts\n"); ret = -EINVAL; @@ -1600,6 +1689,13 @@ static int bcm_sysport_probe(struct platform_device *pdev) dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + /* Request the WOL interrupt and advertise suspend if available */ + priv->wol_irq_disabled = 1; + ret = devm_request_irq(&pdev->dev, priv->wol_irq, + bcm_sysport_wol_isr, 0, dev->name, priv); + if (!ret) + device_set_wakeup_capable(&pdev->dev, 1); + /* Set the needed headroom once and for all */ BUILD_BUG_ON(sizeof(struct bcm_tsb) != 8); dev->needed_headroom += sizeof(struct bcm_tsb); @@ -1647,12 +1743,55 @@ static int bcm_sysport_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP +static int bcm_sysport_suspend_to_wol(struct bcm_sysport_priv *priv) +{ + struct net_device *ndev = priv->netdev; + unsigned int timeout = 1000; + u32 reg; + + /* Password has already been programmed */ + reg = umac_readl(priv, UMAC_MPD_CTRL); + reg |= MPD_EN; + reg &= ~PSW_EN; + if (priv->wolopts & WAKE_MAGICSECURE) + reg |= PSW_EN; + umac_writel(priv, reg, UMAC_MPD_CTRL); + + /* Make sure RBUF entered WoL mode as result */ + do { + reg = rbuf_readl(priv, RBUF_STATUS); + if (reg & RBUF_WOL_MODE) + break; + + udelay(10); + } while (timeout-- > 0); + + /* Do not leave the UniMAC RBUF matching only MPD packets */ + if (!timeout) { + reg = umac_readl(priv, UMAC_MPD_CTRL); + reg &= ~MPD_EN; + umac_writel(priv, reg, UMAC_MPD_CTRL); + netif_err(priv, wol, ndev, "failed to enter WOL mode\n"); + return -ETIMEDOUT; + } + + /* UniMAC receive needs to be turned on */ + umac_enable_set(priv, CMD_RX_EN, 1); + + /* Enable the interrupt wake-up source */ + intrl2_0_mask_clear(priv, INTRL2_0_MPD); + + netif_dbg(priv, wol, ndev, "entered WOL mode\n"); + + return 0; +} + static int bcm_sysport_suspend(struct device *d) { struct net_device *dev = dev_get_drvdata(d); struct bcm_sysport_priv *priv = netdev_priv(dev); unsigned int i; - int ret; + int ret = 0; u32 reg; if (!netif_running(dev)) @@ -1681,7 +1820,8 @@ static int bcm_sysport_suspend(struct device *d) } /* Flush RX pipe */ - topctrl_writel(priv, RX_FLUSH, RX_FLUSH_CNTL); + if (!priv->wolopts) + topctrl_writel(priv, RX_FLUSH, RX_FLUSH_CNTL); ret = tdma_enable_set(priv, 0); if (ret) { @@ -1701,7 +1841,11 @@ static int bcm_sysport_suspend(struct device *d) bcm_sysport_fini_tx_ring(priv, i); bcm_sysport_fini_rx_ring(priv); - return 0; + /* Get prepared for Wake-on-LAN */ + if (device_may_wakeup(d) && priv->wolopts) + ret = bcm_sysport_suspend_to_wol(priv); + + return ret; } static int bcm_sysport_resume(struct device *d) @@ -1715,6 +1859,11 @@ static int bcm_sysport_resume(struct device *d) if (!netif_running(dev)) return 0; + /* We may have been suspended and never received a WOL event that + * would turn off MPD detection, take care of that now + */ + bcm_sysport_resume_from_wol(priv); + /* Initialize both hardware and software ring */ for (i = 0; i < dev->num_tx_queues; i++) { ret = bcm_sysport_init_tx_ring(priv, i); diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h index 20ea7162478f..b08dab828101 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.h +++ b/drivers/net/ethernet/broadcom/bcmsysport.h @@ -246,6 +246,15 @@ struct bcm_rsb { #define MIB_RX_CNT_RST (1 << 0) #define MIB_RUNT_CNT_RST (1 << 1) #define MIB_TX_CNT_RST (1 << 2) + +#define UMAC_MPD_CTRL 0x620 +#define MPD_EN (1 << 0) +#define MSEQ_LEN_SHIFT 16 +#define MSEQ_LEN_MASK 0xff +#define PSW_EN (1 << 27) + +#define UMAC_PSW_MS 0x624 +#define UMAC_PSW_LS 0x628 #define UMAC_MDF_CTRL 0x650 #define UMAC_MDF_ADDR 0x654 @@ -642,6 +651,7 @@ struct bcm_sysport_priv { struct platform_device *pdev; int irq0; int irq1; + int wol_irq; /* Transmit rings */ struct bcm_sysport_tx_ring tx_rings[TDMA_NUM_RINGS]; @@ -668,6 +678,8 @@ struct bcm_sysport_priv { unsigned int tsb_en:1; unsigned int crc_fwd:1; u16 rev; + u32 wolopts; + unsigned int wol_irq_disabled:1; /* MIB related fields */ struct bcm_sysport_mib mib; -- cgit v1.2.3 From 5ed20a68cd6ca4adc0aa2d240913d604a2eb3e25 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Jul 2014 21:32:05 -0700 Subject: flow_dissector: Abstract out hash computation Move the hash computation located in __skb_get_hash to be a separate function which takes flow_keys as input. This will allow flow hash computation in other contexts where we only have addresses and ports. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_keys.h | 1 + net/core/flow_dissector.c | 44 ++++++++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h index fbefdca5e283..6667a054763a 100644 --- a/include/net/flow_keys.h +++ b/include/net/flow_keys.h @@ -29,4 +29,5 @@ struct flow_keys { bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow); __be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto); +u32 flow_hash_from_keys(struct flow_keys *keys); #endif diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index c2b53c1b21d2..2ff8cd4dfc5f 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -202,6 +202,33 @@ static __always_inline u32 __flow_hash_1word(u32 a) return jhash_1word(a, hashrnd); } +static inline u32 __flow_hash_from_keys(struct flow_keys *keys) +{ + u32 hash; + + /* get a consistent hash (same value on both flow directions) */ + if (((__force u32)keys->dst < (__force u32)keys->src) || + (((__force u32)keys->dst == (__force u32)keys->src) && + ((__force u16)keys->port16[1] < (__force u16)keys->port16[0]))) { + swap(keys->dst, keys->src); + swap(keys->port16[0], keys->port16[1]); + } + + hash = __flow_hash_3words((__force u32)keys->dst, + (__force u32)keys->src, + (__force u32)keys->ports); + if (!hash) + hash = 1; + + return hash; +} + +u32 flow_hash_from_keys(struct flow_keys *keys) +{ + return __flow_hash_from_keys(keys); +} +EXPORT_SYMBOL(flow_hash_from_keys); + /* * __skb_get_hash: calculate a flow hash based on src/dst addresses * and src/dst port numbers. Sets hash in skb to non-zero hash value @@ -211,7 +238,6 @@ static __always_inline u32 __flow_hash_1word(u32 a) void __skb_get_hash(struct sk_buff *skb) { struct flow_keys keys; - u32 hash; if (!skb_flow_dissect(skb, &keys)) return; @@ -219,21 +245,7 @@ void __skb_get_hash(struct sk_buff *skb) if (keys.ports) skb->l4_hash = 1; - /* get a consistent hash (same value on both flow directions) */ - if (((__force u32)keys.dst < (__force u32)keys.src) || - (((__force u32)keys.dst == (__force u32)keys.src) && - ((__force u16)keys.port16[1] < (__force u16)keys.port16[0]))) { - swap(keys.dst, keys.src); - swap(keys.port16[0], keys.port16[1]); - } - - hash = __flow_hash_3words((__force u32)keys.dst, - (__force u32)keys.src, - (__force u32)keys.ports); - if (!hash) - hash = 1; - - skb->hash = hash; + skb->hash = __flow_hash_from_keys(&keys); } EXPORT_SYMBOL(__skb_get_hash); -- cgit v1.2.3 From b73c3d0e4f0e1961e15bec18720e48aabebe2109 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Jul 2014 21:32:17 -0700 Subject: net: Save TX flow hash in sock and set in skbuf on xmit For a connected socket we can precompute the flow hash for setting in skb->hash on output. This is a performance advantage over calculating the skb->hash for every packet on the connection. The computation is done using the common hash algorithm to be consistent with computations done for packets of the connection in other states where thers is no socket (e.g. time-wait, syn-recv, syn-cookies). This patch adds sk_txhash to the sock structure. inet_set_txhash and ip6_set_txhash functions are added which are called from points in TCP and UDP where socket moves to established state. skb_set_hash_from_sk is a function which sets skb->hash from the sock txhash value. This is called in UDP and TCP transmit path when transmitting within the context of a socket. Tested: ran super_netperf with 200 TCP_RR streams over a vxlan interface (in this case skb_get_hash called on every TX packet to create a UDP source port). Before fix: 95.02% CPU utilization 154/256/505 90/95/99% latencies 1.13042e+06 tps Time in functions: 0.28% skb_flow_dissect 0.21% __skb_get_hash After fix: 94.95% CPU utilization 156/254/485 90/95/99% latencies 1.15447e+06 Neither __skb_get_hash nor skb_flow_dissect appear in perf Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/ip.h | 14 ++++++++++++++ include/net/ipv6.h | 15 +++++++++++++++ include/net/sock.h | 11 +++++++++++ net/ipv4/datagram.c | 1 + net/ipv4/tcp_ipv4.c | 3 +++ net/ipv4/tcp_output.c | 1 + net/ipv6/datagram.c | 1 + net/ipv6/tcp_ipv6.c | 4 ++++ 8 files changed, 50 insertions(+) diff --git a/include/net/ip.h b/include/net/ip.h index 0e795df05ec9..2e8f055989c3 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -31,6 +31,7 @@ #include #include #include +#include struct sock; @@ -353,6 +354,19 @@ static inline __wsum inet_compute_pseudo(struct sk_buff *skb, int proto) skb->len, proto, 0); } +static inline void inet_set_txhash(struct sock *sk) +{ + struct inet_sock *inet = inet_sk(sk); + struct flow_keys keys; + + keys.src = inet->inet_saddr; + keys.dst = inet->inet_daddr; + keys.port16[0] = inet->inet_sport; + keys.port16[1] = inet->inet_dport; + + sk->sk_txhash = flow_hash_from_keys(&keys); +} + /* * Map a multicast IP onto multicast MAC for type ethernet. */ diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 574337fe72dd..2aa86e1135a1 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #define SIN6_LEN_RFC2133 24 @@ -684,6 +685,20 @@ static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6, return hlimit; } +static inline void ip6_set_txhash(struct sock *sk) +{ + struct inet_sock *inet = inet_sk(sk); + struct ipv6_pinfo *np = inet6_sk(sk); + struct flow_keys keys; + + keys.src = (__force __be32)ipv6_addr_hash(&np->saddr); + keys.dst = (__force __be32)ipv6_addr_hash(&sk->sk_v6_daddr); + keys.port16[0] = inet->inet_sport; + keys.port16[1] = inet->inet_dport; + + sk->sk_txhash = flow_hash_from_keys(&keys); +} + /* * Header manipulation */ diff --git a/include/net/sock.h b/include/net/sock.h index 8d4c9473e7d7..cb84b2f1ad8f 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -273,6 +273,7 @@ struct cg_proto; * @sk_rcvtimeo: %SO_RCVTIMEO setting * @sk_sndtimeo: %SO_SNDTIMEO setting * @sk_rxhash: flow hash received from netif layer + * @sk_txhash: computed flow hash for use on transmit * @sk_filter: socket filtering instructions * @sk_protinfo: private area, net family specific, when not using slab * @sk_timer: sock cleanup timer @@ -347,6 +348,7 @@ struct sock { #ifdef CONFIG_RPS __u32 sk_rxhash; #endif + __u32 sk_txhash; #ifdef CONFIG_NET_RX_BUSY_POLL unsigned int sk_napi_id; unsigned int sk_ll_usec; @@ -1980,6 +1982,14 @@ static inline void sock_poll_wait(struct file *filp, } } +static inline void skb_set_hash_from_sk(struct sk_buff *skb, struct sock *sk) +{ + if (sk->sk_txhash) { + skb->l4_hash = 1; + skb->hash = sk->sk_txhash; + } +} + /* * Queue a received datagram if it will fit. Stream and sequenced * protocols can't normally use this as they need to fit buffers in @@ -1994,6 +2004,7 @@ static inline void skb_set_owner_w(struct sk_buff *skb, struct sock *sk) skb_orphan(skb); skb->sk = sk; skb->destructor = sock_wfree; + skb_set_hash_from_sk(skb, sk); /* * We used to take a refcount on sk, but following operation * is enough to guarantee sk_free() wont free this sock until diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index a3095fdefbed..90c0e8386116 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -76,6 +76,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) inet->inet_daddr = fl4->daddr; inet->inet_dport = usin->sin_port; sk->sk_state = TCP_ESTABLISHED; + inet_set_txhash(sk); inet->inet_id = jiffies; sk_dst_set(sk, &rt->dst); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 52d0f6a1ec2c..1edc739b9da5 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -208,6 +208,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) inet->inet_dport = usin->sin_port; inet->inet_daddr = daddr; + inet_set_txhash(sk); + inet_csk(sk)->icsk_ext_hdr_len = 0; if (inet_opt) inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen; @@ -1334,6 +1336,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newinet->mc_ttl = ip_hdr(skb)->ttl; newinet->rcv_tos = ip_hdr(skb)->tos; inet_csk(newsk)->icsk_ext_hdr_len = 0; + inet_set_txhash(newsk); if (inet_opt) inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen; newinet->inet_id = newtp->write_seq ^ jiffies; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f8f2a944a1ce..bcee13c4627c 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -916,6 +916,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, skb_orphan(skb); skb->sk = sk; skb->destructor = tcp_wfree; + skb_set_hash_from_sk(skb, sk); atomic_add(skb->truesize, &sk->sk_wmem_alloc); /* Build TCP header and checksum it. */ diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index c3bf2d2e519e..2753319524f1 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -199,6 +199,7 @@ ipv4_connected: NULL); sk->sk_state = TCP_ESTABLISHED; + ip6_set_txhash(sk); out: fl6_sock_release(flowlabel); return err; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index a97c95585da8..22055b098428 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -198,6 +198,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, sk->sk_v6_daddr = usin->sin6_addr; np->flow_label = fl6.flowlabel; + ip6_set_txhash(sk); + /* * TCP over IPv4 */ @@ -1132,6 +1134,8 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr; newsk->sk_bound_dev_if = ireq->ir_iif; + ip6_set_txhash(newsk); + /* Now IPv6 options... First: no IPv4 options. -- cgit v1.2.3 From 0e001614e849b68cff94cda8db8b550569d3dba6 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Jul 2014 21:32:27 -0700 Subject: net: Call skb_get_hash in get_xps_queue and __skb_tx_hash Call standard function to get a packet hash instead of taking this from skb->sk->sk_hash or only using skb->protocol. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- include/linux/skbuff.h | 2 +- net/core/flow_dissector.c | 29 +++++------------------------ 3 files changed, 7 insertions(+), 26 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 66f9a04ec270..8b43a28ee0bc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2486,7 +2486,7 @@ static inline int netif_set_xps_queue(struct net_device *dev, * as a distribution range limit for the returned value. */ static inline u16 skb_tx_hash(const struct net_device *dev, - const struct sk_buff *skb) + struct sk_buff *skb) { return __skb_tx_hash(dev, skb, dev->real_num_tx_queues); } diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ec89301ada41..b297af70ac30 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3005,7 +3005,7 @@ static inline bool skb_rx_queue_recorded(const struct sk_buff *skb) return skb->queue_mapping != 0; } -u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb, +u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb, unsigned int num_tx_queues); static inline struct sec_path *skb_sec_path(struct sk_buff *skb) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 2ff8cd4dfc5f..62d1cb624f53 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -196,12 +196,6 @@ static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c) return jhash_3words(a, b, c, hashrnd); } -static __always_inline u32 __flow_hash_1word(u32 a) -{ - __flow_hash_secret_init(); - return jhash_1word(a, hashrnd); -} - static inline u32 __flow_hash_from_keys(struct flow_keys *keys) { u32 hash; @@ -253,7 +247,7 @@ EXPORT_SYMBOL(__skb_get_hash); * Returns a Tx hash based on the given packet descriptor a Tx queues' number * to be used as a distribution range. */ -u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb, +u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb, unsigned int num_tx_queues) { u32 hash; @@ -273,13 +267,7 @@ u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb, qcount = dev->tc_to_txq[tc].count; } - if (skb->sk && skb->sk->sk_hash) - hash = skb->sk->sk_hash; - else - hash = (__force u16) skb->protocol; - hash = __flow_hash_1word(hash); - - return (u16) (((u64) hash * qcount) >> 32) + qoffset; + return (u16) (((u64)skb_get_hash(skb) * qcount) >> 32) + qoffset; } EXPORT_SYMBOL(__skb_tx_hash); @@ -351,17 +339,10 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb) if (map) { if (map->len == 1) queue_index = map->queues[0]; - else { - u32 hash; - if (skb->sk && skb->sk->sk_hash) - hash = skb->sk->sk_hash; - else - hash = (__force u16) skb->protocol ^ - skb->hash; - hash = __flow_hash_1word(hash); + else queue_index = map->queues[ - ((u64)hash * map->len) >> 32]; - } + ((u64)skb_get_hash(skb) * map->len) >> 32]; + if (unlikely(queue_index >= dev->real_num_tx_queues)) queue_index = -1; } -- cgit v1.2.3 From b8f1a55639e6a76cfd274cc7de76eafac9a15ca9 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Jul 2014 21:32:39 -0700 Subject: udp: Add function to make source port for UDP tunnels This patch adds udp_flow_src_port function which is intended to be a common function that UDP tunnel implementations call to set the source port. The source port is chosen so that a hash over the outer headers (IP addresses and UDP ports) acts as suitable hash for the flow of the encapsulated packet. In this manner, UDP encapsulation works with RSS and ECMP based wrt the inner flow. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/udp.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/net/udp.h b/include/net/udp.h index 68a1fefe3dfe..70f941368ace 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -176,6 +176,35 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, int (*)(const struct sock *, const struct sock *), unsigned int hash2_nulladdr); +static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb, + int min, int max, bool use_eth) +{ + u32 hash; + + if (min >= max) { + /* Use default range */ + inet_get_local_port_range(net, &min, &max); + } + + hash = skb_get_hash(skb); + if (unlikely(!hash) && use_eth) { + /* Can't find a normal hash, caller has indicated an Ethernet + * packet so use that to compute a hash. + */ + hash = jhash(skb->data, 2 * ETH_ALEN, + (__force u32) skb->protocol); + } + + /* Since this is being sent on the wire obfuscate hash a bit + * to minimize possbility that any useful information to an + * attacker is leaked. Only upper 16 bits are relevant in the + * computation for 16 bit port value. + */ + hash ^= hash << 16; + + return htons((((u64) hash * (max - min)) >> 32) + min); +} + /* net/ipv4/udp.c */ void udp_v4_early_demux(struct sk_buff *skb); int udp_get_port(struct sock *sk, unsigned short snum, -- cgit v1.2.3 From 535fb8d006bc6a96d59558181a9a6f267be382c5 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Jul 2014 21:32:49 -0700 Subject: vxlan: Call udp_flow_src_port In vxlan and OVS vport-vxlan call common function to get source port for a UDP tunnel. Removed vxlan_src_port since the functionality is now in udp_flow_src_port. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 26 ++------------------------ include/net/vxlan.h | 2 -- net/openvswitch/vport-vxlan.c | 5 +---- 3 files changed, 3 insertions(+), 30 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index ade33ef82823..c2d360150804 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1570,25 +1570,6 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) return false; } -/* Compute source port for outgoing packet - * first choice to use L4 flow hash since it will spread - * better and maybe available from hardware - * secondary choice is to use jhash on the Ethernet header - */ -__be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb) -{ - unsigned int range = (port_max - port_min) + 1; - u32 hash; - - hash = skb_get_hash(skb); - if (!hash) - hash = jhash(skb->data, 2 * ETH_ALEN, - (__force u32) skb->protocol); - - return htons((((u64) hash * range) >> 32) + port_min); -} -EXPORT_SYMBOL_GPL(vxlan_src_port); - static inline struct sk_buff *vxlan_handle_offloads(struct sk_buff *skb, bool udp_csum) { @@ -1807,7 +1788,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (tos == 1) tos = ip_tunnel_get_dsfield(old_iph, skb); - src_port = vxlan_src_port(vxlan->port_min, vxlan->port_max, skb); + src_port = udp_flow_src_port(dev_net(dev), skb, vxlan->port_min, + vxlan->port_max, true); if (dst->sa.sa_family == AF_INET) { memset(&fl4, 0, sizeof(fl4)); @@ -2235,7 +2217,6 @@ static void vxlan_setup(struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); unsigned int h; - int low, high; eth_hw_addr_random(dev); ether_setup(dev); @@ -2272,9 +2253,6 @@ static void vxlan_setup(struct net_device *dev) vxlan->age_timer.function = vxlan_cleanup; vxlan->age_timer.data = (unsigned long) vxlan; - inet_get_local_port_range(dev_net(dev), &low, &high); - vxlan->port_min = low; - vxlan->port_max = high; vxlan->dst_port = htons(vxlan_port); vxlan->dev = dev; diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 12196ce661d9..d5f59f3fc35d 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -45,8 +45,6 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, __be32 vni, bool xnet); -__be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb); - /* IP header + UDP + VXLAN + Ethernet header */ #define VXLAN_HEADROOM (20 + 8 + 8 + 14) /* IPv6 header + UDP + VXLAN + Ethernet header */ diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index 0edbd95c60e7..d8b7e247bebf 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c @@ -143,8 +143,6 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) struct rtable *rt; struct flowi4 fl; __be16 src_port; - int port_min; - int port_max; __be16 df; int err; @@ -172,8 +170,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) skb->ignore_df = 1; - inet_get_local_port_range(net, &port_min, &port_max); - src_port = vxlan_src_port(port_min, port_max, skb); + src_port = udp_flow_src_port(net, skb, 0, 0, true); err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, fl.saddr, OVS_CB(skb)->tun_key->ipv4_dst, -- cgit v1.2.3 From 19469a873bafd4e65daef3597db2bd724c1b03c9 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Jul 2014 21:33:01 -0700 Subject: flow_dissector: Use IPv6 flow label in flow_dissector This patch implements the receive side to support RFC 6438 which is to use the flow label as an ECMP hash. If an IPv6 flow label is set in a packet we can use this as input for computing an L4-hash. There should be no need to parse any transport headers in this case. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/core/flow_dissector.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 62d1cb624f53..c5f3912dad4c 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -80,6 +80,8 @@ ip: case htons(ETH_P_IPV6): { const struct ipv6hdr *iph; struct ipv6hdr _iph; + __be32 flow_label; + ipv6: iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); if (!iph) @@ -89,6 +91,21 @@ ipv6: flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr); flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); nhoff += sizeof(struct ipv6hdr); + + flow_label = ip6_flowlabel(iph); + if (flow_label) { + /* Awesome, IPv6 packet has a flow label so we can + * use that to represent the ports without any + * further dissection. + */ + flow->n_proto = proto; + flow->ip_proto = ip_proto; + flow->ports = flow_label; + flow->thoff = (u16)nhoff; + + return true; + } + break; } case htons(ETH_P_8021AD): -- cgit v1.2.3 From cb1ce2ef387b01686469487edd45994872d52d73 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Jul 2014 21:33:10 -0700 Subject: ipv6: Implement automatic flow label generation on transmit Automatically generate flow labels for IPv6 packets on transmit. The flow label is computed based on skb_get_hash. The flow label will only automatically be set when it is zero otherwise (i.e. flow label manager hasn't set one). This supports the transmit side functionality of RFC 6438. Added an IPv6 sysctl auto_flowlabels to enable/disable this behavior system wide, and added IPV6_AUTOFLOWLABEL socket option to enable this functionality per socket. By default, auto flowlabels are disabled to avoid possible conflicts with flow label manager, however if this feature proves useful we may want to enable it by default. It should also be noted that FreeBSD has already implemented automatic flow labels (including the sysctl and socket option). In FreeBSD, automatic flow labels default to enabled. Performance impact: Running super_netperf with 200 flows for TCP_RR and UDP_RR for IPv6. Note that in UDP case, __skb_get_hash will be called for every packet with explains slight regression. In the TCP case the hash is saved in the socket so there is no regression. Automatic flow labels disabled: TCP_RR: 86.53% CPU utilization 127/195/322 90/95/99% latencies 1.40498e+06 tps UDP_RR: 90.70% CPU utilization 118/168/243 90/95/99% latencies 1.50309e+06 tps Automatic flow labels enabled: TCP_RR: 85.90% CPU utilization 128/199/337 90/95/99% latencies 1.40051e+06 UDP_RR 92.61% CPU utilization 115/164/236 90/95/99% latencies 1.4687e+06 Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 9 +++++++++ include/linux/ipv6.h | 3 ++- include/net/ipv6.h | 20 ++++++++++++++++++++ include/net/netns/ipv6.h | 1 + include/uapi/linux/in6.h | 1 + net/ipv6/af_inet6.c | 1 + net/ipv6/ip6_gre.c | 7 +++++-- net/ipv6/ip6_output.c | 7 +++++-- net/ipv6/ip6_tunnel.c | 3 ++- net/ipv6/ipv6_sockglue.c | 8 ++++++++ net/ipv6/sysctl_net_ipv6.c | 8 ++++++++ 11 files changed, 62 insertions(+), 6 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 10e216c6e05e..f35bfe43bf7a 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1132,6 +1132,15 @@ flowlabel_consistency - BOOLEAN FALSE: disabled Default: TRUE +auto_flowlabels - BOOLEAN + Automatically generate flow labels based based on a flow hash + of the packet. This allows intermediate devices, such as routers, + to idenfify packet flows for mechanisms like Equal Cost Multipath + Routing (see RFC 6438). + TRUE: enabled + FALSE: disabled + Default: false + anycast_src_echo_reply - BOOLEAN Controls the use of anycast addresses as source addresses for ICMPv6 echo reply diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 5dc68c3ebcbd..ff560537dd61 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -199,7 +199,8 @@ struct ipv6_pinfo { * 010: prefer public address * 100: prefer care-of address */ - dontfrag:1; + dontfrag:1, + autoflowlabel:1; __u8 min_hopcount; __u8 tclass; __be32 rcv_flowinfo; diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 2aa86e1135a1..4308f2ada8b3 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -699,6 +699,26 @@ static inline void ip6_set_txhash(struct sock *sk) sk->sk_txhash = flow_hash_from_keys(&keys); } +static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, + __be32 flowlabel, bool autolabel) +{ + if (!flowlabel && (autolabel || net->ipv6.sysctl.auto_flowlabels)) { + __be32 hash; + + hash = skb_get_hash(skb); + + /* Since this is being sent on the wire obfuscate hash a bit + * to minimize possbility that any useful information to an + * attacker is leaked. Only lower 20 bits are relevant. + */ + hash ^= hash >> 12; + + flowlabel = hash & IPV6_FLOWLABEL_MASK; + } + + return flowlabel; +} + /* * Header manipulation */ diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 19d3446e59d2..eade27adecf3 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -28,6 +28,7 @@ struct netns_sysctl_ipv6 { int ip6_rt_mtu_expires; int ip6_rt_min_advmss; int flowlabel_consistency; + int auto_flowlabels; int icmpv6_time; int anycast_src_echo_reply; int fwmark_reflect; diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h index 0d8e0f0342dc..22b7a69619d8 100644 --- a/include/uapi/linux/in6.h +++ b/include/uapi/linux/in6.h @@ -233,6 +233,7 @@ struct in6_flowlabel_req { #if 0 /* not yet */ #define IPV6_USE_MIN_MTU 63 #endif +#define IPV6_AUTOFLOWLABEL 64 /* * Netfilter (1) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index a426cd7099bb..2daa3a133e49 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -765,6 +765,7 @@ static int __net_init inet6_net_init(struct net *net) net->ipv6.sysctl.bindv6only = 0; net->ipv6.sysctl.icmpv6_time = 1*HZ; net->ipv6.sysctl.flowlabel_consistency = 1; + net->ipv6.sysctl.auto_flowlabels = 0; atomic_set(&net->ipv6.rt_genid, 0); err = ipv6_init_mibs(net); diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 3873181ed856..365b2b6f3942 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -723,7 +723,8 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, * Push down and install the IP header. */ ipv6h = ipv6_hdr(skb); - ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel); + ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), + ip6_make_flowlabel(net, skb, fl6->flowlabel, false)); ipv6h->hop_limit = tunnel->parms.hop_limit; ipv6h->nexthdr = proto; ipv6h->saddr = fl6->saddr; @@ -1174,7 +1175,9 @@ static int ip6gre_header(struct sk_buff *skb, struct net_device *dev, struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen); __be16 *p = (__be16 *)(ipv6h+1); - ip6_flow_hdr(ipv6h, 0, t->fl.u.ip6.flowlabel); + ip6_flow_hdr(ipv6h, 0, + ip6_make_flowlabel(dev_net(dev), skb, + t->fl.u.ip6.flowlabel, false)); ipv6h->hop_limit = t->parms.hop_limit; ipv6h->nexthdr = NEXTHDR_GRE; ipv6h->saddr = t->parms.laddr; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index cb9df0eb4023..fa83bdd4c3dd 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -205,7 +205,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, if (hlimit < 0) hlimit = ip6_dst_hoplimit(dst); - ip6_flow_hdr(hdr, tclass, fl6->flowlabel); + ip6_flow_hdr(hdr, tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel, + np->autoflowlabel)); hdr->payload_len = htons(seg_len); hdr->nexthdr = proto; @@ -1569,7 +1570,9 @@ int ip6_push_pending_frames(struct sock *sk) skb_reset_network_header(skb); hdr = ipv6_hdr(skb); - ip6_flow_hdr(hdr, np->cork.tclass, fl6->flowlabel); + ip6_flow_hdr(hdr, np->cork.tclass, + ip6_make_flowlabel(net, skb, fl6->flowlabel, + np->autoflowlabel)); hdr->hop_limit = np->cork.hop_limit; hdr->nexthdr = proto; hdr->saddr = fl6->saddr; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index afa082458360..51a1eb185ea7 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1046,7 +1046,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, skb_push(skb, sizeof(struct ipv6hdr)); skb_reset_network_header(skb); ipv6h = ipv6_hdr(skb); - ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel); + ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), + ip6_make_flowlabel(net, skb, fl6->flowlabel, false)); ipv6h->hop_limit = t->parms.hop_limit; ipv6h->nexthdr = proto; ipv6h->saddr = fl6->saddr; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index cc34f65179e4..b50b9e54cf53 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -834,6 +834,10 @@ pref_skip_coa: np->dontfrag = valbool; retv = 0; break; + case IPV6_AUTOFLOWLABEL: + np->autoflowlabel = valbool; + retv = 0; + break; } release_sock(sk); @@ -1273,6 +1277,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, val = np->dontfrag; break; + case IPV6_AUTOFLOWLABEL: + val = np->autoflowlabel; + break; + default: return -ENOPROTOOPT; } diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 058f3eca2e53..5bf7b61f8ae8 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -38,6 +38,13 @@ static struct ctl_table ipv6_table_template[] = { .mode = 0644, .proc_handler = proc_dointvec }, + { + .procname = "auto_flowlabels", + .data = &init_net.ipv6.sysctl.auto_flowlabels, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, { .procname = "fwmark_reflect", .data = &init_net.ipv6.sysctl.fwmark_reflect, @@ -74,6 +81,7 @@ static int __net_init ipv6_sysctl_net_init(struct net *net) ipv6_table[0].data = &net->ipv6.sysctl.bindv6only; ipv6_table[1].data = &net->ipv6.sysctl.anycast_src_echo_reply; ipv6_table[2].data = &net->ipv6.sysctl.flowlabel_consistency; + ipv6_table[3].data = &net->ipv6.sysctl.auto_flowlabels; ipv6_route_table = ipv6_route_sysctl_init(net); if (!ipv6_route_table) -- cgit v1.2.3 From a3b18ddb9cc1056eea24e3edc1828cfb3fd0726f Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Jul 2014 21:33:17 -0700 Subject: net: Only do flow_dissector hash computation once per packet Add sw_hash flag to skbuff to indicate that skb->hash was computed from flow_dissector. This flag is checked in skb_get_hash to avoid repeatedly trying to compute the hash (ie. in the case that no L4 hash can be computed). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/skbuff.h | 9 +++++++-- net/core/flow_dissector.c | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index b297af70ac30..890fb3307dd6 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -455,6 +455,7 @@ static inline u32 skb_mstamp_us_delta(const struct skb_mstamp *t1, * @ooo_okay: allow the mapping of a socket to a queue to be changed * @l4_hash: indicate hash is a canonical 4-tuple hash over transport * ports. + * @sw_hash: indicates hash was computed in software stack * @wifi_acked_valid: wifi_acked was set * @wifi_acked: whether frame was acked on wifi or not * @no_fcs: Request NIC to treat last 4 bytes as Ethernet FCS @@ -562,6 +563,7 @@ struct sk_buff { __u8 pfmemalloc:1; __u8 ooo_okay:1; __u8 l4_hash:1; + __u8 sw_hash:1; __u8 wifi_acked_valid:1; __u8 wifi_acked:1; __u8 no_fcs:1; @@ -575,7 +577,7 @@ struct sk_buff { __u8 encap_hdr_csum:1; __u8 csum_valid:1; __u8 csum_complete_sw:1; - /* 3/5 bit hole (depending on ndisc_nodetype presence) */ + /* 2/4 bit hole (depending on ndisc_nodetype presence) */ kmemcheck_bitfield_end(flags2); #if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL @@ -830,13 +832,14 @@ static inline void skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type) { skb->l4_hash = (type == PKT_HASH_TYPE_L4); + skb->sw_hash = 0; skb->hash = hash; } void __skb_get_hash(struct sk_buff *skb); static inline __u32 skb_get_hash(struct sk_buff *skb) { - if (!skb->l4_hash) + if (!skb->l4_hash && !skb->sw_hash) __skb_get_hash(skb); return skb->hash; @@ -850,6 +853,7 @@ static inline __u32 skb_get_hash_raw(const struct sk_buff *skb) static inline void skb_clear_hash(struct sk_buff *skb) { skb->hash = 0; + skb->sw_hash = 0; skb->l4_hash = 0; } @@ -862,6 +866,7 @@ static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb) static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from) { to->hash = from->hash; + to->sw_hash = from->sw_hash; to->l4_hash = from->l4_hash; }; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index c5f3912dad4c..5f362c1d0332 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -256,6 +256,8 @@ void __skb_get_hash(struct sk_buff *skb) if (keys.ports) skb->l4_hash = 1; + skb->sw_hash = 1; + skb->hash = __flow_hash_from_keys(&keys); } EXPORT_SYMBOL(__skb_get_hash); -- cgit v1.2.3 From b44592ffb8e0da32f1d17f1586a9d2c59dd152a1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 00:22:34 +0100 Subject: net: fec: iMX6 FEC does not support half-duplex gigabit The iMX6 gigabit FEC does not support half-duplex gigabit operation. Phys attacked to the FEC may support this, and we currently do nothing to disable this feature. This may result in an invalid configuration. Mask out phy support for gigabit half-duplex operation. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 77037fd377b8..a91fe68030e6 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1667,6 +1667,7 @@ static int fec_enet_mii_probe(struct net_device *ndev) /* mask with MAC supported features */ if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) { phy_dev->supported &= PHY_GBIT_FEATURES; + phy_dev->supported &= ~SUPPORTED_1000baseT_Half; #if !defined(CONFIG_M5272) phy_dev->supported |= SUPPORTED_Pause; #endif -- cgit v1.2.3 From 9671a42e4508db8a0196110b098fd8550304ab14 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 00:22:39 +0100 Subject: net: fec: fix ethtool set_pauseparam duplex bug Setting the pause parameters causes a running network interface to be restarted. However, the restart forces the FEC into half-duplex mode, whether or not the remote end is in half-duplex mode. Misconfigured duplex mode is a known source of problems on a link. Fix this by always preserving the duplex mode on configuration changes. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index a91fe68030e6..045ea71f2b59 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1897,7 +1897,7 @@ static int fec_enet_set_pauseparam(struct net_device *ndev, phy_start_aneg(fep->phy_dev); } if (netif_running(ndev)) - fec_restart(ndev, 0); + fec_restart(ndev, fep->full_duplex); return 0; } -- cgit v1.2.3 From 7a16807ce149d4e9cd53facca0cff6a4a647b6be Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 00:22:44 +0100 Subject: net: fec: fix interrupt handling races While running: while :; do iperf -c -P 4; done, transmit timeouts are regularly reported. With the tx ring dumping in place, we can see that all entries are in use, and the hardware has finished transmitting these packets. However, the driver has not reclaimed these ring entries. This can occur if the interrupt handler is invoked at the wrong moment - eg: CPU0 CPU1 fec_enet_tx() interrupt, IEVENT = FEC_ENET_TXF FEC_ENET_TXF cleared napi_schedule_prep() napi_complete() The result is that we clear the transmit interrupt, but we don't trigger any cleaning of the transmit ring. Instead, use a different strategy: - When receiving a transmit or receive interrupt, disable both tx and rx interrupts, but do not acknowledge them. Schedule a napi poll. Don't loop. - When we are polled, read IEVENT, acknowledging the pending transmit and receive interrupts, before then going on to process the appropriate rings. This allows us to avoid the race, and has a number of other advantages: - we cut down on the number of transmit interrupts we have to process. - we only look at the rings which have pending events. - we gain additional throughput: the iperf total bandwidth increases from about 180Mbps to 240Mbps: [ 3] 0.0-10.0 sec 68.1 MBytes 57.0 Mbits/sec [ 5] 0.0-10.0 sec 72.4 MBytes 60.5 Mbits/sec [ 4] 0.0-10.1 sec 76.1 MBytes 63.5 Mbits/sec [ 6] 0.0-10.1 sec 71.9 MBytes 59.9 Mbits/sec [SUM] 0.0-10.1 sec 288 MBytes 241 Mbits/sec Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 40 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 045ea71f2b59..4e695b742030 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1369,29 +1369,25 @@ fec_enet_interrupt(int irq, void *dev_id) { struct net_device *ndev = dev_id; struct fec_enet_private *fep = netdev_priv(ndev); + const unsigned napi_mask = FEC_ENET_RXF | FEC_ENET_TXF; uint int_events; irqreturn_t ret = IRQ_NONE; - do { - int_events = readl(fep->hwp + FEC_IEVENT); - writel(int_events, fep->hwp + FEC_IEVENT); + int_events = readl(fep->hwp + FEC_IEVENT); + writel(int_events & ~napi_mask, fep->hwp + FEC_IEVENT); - if (int_events & (FEC_ENET_RXF | FEC_ENET_TXF)) { - ret = IRQ_HANDLED; + if (int_events & napi_mask) { + ret = IRQ_HANDLED; - /* Disable the RX interrupt */ - if (napi_schedule_prep(&fep->napi)) { - writel(FEC_RX_DISABLED_IMASK, - fep->hwp + FEC_IMASK); - __napi_schedule(&fep->napi); - } - } + /* Disable the NAPI interrupts */ + writel(FEC_ENET_MII, fep->hwp + FEC_IMASK); + napi_schedule(&fep->napi); + } - if (int_events & FEC_ENET_MII) { - ret = IRQ_HANDLED; - complete(&fep->mdio_done); - } - } while (int_events); + if (int_events & FEC_ENET_MII) { + ret = IRQ_HANDLED; + complete(&fep->mdio_done); + } return ret; } @@ -1399,8 +1395,16 @@ fec_enet_interrupt(int irq, void *dev_id) static int fec_enet_rx_napi(struct napi_struct *napi, int budget) { struct net_device *ndev = napi->dev; - int pkts = fec_enet_rx(ndev, budget); struct fec_enet_private *fep = netdev_priv(ndev); + int pkts; + + /* + * Clear any pending transmit or receive interrupts before + * processing the rings to avoid racing with the hardware. + */ + writel(FEC_ENET_RXF | FEC_ENET_TXF, fep->hwp + FEC_IEVENT); + + pkts = fec_enet_rx(ndev, budget); fec_enet_tx(ndev); -- cgit v1.2.3 From b49cd504c46dd729011049c91cf11ea72df01aef Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 00:22:49 +0100 Subject: net: fec: use netif_tx_disable() rather than netif_stop_queue() We use netif_stop_queue() in several places where we want to ensure that the start_xmit function is not running. netif_stop_queue() is not sufficient to achieve that - it merely sets a flag to indicate that the transmit queue(s) should not be run. netif_tx_disable() gives this guarantee, since it takes the transmit queue lock while marking the queue stopped. This will wait for the transmit function to complete before returning. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 4e695b742030..cb9ced738607 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -834,7 +834,7 @@ fec_restart(struct net_device *ndev, int duplex) if (netif_running(ndev)) { netif_device_detach(ndev); napi_disable(&fep->napi); - netif_stop_queue(ndev); + netif_tx_disable(ndev); netif_tx_lock_bh(ndev); } @@ -2181,7 +2181,7 @@ fec_enet_close(struct net_device *ndev) /* Don't know what to do yet. */ napi_disable(&fep->napi); fep->opened = 0; - netif_stop_queue(ndev); + netif_tx_disable(ndev); fec_stop(ndev); if (fep->phy_dev) { -- cgit v1.2.3 From 635cf17ce220aa4fef93528775646e0a181b2dc2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 00:22:54 +0100 Subject: net: fec: remove checking for NULL phy_dev in fec_enet_close() fep->phy_dev can not be NULL here for two reasons: - fec_enet_open() will have successfully connected the phy, or will have failed. - fec_enet_open() will have called phy_start(fep->phy_dev), which unconditionally dereferences this pointer. If it were to be NULL here, then fec_enet_open() will have already oopsed. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index cb9ced738607..6a03d7eced4d 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2184,10 +2184,8 @@ fec_enet_close(struct net_device *ndev) netif_tx_disable(ndev); fec_stop(ndev); - if (fep->phy_dev) { - phy_stop(fep->phy_dev); - phy_disconnect(fep->phy_dev); - } + phy_stop(fep->phy_dev); + phy_disconnect(fep->phy_dev); fec_enet_clk_enable(ndev, false); pinctrl_pm_select_sleep_state(&fep->pdev->dev); -- cgit v1.2.3 From 0b146ca8d467c1dc6ad50628089d183608a47e40 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 00:22:59 +0100 Subject: net: fec: ensure that a disconnected phy isn't configured When we disconnect from a phy, we should forget our pointer to it so we don't accidentally try to configure it. We handle a NULL phy pointer correctly in most places, except fec_enet_set_pauseparam(). Fix this too. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 6a03d7eced4d..cf805468eecc 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1875,6 +1875,9 @@ static int fec_enet_set_pauseparam(struct net_device *ndev, { struct fec_enet_private *fep = netdev_priv(ndev); + if (!fep->phy_dev) + return -ENODEV; + if (pause->tx_pause != pause->rx_pause) { netdev_info(ndev, "hardware only support enable/disable both tx and rx"); @@ -2186,6 +2189,7 @@ fec_enet_close(struct net_device *ndev) phy_stop(fep->phy_dev); phy_disconnect(fep->phy_dev); + fep->phy_dev = NULL; fec_enet_clk_enable(ndev, false); pinctrl_pm_select_sleep_state(&fep->pdev->dev); -- cgit v1.2.3 From d76cfae9674f325de35ff23ab07ff9c7d809de4a Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 00:23:04 +0100 Subject: net: fec: stop the phy before shutting down the MAC When the network interface goes down, stop the phy to prevent further link up status changes before taking the MAC or netif sections down. This prevents further reception of link up events which could potentially call fec_restart(). Since phy_stop() takes the mutex which adjust_link() runs under, we also ensure that adjust_link() will not already be processing a link up event. We also need to do this when suspending as well - we don't want a mis-timed phy state change to restart the MAC after we have stopped it for suspend, and thus need to restart the phy when resuming. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index cf805468eecc..e0a1ac1826b7 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2181,13 +2181,14 @@ fec_enet_close(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); + phy_stop(fep->phy_dev); + /* Don't know what to do yet. */ napi_disable(&fep->napi); fep->opened = 0; netif_tx_disable(ndev); fec_stop(ndev); - phy_stop(fep->phy_dev); phy_disconnect(fep->phy_dev); fep->phy_dev = NULL; @@ -2669,6 +2670,7 @@ fec_suspend(struct device *dev) struct fec_enet_private *fep = netdev_priv(ndev); if (netif_running(ndev)) { + phy_stop(fep->phy_dev); fec_stop(ndev); netif_device_detach(ndev); } @@ -2702,6 +2704,7 @@ fec_resume(struct device *dev) if (netif_running(ndev)) { fec_restart(ndev, fep->full_duplex); netif_device_attach(ndev); + phy_start(fep->phy_dev); } return 0; -- cgit v1.2.3 From 5d165c5543fbcbd26e443ee501063decb4ef73b4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 00:23:09 +0100 Subject: net: fec: remove useless fep->opened napi_disable() waits until the NAPI processing has completed, and then prevents any further polls. At this point, the driver then clears fep->opened. The NAPI poll function uses this to stop processing in the receive path. Hence, it will never see this variable cleared, because the NAPI poll has to complete before it will be cleared. Therefore, this variable serves no purpose, so let's remove it. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec.h | 1 - drivers/net/ethernet/freescale/fec_main.c | 5 ----- 2 files changed, 6 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 671d080105a7..96d2a18f1b99 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -308,7 +308,6 @@ struct fec_enet_private { struct platform_device *pdev; - int opened; int dev_id; /* Phylib and MDIO interface */ diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index e0a1ac1826b7..309aa2ff8cc9 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1215,9 +1215,6 @@ fec_enet_rx(struct net_device *ndev, int budget) if ((status & BD_ENET_RX_LAST) == 0) netdev_err(ndev, "rcv is not +last\n"); - if (!fep->opened) - goto rx_processing_done; - /* Check for errors. */ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { @@ -2172,7 +2169,6 @@ fec_enet_open(struct net_device *ndev) napi_enable(&fep->napi); phy_start(fep->phy_dev); netif_start_queue(ndev); - fep->opened = 1; return 0; } @@ -2185,7 +2181,6 @@ fec_enet_close(struct net_device *ndev) /* Don't know what to do yet. */ napi_disable(&fep->napi); - fep->opened = 0; netif_tx_disable(ndev); fec_stop(ndev); -- cgit v1.2.3 From 730ee3602f300b5133717048859358a02251322f Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 00:23:14 +0100 Subject: net: fec: make rx skb handling more robust Allocate, and then map the receive skb before writing any data to the ring descriptor or storing the skb. When freeing the receive ring entries, unmap and free the skb, and then clear the stored skb pointer. This means we have ring data and skb pointer in one of two states: either both fully setup, or nothing setup. This simplifies the cleanup, as we can use just the skb pointer to indicate whether the descriptor is setup, and thus avoids potentially calling dma_unmap_single() on a DMA error value. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 309aa2ff8cc9..70853a59627a 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2066,12 +2066,12 @@ static void fec_enet_free_buffers(struct net_device *ndev) bdp = fep->rx_bd_base; for (i = 0; i < fep->rx_ring_size; i++) { skb = fep->rx_skbuff[i]; - - if (bdp->cbd_bufaddr) + fep->rx_skbuff[i] = NULL; + if (skb) { dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); - if (skb) dev_kfree_skb(skb); + } bdp = fec_enet_get_nextdesc(bdp, fep); } @@ -2089,21 +2089,26 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) bdp = fep->rx_bd_base; for (i = 0; i < fep->rx_ring_size; i++) { + dma_addr_t addr; + skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE); if (!skb) { fec_enet_free_buffers(ndev); return -ENOMEM; } - fep->rx_skbuff[i] = skb; - bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data, + addr = dma_map_single(&fep->pdev->dev, skb->data, FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); - if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { + if (dma_mapping_error(&fep->pdev->dev, addr)) { + dev_kfree_skb(skb); fec_enet_free_buffers(ndev); if (net_ratelimit()) netdev_err(ndev, "Rx DMA memory map failed\n"); return -ENOMEM; } + + fep->rx_skbuff[i] = skb; + bdp->cbd_bufaddr = addr; bdp->cbd_sc = BD_ENET_RX_EMPTY; if (fep->bufdesc_ex) { -- cgit v1.2.3 From d6bf31431b533629ad65feb954c29bbf5696e490 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 00:23:19 +0100 Subject: net: fec: clean up transmit descriptor setup Avoid writing any state until we're certain we can proceed with the transmission: this avoids writing mapping error address values to the descriptors, or setting the skbuff pointer until we have successfully mapped the skb. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 33 +++++++++++++++++-------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 70853a59627a..9c5570a3e32e 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -373,6 +373,7 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev) skb_frag_t *this_frag; unsigned int index; void *bufaddr; + dma_addr_t addr; int i; for (frag = 0; frag < nr_frags; frag++) { @@ -415,15 +416,16 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev) swap_buffer(bufaddr, frag_len); } - bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr, - frag_len, DMA_TO_DEVICE); - if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { + addr = dma_map_single(&fep->pdev->dev, bufaddr, frag_len, + DMA_TO_DEVICE); + if (dma_mapping_error(&fep->pdev->dev, addr)) { dev_kfree_skb_any(skb); if (net_ratelimit()) netdev_err(ndev, "Tx DMA memory map failed\n"); goto dma_mapping_error; } + bdp->cbd_bufaddr = addr; bdp->cbd_datlen = frag_len; bdp->cbd_sc = status; } @@ -450,6 +452,7 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev) int nr_frags = skb_shinfo(skb)->nr_frags; struct bufdesc *bdp, *last_bdp; void *bufaddr; + dma_addr_t addr; unsigned short status; unsigned short buflen; unsigned int estatus = 0; @@ -490,12 +493,9 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev) swap_buffer(bufaddr, buflen); } - /* Push the data cache so the CPM does not get stale memory - * data. - */ - bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr, - buflen, DMA_TO_DEVICE); - if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { + /* Push the data cache so the CPM does not get stale memory data. */ + addr = dma_map_single(&fep->pdev->dev, bufaddr, buflen, DMA_TO_DEVICE); + if (dma_mapping_error(&fep->pdev->dev, addr)) { dev_kfree_skb_any(skb); if (net_ratelimit()) netdev_err(ndev, "Tx DMA memory map failed\n"); @@ -537,6 +537,7 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev) fep->tx_skbuff[index] = skb; bdp->cbd_datlen = buflen; + bdp->cbd_bufaddr = addr; /* Send it on its way. Tell FEC it's ready, interrupt when done, * it's the last BD of the frame, and to put the CRC on the end. @@ -570,12 +571,12 @@ fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev, struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; unsigned short status; unsigned int estatus = 0; + dma_addr_t addr; status = bdp->cbd_sc; status &= ~BD_ENET_TX_STATS; status |= (BD_ENET_TX_TC | BD_ENET_TX_READY); - bdp->cbd_datlen = size; if (((unsigned long) data) & FEC_ALIGNMENT || id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) { @@ -586,15 +587,17 @@ fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev, swap_buffer(data, size); } - bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data, - size, DMA_TO_DEVICE); - if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { + addr = dma_map_single(&fep->pdev->dev, data, size, DMA_TO_DEVICE); + if (dma_mapping_error(&fep->pdev->dev, addr)) { dev_kfree_skb_any(skb); if (net_ratelimit()) netdev_err(ndev, "Tx DMA memory map failed\n"); return NETDEV_TX_BUSY; } + bdp->cbd_datlen = size; + bdp->cbd_bufaddr = addr; + if (fep->bufdesc_ex) { if (skb->ip_summed == CHECKSUM_PARTIAL) estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS; @@ -801,7 +804,7 @@ static void fec_enet_bd_init(struct net_device *dev) /* Initialize the BD for every fragment in the page. */ bdp->cbd_sc = 0; - if (bdp->cbd_bufaddr && fep->tx_skbuff[i]) { + if (fep->tx_skbuff[i]) { dev_kfree_skb_any(fep->tx_skbuff[i]); fep->tx_skbuff[i] = NULL; } @@ -1100,6 +1103,7 @@ fec_enet_tx(struct net_device *ndev) index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep); skb = fep->tx_skbuff[index]; + fep->tx_skbuff[index] = NULL; if (!IS_TSO_HEADER(fep, bdp->cbd_bufaddr)) dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, bdp->cbd_datlen, DMA_TO_DEVICE); @@ -1154,7 +1158,6 @@ fec_enet_tx(struct net_device *ndev) /* Free the sk buffer associated with this last transmit */ dev_kfree_skb_any(skb); - fep->tx_skbuff[index] = NULL; fep->dirty_tx = bdp; -- cgit v1.2.3 From 8b7c9efa018f96e58fa379ddb8c03f002c4f6a84 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 00:23:25 +0100 Subject: net: fec: ensure fec_enet_free_buffers() properly cleans the rings Ensure that we do not double-free any allocations, and that any transmit skbuffs are properly freed when we clean up the rings. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 9c5570a3e32e..5499bd8ad0a5 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2079,8 +2079,13 @@ static void fec_enet_free_buffers(struct net_device *ndev) } bdp = fep->tx_bd_base; - for (i = 0; i < fep->tx_ring_size; i++) + for (i = 0; i < fep->tx_ring_size; i++) { kfree(fep->tx_bounce[i]); + fep->tx_bounce[i] = NULL; + skb = fep->tx_skbuff[i]; + fep->tx_skbuff[i] = NULL; + dev_kfree_skb(skb); + } } static int fec_enet_alloc_buffers(struct net_device *ndev) -- cgit v1.2.3 From ffdce2cc6a18e3460fd31a399934004bf4cf6539 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 00:23:30 +0100 Subject: net: fec: fix missing kmalloc() failure check in fec_enet_alloc_buffers() fec_enet_alloc_buffers() assumes that kmalloc() will never fail, which is an invalid assumption. Fix this by implementing a common error cleanup path, and use it to also clean up after failed bounce buffer allocation. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 5499bd8ad0a5..f43c388e2eb9 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2100,19 +2100,16 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) dma_addr_t addr; skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE); - if (!skb) { - fec_enet_free_buffers(ndev); - return -ENOMEM; - } + if (!skb) + goto err_alloc; addr = dma_map_single(&fep->pdev->dev, skb->data, FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); if (dma_mapping_error(&fep->pdev->dev, addr)) { dev_kfree_skb(skb); - fec_enet_free_buffers(ndev); if (net_ratelimit()) netdev_err(ndev, "Rx DMA memory map failed\n"); - return -ENOMEM; + goto err_alloc; } fep->rx_skbuff[i] = skb; @@ -2134,6 +2131,8 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) bdp = fep->tx_bd_base; for (i = 0; i < fep->tx_ring_size; i++) { fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL); + if (!fep->tx_bounce[i]) + goto err_alloc; bdp->cbd_sc = 0; bdp->cbd_bufaddr = 0; @@ -2151,6 +2150,10 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) bdp->cbd_sc |= BD_SC_WRAP; return 0; + + err_alloc: + fec_enet_free_buffers(ndev); + return -ENOMEM; } static int -- cgit v1.2.3 From 640985ec2ffd2a81f34dc5004f0951d2c6cb3d5e Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:43 +0200 Subject: mac802154: at86rf230: add hw flags and merge ops This patch adds new mac802154 hw flags for transmit power, csma and listen before transmit (lbt). These flags indicates that the transceiver supports these features. If the flags are set and the driver doesn't implement the necessary functions, then ieee802154_register_device returns -ENOSYS "Function not implemented". This patch merges also all at86rf230 operations into one operations structure and set the right hw flags for the at86rf230 transceivers. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 81 +++++++++++++++++--------------------- include/net/mac802154.h | 19 +++++++++ net/mac802154/ieee802154_dev.c | 60 +++++++++++++++++++++------- 3 files changed, 102 insertions(+), 58 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 50899416f668..dca6bae1402c 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -784,7 +784,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev, } static int -at86rf212_set_txpower(struct ieee802154_dev *dev, int db) +at86rf230_set_txpower(struct ieee802154_dev *dev, int db) { struct at86rf230_local *lp = dev->priv; @@ -803,7 +803,7 @@ at86rf212_set_txpower(struct ieee802154_dev *dev, int db) } static int -at86rf212_set_lbt(struct ieee802154_dev *dev, bool on) +at86rf230_set_lbt(struct ieee802154_dev *dev, bool on) { struct at86rf230_local *lp = dev->priv; @@ -811,7 +811,7 @@ at86rf212_set_lbt(struct ieee802154_dev *dev, bool on) } static int -at86rf212_set_cca_mode(struct ieee802154_dev *dev, u8 mode) +at86rf230_set_cca_mode(struct ieee802154_dev *dev, u8 mode) { struct at86rf230_local *lp = dev->priv; @@ -819,7 +819,7 @@ at86rf212_set_cca_mode(struct ieee802154_dev *dev, u8 mode) } static int -at86rf212_set_cca_ed_level(struct ieee802154_dev *dev, s32 level) +at86rf230_set_cca_ed_level(struct ieee802154_dev *dev, s32 level) { struct at86rf230_local *lp = dev->priv; int desens_steps; @@ -833,7 +833,7 @@ at86rf212_set_cca_ed_level(struct ieee802154_dev *dev, s32 level) } static int -at86rf212_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be, +at86rf230_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be, u8 retries) { struct at86rf230_local *lp = dev->priv; @@ -854,7 +854,7 @@ at86rf212_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be, } static int -at86rf212_set_frame_retries(struct ieee802154_dev *dev, s8 retries) +at86rf230_set_frame_retries(struct ieee802154_dev *dev, s8 retries) { struct at86rf230_local *lp = dev->priv; int rc = 0; @@ -878,22 +878,12 @@ static struct ieee802154_ops at86rf230_ops = { .start = at86rf230_start, .stop = at86rf230_stop, .set_hw_addr_filt = at86rf230_set_hw_addr_filt, -}; - -static struct ieee802154_ops at86rf212_ops = { - .owner = THIS_MODULE, - .xmit = at86rf230_xmit, - .ed = at86rf230_ed, - .set_channel = at86rf230_channel, - .start = at86rf230_start, - .stop = at86rf230_stop, - .set_hw_addr_filt = at86rf230_set_hw_addr_filt, - .set_txpower = at86rf212_set_txpower, - .set_lbt = at86rf212_set_lbt, - .set_cca_mode = at86rf212_set_cca_mode, - .set_cca_ed_level = at86rf212_set_cca_ed_level, - .set_csma_params = at86rf212_set_csma_params, - .set_frame_retries = at86rf212_set_frame_retries, + .set_txpower = at86rf230_set_txpower, + .set_lbt = at86rf230_set_lbt, + .set_cca_mode = at86rf230_set_cca_mode, + .set_cca_ed_level = at86rf230_set_cca_ed_level, + .set_csma_params = at86rf230_set_csma_params, + .set_frame_retries = at86rf230_set_frame_retries, }; static void at86rf230_irqwork(struct work_struct *work) @@ -1048,7 +1038,6 @@ static int at86rf230_probe(struct spi_device *spi) work_func_t irq_worker; int rc, irq_type; const char *chip; - struct ieee802154_ops *ops = NULL; if (!spi->irq) { dev_err(&spi->dev, "no IRQ specified\n"); @@ -1084,9 +1073,25 @@ static int at86rf230_probe(struct spi_device *spi) usleep_range(120, 240); } + dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops); + if (!dev) + return -ENOMEM; + + lp = dev->priv; + lp->dev = dev; + lp->part = part; + lp->vers = version; + + lp->spi = spi; + + dev->parent = &spi->dev; + dev->extra_tx_headroom = 0; + dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | + IEEE802154_HW_TXPOWER | IEEE802154_HW_CSMA; + rc = __at86rf230_detect_device(spi, &man_id, &part, &version); if (rc < 0) - return rc; + goto free_dev; if (man_id != 0x001f) { dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n", @@ -1097,44 +1102,31 @@ static int at86rf230_probe(struct spi_device *spi) switch (part) { case 2: chip = "at86rf230"; + rc = -ENOTSUPP; /* FIXME: should be easy to support; */ break; case 3: chip = "at86rf231"; - ops = &at86rf230_ops; break; case 7: chip = "at86rf212"; if (version == 1) - ops = &at86rf212_ops; + dev->flags |= IEEE802154_HW_LBT; + else + rc = -ENOTSUPP; break; case 11: chip = "at86rf233"; - ops = &at86rf230_ops; break; default: chip = "UNKNOWN"; + rc = -ENOTSUPP; break; } dev_info(&spi->dev, "Detected %s chip version %d\n", chip, version); - if (!ops) - return -ENOTSUPP; - - dev = ieee802154_alloc_device(sizeof(*lp), ops); - if (!dev) - return -ENOMEM; - - lp = dev->priv; - lp->dev = dev; - lp->part = part; - lp->vers = version; - - lp->spi = spi; - - dev->parent = &spi->dev; - dev->extra_tx_headroom = 0; - dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK; + if (rc < 0) + goto free_dev; irq_type = irq_get_trigger_type(spi->irq); if (!irq_type) @@ -1185,6 +1177,7 @@ static int at86rf230_probe(struct spi_device *spi) err_hw_init: flush_work(&lp->irqwork); mutex_destroy(&lp->bmux); +free_dev: ieee802154_free_device(lp->dev); return rc; diff --git a/include/net/mac802154.h b/include/net/mac802154.h index a591053cae63..2e67cdd19cdc 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -80,6 +80,25 @@ struct ieee802154_dev { #define IEEE802154_HW_OMIT_CKSUM 0x00000001 /* Indicates that receiver will autorespond with ACK frames. */ #define IEEE802154_HW_AACK 0x00000002 +/* Indicates that transceiver will support transmit power setting. */ +#define IEEE802154_HW_TXPOWER 0x00000004 +/* Indicates that transceiver will support listen before transmit. */ +#define IEEE802154_HW_LBT 0x00000008 +/* Indicates that transceiver will support cca mode setting. */ +#define IEEE802154_HW_CCA_MODE 0x00000010 +/* Indicates that transceiver will support cca ed level setting. */ +#define IEEE802154_HW_CCA_ED_LEVEL 0x00000020 +/* Indicates that transceiver will support csma (max_be, min_be, csma retries) + * settings. */ +#define IEEE802154_HW_CSMA_PARAMS 0x00000040 +/* Indicates that transceiver will support ARET frame retries setting. */ +#define IEEE802154_HW_FRAME_RETRIES 0x00000080 + +/* This groups the most common CSMA support fields into one. */ +#define IEEE802154_HW_CSMA (IEEE802154_HW_CCA_MODE | \ + IEEE802154_HW_CCA_ED_LEVEL | \ + IEEE802154_HW_CSMA_PARAMS | \ + IEEE802154_HW_FRAME_RETRIES) /* struct ieee802154_ops - callbacks from mac802154 to the driver * diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c index c4d4568611ca..9b54370f5e87 100644 --- a/net/mac802154/ieee802154_dev.c +++ b/net/mac802154/ieee802154_dev.c @@ -304,29 +304,61 @@ EXPORT_SYMBOL(ieee802154_free_device); int ieee802154_register_device(struct ieee802154_dev *dev) { struct mac802154_priv *priv = mac802154_to_priv(dev); - int rc = -ENOMEM; + int rc = -ENOSYS; + + if (dev->flags & IEEE802154_HW_TXPOWER) { + if (!priv->ops->set_txpower) + goto out; + + priv->phy->set_txpower = mac802154_set_txpower; + } + + if (dev->flags & IEEE802154_HW_LBT) { + if (!priv->ops->set_lbt) + goto out; + + priv->phy->set_lbt = mac802154_set_lbt; + } + + if (dev->flags & IEEE802154_HW_CCA_MODE) { + if (!priv->ops->set_cca_mode) + goto out; + + priv->phy->set_cca_mode = mac802154_set_cca_mode; + } + + if (dev->flags & IEEE802154_HW_CCA_ED_LEVEL) { + if (!priv->ops->set_cca_ed_level) + goto out; + + priv->phy->set_cca_ed_level = mac802154_set_cca_ed_level; + } + + if (dev->flags & IEEE802154_HW_CSMA_PARAMS) { + if (!priv->ops->set_csma_params) + goto out; + + priv->phy->set_csma_params = mac802154_set_csma_params; + } + + if (dev->flags & IEEE802154_HW_FRAME_RETRIES) { + if (!priv->ops->set_frame_retries) + goto out; + + priv->phy->set_frame_retries = mac802154_set_frame_retries; + } priv->dev_workqueue = create_singlethread_workqueue(wpan_phy_name(priv->phy)); - if (!priv->dev_workqueue) + if (!priv->dev_workqueue) { + rc = -ENOMEM; goto out; + } wpan_phy_set_dev(priv->phy, priv->hw.parent); priv->phy->add_iface = mac802154_add_iface; priv->phy->del_iface = mac802154_del_iface; - if (priv->ops->set_txpower) - priv->phy->set_txpower = mac802154_set_txpower; - if (priv->ops->set_lbt) - priv->phy->set_lbt = mac802154_set_lbt; - if (priv->ops->set_cca_mode) - priv->phy->set_cca_mode = mac802154_set_cca_mode; - if (priv->ops->set_cca_ed_level) - priv->phy->set_cca_ed_level = mac802154_set_cca_ed_level; - if (priv->ops->set_csma_params) - priv->phy->set_csma_params = mac802154_set_csma_params; - if (priv->ops->set_frame_retries) - priv->phy->set_frame_retries = mac802154_set_frame_retries; rc = wpan_phy_register(priv->phy); if (rc < 0) -- cgit v1.2.3 From f76014f770ff2d4e26c82e4e3a5b0928dee1969b Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:44 +0200 Subject: at86rf230: add regmap support This patch adds regmap support for the at86rf230 driver and drop the lowlevel spi access functions and use the regmap access functions. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/Kconfig | 1 + drivers/net/ieee802154/at86rf230.c | 272 +++++++++++++++++++++++-------------- 2 files changed, 168 insertions(+), 105 deletions(-) diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig index 8b7ae51f30f5..391a916622a9 100644 --- a/drivers/net/ieee802154/Kconfig +++ b/drivers/net/ieee802154/Kconfig @@ -34,6 +34,7 @@ config IEEE802154_AT86RF230 depends on IEEE802154_DRIVERS && MAC802154 tristate "AT86RF230/231/233/212 transceiver driver" depends on SPI + select REGMAP_SPI ---help--- Say Y here to enable the at86rf230/231/233/212 SPI 802.15.4 wireless controller. diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index dca6bae1402c..e3697038bd6d 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,7 @@ struct at86rf230_local { struct completion tx_complete; struct ieee802154_dev *dev; + struct regmap *regmap; spinlock_t lock; bool irq_busy; @@ -256,6 +258,157 @@ static bool is_rf212(struct at86rf230_local *local) #define STATE_BUSY_RX_AACK_NOCLK 0x1E #define STATE_TRANSITION_IN_PROGRESS 0x1F +#define AT86RF2XX_NUMREGS 0x3F + +static inline int +__at86rf230_write(struct at86rf230_local *lp, + unsigned int addr, unsigned int data) +{ + return regmap_write(lp->regmap, addr, data); +} + +static inline int +__at86rf230_read(struct at86rf230_local *lp, + unsigned int addr, unsigned int *data) +{ + return regmap_read(lp->regmap, addr, data); +} + +static inline int +at86rf230_read_subreg(struct at86rf230_local *lp, + unsigned int addr, unsigned int mask, + unsigned int shift, unsigned int *data) +{ + int rc; + + rc = __at86rf230_read(lp, addr, data); + if (rc > 0) + *data = (*data & mask) >> shift; + + return rc; +} + +static inline int +at86rf230_write_subreg(struct at86rf230_local *lp, + unsigned int addr, unsigned int mask, + unsigned int shift, unsigned int data) +{ + return regmap_update_bits(lp->regmap, addr, mask, data << shift); +} + +static bool +at86rf230_reg_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RG_TRX_STATE: + case RG_TRX_CTRL_0: + case RG_TRX_CTRL_1: + case RG_PHY_TX_PWR: + case RG_PHY_ED_LEVEL: + case RG_PHY_CC_CCA: + case RG_CCA_THRES: + case RG_RX_CTRL: + case RG_SFD_VALUE: + case RG_TRX_CTRL_2: + case RG_ANT_DIV: + case RG_IRQ_MASK: + case RG_VREG_CTRL: + case RG_BATMON: + case RG_XOSC_CTRL: + case RG_RX_SYN: + case RG_XAH_CTRL_1: + case RG_FTN_CTRL: + case RG_PLL_CF: + case RG_PLL_DCU: + case RG_SHORT_ADDR_0: + case RG_SHORT_ADDR_1: + case RG_PAN_ID_0: + case RG_PAN_ID_1: + case RG_IEEE_ADDR_0: + case RG_IEEE_ADDR_1: + case RG_IEEE_ADDR_2: + case RG_IEEE_ADDR_3: + case RG_IEEE_ADDR_4: + case RG_IEEE_ADDR_5: + case RG_IEEE_ADDR_6: + case RG_IEEE_ADDR_7: + case RG_XAH_CTRL_0: + case RG_CSMA_SEED_0: + case RG_CSMA_SEED_1: + case RG_CSMA_BE: + return true; + default: + return false; + } +} + +static bool +at86rf230_reg_readable(struct device *dev, unsigned int reg) +{ + bool rc; + + /* all writeable are also readable */ + rc = at86rf230_reg_writeable(dev, reg); + if (rc) + return rc; + + /* readonly regs */ + switch (reg) { + case RG_TRX_STATUS: + case RG_PHY_RSSI: + case RG_IRQ_STATUS: + case RG_PART_NUM: + case RG_VERSION_NUM: + case RG_MAN_ID_1: + case RG_MAN_ID_0: + return true; + default: + return false; + } +} + +static bool +at86rf230_reg_volatile(struct device *dev, unsigned int reg) +{ + /* can be changed during runtime */ + switch (reg) { + case RG_TRX_STATUS: + case RG_TRX_STATE: + case RG_PHY_RSSI: + case RG_PHY_ED_LEVEL: + case RG_IRQ_STATUS: + case RG_VREG_CTRL: + return true; + default: + return false; + } +} + +static bool +at86rf230_reg_precious(struct device *dev, unsigned int reg) +{ + /* don't clear irq line on read */ + switch (reg) { + case RG_IRQ_STATUS: + return true; + default: + return false; + } +} + +static struct regmap_config at86rf230_regmap_spi_config = { + .reg_bits = 8, + .val_bits = 8, + .write_flag_mask = CMD_REG | CMD_WRITE, + .read_flag_mask = CMD_REG, + .cache_type = REGCACHE_RBTREE, + .max_register = AT86RF2XX_NUMREGS, + .writeable_reg = at86rf230_reg_writeable, + .readable_reg = at86rf230_reg_readable, + .volatile_reg = at86rf230_reg_volatile, + .precious_reg = at86rf230_reg_precious, +}; + static int __at86rf230_detect_device(struct spi_device *spi, u16 *man_id, u8 *part, u8 *version) @@ -307,105 +460,6 @@ __at86rf230_detect_device(struct spi_device *spi, u16 *man_id, u8 *part, return status; } -static int -__at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data) -{ - u8 *buf = lp->buf; - int status; - struct spi_message msg; - struct spi_transfer xfer = { - .len = 2, - .tx_buf = buf, - }; - - buf[0] = (addr & CMD_REG_MASK) | CMD_REG | CMD_WRITE; - buf[1] = data; - dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]); - dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]); - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - - status = spi_sync(lp->spi, &msg); - dev_vdbg(&lp->spi->dev, "status = %d\n", status); - if (msg.status) - status = msg.status; - - dev_vdbg(&lp->spi->dev, "status = %d\n", status); - dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]); - dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]); - - return status; -} - -static int -__at86rf230_read_subreg(struct at86rf230_local *lp, - u8 addr, u8 mask, int shift, u8 *data) -{ - u8 *buf = lp->buf; - int status; - struct spi_message msg; - struct spi_transfer xfer = { - .len = 2, - .tx_buf = buf, - .rx_buf = buf, - }; - - buf[0] = (addr & CMD_REG_MASK) | CMD_REG; - buf[1] = 0xff; - dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]); - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - - status = spi_sync(lp->spi, &msg); - dev_vdbg(&lp->spi->dev, "status = %d\n", status); - if (msg.status) - status = msg.status; - - dev_vdbg(&lp->spi->dev, "status = %d\n", status); - dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]); - dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]); - - if (status == 0) - *data = (buf[1] & mask) >> shift; - - return status; -} - -static int -at86rf230_read_subreg(struct at86rf230_local *lp, - u8 addr, u8 mask, int shift, u8 *data) -{ - int status; - - mutex_lock(&lp->bmux); - status = __at86rf230_read_subreg(lp, addr, mask, shift, data); - mutex_unlock(&lp->bmux); - - return status; -} - -static int -at86rf230_write_subreg(struct at86rf230_local *lp, - u8 addr, u8 mask, int shift, u8 data) -{ - int status; - u8 val; - - mutex_lock(&lp->bmux); - status = __at86rf230_read_subreg(lp, addr, 0xff, 0, &val); - if (status) - goto out; - - val &= ~mask; - val |= (data << shift) & mask; - - status = __at86rf230_write(lp, addr, val); -out: - mutex_unlock(&lp->bmux); - - return status; -} - static int at86rf230_write_fbuf(struct at86rf230_local *lp, u8 *data, u8 len) { @@ -520,7 +574,7 @@ at86rf230_state(struct ieee802154_dev *dev, int state) { struct at86rf230_local *lp = dev->priv; int rc; - u8 val; + unsigned int val; u8 desired_status; might_sleep(); @@ -890,12 +944,11 @@ static void at86rf230_irqwork(struct work_struct *work) { struct at86rf230_local *lp = container_of(work, struct at86rf230_local, irqwork); - u8 status = 0, val; + unsigned int status; int rc; unsigned long flags; - rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &val); - status |= val; + rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status); status &= ~IRQ_PLL_LOCK; /* ignore */ status &= ~IRQ_RX_START; /* ignore */ @@ -954,7 +1007,7 @@ static irqreturn_t at86rf230_isr_level(int irq, void *data) static int at86rf230_hw_init(struct at86rf230_local *lp) { int rc, irq_pol, irq_type; - u8 dvdd; + unsigned int dvdd; u8 csma_seed[2]; rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_FORCE_TRX_OFF); @@ -1033,7 +1086,8 @@ static int at86rf230_probe(struct spi_device *spi) struct ieee802154_dev *dev; struct at86rf230_local *lp; u16 man_id = 0; - u8 part = 0, version = 0, status; + u8 part = 0, version = 0; + unsigned int status; irq_handler_t irq_handler; work_func_t irq_worker; int rc, irq_type; @@ -1128,6 +1182,14 @@ static int at86rf230_probe(struct spi_device *spi) if (rc < 0) goto free_dev; + lp->regmap = devm_regmap_init_spi(spi, &at86rf230_regmap_spi_config); + if (IS_ERR(lp->regmap)) { + rc = PTR_ERR(lp->regmap); + dev_err(&spi->dev, "Failed to allocate register map: %d\n", + rc); + goto free_dev; + } + irq_type = irq_get_trigger_type(spi->irq); if (!irq_type) irq_type = IRQF_TRIGGER_RISING; -- cgit v1.2.3 From c8ee0f56c833d70a03f06bf809089423dd190ee8 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:45 +0200 Subject: at86rf230: rework detect device handling This patch drops the current lowlevel spi calls for the detect device function instead we handle this via regmap. Also put the detection of in a seperate function and set all device specific attributes while detection. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 183 +++++++++++++++---------------------- 1 file changed, 76 insertions(+), 107 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index e3697038bd6d..7d96cd410edb 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -409,57 +409,6 @@ static struct regmap_config at86rf230_regmap_spi_config = { .precious_reg = at86rf230_reg_precious, }; -static int -__at86rf230_detect_device(struct spi_device *spi, u16 *man_id, u8 *part, - u8 *version) -{ - u8 data[4]; - u8 *buf = kmalloc(2, GFP_KERNEL); - int status; - struct spi_message msg; - struct spi_transfer xfer = { - .len = 2, - .tx_buf = buf, - .rx_buf = buf, - }; - u8 reg; - - if (!buf) - return -ENOMEM; - - for (reg = RG_PART_NUM; reg <= RG_MAN_ID_1; reg++) { - buf[0] = (reg & CMD_REG_MASK) | CMD_REG; - buf[1] = 0xff; - dev_vdbg(&spi->dev, "buf[0] = %02x\n", buf[0]); - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - - status = spi_sync(spi, &msg); - dev_vdbg(&spi->dev, "status = %d\n", status); - if (msg.status) - status = msg.status; - - dev_vdbg(&spi->dev, "status = %d\n", status); - dev_vdbg(&spi->dev, "buf[0] = %02x\n", buf[0]); - dev_vdbg(&spi->dev, "buf[1] = %02x\n", buf[1]); - - if (status == 0) - data[reg - RG_PART_NUM] = buf[1]; - else - break; - } - - if (status == 0) { - *part = data[0]; - *version = data[1]; - *man_id = (data[3] << 8) | data[2]; - } - - kfree(buf); - - return status; -} - static int at86rf230_write_fbuf(struct at86rf230_local *lp, u8 *data, u8 len) { @@ -1080,18 +1029,87 @@ done: return pdata; } +static int +at86rf230_detect_device(struct at86rf230_local *lp) +{ + unsigned int part, version, val; + u16 man_id = 0; + const char *chip; + int rc; + + rc = __at86rf230_read(lp, RG_MAN_ID_0, &val); + if (rc) + return rc; + man_id |= val; + + rc = __at86rf230_read(lp, RG_MAN_ID_1, &val); + if (rc) + return rc; + man_id |= (val << 8); + + rc = __at86rf230_read(lp, RG_PART_NUM, &part); + if (rc) + return rc; + + rc = __at86rf230_read(lp, RG_PART_NUM, &version); + if (rc) + return rc; + + if (man_id != 0x001f) { + dev_err(&lp->spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n", + man_id >> 8, man_id & 0xFF); + return -EINVAL; + } + + lp->part = part; + lp->vers = version; + lp->dev->extra_tx_headroom = 0; + lp->dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | + IEEE802154_HW_TXPOWER | IEEE802154_HW_CSMA; + + switch (part) { + case 2: + chip = "at86rf230"; + rc = -ENOTSUPP; + break; + case 3: + chip = "at86rf231"; + lp->dev->phy->channels_supported[0] = 0x7FFF800; + break; + case 7: + chip = "at86rf212"; + if (version == 1) { + lp->dev->flags |= IEEE802154_HW_LBT; + lp->dev->phy->channels_supported[0] = 0x00007FF; + lp->dev->phy->channels_supported[2] = 0x00007FF; + } else { + rc = -ENOTSUPP; + } + break; + case 11: + chip = "at86rf233"; + lp->dev->phy->channels_supported[0] = 0x7FFF800; + break; + default: + chip = "unkown"; + rc = -ENOTSUPP; + break; + } + + dev_info(&lp->spi->dev, "Detected %s chip version %d\n", chip, version); + + return rc; +} + static int at86rf230_probe(struct spi_device *spi) { struct at86rf230_platform_data *pdata; struct ieee802154_dev *dev; struct at86rf230_local *lp; - u16 man_id = 0; - u8 part = 0, version = 0; unsigned int status; irq_handler_t irq_handler; work_func_t irq_worker; int rc, irq_type; - const char *chip; if (!spi->irq) { dev_err(&spi->dev, "no IRQ specified\n"); @@ -1133,54 +1151,8 @@ static int at86rf230_probe(struct spi_device *spi) lp = dev->priv; lp->dev = dev; - lp->part = part; - lp->vers = version; - lp->spi = spi; - dev->parent = &spi->dev; - dev->extra_tx_headroom = 0; - dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | - IEEE802154_HW_TXPOWER | IEEE802154_HW_CSMA; - - rc = __at86rf230_detect_device(spi, &man_id, &part, &version); - if (rc < 0) - goto free_dev; - - if (man_id != 0x001f) { - dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n", - man_id >> 8, man_id & 0xFF); - return -EINVAL; - } - - switch (part) { - case 2: - chip = "at86rf230"; - rc = -ENOTSUPP; - /* FIXME: should be easy to support; */ - break; - case 3: - chip = "at86rf231"; - break; - case 7: - chip = "at86rf212"; - if (version == 1) - dev->flags |= IEEE802154_HW_LBT; - else - rc = -ENOTSUPP; - break; - case 11: - chip = "at86rf233"; - break; - default: - chip = "UNKNOWN"; - rc = -ENOTSUPP; - break; - } - - dev_info(&spi->dev, "Detected %s chip version %d\n", chip, version); - if (rc < 0) - goto free_dev; lp->regmap = devm_regmap_init_spi(spi, &at86rf230_regmap_spi_config); if (IS_ERR(lp->regmap)) { @@ -1190,6 +1162,10 @@ static int at86rf230_probe(struct spi_device *spi) goto free_dev; } + rc = at86rf230_detect_device(lp); + if (rc < 0) + goto free_dev; + irq_type = irq_get_trigger_type(spi->irq); if (!irq_type) irq_type = IRQF_TRIGGER_RISING; @@ -1208,13 +1184,6 @@ static int at86rf230_probe(struct spi_device *spi) spi_set_drvdata(spi, lp); - if (is_rf212(lp)) { - dev->phy->channels_supported[0] = 0x00007FF; - dev->phy->channels_supported[2] = 0x00007FF; - } else { - dev->phy->channels_supported[0] = 0x7FFF800; - } - rc = at86rf230_hw_init(lp); if (rc) goto err_hw_init; -- cgit v1.2.3 From a53d1f7c3d53353f68b2355a19cd5d5c7e4c7b34 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:46 +0200 Subject: at86rf230: remove is212 and add driver data This patch adds a new at86rf2xx_chip_data structure which holds device specific attributes. Instead of runtime decisions "if (is212())" we set callbacks/attributes while device detection. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 59 +++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 7d96cd410edb..694f5cf339e3 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -38,12 +38,19 @@ #include #include +struct at86rf230_local; +/* at86rf2xx chip depend data. + * All timings are in us. + */ +struct at86rf2xx_chip_data { + int rssi_base_val; + + int (*set_channel)(struct at86rf230_local *, int, int); +}; + struct at86rf230_local { struct spi_device *spi; - u8 part; - u8 vers; - u8 buf[2]; struct mutex bmux; @@ -56,16 +63,11 @@ struct at86rf230_local { spinlock_t lock; bool irq_busy; bool is_tx; - bool tx_aret; - int rssi_base_val; + struct at86rf2xx_chip_data *data; + bool tx_aret; }; -static bool is_rf212(struct at86rf230_local *local) -{ - return local->part == 7; -} - #define RG_TRX_STATUS (0x01) #define SR_TRX_STATUS 0x01, 0x1f, 0 #define SR_RESERVED_01_3 0x01, 0x20, 5 @@ -593,10 +595,8 @@ at86rf230_stop(struct ieee802154_dev *dev) } static int -at86rf230_set_channel(struct at86rf230_local *lp, int page, int channel) +at86rf23x_set_channel(struct at86rf230_local *lp, int page, int channel) { - lp->rssi_base_val = -91; - return at86rf230_write_subreg(lp, SR_CHANNEL, channel); } @@ -614,10 +614,10 @@ at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel) if (page == 0) { rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 0); - lp->rssi_base_val = -100; + lp->data->rssi_base_val = -100; } else { rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 1); - lp->rssi_base_val = -98; + lp->data->rssi_base_val = -98; } if (rc < 0) return rc; @@ -639,10 +639,7 @@ at86rf230_channel(struct ieee802154_dev *dev, int page, int channel) return -EINVAL; } - if (is_rf212(lp)) - rc = at86rf212_set_channel(lp, page, channel); - else - rc = at86rf230_set_channel(lp, page, channel); + rc = lp->data->set_channel(lp, page, channel); if (rc < 0) return rc; @@ -827,10 +824,10 @@ at86rf230_set_cca_ed_level(struct ieee802154_dev *dev, s32 level) struct at86rf230_local *lp = dev->priv; int desens_steps; - if (level < lp->rssi_base_val || level > 30) + if (level < lp->data->rssi_base_val || level > 30) return -EINVAL; - desens_steps = (level - lp->rssi_base_val) * 100 / 207; + desens_steps = (level - lp->data->rssi_base_val) * 100 / 207; return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, desens_steps); } @@ -889,6 +886,21 @@ static struct ieee802154_ops at86rf230_ops = { .set_frame_retries = at86rf230_set_frame_retries, }; +static struct at86rf2xx_chip_data at86rf233_data = { + .rssi_base_val = -91, + .set_channel = at86rf23x_set_channel, +}; + +static struct at86rf2xx_chip_data at86rf231_data = { + .rssi_base_val = -91, + .set_channel = at86rf23x_set_channel, +}; + +static struct at86rf2xx_chip_data at86rf212_data = { + .rssi_base_val = -100, + .set_channel = at86rf212_set_channel, +}; + static void at86rf230_irqwork(struct work_struct *work) { struct at86rf230_local *lp = @@ -1061,8 +1073,6 @@ at86rf230_detect_device(struct at86rf230_local *lp) return -EINVAL; } - lp->part = part; - lp->vers = version; lp->dev->extra_tx_headroom = 0; lp->dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | IEEE802154_HW_TXPOWER | IEEE802154_HW_CSMA; @@ -1074,11 +1084,13 @@ at86rf230_detect_device(struct at86rf230_local *lp) break; case 3: chip = "at86rf231"; + lp->data = &at86rf231_data; lp->dev->phy->channels_supported[0] = 0x7FFF800; break; case 7: chip = "at86rf212"; if (version == 1) { + lp->data = &at86rf212_data; lp->dev->flags |= IEEE802154_HW_LBT; lp->dev->phy->channels_supported[0] = 0x00007FF; lp->dev->phy->channels_supported[2] = 0x00007FF; @@ -1088,6 +1100,7 @@ at86rf230_detect_device(struct at86rf230_local *lp) break; case 11: chip = "at86rf233"; + lp->data = &at86rf233_data; lp->dev->phy->channels_supported[0] = 0x7FFF800; break; default: -- cgit v1.2.3 From a7d7eda9054450320d5f7144ff8a0767ab619da3 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:47 +0200 Subject: at86rf230: add support for at86rf23x desense To set the CCA_ED_THRES register the calculation for at86rf23x is different than for at86rf212. This patch adds a new callback for this calculation in chip data struct. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 694f5cf339e3..6556fecec5e2 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -46,6 +46,7 @@ struct at86rf2xx_chip_data { int rssi_base_val; int (*set_channel)(struct at86rf230_local *, int, int); + int (*get_desense_steps)(struct at86rf230_local *, s32); }; struct at86rf230_local { @@ -818,18 +819,28 @@ at86rf230_set_cca_mode(struct ieee802154_dev *dev, u8 mode) return at86rf230_write_subreg(lp, SR_CCA_MODE, mode); } +static int +at86rf212_get_desens_steps(struct at86rf230_local *lp, s32 level) +{ + return (level - lp->data->rssi_base_val) * 100 / 207; +} + +static int +at86rf23x_get_desens_steps(struct at86rf230_local *lp, s32 level) +{ + return (level - lp->data->rssi_base_val) / 2; +} + static int at86rf230_set_cca_ed_level(struct ieee802154_dev *dev, s32 level) { struct at86rf230_local *lp = dev->priv; - int desens_steps; if (level < lp->data->rssi_base_val || level > 30) return -EINVAL; - desens_steps = (level - lp->data->rssi_base_val) * 100 / 207; - - return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, desens_steps); + return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, + lp->data->get_desense_steps(lp, level)); } static int @@ -889,16 +900,19 @@ static struct ieee802154_ops at86rf230_ops = { static struct at86rf2xx_chip_data at86rf233_data = { .rssi_base_val = -91, .set_channel = at86rf23x_set_channel, + .get_desense_steps = at86rf23x_get_desens_steps }; static struct at86rf2xx_chip_data at86rf231_data = { .rssi_base_val = -91, .set_channel = at86rf23x_set_channel, + .get_desense_steps = at86rf23x_get_desens_steps }; static struct at86rf2xx_chip_data at86rf212_data = { .rssi_base_val = -100, .set_channel = at86rf212_set_channel, + .get_desense_steps = at86rf212_get_desens_steps }; static void at86rf230_irqwork(struct work_struct *work) -- cgit v1.2.3 From 1d15d6b5b951063184c1749f6145db3170de9e07 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:48 +0200 Subject: at86rf230: rework transmit and receive handling This patch is a complete reimplementation of transmit and receive handling for the at86rf230 driver. It solves also six bugs: First: The RX_SAFE_MODE is enabled and the transceiver doesn't leave the receive state while the framebuffer isn't read by a CMD_FB command. This is useful to read out the frame and don't get into another receive or transmit state, otherwise the frame would be overwritten. The current driver do twice CMD_FB calls, the first one leaves this protection. Second: Sometimes the CRC calculation is correct and the length field is greater 127. The current mac802154 layer and filter of a at86rf2xx doesn't check on this and the kernel crashes. In this case the frame is corrupted, we send the whole receive buffer to the next layer which can be useful for sniffing. Thrid: There is a undocumented race condition. When we are go into the RX_AACK_ON state the transceiver could be changed into RX_AACK_BUSY state. This is a normal behaviour. In this case the transceiver received a SHR while assert wasn't finished. Fourth: It also handle some more "correct" state changes. In aret mode the transceiver need to go to TX_ON before the transceiver go into RX_AACK_ON. Fifth: The programming model [0] describes also a error handling in ARET mode if the trac status is different than zero. This is patch adds support for handling this. Sixth: In receive handling the transceiver should also get the trac status according [0]. The driver could use the trac status as error statistic handling, but the driver doesn't use this currently. There is maybe some timing behaviour or the read of this register change some transceiver states. In addition the irqworker is removed. Instead we do async spi calls and no scheduling is involved anymore. The transmit function is also asynchron but with a wait_for_completion handling. The mac802154 layer doesn't support asynchron transmit handling right now. The state change behaviour is now changes, before it was: 1. assert while(!STATE_TRANSITION_IN_PROGRESS) 2. state change 3. assert while(!STATE_TRANSITION_IN_PROGRESS) 4. assert once(wanted state != current state) Sometimes a unexcepted state change occurs when 4. assert was violated. The new state change behaviour is: 1. assert while(!STATE_TRANSITION_IN_PROGRESS) 2. state change 3. wait state change timing according datasheet 4. assert once(wanted state != current state) This behaviour is described in the at86rf231 software programming model [0]. The state change documentation in this programming guide should also valid for at86rf212 and at86rf233 chips. The transceiver don't do a FORCE_TX_ON while we want to transmit a PDU. The new behaviour is a TX_ON and wait a receiving time (tFrame + tPAck). If we are still in RX_AACK_BUSY then we transmit a FORCE_TX_ON as timeout handling. The different is that FORCE_TX_ON aborts receiving and TX_ON waits if RX_AACK_BUSY is finished. This should decrease the drop rate of packets. [0] http://www.atmel.com/Images/AVR2022_swpm231-2.0.zip Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 839 +++++++++++++++++++++++++------------ 1 file changed, 571 insertions(+), 268 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 6556fecec5e2..39c3c117340d 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -26,8 +26,6 @@ #include #include #include -#include -#include #include #include #include @@ -35,6 +33,7 @@ #include #include +#include #include #include @@ -43,30 +42,50 @@ struct at86rf230_local; * All timings are in us. */ struct at86rf2xx_chip_data { + u16 t_frame; + u16 t_p_ack; + /* short interframe spacing time */ + u16 t_sifs; + /* long interframe spacing time */ + u16 t_lifs; + /* completion timeout for tx in msecs */ + u16 t_tx_timeout; int rssi_base_val; int (*set_channel)(struct at86rf230_local *, int, int); int (*get_desense_steps)(struct at86rf230_local *, s32); }; -struct at86rf230_local { - struct spi_device *spi; +#define AT86RF2XX_MAX_BUF (127 + 3) - u8 buf[2]; - struct mutex bmux; +struct at86rf230_state_change { + struct at86rf230_local *lp; - struct work_struct irqwork; - struct completion tx_complete; + struct spi_message msg; + struct spi_transfer trx; + u8 buf[AT86RF2XX_MAX_BUF]; + + void (*complete)(void *context); + u8 from_state; + u8 to_state; +}; + +struct at86rf230_local { + struct spi_device *spi; struct ieee802154_dev *dev; + struct at86rf2xx_chip_data *data; struct regmap *regmap; - spinlock_t lock; - bool irq_busy; - bool is_tx; + struct at86rf230_state_change irq; - struct at86rf2xx_chip_data *data; bool tx_aret; + bool is_tx; + /* spinlock for is_tx protection */ + spinlock_t lock; + struct completion tx_complete; + struct sk_buff *tx_skb; + struct at86rf230_state_change tx; }; #define RG_TRX_STATUS (0x01) @@ -263,6 +282,11 @@ struct at86rf230_local { #define AT86RF2XX_NUMREGS 0x3F +static int +at86rf230_async_state_change(struct at86rf230_local *lp, + struct at86rf230_state_change *ctx, + const u8 state, void (*complete)(void *context)); + static inline int __at86rf230_write(struct at86rf230_local *lp, unsigned int addr, unsigned int data) @@ -412,104 +436,515 @@ static struct regmap_config at86rf230_regmap_spi_config = { .precious_reg = at86rf230_reg_precious, }; +static void +at86rf230_async_error_recover(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + + at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL); +} + +static void +at86rf230_async_error(struct at86rf230_local *lp, + struct at86rf230_state_change *ctx, int rc) +{ + dev_err(&lp->spi->dev, "spi_async error %d\n", rc); + + at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, + at86rf230_async_error_recover); +} + +/* Generic function to get some register value in async mode */ static int -at86rf230_write_fbuf(struct at86rf230_local *lp, u8 *data, u8 len) +at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, + struct at86rf230_state_change *ctx, + void (*complete)(void *context)) { - u8 *buf = lp->buf; - int status; - struct spi_message msg; - struct spi_transfer xfer_head = { - .len = 2, - .tx_buf = buf, - - }; - struct spi_transfer xfer_buf = { - .len = len, - .tx_buf = data, - }; - - mutex_lock(&lp->bmux); - buf[0] = CMD_WRITE | CMD_FB; - buf[1] = len + 2; /* 2 bytes for CRC that isn't written */ - - dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]); - dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]); - - spi_message_init(&msg); - spi_message_add_tail(&xfer_head, &msg); - spi_message_add_tail(&xfer_buf, &msg); - - status = spi_sync(lp->spi, &msg); - dev_vdbg(&lp->spi->dev, "status = %d\n", status); - if (msg.status) - status = msg.status; - - dev_vdbg(&lp->spi->dev, "status = %d\n", status); - dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]); - dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]); - - mutex_unlock(&lp->bmux); - return status; + u8 *tx_buf = ctx->buf; + + tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG; + ctx->trx.len = 2; + ctx->msg.complete = complete; + return spi_async(lp->spi, &ctx->msg); +} + +static void +at86rf230_async_state_assert(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + const u8 *buf = ctx->buf; + const u8 trx_state = buf[1] & 0x1f; + + /* Assert state change */ + if (trx_state != ctx->to_state) { + /* Special handling if transceiver state is in + * STATE_BUSY_RX_AACK and a SHR was detected. + */ + if (trx_state == STATE_BUSY_RX_AACK) { + /* Undocumented race condition. If we send a state + * change to STATE_RX_AACK_ON the transceiver could + * change his state automatically to STATE_BUSY_RX_AACK + * if a SHR was detected. This is not an error, but we + * can't assert this. + */ + if (ctx->to_state == STATE_RX_AACK_ON) + goto done; + + /* If we change to STATE_TX_ON without forcing and + * transceiver state is STATE_BUSY_RX_AACK, we wait + * 'tFrame + tPAck' receiving time. In this time the + * PDU should be received. If the transceiver is still + * in STATE_BUSY_RX_AACK, we run a force state change + * to STATE_TX_ON. This is a timeout handling, if the + * transceiver stucks in STATE_BUSY_RX_AACK. + */ + if (ctx->to_state == STATE_TX_ON) { + at86rf230_async_state_change(lp, ctx, + STATE_FORCE_TX_ON, + ctx->complete); + return; + } + } + + + dev_warn(&lp->spi->dev, "unexcept state change from 0x%02x to 0x%02x. Actual state: 0x%02x\n", + ctx->from_state, ctx->to_state, trx_state); + } + +done: + if (ctx->complete) + ctx->complete(context); +} + +/* Do state change timing delay. */ +static void +at86rf230_async_state_delay(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + struct at86rf2xx_chip_data *c = lp->data; + bool force = false; + int rc; + + /* The force state changes are will show as normal states in the + * state status subregister. We change the to_state to the + * corresponding one and remember if it was a force change, this + * differs if we do a state change from STATE_BUSY_RX_AACK. + */ + switch (ctx->to_state) { + case STATE_FORCE_TX_ON: + ctx->to_state = STATE_TX_ON; + force = true; + break; + case STATE_FORCE_TRX_OFF: + ctx->to_state = STATE_TRX_OFF; + force = true; + break; + default: + break; + } + + switch (ctx->from_state) { + case STATE_BUSY_RX_AACK: + switch (ctx->to_state) { + case STATE_TX_ON: + /* Wait for worst case receiving time if we + * didn't make a force change from BUSY_RX_AACK + * to TX_ON. + */ + if (!force) { + usleep_range(c->t_frame + c->t_p_ack, + c->t_frame + c->t_p_ack + 1000); + goto change; + } + break; + default: + break; + } + break; + default: + break; + } + + /* Default delay is 1us in the most cases */ + udelay(1); + +change: + rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, + at86rf230_async_state_assert); + if (rc) + dev_err(&lp->spi->dev, "spi_async error %d\n", rc); +} + +static void +at86rf230_async_state_change_start(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + u8 *buf = ctx->buf; + const u8 trx_state = buf[1] & 0x1f; + int rc; + + /* Check for "possible" STATE_TRANSITION_IN_PROGRESS */ + if (trx_state == STATE_TRANSITION_IN_PROGRESS) { + udelay(1); + rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, + at86rf230_async_state_change_start); + if (rc) + dev_err(&lp->spi->dev, "spi_async error %d\n", rc); + return; + } + + /* Check if we already are in the state which we change in */ + if (trx_state == ctx->to_state) { + if (ctx->complete) + ctx->complete(context); + return; + } + + /* Set current state to the context of state change */ + ctx->from_state = trx_state; + + /* Going into the next step for a state change which do a timing + * relevant delay. + */ + buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE; + buf[1] = ctx->to_state; + ctx->trx.len = 2; + ctx->msg.complete = at86rf230_async_state_delay; + rc = spi_async(lp->spi, &ctx->msg); + if (rc) + dev_err(&lp->spi->dev, "spi_async error %d\n", rc); } static int -at86rf230_read_fbuf(struct at86rf230_local *lp, u8 *data, u8 *len, u8 *lqi) +at86rf230_async_state_change(struct at86rf230_local *lp, + struct at86rf230_state_change *ctx, + const u8 state, void (*complete)(void *context)) { - u8 *buf = lp->buf; - int status; - struct spi_message msg; - struct spi_transfer xfer_head = { - .len = 2, - .tx_buf = buf, - .rx_buf = buf, - }; - struct spi_transfer xfer_head1 = { - .len = 2, - .tx_buf = buf, - .rx_buf = buf, - }; - struct spi_transfer xfer_buf = { - .len = 0, - .rx_buf = data, - }; - - mutex_lock(&lp->bmux); + /* Initialization for the state change context */ + ctx->to_state = state; + ctx->complete = complete; + return at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, + at86rf230_async_state_change_start); +} - buf[0] = CMD_FB; - buf[1] = 0x00; +static void +at86rf230_tx_complete(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + + complete(&lp->tx_complete); +} + +static void +at86rf230_tx_on(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + int rc; + + rc = at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON, + at86rf230_tx_complete); + if (rc) + at86rf230_async_error(lp, ctx, rc); +} + +static void +at86rf230_tx_trac_error(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + int rc; + + rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON, + at86rf230_tx_on); + if (rc) + at86rf230_async_error(lp, ctx, rc); +} + +static void +at86rf230_tx_trac_check(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + const u8 *buf = ctx->buf; + const u8 trac = (buf[1] & 0xe0) >> 5; + int rc; + + /* If trac status is different than zero we need to do a state change + * to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver + * state to TX_ON. + */ + if (trac) { + rc = at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, + at86rf230_tx_trac_error); + if (rc) + at86rf230_async_error(lp, ctx, rc); + return; + } + + at86rf230_tx_on(context); +} + + +static void +at86rf230_tx_trac_status(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + int rc; + + rc = at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx, + at86rf230_tx_trac_check); + if (rc) + at86rf230_async_error(lp, ctx, rc); +} + +static void +at86rf230_rx(struct at86rf230_local *lp, + const u8 *data, u8 len) +{ + u8 lqi; + struct sk_buff *skb; + u8 rx_local_buf[AT86RF2XX_MAX_BUF]; + + if (len < 2) + return; + + /* read full frame buffer and invalid lqi value to lowest + * indicator if frame was is in a corrupted state. + */ + if (len > IEEE802154_MTU) { + lqi = 0; + len = IEEE802154_MTU; + dev_vdbg(&lp->spi->dev, "corrupted frame received\n"); + } else { + lqi = data[len]; + } + + memcpy(rx_local_buf, data, len); + enable_irq(lp->spi->irq); + + skb = alloc_skb(IEEE802154_MTU, GFP_ATOMIC); + if (!skb) { + dev_vdbg(&lp->spi->dev, "failed to allocate sk_buff\n"); + return; + } + + memcpy(skb_put(skb, len), rx_local_buf, len); + + /* We do not put CRC into the frame */ + skb_trim(skb, len - 2); - spi_message_init(&msg); - spi_message_add_tail(&xfer_head, &msg); + ieee802154_rx_irqsafe(lp->dev, skb, lqi); +} - status = spi_sync(lp->spi, &msg); - dev_vdbg(&lp->spi->dev, "status = %d\n", status); +static void +at86rf230_rx_read_frame_complete(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + const u8 *buf = lp->irq.buf; + const u8 len = buf[1]; - xfer_buf.len = *(buf + 1) + 1; - *len = buf[1]; + at86rf230_rx(lp, buf + 2, len); +} + +static int +at86rf230_rx_read_frame(struct at86rf230_local *lp) +{ + u8 *buf = lp->irq.buf; buf[0] = CMD_FB; - buf[1] = 0x00; + lp->irq.trx.len = AT86RF2XX_MAX_BUF; + lp->irq.msg.complete = at86rf230_rx_read_frame_complete; + return spi_async(lp->spi, &lp->irq.msg); +} + +static void +at86rf230_rx_trac_check(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + int rc; + + /* Possible check on trac status here. This could be useful to make + * some stats why receive is failed. Not used at the moment, but it's + * maybe timing relevant. Datasheet doesn't say anything about this. + * The programming guide say do it so. + */ + + rc = at86rf230_rx_read_frame(lp); + if (rc) { + enable_irq(lp->spi->irq); + at86rf230_async_error(lp, ctx, rc); + } +} + +static int +at86rf230_irq_trx_end(struct at86rf230_local *lp) +{ + spin_lock(&lp->lock); + if (lp->is_tx) { + lp->is_tx = 0; + spin_unlock(&lp->lock); + enable_irq(lp->spi->irq); + + if (lp->tx_aret) + return at86rf230_async_state_change(lp, &lp->irq, + STATE_FORCE_TX_ON, + at86rf230_tx_trac_status); + else + return at86rf230_async_state_change(lp, &lp->irq, + STATE_RX_AACK_ON, + at86rf230_tx_complete); + } else { + spin_unlock(&lp->lock); + return at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq, + at86rf230_rx_trac_check); + } +} + +static void +at86rf230_irq_status(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + const u8 *buf = lp->irq.buf; + const u8 irq = buf[1]; + int rc; + + if (irq & IRQ_TRX_END) { + rc = at86rf230_irq_trx_end(lp); + if (rc) + at86rf230_async_error(lp, ctx, rc); + } else { + enable_irq(lp->spi->irq); + dev_err(&lp->spi->dev, "not supported irq %02x received\n", + irq); + } +} + +static irqreturn_t at86rf230_isr(int irq, void *data) +{ + struct at86rf230_local *lp = data; + struct at86rf230_state_change *ctx = &lp->irq; + u8 *buf = ctx->buf; + int rc; + + disable_irq_nosync(lp->spi->irq); + + buf[0] = (RG_IRQ_STATUS & CMD_REG_MASK) | CMD_REG; + ctx->trx.len = 2; + ctx->msg.complete = at86rf230_irq_status; + rc = spi_async(lp->spi, &ctx->msg); + if (rc) { + at86rf230_async_error(lp, ctx, rc); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static void +at86rf230_write_frame_complete(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + u8 *buf = ctx->buf; + int rc; + + buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE; + buf[1] = STATE_BUSY_TX; + ctx->trx.len = 2; + ctx->msg.complete = NULL; + rc = spi_async(lp->spi, &ctx->msg); + if (rc) + at86rf230_async_error(lp, ctx, rc); +} + +static void +at86rf230_write_frame(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + struct sk_buff *skb = lp->tx_skb; + u8 *buf = lp->tx.buf; + int rc; + + spin_lock(&lp->lock); + lp->is_tx = 1; + spin_unlock(&lp->lock); + + buf[0] = CMD_FB | CMD_WRITE; + buf[1] = skb->len + 2; + memcpy(buf + 2, skb->data, skb->len); + lp->tx.trx.len = skb->len + 2; + lp->tx.msg.complete = at86rf230_write_frame_complete; + rc = spi_async(lp->spi, &lp->tx.msg); + if (rc) + at86rf230_async_error(lp, ctx, rc); +} + +static void +at86rf230_xmit_tx_on(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + int rc; - spi_message_init(&msg); - spi_message_add_tail(&xfer_head1, &msg); - spi_message_add_tail(&xfer_buf, &msg); + rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON, + at86rf230_write_frame); + if (rc) + at86rf230_async_error(lp, ctx, rc); +} + +static int +at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb) +{ + struct at86rf230_local *lp = dev->priv; + struct at86rf230_state_change *ctx = &lp->tx; - status = spi_sync(lp->spi, &msg); + void (*tx_complete)(void *context) = at86rf230_write_frame; + int rc; - if (msg.status) - status = msg.status; + lp->tx_skb = skb; - dev_vdbg(&lp->spi->dev, "status = %d\n", status); - dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]); - dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]); + /* In ARET mode we need to go into STATE_TX_ARET_ON after we + * are in STATE_TX_ON. The pfad differs here, so we change + * the complete handler. + */ + if (lp->tx_aret) + tx_complete = at86rf230_xmit_tx_on; - if (status) { - if (lqi && (*len > lp->buf[1])) - *lqi = data[lp->buf[1]]; + rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON, + tx_complete); + if (rc) { + at86rf230_async_error(lp, ctx, rc); + return rc; + } + rc = wait_for_completion_interruptible_timeout(&lp->tx_complete, + msecs_to_jiffies(lp->data->t_tx_timeout)); + if (!rc) { + at86rf230_async_error(lp, ctx, rc); + return -ETIMEDOUT; } - mutex_unlock(&lp->bmux); - return status; + /* Interfame spacing time, which is phy depend. + * TODO + * Move this handling in MAC 802.15.4 layer. + * This is currently a workaround to avoid fragmenation issues. + */ + if (skb->len > 18) + usleep_range(lp->data->t_lifs, lp->data->t_lifs + 10); + else + usleep_range(lp->data->t_sifs, lp->data->t_sifs + 10); + + return 0; } static int @@ -651,92 +1086,6 @@ at86rf230_channel(struct ieee802154_dev *dev, int page, int channel) return 0; } -static int -at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb) -{ - struct at86rf230_local *lp = dev->priv; - int rc; - unsigned long flags; - - spin_lock_irqsave(&lp->lock, flags); - if (lp->irq_busy) { - spin_unlock_irqrestore(&lp->lock, flags); - return -EBUSY; - } - spin_unlock_irqrestore(&lp->lock, flags); - - might_sleep(); - - rc = at86rf230_state(dev, STATE_FORCE_TX_ON); - if (rc) - goto err; - - spin_lock_irqsave(&lp->lock, flags); - lp->is_tx = 1; - reinit_completion(&lp->tx_complete); - spin_unlock_irqrestore(&lp->lock, flags); - - rc = at86rf230_write_fbuf(lp, skb->data, skb->len); - if (rc) - goto err_rx; - - if (lp->tx_aret) { - rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ARET_ON); - if (rc) - goto err_rx; - } - - rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX); - if (rc) - goto err_rx; - - rc = wait_for_completion_interruptible(&lp->tx_complete); - if (rc < 0) - goto err_rx; - - return at86rf230_start(dev); -err_rx: - at86rf230_start(dev); -err: - pr_err("error: %d\n", rc); - - spin_lock_irqsave(&lp->lock, flags); - lp->is_tx = 0; - spin_unlock_irqrestore(&lp->lock, flags); - - return rc; -} - -static int at86rf230_rx(struct at86rf230_local *lp) -{ - u8 len = 128, lqi = 0; - struct sk_buff *skb; - - skb = alloc_skb(len, GFP_KERNEL); - - if (!skb) - return -ENOMEM; - - if (at86rf230_read_fbuf(lp, skb_put(skb, len), &len, &lqi)) - goto err; - - if (len < 2) - goto err; - - skb_trim(skb, len - 2); /* We do not put CRC into the frame */ - - ieee802154_rx_irqsafe(lp->dev, skb, lqi); - - dev_dbg(&lp->spi->dev, "READ_FBUF: %d %x\n", len, lqi); - - return 0; -err: - pr_debug("received frame is too small\n"); - - kfree_skb(skb); - return -EINVAL; -} - static int at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev, struct ieee802154_hw_addr_filt *filt, @@ -898,87 +1247,38 @@ static struct ieee802154_ops at86rf230_ops = { }; static struct at86rf2xx_chip_data at86rf233_data = { + .t_frame = 4096, + .t_p_ack = 545, + .t_sifs = 192, + .t_lifs = 480, + .t_tx_timeout = 2000, .rssi_base_val = -91, .set_channel = at86rf23x_set_channel, .get_desense_steps = at86rf23x_get_desens_steps }; static struct at86rf2xx_chip_data at86rf231_data = { + .t_frame = 4096, + .t_p_ack = 545, + .t_sifs = 192, + .t_lifs = 480, + .t_tx_timeout = 2000, .rssi_base_val = -91, .set_channel = at86rf23x_set_channel, .get_desense_steps = at86rf23x_get_desens_steps }; static struct at86rf2xx_chip_data at86rf212_data = { + .t_frame = 4096, + .t_p_ack = 545, + .t_sifs = 192, + .t_lifs = 480, + .t_tx_timeout = 2000, .rssi_base_val = -100, .set_channel = at86rf212_set_channel, .get_desense_steps = at86rf212_get_desens_steps }; -static void at86rf230_irqwork(struct work_struct *work) -{ - struct at86rf230_local *lp = - container_of(work, struct at86rf230_local, irqwork); - unsigned int status; - int rc; - unsigned long flags; - - rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status); - - status &= ~IRQ_PLL_LOCK; /* ignore */ - status &= ~IRQ_RX_START; /* ignore */ - status &= ~IRQ_AMI; /* ignore */ - status &= ~IRQ_TRX_UR; /* FIXME: possibly handle ???*/ - - if (status & IRQ_TRX_END) { - status &= ~IRQ_TRX_END; - spin_lock_irqsave(&lp->lock, flags); - if (lp->is_tx) { - lp->is_tx = 0; - spin_unlock_irqrestore(&lp->lock, flags); - complete(&lp->tx_complete); - } else { - spin_unlock_irqrestore(&lp->lock, flags); - at86rf230_rx(lp); - } - } - - spin_lock_irqsave(&lp->lock, flags); - lp->irq_busy = 0; - spin_unlock_irqrestore(&lp->lock, flags); -} - -static void at86rf230_irqwork_level(struct work_struct *work) -{ - struct at86rf230_local *lp = - container_of(work, struct at86rf230_local, irqwork); - - at86rf230_irqwork(work); - - enable_irq(lp->spi->irq); -} - -static irqreturn_t at86rf230_isr(int irq, void *data) -{ - struct at86rf230_local *lp = data; - unsigned long flags; - - spin_lock_irqsave(&lp->lock, flags); - lp->irq_busy = 1; - spin_unlock_irqrestore(&lp->lock, flags); - - schedule_work(&lp->irqwork); - - return IRQ_HANDLED; -} - -static irqreturn_t at86rf230_isr_level(int irq, void *data) -{ - disable_irq_nosync(irq); - - return at86rf230_isr(irq, data); -} - static int at86rf230_hw_init(struct at86rf230_local *lp) { int rc, irq_pol, irq_type; @@ -1128,14 +1428,30 @@ at86rf230_detect_device(struct at86rf230_local *lp) return rc; } +static void +at86rf230_setup_spi_messages(struct at86rf230_local *lp) +{ + lp->irq.lp = lp; + spi_message_init(&lp->irq.msg); + lp->irq.msg.context = &lp->irq; + lp->irq.trx.tx_buf = lp->irq.buf; + lp->irq.trx.rx_buf = lp->irq.buf; + spi_message_add_tail(&lp->irq.trx, &lp->irq.msg); + + lp->tx.lp = lp; + spi_message_init(&lp->tx.msg); + lp->tx.msg.context = &lp->tx; + lp->tx.trx.tx_buf = lp->tx.buf; + lp->tx.trx.rx_buf = lp->tx.buf; + spi_message_add_tail(&lp->tx.trx, &lp->tx.msg); +} + static int at86rf230_probe(struct spi_device *spi) { struct at86rf230_platform_data *pdata; struct ieee802154_dev *dev; struct at86rf230_local *lp; unsigned int status; - irq_handler_t irq_handler; - work_func_t irq_worker; int rc, irq_type; if (!spi->irq) { @@ -1189,23 +1505,12 @@ static int at86rf230_probe(struct spi_device *spi) goto free_dev; } + at86rf230_setup_spi_messages(lp); + rc = at86rf230_detect_device(lp); if (rc < 0) goto free_dev; - irq_type = irq_get_trigger_type(spi->irq); - if (!irq_type) - irq_type = IRQF_TRIGGER_RISING; - if (irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { - irq_worker = at86rf230_irqwork; - irq_handler = at86rf230_isr; - } else { - irq_worker = at86rf230_irqwork_level; - irq_handler = at86rf230_isr_level; - } - - mutex_init(&lp->bmux); - INIT_WORK(&lp->irqwork, irq_worker); spin_lock_init(&lp->lock); init_completion(&lp->tx_complete); @@ -1213,28 +1518,28 @@ static int at86rf230_probe(struct spi_device *spi) rc = at86rf230_hw_init(lp); if (rc) - goto err_hw_init; + goto free_dev; /* Read irq status register to reset irq line */ rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status); if (rc) - goto err_hw_init; + goto free_dev; - rc = devm_request_irq(&spi->dev, spi->irq, irq_handler, - IRQF_SHARED | irq_type, - dev_name(&spi->dev), lp); + irq_type = irq_get_trigger_type(spi->irq); + if (!irq_type) + irq_type = IRQF_TRIGGER_RISING; + + rc = devm_request_irq(&spi->dev, spi->irq, at86rf230_isr, + IRQF_SHARED | irq_type, dev_name(&spi->dev), lp); if (rc) - goto err_hw_init; + goto free_dev; rc = ieee802154_register_device(lp->dev); if (rc) - goto err_hw_init; + goto free_dev; return rc; -err_hw_init: - flush_work(&lp->irqwork); - mutex_destroy(&lp->bmux); free_dev: ieee802154_free_device(lp->dev); @@ -1248,8 +1553,6 @@ static int at86rf230_remove(struct spi_device *spi) /* mask all at86rf230 irq's */ at86rf230_write_subreg(lp, SR_IRQ_MASK, 0); ieee802154_unregister_device(lp->dev); - flush_work(&lp->irqwork); - mutex_destroy(&lp->bmux); ieee802154_free_device(lp->dev); dev_dbg(&spi->dev, "unregistered at86rf230\n"); -- cgit v1.2.3 From 6bd2b132bfbaea46abbcc65f1be57709b2fb601a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:49 +0200 Subject: at86rf230: move RX_SAFE_MODE setting to hw_init There is no need to set this bit in start callback which could be called more than once. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 39c3c117340d..492fb7e7675d 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1010,13 +1010,8 @@ err: static int at86rf230_start(struct ieee802154_dev *dev) { - struct at86rf230_local *lp = dev->priv; u8 rc; - rc = at86rf230_write_subreg(lp, SR_RX_SAFE_MODE, 1); - if (rc) - return rc; - rc = at86rf230_state(dev, STATE_TX_ON); if (rc) return rc; @@ -1300,6 +1295,10 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) if (rc) return rc; + rc = at86rf230_write_subreg(lp, SR_RX_SAFE_MODE, 1); + if (rc) + return rc; + rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, IRQ_TRX_END); if (rc) return rc; -- cgit v1.2.3 From 1db0558e87ddf0e4892963602b35ac079b507dd9 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:50 +0200 Subject: at86rf230: rework irq_pol setting This patch rework the irq_pol register setting for rising and falling interrupt settings only. The default behaviour should be rising flag. Also use IRQ_TYPE_* defines instead of IRQF_* defines. There is no functionality change but irq_get_trigger_type returns IRQ_TYPE_* defines. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 492fb7e7675d..46db6f8fb58f 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1276,7 +1276,7 @@ static struct at86rf2xx_chip_data at86rf212_data = { static int at86rf230_hw_init(struct at86rf230_local *lp) { - int rc, irq_pol, irq_type; + int rc, irq_type, irq_pol = IRQ_ACTIVE_HIGH; unsigned int dvdd; u8 csma_seed[2]; @@ -1285,11 +1285,8 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) return rc; irq_type = irq_get_trigger_type(lp->spi->irq); - /* configure irq polarity, defaults to high active */ - if (irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW)) + if (irq_type == IRQ_TYPE_EDGE_FALLING) irq_pol = IRQ_ACTIVE_LOW; - else - irq_pol = IRQ_ACTIVE_HIGH; rc = at86rf230_write_subreg(lp, SR_IRQ_POLARITY, irq_pol); if (rc) -- cgit v1.2.3 From 2e0571c0d6835e224b5863df630efbcf00696483 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:51 +0200 Subject: at86rf230: rework state change and start/stop This patch removes the current synchron state change function and add a new function for a state assert. Change the start and stop callbacks to use this new synchron state change behaviour. It's a wrapper around the async state change function. Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 126 ++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 59 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 46db6f8fb58f..265fea8a6030 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -42,6 +42,8 @@ struct at86rf230_local; * All timings are in us. */ struct at86rf2xx_chip_data { + u16 t_off_to_aack; + u16 t_off_to_tx_on; u16 t_frame; u16 t_p_ack; /* short interframe spacing time */ @@ -77,6 +79,9 @@ struct at86rf230_local { struct at86rf2xx_chip_data *data; struct regmap *regmap; + struct completion state_complete; + struct at86rf230_state_change state; + struct at86rf230_state_change irq; bool tx_aret; @@ -547,6 +552,19 @@ at86rf230_async_state_delay(void *context) } switch (ctx->from_state) { + case STATE_TRX_OFF: + switch (ctx->to_state) { + case STATE_RX_AACK_ON: + usleep_range(c->t_off_to_aack, c->t_off_to_aack + 10); + goto change; + case STATE_TX_ON: + usleep_range(c->t_off_to_tx_on, + c->t_off_to_tx_on + 10); + goto change; + default: + break; + } + break; case STATE_BUSY_RX_AACK: switch (ctx->to_state) { case STATE_TX_ON: @@ -631,6 +649,39 @@ at86rf230_async_state_change(struct at86rf230_local *lp, at86rf230_async_state_change_start); } +static void +at86rf230_sync_state_change_complete(void *context) +{ + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; + + complete(&lp->state_complete); +} + +/* This function do a sync framework above the async state change. + * Some callbacks of the IEEE 802.15.4 driver interface need to be + * handled synchronously. + */ +static int +at86rf230_sync_state_change(struct at86rf230_local *lp, unsigned int state) +{ + int rc; + + rc = at86rf230_async_state_change(lp, &lp->state, state, + at86rf230_sync_state_change_complete); + if (rc) { + at86rf230_async_error(lp, &lp->state, rc); + return rc; + } + + rc = wait_for_completion_timeout(&lp->state_complete, + msecs_to_jiffies(100)); + if (!rc) + return -ETIMEDOUT; + + return 0; +} + static void at86rf230_tx_complete(void *context) { @@ -956,73 +1007,16 @@ at86rf230_ed(struct ieee802154_dev *dev, u8 *level) return 0; } -static int -at86rf230_state(struct ieee802154_dev *dev, int state) -{ - struct at86rf230_local *lp = dev->priv; - int rc; - unsigned int val; - u8 desired_status; - - might_sleep(); - - if (state == STATE_FORCE_TX_ON) - desired_status = STATE_TX_ON; - else if (state == STATE_FORCE_TRX_OFF) - desired_status = STATE_TRX_OFF; - else - desired_status = state; - - do { - rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &val); - if (rc) - goto err; - } while (val == STATE_TRANSITION_IN_PROGRESS); - - if (val == desired_status) - return 0; - - /* state is equal to phy states */ - rc = at86rf230_write_subreg(lp, SR_TRX_CMD, state); - if (rc) - goto err; - - do { - rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &val); - if (rc) - goto err; - } while (val == STATE_TRANSITION_IN_PROGRESS); - - - if (val == desired_status || - (desired_status == STATE_RX_ON && val == STATE_BUSY_RX) || - (desired_status == STATE_RX_AACK_ON && val == STATE_BUSY_RX_AACK)) - return 0; - - pr_err("unexpected state change: %d, asked for %d\n", val, state); - return -EBUSY; - -err: - pr_err("error: %d\n", rc); - return rc; -} - static int at86rf230_start(struct ieee802154_dev *dev) { - u8 rc; - - rc = at86rf230_state(dev, STATE_TX_ON); - if (rc) - return rc; - - return at86rf230_state(dev, STATE_RX_AACK_ON); + return at86rf230_sync_state_change(dev->priv, STATE_RX_AACK_ON); } static void at86rf230_stop(struct ieee802154_dev *dev) { - at86rf230_state(dev, STATE_FORCE_TRX_OFF); + at86rf230_sync_state_change(dev->priv, STATE_FORCE_TRX_OFF); } static int @@ -1242,6 +1236,8 @@ static struct ieee802154_ops at86rf230_ops = { }; static struct at86rf2xx_chip_data at86rf233_data = { + .t_off_to_aack = 80, + .t_off_to_tx_on = 80, .t_frame = 4096, .t_p_ack = 545, .t_sifs = 192, @@ -1253,6 +1249,8 @@ static struct at86rf2xx_chip_data at86rf233_data = { }; static struct at86rf2xx_chip_data at86rf231_data = { + .t_off_to_aack = 110, + .t_off_to_tx_on = 110, .t_frame = 4096, .t_p_ack = 545, .t_sifs = 192, @@ -1264,6 +1262,8 @@ static struct at86rf2xx_chip_data at86rf231_data = { }; static struct at86rf2xx_chip_data at86rf212_data = { + .t_off_to_aack = 200, + .t_off_to_tx_on = 200, .t_frame = 4096, .t_p_ack = 545, .t_sifs = 192, @@ -1427,6 +1427,13 @@ at86rf230_detect_device(struct at86rf230_local *lp) static void at86rf230_setup_spi_messages(struct at86rf230_local *lp) { + lp->state.lp = lp; + spi_message_init(&lp->state.msg); + lp->state.msg.context = &lp->state; + lp->state.trx.tx_buf = lp->state.buf; + lp->state.trx.rx_buf = lp->state.buf; + spi_message_add_tail(&lp->state.trx, &lp->state.msg); + lp->irq.lp = lp; spi_message_init(&lp->irq.msg); lp->irq.msg.context = &lp->irq; @@ -1509,6 +1516,7 @@ static int at86rf230_probe(struct spi_device *spi) spin_lock_init(&lp->lock); init_completion(&lp->tx_complete); + init_completion(&lp->state_complete); spi_set_drvdata(spi, lp); -- cgit v1.2.3 From 09e536cd4fb9bf52e729ec097bbe7d0651d3c69f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:52 +0200 Subject: at86rf230: rework reset to trx_off state change Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 265fea8a6030..a64914a39866 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -42,6 +42,7 @@ struct at86rf230_local; * All timings are in us. */ struct at86rf2xx_chip_data { + u16 t_reset_to_off; u16 t_off_to_aack; u16 t_off_to_tx_on; u16 t_frame; @@ -582,6 +583,16 @@ at86rf230_async_state_delay(void *context) break; } break; + /* Default value, means RESET state */ + case STATE_P_ON: + switch (ctx->to_state) { + case STATE_TRX_OFF: + usleep_range(c->t_reset_to_off, c->t_reset_to_off + 10); + goto change; + default: + break; + } + break; default: break; } @@ -1236,6 +1247,7 @@ static struct ieee802154_ops at86rf230_ops = { }; static struct at86rf2xx_chip_data at86rf233_data = { + .t_reset_to_off = 26, .t_off_to_aack = 80, .t_off_to_tx_on = 80, .t_frame = 4096, @@ -1249,6 +1261,7 @@ static struct at86rf2xx_chip_data at86rf233_data = { }; static struct at86rf2xx_chip_data at86rf231_data = { + .t_reset_to_off = 37, .t_off_to_aack = 110, .t_off_to_tx_on = 110, .t_frame = 4096, @@ -1262,6 +1275,7 @@ static struct at86rf2xx_chip_data at86rf231_data = { }; static struct at86rf2xx_chip_data at86rf212_data = { + .t_reset_to_off = 26, .t_off_to_aack = 200, .t_off_to_tx_on = 200, .t_frame = 4096, @@ -1280,7 +1294,7 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) unsigned int dvdd; u8 csma_seed[2]; - rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_FORCE_TRX_OFF); + rc = at86rf230_sync_state_change(lp, STATE_FORCE_TRX_OFF); if (rc) return rc; -- cgit v1.2.3 From 984e0c682c5aebdf65bab95906ec0538e9d6ee7d Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:53 +0200 Subject: at86rf230: add timing for channel switch Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index a64914a39866..dbf85b85a708 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -42,6 +42,7 @@ struct at86rf230_local; * All timings are in us. */ struct at86rf2xx_chip_data { + u16 t_channel_switch; u16 t_reset_to_off; u16 t_off_to_aack; u16 t_off_to_tx_on; @@ -1079,7 +1080,9 @@ at86rf230_channel(struct ieee802154_dev *dev, int page, int channel) if (rc < 0) return rc; - msleep(1); /* Wait for PLL */ + /* Wait for PLL */ + usleep_range(lp->data->t_channel_switch, + lp->data->t_channel_switch + 10); dev->phy->current_channel = channel; dev->phy->current_page = page; @@ -1247,6 +1250,7 @@ static struct ieee802154_ops at86rf230_ops = { }; static struct at86rf2xx_chip_data at86rf233_data = { + .t_channel_switch = 11, .t_reset_to_off = 26, .t_off_to_aack = 80, .t_off_to_tx_on = 80, @@ -1261,6 +1265,7 @@ static struct at86rf2xx_chip_data at86rf233_data = { }; static struct at86rf2xx_chip_data at86rf231_data = { + .t_channel_switch = 24, .t_reset_to_off = 37, .t_off_to_aack = 110, .t_off_to_tx_on = 110, @@ -1275,6 +1280,7 @@ static struct at86rf2xx_chip_data at86rf231_data = { }; static struct at86rf2xx_chip_data at86rf212_data = { + .t_channel_switch = 11, .t_reset_to_off = 26, .t_off_to_aack = 200, .t_off_to_tx_on = 200, -- cgit v1.2.3 From 7a4ef918541db1509226cca3b6fba2fd20f5f9bc Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:54 +0200 Subject: at86rf230: add sleep cycle timing Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index dbf85b85a708..79ec843416f7 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -42,6 +42,7 @@ struct at86rf230_local; * All timings are in us. */ struct at86rf2xx_chip_data { + u16 t_sleep_cycle; u16 t_channel_switch; u16 t_reset_to_off; u16 t_off_to_aack; @@ -1250,6 +1251,7 @@ static struct ieee802154_ops at86rf230_ops = { }; static struct at86rf2xx_chip_data at86rf233_data = { + .t_sleep_cycle = 330, .t_channel_switch = 11, .t_reset_to_off = 26, .t_off_to_aack = 80, @@ -1265,6 +1267,7 @@ static struct at86rf2xx_chip_data at86rf233_data = { }; static struct at86rf2xx_chip_data at86rf231_data = { + .t_sleep_cycle = 330, .t_channel_switch = 24, .t_reset_to_off = 37, .t_off_to_aack = 110, @@ -1280,6 +1283,7 @@ static struct at86rf2xx_chip_data at86rf231_data = { }; static struct at86rf2xx_chip_data at86rf212_data = { + .t_sleep_cycle = 330, .t_channel_switch = 11, .t_reset_to_off = 26, .t_off_to_aack = 200, @@ -1338,7 +1342,8 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) if (rc) return rc; /* Wait the next SLEEP cycle */ - msleep(100); + usleep_range(lp->data->t_sleep_cycle, + lp->data->t_sleep_cycle + 100); rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &dvdd); if (rc) -- cgit v1.2.3 From 01ebd60b0ac64fc1f3a449ca29f2c02b37727967 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 3 Jul 2014 00:20:55 +0200 Subject: at86rf230: add new author Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 79ec843416f7..c9d2a752abd7 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -19,6 +19,7 @@ * Written by: * Dmitry Eremin-Solenikov * Alexander Smirnov + * Alexander Aring */ #include #include -- cgit v1.2.3 From e721f87d806f2a959d6a530be18dabee6097aa79 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 2 Jul 2014 11:55:38 +0200 Subject: bonding: remove no longer relevant vlan warnings These warnings are no longer relevant. Even when last slave is removed, there is a valid address assigned to bond (random). The correct functionality of vlans is ensured by maintaining unicast list in vlan_sync_address(). Suggested-by: Jay Vosburgh Signed-off-by: Jiri Pirko Acked-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ffefb704b529..09dc3ef771a7 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1754,13 +1754,6 @@ static int __bond_release_one(struct net_device *bond_dev, if (!bond_has_slaves(bond)) { bond_set_carrier(bond); eth_hw_addr_random(bond_dev); - - if (vlan_uses_dev(bond_dev)) { - pr_warn("%s: Warning: clearing HW address of %s while it still has VLANs\n", - bond_dev->name, bond_dev->name); - pr_warn("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs\n", - bond_dev->name); - } } unblock_netpoll_tx(); -- cgit v1.2.3 From a16a3361927f75e6032df110920c83ca6c5045d3 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Wed, 2 Jul 2014 15:42:15 +0530 Subject: enic: fix return values in enic_set_coalesce enic_set_coalesce() has two problems. * It should return -EINVAL and not -EOPNOTSUPP for invalid coalesce values. * In case of MSIX, enic_set_coalesce return error after applying requested coalescing setting partially. We should either apply all the setting requeste and return success or apply non and return error. * This patch also simplifies the algo. This was introduced by '7c2ce6e60f703 enic: Add support for adaptive interrupt coalescing' These changes were suggested by Ben Hutchings here http://www.spinics.net/lists/netdev/msg283972.html Also change enic driver version. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic.h | 2 +- drivers/net/ethernet/cisco/enic/enic_ethtool.c | 27 +++++++++++--------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index c8aa9fb81d3c..4ecbbb3c024a 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -33,7 +33,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION "2.1.1.50" +#define DRV_VERSION "2.1.1.67" #define DRV_COPYRIGHT "Copyright 2008-2013 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c index 2e50b5489d20..c75f84b42751 100644 --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c @@ -231,7 +231,7 @@ static int enic_set_coalesce(struct net_device *netdev, if (ecmd->use_adaptive_rx_coalesce || ecmd->rx_coalesce_usecs_low || ecmd->rx_coalesce_usecs_high) - return -EOPNOTSUPP; + return -EINVAL; intr = enic_legacy_io_intr(); vnic_intr_coalescing_timer_set(&enic->intr[intr], @@ -243,34 +243,29 @@ static int enic_set_coalesce(struct net_device *netdev, if (ecmd->use_adaptive_rx_coalesce || ecmd->rx_coalesce_usecs_low || ecmd->rx_coalesce_usecs_high) - return -EOPNOTSUPP; + return -EINVAL; vnic_intr_coalescing_timer_set(&enic->intr[0], tx_coalesce_usecs); break; case VNIC_DEV_INTR_MODE_MSIX: + if (ecmd->rx_coalesce_usecs_high && + (rx_coalesce_usecs_high < + rx_coalesce_usecs_low + ENIC_AIC_LARGE_PKT_DIFF)) + return -EINVAL; + for (i = 0; i < enic->wq_count; i++) { intr = enic_msix_wq_intr(enic, i); vnic_intr_coalescing_timer_set(&enic->intr[intr], tx_coalesce_usecs); } - if (rxcoal->use_adaptive_rx_coalesce) { - if (!ecmd->use_adaptive_rx_coalesce) { - rxcoal->use_adaptive_rx_coalesce = 0; - enic_intr_coal_set_rx(enic, rx_coalesce_usecs); - } - } else { - if (ecmd->use_adaptive_rx_coalesce) - rxcoal->use_adaptive_rx_coalesce = 1; - else - enic_intr_coal_set_rx(enic, rx_coalesce_usecs); - } + rxcoal->use_adaptive_rx_coalesce = + !!ecmd->use_adaptive_rx_coalesce; + if (!rxcoal->use_adaptive_rx_coalesce) + enic_intr_coal_set_rx(enic, rx_coalesce_usecs); if (ecmd->rx_coalesce_usecs_high) { - if (rx_coalesce_usecs_high < - (rx_coalesce_usecs_low + ENIC_AIC_LARGE_PKT_DIFF)) - return -EINVAL; rxcoal->range_end = rx_coalesce_usecs_high; rxcoal->small_pkt_range_start = rx_coalesce_usecs_low; rxcoal->large_pkt_range_start = rx_coalesce_usecs_low + -- cgit v1.2.3 From db55b62cab8d458aba4e7a81dc4dd98b45c03d85 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 2 Jul 2014 14:12:01 +0200 Subject: net: arcnet: Remove "#define bool int" The header file include/linux/arcdevice.h #defines bool to int, if bool is not already #defined. However, the files which use that header file seem to rely on that #define (unconditionally) being in effect: the prototypes for the functions arcrimi_reset, com20020_reset, com90io_reset, com90xx_reset (whose addresses are assigned to the hw.reset member of struct arcnet_local) use int explicitly. Moreover, that #define is an accident waiting to happen (scenario: inclusion of arcdevice.h followed by inclusion of some header which declares function prototypes using bool). Also, #include must appear before #include (the compiler wouldn't like "typedef _Bool int"). Since none of the files using arcdevice.h declare variables of type "bool", the patch is actually quite simple, unlike the commit message. Signed-off-by: Rasmus Villemoes Signed-off-by: David S. Miller --- include/linux/arcdevice.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h index 7216b0daf544..df0356220730 100644 --- a/include/linux/arcdevice.h +++ b/include/linux/arcdevice.h @@ -22,10 +22,6 @@ #ifdef __KERNEL__ #include -#ifndef bool -#define bool int -#endif - /* * RECON_THRESHOLD is the maximum number of RECON messages to receive * within one minute before printing a "cabling problem" warning. The @@ -285,9 +281,9 @@ struct arcnet_local { unsigned long first_recon; /* time of "first" RECON message to count */ unsigned long last_recon; /* time of most recent RECON */ int num_recons; /* number of RECONs between first and last. */ - bool network_down; /* do we think the network is down? */ + int network_down; /* do we think the network is down? */ - bool excnak_pending; /* We just got an excesive nak interrupt */ + int excnak_pending; /* We just got an excesive nak interrupt */ struct { uint16_t sequence; /* sequence number (incs with each packet) */ @@ -305,7 +301,7 @@ struct arcnet_local { void (*command) (struct net_device * dev, int cmd); int (*status) (struct net_device * dev); void (*intmask) (struct net_device * dev, int mask); - bool (*reset) (struct net_device * dev, bool really_reset); + int (*reset) (struct net_device * dev, int really_reset); void (*open) (struct net_device * dev); void (*close) (struct net_device * dev); -- cgit v1.2.3 From f3f128d40c4cc263af8e30b009a3eb17655e912b Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 2 Jul 2014 13:04:28 -0500 Subject: amd-xgbe: Fix debugfs compatibility change with kstrtouint The initial change from sscanf to kstrtouint broke backward compatbility by using a base of "0" in the kstrtouint call. This allowed for entering decimal, hexadecimal or octal as input where previously the sscanf always interpreted the input as hexadecimal. Additionally, -EIO was returned on error prior to this change and now it is whatever the error value that is returned by kstrtouint. Change the base value of the kstrtouint from 0 to 16 and return -EIO on error. Signed-off-by: Tom Lendacky Reported-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c index 81198587a6c6..346592dca33c 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c @@ -165,9 +165,9 @@ static ssize_t xgbe_common_write(const char __user *buffer, size_t count, return len; workarea[len] = '\0'; - ret = kstrtouint(workarea, 0, value); + ret = kstrtouint(workarea, 16, value); if (ret) - return ret; + return -EIO; return len; } -- cgit v1.2.3 From 91f873453b70fe6cdb83409bee68e1023204c381 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 2 Jul 2014 13:04:34 -0500 Subject: amd-xgbe: Clear the proper MTL interrupt register When initializing the MTL interrupts the interrupt status register is written to instead of the interrupt enable register. Since no MTL interrupts are being enabled and the default state is for MTL interrupts to be disabled this did not cause a problem, but needs to be fixed to target the correct register. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index a56069c91fc4..e9fed23b2c33 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -486,7 +486,7 @@ static void xgbe_enable_mtl_interrupts(struct xgbe_prv_data *pdata) XGMAC_MTL_IOWRITE(pdata, i, MTL_Q_ISR, mtl_q_isr); /* No MTL interrupts to be enabled */ - XGMAC_MTL_IOWRITE(pdata, i, MTL_Q_ISR, 0); + XGMAC_MTL_IOWRITE(pdata, i, MTL_Q_IER, 0); } } -- cgit v1.2.3 From ff42606eed00bc065365f55269d558c06b968594 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 2 Jul 2014 13:04:40 -0500 Subject: amd-xgbe: Call netif_napi_del on ndo_stop operation Currently the napi context is added using netif_napi_add each time the ndo_open operation is called. However, there is not a corresponding netif_napi_del call during the ndo_stop operation. If the device ndo_open operation was called more than once an infinite loop occurs during module unload. Add a call to netif_napi_del during the ndo_stop operation. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 72dd61166a1c..b5fdf66f9a56 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -412,9 +412,12 @@ static void xgbe_napi_enable(struct xgbe_prv_data *pdata, unsigned int add) napi_enable(&pdata->napi); } -static void xgbe_napi_disable(struct xgbe_prv_data *pdata) +static void xgbe_napi_disable(struct xgbe_prv_data *pdata, unsigned int del) { napi_disable(&pdata->napi); + + if (del) + netif_napi_del(&pdata->napi); } void xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata) @@ -518,7 +521,7 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller) netif_device_detach(netdev); netif_tx_stop_all_queues(netdev); - xgbe_napi_disable(pdata); + xgbe_napi_disable(pdata, 0); /* Powerdown Tx/Rx */ hw_if->powerdown_tx(pdata); @@ -607,7 +610,7 @@ static void xgbe_stop(struct xgbe_prv_data *pdata) phy_stop(pdata->phydev); netif_tx_stop_all_queues(netdev); - xgbe_napi_disable(pdata); + xgbe_napi_disable(pdata, 1); xgbe_stop_tx_timers(pdata); -- cgit v1.2.3 From 9867e8fb2c45888cc594457914dcbba599f086c8 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 2 Jul 2014 13:04:46 -0500 Subject: amd-xgbe: Performance enhancements This patch provides some general performance enhancements for the driver: - Modify the default coalescing settings (reduce usec, increase frames) - Change the AXI burst length to 256 bytes (default was 16 bytes which was smaller than a cache line) - Change the AXI cache settings to write-back/write-allocate which allocate cache entries for received packets during the DMA since the packet will be processed soon afterwards - Combine ioread/iowrite when disabling both the Tx and Rx interrupts - Change to processing the Tx/Rx channels in pairs - Only recycle the Rx descriptors when a threshold of dirty descriptors is reached Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 2 + drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 73 +++++++++++------------ drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 91 ++++++++++++++++++----------- drivers/net/ethernet/amd/xgbe/xgbe.h | 12 ++-- 4 files changed, 100 insertions(+), 78 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index ccbceba553e5..7ec80ac7043f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -170,6 +170,8 @@ #define DMA_MR_SWR_WIDTH 1 #define DMA_SBMR_EAME_INDEX 11 #define DMA_SBMR_EAME_WIDTH 1 +#define DMA_SBMR_BLEN_256_INDEX 7 +#define DMA_SBMR_BLEN_256_WIDTH 1 #define DMA_SBMR_UNDEF_INDEX 0 #define DMA_SBMR_UNDEF_WIDTH 1 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index e9fed23b2c33..d6a45ced8adb 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -1306,56 +1306,48 @@ static int xgbe_is_last_desc(struct xgbe_ring_desc *rdesc) return XGMAC_GET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, LD); } -static void xgbe_save_interrupt_status(struct xgbe_channel *channel, - enum xgbe_int_state int_state) +static int xgbe_enable_int(struct xgbe_channel *channel, + enum xgbe_int int_id) { unsigned int dma_ch_ier; - if (int_state == XGMAC_INT_STATE_SAVE) { - channel->saved_ier = XGMAC_DMA_IOREAD(channel, DMA_CH_IER); - channel->saved_ier &= XGBE_DMA_INTERRUPT_MASK; - } else { - dma_ch_ier = XGMAC_DMA_IOREAD(channel, DMA_CH_IER); - dma_ch_ier |= channel->saved_ier; - XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier); - } -} + dma_ch_ier = XGMAC_DMA_IOREAD(channel, DMA_CH_IER); -static int xgbe_enable_int(struct xgbe_channel *channel, - enum xgbe_int int_id) -{ switch (int_id) { - case XGMAC_INT_DMA_ISR_DC0IS: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, TIE, 1); - break; case XGMAC_INT_DMA_CH_SR_TI: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, TIE, 1); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 1); break; case XGMAC_INT_DMA_CH_SR_TPS: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, TXSE, 1); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TXSE, 1); break; case XGMAC_INT_DMA_CH_SR_TBU: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, TBUE, 1); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TBUE, 1); break; case XGMAC_INT_DMA_CH_SR_RI: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, RIE, 1); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 1); break; case XGMAC_INT_DMA_CH_SR_RBU: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, RBUE, 1); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RBUE, 1); break; case XGMAC_INT_DMA_CH_SR_RPS: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, RSE, 1); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RSE, 1); + break; + case XGMAC_INT_DMA_CH_SR_TI_RI: + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 1); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 1); break; case XGMAC_INT_DMA_CH_SR_FBE: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, FBEE, 1); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, FBEE, 1); break; case XGMAC_INT_DMA_ALL: - xgbe_save_interrupt_status(channel, XGMAC_INT_STATE_RESTORE); + dma_ch_ier |= channel->saved_ier; break; default: return -1; } + XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier); + return 0; } @@ -1364,42 +1356,44 @@ static int xgbe_disable_int(struct xgbe_channel *channel, { unsigned int dma_ch_ier; + dma_ch_ier = XGMAC_DMA_IOREAD(channel, DMA_CH_IER); + switch (int_id) { - case XGMAC_INT_DMA_ISR_DC0IS: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, TIE, 0); - break; case XGMAC_INT_DMA_CH_SR_TI: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, TIE, 0); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 0); break; case XGMAC_INT_DMA_CH_SR_TPS: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, TXSE, 0); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TXSE, 0); break; case XGMAC_INT_DMA_CH_SR_TBU: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, TBUE, 0); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TBUE, 0); break; case XGMAC_INT_DMA_CH_SR_RI: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, RIE, 0); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 0); break; case XGMAC_INT_DMA_CH_SR_RBU: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, RBUE, 0); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RBUE, 0); break; case XGMAC_INT_DMA_CH_SR_RPS: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, RSE, 0); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RSE, 0); + break; + case XGMAC_INT_DMA_CH_SR_TI_RI: + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 0); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 0); break; case XGMAC_INT_DMA_CH_SR_FBE: - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_IER, FBEE, 0); + XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, FBEE, 0); break; case XGMAC_INT_DMA_ALL: - xgbe_save_interrupt_status(channel, XGMAC_INT_STATE_SAVE); - - dma_ch_ier = XGMAC_DMA_IOREAD(channel, DMA_CH_IER); + channel->saved_ier = dma_ch_ier & XGBE_DMA_INTERRUPT_MASK; dma_ch_ier &= ~XGBE_DMA_INTERRUPT_MASK; - XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier); break; default: return -1; } + XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier); + return 0; } @@ -1453,6 +1447,7 @@ static void xgbe_config_dma_bus(struct xgbe_prv_data *pdata) /* Set the System Bus mode */ XGMAC_IOWRITE_BITS(pdata, DMA_SBMR, UNDEF, 1); + XGMAC_IOWRITE_BITS(pdata, DMA_SBMR, BLEN_256, 1); } static void xgbe_config_dma_cache(struct xgbe_prv_data *pdata) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index b5fdf66f9a56..344e6b19ec0e 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -156,16 +156,21 @@ static void xgbe_enable_rx_tx_ints(struct xgbe_prv_data *pdata) { struct xgbe_hw_if *hw_if = &pdata->hw_if; struct xgbe_channel *channel; + enum xgbe_int int_id; unsigned int i; channel = pdata->channel; for (i = 0; i < pdata->channel_count; i++, channel++) { - if (channel->tx_ring) - hw_if->enable_int(channel, - XGMAC_INT_DMA_CH_SR_TI); - if (channel->rx_ring) - hw_if->enable_int(channel, - XGMAC_INT_DMA_CH_SR_RI); + if (channel->tx_ring && channel->rx_ring) + int_id = XGMAC_INT_DMA_CH_SR_TI_RI; + else if (channel->tx_ring) + int_id = XGMAC_INT_DMA_CH_SR_TI; + else if (channel->rx_ring) + int_id = XGMAC_INT_DMA_CH_SR_RI; + else + continue; + + hw_if->enable_int(channel, int_id); } } @@ -173,16 +178,21 @@ static void xgbe_disable_rx_tx_ints(struct xgbe_prv_data *pdata) { struct xgbe_hw_if *hw_if = &pdata->hw_if; struct xgbe_channel *channel; + enum xgbe_int int_id; unsigned int i; channel = pdata->channel; for (i = 0; i < pdata->channel_count; i++, channel++) { - if (channel->tx_ring) - hw_if->disable_int(channel, - XGMAC_INT_DMA_CH_SR_TI); - if (channel->rx_ring) - hw_if->disable_int(channel, - XGMAC_INT_DMA_CH_SR_RI); + if (channel->tx_ring && channel->rx_ring) + int_id = XGMAC_INT_DMA_CH_SR_TI_RI; + else if (channel->tx_ring) + int_id = XGMAC_INT_DMA_CH_SR_TI; + else if (channel->rx_ring) + int_id = XGMAC_INT_DMA_CH_SR_RI; + else + continue; + + hw_if->disable_int(channel, int_id); } } @@ -1114,6 +1124,22 @@ struct net_device_ops *xgbe_get_netdev_ops(void) return (struct net_device_ops *)&xgbe_netdev_ops; } +static void xgbe_rx_refresh(struct xgbe_channel *channel) +{ + struct xgbe_prv_data *pdata = channel->pdata; + struct xgbe_desc_if *desc_if = &pdata->desc_if; + struct xgbe_ring *ring = channel->rx_ring; + struct xgbe_ring_data *rdata; + + desc_if->realloc_skb(channel); + + /* Update the Rx Tail Pointer Register with address of + * the last cleaned entry */ + rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index - 1); + XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO, + lower_32_bits(rdata->rdesc_dma)); +} + static int xgbe_tx_poll(struct xgbe_channel *channel) { struct xgbe_prv_data *pdata = channel->pdata; @@ -1171,7 +1197,6 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) { struct xgbe_prv_data *pdata = channel->pdata; struct xgbe_hw_if *hw_if = &pdata->hw_if; - struct xgbe_desc_if *desc_if = &pdata->desc_if; struct xgbe_ring *ring = channel->rx_ring; struct xgbe_ring_data *rdata; struct xgbe_packet_data *packet; @@ -1198,6 +1223,9 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) cur_len = 0; read_again: + if (ring->dirty > (XGBE_RX_DESC_CNT >> 3)) + xgbe_rx_refresh(channel); + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); if (hw_if->dev_read(channel)) @@ -1285,16 +1313,6 @@ read_again: napi_gro_receive(&pdata->napi, skb); } - if (received) { - desc_if->realloc_skb(channel); - - /* Update the Rx Tail Pointer Register with address of - * the last cleaned entry */ - rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index - 1); - XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO, - lower_32_bits(rdata->rdesc_dma)); - } - DBGPR("<--xgbe_rx_poll: received = %d\n", received); return received; @@ -1305,21 +1323,28 @@ static int xgbe_poll(struct napi_struct *napi, int budget) struct xgbe_prv_data *pdata = container_of(napi, struct xgbe_prv_data, napi); struct xgbe_channel *channel; - int processed; + int ring_budget; + int processed, last_processed; unsigned int i; DBGPR("-->xgbe_poll: budget=%d\n", budget); - /* Cleanup Tx ring first */ - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) - xgbe_tx_poll(channel); - - /* Process Rx ring next */ processed = 0; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) - processed += xgbe_rx_poll(channel, budget - processed); + ring_budget = budget / pdata->rx_ring_count; + do { + last_processed = processed; + + channel = pdata->channel; + for (i = 0; i < pdata->channel_count; i++, channel++) { + /* Cleanup Tx ring first */ + xgbe_tx_poll(channel); + + /* Process Rx ring next */ + if (ring_budget > (budget - processed)) + ring_budget = budget - processed; + processed += xgbe_rx_poll(channel, ring_budget); + } + } while ((processed < budget) && (processed != last_processed)); /* If we processed everything, we are done */ if (processed < budget) { diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index a2d5f5f5d8b7..eef8ea1dee47 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -146,7 +146,7 @@ #define XGBE_DMA_ARDOMAIN 0x2 #define XGBE_DMA_ARCACHE 0xb #define XGBE_DMA_AWDOMAIN 0x2 -#define XGBE_DMA_AWCACHE 0x7 +#define XGBE_DMA_AWCACHE 0xf #define XGBE_DMA_INTERRUPT_MASK 0x31c7 @@ -181,12 +181,12 @@ /* Default coalescing parameters */ -#define XGMAC_INIT_DMA_TX_USECS 100 -#define XGMAC_INIT_DMA_TX_FRAMES 16 +#define XGMAC_INIT_DMA_TX_USECS 50 +#define XGMAC_INIT_DMA_TX_FRAMES 25 #define XGMAC_MAX_DMA_RIWT 0xff -#define XGMAC_INIT_DMA_RX_USECS 100 -#define XGMAC_INIT_DMA_RX_FRAMES 16 +#define XGMAC_INIT_DMA_RX_USECS 30 +#define XGMAC_INIT_DMA_RX_FRAMES 25 /* Flow control queue count */ #define XGMAC_MAX_FLOW_CONTROL_QUEUES 8 @@ -307,13 +307,13 @@ struct xgbe_channel { } ____cacheline_aligned; enum xgbe_int { - XGMAC_INT_DMA_ISR_DC0IS, XGMAC_INT_DMA_CH_SR_TI, XGMAC_INT_DMA_CH_SR_TPS, XGMAC_INT_DMA_CH_SR_TBU, XGMAC_INT_DMA_CH_SR_RI, XGMAC_INT_DMA_CH_SR_RBU, XGMAC_INT_DMA_CH_SR_RPS, + XGMAC_INT_DMA_CH_SR_TI_RI, XGMAC_INT_DMA_CH_SR_FBE, XGMAC_INT_DMA_ALL, }; -- cgit v1.2.3 From cfa50c7811fe3857fd882be96b2b2f130fa5da6d Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 2 Jul 2014 13:04:57 -0500 Subject: amd-xgbe: Base AXI DMA cache settings on device tree The default cache operations for ARM64 were changed during 3.15. To use coherent operations a "dma-coherent" device tree property is required. If that property is not present in the device tree node then the non-coherent operations are assigned for the device. Add support to the amd-xgbe driver to assign the AXI DMA cache settings based on whether the "dma-coherent" property is present in the device node. If present, use settings that work with the caches. If not present, use settings that do not look at the caches. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 28 ++++++++++++++-------------- drivers/net/ethernet/amd/xgbe/xgbe-main.c | 10 ++++++++++ drivers/net/ethernet/amd/xgbe/xgbe.h | 17 +++++++++++++---- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index d6a45ced8adb..699cff5d3184 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -1455,23 +1455,23 @@ static void xgbe_config_dma_cache(struct xgbe_prv_data *pdata) unsigned int arcache, awcache; arcache = 0; - XGMAC_SET_BITS(arcache, DMA_AXIARCR, DRC, XGBE_DMA_ARCACHE); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, DRD, XGBE_DMA_ARDOMAIN); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, TEC, XGBE_DMA_ARCACHE); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, TED, XGBE_DMA_ARDOMAIN); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, THC, XGBE_DMA_ARCACHE); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, THD, XGBE_DMA_ARDOMAIN); + XGMAC_SET_BITS(arcache, DMA_AXIARCR, DRC, pdata->arcache); + XGMAC_SET_BITS(arcache, DMA_AXIARCR, DRD, pdata->axdomain); + XGMAC_SET_BITS(arcache, DMA_AXIARCR, TEC, pdata->arcache); + XGMAC_SET_BITS(arcache, DMA_AXIARCR, TED, pdata->axdomain); + XGMAC_SET_BITS(arcache, DMA_AXIARCR, THC, pdata->arcache); + XGMAC_SET_BITS(arcache, DMA_AXIARCR, THD, pdata->axdomain); XGMAC_IOWRITE(pdata, DMA_AXIARCR, arcache); awcache = 0; - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, DWC, XGBE_DMA_AWCACHE); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, DWD, XGBE_DMA_AWDOMAIN); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RPC, XGBE_DMA_AWCACHE); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RPD, XGBE_DMA_AWDOMAIN); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RHC, XGBE_DMA_AWCACHE); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RHD, XGBE_DMA_AWDOMAIN); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, TDC, XGBE_DMA_AWCACHE); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, TDD, XGBE_DMA_AWDOMAIN); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, DWC, pdata->awcache); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, DWD, pdata->axdomain); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RPC, pdata->awcache); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RPD, pdata->axdomain); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RHC, pdata->awcache); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RHD, pdata->axdomain); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, TDC, pdata->awcache); + XGMAC_SET_BITS(awcache, DMA_AXIAWCR, TDD, pdata->axdomain); XGMAC_IOWRITE(pdata, DMA_AXIAWCR, awcache); } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index b411ac557c47..d5a4f76e9474 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -297,6 +297,16 @@ static int xgbe_probe(struct platform_device *pdev) *(dev->dma_mask) = DMA_BIT_MASK(40); dev->coherent_dma_mask = DMA_BIT_MASK(40); + if (of_property_read_bool(dev->of_node, "dma-coherent")) { + pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; + pdata->arcache = XGBE_DMA_OS_ARCACHE; + pdata->awcache = XGBE_DMA_OS_AWCACHE; + } else { + pdata->axdomain = XGBE_DMA_SYS_AXDOMAIN; + pdata->arcache = XGBE_DMA_SYS_ARCACHE; + pdata->awcache = XGBE_DMA_SYS_AWCACHE; + } + ret = platform_get_irq(pdev, 0); if (ret < 0) { dev_err(dev, "platform_get_irq failed\n"); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index eef8ea1dee47..9e24b296e272 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -143,10 +143,14 @@ #define XGBE_MAX_DMA_CHANNELS 16 /* DMA cache settings - Outer sharable, write-back, write-allocate */ -#define XGBE_DMA_ARDOMAIN 0x2 -#define XGBE_DMA_ARCACHE 0xb -#define XGBE_DMA_AWDOMAIN 0x2 -#define XGBE_DMA_AWCACHE 0xf +#define XGBE_DMA_OS_AXDOMAIN 0x2 +#define XGBE_DMA_OS_ARCACHE 0xb +#define XGBE_DMA_OS_AWCACHE 0xf + +/* DMA cache settings - System, no caches used */ +#define XGBE_DMA_SYS_AXDOMAIN 0x3 +#define XGBE_DMA_SYS_ARCACHE 0x0 +#define XGBE_DMA_SYS_AWCACHE 0x0 #define XGBE_DMA_INTERRUPT_MASK 0x31c7 @@ -536,6 +540,11 @@ struct xgbe_prv_data { struct xgbe_hw_if hw_if; struct xgbe_desc_if desc_if; + /* AXI DMA settings */ + unsigned int axdomain; + unsigned int arcache; + unsigned int awcache; + /* Rings for Tx/Rx on a DMA channel */ struct xgbe_channel *channel; unsigned int channel_count; -- cgit v1.2.3 From 5fc7d86c7afd61ac8c9d468cba014c472e9c4dcb Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 8 Jul 2014 08:44:31 +0300 Subject: iwlwifi: mvm: BT Coex - fix TLC with old API A copy paste issue broke the rate control when a firmware with the old API is used. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 8110fe00bf55..e0a5cf29c38e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -1150,7 +1150,7 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, enum iwl_bt_coex_lut_type lut_type; if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) - return iwl_mvm_coex_agg_time_limit_old(mvm, sta); + return iwl_mvm_bt_coex_is_mimo_allowed_old(mvm, sta); if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id)) return true; -- cgit v1.2.3 From 66c417c1ee01398ac5ab1c749a20c4d8ba50e9a9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Jul 2014 15:07:47 +0300 Subject: Bluetooth: Add flag to track the real advertising state Having a single HCI_ADVERTISING flag is problematic since it tries to track both the real advertising state and the corresponding mgmt setting. To make the logic simpler and more reliable add a new flag that only tracks the actual advertising state that has been written to the controller. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 4 ++-- net/bluetooth/hci_event.c | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 5481d1c8badb..6ed1f7288f13 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -175,7 +175,7 @@ enum { HCI_UNCONFIGURED, HCI_USER_CHANNEL, HCI_EXT_CONFIGURED, - + HCI_LE_ADV, HCI_LE_SCAN, HCI_SSP_ENABLED, HCI_SC_ENABLED, @@ -200,7 +200,7 @@ enum { * or the HCI device is closed. */ #define HCI_PERSISTENT_MASK (BIT(HCI_LE_SCAN) | BIT(HCI_PERIODIC_INQ) | \ - BIT(HCI_FAST_CONNECTABLE)) + BIT(HCI_FAST_CONNECTABLE) | BIT(HCI_LE_ADV)) /* HCI ioctl defines */ #define HCIDEVUP _IOW('H', 201, int) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a6816498b0b9..10f8de9400bc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1069,11 +1069,15 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) if (*sent) { struct hci_conn *conn; + set_bit(HCI_LE_ADV, &hdev->dev_flags); + conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); if (conn) queue_delayed_work(hdev->workqueue, &conn->le_conn_timeout, conn->conn_timeout); + } else { + clear_bit(HCI_LE_ADV, &hdev->dev_flags); } mgmt_advertising(hdev, *sent); -- cgit v1.2.3 From c93bd15033027928709ee15bab2ce1f5582085c6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Jul 2014 15:07:48 +0300 Subject: Bluetooth: Remove unnecessary mgmt_advertising function Since the real advertising state is now tracked with its own flag we can simply set/unset the HCI_ADVERTISING flag in the set_advertising_complete function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_event.c | 2 -- net/bluetooth/mgmt.c | 17 +++++------------ 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5701d15779dd..c98de309967e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1292,7 +1292,6 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered); void mgmt_discoverable_timeout(struct hci_dev *hdev); void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); void mgmt_connectable(struct hci_dev *hdev, u8 connectable); -void mgmt_advertising(struct hci_dev *hdev, u8 advertising); void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 10f8de9400bc..8fbf604ba228 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1080,8 +1080,6 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) clear_bit(HCI_LE_ADV, &hdev->dev_flags); } - mgmt_advertising(hdev, *sent); - hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9cc7108f4c45..dda1eb124208 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4034,6 +4034,11 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status) return; } + if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) + set_bit(HCI_ADVERTISING, &hdev->dev_flags); + else + clear_bit(HCI_ADVERTISING, &hdev->dev_flags); + mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp, &match); @@ -5978,18 +5983,6 @@ void mgmt_connectable(struct hci_dev *hdev, u8 connectable) new_settings(hdev, NULL); } -void mgmt_advertising(struct hci_dev *hdev, u8 advertising) -{ - /* Powering off may stop advertising - don't let that interfere */ - if (!advertising && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) - return; - - if (advertising) - set_bit(HCI_ADVERTISING, &hdev->dev_flags); - else - clear_bit(HCI_ADVERTISING, &hdev->dev_flags); -} - void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) { u8 mgmt_err = mgmt_status(status); -- cgit v1.2.3 From 5ce194c4a751ac603966dd1567b62035a7dfbf89 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Jul 2014 15:07:49 +0300 Subject: Bluetooth: Use real advertising state to random address update decision Now that we have a flag for tracking the real advertising state we should use that to determine whether it's safe to update the random address or not. The couple of places that were clearing the flag due to a pending request need to be updated too. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 4 ++-- net/bluetooth/hci_core.c | 2 +- net/bluetooth/mgmt.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 16fd55da9c1d..0db2579ea6c6 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -671,12 +671,12 @@ static void hci_req_directed_advertising(struct hci_request *req, enable = 0x00; hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); - /* Clear the HCI_ADVERTISING bit temporarily so that the + /* Clear the HCI_LE_ADV bit temporarily so that the * hci_update_random_address knows that it's safe to go ahead * and write a new random address. The flag will be set back on * as soon as the SET_ADV_ENABLE HCI command completes. */ - clear_bit(HCI_ADVERTISING, &hdev->dev_flags); + clear_bit(HCI_LE_ADV, &hdev->dev_flags); /* Set require_privacy to false so that the remote device has a * chance of identifying us. diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f1c5a077e558..8ffaca0290f8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3746,7 +3746,7 @@ static void set_random_addr(struct hci_request *req, bdaddr_t *rpa) * In this kind of scenario skip the update and let the random * address be updated at the next cycle. */ - if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) || + if (test_bit(HCI_LE_ADV, &hdev->dev_flags) || hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) { BT_DBG("Deferring random address update"); return; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index dda1eb124208..be589d8d437f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1046,12 +1046,12 @@ static void enable_advertising(struct hci_request *req) u8 own_addr_type, enable = 0x01; bool connectable; - /* Clear the HCI_ADVERTISING bit temporarily so that the + /* Clear the HCI_LE_ADV bit temporarily so that the * hci_update_random_address knows that it's safe to go ahead * and write a new random address. The flag will be set back on * as soon as the SET_ADV_ENABLE HCI command completes. */ - clear_bit(HCI_ADVERTISING, &hdev->dev_flags); + clear_bit(HCI_LE_ADV, &hdev->dev_flags); connectable = get_connectable(hdev); -- cgit v1.2.3 From 0ec5ae8438af02bf2295f08585d8ab49d15eaf2c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Jul 2014 15:07:50 +0300 Subject: Bluetooth: Simplify usage of the enable_advertising function By adding support for disabling advertising when necessary and doing the checks for existing LE connections inside the enable_advertising function we can simplify the calling code quite a lot. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 49 ++++++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index be589d8d437f..68c0698124fb 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1039,6 +1039,13 @@ static bool get_connectable(struct hci_dev *hdev) return test_bit(HCI_CONNECTABLE, &hdev->dev_flags); } +static void disable_advertising(struct hci_request *req) +{ + u8 enable = 0x00; + + hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); +} + static void enable_advertising(struct hci_request *req) { struct hci_dev *hdev = req->hdev; @@ -1046,6 +1053,12 @@ static void enable_advertising(struct hci_request *req) u8 own_addr_type, enable = 0x01; bool connectable; + if (hci_conn_num(hdev, LE_LINK) > 0) + return; + + if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) + disable_advertising(req); + /* Clear the HCI_LE_ADV bit temporarily so that the * hci_update_random_address knows that it's safe to go ahead * and write a new random address. The flag will be set back on @@ -1074,13 +1087,6 @@ static void enable_advertising(struct hci_request *req) hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); } -static void disable_advertising(struct hci_request *req) -{ - u8 enable = 0x00; - - hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); -} - static void service_cache_off(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, @@ -1112,19 +1118,14 @@ static void rpa_expired(struct work_struct *work) set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags); - if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags) || - hci_conn_num(hdev, LE_LINK) > 0) + if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags)) return; /* The generation of a new RPA and programming it into the * controller happens in the enable_advertising() function. */ - hci_req_init(&req, hdev); - - disable_advertising(&req); enable_advertising(&req); - hci_req_run(&req, NULL); } @@ -1864,10 +1865,8 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, write_fast_connectable(&req, false); if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && - hci_conn_num(hdev, LE_LINK) == 0) { - disable_advertising(&req); + !test_bit(HCI_LE_ADV, &hdev->dev_flags)) enable_advertising(&req); - } err = hci_req_run(&req, set_connectable_complete); if (err < 0) { @@ -6809,32 +6808,16 @@ void mgmt_discovering(struct hci_dev *hdev, u8 discovering) static void adv_enable_complete(struct hci_dev *hdev, u8 status) { BT_DBG("%s status %u", hdev->name, status); - - /* Clear the advertising mgmt setting if we failed to re-enable it */ - if (status) { - clear_bit(HCI_ADVERTISING, &hdev->dev_flags); - new_settings(hdev, NULL); - } } void mgmt_reenable_advertising(struct hci_dev *hdev) { struct hci_request req; - if (hci_conn_num(hdev, LE_LINK) > 0) - return; - if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags)) return; hci_req_init(&req, hdev); enable_advertising(&req); - - /* If this fails we have no option but to let user space know - * that we've disabled advertising. - */ - if (hci_req_run(&req, adv_enable_complete) < 0) { - clear_bit(HCI_ADVERTISING, &hdev->dev_flags); - new_settings(hdev, NULL); - } + hci_req_run(&req, adv_enable_complete); } -- cgit v1.2.3 From 73e082f80d990c017c695a6750f7ac96cdc6308a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Jul 2014 15:07:51 +0300 Subject: Bluetooth: Use the correct flag to decide to disable advertising When deciding to call disable_advertising() we're interested in the real state instead of the mgmt setting. Use therefore HCI_LE_ADV instead of the HCI_ADVERTISING flag. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 68c0698124fb..9549d7366da2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1301,7 +1301,7 @@ static int clean_up_hci_state(struct hci_dev *hdev) hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); } - if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) + if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) disable_advertising(&req); hci_stop_discovery(&req); @@ -2230,7 +2230,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) hci_cp.le = val; hci_cp.simul = lmp_le_br_capable(hdev); } else { - if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) + if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) disable_advertising(&req); } -- cgit v1.2.3 From 376f54c171674ac1f9a2eefe67d413db4836d25a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Jul 2014 15:07:52 +0300 Subject: Bluetooth: Stop advertising always before initiating a connection Most controllers do not support advertising while initiating an LE connection. We also have to first disable current advertising if the initiation is going to happen through direct advertising. Therefore, simply stop advertising as the first thing when starting to issue commands to establish an LE connection. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 0db2579ea6c6..1517f1549f85 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -668,9 +668,6 @@ static void hci_req_directed_advertising(struct hci_request *req, u8 own_addr_type; u8 enable; - enable = 0x00; - hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); - /* Clear the HCI_LE_ADV bit temporarily so that the * hci_update_random_address knows that it's safe to go ahead * and write a new random address. The flag will be set back on @@ -761,6 +758,18 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, hci_req_init(&req, hdev); + /* Disable advertising if we're active. For master role + * connections most controllers will refuse to connect if + * advertising is enabled, and for slave role connections we + * anyway have to disable it in order to start directed + * advertising. + */ + if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) { + u8 enable = 0x00; + hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), + &enable); + } + /* If requested to connect as slave use directed advertising */ if (!master) { hci_req_directed_advertising(&req, conn); -- cgit v1.2.3 From e8bb6b9739e2e80e0e413f56816af3871388cfe8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Jul 2014 15:07:53 +0300 Subject: Bluetooth: Fix advertising and active scanning co-existence Many controllers allow simultaneous active scanning and advertising (e.g. Intel and Broadcom) but some do not (e.g. CSR). It's therefore safest to implement mutual exclusion of these states in the kernel. This patch ensures that the two states are never entered simultaneously. Extra precaution needs to be taken for outgoing connection attempts in slave role (i.e. through directed advertising) in which case the operation that came first has precedence and the one that comes after gets a rejection. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 10 ++++++++++ net/bluetooth/hci_event.c | 10 +++++++++- net/bluetooth/mgmt.c | 24 ++++++++++++++++++------ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 1517f1549f85..490ee8846d9e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -772,6 +772,16 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, /* If requested to connect as slave use directed advertising */ if (!master) { + /* If we're active scanning most controllers are unable + * to initiate advertising. Simply reject the attempt. + */ + if (test_bit(HCI_LE_SCAN, &hdev->dev_flags) && + hdev->le_scan_type == LE_SCAN_ACTIVE) { + skb_queue_purge(&req.cmd_q); + hci_conn_del(conn); + return ERR_PTR(-EBUSY); + } + hci_req_directed_advertising(&req, conn); goto create_conn; } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8fbf604ba228..5d3095d7d4b0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1176,13 +1176,21 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, cancel_delayed_work(&hdev->le_scan_disable); clear_bit(HCI_LE_SCAN, &hdev->dev_flags); + /* The HCI_LE_SCAN_INTERRUPTED flag indicates that we * interrupted scanning due to a connect request. Mark - * therefore discovery as stopped. + * therefore discovery as stopped. If this was not + * because of a connect request advertising might have + * been disabled because of active scanning, so + * re-enable it again if necessary. */ if (test_and_clear_bit(HCI_LE_SCAN_INTERRUPTED, &hdev->dev_flags)) hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + else if (!test_bit(HCI_LE_ADV, &hdev->dev_flags) && + hdev->discovery.state != DISCOVERY_STARTING) + mgmt_reenable_advertising(hdev); + break; default: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9549d7366da2..944e6463fd61 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3726,11 +3726,21 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, goto failed; } - if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) { - err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_REJECTED); - mgmt_pending_remove(cmd); - goto failed; + if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) { + /* Don't let discovery abort an outgoing + * connection attempt that's using directed + * advertising. + */ + if (hci_conn_hash_lookup_state(hdev, LE_LINK, + BT_CONNECT)) { + err = cmd_status(sk, hdev->id, + MGMT_OP_START_DISCOVERY, + MGMT_STATUS_REJECTED); + mgmt_pending_remove(cmd); + goto failed; + } + + disable_advertising(&req); } /* If controller is scanning, it means the background scanning @@ -4078,7 +4088,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, * necessary). */ if (!hdev_is_powered(hdev) || val == enabled || - hci_conn_num(hdev, LE_LINK) > 0) { + hci_conn_num(hdev, LE_LINK) > 0 || + (test_bit(HCI_LE_SCAN, &hdev->dev_flags) && + hdev->le_scan_type == LE_SCAN_ACTIVE)) { bool changed = false; if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) { -- cgit v1.2.3 From 34722277045f84d0ee618865d02030a44b1ed257 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Jul 2014 16:05:05 +0300 Subject: Bluetooth: Fix check for re-enabling advertising There are many different places that can disable LE scanning but we only want to re-enable advertising in hci_cc_le_set_scan_enable() for a very specific use case, which is when the active scanning part of Start Discovery is complete. Because of this, fix the discovery state check to test for the exact state. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5d3095d7d4b0..2b3d366e5d98 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1188,7 +1188,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, &hdev->dev_flags)) hci_discovery_set_state(hdev, DISCOVERY_STOPPED); else if (!test_bit(HCI_LE_ADV, &hdev->dev_flags) && - hdev->discovery.state != DISCOVERY_STARTING) + hdev->discovery.state == DISCOVERY_FINDING) mgmt_reenable_advertising(hdev); break; -- cgit v1.2.3 From 23a48093b53999f8539144db1d9567964a84655c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Jul 2014 16:05:06 +0300 Subject: Bluetooth: Fix setting STOPPING state for discovery If any of the HCI commands from the hci_stop_discovery function were successfully sent we need to set the discovery state to STOPPING. The Stop Discovery code was already handling this, but the code in clean_up_hci_state was not. This patch updates the hci_stop_discovery to return a bool to indicate whether it queued any commands and the clean_up_hci_state() function respectively to look at the return value and call hci_discovery_set_state() if necessary. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 944e6463fd61..a4232bc237f3 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1251,7 +1251,7 @@ static void clean_up_hci_complete(struct hci_dev *hdev, u8 status) } } -static void hci_stop_discovery(struct hci_request *req) +static bool hci_stop_discovery(struct hci_request *req) { struct hci_dev *hdev = req->hdev; struct hci_cp_remote_name_req_cancel cp; @@ -1266,32 +1266,39 @@ static void hci_stop_discovery(struct hci_request *req) hci_req_add_le_scan_disable(req); } - break; + return true; case DISCOVERY_RESOLVING: e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING); if (!e) - return; + break; bacpy(&cp.bdaddr, &e->data.bdaddr); hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp), &cp); - break; + return true; default: /* Passive scanning */ - if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) + if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) { hci_req_add_le_scan_disable(req); + return true; + } + break; } + + return false; } static int clean_up_hci_state(struct hci_dev *hdev) { struct hci_request req; struct hci_conn *conn; + bool discov_stopped; + int err; hci_req_init(&req, hdev); @@ -1304,7 +1311,7 @@ static int clean_up_hci_state(struct hci_dev *hdev) if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) disable_advertising(&req); - hci_stop_discovery(&req); + discov_stopped = hci_stop_discovery(&req); list_for_each_entry(conn, &hdev->conn_hash.list, list) { struct hci_cp_disconnect dc; @@ -1338,7 +1345,11 @@ static int clean_up_hci_state(struct hci_dev *hdev) } } - return hci_req_run(&req, clean_up_hci_complete); + err = hci_req_run(&req, clean_up_hci_complete); + if (!err && discov_stopped) + hci_discovery_set_state(hdev, DISCOVERY_STOPPING); + + return err; } static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, -- cgit v1.2.3 From 3742abfc4e853f9c926982d8d45be6ff010966ae Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Jul 2014 16:07:34 +0300 Subject: Bluetooth: Fix connectable and discoverable supported settings values The connectable and discoverable mgmt settings are supported both for LE and BR/EDR controllers so they do not belong behind a lmp_bredr_capable() condition. This patch fixes the issue in get_supported_settings(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a4232bc237f3..376b164c5250 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -555,12 +555,12 @@ static u32 get_supported_settings(struct hci_dev *hdev) settings |= MGMT_SETTING_POWERED; settings |= MGMT_SETTING_PAIRABLE; settings |= MGMT_SETTING_DEBUG_KEYS; + settings |= MGMT_SETTING_CONNECTABLE; + settings |= MGMT_SETTING_DISCOVERABLE; if (lmp_bredr_capable(hdev)) { - settings |= MGMT_SETTING_CONNECTABLE; if (hdev->hci_ver >= BLUETOOTH_VER_1_2) settings |= MGMT_SETTING_FAST_CONNECTABLE; - settings |= MGMT_SETTING_DISCOVERABLE; settings |= MGMT_SETTING_BREDR; settings |= MGMT_SETTING_LINK_SECURITY; -- cgit v1.2.3 From 562064e654d42599ad986812adaded653f3b81df Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Jul 2014 16:35:34 +0300 Subject: Bluetooth: Fix toggling background scan when changing connectable state If the connectable state change doesn't require any special HCI commands the set_connectable_update_settings() function is used instead of the set_connectable_complete() function. We must therefore make sure to call hci_update_background_scan() there as well. This code path is used also when we're powered off, but that's fine since hci_update_background_scan() has the necessary checks for it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 376b164c5250..216aa93514b6 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1794,8 +1794,10 @@ static int set_connectable_update_settings(struct hci_dev *hdev, if (err < 0) return err; - if (changed) + if (changed) { + hci_update_background_scan(hdev); return new_settings(hdev, sk); + } return 0; } -- cgit v1.2.3 From fbd96c151cdcadb0ce83b45747d738498d72aa9d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 8 Jul 2014 17:21:51 +0300 Subject: Bluetooth: Fix clearing HCI_LE_ADV for LE connections All LE controllers always implicitly stop advertising when establishing connections. Therefore, be sure to clear the flag in the event handler for new LE connections. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 2b3d366e5d98..f6997901bdd7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4097,6 +4097,11 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); + /* All controllers implicitly stop advertising in the event of a + * connection, so ensure that the state bit is cleared. + */ + clear_bit(HCI_LE_ADV, &hdev->dev_flags); + conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); if (!conn) { conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr); -- cgit v1.2.3 From fa2f1394fe9c1a217213f02df77812701de6362f Mon Sep 17 00:00:00 2001 From: Anantha Krishnan Date: Tue, 8 Jul 2014 19:25:08 +0530 Subject: Bluetooth: Add support for Acer [13D3:3432] Add support for the QCA6174 chip. T: Bus=04 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 30 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3432 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: Anantha Krishnan Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index abe6aecbabb2..230c552daf91 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -103,6 +103,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x13d3, 0x3375) }, { USB_DEVICE(0x13d3, 0x3393) }, { USB_DEVICE(0x13d3, 0x3402) }, + { USB_DEVICE(0x13d3, 0x3432) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, @@ -152,6 +153,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU22 with sflash firmware */ { USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ef4375d5c4ed..ed7b33b06b43 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -177,6 +177,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, -- cgit v1.2.3 From 4f6ad60cf357e1663d84de052af68dfccd734ec7 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 2 Jul 2014 22:22:20 +0200 Subject: ipconfig: add static to local variable ic_dev_xid is only used in ipconfig.c Cc: "David S. Miller" Cc: Alexey Kuznetsov Cc: netdev@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/ipv4/ipconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index b3e86ea7b71b..f0f3f9f77b30 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -143,7 +143,7 @@ __be32 ic_servaddr = NONE; /* Boot server IP address */ __be32 root_server_addr = NONE; /* Address of NFS server */ u8 root_server_path[256] = { 0, }; /* Path to mount as root */ -__be32 ic_dev_xid; /* Device under configuration */ +static __be32 ic_dev_xid; /* Device under configuration */ /* vendor class identifier */ static char vendor_class_identifier[253] __initdata; -- cgit v1.2.3 From b8125404c242a6336eacaa54047b27cfd3fee68e Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 3 Jul 2014 11:55:48 +0800 Subject: r8152: increase the tx timeout When the system is too busy to complete the urb, the tx timout function would be called. This causes the other tx urbs would be killed, too. Increase the tx timeout to avoid it. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 25431965a625..e9685ce98327 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -441,7 +441,7 @@ enum rtl_register_content { #define BYTE_EN_END_MASK 0xf0 #define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN) -#define RTL8152_TX_TIMEOUT (HZ) +#define RTL8152_TX_TIMEOUT (5 * HZ) /* rtl8152 flags */ enum rtl8152_flags { -- cgit v1.2.3 From 70ebe4a47185db15f3c55be9611a1a971237870b Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Fri, 4 Jul 2014 23:34:38 +0200 Subject: net/hsr: Better variable names and update of contact info. Signed-off-by: Arvid Brodin Signed-off-by: David S. Miller --- net/hsr/hsr_device.c | 207 ++++++++++++++++++++++++------------------------- net/hsr/hsr_device.h | 6 +- net/hsr/hsr_framereg.c | 108 +++++++++++++------------- net/hsr/hsr_framereg.h | 36 ++++----- net/hsr/hsr_main.c | 170 ++++++++++++++++++++-------------------- net/hsr/hsr_main.h | 20 ++--- net/hsr/hsr_netlink.c | 54 ++++++------- net/hsr/hsr_netlink.h | 8 +- 8 files changed, 304 insertions(+), 305 deletions(-) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index e5302b7f7ca9..4dc2a4207ee2 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -1,4 +1,4 @@ -/* Copyright 2011-2013 Autronica Fire and Security AS +/* Copyright 2011-2014 Autronica Fire and Security AS * * 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 @@ -6,7 +6,7 @@ * any later version. * * Author(s): - * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com + * 2011-2014 Arvid Brodin, arvid.brodin@alten.se * * This file contains device methods for creating, using and destroying * virtual HSR devices. @@ -71,49 +71,49 @@ void hsr_set_carrier(struct net_device *hsr_dev, struct net_device *slave1, void hsr_check_announce(struct net_device *hsr_dev, int old_operstate) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; - hsr_priv = netdev_priv(hsr_dev); + hsr = netdev_priv(hsr_dev); if ((hsr_dev->operstate == IF_OPER_UP) && (old_operstate != IF_OPER_UP)) { /* Went up */ - hsr_priv->announce_count = 0; - hsr_priv->announce_timer.expires = jiffies + + hsr->announce_count = 0; + hsr->announce_timer.expires = jiffies + msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL); - add_timer(&hsr_priv->announce_timer); + add_timer(&hsr->announce_timer); } if ((hsr_dev->operstate != IF_OPER_UP) && (old_operstate == IF_OPER_UP)) /* Went down */ - del_timer(&hsr_priv->announce_timer); + del_timer(&hsr->announce_timer); } -int hsr_get_max_mtu(struct hsr_priv *hsr_priv) +int hsr_get_max_mtu(struct hsr_priv *hsr) { int mtu_max; - if (hsr_priv->slave[0] && hsr_priv->slave[1]) - mtu_max = min(hsr_priv->slave[0]->mtu, hsr_priv->slave[1]->mtu); - else if (hsr_priv->slave[0]) - mtu_max = hsr_priv->slave[0]->mtu; - else if (hsr_priv->slave[1]) - mtu_max = hsr_priv->slave[1]->mtu; + if (hsr->slave[0] && hsr->slave[1]) + mtu_max = min(hsr->slave[0]->mtu, hsr->slave[1]->mtu); + else if (hsr->slave[0]) + mtu_max = hsr->slave[0]->mtu; + else if (hsr->slave[1]) + mtu_max = hsr->slave[1]->mtu; else - mtu_max = HSR_TAGLEN; + mtu_max = HSR_HLEN; - return mtu_max - HSR_TAGLEN; + return mtu_max - HSR_HLEN; } static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; - hsr_priv = netdev_priv(dev); + hsr = netdev_priv(dev); - if (new_mtu > hsr_get_max_mtu(hsr_priv)) { - netdev_info(hsr_priv->dev, "A HSR master's MTU cannot be greater than the smallest MTU of its slaves minus the HSR Tag length (%d octets).\n", - HSR_TAGLEN); + if (new_mtu > hsr_get_max_mtu(hsr)) { + netdev_info(hsr->dev, "A HSR master's MTU cannot be greater than the smallest MTU of its slaves minus the HSR Tag length (%d octets).\n", + HSR_HLEN); return -EINVAL; } @@ -124,19 +124,19 @@ static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu) static int hsr_dev_open(struct net_device *dev) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; int i; char *slave_name; - hsr_priv = netdev_priv(dev); + hsr = netdev_priv(dev); for (i = 0; i < HSR_MAX_SLAVE; i++) { - if (hsr_priv->slave[i]) - slave_name = hsr_priv->slave[i]->name; + if (hsr->slave[i]) + slave_name = hsr->slave[i]->name; else slave_name = "null"; - if (!is_slave_up(hsr_priv->slave[i])) + if (!is_slave_up(hsr->slave[i])) netdev_warn(dev, "Slave %c (%s) is not up; please bring it up to get a working HSR network\n", 'A' + i, slave_name); } @@ -156,7 +156,7 @@ static int hsr_dev_close(struct net_device *dev) } -static void hsr_fill_tag(struct hsr_ethhdr *hsr_ethhdr, struct hsr_priv *hsr_priv) +static void hsr_fill_tag(struct hsr_ethhdr *hsr_ethhdr, struct hsr_priv *hsr) { unsigned long irqflags; @@ -185,26 +185,26 @@ static void hsr_fill_tag(struct hsr_ethhdr *hsr_ethhdr, struct hsr_priv *hsr_pri */ set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, 0); - spin_lock_irqsave(&hsr_priv->seqnr_lock, irqflags); - hsr_ethhdr->hsr_tag.sequence_nr = htons(hsr_priv->sequence_nr); - hsr_priv->sequence_nr++; - spin_unlock_irqrestore(&hsr_priv->seqnr_lock, irqflags); + spin_lock_irqsave(&hsr->seqnr_lock, irqflags); + hsr_ethhdr->hsr_tag.sequence_nr = htons(hsr->sequence_nr); + hsr->sequence_nr++; + spin_unlock_irqrestore(&hsr->seqnr_lock, irqflags); hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto; hsr_ethhdr->ethhdr.h_proto = htons(ETH_P_PRP); } -static int slave_xmit(struct sk_buff *skb, struct hsr_priv *hsr_priv, +static int slave_xmit(struct sk_buff *skb, struct hsr_priv *hsr, enum hsr_dev_idx dev_idx) { struct hsr_ethhdr *hsr_ethhdr; hsr_ethhdr = (struct hsr_ethhdr *) skb->data; - skb->dev = hsr_priv->slave[dev_idx]; + skb->dev = hsr->slave[dev_idx]; - hsr_addr_subst_dest(hsr_priv, &hsr_ethhdr->ethhdr, dev_idx); + hsr_addr_subst_dest(hsr, &hsr_ethhdr->ethhdr, dev_idx); /* Address substitution (IEC62439-3 pp 26, 50): replace mac * address of outgoing frame with that of the outgoing slave's. @@ -217,36 +217,36 @@ static int slave_xmit(struct sk_buff *skb, struct hsr_priv *hsr_priv, static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; struct hsr_ethhdr *hsr_ethhdr; struct sk_buff *skb2; int res1, res2; - hsr_priv = netdev_priv(dev); + hsr = netdev_priv(dev); hsr_ethhdr = (struct hsr_ethhdr *) skb->data; if ((skb->protocol != htons(ETH_P_PRP)) || (hsr_ethhdr->ethhdr.h_proto != htons(ETH_P_PRP))) { - hsr_fill_tag(hsr_ethhdr, hsr_priv); + hsr_fill_tag(hsr_ethhdr, hsr); skb->protocol = htons(ETH_P_PRP); } skb2 = pskb_copy(skb, GFP_ATOMIC); res1 = NET_XMIT_DROP; - if (likely(hsr_priv->slave[HSR_DEV_SLAVE_A])) - res1 = slave_xmit(skb, hsr_priv, HSR_DEV_SLAVE_A); + if (likely(hsr->slave[HSR_DEV_SLAVE_A])) + res1 = slave_xmit(skb, hsr, HSR_DEV_SLAVE_A); res2 = NET_XMIT_DROP; - if (likely(skb2 && hsr_priv->slave[HSR_DEV_SLAVE_B])) - res2 = slave_xmit(skb2, hsr_priv, HSR_DEV_SLAVE_B); + if (likely(skb2 && hsr->slave[HSR_DEV_SLAVE_B])) + res2 = slave_xmit(skb2, hsr, HSR_DEV_SLAVE_B); if (likely(res1 == NET_XMIT_SUCCESS || res1 == NET_XMIT_CN || res2 == NET_XMIT_SUCCESS || res2 == NET_XMIT_CN)) { - hsr_priv->dev->stats.tx_packets++; - hsr_priv->dev->stats.tx_bytes += skb->len; + hsr->dev->stats.tx_packets++; + hsr->dev->stats.tx_bytes += skb->len; } else { - hsr_priv->dev->stats.tx_dropped++; + hsr->dev->stats.tx_dropped++; } return NETDEV_TX_OK; @@ -262,21 +262,21 @@ static int hsr_header_create(struct sk_buff *skb, struct net_device *dev, /* Make room for the HSR tag now. We will fill it in later (in * hsr_dev_xmit) */ - if (skb_headroom(skb) < HSR_TAGLEN + ETH_HLEN) + if (skb_headroom(skb) < HSR_HLEN + ETH_HLEN) return -ENOBUFS; - skb_push(skb, HSR_TAGLEN); + skb_push(skb, HSR_HLEN); /* To allow VLAN/HSR combos we should probably use - * res = dev_hard_header(skb, dev, type, daddr, saddr, len + HSR_TAGLEN); + * res = dev_hard_header(skb, dev, type, daddr, saddr, len + HSR_HLEN); * here instead. It would require other changes too, though - e.g. * separate headers for each slave etc... */ - res = eth_header(skb, dev, type, daddr, saddr, len + HSR_TAGLEN); + res = eth_header(skb, dev, type, daddr, saddr, len + HSR_HLEN); if (res <= 0) return res; skb_reset_mac_header(skb); - return res + HSR_TAGLEN; + return res + HSR_HLEN; } @@ -291,7 +291,7 @@ static const struct header_ops hsr_header_ops = { */ static int hsr_pad(int size) { - const int min_size = ETH_ZLEN - HSR_TAGLEN - ETH_HLEN; + const int min_size = ETH_ZLEN - HSR_HLEN - ETH_HLEN; if (size >= min_size) return size; @@ -300,7 +300,7 @@ static int hsr_pad(int size) static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; struct sk_buff *skb; int hlen, tlen; struct hsr_sup_tag *hsr_stag; @@ -315,7 +315,7 @@ static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type) if (skb == NULL) return; - hsr_priv = netdev_priv(hsr_dev); + hsr = netdev_priv(hsr_dev); skb_reserve(skb, hlen); @@ -324,7 +324,7 @@ static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type) skb->priority = TC_PRIO_CONTROL; if (dev_hard_header(skb, skb->dev, ETH_P_PRP, - hsr_priv->sup_multicast_addr, + hsr->sup_multicast_addr, skb->dev->dev_addr, skb->len) < 0) goto out; @@ -334,10 +334,10 @@ static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type) set_hsr_stag_path(hsr_stag, 0xf); set_hsr_stag_HSR_Ver(hsr_stag, 0); - spin_lock_irqsave(&hsr_priv->seqnr_lock, irqflags); - hsr_stag->sequence_nr = htons(hsr_priv->sequence_nr); - hsr_priv->sequence_nr++; - spin_unlock_irqrestore(&hsr_priv->seqnr_lock, irqflags); + spin_lock_irqsave(&hsr->seqnr_lock, irqflags); + hsr_stag->sequence_nr = htons(hsr->sequence_nr); + hsr->sequence_nr++; + spin_unlock_irqrestore(&hsr->seqnr_lock, irqflags); hsr_stag->HSR_TLV_Type = type; hsr_stag->HSR_TLV_Length = 12; @@ -360,48 +360,48 @@ out: */ static void hsr_announce(unsigned long data) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; - hsr_priv = (struct hsr_priv *) data; + hsr = (struct hsr_priv *) data; - if (hsr_priv->announce_count < 3) { - send_hsr_supervision_frame(hsr_priv->dev, HSR_TLV_ANNOUNCE); - hsr_priv->announce_count++; + if (hsr->announce_count < 3) { + send_hsr_supervision_frame(hsr->dev, HSR_TLV_ANNOUNCE); + hsr->announce_count++; } else { - send_hsr_supervision_frame(hsr_priv->dev, HSR_TLV_LIFE_CHECK); + send_hsr_supervision_frame(hsr->dev, HSR_TLV_LIFE_CHECK); } - if (hsr_priv->announce_count < 3) - hsr_priv->announce_timer.expires = jiffies + + if (hsr->announce_count < 3) + hsr->announce_timer.expires = jiffies + msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL); else - hsr_priv->announce_timer.expires = jiffies + + hsr->announce_timer.expires = jiffies + msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL); - if (is_admin_up(hsr_priv->dev)) - add_timer(&hsr_priv->announce_timer); + if (is_admin_up(hsr->dev)) + add_timer(&hsr->announce_timer); } static void restore_slaves(struct net_device *hsr_dev) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; int i; int res; - hsr_priv = netdev_priv(hsr_dev); + hsr = netdev_priv(hsr_dev); rtnl_lock(); /* Restore promiscuity */ for (i = 0; i < HSR_MAX_SLAVE; i++) { - if (!hsr_priv->slave[i]) + if (!hsr->slave[i]) continue; - res = dev_set_promiscuity(hsr_priv->slave[i], -1); + res = dev_set_promiscuity(hsr->slave[i], -1); if (res) netdev_info(hsr_dev, "Cannot restore slave promiscuity (%s, %d)\n", - hsr_priv->slave[i]->name, res); + hsr->slave[i]->name, res); } rtnl_unlock(); @@ -409,10 +409,10 @@ static void restore_slaves(struct net_device *hsr_dev) static void reclaim_hsr_dev(struct rcu_head *rh) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; - hsr_priv = container_of(rh, struct hsr_priv, rcu_head); - free_netdev(hsr_priv->dev); + hsr = container_of(rh, struct hsr_priv, rcu_head); + free_netdev(hsr->dev); } @@ -421,14 +421,14 @@ static void reclaim_hsr_dev(struct rcu_head *rh) */ static void hsr_dev_destroy(struct net_device *hsr_dev) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; - hsr_priv = netdev_priv(hsr_dev); + hsr = netdev_priv(hsr_dev); - del_timer(&hsr_priv->announce_timer); - unregister_hsr_master(hsr_priv); /* calls list_del_rcu on hsr_priv */ + del_timer(&hsr->announce_timer); + unregister_hsr_master(hsr); /* calls list_del_rcu on hsr */ restore_slaves(hsr_dev); - call_rcu(&hsr_priv->rcu_head, reclaim_hsr_dev); /* reclaim hsr_priv */ + call_rcu(&hsr->rcu_head, reclaim_hsr_dev); /* reclaim hsr */ } static const struct net_device_ops hsr_device_ops = { @@ -500,27 +500,27 @@ static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = { int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], unsigned char multicast_spec) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; int i; int res; - hsr_priv = netdev_priv(hsr_dev); - hsr_priv->dev = hsr_dev; - INIT_LIST_HEAD(&hsr_priv->node_db); - INIT_LIST_HEAD(&hsr_priv->self_node_db); + hsr = netdev_priv(hsr_dev); + hsr->dev = hsr_dev; + INIT_LIST_HEAD(&hsr->node_db); + INIT_LIST_HEAD(&hsr->self_node_db); for (i = 0; i < HSR_MAX_SLAVE; i++) - hsr_priv->slave[i] = slave[i]; + hsr->slave[i] = slave[i]; - spin_lock_init(&hsr_priv->seqnr_lock); + spin_lock_init(&hsr->seqnr_lock); /* Overflow soon to find bugs easier: */ - hsr_priv->sequence_nr = USHRT_MAX - 1024; + hsr->sequence_nr = USHRT_MAX - 1024; - init_timer(&hsr_priv->announce_timer); - hsr_priv->announce_timer.function = hsr_announce; - hsr_priv->announce_timer.data = (unsigned long) hsr_priv; + init_timer(&hsr->announce_timer); + hsr->announce_timer.function = hsr_announce; + hsr->announce_timer.data = (unsigned long) hsr; - ether_addr_copy(hsr_priv->sup_multicast_addr, def_multicast_addr); - hsr_priv->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec; + ether_addr_copy(hsr->sup_multicast_addr, def_multicast_addr); + hsr->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec; /* FIXME: should I modify the value of these? * @@ -547,20 +547,20 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], hsr_dev->features |= NETIF_F_VLAN_CHALLENGED; /* Set hsr_dev's MAC address to that of mac_slave1 */ - ether_addr_copy(hsr_dev->dev_addr, hsr_priv->slave[0]->dev_addr); + ether_addr_copy(hsr_dev->dev_addr, hsr->slave[0]->dev_addr); /* Set required header length */ for (i = 0; i < HSR_MAX_SLAVE; i++) { - if (slave[i]->hard_header_len + HSR_TAGLEN > + if (slave[i]->hard_header_len + HSR_HLEN > hsr_dev->hard_header_len) hsr_dev->hard_header_len = - slave[i]->hard_header_len + HSR_TAGLEN; + slave[i]->hard_header_len + HSR_HLEN; } /* MTU */ for (i = 0; i < HSR_MAX_SLAVE; i++) - if (slave[i]->mtu - HSR_TAGLEN < hsr_dev->mtu) - hsr_dev->mtu = slave[i]->mtu - HSR_TAGLEN; + if (slave[i]->mtu - HSR_HLEN < hsr_dev->mtu) + hsr_dev->mtu = slave[i]->mtu - HSR_HLEN; /* Make sure the 1st call to netif_carrier_on() gets through */ netif_carrier_off(hsr_dev); @@ -576,9 +576,8 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], } /* Make sure we recognize frames from ourselves in hsr_rcv() */ - res = hsr_create_self_node(&hsr_priv->self_node_db, - hsr_dev->dev_addr, - hsr_priv->slave[1]->dev_addr); + res = hsr_create_self_node(&hsr->self_node_db, hsr_dev->dev_addr, + hsr->slave[1]->dev_addr); if (res < 0) goto fail; @@ -586,7 +585,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], if (res) goto fail; - register_hsr_master(hsr_priv); + register_hsr_master(hsr); return 0; diff --git a/net/hsr/hsr_device.h b/net/hsr/hsr_device.h index 2c7148e73914..feb744f90f3d 100644 --- a/net/hsr/hsr_device.h +++ b/net/hsr/hsr_device.h @@ -1,4 +1,4 @@ -/* Copyright 2011-2013 Autronica Fire and Security AS +/* Copyright 2011-2014 Autronica Fire and Security AS * * 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 @@ -6,7 +6,7 @@ * any later version. * * Author(s): - * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com + * 2011-2014 Arvid Brodin, arvid.brodin@alten.se */ #ifndef __HSR_DEVICE_H @@ -24,6 +24,6 @@ void hsr_set_carrier(struct net_device *hsr_dev, struct net_device *slave1, struct net_device *slave2); void hsr_check_announce(struct net_device *hsr_dev, int old_operstate); bool is_hsr_master(struct net_device *dev); -int hsr_get_max_mtu(struct hsr_priv *hsr_priv); +int hsr_get_max_mtu(struct hsr_priv *hsr); #endif /* __HSR_DEVICE_H */ diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index 83e58449366a..b419edbd7012 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c @@ -1,4 +1,4 @@ -/* Copyright 2011-2013 Autronica Fire and Security AS +/* Copyright 2011-2014 Autronica Fire and Security AS * * 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 @@ -6,7 +6,7 @@ * any later version. * * Author(s): - * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com + * 2011-2014 Arvid Brodin, arvid.brodin@alten.se * * The HSR spec says never to forward the same frame twice on the same * interface. A frame is identified by its source MAC address and its HSR @@ -23,17 +23,17 @@ #include "hsr_netlink.h" -struct node_entry { - struct list_head mac_list; - unsigned char MacAddressA[ETH_ALEN]; - unsigned char MacAddressB[ETH_ALEN]; - enum hsr_dev_idx AddrB_if; /* The local slave through which AddrB - * frames are received from this node - */ - unsigned long time_in[HSR_MAX_SLAVE]; - bool time_in_stale[HSR_MAX_SLAVE]; - u16 seq_out[HSR_MAX_DEV]; - struct rcu_head rcu_head; +struct hsr_node { + struct list_head mac_list; + unsigned char MacAddressA[ETH_ALEN]; + unsigned char MacAddressB[ETH_ALEN]; + enum hsr_dev_idx AddrB_if;/* The local slave through which AddrB + * frames are received from this node + */ + unsigned long time_in[HSR_MAX_SLAVE]; + bool time_in_stale[HSR_MAX_SLAVE]; + u16 seq_out[HSR_MAX_DEV]; + struct rcu_head rcu_head; }; /* TODO: use hash lists for mac addresses (linux/jhash.h)? */ @@ -42,10 +42,10 @@ struct node_entry { /* Search for mac entry. Caller must hold rcu read lock. */ -static struct node_entry *find_node_by_AddrA(struct list_head *node_db, - const unsigned char addr[ETH_ALEN]) +static struct hsr_node *find_node_by_AddrA(struct list_head *node_db, + const unsigned char addr[ETH_ALEN]) { - struct node_entry *node; + struct hsr_node *node; list_for_each_entry_rcu(node, node_db, mac_list) { if (ether_addr_equal(node->MacAddressA, addr)) @@ -58,10 +58,10 @@ static struct node_entry *find_node_by_AddrA(struct list_head *node_db, /* Search for mac entry. Caller must hold rcu read lock. */ -static struct node_entry *find_node_by_AddrB(struct list_head *node_db, - const unsigned char addr[ETH_ALEN]) +static struct hsr_node *find_node_by_AddrB(struct list_head *node_db, + const unsigned char addr[ETH_ALEN]) { - struct node_entry *node; + struct hsr_node *node; list_for_each_entry_rcu(node, node_db, mac_list) { if (ether_addr_equal(node->MacAddressB, addr)) @@ -74,9 +74,9 @@ static struct node_entry *find_node_by_AddrB(struct list_head *node_db, /* Search for mac entry. Caller must hold rcu read lock. */ -struct node_entry *hsr_find_node(struct list_head *node_db, struct sk_buff *skb) +struct hsr_node *hsr_find_node(struct list_head *node_db, struct sk_buff *skb) { - struct node_entry *node; + struct hsr_node *node; struct ethhdr *ethhdr; if (!skb_mac_header_was_set(skb)) @@ -102,7 +102,7 @@ int hsr_create_self_node(struct list_head *self_node_db, unsigned char addr_a[ETH_ALEN], unsigned char addr_b[ETH_ALEN]) { - struct node_entry *node, *oldnode; + struct hsr_node *node, *oldnode; node = kmalloc(sizeof(*node), GFP_KERNEL); if (!node) @@ -113,7 +113,7 @@ int hsr_create_self_node(struct list_head *self_node_db, rcu_read_lock(); oldnode = list_first_or_null_rcu(self_node_db, - struct node_entry, mac_list); + struct hsr_node, mac_list); if (oldnode) { list_replace_rcu(&oldnode->mac_list, &node->mac_list); rcu_read_unlock(); @@ -154,10 +154,10 @@ int hsr_create_self_node(struct list_head *self_node_db, * We also need to detect if the sender's SlaveA and SlaveB cables have been * swapped. */ -struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv, - struct node_entry *node, - struct sk_buff *skb, - enum hsr_dev_idx dev_idx) +struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, + struct hsr_node *node, + struct sk_buff *skb, + enum hsr_dev_idx dev_idx) { struct hsr_sup_payload *hsr_sp; struct hsr_ethhdr_sp *hsr_ethsup; @@ -194,7 +194,7 @@ struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv, if (node) return node; - node = find_node_by_AddrA(&hsr_priv->node_db, hsr_sp->MacAddressA); + node = find_node_by_AddrA(&hsr->node_db, hsr_sp->MacAddressA); if (node) { /* Node is known, but frame was received from an unknown * address. Node is PICS_SUBS capable; merge its AddrB. @@ -224,7 +224,7 @@ struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv, for (i = 0; i < HSR_MAX_DEV; i++) node->seq_out[i] = ntohs(hsr_ethsup->hsr_sup.sequence_nr) - 1; - list_add_tail_rcu(&node->mac_list, &hsr_priv->node_db); + list_add_tail_rcu(&node->mac_list, &hsr->node_db); return node; } @@ -236,10 +236,10 @@ struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv, * address with that node's "official" address (MacAddressA) so that upper * layers recognize where it came from. */ -void hsr_addr_subst_source(struct hsr_priv *hsr_priv, struct sk_buff *skb) +void hsr_addr_subst_source(struct hsr_priv *hsr, struct sk_buff *skb) { struct ethhdr *ethhdr; - struct node_entry *node; + struct hsr_node *node; if (!skb_mac_header_was_set(skb)) { WARN_ONCE(1, "%s: Mac header not set\n", __func__); @@ -248,7 +248,7 @@ void hsr_addr_subst_source(struct hsr_priv *hsr_priv, struct sk_buff *skb) ethhdr = (struct ethhdr *) skb_mac_header(skb); rcu_read_lock(); - node = find_node_by_AddrB(&hsr_priv->node_db, ethhdr->h_source); + node = find_node_by_AddrB(&hsr->node_db, ethhdr->h_source); if (node) ether_addr_copy(ethhdr->h_source, node->MacAddressA); rcu_read_unlock(); @@ -264,13 +264,13 @@ void hsr_addr_subst_source(struct hsr_priv *hsr_priv, struct sk_buff *skb) * This is needed to keep the packets flowing through switches that learn on * which "side" the different interfaces are. */ -void hsr_addr_subst_dest(struct hsr_priv *hsr_priv, struct ethhdr *ethhdr, +void hsr_addr_subst_dest(struct hsr_priv *hsr, struct ethhdr *ethhdr, enum hsr_dev_idx dev_idx) { - struct node_entry *node; + struct hsr_node *node; rcu_read_lock(); - node = find_node_by_AddrA(&hsr_priv->node_db, ethhdr->h_dest); + node = find_node_by_AddrA(&hsr->node_db, ethhdr->h_dest); if (node && (node->AddrB_if == dev_idx)) ether_addr_copy(ethhdr->h_dest, node->MacAddressB); rcu_read_unlock(); @@ -295,7 +295,7 @@ static bool seq_nr_after(u16 a, u16 b) #define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b))) -void hsr_register_frame_in(struct node_entry *node, enum hsr_dev_idx dev_idx) +void hsr_register_frame_in(struct hsr_node *node, enum hsr_dev_idx dev_idx) { if ((dev_idx < 0) || (dev_idx >= HSR_MAX_SLAVE)) { WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx); @@ -314,7 +314,7 @@ void hsr_register_frame_in(struct node_entry *node, enum hsr_dev_idx dev_idx) * 0 otherwise, or * negative error code on error */ -int hsr_register_frame_out(struct node_entry *node, enum hsr_dev_idx dev_idx, +int hsr_register_frame_out(struct hsr_node *node, enum hsr_dev_idx dev_idx, struct sk_buff *skb) { struct hsr_ethhdr *hsr_ethhdr; @@ -340,7 +340,7 @@ int hsr_register_frame_out(struct node_entry *node, enum hsr_dev_idx dev_idx, -static bool is_late(struct node_entry *node, enum hsr_dev_idx dev_idx) +static bool is_late(struct hsr_node *node, enum hsr_dev_idx dev_idx) { enum hsr_dev_idx other; @@ -366,14 +366,14 @@ static bool is_late(struct node_entry *node, enum hsr_dev_idx dev_idx) /* Remove stale sequence_nr records. Called by timer every * HSR_LIFE_CHECK_INTERVAL (two seconds or so). */ -void hsr_prune_nodes(struct hsr_priv *hsr_priv) +void hsr_prune_nodes(struct hsr_priv *hsr) { - struct node_entry *node; + struct hsr_node *node; unsigned long timestamp; unsigned long time_a, time_b; rcu_read_lock(); - list_for_each_entry_rcu(node, &hsr_priv->node_db, mac_list) { + list_for_each_entry_rcu(node, &hsr->node_db, mac_list) { /* Shorthand */ time_a = node->time_in[HSR_DEV_SLAVE_A]; time_b = node->time_in[HSR_DEV_SLAVE_B]; @@ -399,17 +399,17 @@ void hsr_prune_nodes(struct hsr_priv *hsr_priv) msecs_to_jiffies(1.5*MAX_SLAVE_DIFF))) { if (is_late(node, HSR_DEV_SLAVE_A)) - hsr_nl_ringerror(hsr_priv, node->MacAddressA, + hsr_nl_ringerror(hsr, node->MacAddressA, HSR_DEV_SLAVE_A); else if (is_late(node, HSR_DEV_SLAVE_B)) - hsr_nl_ringerror(hsr_priv, node->MacAddressA, + hsr_nl_ringerror(hsr, node->MacAddressA, HSR_DEV_SLAVE_B); } /* Prune old entries */ if (time_is_before_jiffies(timestamp + msecs_to_jiffies(HSR_NODE_FORGET_TIME))) { - hsr_nl_nodedown(hsr_priv, node->MacAddressA); + hsr_nl_nodedown(hsr, node->MacAddressA); list_del_rcu(&node->mac_list); /* Note that we need to free this entry later: */ kfree_rcu(node, rcu_head); @@ -419,21 +419,21 @@ void hsr_prune_nodes(struct hsr_priv *hsr_priv) } -void *hsr_get_next_node(struct hsr_priv *hsr_priv, void *_pos, +void *hsr_get_next_node(struct hsr_priv *hsr, void *_pos, unsigned char addr[ETH_ALEN]) { - struct node_entry *node; + struct hsr_node *node; if (!_pos) { - node = list_first_or_null_rcu(&hsr_priv->node_db, - struct node_entry, mac_list); + node = list_first_or_null_rcu(&hsr->node_db, + struct hsr_node, mac_list); if (node) ether_addr_copy(addr, node->MacAddressA); return node; } node = _pos; - list_for_each_entry_continue_rcu(node, &hsr_priv->node_db, mac_list) { + list_for_each_entry_continue_rcu(node, &hsr->node_db, mac_list) { ether_addr_copy(addr, node->MacAddressA); return node; } @@ -442,7 +442,7 @@ void *hsr_get_next_node(struct hsr_priv *hsr_priv, void *_pos, } -int hsr_get_node_data(struct hsr_priv *hsr_priv, +int hsr_get_node_data(struct hsr_priv *hsr, const unsigned char *addr, unsigned char addr_b[ETH_ALEN], unsigned int *addr_b_ifindex, @@ -451,12 +451,12 @@ int hsr_get_node_data(struct hsr_priv *hsr_priv, int *if2_age, u16 *if2_seq) { - struct node_entry *node; + struct hsr_node *node; unsigned long tdiff; rcu_read_lock(); - node = find_node_by_AddrA(&hsr_priv->node_db, addr); + node = find_node_by_AddrA(&hsr->node_db, addr); if (!node) { rcu_read_unlock(); return -ENOENT; /* No such entry */ @@ -488,8 +488,8 @@ int hsr_get_node_data(struct hsr_priv *hsr_priv, *if1_seq = node->seq_out[HSR_DEV_SLAVE_B]; *if2_seq = node->seq_out[HSR_DEV_SLAVE_A]; - if ((node->AddrB_if != HSR_DEV_NONE) && hsr_priv->slave[node->AddrB_if]) - *addr_b_ifindex = hsr_priv->slave[node->AddrB_if]->ifindex; + if ((node->AddrB_if != HSR_DEV_NONE) && hsr->slave[node->AddrB_if]) + *addr_b_ifindex = hsr->slave[node->AddrB_if]->ifindex; else *addr_b_ifindex = -1; diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h index e6c4022030ad..3675139df379 100644 --- a/net/hsr/hsr_framereg.h +++ b/net/hsr/hsr_framereg.h @@ -1,4 +1,4 @@ -/* Copyright 2011-2013 Autronica Fire and Security AS +/* Copyright 2011-2014 Autronica Fire and Security AS * * 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 @@ -6,42 +6,42 @@ * any later version. * * Author(s): - * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com + * 2011-2014 Arvid Brodin, arvid.brodin@alten.se */ -#ifndef _HSR_FRAMEREG_H -#define _HSR_FRAMEREG_H +#ifndef __HSR_FRAMEREG_H +#define __HSR_FRAMEREG_H #include "hsr_main.h" -struct node_entry; +struct hsr_node; -struct node_entry *hsr_find_node(struct list_head *node_db, struct sk_buff *skb); +struct hsr_node *hsr_find_node(struct list_head *node_db, struct sk_buff *skb); -struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv, - struct node_entry *node, - struct sk_buff *skb, - enum hsr_dev_idx dev_idx); +struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, + struct hsr_node *node, + struct sk_buff *skb, + enum hsr_dev_idx dev_idx); -void hsr_addr_subst_source(struct hsr_priv *hsr_priv, struct sk_buff *skb); -void hsr_addr_subst_dest(struct hsr_priv *hsr_priv, struct ethhdr *ethhdr, +void hsr_addr_subst_source(struct hsr_priv *hsr, struct sk_buff *skb); +void hsr_addr_subst_dest(struct hsr_priv *hsr, struct ethhdr *ethhdr, enum hsr_dev_idx dev_idx); -void hsr_register_frame_in(struct node_entry *node, enum hsr_dev_idx dev_idx); +void hsr_register_frame_in(struct hsr_node *node, enum hsr_dev_idx dev_idx); -int hsr_register_frame_out(struct node_entry *node, enum hsr_dev_idx dev_idx, +int hsr_register_frame_out(struct hsr_node *node, enum hsr_dev_idx dev_idx, struct sk_buff *skb); -void hsr_prune_nodes(struct hsr_priv *hsr_priv); +void hsr_prune_nodes(struct hsr_priv *hsr); int hsr_create_self_node(struct list_head *self_node_db, unsigned char addr_a[ETH_ALEN], unsigned char addr_b[ETH_ALEN]); -void *hsr_get_next_node(struct hsr_priv *hsr_priv, void *_pos, +void *hsr_get_next_node(struct hsr_priv *hsr, void *_pos, unsigned char addr[ETH_ALEN]); -int hsr_get_node_data(struct hsr_priv *hsr_priv, +int hsr_get_node_data(struct hsr_priv *hsr, const unsigned char *addr, unsigned char addr_b[ETH_ALEN], unsigned int *addr_b_ifindex, @@ -50,4 +50,4 @@ int hsr_get_node_data(struct hsr_priv *hsr_priv, int *if2_age, u16 *if2_seq); -#endif /* _HSR_FRAMEREG_H */ +#endif /* __HSR_FRAMEREG_H */ diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c index 3fee5218a691..99b8fc4eca6c 100644 --- a/net/hsr/hsr_main.c +++ b/net/hsr/hsr_main.c @@ -1,4 +1,4 @@ -/* Copyright 2011-2013 Autronica Fire and Security AS +/* Copyright 2011-2014 Autronica Fire and Security AS * * 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 @@ -6,7 +6,7 @@ * any later version. * * Author(s): - * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com + * 2011-2014 Arvid Brodin, arvid.brodin@alten.se * * In addition to routines for registering and unregistering HSR support, this * file also contains the receive routine that handles all incoming frames with @@ -26,30 +26,30 @@ /* List of all registered virtual HSR devices */ static LIST_HEAD(hsr_list); -void register_hsr_master(struct hsr_priv *hsr_priv) +void register_hsr_master(struct hsr_priv *hsr) { - list_add_tail_rcu(&hsr_priv->hsr_list, &hsr_list); + list_add_tail_rcu(&hsr->hsr_list, &hsr_list); } -void unregister_hsr_master(struct hsr_priv *hsr_priv) +void unregister_hsr_master(struct hsr_priv *hsr) { - struct hsr_priv *hsr_priv_it; + struct hsr_priv *hsr_it; - list_for_each_entry(hsr_priv_it, &hsr_list, hsr_list) - if (hsr_priv_it == hsr_priv) { - list_del_rcu(&hsr_priv_it->hsr_list); + list_for_each_entry(hsr_it, &hsr_list, hsr_list) + if (hsr_it == hsr) { + list_del_rcu(&hsr_it->hsr_list); return; } } bool is_hsr_slave(struct net_device *dev) { - struct hsr_priv *hsr_priv_it; + struct hsr_priv *hsr_it; - list_for_each_entry_rcu(hsr_priv_it, &hsr_list, hsr_list) { - if (dev == hsr_priv_it->slave[0]) + list_for_each_entry_rcu(hsr_it, &hsr_list, hsr_list) { + if (dev == hsr_it->slave[0]) return true; - if (dev == hsr_priv_it->slave[1]) + if (dev == hsr_it->slave[1]) return true; } @@ -62,14 +62,14 @@ bool is_hsr_slave(struct net_device *dev) */ static struct hsr_priv *get_hsr_master(struct net_device *dev) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; rcu_read_lock(); - list_for_each_entry_rcu(hsr_priv, &hsr_list, hsr_list) - if ((dev == hsr_priv->slave[0]) || - (dev == hsr_priv->slave[1])) { + list_for_each_entry_rcu(hsr, &hsr_list, hsr_list) + if ((dev == hsr->slave[0]) || + (dev == hsr->slave[1])) { rcu_read_unlock(); - return hsr_priv; + return hsr; } rcu_read_unlock(); @@ -80,13 +80,13 @@ static struct hsr_priv *get_hsr_master(struct net_device *dev) /* If dev is a HSR slave device, return the other slave device. Return NULL * otherwise. */ -static struct net_device *get_other_slave(struct hsr_priv *hsr_priv, +static struct net_device *get_other_slave(struct hsr_priv *hsr, struct net_device *dev) { - if (dev == hsr_priv->slave[0]) - return hsr_priv->slave[1]; - if (dev == hsr_priv->slave[1]) - return hsr_priv->slave[0]; + if (dev == hsr->slave[0]) + return hsr->slave[1]; + if (dev == hsr->slave[1]) + return hsr->slave[0]; return NULL; } @@ -96,7 +96,7 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, void *ptr) { struct net_device *slave, *other_slave; - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; int old_operstate; int mtu_max; int res; @@ -104,68 +104,68 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, dev = netdev_notifier_info_to_dev(ptr); - hsr_priv = get_hsr_master(dev); - if (hsr_priv) { + hsr = get_hsr_master(dev); + if (hsr) { /* dev is a slave device */ slave = dev; - other_slave = get_other_slave(hsr_priv, slave); + other_slave = get_other_slave(hsr, slave); } else { if (!is_hsr_master(dev)) return NOTIFY_DONE; - hsr_priv = netdev_priv(dev); - slave = hsr_priv->slave[0]; - other_slave = hsr_priv->slave[1]; + hsr = netdev_priv(dev); + slave = hsr->slave[0]; + other_slave = hsr->slave[1]; } switch (event) { case NETDEV_UP: /* Administrative state DOWN */ case NETDEV_DOWN: /* Administrative state UP */ case NETDEV_CHANGE: /* Link (carrier) state changes */ - old_operstate = hsr_priv->dev->operstate; - hsr_set_carrier(hsr_priv->dev, slave, other_slave); + old_operstate = hsr->dev->operstate; + hsr_set_carrier(hsr->dev, slave, other_slave); /* netif_stacked_transfer_operstate() cannot be used here since * it doesn't set IF_OPER_LOWERLAYERDOWN (?) */ - hsr_set_operstate(hsr_priv->dev, slave, other_slave); - hsr_check_announce(hsr_priv->dev, old_operstate); + hsr_set_operstate(hsr->dev, slave, other_slave); + hsr_check_announce(hsr->dev, old_operstate); break; case NETDEV_CHANGEADDR: /* This should not happen since there's no ndo_set_mac_address() * for HSR devices - i.e. not supported. */ - if (dev == hsr_priv->dev) + if (dev == hsr->dev) break; - if (dev == hsr_priv->slave[0]) - ether_addr_copy(hsr_priv->dev->dev_addr, - hsr_priv->slave[0]->dev_addr); + if (dev == hsr->slave[0]) + ether_addr_copy(hsr->dev->dev_addr, + hsr->slave[0]->dev_addr); /* Make sure we recognize frames from ourselves in hsr_rcv() */ - res = hsr_create_self_node(&hsr_priv->self_node_db, - hsr_priv->dev->dev_addr, - hsr_priv->slave[1] ? - hsr_priv->slave[1]->dev_addr : - hsr_priv->dev->dev_addr); + res = hsr_create_self_node(&hsr->self_node_db, + hsr->dev->dev_addr, + hsr->slave[1] ? + hsr->slave[1]->dev_addr : + hsr->dev->dev_addr); if (res) - netdev_warn(hsr_priv->dev, + netdev_warn(hsr->dev, "Could not update HSR node address.\n"); - if (dev == hsr_priv->slave[0]) - call_netdevice_notifiers(NETDEV_CHANGEADDR, hsr_priv->dev); + if (dev == hsr->slave[0]) + call_netdevice_notifiers(NETDEV_CHANGEADDR, hsr->dev); break; case NETDEV_CHANGEMTU: - if (dev == hsr_priv->dev) + if (dev == hsr->dev) break; /* Handled in ndo_change_mtu() */ - mtu_max = hsr_get_max_mtu(hsr_priv); - if (hsr_priv->dev->mtu > mtu_max) - dev_set_mtu(hsr_priv->dev, mtu_max); + mtu_max = hsr_get_max_mtu(hsr); + if (hsr->dev->mtu > mtu_max) + dev_set_mtu(hsr->dev, mtu_max); break; case NETDEV_UNREGISTER: - if (dev == hsr_priv->slave[0]) - hsr_priv->slave[0] = NULL; - if (dev == hsr_priv->slave[1]) - hsr_priv->slave[1] = NULL; + if (dev == hsr->slave[0]) + hsr->slave[0] = NULL; + if (dev == hsr->slave[1]) + hsr->slave[1] = NULL; /* There should really be a way to set a new slave device... */ @@ -185,11 +185,11 @@ static struct timer_list prune_timer; static void prune_nodes_all(unsigned long data) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; rcu_read_lock(); - list_for_each_entry_rcu(hsr_priv, &hsr_list, hsr_list) - hsr_prune_nodes(hsr_priv); + list_for_each_entry_rcu(hsr, &hsr_list, hsr_list) + hsr_prune_nodes(hsr); rcu_read_unlock(); prune_timer.expires = jiffies + msecs_to_jiffies(PRUNE_PERIOD); @@ -207,12 +207,12 @@ static struct sk_buff *hsr_pull_tag(struct sk_buff *skb) goto err_free; skb = skb2; - if (unlikely(!pskb_may_pull(skb, HSR_TAGLEN))) + if (unlikely(!pskb_may_pull(skb, HSR_HLEN))) goto err_free; hsr_tag = (struct hsr_tag *) skb->data; skb->protocol = hsr_tag->encap_proto; - skb_pull(skb, HSR_TAGLEN); + skb_pull(skb, HSR_HLEN); return skb; @@ -237,12 +237,12 @@ err_free: * 3) Allow different MAC addresses for the two slave interfaces, using the * MacAddressA field. */ -static bool is_supervision_frame(struct hsr_priv *hsr_priv, struct sk_buff *skb) +static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) { struct hsr_sup_tag *hsr_stag; if (!ether_addr_equal(eth_hdr(skb)->h_dest, - hsr_priv->sup_multicast_addr)) + hsr->sup_multicast_addr)) return false; hsr_stag = (struct hsr_sup_tag *) skb->data; @@ -263,25 +263,25 @@ static bool is_supervision_frame(struct hsr_priv *hsr_priv, struct sk_buff *skb) static int hsr_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; struct net_device *other_slave; - struct node_entry *node; + struct hsr_node *node; bool deliver_to_self; struct sk_buff *skb_deliver; enum hsr_dev_idx dev_in_idx, dev_other_idx; bool dup_out; int ret; - hsr_priv = get_hsr_master(dev); + hsr = get_hsr_master(dev); - if (!hsr_priv) { + if (!hsr) { /* Non-HSR-slave device 'dev' is connected to a HSR network */ kfree_skb(skb); dev->stats.rx_errors++; return NET_RX_SUCCESS; } - if (dev == hsr_priv->slave[0]) { + if (dev == hsr->slave[0]) { dev_in_idx = HSR_DEV_SLAVE_A; dev_other_idx = HSR_DEV_SLAVE_B; } else { @@ -289,7 +289,7 @@ static int hsr_rcv(struct sk_buff *skb, struct net_device *dev, dev_other_idx = HSR_DEV_SLAVE_A; } - node = hsr_find_node(&hsr_priv->self_node_db, skb); + node = hsr_find_node(&hsr->self_node_db, skb); if (node) { /* Always kill frames sent by ourselves */ kfree_skb(skb); @@ -303,22 +303,22 @@ static int hsr_rcv(struct sk_buff *skb, struct net_device *dev, (skb->pkt_type == PACKET_BROADCAST)) deliver_to_self = true; else if (ether_addr_equal(eth_hdr(skb)->h_dest, - hsr_priv->dev->dev_addr)) { + hsr->dev->dev_addr)) { skb->pkt_type = PACKET_HOST; deliver_to_self = true; } rcu_read_lock(); /* node_db */ - node = hsr_find_node(&hsr_priv->node_db, skb); + node = hsr_find_node(&hsr->node_db, skb); - if (is_supervision_frame(hsr_priv, skb)) { + if (is_supervision_frame(hsr, skb)) { skb_pull(skb, sizeof(struct hsr_sup_tag)); - node = hsr_merge_node(hsr_priv, node, skb, dev_in_idx); + node = hsr_merge_node(hsr, node, skb, dev_in_idx); if (!node) { rcu_read_unlock(); /* node_db */ kfree_skb(skb); - hsr_priv->dev->stats.rx_dropped++; + hsr->dev->stats.rx_dropped++; return NET_RX_DROP; } skb_push(skb, sizeof(struct hsr_sup_tag)); @@ -345,7 +345,7 @@ static int hsr_rcv(struct sk_buff *skb, struct net_device *dev, /* Forward this frame? */ if (!dup_out && (skb->pkt_type != PACKET_HOST)) - other_slave = get_other_slave(hsr_priv, dev); + other_slave = get_other_slave(hsr, dev); else other_slave = NULL; @@ -368,7 +368,7 @@ static int hsr_rcv(struct sk_buff *skb, struct net_device *dev, skb_deliver = pskb_copy(skb, GFP_ATOMIC); if (!skb_deliver) { deliver_to_self = false; - hsr_priv->dev->stats.rx_dropped++; + hsr->dev->stats.rx_dropped++; } } @@ -377,7 +377,7 @@ static int hsr_rcv(struct sk_buff *skb, struct net_device *dev, skb_deliver = hsr_pull_tag(skb_deliver); if (!skb_deliver) { - hsr_priv->dev->stats.rx_dropped++; + hsr->dev->stats.rx_dropped++; goto forward; } #if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) @@ -386,7 +386,7 @@ static int hsr_rcv(struct sk_buff *skb, struct net_device *dev, * tag. In practice, this removes/overwrites the HSR tag in * the header and restores a "standard" packet. */ - memmove(skb_deliver->data - HSR_TAGLEN, skb_deliver->data, + memmove(skb_deliver->data - HSR_HLEN, skb_deliver->data, skb_headlen(skb_deliver)); /* Adjust skb members so they correspond with the move above. @@ -397,20 +397,20 @@ static int hsr_rcv(struct sk_buff *skb, struct net_device *dev, * the mac header nor the head. So we only need to adjust data * and tail: */ - skb_deliver->data -= HSR_TAGLEN; - skb_deliver->tail -= HSR_TAGLEN; + skb_deliver->data -= HSR_HLEN; + skb_deliver->tail -= HSR_HLEN; #endif - skb_deliver->dev = hsr_priv->dev; - hsr_addr_subst_source(hsr_priv, skb_deliver); + skb_deliver->dev = hsr->dev; + hsr_addr_subst_source(hsr, skb_deliver); multicast_frame = (skb_deliver->pkt_type == PACKET_MULTICAST); ret = netif_rx(skb_deliver); if (ret == NET_RX_DROP) { - hsr_priv->dev->stats.rx_dropped++; + hsr->dev->stats.rx_dropped++; } else { - hsr_priv->dev->stats.rx_packets++; - hsr_priv->dev->stats.rx_bytes += skb->len; + hsr->dev->stats.rx_packets++; + hsr->dev->stats.rx_bytes += skb->len; if (multicast_frame) - hsr_priv->dev->stats.multicast++; + hsr->dev->stats.multicast++; } } @@ -439,7 +439,7 @@ static int __init hsr_init(void) { int res; - BUILD_BUG_ON(sizeof(struct hsr_tag) != HSR_TAGLEN); + BUILD_BUG_ON(sizeof(struct hsr_tag) != HSR_HLEN); dev_add_pack(&hsr_pt); diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h index 56fe060c0ab1..360a49af0c1b 100644 --- a/net/hsr/hsr_main.h +++ b/net/hsr/hsr_main.h @@ -1,4 +1,4 @@ -/* Copyright 2011-2013 Autronica Fire and Security AS +/* Copyright 2011-2014 Autronica Fire and Security AS * * 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 @@ -6,11 +6,11 @@ * any later version. * * Author(s): - * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com + * 2011-2014 Arvid Brodin, arvid.brodin@alten.se */ -#ifndef _HSR_PRIVATE_H -#define _HSR_PRIVATE_H +#ifndef __HSR_PRIVATE_H +#define __HSR_PRIVATE_H #include #include @@ -46,16 +46,16 @@ * path, LSDU_size, sequence Nr }. But we let eth_header() create { h_dest, * h_source, h_proto = 0x88FB }, and add { path, LSDU_size, sequence Nr, * encapsulated protocol } instead. + * + * Field names as defined in the IEC:2010 standard for HSR. */ -#define HSR_TAGLEN 6 - -/* Field names below as defined in the IEC:2010 standard for HSR. */ struct hsr_tag { __be16 path_and_LSDU_size; __be16 sequence_nr; __be16 encap_proto; } __packed; +#define HSR_HLEN 6 /* The helper functions below assumes that 'path' occupies the 4 most * significant bits of the 16-bit field shared by 'path' and 'LSDU_size' (or @@ -159,8 +159,8 @@ struct hsr_priv { unsigned char sup_multicast_addr[ETH_ALEN]; }; -void register_hsr_master(struct hsr_priv *hsr_priv); -void unregister_hsr_master(struct hsr_priv *hsr_priv); +void register_hsr_master(struct hsr_priv *hsr); +void unregister_hsr_master(struct hsr_priv *hsr); bool is_hsr_slave(struct net_device *dev); -#endif /* _HSR_PRIVATE_H */ +#endif /* __HSR_PRIVATE_H */ diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index 01a5261ac7a5..bea250ec3586 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c @@ -1,4 +1,4 @@ -/* Copyright 2011-2013 Autronica Fire and Security AS +/* Copyright 2011-2014 Autronica Fire and Security AS * * 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 @@ -6,7 +6,7 @@ * any later version. * * Author(s): - * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com + * 2011-2014 Arvid Brodin, arvid.brodin@alten.se * * Routines for handling Netlink messages for HSR. */ @@ -63,21 +63,21 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev, static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) { - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; - hsr_priv = netdev_priv(dev); + hsr = netdev_priv(dev); - if (hsr_priv->slave[0]) - if (nla_put_u32(skb, IFLA_HSR_SLAVE1, hsr_priv->slave[0]->ifindex)) + if (hsr->slave[0]) + if (nla_put_u32(skb, IFLA_HSR_SLAVE1, hsr->slave[0]->ifindex)) goto nla_put_failure; - if (hsr_priv->slave[1]) - if (nla_put_u32(skb, IFLA_HSR_SLAVE2, hsr_priv->slave[1]->ifindex)) + if (hsr->slave[1]) + if (nla_put_u32(skb, IFLA_HSR_SLAVE2, hsr->slave[1]->ifindex)) goto nla_put_failure; if (nla_put(skb, IFLA_HSR_SUPERVISION_ADDR, ETH_ALEN, - hsr_priv->sup_multicast_addr) || - nla_put_u16(skb, IFLA_HSR_SEQ_NR, hsr_priv->sequence_nr)) + hsr->sup_multicast_addr) || + nla_put_u16(skb, IFLA_HSR_SEQ_NR, hsr->sequence_nr)) goto nla_put_failure; return 0; @@ -128,7 +128,7 @@ static const struct genl_multicast_group hsr_mcgrps[] = { * over one of the slave interfaces. This would indicate an open network ring * (i.e. a link has failed somewhere). */ -void hsr_nl_ringerror(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN], +void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN], enum hsr_dev_idx dev_idx) { struct sk_buff *skb; @@ -148,8 +148,8 @@ void hsr_nl_ringerror(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN], if (res < 0) goto nla_put_failure; - if (hsr_priv->slave[dev_idx]) - ifindex = hsr_priv->slave[dev_idx]->ifindex; + if (hsr->slave[dev_idx]) + ifindex = hsr->slave[dev_idx]->ifindex; else ifindex = -1; res = nla_put_u32(skb, HSR_A_IFINDEX, ifindex); @@ -165,13 +165,13 @@ nla_put_failure: kfree_skb(skb); fail: - netdev_warn(hsr_priv->dev, "Could not send HSR ring error message\n"); + netdev_warn(hsr->dev, "Could not send HSR ring error message\n"); } /* This is called when we haven't heard from the node with MAC address addr for * some time (just before the node is removed from the node table/list). */ -void hsr_nl_nodedown(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN]) +void hsr_nl_nodedown(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN]) { struct sk_buff *skb; void *msg_head; @@ -199,7 +199,7 @@ nla_put_failure: kfree_skb(skb); fail: - netdev_warn(hsr_priv->dev, "Could not send HSR node down\n"); + netdev_warn(hsr->dev, "Could not send HSR node down\n"); } @@ -220,7 +220,7 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) /* For sending */ struct sk_buff *skb_out; void *msg_head; - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; unsigned char hsr_node_addr_b[ETH_ALEN]; int hsr_node_if1_age; u16 hsr_node_if1_seq; @@ -267,8 +267,8 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) if (res < 0) goto nla_put_failure; - hsr_priv = netdev_priv(hsr_dev); - res = hsr_get_node_data(hsr_priv, + hsr = netdev_priv(hsr_dev); + res = hsr_get_node_data(hsr, (unsigned char *) nla_data(info->attrs[HSR_A_NODE_ADDR]), hsr_node_addr_b, &addr_b_ifindex, @@ -301,9 +301,9 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) res = nla_put_u16(skb_out, HSR_A_IF1_SEQ, hsr_node_if1_seq); if (res < 0) goto nla_put_failure; - if (hsr_priv->slave[0]) + if (hsr->slave[0]) res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX, - hsr_priv->slave[0]->ifindex); + hsr->slave[0]->ifindex); if (res < 0) goto nla_put_failure; @@ -313,9 +313,9 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) res = nla_put_u16(skb_out, HSR_A_IF2_SEQ, hsr_node_if2_seq); if (res < 0) goto nla_put_failure; - if (hsr_priv->slave[1]) + if (hsr->slave[1]) res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX, - hsr_priv->slave[1]->ifindex); + hsr->slave[1]->ifindex); genlmsg_end(skb_out, msg_head); genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid); @@ -345,7 +345,7 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) /* For sending */ struct sk_buff *skb_out; void *msg_head; - struct hsr_priv *hsr_priv; + struct hsr_priv *hsr; void *pos; unsigned char addr[ETH_ALEN]; int res; @@ -385,17 +385,17 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) if (res < 0) goto nla_put_failure; - hsr_priv = netdev_priv(hsr_dev); + hsr = netdev_priv(hsr_dev); rcu_read_lock(); - pos = hsr_get_next_node(hsr_priv, NULL, addr); + pos = hsr_get_next_node(hsr, NULL, addr); while (pos) { res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, addr); if (res < 0) { rcu_read_unlock(); goto nla_put_failure; } - pos = hsr_get_next_node(hsr_priv, pos, addr); + pos = hsr_get_next_node(hsr, pos, addr); } rcu_read_unlock(); diff --git a/net/hsr/hsr_netlink.h b/net/hsr/hsr_netlink.h index d4579dcc3c7d..3047f9cea5f5 100644 --- a/net/hsr/hsr_netlink.h +++ b/net/hsr/hsr_netlink.h @@ -1,4 +1,4 @@ -/* Copyright 2011-2013 Autronica Fire and Security AS +/* Copyright 2011-2014 Autronica Fire and Security AS * * 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 @@ -6,7 +6,7 @@ * any later version. * * Author(s): - * 2011-2013 Arvid Brodin, arvid.brodin@xdin.com + * 2011-2014 Arvid Brodin, arvid.brodin@alten.se */ #ifndef __HSR_NETLINK_H @@ -21,9 +21,9 @@ struct hsr_priv; int __init hsr_netlink_init(void); void __exit hsr_netlink_exit(void); -void hsr_nl_ringerror(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN], +void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN], int dev_idx); -void hsr_nl_nodedown(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN]); +void hsr_nl_nodedown(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN]); void hsr_nl_framedrop(int dropcount, int dev_idx); void hsr_nl_linkdown(int dev_idx); -- cgit v1.2.3 From 81ba6afd6e6443d2bf4bf40f16df1f1f91c603f8 Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Fri, 4 Jul 2014 23:35:24 +0200 Subject: net/hsr: Switch from dev_add_pack() to netdev_rx_handler_register() Also move the frame receive handler to hsr_slave.c. Signed-off-by: Arvid Brodin Signed-off-by: David S. Miller --- net/hsr/Makefile | 3 +- net/hsr/hsr_device.c | 13 ++- net/hsr/hsr_main.c | 248 +-------------------------------------------------- net/hsr/hsr_main.h | 3 + net/hsr/hsr_slave.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++ net/hsr/hsr_slave.h | 20 +++++ 6 files changed, 283 insertions(+), 247 deletions(-) create mode 100644 net/hsr/hsr_slave.c create mode 100644 net/hsr/hsr_slave.h diff --git a/net/hsr/Makefile b/net/hsr/Makefile index b68359f181cc..b533b243a48b 100644 --- a/net/hsr/Makefile +++ b/net/hsr/Makefile @@ -4,4 +4,5 @@ obj-$(CONFIG_HSR) += hsr.o -hsr-y := hsr_main.o hsr_framereg.o hsr_device.o hsr_netlink.o +hsr-y := hsr_main.o hsr_framereg.o hsr_device.o hsr_netlink.o \ + hsr_slave.o diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 4dc2a4207ee2..4e5d92a8f079 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -19,6 +19,7 @@ #include #include #include "hsr_device.h" +#include "hsr_slave.h" #include "hsr_framereg.h" #include "hsr_main.h" @@ -393,7 +394,6 @@ static void restore_slaves(struct net_device *hsr_dev) rtnl_lock(); - /* Restore promiscuity */ for (i = 0; i < HSR_MAX_SLAVE; i++) { if (!hsr->slave[i]) continue; @@ -402,8 +402,12 @@ static void restore_slaves(struct net_device *hsr_dev) netdev_info(hsr_dev, "Cannot restore slave promiscuity (%s, %d)\n", hsr->slave[i]->name, res); + + if (hsr->slave[i]->rx_handler == hsr_handle_frame) + netdev_rx_handler_unregister(hsr->slave[i]); } + rtnl_unlock(); } @@ -575,6 +579,13 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], } } + for (i = 0; i < HSR_MAX_SLAVE; i++) { + res = netdev_rx_handler_register(slave[i], hsr_handle_frame, + hsr); + if (res) + goto fail; + } + /* Make sure we recognize frames from ourselves in hsr_rcv() */ res = hsr_create_self_node(&hsr->self_node_db, hsr_dev->dev_addr, hsr->slave[1]->dev_addr); diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c index 99b8fc4eca6c..bcda901437bc 100644 --- a/net/hsr/hsr_main.c +++ b/net/hsr/hsr_main.c @@ -7,10 +7,6 @@ * * Author(s): * 2011-2014 Arvid Brodin, arvid.brodin@alten.se - * - * In addition to routines for registering and unregistering HSR support, this - * file also contains the receive routine that handles all incoming frames with - * Ethertype (protocol) ETH_P_PRP (HSRv0), and network device event handling. */ #include @@ -56,11 +52,10 @@ bool is_hsr_slave(struct net_device *dev) return false; } - /* If dev is a HSR slave device, return the virtual master device. Return NULL * otherwise. */ -static struct hsr_priv *get_hsr_master(struct net_device *dev) +struct hsr_priv *get_hsr_master(struct net_device *dev) { struct hsr_priv *hsr; @@ -76,12 +71,11 @@ static struct hsr_priv *get_hsr_master(struct net_device *dev) return NULL; } - /* If dev is a HSR slave device, return the other slave device. Return NULL * otherwise. */ -static struct net_device *get_other_slave(struct hsr_priv *hsr, - struct net_device *dev) +struct net_device *get_other_slave(struct hsr_priv *hsr, + struct net_device *dev) { if (dev == hsr->slave[0]) return hsr->slave[1]; @@ -197,239 +191,6 @@ static void prune_nodes_all(unsigned long data) } -static struct sk_buff *hsr_pull_tag(struct sk_buff *skb) -{ - struct hsr_tag *hsr_tag; - struct sk_buff *skb2; - - skb2 = skb_share_check(skb, GFP_ATOMIC); - if (unlikely(!skb2)) - goto err_free; - skb = skb2; - - if (unlikely(!pskb_may_pull(skb, HSR_HLEN))) - goto err_free; - - hsr_tag = (struct hsr_tag *) skb->data; - skb->protocol = hsr_tag->encap_proto; - skb_pull(skb, HSR_HLEN); - - return skb; - -err_free: - kfree_skb(skb); - return NULL; -} - - -/* The uses I can see for these HSR supervision frames are: - * 1) Use the frames that are sent after node initialization ("HSR_TLV.Type = - * 22") to reset any sequence_nr counters belonging to that node. Useful if - * the other node's counter has been reset for some reason. - * -- - * Or not - resetting the counter and bridging the frame would create a - * loop, unfortunately. - * - * 2) Use the LifeCheck frames to detect ring breaks. I.e. if no LifeCheck - * frame is received from a particular node, we know something is wrong. - * We just register these (as with normal frames) and throw them away. - * - * 3) Allow different MAC addresses for the two slave interfaces, using the - * MacAddressA field. - */ -static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) -{ - struct hsr_sup_tag *hsr_stag; - - if (!ether_addr_equal(eth_hdr(skb)->h_dest, - hsr->sup_multicast_addr)) - return false; - - hsr_stag = (struct hsr_sup_tag *) skb->data; - if (get_hsr_stag_path(hsr_stag) != 0x0f) - return false; - if ((hsr_stag->HSR_TLV_Type != HSR_TLV_ANNOUNCE) && - (hsr_stag->HSR_TLV_Type != HSR_TLV_LIFE_CHECK)) - return false; - if (hsr_stag->HSR_TLV_Length != 12) - return false; - - return true; -} - - -/* Implementation somewhat according to IEC-62439-3, p. 43 - */ -static int hsr_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev) -{ - struct hsr_priv *hsr; - struct net_device *other_slave; - struct hsr_node *node; - bool deliver_to_self; - struct sk_buff *skb_deliver; - enum hsr_dev_idx dev_in_idx, dev_other_idx; - bool dup_out; - int ret; - - hsr = get_hsr_master(dev); - - if (!hsr) { - /* Non-HSR-slave device 'dev' is connected to a HSR network */ - kfree_skb(skb); - dev->stats.rx_errors++; - return NET_RX_SUCCESS; - } - - if (dev == hsr->slave[0]) { - dev_in_idx = HSR_DEV_SLAVE_A; - dev_other_idx = HSR_DEV_SLAVE_B; - } else { - dev_in_idx = HSR_DEV_SLAVE_B; - dev_other_idx = HSR_DEV_SLAVE_A; - } - - node = hsr_find_node(&hsr->self_node_db, skb); - if (node) { - /* Always kill frames sent by ourselves */ - kfree_skb(skb); - return NET_RX_SUCCESS; - } - - /* Is this frame a candidate for local reception? */ - deliver_to_self = false; - if ((skb->pkt_type == PACKET_HOST) || - (skb->pkt_type == PACKET_MULTICAST) || - (skb->pkt_type == PACKET_BROADCAST)) - deliver_to_self = true; - else if (ether_addr_equal(eth_hdr(skb)->h_dest, - hsr->dev->dev_addr)) { - skb->pkt_type = PACKET_HOST; - deliver_to_self = true; - } - - - rcu_read_lock(); /* node_db */ - node = hsr_find_node(&hsr->node_db, skb); - - if (is_supervision_frame(hsr, skb)) { - skb_pull(skb, sizeof(struct hsr_sup_tag)); - node = hsr_merge_node(hsr, node, skb, dev_in_idx); - if (!node) { - rcu_read_unlock(); /* node_db */ - kfree_skb(skb); - hsr->dev->stats.rx_dropped++; - return NET_RX_DROP; - } - skb_push(skb, sizeof(struct hsr_sup_tag)); - deliver_to_self = false; - } - - if (!node) { - /* Source node unknown; this might be a HSR frame from - * another net (different multicast address). Ignore it. - */ - rcu_read_unlock(); /* node_db */ - kfree_skb(skb); - return NET_RX_SUCCESS; - } - - /* Register ALL incoming frames as outgoing through the other interface. - * This allows us to register frames as incoming only if they are valid - * for the receiving interface, without using a specific counter for - * incoming frames. - */ - dup_out = hsr_register_frame_out(node, dev_other_idx, skb); - if (!dup_out) - hsr_register_frame_in(node, dev_in_idx); - - /* Forward this frame? */ - if (!dup_out && (skb->pkt_type != PACKET_HOST)) - other_slave = get_other_slave(hsr, dev); - else - other_slave = NULL; - - if (hsr_register_frame_out(node, HSR_DEV_MASTER, skb)) - deliver_to_self = false; - - rcu_read_unlock(); /* node_db */ - - if (!deliver_to_self && !other_slave) { - kfree_skb(skb); - /* Circulated frame; silently remove it. */ - return NET_RX_SUCCESS; - } - - skb_deliver = skb; - if (deliver_to_self && other_slave) { - /* skb_clone() is not enough since we will strip the hsr tag - * and do address substitution below - */ - skb_deliver = pskb_copy(skb, GFP_ATOMIC); - if (!skb_deliver) { - deliver_to_self = false; - hsr->dev->stats.rx_dropped++; - } - } - - if (deliver_to_self) { - bool multicast_frame; - - skb_deliver = hsr_pull_tag(skb_deliver); - if (!skb_deliver) { - hsr->dev->stats.rx_dropped++; - goto forward; - } -#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - /* Move everything in the header that is after the HSR tag, - * to work around alignment problems caused by the 6-byte HSR - * tag. In practice, this removes/overwrites the HSR tag in - * the header and restores a "standard" packet. - */ - memmove(skb_deliver->data - HSR_HLEN, skb_deliver->data, - skb_headlen(skb_deliver)); - - /* Adjust skb members so they correspond with the move above. - * This cannot possibly underflow skb->data since hsr_pull_tag() - * above succeeded. - * At this point in the protocol stack, the transport and - * network headers have not been set yet, and we haven't touched - * the mac header nor the head. So we only need to adjust data - * and tail: - */ - skb_deliver->data -= HSR_HLEN; - skb_deliver->tail -= HSR_HLEN; -#endif - skb_deliver->dev = hsr->dev; - hsr_addr_subst_source(hsr, skb_deliver); - multicast_frame = (skb_deliver->pkt_type == PACKET_MULTICAST); - ret = netif_rx(skb_deliver); - if (ret == NET_RX_DROP) { - hsr->dev->stats.rx_dropped++; - } else { - hsr->dev->stats.rx_packets++; - hsr->dev->stats.rx_bytes += skb->len; - if (multicast_frame) - hsr->dev->stats.multicast++; - } - } - -forward: - if (other_slave) { - skb_push(skb, ETH_HLEN); - skb->dev = other_slave; - dev_queue_xmit(skb); - } - - return NET_RX_SUCCESS; -} - - -static struct packet_type hsr_pt __read_mostly = { - .type = htons(ETH_P_PRP), - .func = hsr_rcv, -}; - static struct notifier_block hsr_nb = { .notifier_call = hsr_netdev_notify, /* Slave event notifications */ }; @@ -441,8 +202,6 @@ static int __init hsr_init(void) BUILD_BUG_ON(sizeof(struct hsr_tag) != HSR_HLEN); - dev_add_pack(&hsr_pt); - init_timer(&prune_timer); prune_timer.function = prune_nodes_all; prune_timer.data = 0; @@ -461,7 +220,6 @@ static void __exit hsr_exit(void) unregister_netdevice_notifier(&hsr_nb); del_timer_sync(&prune_timer); hsr_netlink_exit(); - dev_remove_pack(&hsr_pt); } module_init(hsr_init); diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h index 360a49af0c1b..d919321b0bdb 100644 --- a/net/hsr/hsr_main.h +++ b/net/hsr/hsr_main.h @@ -162,5 +162,8 @@ struct hsr_priv { void register_hsr_master(struct hsr_priv *hsr); void unregister_hsr_master(struct hsr_priv *hsr); bool is_hsr_slave(struct net_device *dev); +struct hsr_priv *get_hsr_master(struct net_device *dev); +struct net_device *get_other_slave(struct hsr_priv *hsr, + struct net_device *dev); #endif /* __HSR_PRIVATE_H */ diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c new file mode 100644 index 000000000000..702814631ee1 --- /dev/null +++ b/net/hsr/hsr_slave.c @@ -0,0 +1,243 @@ +/* Copyright 2011-2014 Autronica Fire and Security AS + * + * 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. + * + * Author(s): + * 2011-2014 Arvid Brodin, arvid.brodin@alten.se + */ + +#include "hsr_slave.h" +#include +#include "hsr_main.h" +#include "hsr_framereg.h" + + +static struct sk_buff *hsr_pull_tag(struct sk_buff *skb) +{ + struct hsr_tag *hsr_tag; + struct sk_buff *skb2; + + skb2 = skb_share_check(skb, GFP_ATOMIC); + if (unlikely(!skb2)) + goto err_free; + skb = skb2; + + if (unlikely(!pskb_may_pull(skb, HSR_HLEN))) + goto err_free; + + hsr_tag = (struct hsr_tag *) skb->data; + skb->protocol = hsr_tag->encap_proto; + skb_pull(skb, HSR_HLEN); + + return skb; + +err_free: + kfree_skb(skb); + return NULL; +} + + +/* The uses I can see for these HSR supervision frames are: + * 1) Use the frames that are sent after node initialization ("HSR_TLV.Type = + * 22") to reset any sequence_nr counters belonging to that node. Useful if + * the other node's counter has been reset for some reason. + * -- + * Or not - resetting the counter and bridging the frame would create a + * loop, unfortunately. + * + * 2) Use the LifeCheck frames to detect ring breaks. I.e. if no LifeCheck + * frame is received from a particular node, we know something is wrong. + * We just register these (as with normal frames) and throw them away. + * + * 3) Allow different MAC addresses for the two slave interfaces, using the + * MacAddressA field. + */ +static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) +{ + struct hsr_sup_tag *hsr_stag; + + if (!ether_addr_equal(eth_hdr(skb)->h_dest, + hsr->sup_multicast_addr)) + return false; + + hsr_stag = (struct hsr_sup_tag *) skb->data; + if (get_hsr_stag_path(hsr_stag) != 0x0f) + return false; + if ((hsr_stag->HSR_TLV_Type != HSR_TLV_ANNOUNCE) && + (hsr_stag->HSR_TLV_Type != HSR_TLV_LIFE_CHECK)) + return false; + if (hsr_stag->HSR_TLV_Length != 12) + return false; + + return true; +} + + +/* Implementation somewhat according to IEC-62439-3, p. 43 + */ +rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct net_device *dev = skb->dev; + struct hsr_priv *hsr; + struct net_device *other_slave; + struct hsr_node *node; + bool deliver_to_self; + struct sk_buff *skb_deliver; + enum hsr_dev_idx dev_in_idx, dev_other_idx; + bool dup_out; + int ret; + + if (eth_hdr(skb)->h_proto != htons(ETH_P_PRP)) + return RX_HANDLER_PASS; + + hsr = get_hsr_master(dev); + if (!hsr) { + WARN_ON_ONCE(1); + return RX_HANDLER_PASS; + } + + if (dev == hsr->slave[0]) { + dev_in_idx = HSR_DEV_SLAVE_A; + dev_other_idx = HSR_DEV_SLAVE_B; + } else { + dev_in_idx = HSR_DEV_SLAVE_B; + dev_other_idx = HSR_DEV_SLAVE_A; + } + + node = hsr_find_node(&hsr->self_node_db, skb); + if (node) { + /* Always kill frames sent by ourselves */ + kfree_skb(skb); + return RX_HANDLER_CONSUMED; + } + + /* Is this frame a candidate for local reception? */ + deliver_to_self = false; + if ((skb->pkt_type == PACKET_HOST) || + (skb->pkt_type == PACKET_MULTICAST) || + (skb->pkt_type == PACKET_BROADCAST)) + deliver_to_self = true; + else if (ether_addr_equal(eth_hdr(skb)->h_dest, hsr->dev->dev_addr)) { + skb->pkt_type = PACKET_HOST; + deliver_to_self = true; + } + + + rcu_read_lock(); /* node_db */ + node = hsr_find_node(&hsr->node_db, skb); + + if (is_supervision_frame(hsr, skb)) { + skb_pull(skb, sizeof(struct hsr_sup_tag)); + node = hsr_merge_node(hsr, node, skb, dev_in_idx); + if (!node) { + rcu_read_unlock(); /* node_db */ + kfree_skb(skb); + hsr->dev->stats.rx_dropped++; + return RX_HANDLER_CONSUMED; + } + skb_push(skb, sizeof(struct hsr_sup_tag)); + deliver_to_self = false; + } + + if (!node) { + /* Source node unknown; this might be a HSR frame from + * another net (different multicast address). Ignore it. + */ + rcu_read_unlock(); /* node_db */ + kfree_skb(skb); + return RX_HANDLER_CONSUMED; + } + + /* Register ALL incoming frames as outgoing through the other interface. + * This allows us to register frames as incoming only if they are valid + * for the receiving interface, without using a specific counter for + * incoming frames. + */ + dup_out = hsr_register_frame_out(node, dev_other_idx, skb); + if (!dup_out) + hsr_register_frame_in(node, dev_in_idx); + + /* Forward this frame? */ + if (!dup_out && (skb->pkt_type != PACKET_HOST)) + other_slave = get_other_slave(hsr, dev); + else + other_slave = NULL; + + if (hsr_register_frame_out(node, HSR_DEV_MASTER, skb)) + deliver_to_self = false; + + rcu_read_unlock(); /* node_db */ + + if (!deliver_to_self && !other_slave) { + kfree_skb(skb); + /* Circulated frame; silently remove it. */ + return RX_HANDLER_CONSUMED; + } + + skb_deliver = skb; + if (deliver_to_self && other_slave) { + /* skb_clone() is not enough since we will strip the hsr tag + * and do address substitution below + */ + skb_deliver = pskb_copy(skb, GFP_ATOMIC); + if (!skb_deliver) { + deliver_to_self = false; + hsr->dev->stats.rx_dropped++; + } + } + + if (deliver_to_self) { + bool multicast_frame; + + skb_deliver = hsr_pull_tag(skb_deliver); + if (!skb_deliver) { + hsr->dev->stats.rx_dropped++; + goto forward; + } +#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + /* Move everything in the header that is after the HSR tag, + * to work around alignment problems caused by the 6-byte HSR + * tag. In practice, this removes/overwrites the HSR tag in + * the header and restores a "standard" packet. + */ + memmove(skb_deliver->data - HSR_HLEN, skb_deliver->data, + skb_headlen(skb_deliver)); + + /* Adjust skb members so they correspond with the move above. + * This cannot possibly underflow skb->data since hsr_pull_tag() + * above succeeded. + * At this point in the protocol stack, the transport and + * network headers have not been set yet, and we haven't touched + * the mac header nor the head. So we only need to adjust data + * and tail: + */ + skb_deliver->data -= HSR_HLEN; + skb_deliver->tail -= HSR_HLEN; +#endif + skb_deliver->dev = hsr->dev; + hsr_addr_subst_source(hsr, skb_deliver); + multicast_frame = (skb_deliver->pkt_type == PACKET_MULTICAST); + ret = netif_rx(skb_deliver); + if (ret == NET_RX_DROP) { + hsr->dev->stats.rx_dropped++; + } else { + hsr->dev->stats.rx_packets++; + hsr->dev->stats.rx_bytes += skb->len; + if (multicast_frame) + hsr->dev->stats.multicast++; + } + } + +forward: + if (other_slave) { + skb_push(skb, ETH_HLEN); + skb->dev = other_slave; + dev_queue_xmit(skb); + } + + return RX_HANDLER_CONSUMED; +} diff --git a/net/hsr/hsr_slave.h b/net/hsr/hsr_slave.h new file mode 100644 index 000000000000..ae90c8d0fde4 --- /dev/null +++ b/net/hsr/hsr_slave.h @@ -0,0 +1,20 @@ +/* Copyright 2011-2014 Autronica Fire and Security AS + * + * 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. + * + * Author(s): + * 2011-2014 Arvid Brodin, arvid.brodin@alten.se + */ + +#ifndef __HSR_SLAVE_H +#define __HSR_SLAVE_H + +#include +#include + +rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb); + +#endif /* __HSR_SLAVE_H */ -- cgit v1.2.3 From abff7162765cd66ab109c97fd433ef1f39299120 Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Fri, 4 Jul 2014 23:35:47 +0200 Subject: net/hsr: Move to per-hsr device prune timer. Signed-off-by: Arvid Brodin Signed-off-by: David S. Miller --- net/hsr/hsr_device.c | 10 +++++++++- net/hsr/hsr_framereg.c | 5 ++++- net/hsr/hsr_framereg.h | 2 +- net/hsr/hsr_main.c | 24 ------------------------ net/hsr/hsr_main.h | 1 + 5 files changed, 15 insertions(+), 27 deletions(-) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 4e5d92a8f079..f224067153e4 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -429,7 +429,8 @@ static void hsr_dev_destroy(struct net_device *hsr_dev) hsr = netdev_priv(hsr_dev); - del_timer(&hsr->announce_timer); + del_timer_sync(&hsr->prune_timer); + del_timer_sync(&hsr->announce_timer); unregister_hsr_master(hsr); /* calls list_del_rcu on hsr */ restore_slaves(hsr_dev); call_rcu(&hsr->rcu_head, reclaim_hsr_dev); /* reclaim hsr */ @@ -523,6 +524,10 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], hsr->announce_timer.function = hsr_announce; hsr->announce_timer.data = (unsigned long) hsr; + init_timer(&hsr->prune_timer); + hsr->prune_timer.function = hsr_prune_nodes; + hsr->prune_timer.data = (unsigned long) hsr; + ether_addr_copy(hsr->sup_multicast_addr, def_multicast_addr); hsr->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec; @@ -596,6 +601,9 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], if (res) goto fail; + hsr->prune_timer.expires = jiffies + msecs_to_jiffies(PRUNE_PERIOD); + add_timer(&hsr->prune_timer); + register_hsr_master(hsr); return 0; diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index b419edbd7012..79e3f7ff6654 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c @@ -366,12 +366,15 @@ static bool is_late(struct hsr_node *node, enum hsr_dev_idx dev_idx) /* Remove stale sequence_nr records. Called by timer every * HSR_LIFE_CHECK_INTERVAL (two seconds or so). */ -void hsr_prune_nodes(struct hsr_priv *hsr) +void hsr_prune_nodes(unsigned long data) { + struct hsr_priv *hsr; struct hsr_node *node; unsigned long timestamp; unsigned long time_a, time_b; + hsr = (struct hsr_priv *) data; + rcu_read_lock(); list_for_each_entry_rcu(node, &hsr->node_db, mac_list) { /* Shorthand */ diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h index 3675139df379..ccb09cf4ec5b 100644 --- a/net/hsr/hsr_framereg.h +++ b/net/hsr/hsr_framereg.h @@ -32,7 +32,7 @@ void hsr_register_frame_in(struct hsr_node *node, enum hsr_dev_idx dev_idx); int hsr_register_frame_out(struct hsr_node *node, enum hsr_dev_idx dev_idx, struct sk_buff *skb); -void hsr_prune_nodes(struct hsr_priv *hsr); +void hsr_prune_nodes(unsigned long data); int hsr_create_self_node(struct list_head *self_node_db, unsigned char addr_a[ETH_ALEN], diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c index bcda901437bc..5f9cd7fdbd93 100644 --- a/net/hsr/hsr_main.c +++ b/net/hsr/hsr_main.c @@ -175,22 +175,6 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, } -static struct timer_list prune_timer; - -static void prune_nodes_all(unsigned long data) -{ - struct hsr_priv *hsr; - - rcu_read_lock(); - list_for_each_entry_rcu(hsr, &hsr_list, hsr_list) - hsr_prune_nodes(hsr); - rcu_read_unlock(); - - prune_timer.expires = jiffies + msecs_to_jiffies(PRUNE_PERIOD); - add_timer(&prune_timer); -} - - static struct notifier_block hsr_nb = { .notifier_call = hsr_netdev_notify, /* Slave event notifications */ }; @@ -202,14 +186,7 @@ static int __init hsr_init(void) BUILD_BUG_ON(sizeof(struct hsr_tag) != HSR_HLEN); - init_timer(&prune_timer); - prune_timer.function = prune_nodes_all; - prune_timer.data = 0; - prune_timer.expires = jiffies + msecs_to_jiffies(PRUNE_PERIOD); - add_timer(&prune_timer); - register_netdevice_notifier(&hsr_nb); - res = hsr_netlink_init(); return res; @@ -218,7 +195,6 @@ static int __init hsr_init(void) static void __exit hsr_exit(void) { unregister_netdevice_notifier(&hsr_nb); - del_timer_sync(&prune_timer); hsr_netlink_exit(); } diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h index d919321b0bdb..43689a6d731f 100644 --- a/net/hsr/hsr_main.h +++ b/net/hsr/hsr_main.h @@ -153,6 +153,7 @@ struct hsr_priv { struct list_head node_db; /* Other HSR nodes */ struct list_head self_node_db; /* MACs of slaves */ struct timer_list announce_timer; /* Supervision frame dispatch */ + struct timer_list prune_timer; int announce_count; u16 sequence_nr; spinlock_t seqnr_lock; /* locking for sequence_nr */ -- cgit v1.2.3 From e9aae56ea43ef4a32527b9d86c1f6b5eebfbd223 Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Fri, 4 Jul 2014 23:36:40 +0200 Subject: net/hsr: Operstate handling cleanup. Signed-off-by: Arvid Brodin Signed-off-by: David S. Miller --- net/hsr/hsr_device.c | 37 ++++++++++++++++++++++++++++--------- net/hsr/hsr_device.h | 6 +----- net/hsr/hsr_main.c | 9 +-------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index f224067153e4..8936b3c2bb84 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -46,31 +46,36 @@ static void __hsr_set_operstate(struct net_device *dev, int transition) } } -void hsr_set_operstate(struct net_device *hsr_dev, struct net_device *slave1, - struct net_device *slave2) +static void hsr_set_operstate(struct net_device *hsr_dev, bool has_carrier) { if (!is_admin_up(hsr_dev)) { __hsr_set_operstate(hsr_dev, IF_OPER_DOWN); return; } - if (is_slave_up(slave1) || is_slave_up(slave2)) + if (has_carrier) __hsr_set_operstate(hsr_dev, IF_OPER_UP); else __hsr_set_operstate(hsr_dev, IF_OPER_LOWERLAYERDOWN); } -void hsr_set_carrier(struct net_device *hsr_dev, struct net_device *slave1, - struct net_device *slave2) +static bool hsr_check_carrier(struct hsr_priv *hsr) { - if (is_slave_up(slave1) || is_slave_up(slave2)) - netif_carrier_on(hsr_dev); + bool has_carrier; + + has_carrier = (is_slave_up(hsr->slave[0]) || is_slave_up(hsr->slave[1])); + + if (has_carrier) + netif_carrier_on(hsr->dev); else - netif_carrier_off(hsr_dev); + netif_carrier_off(hsr->dev); + + return has_carrier; } -void hsr_check_announce(struct net_device *hsr_dev, int old_operstate) +static void hsr_check_announce(struct net_device *hsr_dev, + unsigned char old_operstate) { struct hsr_priv *hsr; @@ -89,6 +94,20 @@ void hsr_check_announce(struct net_device *hsr_dev, int old_operstate) del_timer(&hsr->announce_timer); } +void hsr_check_carrier_and_operstate(struct hsr_priv *hsr) +{ + unsigned char old_operstate; + bool has_carrier; + + /* netif_stacked_transfer_operstate() cannot be used here since + * it doesn't set IF_OPER_LOWERLAYERDOWN (?) + */ + old_operstate = hsr->dev->operstate; + has_carrier = hsr_check_carrier(hsr); + hsr_set_operstate(hsr->dev, has_carrier); + hsr_check_announce(hsr->dev, old_operstate); +} + int hsr_get_max_mtu(struct hsr_priv *hsr) { diff --git a/net/hsr/hsr_device.h b/net/hsr/hsr_device.h index feb744f90f3d..108a5d59d2a6 100644 --- a/net/hsr/hsr_device.h +++ b/net/hsr/hsr_device.h @@ -18,11 +18,7 @@ void hsr_dev_setup(struct net_device *dev); int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], unsigned char multicast_spec); -void hsr_set_operstate(struct net_device *hsr_dev, struct net_device *slave1, - struct net_device *slave2); -void hsr_set_carrier(struct net_device *hsr_dev, struct net_device *slave1, - struct net_device *slave2); -void hsr_check_announce(struct net_device *hsr_dev, int old_operstate); +void hsr_check_carrier_and_operstate(struct hsr_priv *hsr); bool is_hsr_master(struct net_device *dev); int hsr_get_max_mtu(struct hsr_priv *hsr); diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c index 5f9cd7fdbd93..431b528c2447 100644 --- a/net/hsr/hsr_main.c +++ b/net/hsr/hsr_main.c @@ -91,7 +91,6 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, { struct net_device *slave, *other_slave; struct hsr_priv *hsr; - int old_operstate; int mtu_max; int res; struct net_device *dev; @@ -115,13 +114,7 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, case NETDEV_UP: /* Administrative state DOWN */ case NETDEV_DOWN: /* Administrative state UP */ case NETDEV_CHANGE: /* Link (carrier) state changes */ - old_operstate = hsr->dev->operstate; - hsr_set_carrier(hsr->dev, slave, other_slave); - /* netif_stacked_transfer_operstate() cannot be used here since - * it doesn't set IF_OPER_LOWERLAYERDOWN (?) - */ - hsr_set_operstate(hsr->dev, slave, other_slave); - hsr_check_announce(hsr->dev, old_operstate); + hsr_check_carrier_and_operstate(hsr); break; case NETDEV_CHANGEADDR: -- cgit v1.2.3 From 51f3c605318b056ac5deb9079bbef2a976558827 Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Fri, 4 Jul 2014 23:37:27 +0200 Subject: net/hsr: Move slave init to hsr_slave.c. Also try to prevent some possible slave dereference race conditions. This is finalized in the next patch, which abandons the slave array in favour of a list_head list and list RCU. Signed-off-by: Arvid Brodin Signed-off-by: David S. Miller --- net/hsr/hsr_device.c | 192 ++++++++++++++----------------------------------- net/hsr/hsr_framereg.c | 6 +- net/hsr/hsr_main.c | 24 ++++--- net/hsr/hsr_netlink.c | 53 ++++++++++---- net/hsr/hsr_slave.c | 91 +++++++++++++++++++++++ net/hsr/hsr_slave.h | 3 + 6 files changed, 205 insertions(+), 164 deletions(-) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 8936b3c2bb84..1f8869cb70ae 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include "hsr_device.h" @@ -108,23 +107,27 @@ void hsr_check_carrier_and_operstate(struct hsr_priv *hsr) hsr_check_announce(hsr->dev, old_operstate); } - int hsr_get_max_mtu(struct hsr_priv *hsr) { - int mtu_max; - - if (hsr->slave[0] && hsr->slave[1]) - mtu_max = min(hsr->slave[0]->mtu, hsr->slave[1]->mtu); - else if (hsr->slave[0]) - mtu_max = hsr->slave[0]->mtu; - else if (hsr->slave[1]) - mtu_max = hsr->slave[1]->mtu; - else - mtu_max = HSR_HLEN; - + unsigned int mtu_max; + struct net_device *slave; + + mtu_max = ETH_DATA_LEN; + rcu_read_lock(); + slave = hsr->slave[0]; + if (slave) + mtu_max = min(slave->mtu, mtu_max); + slave = hsr->slave[1]; + if (slave) + mtu_max = min(slave->mtu, mtu_max); + rcu_read_unlock(); + + if (mtu_max < HSR_HLEN) + return 0; return mtu_max - HSR_HLEN; } + static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu) { struct hsr_priv *hsr; @@ -145,18 +148,20 @@ static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu) static int hsr_dev_open(struct net_device *dev) { struct hsr_priv *hsr; + struct net_device *slave; int i; char *slave_name; hsr = netdev_priv(dev); for (i = 0; i < HSR_MAX_SLAVE; i++) { - if (hsr->slave[i]) - slave_name = hsr->slave[i]->name; + slave = hsr->slave[i]; + if (slave) + slave_name = slave->name; else slave_name = "null"; - if (!is_slave_up(hsr->slave[i])) + if (!is_slave_up(slave)) netdev_warn(dev, "Slave %c (%s) is not up; please bring it up to get a working HSR network\n", 'A' + i, slave_name); } @@ -223,6 +228,8 @@ static int slave_xmit(struct sk_buff *skb, struct hsr_priv *hsr, hsr_ethhdr = (struct hsr_ethhdr *) skb->data; skb->dev = hsr->slave[dev_idx]; + if (unlikely(!skb->dev)) + return NET_XMIT_DROP; hsr_addr_subst_dest(hsr, &hsr_ethhdr->ethhdr, dev_idx); @@ -252,14 +259,8 @@ static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev) } skb2 = pskb_copy(skb, GFP_ATOMIC); - - res1 = NET_XMIT_DROP; - if (likely(hsr->slave[HSR_DEV_SLAVE_A])) - res1 = slave_xmit(skb, hsr, HSR_DEV_SLAVE_A); - - res2 = NET_XMIT_DROP; - if (likely(skb2 && hsr->slave[HSR_DEV_SLAVE_B])) - res2 = slave_xmit(skb2, hsr, HSR_DEV_SLAVE_B); + res1 = slave_xmit(skb, hsr, HSR_DEV_SLAVE_A); + res2 = slave_xmit(skb2, hsr, HSR_DEV_SLAVE_B); if (likely(res1 == NET_XMIT_SUCCESS || res1 == NET_XMIT_CN || res2 == NET_XMIT_SUCCESS || res2 == NET_XMIT_CN)) { @@ -406,28 +407,10 @@ static void hsr_announce(unsigned long data) static void restore_slaves(struct net_device *hsr_dev) { struct hsr_priv *hsr; - int i; - int res; hsr = netdev_priv(hsr_dev); - - rtnl_lock(); - - for (i = 0; i < HSR_MAX_SLAVE; i++) { - if (!hsr->slave[i]) - continue; - res = dev_set_promiscuity(hsr->slave[i], -1); - if (res) - netdev_info(hsr_dev, - "Cannot restore slave promiscuity (%s, %d)\n", - hsr->slave[i]->name, res); - - if (hsr->slave[i]->rx_handler == hsr_handle_frame) - netdev_rx_handler_unregister(hsr->slave[i]); - } - - - rtnl_unlock(); + hsr_del_slave(hsr, 1); + hsr_del_slave(hsr, 0); } static void reclaim_hsr_dev(struct rcu_head *rh) @@ -483,38 +466,6 @@ bool is_hsr_master(struct net_device *dev) return (dev->netdev_ops->ndo_start_xmit == hsr_dev_xmit); } -static int check_slave_ok(struct net_device *dev) -{ - /* Don't allow HSR on non-ethernet like devices */ - if ((dev->flags & IFF_LOOPBACK) || (dev->type != ARPHRD_ETHER) || - (dev->addr_len != ETH_ALEN)) { - netdev_info(dev, "Cannot use loopback or non-ethernet device as HSR slave.\n"); - return -EINVAL; - } - - /* Don't allow enslaving hsr devices */ - if (is_hsr_master(dev)) { - netdev_info(dev, "Cannot create trees of HSR devices.\n"); - return -EINVAL; - } - - if (is_hsr_slave(dev)) { - netdev_info(dev, "This device is already a HSR slave.\n"); - return -EINVAL; - } - - if (dev->priv_flags & IFF_802_1Q_VLAN) { - netdev_info(dev, "HSR on top of VLAN is not yet supported in this driver.\n"); - return -EINVAL; - } - - /* HSR over bonded devices has not been tested, but I'm not sure it - * won't work... - */ - - return 0; -} - /* Default multicast address for HSR Supervision frames */ static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = { @@ -525,15 +476,30 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], unsigned char multicast_spec) { struct hsr_priv *hsr; - int i; int res; hsr = netdev_priv(hsr_dev); hsr->dev = hsr_dev; + hsr->slave[0] = NULL; + hsr->slave[1] = NULL; INIT_LIST_HEAD(&hsr->node_db); INIT_LIST_HEAD(&hsr->self_node_db); - for (i = 0; i < HSR_MAX_SLAVE; i++) - hsr->slave[i] = slave[i]; + + ether_addr_copy(hsr_dev->dev_addr, slave[0]->dev_addr); + + /* Make sure we recognize frames from ourselves in hsr_rcv() */ + res = hsr_create_self_node(&hsr->self_node_db, hsr_dev->dev_addr, + slave[1]->dev_addr); + if (res < 0) + return res; + + hsr_dev->features = slave[0]->features & slave[1]->features; + /* Prevent recursive tx locking */ + hsr_dev->features |= NETIF_F_LLTX; + /* VLAN on top of HSR needs testing and probably some work on + * hsr_header_create() etc. + */ + hsr_dev->features |= NETIF_F_VLAN_CHALLENGED; spin_lock_init(&hsr->seqnr_lock); /* Overflow soon to find bugs easier: */ @@ -560,65 +526,21 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], * IFF_HSR_MASTER/SLAVE? */ - for (i = 0; i < HSR_MAX_SLAVE; i++) { - res = check_slave_ok(slave[i]); - if (res) - return res; - } - - hsr_dev->features = slave[0]->features & slave[1]->features; - /* Prevent recursive tx locking */ - hsr_dev->features |= NETIF_F_LLTX; - /* VLAN on top of HSR needs testing and probably some work on - * hsr_header_create() etc. - */ - hsr_dev->features |= NETIF_F_VLAN_CHALLENGED; - - /* Set hsr_dev's MAC address to that of mac_slave1 */ - ether_addr_copy(hsr_dev->dev_addr, hsr->slave[0]->dev_addr); - - /* Set required header length */ - for (i = 0; i < HSR_MAX_SLAVE; i++) { - if (slave[i]->hard_header_len + HSR_HLEN > - hsr_dev->hard_header_len) - hsr_dev->hard_header_len = - slave[i]->hard_header_len + HSR_HLEN; - } - - /* MTU */ - for (i = 0; i < HSR_MAX_SLAVE; i++) - if (slave[i]->mtu - HSR_HLEN < hsr_dev->mtu) - hsr_dev->mtu = slave[i]->mtu - HSR_HLEN; - /* Make sure the 1st call to netif_carrier_on() gets through */ netif_carrier_off(hsr_dev); - /* Promiscuity */ - for (i = 0; i < HSR_MAX_SLAVE; i++) { - res = dev_set_promiscuity(slave[i], 1); - if (res) { - netdev_info(hsr_dev, "Cannot set slave promiscuity (%s, %d)\n", - slave[i]->name, res); - goto fail; - } - } - - for (i = 0; i < HSR_MAX_SLAVE; i++) { - res = netdev_rx_handler_register(slave[i], hsr_handle_frame, - hsr); - if (res) - goto fail; - } - - /* Make sure we recognize frames from ourselves in hsr_rcv() */ - res = hsr_create_self_node(&hsr->self_node_db, hsr_dev->dev_addr, - hsr->slave[1]->dev_addr); - if (res < 0) - goto fail; - res = register_netdevice(hsr_dev); if (res) - goto fail; + return res; + + res = hsr_add_slave(hsr, slave[0], 0); + if (res) + return res; + res = hsr_add_slave(hsr, slave[1], 1); + if (res) { + hsr_del_slave(hsr, 0); + return res; + } hsr->prune_timer.expires = jiffies + msecs_to_jiffies(PRUNE_PERIOD); add_timer(&hsr->prune_timer); @@ -626,8 +548,4 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], register_hsr_master(hsr); return 0; - -fail: - restore_slaves(hsr_dev); - return res; } diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index 79e3f7ff6654..3666f94c526f 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c @@ -455,6 +455,7 @@ int hsr_get_node_data(struct hsr_priv *hsr, u16 *if2_seq) { struct hsr_node *node; + struct net_device *slave; unsigned long tdiff; @@ -491,8 +492,9 @@ int hsr_get_node_data(struct hsr_priv *hsr, *if1_seq = node->seq_out[HSR_DEV_SLAVE_B]; *if2_seq = node->seq_out[HSR_DEV_SLAVE_A]; - if ((node->AddrB_if != HSR_DEV_NONE) && hsr->slave[node->AddrB_if]) - *addr_b_ifindex = hsr->slave[node->AddrB_if]->ifindex; + slave = hsr->slave[node->AddrB_if]; + if ((node->AddrB_if != HSR_DEV_NONE) && slave) + *addr_b_ifindex = slave->ifindex; else *addr_b_ifindex = -1; diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c index 431b528c2447..b5abe26f7b4c 100644 --- a/net/hsr/hsr_main.c +++ b/net/hsr/hsr_main.c @@ -17,6 +17,7 @@ #include "hsr_device.h" #include "hsr_netlink.h" #include "hsr_framereg.h" +#include "hsr_slave.h" /* List of all registered virtual HSR devices */ @@ -124,22 +125,21 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, if (dev == hsr->dev) break; - if (dev == hsr->slave[0]) - ether_addr_copy(hsr->dev->dev_addr, - hsr->slave[0]->dev_addr); + if (dev == hsr->slave[0]) { + ether_addr_copy(hsr->dev->dev_addr, dev->dev_addr); + call_netdevice_notifiers(NETDEV_CHANGEADDR, hsr->dev); + } /* Make sure we recognize frames from ourselves in hsr_rcv() */ + other_slave = hsr->slave[1]; res = hsr_create_self_node(&hsr->self_node_db, hsr->dev->dev_addr, - hsr->slave[1] ? - hsr->slave[1]->dev_addr : + other_slave ? + other_slave->dev_addr : hsr->dev->dev_addr); if (res) netdev_warn(hsr->dev, "Could not update HSR node address.\n"); - - if (dev == hsr->slave[0]) - call_netdevice_notifiers(NETDEV_CHANGEADDR, hsr->dev); break; case NETDEV_CHANGEMTU: if (dev == hsr->dev) @@ -149,10 +149,14 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, dev_set_mtu(hsr->dev, mtu_max); break; case NETDEV_UNREGISTER: - if (dev == hsr->slave[0]) + if (dev == hsr->slave[0]) { hsr->slave[0] = NULL; - if (dev == hsr->slave[1]) + hsr_del_slave(hsr, 0); + } + if (dev == hsr->slave[1]) { hsr->slave[1] = NULL; + hsr_del_slave(hsr, 1); + } /* There should really be a way to set a new slave device... */ diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index bea250ec3586..a2ce359774f3 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c @@ -64,16 +64,28 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev, static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) { struct hsr_priv *hsr; + struct net_device *slave; + int res; hsr = netdev_priv(dev); - if (hsr->slave[0]) - if (nla_put_u32(skb, IFLA_HSR_SLAVE1, hsr->slave[0]->ifindex)) - goto nla_put_failure; + res = 0; - if (hsr->slave[1]) - if (nla_put_u32(skb, IFLA_HSR_SLAVE2, hsr->slave[1]->ifindex)) - goto nla_put_failure; + rcu_read_lock(); + slave = hsr->slave[0]; + if (slave) + res = nla_put_u32(skb, IFLA_HSR_SLAVE1, slave->ifindex); + rcu_read_unlock(); + if (res) + goto nla_put_failure; + + rcu_read_lock(); + slave = hsr->slave[1]; + if (slave) + res = nla_put_u32(skb, IFLA_HSR_SLAVE2, slave->ifindex); + rcu_read_unlock(); + if (res) + goto nla_put_failure; if (nla_put(skb, IFLA_HSR_SUPERVISION_ADDR, ETH_ALEN, hsr->sup_multicast_addr) || @@ -132,6 +144,7 @@ void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN], enum hsr_dev_idx dev_idx) { struct sk_buff *skb; + struct net_device *slave; void *msg_head; int res; int ifindex; @@ -148,10 +161,14 @@ void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN], if (res < 0) goto nla_put_failure; - if (hsr->slave[dev_idx]) - ifindex = hsr->slave[dev_idx]->ifindex; + rcu_read_lock(); + slave = hsr->slave[dev_idx]; + if (slave) + ifindex = slave->ifindex; else ifindex = -1; + rcu_read_unlock(); + res = nla_put_u32(skb, HSR_A_IFINDEX, ifindex); if (res < 0) goto nla_put_failure; @@ -215,7 +232,7 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) { /* For receiving */ struct nlattr *na; - struct net_device *hsr_dev; + struct net_device *hsr_dev, *slave; /* For sending */ struct sk_buff *skb_out; @@ -301,9 +318,11 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) res = nla_put_u16(skb_out, HSR_A_IF1_SEQ, hsr_node_if1_seq); if (res < 0) goto nla_put_failure; - if (hsr->slave[0]) - res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX, - hsr->slave[0]->ifindex); + rcu_read_lock(); + slave = hsr->slave[0]; + if (slave) + res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX, slave->ifindex); + rcu_read_unlock(); if (res < 0) goto nla_put_failure; @@ -313,9 +332,13 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) res = nla_put_u16(skb_out, HSR_A_IF2_SEQ, hsr_node_if2_seq); if (res < 0) goto nla_put_failure; - if (hsr->slave[1]) - res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX, - hsr->slave[1]->ifindex); + rcu_read_lock(); + slave = hsr->slave[1]; + if (slave) + res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX, slave->ifindex); + rcu_read_unlock(); + if (res < 0) + goto nla_put_failure; genlmsg_end(skb_out, msg_head); genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid); diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index 702814631ee1..d676090f7900 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c @@ -11,10 +11,45 @@ #include "hsr_slave.h" #include +#include #include "hsr_main.h" +#include "hsr_device.h" #include "hsr_framereg.h" +static int check_slave_ok(struct net_device *dev) +{ + /* Don't allow HSR on non-ethernet like devices */ + if ((dev->flags & IFF_LOOPBACK) || (dev->type != ARPHRD_ETHER) || + (dev->addr_len != ETH_ALEN)) { + netdev_info(dev, "Cannot use loopback or non-ethernet device as HSR slave.\n"); + return -EINVAL; + } + + /* Don't allow enslaving hsr devices */ + if (is_hsr_master(dev)) { + netdev_info(dev, "Cannot create trees of HSR devices.\n"); + return -EINVAL; + } + + if (is_hsr_slave(dev)) { + netdev_info(dev, "This device is already a HSR slave.\n"); + return -EINVAL; + } + + if (dev->priv_flags & IFF_802_1Q_VLAN) { + netdev_info(dev, "HSR on top of VLAN is not yet supported in this driver.\n"); + return -EINVAL; + } + + /* HSR over bonded devices has not been tested, but I'm not sure it + * won't work... + */ + + return 0; +} + + static struct sk_buff *hsr_pull_tag(struct sk_buff *skb) { struct hsr_tag *hsr_tag; @@ -241,3 +276,59 @@ forward: return RX_HANDLER_CONSUMED; } + +int hsr_add_slave(struct hsr_priv *hsr, struct net_device *dev, int idx) +{ + int res; + + dev_hold(dev); + + res = check_slave_ok(dev); + if (res) + goto fail; + + res = dev_set_promiscuity(dev, 1); + if (res) + goto fail; + + res = netdev_rx_handler_register(dev, hsr_handle_frame, hsr); + if (res) + goto fail_rx_handler; + + + hsr->slave[idx] = dev; + + /* Set required header length */ + if (dev->hard_header_len + HSR_HLEN > hsr->dev->hard_header_len) + hsr->dev->hard_header_len = dev->hard_header_len + HSR_HLEN; + + dev_set_mtu(hsr->dev, hsr_get_max_mtu(hsr)); + + return 0; + +fail_rx_handler: + dev_set_promiscuity(dev, -1); + +fail: + dev_put(dev); + return res; +} + +void hsr_del_slave(struct hsr_priv *hsr, int idx) +{ + struct net_device *slave; + + slave = hsr->slave[idx]; + hsr->slave[idx] = NULL; + + netdev_update_features(hsr->dev); + dev_set_mtu(hsr->dev, hsr_get_max_mtu(hsr)); + + if (slave) { + netdev_rx_handler_unregister(slave); + dev_set_promiscuity(slave, -1); + } + + synchronize_rcu(); + dev_put(slave); +} diff --git a/net/hsr/hsr_slave.h b/net/hsr/hsr_slave.h index ae90c8d0fde4..03c15fda39a8 100644 --- a/net/hsr/hsr_slave.h +++ b/net/hsr/hsr_slave.h @@ -14,7 +14,10 @@ #include #include +#include "hsr_main.h" +int hsr_add_slave(struct hsr_priv *hsr, struct net_device *dev, int idx); +void hsr_del_slave(struct hsr_priv *hsr, int idx); rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb); #endif /* __HSR_SLAVE_H */ -- cgit v1.2.3 From c5a7591172100269e426cf630da0f2dc8138a206 Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Fri, 4 Jul 2014 23:38:05 +0200 Subject: net/hsr: Use list_head (and rcu) instead of array for slave devices. Signed-off-by: Arvid Brodin Signed-off-by: David S. Miller --- net/hsr/hsr_device.c | 242 +++++++++++++++++++++++++++---------------------- net/hsr/hsr_framereg.c | 142 +++++++++++++---------------- net/hsr/hsr_framereg.h | 12 +-- net/hsr/hsr_main.c | 128 ++++++++------------------ net/hsr/hsr_main.h | 31 ++++--- net/hsr/hsr_netlink.c | 57 ++++++------ net/hsr/hsr_netlink.h | 3 +- net/hsr/hsr_slave.c | 199 ++++++++++++++++++++++++---------------- net/hsr/hsr_slave.h | 29 +++++- 9 files changed, 438 insertions(+), 405 deletions(-) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 1f8869cb70ae..1fc4ea20752e 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -45,29 +45,38 @@ static void __hsr_set_operstate(struct net_device *dev, int transition) } } -static void hsr_set_operstate(struct net_device *hsr_dev, bool has_carrier) +static void hsr_set_operstate(struct hsr_port *master, bool has_carrier) { - if (!is_admin_up(hsr_dev)) { - __hsr_set_operstate(hsr_dev, IF_OPER_DOWN); + if (!is_admin_up(master->dev)) { + __hsr_set_operstate(master->dev, IF_OPER_DOWN); return; } if (has_carrier) - __hsr_set_operstate(hsr_dev, IF_OPER_UP); + __hsr_set_operstate(master->dev, IF_OPER_UP); else - __hsr_set_operstate(hsr_dev, IF_OPER_LOWERLAYERDOWN); + __hsr_set_operstate(master->dev, IF_OPER_LOWERLAYERDOWN); } -static bool hsr_check_carrier(struct hsr_priv *hsr) +static bool hsr_check_carrier(struct hsr_port *master) { + struct hsr_port *port; bool has_carrier; - has_carrier = (is_slave_up(hsr->slave[0]) || is_slave_up(hsr->slave[1])); + has_carrier = false; + + rcu_read_lock(); + hsr_for_each_port(master->hsr, port) + if ((port->type != HSR_PT_MASTER) && is_slave_up(port->dev)) { + has_carrier = true; + break; + } + rcu_read_unlock(); if (has_carrier) - netif_carrier_on(hsr->dev); + netif_carrier_on(master->dev); else - netif_carrier_off(hsr->dev); + netif_carrier_off(master->dev); return has_carrier; } @@ -95,31 +104,30 @@ static void hsr_check_announce(struct net_device *hsr_dev, void hsr_check_carrier_and_operstate(struct hsr_priv *hsr) { + struct hsr_port *master; unsigned char old_operstate; bool has_carrier; + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); /* netif_stacked_transfer_operstate() cannot be used here since * it doesn't set IF_OPER_LOWERLAYERDOWN (?) */ - old_operstate = hsr->dev->operstate; - has_carrier = hsr_check_carrier(hsr); - hsr_set_operstate(hsr->dev, has_carrier); - hsr_check_announce(hsr->dev, old_operstate); + old_operstate = master->dev->operstate; + has_carrier = hsr_check_carrier(master); + hsr_set_operstate(master, has_carrier); + hsr_check_announce(master->dev, old_operstate); } int hsr_get_max_mtu(struct hsr_priv *hsr) { unsigned int mtu_max; - struct net_device *slave; + struct hsr_port *port; mtu_max = ETH_DATA_LEN; rcu_read_lock(); - slave = hsr->slave[0]; - if (slave) - mtu_max = min(slave->mtu, mtu_max); - slave = hsr->slave[1]; - if (slave) - mtu_max = min(slave->mtu, mtu_max); + hsr_for_each_port(hsr, port) + if (port->type != HSR_PT_MASTER) + mtu_max = min(port->dev->mtu, mtu_max); rcu_read_unlock(); if (mtu_max < HSR_HLEN) @@ -131,11 +139,13 @@ int hsr_get_max_mtu(struct hsr_priv *hsr) static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu) { struct hsr_priv *hsr; + struct hsr_port *master; hsr = netdev_priv(dev); + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); if (new_mtu > hsr_get_max_mtu(hsr)) { - netdev_info(hsr->dev, "A HSR master's MTU cannot be greater than the smallest MTU of its slaves minus the HSR Tag length (%d octets).\n", + netdev_info(master->dev, "A HSR master's MTU cannot be greater than the smallest MTU of its slaves minus the HSR Tag length (%d octets).\n", HSR_HLEN); return -EINVAL; } @@ -148,35 +158,42 @@ static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu) static int hsr_dev_open(struct net_device *dev) { struct hsr_priv *hsr; - struct net_device *slave; - int i; - char *slave_name; + struct hsr_port *port; + char designation; hsr = netdev_priv(dev); + designation = '\0'; - for (i = 0; i < HSR_MAX_SLAVE; i++) { - slave = hsr->slave[i]; - if (slave) - slave_name = slave->name; - else - slave_name = "null"; - - if (!is_slave_up(slave)) - netdev_warn(dev, "Slave %c (%s) is not up; please bring it up to get a working HSR network\n", - 'A' + i, slave_name); + rcu_read_lock(); + hsr_for_each_port(hsr, port) { + if (port->type == HSR_PT_MASTER) + continue; + switch (port->type) { + case HSR_PT_SLAVE_A: + designation = 'A'; + break; + case HSR_PT_SLAVE_B: + designation = 'B'; + break; + default: + designation = '?'; + } + if (!is_slave_up(port->dev)) + netdev_warn(dev, "Slave %c (%s) is not up; please bring it up to get a fully working HSR network\n", + designation, port->dev->name); } + rcu_read_unlock(); + + if (designation == '\0') + netdev_warn(dev, "No slave devices configured\n"); return 0; } + static int hsr_dev_close(struct net_device *dev) { - /* Nothing to do here. We could try to restore the state of the slaves - * to what they were before being changed by the hsr master dev's state, - * but they might have been changed manually in the mean time too, so - * taking them up or down here might be confusing and is probably not a - * good idea. - */ + /* Nothing to do here. */ return 0; } @@ -220,18 +237,24 @@ static void hsr_fill_tag(struct hsr_ethhdr *hsr_ethhdr, struct hsr_priv *hsr) hsr_ethhdr->ethhdr.h_proto = htons(ETH_P_PRP); } -static int slave_xmit(struct sk_buff *skb, struct hsr_priv *hsr, - enum hsr_dev_idx dev_idx) +static int slave_xmit(struct hsr_priv *hsr, struct sk_buff *skb, + enum hsr_port_type type) { + struct hsr_port *port; struct hsr_ethhdr *hsr_ethhdr; hsr_ethhdr = (struct hsr_ethhdr *) skb->data; - skb->dev = hsr->slave[dev_idx]; - if (unlikely(!skb->dev)) + rcu_read_lock(); + port = hsr_port_get_hsr(hsr, type); + if (!port) { + rcu_read_unlock(); return NET_XMIT_DROP; + } + skb->dev = port->dev; - hsr_addr_subst_dest(hsr, &hsr_ethhdr->ethhdr, dev_idx); + hsr_addr_subst_dest(port->hsr, &hsr_ethhdr->ethhdr, port); + rcu_read_unlock(); /* Address substitution (IEC62439-3 pp 26, 50): replace mac * address of outgoing frame with that of the outgoing slave's. @@ -241,10 +264,10 @@ static int slave_xmit(struct sk_buff *skb, struct hsr_priv *hsr, return dev_queue_xmit(skb); } - static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev) { struct hsr_priv *hsr; + struct hsr_port *master; struct hsr_ethhdr *hsr_ethhdr; struct sk_buff *skb2; int res1, res2; @@ -259,16 +282,23 @@ static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev) } skb2 = pskb_copy(skb, GFP_ATOMIC); - res1 = slave_xmit(skb, hsr, HSR_DEV_SLAVE_A); - res2 = slave_xmit(skb2, hsr, HSR_DEV_SLAVE_B); + res1 = slave_xmit(hsr, skb, HSR_PT_SLAVE_A); + if (skb2) + res2 = slave_xmit(hsr, skb2, HSR_PT_SLAVE_B); + else + res2 = NET_XMIT_DROP; + + rcu_read_lock(); + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); if (likely(res1 == NET_XMIT_SUCCESS || res1 == NET_XMIT_CN || res2 == NET_XMIT_SUCCESS || res2 == NET_XMIT_CN)) { - hsr->dev->stats.tx_packets++; - hsr->dev->stats.tx_bytes += skb->len; + master->dev->stats.tx_packets++; + master->dev->stats.tx_bytes += skb->len; } else { - hsr->dev->stats.tx_dropped++; + master->dev->stats.tx_dropped++; } + rcu_read_unlock(); return NETDEV_TX_OK; } @@ -322,31 +352,35 @@ static int hsr_pad(int size) static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type) { struct hsr_priv *hsr; + struct hsr_port *master; struct sk_buff *skb; int hlen, tlen; struct hsr_sup_tag *hsr_stag; struct hsr_sup_payload *hsr_sp; unsigned long irqflags; + int res; + + hsr = netdev_priv(hsr_dev); + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); - hlen = LL_RESERVED_SPACE(hsr_dev); - tlen = hsr_dev->needed_tailroom; + hlen = LL_RESERVED_SPACE(master->dev); + tlen = master->dev->needed_tailroom; skb = alloc_skb(hsr_pad(sizeof(struct hsr_sup_payload)) + hlen + tlen, GFP_ATOMIC); if (skb == NULL) return; - hsr = netdev_priv(hsr_dev); - skb_reserve(skb, hlen); - skb->dev = hsr_dev; + skb->dev = master->dev; skb->protocol = htons(ETH_P_PRP); skb->priority = TC_PRIO_CONTROL; - if (dev_hard_header(skb, skb->dev, ETH_P_PRP, - hsr->sup_multicast_addr, - skb->dev->dev_addr, skb->len) < 0) + res = dev_hard_header(skb, skb->dev, ETH_P_PRP, + hsr->sup_multicast_addr, + skb->dev->dev_addr, skb->len); + if (res <= 0) goto out; skb_pull(skb, sizeof(struct ethhdr)); @@ -367,12 +401,13 @@ static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type) /* Payload: MacAddressA */ hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(*hsr_sp)); - ether_addr_copy(hsr_sp->MacAddressA, hsr_dev->dev_addr); + ether_addr_copy(hsr_sp->MacAddressA, master->dev->dev_addr); dev_queue_xmit(skb); return; out: + WARN_ON_ONCE("HSR: Could not send supervision frame\n"); kfree_skb(skb); } @@ -382,14 +417,16 @@ out: static void hsr_announce(unsigned long data) { struct hsr_priv *hsr; + struct hsr_port *master; hsr = (struct hsr_priv *) data; + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); if (hsr->announce_count < 3) { - send_hsr_supervision_frame(hsr->dev, HSR_TLV_ANNOUNCE); + send_hsr_supervision_frame(master->dev, HSR_TLV_ANNOUNCE); hsr->announce_count++; } else { - send_hsr_supervision_frame(hsr->dev, HSR_TLV_LIFE_CHECK); + send_hsr_supervision_frame(master->dev, HSR_TLV_LIFE_CHECK); } if (hsr->announce_count < 3) @@ -399,43 +436,28 @@ static void hsr_announce(unsigned long data) hsr->announce_timer.expires = jiffies + msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL); - if (is_admin_up(hsr->dev)) + if (is_admin_up(master->dev)) add_timer(&hsr->announce_timer); } -static void restore_slaves(struct net_device *hsr_dev) -{ - struct hsr_priv *hsr; - - hsr = netdev_priv(hsr_dev); - hsr_del_slave(hsr, 1); - hsr_del_slave(hsr, 0); -} - -static void reclaim_hsr_dev(struct rcu_head *rh) -{ - struct hsr_priv *hsr; - - hsr = container_of(rh, struct hsr_priv, rcu_head); - free_netdev(hsr->dev); -} - - /* According to comments in the declaration of struct net_device, this function * is "Called from unregister, can be used to call free_netdev". Ok then... */ static void hsr_dev_destroy(struct net_device *hsr_dev) { struct hsr_priv *hsr; + struct hsr_port *port; hsr = netdev_priv(hsr_dev); + hsr_for_each_port(hsr, port) + hsr_del_port(port); del_timer_sync(&hsr->prune_timer); del_timer_sync(&hsr->announce_timer); - unregister_hsr_master(hsr); /* calls list_del_rcu on hsr */ - restore_slaves(hsr_dev); - call_rcu(&hsr->rcu_head, reclaim_hsr_dev); /* reclaim hsr */ + + synchronize_rcu(); + free_netdev(hsr_dev); } static const struct net_device_ops hsr_device_ops = { @@ -461,12 +483,11 @@ void hsr_dev_setup(struct net_device *dev) /* Return true if dev is a HSR master; return false otherwise. */ -bool is_hsr_master(struct net_device *dev) +inline bool is_hsr_master(struct net_device *dev) { return (dev->netdev_ops->ndo_start_xmit == hsr_dev_xmit); } - /* Default multicast address for HSR Supervision frames */ static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = { 0x01, 0x15, 0x4e, 0x00, 0x01, 0x00 @@ -476,12 +497,11 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], unsigned char multicast_spec) { struct hsr_priv *hsr; + struct hsr_port *port; int res; hsr = netdev_priv(hsr_dev); - hsr->dev = hsr_dev; - hsr->slave[0] = NULL; - hsr->slave[1] = NULL; + INIT_LIST_HEAD(&hsr->ports); INIT_LIST_HEAD(&hsr->node_db); INIT_LIST_HEAD(&hsr->self_node_db); @@ -516,36 +536,42 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], ether_addr_copy(hsr->sup_multicast_addr, def_multicast_addr); hsr->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec; -/* FIXME: should I modify the value of these? - * - * - hsr_dev->flags - i.e. - * IFF_MASTER/SLAVE? - * - hsr_dev->priv_flags - i.e. - * IFF_EBRIDGE? - * IFF_TX_SKB_SHARING? - * IFF_HSR_MASTER/SLAVE? - */ + /* FIXME: should I modify the value of these? + * + * - hsr_dev->flags - i.e. + * IFF_MASTER/SLAVE? + * - hsr_dev->priv_flags - i.e. + * IFF_EBRIDGE? + * IFF_TX_SKB_SHARING? + * IFF_HSR_MASTER/SLAVE? + */ /* Make sure the 1st call to netif_carrier_on() gets through */ netif_carrier_off(hsr_dev); - res = register_netdevice(hsr_dev); + res = hsr_add_port(hsr, hsr_dev, HSR_PT_MASTER); if (res) return res; - res = hsr_add_slave(hsr, slave[0], 0); + res = register_netdevice(hsr_dev); if (res) - return res; - res = hsr_add_slave(hsr, slave[1], 1); - if (res) { - hsr_del_slave(hsr, 0); - return res; - } + goto fail; + + res = hsr_add_port(hsr, slave[0], HSR_PT_SLAVE_A); + if (res) + goto fail; + res = hsr_add_port(hsr, slave[1], HSR_PT_SLAVE_B); + if (res) + goto fail; hsr->prune_timer.expires = jiffies + msecs_to_jiffies(PRUNE_PERIOD); add_timer(&hsr->prune_timer); - register_hsr_master(hsr); - return 0; + +fail: + hsr_for_each_port(hsr, port) + hsr_del_port(port); + + return res; } diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index 3666f94c526f..c9b78c52c75b 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c @@ -27,12 +27,11 @@ struct hsr_node { struct list_head mac_list; unsigned char MacAddressA[ETH_ALEN]; unsigned char MacAddressB[ETH_ALEN]; - enum hsr_dev_idx AddrB_if;/* The local slave through which AddrB - * frames are received from this node - */ - unsigned long time_in[HSR_MAX_SLAVE]; - bool time_in_stale[HSR_MAX_SLAVE]; - u16 seq_out[HSR_MAX_DEV]; + /* Local slave through which AddrB frames are received from this node */ + enum hsr_port_type AddrB_port; + unsigned long time_in[HSR_PT_PORTS]; + bool time_in_stale[HSR_PT_PORTS]; + u16 seq_out[HSR_PT_PORTS]; struct rcu_head rcu_head; }; @@ -154,11 +153,10 @@ int hsr_create_self_node(struct list_head *self_node_db, * We also need to detect if the sender's SlaveA and SlaveB cables have been * swapped. */ -struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, - struct hsr_node *node, - struct sk_buff *skb, - enum hsr_dev_idx dev_idx) +struct hsr_node *hsr_merge_node(struct hsr_node *node, struct sk_buff *skb, + struct hsr_port *port) { + struct hsr_priv *hsr; struct hsr_sup_payload *hsr_sp; struct hsr_ethhdr_sp *hsr_ethsup; int i; @@ -166,6 +164,7 @@ struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, hsr_ethsup = (struct hsr_ethhdr_sp *) skb_mac_header(skb); hsr_sp = (struct hsr_sup_payload *) skb->data; + hsr = port->hsr; if (node && !ether_addr_equal(node->MacAddressA, hsr_sp->MacAddressA)) { /* Node has changed its AddrA, frame was received from SlaveB */ @@ -174,7 +173,7 @@ struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, node = NULL; } - if (node && (dev_idx == node->AddrB_if) && + if (node && (port->type == node->AddrB_port) && !ether_addr_equal(node->MacAddressB, hsr_ethsup->ethhdr.h_source)) { /* Cables have been swapped */ list_del_rcu(&node->mac_list); @@ -182,8 +181,8 @@ struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, node = NULL; } - if (node && (dev_idx != node->AddrB_if) && - (node->AddrB_if != HSR_DEV_NONE) && + if (node && (port->type != node->AddrB_port) && + (node->AddrB_port != HSR_PT_NONE) && !ether_addr_equal(node->MacAddressA, hsr_ethsup->ethhdr.h_source)) { /* Cables have been swapped */ list_del_rcu(&node->mac_list); @@ -200,7 +199,7 @@ struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, * address. Node is PICS_SUBS capable; merge its AddrB. */ ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source); - node->AddrB_if = dev_idx; + node->AddrB_port = port->type; return node; } @@ -211,17 +210,15 @@ struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, ether_addr_copy(node->MacAddressA, hsr_sp->MacAddressA); ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source); if (!ether_addr_equal(hsr_sp->MacAddressA, hsr_ethsup->ethhdr.h_source)) - node->AddrB_if = dev_idx; - else - node->AddrB_if = HSR_DEV_NONE; + node->AddrB_port = port->type; /* We are only interested in time diffs here, so use current jiffies * as initialization. (0 could trigger an spurious ring error warning). */ now = jiffies; - for (i = 0; i < HSR_MAX_SLAVE; i++) + for (i = 0; i < HSR_PT_PORTS; i++) node->time_in[i] = now; - for (i = 0; i < HSR_MAX_DEV; i++) + for (i = 0; i < HSR_PT_PORTS; i++) node->seq_out[i] = ntohs(hsr_ethsup->hsr_sup.sequence_nr) - 1; list_add_tail_rcu(&node->mac_list, &hsr->node_db); @@ -265,13 +262,13 @@ void hsr_addr_subst_source(struct hsr_priv *hsr, struct sk_buff *skb) * which "side" the different interfaces are. */ void hsr_addr_subst_dest(struct hsr_priv *hsr, struct ethhdr *ethhdr, - enum hsr_dev_idx dev_idx) + struct hsr_port *port) { struct hsr_node *node; rcu_read_lock(); node = find_node_by_AddrA(&hsr->node_db, ethhdr->h_dest); - if (node && (node->AddrB_if == dev_idx)) + if (node && (node->AddrB_port == port->type)) ether_addr_copy(ethhdr->h_dest, node->MacAddressB); rcu_read_unlock(); } @@ -295,14 +292,10 @@ static bool seq_nr_after(u16 a, u16 b) #define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b))) -void hsr_register_frame_in(struct hsr_node *node, enum hsr_dev_idx dev_idx) +void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port) { - if ((dev_idx < 0) || (dev_idx >= HSR_MAX_SLAVE)) { - WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx); - return; - } - node->time_in[dev_idx] = jiffies; - node->time_in_stale[dev_idx] = false; + node->time_in[port->type] = jiffies; + node->time_in_stale[port->type] = false; } @@ -314,16 +307,12 @@ void hsr_register_frame_in(struct hsr_node *node, enum hsr_dev_idx dev_idx) * 0 otherwise, or * negative error code on error */ -int hsr_register_frame_out(struct hsr_node *node, enum hsr_dev_idx dev_idx, +int hsr_register_frame_out(struct hsr_node *node, struct hsr_port *port, struct sk_buff *skb) { struct hsr_ethhdr *hsr_ethhdr; u16 sequence_nr; - if ((dev_idx < 0) || (dev_idx >= HSR_MAX_DEV)) { - WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx); - return -EINVAL; - } if (!skb_mac_header_was_set(skb)) { WARN_ONCE(1, "%s: Mac header not set\n", __func__); return -EINVAL; @@ -331,35 +320,32 @@ int hsr_register_frame_out(struct hsr_node *node, enum hsr_dev_idx dev_idx, hsr_ethhdr = (struct hsr_ethhdr *) skb_mac_header(skb); sequence_nr = ntohs(hsr_ethhdr->hsr_tag.sequence_nr); - if (seq_nr_before_or_eq(sequence_nr, node->seq_out[dev_idx])) + if (seq_nr_before_or_eq(sequence_nr, node->seq_out[port->type])) return 1; - node->seq_out[dev_idx] = sequence_nr; + node->seq_out[port->type] = sequence_nr; return 0; } - -static bool is_late(struct hsr_node *node, enum hsr_dev_idx dev_idx) +static struct hsr_port *get_late_port(struct hsr_priv *hsr, + struct hsr_node *node) { - enum hsr_dev_idx other; - - if (node->time_in_stale[dev_idx]) - return true; - - if (dev_idx == HSR_DEV_SLAVE_A) - other = HSR_DEV_SLAVE_B; - else - other = HSR_DEV_SLAVE_A; - - if (node->time_in_stale[other]) - return false; + if (node->time_in_stale[HSR_PT_SLAVE_A]) + return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); + if (node->time_in_stale[HSR_PT_SLAVE_B]) + return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); + + if (time_after(node->time_in[HSR_PT_SLAVE_B], + node->time_in[HSR_PT_SLAVE_A] + + msecs_to_jiffies(MAX_SLAVE_DIFF))) + return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); + if (time_after(node->time_in[HSR_PT_SLAVE_A], + node->time_in[HSR_PT_SLAVE_B] + + msecs_to_jiffies(MAX_SLAVE_DIFF))) + return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); - if (time_after(node->time_in[other], node->time_in[dev_idx] + - msecs_to_jiffies(MAX_SLAVE_DIFF))) - return true; - - return false; + return NULL; } @@ -370,6 +356,7 @@ void hsr_prune_nodes(unsigned long data) { struct hsr_priv *hsr; struct hsr_node *node; + struct hsr_port *port; unsigned long timestamp; unsigned long time_a, time_b; @@ -378,35 +365,33 @@ void hsr_prune_nodes(unsigned long data) rcu_read_lock(); list_for_each_entry_rcu(node, &hsr->node_db, mac_list) { /* Shorthand */ - time_a = node->time_in[HSR_DEV_SLAVE_A]; - time_b = node->time_in[HSR_DEV_SLAVE_B]; + time_a = node->time_in[HSR_PT_SLAVE_A]; + time_b = node->time_in[HSR_PT_SLAVE_B]; /* Check for timestamps old enough to risk wrap-around */ if (time_after(jiffies, time_a + MAX_JIFFY_OFFSET/2)) - node->time_in_stale[HSR_DEV_SLAVE_A] = true; + node->time_in_stale[HSR_PT_SLAVE_A] = true; if (time_after(jiffies, time_b + MAX_JIFFY_OFFSET/2)) - node->time_in_stale[HSR_DEV_SLAVE_B] = true; + node->time_in_stale[HSR_PT_SLAVE_B] = true; /* Get age of newest frame from node. * At least one time_in is OK here; nodes get pruned long * before both time_ins can get stale */ timestamp = time_a; - if (node->time_in_stale[HSR_DEV_SLAVE_A] || - (!node->time_in_stale[HSR_DEV_SLAVE_B] && + if (node->time_in_stale[HSR_PT_SLAVE_A] || + (!node->time_in_stale[HSR_PT_SLAVE_B] && time_after(time_b, time_a))) timestamp = time_b; /* Warn of ring error only as long as we get frames at all */ if (time_is_after_jiffies(timestamp + msecs_to_jiffies(1.5*MAX_SLAVE_DIFF))) { - - if (is_late(node, HSR_DEV_SLAVE_A)) - hsr_nl_ringerror(hsr, node->MacAddressA, - HSR_DEV_SLAVE_A); - else if (is_late(node, HSR_DEV_SLAVE_B)) - hsr_nl_ringerror(hsr, node->MacAddressA, - HSR_DEV_SLAVE_B); + rcu_read_lock(); + port = get_late_port(hsr, node); + if (port != NULL) + hsr_nl_ringerror(hsr, node->MacAddressA, port); + rcu_read_unlock(); } /* Prune old entries */ @@ -455,7 +440,7 @@ int hsr_get_node_data(struct hsr_priv *hsr, u16 *if2_seq) { struct hsr_node *node; - struct net_device *slave; + struct hsr_port *port; unsigned long tdiff; @@ -468,8 +453,8 @@ int hsr_get_node_data(struct hsr_priv *hsr, ether_addr_copy(addr_b, node->MacAddressB); - tdiff = jiffies - node->time_in[HSR_DEV_SLAVE_A]; - if (node->time_in_stale[HSR_DEV_SLAVE_A]) + tdiff = jiffies - node->time_in[HSR_PT_SLAVE_A]; + if (node->time_in_stale[HSR_PT_SLAVE_A]) *if1_age = INT_MAX; #if HZ <= MSEC_PER_SEC else if (tdiff > msecs_to_jiffies(INT_MAX)) @@ -478,8 +463,8 @@ int hsr_get_node_data(struct hsr_priv *hsr, else *if1_age = jiffies_to_msecs(tdiff); - tdiff = jiffies - node->time_in[HSR_DEV_SLAVE_B]; - if (node->time_in_stale[HSR_DEV_SLAVE_B]) + tdiff = jiffies - node->time_in[HSR_PT_SLAVE_B]; + if (node->time_in_stale[HSR_PT_SLAVE_B]) *if2_age = INT_MAX; #if HZ <= MSEC_PER_SEC else if (tdiff > msecs_to_jiffies(INT_MAX)) @@ -489,14 +474,15 @@ int hsr_get_node_data(struct hsr_priv *hsr, *if2_age = jiffies_to_msecs(tdiff); /* Present sequence numbers as if they were incoming on interface */ - *if1_seq = node->seq_out[HSR_DEV_SLAVE_B]; - *if2_seq = node->seq_out[HSR_DEV_SLAVE_A]; + *if1_seq = node->seq_out[HSR_PT_SLAVE_B]; + *if2_seq = node->seq_out[HSR_PT_SLAVE_A]; - slave = hsr->slave[node->AddrB_if]; - if ((node->AddrB_if != HSR_DEV_NONE) && slave) - *addr_b_ifindex = slave->ifindex; - else + if (node->AddrB_port != HSR_PT_NONE) { + port = hsr_port_get_hsr(hsr, node->AddrB_port); + *addr_b_ifindex = port->dev->ifindex; + } else { *addr_b_ifindex = -1; + } rcu_read_unlock(); diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h index ccb09cf4ec5b..c87f36fc154c 100644 --- a/net/hsr/hsr_framereg.h +++ b/net/hsr/hsr_framereg.h @@ -18,18 +18,16 @@ struct hsr_node; struct hsr_node *hsr_find_node(struct list_head *node_db, struct sk_buff *skb); -struct hsr_node *hsr_merge_node(struct hsr_priv *hsr, - struct hsr_node *node, - struct sk_buff *skb, - enum hsr_dev_idx dev_idx); +struct hsr_node *hsr_merge_node(struct hsr_node *node, struct sk_buff *skb, + struct hsr_port *port); void hsr_addr_subst_source(struct hsr_priv *hsr, struct sk_buff *skb); void hsr_addr_subst_dest(struct hsr_priv *hsr, struct ethhdr *ethhdr, - enum hsr_dev_idx dev_idx); + struct hsr_port *port); -void hsr_register_frame_in(struct hsr_node *node, enum hsr_dev_idx dev_idx); +void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port); -int hsr_register_frame_out(struct hsr_node *node, enum hsr_dev_idx dev_idx, +int hsr_register_frame_out(struct hsr_node *node, struct hsr_port *port, struct sk_buff *skb); void hsr_prune_nodes(unsigned long data); diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c index b5abe26f7b4c..a06cab57ab68 100644 --- a/net/hsr/hsr_main.c +++ b/net/hsr/hsr_main.c @@ -39,76 +39,25 @@ void unregister_hsr_master(struct hsr_priv *hsr) } } -bool is_hsr_slave(struct net_device *dev) -{ - struct hsr_priv *hsr_it; - - list_for_each_entry_rcu(hsr_it, &hsr_list, hsr_list) { - if (dev == hsr_it->slave[0]) - return true; - if (dev == hsr_it->slave[1]) - return true; - } - - return false; -} - -/* If dev is a HSR slave device, return the virtual master device. Return NULL - * otherwise. - */ -struct hsr_priv *get_hsr_master(struct net_device *dev) -{ - struct hsr_priv *hsr; - - rcu_read_lock(); - list_for_each_entry_rcu(hsr, &hsr_list, hsr_list) - if ((dev == hsr->slave[0]) || - (dev == hsr->slave[1])) { - rcu_read_unlock(); - return hsr; - } - - rcu_read_unlock(); - return NULL; -} - -/* If dev is a HSR slave device, return the other slave device. Return NULL - * otherwise. - */ -struct net_device *get_other_slave(struct hsr_priv *hsr, - struct net_device *dev) -{ - if (dev == hsr->slave[0]) - return hsr->slave[1]; - if (dev == hsr->slave[1]) - return hsr->slave[0]; - - return NULL; -} - static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, void *ptr) { - struct net_device *slave, *other_slave; + struct net_device *dev; + struct hsr_port *port, *master; struct hsr_priv *hsr; int mtu_max; int res; - struct net_device *dev; dev = netdev_notifier_info_to_dev(ptr); - - hsr = get_hsr_master(dev); - if (hsr) { - /* dev is a slave device */ - slave = dev; - other_slave = get_other_slave(hsr, slave); - } else { + port = hsr_port_get_rtnl(dev); + if (port == NULL) { if (!is_hsr_master(dev)) - return NOTIFY_DONE; + return NOTIFY_DONE; /* Not an HSR device */ hsr = netdev_priv(dev); - slave = hsr->slave[0]; - other_slave = hsr->slave[1]; + port = hsr_port_get_hsr(hsr, HSR_PT_MASTER); + } else { + hsr = port->hsr; } switch (event) { @@ -118,48 +67,41 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, hsr_check_carrier_and_operstate(hsr); break; case NETDEV_CHANGEADDR: - - /* This should not happen since there's no ndo_set_mac_address() - * for HSR devices - i.e. not supported. - */ - if (dev == hsr->dev) + if (port->type == HSR_PT_MASTER) { + /* This should not happen since there's no + * ndo_set_mac_address() for HSR devices - i.e. not + * supported. + */ break; + } - if (dev == hsr->slave[0]) { - ether_addr_copy(hsr->dev->dev_addr, dev->dev_addr); - call_netdevice_notifiers(NETDEV_CHANGEADDR, hsr->dev); + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); + + if (port->type == HSR_PT_SLAVE_A) { + ether_addr_copy(master->dev->dev_addr, dev->dev_addr); + call_netdevice_notifiers(NETDEV_CHANGEADDR, master->dev); } /* Make sure we recognize frames from ourselves in hsr_rcv() */ - other_slave = hsr->slave[1]; + port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); res = hsr_create_self_node(&hsr->self_node_db, - hsr->dev->dev_addr, - other_slave ? - other_slave->dev_addr : - hsr->dev->dev_addr); + master->dev->dev_addr, + port ? + port->dev->dev_addr : + master->dev->dev_addr); if (res) - netdev_warn(hsr->dev, + netdev_warn(master->dev, "Could not update HSR node address.\n"); break; case NETDEV_CHANGEMTU: - if (dev == hsr->dev) + if (port->type == HSR_PT_MASTER) break; /* Handled in ndo_change_mtu() */ - mtu_max = hsr_get_max_mtu(hsr); - if (hsr->dev->mtu > mtu_max) - dev_set_mtu(hsr->dev, mtu_max); + mtu_max = hsr_get_max_mtu(port->hsr); + master = hsr_port_get_hsr(port->hsr, HSR_PT_MASTER); + master->dev->mtu = mtu_max; break; case NETDEV_UNREGISTER: - if (dev == hsr->slave[0]) { - hsr->slave[0] = NULL; - hsr_del_slave(hsr, 0); - } - if (dev == hsr->slave[1]) { - hsr->slave[1] = NULL; - hsr_del_slave(hsr, 1); - } - - /* There should really be a way to set a new slave device... */ - + hsr_del_port(port); break; case NETDEV_PRE_TYPE_CHANGE: /* HSR works only on Ethernet devices. Refuse slave to change @@ -172,6 +114,16 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, } +struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt) +{ + struct hsr_port *port; + + hsr_for_each_port(hsr, port) + if (port->type == pt) + return port; + return NULL; +} + static struct notifier_block hsr_nb = { .notifier_call = hsr_netdev_notify, /* Slave event notifications */ }; diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h index 43689a6d731f..e31c3069fdf8 100644 --- a/net/hsr/hsr_main.h +++ b/net/hsr/hsr_main.h @@ -136,20 +136,26 @@ struct hsr_ethhdr_sp { } __packed; -enum hsr_dev_idx { - HSR_DEV_NONE = -1, - HSR_DEV_SLAVE_A = 0, - HSR_DEV_SLAVE_B, - HSR_DEV_MASTER, +enum hsr_port_type { + HSR_PT_NONE = 0, /* Must be 0, used by framereg */ + HSR_PT_SLAVE_A, + HSR_PT_SLAVE_B, + HSR_PT_INTERLINK, + HSR_PT_MASTER, + HSR_PT_PORTS, /* This must be the last item in the enum */ +}; + +struct hsr_port { + struct list_head port_list; + struct net_device *dev; + struct hsr_priv *hsr; + enum hsr_port_type type; }; -#define HSR_MAX_SLAVE (HSR_DEV_SLAVE_B + 1) -#define HSR_MAX_DEV (HSR_DEV_MASTER + 1) struct hsr_priv { struct list_head hsr_list; /* List of hsr devices */ struct rcu_head rcu_head; - struct net_device *dev; - struct net_device *slave[HSR_MAX_SLAVE]; + struct list_head ports; struct list_head node_db; /* Other HSR nodes */ struct list_head self_node_db; /* MACs of slaves */ struct timer_list announce_timer; /* Supervision frame dispatch */ @@ -160,11 +166,6 @@ struct hsr_priv { unsigned char sup_multicast_addr[ETH_ALEN]; }; -void register_hsr_master(struct hsr_priv *hsr); -void unregister_hsr_master(struct hsr_priv *hsr); -bool is_hsr_slave(struct net_device *dev); -struct hsr_priv *get_hsr_master(struct net_device *dev); -struct net_device *get_other_slave(struct hsr_priv *hsr, - struct net_device *dev); +struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt); #endif /* __HSR_PRIVATE_H */ diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index a2ce359774f3..67082453928c 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c @@ -64,7 +64,7 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev, static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) { struct hsr_priv *hsr; - struct net_device *slave; + struct hsr_port *port; int res; hsr = netdev_priv(dev); @@ -72,17 +72,17 @@ static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) res = 0; rcu_read_lock(); - slave = hsr->slave[0]; - if (slave) - res = nla_put_u32(skb, IFLA_HSR_SLAVE1, slave->ifindex); + port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); + if (port) + res = nla_put_u32(skb, IFLA_HSR_SLAVE1, port->dev->ifindex); rcu_read_unlock(); if (res) goto nla_put_failure; rcu_read_lock(); - slave = hsr->slave[1]; - if (slave) - res = nla_put_u32(skb, IFLA_HSR_SLAVE2, slave->ifindex); + port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); + if (port) + res = nla_put_u32(skb, IFLA_HSR_SLAVE2, port->dev->ifindex); rcu_read_unlock(); if (res) goto nla_put_failure; @@ -141,13 +141,12 @@ static const struct genl_multicast_group hsr_mcgrps[] = { * (i.e. a link has failed somewhere). */ void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN], - enum hsr_dev_idx dev_idx) + struct hsr_port *port) { struct sk_buff *skb; - struct net_device *slave; void *msg_head; + struct hsr_port *master; int res; - int ifindex; skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); if (!skb) @@ -161,15 +160,7 @@ void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN], if (res < 0) goto nla_put_failure; - rcu_read_lock(); - slave = hsr->slave[dev_idx]; - if (slave) - ifindex = slave->ifindex; - else - ifindex = -1; - rcu_read_unlock(); - - res = nla_put_u32(skb, HSR_A_IFINDEX, ifindex); + res = nla_put_u32(skb, HSR_A_IFINDEX, port->dev->ifindex); if (res < 0) goto nla_put_failure; @@ -182,7 +173,10 @@ nla_put_failure: kfree_skb(skb); fail: - netdev_warn(hsr->dev, "Could not send HSR ring error message\n"); + rcu_read_lock(); + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); + netdev_warn(master->dev, "Could not send HSR ring error message\n"); + rcu_read_unlock(); } /* This is called when we haven't heard from the node with MAC address addr for @@ -192,6 +186,7 @@ void hsr_nl_nodedown(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN]) { struct sk_buff *skb; void *msg_head; + struct hsr_port *master; int res; skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); @@ -216,7 +211,10 @@ nla_put_failure: kfree_skb(skb); fail: - netdev_warn(hsr->dev, "Could not send HSR node down\n"); + rcu_read_lock(); + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); + netdev_warn(master->dev, "Could not send HSR node down\n"); + rcu_read_unlock(); } @@ -232,12 +230,13 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) { /* For receiving */ struct nlattr *na; - struct net_device *hsr_dev, *slave; + struct net_device *hsr_dev; /* For sending */ struct sk_buff *skb_out; void *msg_head; struct hsr_priv *hsr; + struct hsr_port *port; unsigned char hsr_node_addr_b[ETH_ALEN]; int hsr_node_if1_age; u16 hsr_node_if1_seq; @@ -319,9 +318,10 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) if (res < 0) goto nla_put_failure; rcu_read_lock(); - slave = hsr->slave[0]; - if (slave) - res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX, slave->ifindex); + port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); + if (port) + res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX, + port->dev->ifindex); rcu_read_unlock(); if (res < 0) goto nla_put_failure; @@ -333,9 +333,10 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) if (res < 0) goto nla_put_failure; rcu_read_lock(); - slave = hsr->slave[1]; - if (slave) - res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX, slave->ifindex); + port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); + if (port) + res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX, + port->dev->ifindex); rcu_read_unlock(); if (res < 0) goto nla_put_failure; diff --git a/net/hsr/hsr_netlink.h b/net/hsr/hsr_netlink.h index 3047f9cea5f5..3f6b95b5b6b8 100644 --- a/net/hsr/hsr_netlink.h +++ b/net/hsr/hsr_netlink.h @@ -17,12 +17,13 @@ #include struct hsr_priv; +struct hsr_port; int __init hsr_netlink_init(void); void __exit hsr_netlink_exit(void); void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN], - int dev_idx); + struct hsr_port *port); void hsr_nl_nodedown(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN]); void hsr_nl_framedrop(int dropcount, int dev_idx); void hsr_nl_linkdown(int dev_idx); diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index d676090f7900..fffd69297c3e 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c @@ -17,7 +17,7 @@ #include "hsr_framereg.h" -static int check_slave_ok(struct net_device *dev) +static int hsr_check_dev_ok(struct net_device *dev) { /* Don't allow HSR on non-ethernet like devices */ if ((dev->flags & IFF_LOOPBACK) || (dev->type != ARPHRD_ETHER) || @@ -32,7 +32,7 @@ static int check_slave_ok(struct net_device *dev) return -EINVAL; } - if (is_hsr_slave(dev)) { + if (hsr_port_exists(dev)) { netdev_info(dev, "This device is already a HSR slave.\n"); return -EINVAL; } @@ -116,38 +116,29 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) { struct sk_buff *skb = *pskb; - struct net_device *dev = skb->dev; + struct hsr_port *port, *other_port, *master; struct hsr_priv *hsr; - struct net_device *other_slave; struct hsr_node *node; bool deliver_to_self; struct sk_buff *skb_deliver; - enum hsr_dev_idx dev_in_idx, dev_other_idx; bool dup_out; int ret; if (eth_hdr(skb)->h_proto != htons(ETH_P_PRP)) return RX_HANDLER_PASS; - hsr = get_hsr_master(dev); - if (!hsr) { - WARN_ON_ONCE(1); - return RX_HANDLER_PASS; - } + rcu_read_lock(); /* ports & node */ - if (dev == hsr->slave[0]) { - dev_in_idx = HSR_DEV_SLAVE_A; - dev_other_idx = HSR_DEV_SLAVE_B; - } else { - dev_in_idx = HSR_DEV_SLAVE_B; - dev_other_idx = HSR_DEV_SLAVE_A; - } + port = hsr_port_get_rcu(skb->dev); + hsr = port->hsr; + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); node = hsr_find_node(&hsr->self_node_db, skb); if (node) { /* Always kill frames sent by ourselves */ kfree_skb(skb); - return RX_HANDLER_CONSUMED; + ret = RX_HANDLER_CONSUMED; + goto finish; } /* Is this frame a candidate for local reception? */ @@ -156,23 +147,22 @@ rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) (skb->pkt_type == PACKET_MULTICAST) || (skb->pkt_type == PACKET_BROADCAST)) deliver_to_self = true; - else if (ether_addr_equal(eth_hdr(skb)->h_dest, hsr->dev->dev_addr)) { + else if (ether_addr_equal(eth_hdr(skb)->h_dest, + master->dev->dev_addr)) { skb->pkt_type = PACKET_HOST; deliver_to_self = true; } - - rcu_read_lock(); /* node_db */ node = hsr_find_node(&hsr->node_db, skb); if (is_supervision_frame(hsr, skb)) { skb_pull(skb, sizeof(struct hsr_sup_tag)); - node = hsr_merge_node(hsr, node, skb, dev_in_idx); + node = hsr_merge_node(node, skb, port); if (!node) { - rcu_read_unlock(); /* node_db */ kfree_skb(skb); - hsr->dev->stats.rx_dropped++; - return RX_HANDLER_CONSUMED; + master->dev->stats.rx_dropped++; + ret = RX_HANDLER_CONSUMED; + goto finish; } skb_push(skb, sizeof(struct hsr_sup_tag)); deliver_to_self = false; @@ -182,46 +172,51 @@ rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) /* Source node unknown; this might be a HSR frame from * another net (different multicast address). Ignore it. */ - rcu_read_unlock(); /* node_db */ kfree_skb(skb); - return RX_HANDLER_CONSUMED; + ret = RX_HANDLER_CONSUMED; + goto finish; } + if (port->type == HSR_PT_SLAVE_A) + other_port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); + else + other_port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); + /* Register ALL incoming frames as outgoing through the other interface. * This allows us to register frames as incoming only if they are valid * for the receiving interface, without using a specific counter for * incoming frames. */ - dup_out = hsr_register_frame_out(node, dev_other_idx, skb); + if (other_port) + dup_out = hsr_register_frame_out(node, other_port, skb); + else + dup_out = 0; if (!dup_out) - hsr_register_frame_in(node, dev_in_idx); + hsr_register_frame_in(node, port); /* Forward this frame? */ - if (!dup_out && (skb->pkt_type != PACKET_HOST)) - other_slave = get_other_slave(hsr, dev); - else - other_slave = NULL; + if (dup_out || (skb->pkt_type == PACKET_HOST)) + other_port = NULL; - if (hsr_register_frame_out(node, HSR_DEV_MASTER, skb)) + if (hsr_register_frame_out(node, master, skb)) deliver_to_self = false; - rcu_read_unlock(); /* node_db */ - - if (!deliver_to_self && !other_slave) { + if (!deliver_to_self && !other_port) { kfree_skb(skb); /* Circulated frame; silently remove it. */ - return RX_HANDLER_CONSUMED; + ret = RX_HANDLER_CONSUMED; + goto finish; } skb_deliver = skb; - if (deliver_to_self && other_slave) { + if (deliver_to_self && other_port) { /* skb_clone() is not enough since we will strip the hsr tag * and do address substitution below */ skb_deliver = pskb_copy(skb, GFP_ATOMIC); if (!skb_deliver) { deliver_to_self = false; - hsr->dev->stats.rx_dropped++; + master->dev->stats.rx_dropped++; } } @@ -230,7 +225,7 @@ rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) skb_deliver = hsr_pull_tag(skb_deliver); if (!skb_deliver) { - hsr->dev->stats.rx_dropped++; + master->dev->stats.rx_dropped++; goto forward; } #if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) @@ -253,82 +248,130 @@ rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) skb_deliver->data -= HSR_HLEN; skb_deliver->tail -= HSR_HLEN; #endif - skb_deliver->dev = hsr->dev; + skb_deliver->dev = master->dev; hsr_addr_subst_source(hsr, skb_deliver); multicast_frame = (skb_deliver->pkt_type == PACKET_MULTICAST); ret = netif_rx(skb_deliver); if (ret == NET_RX_DROP) { - hsr->dev->stats.rx_dropped++; + master->dev->stats.rx_dropped++; } else { - hsr->dev->stats.rx_packets++; - hsr->dev->stats.rx_bytes += skb->len; + master->dev->stats.rx_packets++; + master->dev->stats.rx_bytes += skb->len; if (multicast_frame) - hsr->dev->stats.multicast++; + master->dev->stats.multicast++; } } forward: - if (other_slave) { + if (other_port) { skb_push(skb, ETH_HLEN); - skb->dev = other_slave; + skb->dev = other_port->dev; dev_queue_xmit(skb); } - return RX_HANDLER_CONSUMED; + ret = RX_HANDLER_CONSUMED; + +finish: + rcu_read_unlock(); + return ret; } -int hsr_add_slave(struct hsr_priv *hsr, struct net_device *dev, int idx) +/* Setup device to be added to the HSR bridge. */ +static int hsr_portdev_setup(struct net_device *dev, struct hsr_port *port) { int res; dev_hold(dev); - - res = check_slave_ok(dev); - if (res) - goto fail; - res = dev_set_promiscuity(dev, 1); if (res) - goto fail; - - res = netdev_rx_handler_register(dev, hsr_handle_frame, hsr); + goto fail_promiscuity; + res = netdev_rx_handler_register(dev, hsr_handle_frame, port); if (res) goto fail_rx_handler; + dev_disable_lro(dev); - - hsr->slave[idx] = dev; - - /* Set required header length */ - if (dev->hard_header_len + HSR_HLEN > hsr->dev->hard_header_len) - hsr->dev->hard_header_len = dev->hard_header_len + HSR_HLEN; - - dev_set_mtu(hsr->dev, hsr_get_max_mtu(hsr)); + /* FIXME: + * What does net device "adjacency" mean? Should we do + * res = netdev_master_upper_dev_link(port->dev, port->hsr->dev); ? + */ return 0; fail_rx_handler: dev_set_promiscuity(dev, -1); - -fail: +fail_promiscuity: dev_put(dev); + return res; } -void hsr_del_slave(struct hsr_priv *hsr, int idx) +int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev, + enum hsr_port_type type) { - struct net_device *slave; + struct hsr_port *port, *master; + int res; - slave = hsr->slave[idx]; - hsr->slave[idx] = NULL; + if (type != HSR_PT_MASTER) { + res = hsr_check_dev_ok(dev); + if (res) + return res; + } + + port = hsr_port_get_hsr(hsr, type); + if (port != NULL) + return -EBUSY; /* This port already exists */ + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (port == NULL) + return -ENOMEM; + + if (type != HSR_PT_MASTER) { + res = hsr_portdev_setup(dev, port); + if (res) + goto fail_dev_setup; + } + + port->hsr = hsr; + port->dev = dev; + port->type = type; + + list_add_tail_rcu(&port->port_list, &hsr->ports); + synchronize_rcu(); + + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); + + /* Set required header length */ + if (dev->hard_header_len + HSR_HLEN > master->dev->hard_header_len) + master->dev->hard_header_len = dev->hard_header_len + HSR_HLEN; - netdev_update_features(hsr->dev); - dev_set_mtu(hsr->dev, hsr_get_max_mtu(hsr)); + dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); - if (slave) { - netdev_rx_handler_unregister(slave); - dev_set_promiscuity(slave, -1); + return 0; + +fail_dev_setup: + kfree(port); + return res; +} + +void hsr_del_port(struct hsr_port *port) +{ + struct hsr_priv *hsr; + struct hsr_port *master; + + hsr = port->hsr; + master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); + list_del_rcu(&port->port_list); + + if (port != master) { + dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); + netdev_rx_handler_unregister(port->dev); + dev_set_promiscuity(port->dev, -1); } + /* FIXME? + * netdev_upper_dev_unlink(port->dev, port->hsr->dev); + */ + synchronize_rcu(); - dev_put(slave); + dev_put(port->dev); } diff --git a/net/hsr/hsr_slave.h b/net/hsr/hsr_slave.h index 03c15fda39a8..3055022eddb3 100644 --- a/net/hsr/hsr_slave.h +++ b/net/hsr/hsr_slave.h @@ -14,10 +14,35 @@ #include #include +#include #include "hsr_main.h" -int hsr_add_slave(struct hsr_priv *hsr, struct net_device *dev, int idx); -void hsr_del_slave(struct hsr_priv *hsr, int idx); +int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev, + enum hsr_port_type pt); +void hsr_del_port(struct hsr_port *port); rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb); + +#define hsr_for_each_port(hsr, port) \ + list_for_each_entry_rcu((port), &(hsr)->ports, port_list) + + +static inline bool hsr_port_exists(const struct net_device *dev) +{ + return dev->rx_handler == hsr_handle_frame; +} + +static inline struct hsr_port *hsr_port_get_rtnl(const struct net_device *dev) +{ + ASSERT_RTNL(); + return hsr_port_exists(dev) ? + rtnl_dereference(dev->rx_handler_data) : NULL; +} + +static inline struct hsr_port *hsr_port_get_rcu(const struct net_device *dev) +{ + return hsr_port_exists(dev) ? + rcu_dereference(dev->rx_handler_data) : NULL; +} + #endif /* __HSR_SLAVE_H */ -- cgit v1.2.3 From 1cc1eb52734bfd2fc57c7b3337a11198e713580d Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Fri, 4 Jul 2014 23:38:57 +0200 Subject: net/hsr: Implemented .ndo_fix_features (better device features handling). Signed-off-by: Arvid Brodin Signed-off-by: David S. Miller --- net/hsr/hsr_device.c | 55 ++++++++++++++++++++++++++++++++++++++++++++-------- net/hsr/hsr_slave.c | 2 ++ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 1fc4ea20752e..c489aed98df4 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -198,6 +198,39 @@ static int hsr_dev_close(struct net_device *dev) } +static netdev_features_t hsr_features_recompute(struct hsr_priv *hsr, + netdev_features_t features) +{ + netdev_features_t mask; + struct hsr_port *port; + + mask = features; + + /* Mask out all features that, if supported by one device, should be + * enabled for all devices (see NETIF_F_ONE_FOR_ALL). + * + * Anything that's off in mask will not be enabled - so only things + * that were in features originally, and also is in NETIF_F_ONE_FOR_ALL, + * may become enabled. + */ + features &= ~NETIF_F_ONE_FOR_ALL; + hsr_for_each_port(hsr, port) + features = netdev_increment_features(features, + port->dev->features, + mask); + + return features; +} + +static netdev_features_t hsr_fix_features(struct net_device *dev, + netdev_features_t features) +{ + struct hsr_priv *hsr = netdev_priv(dev); + + return hsr_features_recompute(hsr, features); +} + + static void hsr_fill_tag(struct hsr_ethhdr *hsr_ethhdr, struct hsr_priv *hsr) { unsigned long irqflags; @@ -465,6 +498,7 @@ static const struct net_device_ops hsr_device_ops = { .ndo_open = hsr_dev_open, .ndo_stop = hsr_dev_close, .ndo_start_xmit = hsr_dev_xmit, + .ndo_fix_features = hsr_fix_features, }; @@ -478,6 +512,19 @@ void hsr_dev_setup(struct net_device *dev) dev->tx_queue_len = 0; dev->destructor = hsr_dev_destroy; + + dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | + NETIF_F_GSO_MASK | NETIF_F_HW_CSUM | + NETIF_F_HW_VLAN_CTAG_TX; + + dev->features = dev->hw_features; + + /* Prevent recursive tx locking */ + dev->features |= NETIF_F_LLTX; + /* VLAN on top of HSR needs testing and probably some work on + * hsr_header_create() etc. + */ + dev->features |= NETIF_F_VLAN_CHALLENGED; } @@ -513,14 +560,6 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], if (res < 0) return res; - hsr_dev->features = slave[0]->features & slave[1]->features; - /* Prevent recursive tx locking */ - hsr_dev->features |= NETIF_F_LLTX; - /* VLAN on top of HSR needs testing and probably some work on - * hsr_header_create() etc. - */ - hsr_dev->features |= NETIF_F_VLAN_CHALLENGED; - spin_lock_init(&hsr->seqnr_lock); /* Overflow soon to find bugs easier: */ hsr->sequence_nr = USHRT_MAX - 1024; diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index fffd69297c3e..23817d0b765b 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c @@ -344,6 +344,7 @@ int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev, if (dev->hard_header_len + HSR_HLEN > master->dev->hard_header_len) master->dev->hard_header_len = dev->hard_header_len + HSR_HLEN; + netdev_update_features(master->dev); dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); return 0; @@ -363,6 +364,7 @@ void hsr_del_port(struct hsr_port *port) list_del_rcu(&port->port_list); if (port != master) { + netdev_update_features(master->dev); dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); netdev_rx_handler_unregister(port->dev); dev_set_promiscuity(port->dev, -1); -- cgit v1.2.3 From 4c3477dca2fde1e3ab748387d736d40afe0df21d Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Fri, 4 Jul 2014 23:39:42 +0200 Subject: net/hsr: Added SET_NETDEV_DEVTYPE and features |= NETIF_F_NETNS_LOCAL to dev_setup. Signed-off-by: Arvid Brodin Signed-off-by: David S. Miller --- net/hsr/hsr_device.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index c489aed98df4..c2ae54924a0f 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -501,15 +501,19 @@ static const struct net_device_ops hsr_device_ops = { .ndo_fix_features = hsr_fix_features, }; +static struct device_type hsr_type = { + .name = "hsr", +}; void hsr_dev_setup(struct net_device *dev) { random_ether_addr(dev->dev_addr); ether_setup(dev); - dev->header_ops = &hsr_header_ops; - dev->netdev_ops = &hsr_device_ops; - dev->tx_queue_len = 0; + dev->header_ops = &hsr_header_ops; + dev->netdev_ops = &hsr_device_ops; + SET_NETDEV_DEVTYPE(dev, &hsr_type); + dev->tx_queue_len = 0; dev->destructor = hsr_dev_destroy; @@ -525,6 +529,10 @@ void hsr_dev_setup(struct net_device *dev) * hsr_header_create() etc. */ dev->features |= NETIF_F_VLAN_CHALLENGED; + /* Not sure about this. Taken from bridge code. netdev_features.h says + * it means "Does not change network namespaces". + */ + dev->features |= NETIF_F_NETNS_LOCAL; } -- cgit v1.2.3 From f266a683a4804dc499efc6c2206ef68efed029d0 Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Fri, 4 Jul 2014 23:41:03 +0200 Subject: net/hsr: Better frame dispatch This patch removes the separate paths for frames coming from the outside, and frames sent from the HSR device, and instead makes all frames go through hsr_forward_skb() in hsr_forward.c. This greatly improves code readability and also opens up the possibility for future support of the HSR Interlink device that is the basis for HSR RedBoxes and HSR QuadBoxes, as well as VLAN compatibility. Other improvements: * A reduction in the number of times an skb is copied on machines without HAVE_EFFICIENT_UNALIGNED_ACCESS, which improves throughput somewhat. * Headers are now created using the standard eth_header(), and using the standard hard_header_len. * Each HSR slave now gets its own private skb, so slave-specific fields can be correctly set. Signed-off-by: Arvid Brodin Signed-off-by: David S. Miller --- net/hsr/Makefile | 4 +- net/hsr/hsr_device.c | 170 ++++------------------- net/hsr/hsr_forward.c | 368 +++++++++++++++++++++++++++++++++++++++++++++++++ net/hsr/hsr_forward.h | 20 +++ net/hsr/hsr_framereg.c | 318 +++++++++++++++++++++--------------------- net/hsr/hsr_framereg.h | 25 ++-- net/hsr/hsr_main.c | 20 --- net/hsr/hsr_main.h | 16 ++- net/hsr/hsr_netlink.c | 2 +- net/hsr/hsr_slave.c | 287 +++++++------------------------------- net/hsr/hsr_slave.h | 12 +- 11 files changed, 656 insertions(+), 586 deletions(-) create mode 100644 net/hsr/hsr_forward.c create mode 100644 net/hsr/hsr_forward.h diff --git a/net/hsr/Makefile b/net/hsr/Makefile index b533b243a48b..9ae972a820f4 100644 --- a/net/hsr/Makefile +++ b/net/hsr/Makefile @@ -4,5 +4,5 @@ obj-$(CONFIG_HSR) += hsr.o -hsr-y := hsr_main.o hsr_framereg.o hsr_device.o hsr_netlink.o \ - hsr_slave.o +hsr-y := hsr_main.o hsr_framereg.o hsr_device.o \ + hsr_netlink.o hsr_slave.o hsr_forward.o diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index c2ae54924a0f..a138d75751df 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -21,6 +21,7 @@ #include "hsr_slave.h" #include "hsr_framereg.h" #include "hsr_main.h" +#include "hsr_forward.h" static bool is_admin_up(struct net_device *dev) @@ -231,141 +232,21 @@ static netdev_features_t hsr_fix_features(struct net_device *dev, } -static void hsr_fill_tag(struct hsr_ethhdr *hsr_ethhdr, struct hsr_priv *hsr) -{ - unsigned long irqflags; - - /* IEC 62439-1:2010, p 48, says the 4-bit "path" field can take values - * between 0001-1001 ("ring identifier", for regular HSR frames), - * or 1111 ("HSR management", supervision frames). Unfortunately, the - * spec writers forgot to explain what a "ring identifier" is, or - * how it is used. So we just set this to 0001 for regular frames, - * and 1111 for supervision frames. - */ - set_hsr_tag_path(&hsr_ethhdr->hsr_tag, 0x1); - - /* IEC 62439-1:2010, p 12: "The link service data unit in an Ethernet - * frame is the content of the frame located between the Length/Type - * field and the Frame Check Sequence." - * - * IEC 62439-3, p 48, specifies the "original LPDU" to include the - * original "LT" field (what "LT" means is not explained anywhere as - * far as I can see - perhaps "Length/Type"?). So LSDU_size might - * equal original length + 2. - * Also, the fact that this field is not used anywhere (might be used - * by a RedBox connecting HSR and PRP nets?) means I cannot test its - * correctness. Instead of guessing, I set this to 0 here, to make any - * problems immediately apparent. Anyone using this driver with PRP/HSR - * RedBoxes might need to fix this... - */ - set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, 0); - - spin_lock_irqsave(&hsr->seqnr_lock, irqflags); - hsr_ethhdr->hsr_tag.sequence_nr = htons(hsr->sequence_nr); - hsr->sequence_nr++; - spin_unlock_irqrestore(&hsr->seqnr_lock, irqflags); - - hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto; - - hsr_ethhdr->ethhdr.h_proto = htons(ETH_P_PRP); -} - -static int slave_xmit(struct hsr_priv *hsr, struct sk_buff *skb, - enum hsr_port_type type) -{ - struct hsr_port *port; - struct hsr_ethhdr *hsr_ethhdr; - - hsr_ethhdr = (struct hsr_ethhdr *) skb->data; - - rcu_read_lock(); - port = hsr_port_get_hsr(hsr, type); - if (!port) { - rcu_read_unlock(); - return NET_XMIT_DROP; - } - skb->dev = port->dev; - - hsr_addr_subst_dest(port->hsr, &hsr_ethhdr->ethhdr, port); - rcu_read_unlock(); - - /* Address substitution (IEC62439-3 pp 26, 50): replace mac - * address of outgoing frame with that of the outgoing slave's. - */ - ether_addr_copy(hsr_ethhdr->ethhdr.h_source, skb->dev->dev_addr); - - return dev_queue_xmit(skb); -} - static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev) { - struct hsr_priv *hsr; + struct hsr_priv *hsr = netdev_priv(dev); struct hsr_port *master; - struct hsr_ethhdr *hsr_ethhdr; - struct sk_buff *skb2; - int res1, res2; - - hsr = netdev_priv(dev); - hsr_ethhdr = (struct hsr_ethhdr *) skb->data; - - if ((skb->protocol != htons(ETH_P_PRP)) || - (hsr_ethhdr->ethhdr.h_proto != htons(ETH_P_PRP))) { - hsr_fill_tag(hsr_ethhdr, hsr); - skb->protocol = htons(ETH_P_PRP); - } - skb2 = pskb_copy(skb, GFP_ATOMIC); - - res1 = slave_xmit(hsr, skb, HSR_PT_SLAVE_A); - if (skb2) - res2 = slave_xmit(hsr, skb2, HSR_PT_SLAVE_B); - else - res2 = NET_XMIT_DROP; - - rcu_read_lock(); master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); - if (likely(res1 == NET_XMIT_SUCCESS || res1 == NET_XMIT_CN || - res2 == NET_XMIT_SUCCESS || res2 == NET_XMIT_CN)) { - master->dev->stats.tx_packets++; - master->dev->stats.tx_bytes += skb->len; - } else { - master->dev->stats.tx_dropped++; - } - rcu_read_unlock(); + skb->dev = master->dev; + hsr_forward_skb(skb, master); return NETDEV_TX_OK; } -static int hsr_header_create(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *daddr, - const void *saddr, unsigned int len) -{ - int res; - - /* Make room for the HSR tag now. We will fill it in later (in - * hsr_dev_xmit) - */ - if (skb_headroom(skb) < HSR_HLEN + ETH_HLEN) - return -ENOBUFS; - skb_push(skb, HSR_HLEN); - - /* To allow VLAN/HSR combos we should probably use - * res = dev_hard_header(skb, dev, type, daddr, saddr, len + HSR_HLEN); - * here instead. It would require other changes too, though - e.g. - * separate headers for each slave etc... - */ - res = eth_header(skb, dev, type, daddr, saddr, len + HSR_HLEN); - if (res <= 0) - return res; - skb_reset_mac_header(skb); - - return res + HSR_HLEN; -} - - static const struct header_ops hsr_header_ops = { - .create = hsr_header_create, + .create = eth_header, .parse = eth_header_parse, }; @@ -382,19 +263,13 @@ static int hsr_pad(int size) return min_size; } -static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type) +static void send_hsr_supervision_frame(struct hsr_port *master, u8 type) { - struct hsr_priv *hsr; - struct hsr_port *master; struct sk_buff *skb; int hlen, tlen; struct hsr_sup_tag *hsr_stag; struct hsr_sup_payload *hsr_sp; unsigned long irqflags; - int res; - - hsr = netdev_priv(hsr_dev); - master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); hlen = LL_RESERVED_SPACE(master->dev); tlen = master->dev->needed_tailroom; @@ -410,33 +285,30 @@ static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type) skb->protocol = htons(ETH_P_PRP); skb->priority = TC_PRIO_CONTROL; - res = dev_hard_header(skb, skb->dev, ETH_P_PRP, - hsr->sup_multicast_addr, - skb->dev->dev_addr, skb->len); - if (res <= 0) + if (dev_hard_header(skb, skb->dev, ETH_P_PRP, + master->hsr->sup_multicast_addr, + skb->dev->dev_addr, skb->len) <= 0) goto out; + skb_reset_mac_header(skb); - skb_pull(skb, sizeof(struct ethhdr)); - hsr_stag = (typeof(hsr_stag)) skb->data; + hsr_stag = (typeof(hsr_stag)) skb_put(skb, sizeof(*hsr_stag)); set_hsr_stag_path(hsr_stag, 0xf); set_hsr_stag_HSR_Ver(hsr_stag, 0); - spin_lock_irqsave(&hsr->seqnr_lock, irqflags); - hsr_stag->sequence_nr = htons(hsr->sequence_nr); - hsr->sequence_nr++; - spin_unlock_irqrestore(&hsr->seqnr_lock, irqflags); + spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags); + hsr_stag->sequence_nr = htons(master->hsr->sequence_nr); + master->hsr->sequence_nr++; + spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags); hsr_stag->HSR_TLV_Type = type; hsr_stag->HSR_TLV_Length = 12; - skb_push(skb, sizeof(struct ethhdr)); - /* Payload: MacAddressA */ hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(*hsr_sp)); ether_addr_copy(hsr_sp->MacAddressA, master->dev->dev_addr); - dev_queue_xmit(skb); + hsr_forward_skb(skb, master); return; out: @@ -453,13 +325,15 @@ static void hsr_announce(unsigned long data) struct hsr_port *master; hsr = (struct hsr_priv *) data; + + rcu_read_lock(); master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); if (hsr->announce_count < 3) { - send_hsr_supervision_frame(master->dev, HSR_TLV_ANNOUNCE); + send_hsr_supervision_frame(master, HSR_TLV_ANNOUNCE); hsr->announce_count++; } else { - send_hsr_supervision_frame(master->dev, HSR_TLV_LIFE_CHECK); + send_hsr_supervision_frame(master, HSR_TLV_LIFE_CHECK); } if (hsr->announce_count < 3) @@ -471,6 +345,8 @@ static void hsr_announce(unsigned long data) if (is_admin_up(master->dev)) add_timer(&hsr->announce_timer); + + rcu_read_unlock(); } @@ -570,7 +446,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], spin_lock_init(&hsr->seqnr_lock); /* Overflow soon to find bugs easier: */ - hsr->sequence_nr = USHRT_MAX - 1024; + hsr->sequence_nr = HSR_SEQNR_START; init_timer(&hsr->announce_timer); hsr->announce_timer.function = hsr_announce; diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c new file mode 100644 index 000000000000..7871ed6d3825 --- /dev/null +++ b/net/hsr/hsr_forward.c @@ -0,0 +1,368 @@ +/* Copyright 2011-2014 Autronica Fire and Security AS + * + * 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. + * + * Author(s): + * 2011-2014 Arvid Brodin, arvid.brodin@alten.se + */ + +#include "hsr_forward.h" +#include +#include +#include +#include +#include "hsr_main.h" +#include "hsr_framereg.h" + + +struct hsr_node; + +struct hsr_frame_info { + struct sk_buff *skb_std; + struct sk_buff *skb_hsr; + struct hsr_port *port_rcv; + struct hsr_node *node_src; + u16 sequence_nr; + bool is_supervision; + bool is_vlan; + bool is_local_dest; + bool is_local_exclusive; +}; + + +/* The uses I can see for these HSR supervision frames are: + * 1) Use the frames that are sent after node initialization ("HSR_TLV.Type = + * 22") to reset any sequence_nr counters belonging to that node. Useful if + * the other node's counter has been reset for some reason. + * -- + * Or not - resetting the counter and bridging the frame would create a + * loop, unfortunately. + * + * 2) Use the LifeCheck frames to detect ring breaks. I.e. if no LifeCheck + * frame is received from a particular node, we know something is wrong. + * We just register these (as with normal frames) and throw them away. + * + * 3) Allow different MAC addresses for the two slave interfaces, using the + * MacAddressA field. + */ +static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) +{ + struct hsr_ethhdr_sp *hdr; + + WARN_ON_ONCE(!skb_mac_header_was_set(skb)); + hdr = (struct hsr_ethhdr_sp *) skb_mac_header(skb); + + if (!ether_addr_equal(hdr->ethhdr.h_dest, + hsr->sup_multicast_addr)) + return false; + + if (get_hsr_stag_path(&hdr->hsr_sup) != 0x0f) + return false; + if ((hdr->hsr_sup.HSR_TLV_Type != HSR_TLV_ANNOUNCE) && + (hdr->hsr_sup.HSR_TLV_Type != HSR_TLV_LIFE_CHECK)) + return false; + if (hdr->hsr_sup.HSR_TLV_Length != 12) + return false; + + return true; +} + + +static struct sk_buff *create_stripped_skb(struct sk_buff *skb_in, + struct hsr_frame_info *frame) +{ + struct sk_buff *skb; + int copylen; + unsigned char *dst, *src; + + skb_pull(skb_in, HSR_HLEN); + skb = __pskb_copy(skb_in, skb_headroom(skb_in) - HSR_HLEN, GFP_ATOMIC); + skb_push(skb_in, HSR_HLEN); + if (skb == NULL) + return NULL; + + skb_reset_mac_header(skb); + + if (skb->ip_summed == CHECKSUM_PARTIAL) + skb->csum_start -= HSR_HLEN; + + copylen = 2*ETH_ALEN; + if (frame->is_vlan) + copylen += VLAN_HLEN; + src = skb_mac_header(skb_in); + dst = skb_mac_header(skb); + memcpy(dst, src, copylen); + + skb->protocol = eth_hdr(skb)->h_proto; + return skb; +} + +static struct sk_buff *frame_get_stripped_skb(struct hsr_frame_info *frame, + struct hsr_port *port) +{ + if (!frame->skb_std) + frame->skb_std = create_stripped_skb(frame->skb_hsr, frame); + return skb_clone(frame->skb_std, GFP_ATOMIC); +} + + +static void hsr_fill_tag(struct sk_buff *skb, struct hsr_frame_info *frame, + struct hsr_port *port) +{ + struct hsr_ethhdr *hsr_ethhdr; + int lane_id; + int lsdu_size; + + if (port->type == HSR_PT_SLAVE_A) + lane_id = 0; + else + lane_id = 1; + + lsdu_size = skb->len - 14; + if (frame->is_vlan) + lsdu_size -= 4; + + hsr_ethhdr = (struct hsr_ethhdr *) skb_mac_header(skb); + + set_hsr_tag_path(&hsr_ethhdr->hsr_tag, lane_id); + set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, lsdu_size); + hsr_ethhdr->hsr_tag.sequence_nr = htons(frame->sequence_nr); + hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto; + hsr_ethhdr->ethhdr.h_proto = htons(ETH_P_PRP); +} + +static struct sk_buff *create_tagged_skb(struct sk_buff *skb_o, + struct hsr_frame_info *frame, + struct hsr_port *port) +{ + int movelen; + unsigned char *dst, *src; + struct sk_buff *skb; + + /* Create the new skb with enough headroom to fit the HSR tag */ + skb = __pskb_copy(skb_o, skb_headroom(skb_o) + HSR_HLEN, GFP_ATOMIC); + if (skb == NULL) + return NULL; + skb_reset_mac_header(skb); + + if (skb->ip_summed == CHECKSUM_PARTIAL) + skb->csum_start += HSR_HLEN; + + movelen = ETH_HLEN; + if (frame->is_vlan) + movelen += VLAN_HLEN; + + src = skb_mac_header(skb); + dst = skb_push(skb, HSR_HLEN); + memmove(dst, src, movelen); + skb_reset_mac_header(skb); + + hsr_fill_tag(skb, frame, port); + + return skb; +} + +/* If the original frame was an HSR tagged frame, just clone it to be sent + * unchanged. Otherwise, create a private frame especially tagged for 'port'. + */ +static struct sk_buff *frame_get_tagged_skb(struct hsr_frame_info *frame, + struct hsr_port *port) +{ + if (frame->skb_hsr) + return skb_clone(frame->skb_hsr, GFP_ATOMIC); + + if ((port->type != HSR_PT_SLAVE_A) && (port->type != HSR_PT_SLAVE_B)) { + WARN_ONCE(1, "HSR: Bug: trying to create a tagged frame for a non-ring port"); + return NULL; + } + + return create_tagged_skb(frame->skb_std, frame, port); +} + + +static void hsr_deliver_master(struct sk_buff *skb, struct net_device *dev, + struct hsr_node *node_src) +{ + bool was_multicast_frame; + int res; + + was_multicast_frame = (skb->pkt_type == PACKET_MULTICAST); + hsr_addr_subst_source(node_src, skb); + skb_pull(skb, ETH_HLEN); + res = netif_rx(skb); + if (res == NET_RX_DROP) { + dev->stats.rx_dropped++; + } else { + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + if (was_multicast_frame) + dev->stats.multicast++; + } +} + +static int hsr_xmit(struct sk_buff *skb, struct hsr_port *port, + struct hsr_frame_info *frame) +{ + if (frame->port_rcv->type == HSR_PT_MASTER) { + hsr_addr_subst_dest(frame->node_src, skb, port); + + /* Address substitution (IEC62439-3 pp 26, 50): replace mac + * address of outgoing frame with that of the outgoing slave's. + */ + ether_addr_copy(eth_hdr(skb)->h_source, port->dev->dev_addr); + } + return dev_queue_xmit(skb); +} + + +/* Forward the frame through all devices except: + * - Back through the receiving device + * - If it's a HSR frame: through a device where it has passed before + * - To the local HSR master only if the frame is directly addressed to it, or + * a non-supervision multicast or broadcast frame. + * + * HSR slave devices should insert a HSR tag into the frame, or forward the + * frame unchanged if it's already tagged. Interlink devices should strip HSR + * tags if they're of the non-HSR type (but only after duplicate discard). The + * master device always strips HSR tags. + */ +static void hsr_forward_do(struct hsr_frame_info *frame) +{ + struct hsr_port *port; + struct sk_buff *skb; + + hsr_for_each_port(frame->port_rcv->hsr, port) { + /* Don't send frame back the way it came */ + if (port == frame->port_rcv) + continue; + + /* Don't deliver locally unless we should */ + if ((port->type == HSR_PT_MASTER) && !frame->is_local_dest) + continue; + + /* Deliver frames directly addressed to us to master only */ + if ((port->type != HSR_PT_MASTER) && frame->is_local_exclusive) + continue; + + /* Don't send frame over port where it has been sent before */ + if (hsr_register_frame_out(port, frame->node_src, + frame->sequence_nr)) + continue; + + if (frame->is_supervision && (port->type == HSR_PT_MASTER)) { + hsr_handle_sup_frame(frame->skb_hsr, + frame->node_src, + frame->port_rcv); + continue; + } + + if (port->type != HSR_PT_MASTER) + skb = frame_get_tagged_skb(frame, port); + else + skb = frame_get_stripped_skb(frame, port); + if (skb == NULL) { + /* FIXME: Record the dropped frame? */ + continue; + } + + skb->dev = port->dev; + if (port->type == HSR_PT_MASTER) + hsr_deliver_master(skb, port->dev, frame->node_src); + else + hsr_xmit(skb, port, frame); + } +} + + +static void check_local_dest(struct hsr_priv *hsr, struct sk_buff *skb, + struct hsr_frame_info *frame) +{ + struct net_device *master_dev; + + master_dev = hsr_port_get_hsr(hsr, HSR_PT_MASTER)->dev; + + if (hsr_addr_is_self(hsr, eth_hdr(skb)->h_dest)) { + frame->is_local_exclusive = true; + skb->pkt_type = PACKET_HOST; + } else { + frame->is_local_exclusive = false; + } + + if ((skb->pkt_type == PACKET_HOST) || + (skb->pkt_type == PACKET_MULTICAST) || + (skb->pkt_type == PACKET_BROADCAST)) { + frame->is_local_dest = true; + } else { + frame->is_local_dest = false; + } +} + + +static int hsr_fill_frame_info(struct hsr_frame_info *frame, + struct sk_buff *skb, struct hsr_port *port) +{ + struct ethhdr *ethhdr; + unsigned long irqflags; + + frame->is_supervision = is_supervision_frame(port->hsr, skb); + frame->node_src = hsr_get_node(&port->hsr->node_db, skb, + frame->is_supervision); + if (frame->node_src == NULL) + return -1; /* Unknown node and !is_supervision, or no mem */ + + ethhdr = (struct ethhdr *) skb_mac_header(skb); + frame->is_vlan = false; + if (ethhdr->h_proto == htons(ETH_P_8021Q)) { + frame->is_vlan = true; + /* FIXME: */ + WARN_ONCE(1, "HSR: VLAN not yet supported"); + } + if (ethhdr->h_proto == htons(ETH_P_PRP)) { + frame->skb_std = NULL; + frame->skb_hsr = skb; + frame->sequence_nr = hsr_get_skb_sequence_nr(skb); + } else { + frame->skb_std = skb; + frame->skb_hsr = NULL; + /* Sequence nr for the master node */ + spin_lock_irqsave(&port->hsr->seqnr_lock, irqflags); + frame->sequence_nr = port->hsr->sequence_nr; + port->hsr->sequence_nr++; + spin_unlock_irqrestore(&port->hsr->seqnr_lock, irqflags); + } + + frame->port_rcv = port; + check_local_dest(port->hsr, skb, frame); + + return 0; +} + +/* Must be called holding rcu read lock (because of the port parameter) */ +void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port) +{ + struct hsr_frame_info frame; + + if (skb_mac_header(skb) != skb->data) { + WARN_ONCE(1, "%s:%d: Malformed frame (port_src %s)\n", + __FILE__, __LINE__, port->dev->name); + goto out_drop; + } + + if (hsr_fill_frame_info(&frame, skb, port) < 0) + goto out_drop; + hsr_register_frame_in(frame.node_src, port, frame.sequence_nr); + hsr_forward_do(&frame); + + if (frame.skb_hsr != NULL) + kfree_skb(frame.skb_hsr); + if (frame.skb_std != NULL) + kfree_skb(frame.skb_std); + return; + +out_drop: + port->dev->stats.tx_dropped++; + kfree_skb(skb); +} diff --git a/net/hsr/hsr_forward.h b/net/hsr/hsr_forward.h new file mode 100644 index 000000000000..5c5bc4b6b75f --- /dev/null +++ b/net/hsr/hsr_forward.h @@ -0,0 +1,20 @@ +/* Copyright 2011-2014 Autronica Fire and Security AS + * + * 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. + * + * Author(s): + * 2011-2014 Arvid Brodin, arvid.brodin@alten.se + */ + +#ifndef __HSR_FORWARD_H +#define __HSR_FORWARD_H + +#include +#include "hsr_main.h" + +void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port); + +#endif /* __HSR_FORWARD_H */ diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index c9b78c52c75b..c709c13842cb 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c @@ -35,58 +35,56 @@ struct hsr_node { struct rcu_head rcu_head; }; -/* TODO: use hash lists for mac addresses (linux/jhash.h)? */ +/* TODO: use hash lists for mac addresses (linux/jhash.h)? */ -/* Search for mac entry. Caller must hold rcu read lock. +/* seq_nr_after(a, b) - return true if a is after (higher in sequence than) b, + * false otherwise. */ -static struct hsr_node *find_node_by_AddrA(struct list_head *node_db, - const unsigned char addr[ETH_ALEN]) +static bool seq_nr_after(u16 a, u16 b) { - struct hsr_node *node; - - list_for_each_entry_rcu(node, node_db, mac_list) { - if (ether_addr_equal(node->MacAddressA, addr)) - return node; - } + /* Remove inconsistency where + * seq_nr_after(a, b) == seq_nr_before(a, b) + */ + if ((int) b - a == 32768) + return false; - return NULL; + return (((s16) (b - a)) < 0); } +#define seq_nr_before(a, b) seq_nr_after((b), (a)) +#define seq_nr_after_or_eq(a, b) (!seq_nr_before((a), (b))) +#define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b))) -/* Search for mac entry. Caller must hold rcu read lock. - */ -static struct hsr_node *find_node_by_AddrB(struct list_head *node_db, - const unsigned char addr[ETH_ALEN]) +bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr) { struct hsr_node *node; - list_for_each_entry_rcu(node, node_db, mac_list) { - if (ether_addr_equal(node->MacAddressB, addr)) - return node; + node = list_first_or_null_rcu(&hsr->self_node_db, struct hsr_node, + mac_list); + if (!node) { + WARN_ONCE(1, "HSR: No self node\n"); + return false; } - return NULL; -} + if (ether_addr_equal(addr, node->MacAddressA)) + return true; + if (ether_addr_equal(addr, node->MacAddressB)) + return true; + return false; +} /* Search for mac entry. Caller must hold rcu read lock. */ -struct hsr_node *hsr_find_node(struct list_head *node_db, struct sk_buff *skb) +static struct hsr_node *find_node_by_AddrA(struct list_head *node_db, + const unsigned char addr[ETH_ALEN]) { struct hsr_node *node; - struct ethhdr *ethhdr; - - if (!skb_mac_header_was_set(skb)) - return NULL; - - ethhdr = (struct ethhdr *) skb_mac_header(skb); list_for_each_entry_rcu(node, node_db, mac_list) { - if (ether_addr_equal(node->MacAddressA, ethhdr->h_source)) - return node; - if (ether_addr_equal(node->MacAddressB, ethhdr->h_source)) + if (ether_addr_equal(node->MacAddressA, addr)) return node; } @@ -127,90 +125,22 @@ int hsr_create_self_node(struct list_head *self_node_db, } -/* Add/merge node to the database of nodes. 'skb' must contain an HSR - * supervision frame. - * - If the supervision header's MacAddressA field is not yet in the database, - * this frame is from an hitherto unknown node - add it to the database. - * - If the sender's MAC address is not the same as its MacAddressA address, - * the node is using PICS_SUBS (address substitution). Record the sender's - * address as the node's MacAddressB. - * - * This function needs to work even if the sender node has changed one of its - * slaves' MAC addresses. In this case, there are four different cases described - * by (Addr-changed, received-from) pairs as follows. Note that changing the - * SlaveA address is equal to changing the node's own address: - * - * - (AddrB, SlaveB): The new AddrB will be recorded by PICS_SUBS code since - * node == NULL. - * - (AddrB, SlaveA): Will work as usual (the AddrB change won't be detected - * from this frame). - * - * - (AddrA, SlaveB): The old node will be found. We need to detect this and - * remove the node. - * - (AddrA, SlaveA): A new node will be registered (non-PICS_SUBS at first). - * The old one will be pruned after HSR_NODE_FORGET_TIME. - * - * We also need to detect if the sender's SlaveA and SlaveB cables have been - * swapped. +/* Allocate an hsr_node and add it to node_db. 'addr' is the node's AddressA; + * seq_out is used to initialize filtering of outgoing duplicate frames + * originating from the newly added node. */ -struct hsr_node *hsr_merge_node(struct hsr_node *node, struct sk_buff *skb, - struct hsr_port *port) +struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[], + u16 seq_out) { - struct hsr_priv *hsr; - struct hsr_sup_payload *hsr_sp; - struct hsr_ethhdr_sp *hsr_ethsup; - int i; + struct hsr_node *node; unsigned long now; - - hsr_ethsup = (struct hsr_ethhdr_sp *) skb_mac_header(skb); - hsr_sp = (struct hsr_sup_payload *) skb->data; - hsr = port->hsr; - - if (node && !ether_addr_equal(node->MacAddressA, hsr_sp->MacAddressA)) { - /* Node has changed its AddrA, frame was received from SlaveB */ - list_del_rcu(&node->mac_list); - kfree_rcu(node, rcu_head); - node = NULL; - } - - if (node && (port->type == node->AddrB_port) && - !ether_addr_equal(node->MacAddressB, hsr_ethsup->ethhdr.h_source)) { - /* Cables have been swapped */ - list_del_rcu(&node->mac_list); - kfree_rcu(node, rcu_head); - node = NULL; - } - - if (node && (port->type != node->AddrB_port) && - (node->AddrB_port != HSR_PT_NONE) && - !ether_addr_equal(node->MacAddressA, hsr_ethsup->ethhdr.h_source)) { - /* Cables have been swapped */ - list_del_rcu(&node->mac_list); - kfree_rcu(node, rcu_head); - node = NULL; - } - - if (node) - return node; - - node = find_node_by_AddrA(&hsr->node_db, hsr_sp->MacAddressA); - if (node) { - /* Node is known, but frame was received from an unknown - * address. Node is PICS_SUBS capable; merge its AddrB. - */ - ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source); - node->AddrB_port = port->type; - return node; - } + int i; node = kzalloc(sizeof(*node), GFP_ATOMIC); if (!node) return NULL; - ether_addr_copy(node->MacAddressA, hsr_sp->MacAddressA); - ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source); - if (!ether_addr_equal(hsr_sp->MacAddressA, hsr_ethsup->ethhdr.h_source)) - node->AddrB_port = port->type; + ether_addr_copy(node->MacAddressA, addr); /* We are only interested in time diffs here, so use current jiffies * as initialization. (0 could trigger an spurious ring error warning). @@ -219,41 +149,120 @@ struct hsr_node *hsr_merge_node(struct hsr_node *node, struct sk_buff *skb, for (i = 0; i < HSR_PT_PORTS; i++) node->time_in[i] = now; for (i = 0; i < HSR_PT_PORTS; i++) - node->seq_out[i] = ntohs(hsr_ethsup->hsr_sup.sequence_nr) - 1; + node->seq_out[i] = seq_out; - list_add_tail_rcu(&node->mac_list, &hsr->node_db); + list_add_tail_rcu(&node->mac_list, node_db); return node; } +/* Get the hsr_node from which 'skb' was sent. + */ +struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb, + bool is_sup) +{ + struct hsr_node *node; + struct ethhdr *ethhdr; + u16 seq_out; + + if (!skb_mac_header_was_set(skb)) + return NULL; + + ethhdr = (struct ethhdr *) skb_mac_header(skb); + + list_for_each_entry_rcu(node, node_db, mac_list) { + if (ether_addr_equal(node->MacAddressA, ethhdr->h_source)) + return node; + if (ether_addr_equal(node->MacAddressB, ethhdr->h_source)) + return node; + } + + if (!is_sup) + return NULL; /* Only supervision frame may create node entry */ + + if (ethhdr->h_proto == htons(ETH_P_PRP)) { + /* Use the existing sequence_nr from the tag as starting point + * for filtering duplicate frames. + */ + seq_out = hsr_get_skb_sequence_nr(skb) - 1; + } else { + WARN_ONCE(1, "%s: Non-HSR frame\n", __func__); + seq_out = 0; + } + + return hsr_add_node(node_db, ethhdr->h_source, seq_out); +} + +/* Use the Supervision frame's info about an eventual MacAddressB for merging + * nodes that has previously had their MacAddressB registered as a separate + * node. + */ +void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr, + struct hsr_port *port_rcv) +{ + struct hsr_node *node_real; + struct hsr_sup_payload *hsr_sp; + struct list_head *node_db; + int i; + + skb_pull(skb, sizeof(struct hsr_ethhdr_sp)); + hsr_sp = (struct hsr_sup_payload *) skb->data; + + if (ether_addr_equal(eth_hdr(skb)->h_source, hsr_sp->MacAddressA)) + /* Not sent from MacAddressB of a PICS_SUBS capable node */ + goto done; + + /* Merge node_curr (registered on MacAddressB) into node_real */ + node_db = &port_rcv->hsr->node_db; + node_real = find_node_by_AddrA(node_db, hsr_sp->MacAddressA); + if (!node_real) + /* No frame received from AddrA of this node yet */ + node_real = hsr_add_node(node_db, hsr_sp->MacAddressA, + HSR_SEQNR_START - 1); + if (!node_real) + goto done; /* No mem */ + if (node_real == node_curr) + /* Node has already been merged */ + goto done; + + ether_addr_copy(node_real->MacAddressB, eth_hdr(skb)->h_source); + for (i = 0; i < HSR_PT_PORTS; i++) { + if (!node_curr->time_in_stale[i] && + time_after(node_curr->time_in[i], node_real->time_in[i])) { + node_real->time_in[i] = node_curr->time_in[i]; + node_real->time_in_stale[i] = node_curr->time_in_stale[i]; + } + if (seq_nr_after(node_curr->seq_out[i], node_real->seq_out[i])) + node_real->seq_out[i] = node_curr->seq_out[i]; + } + node_real->AddrB_port = port_rcv->type; + + list_del_rcu(&node_curr->mac_list); + kfree_rcu(node_curr, rcu_head); + +done: + skb_push(skb, sizeof(struct hsr_ethhdr_sp)); +} + /* 'skb' is a frame meant for this host, that is to be passed to upper layers. * - * If the frame was sent by a node's B interface, replace the sender + * If the frame was sent by a node's B interface, replace the source * address with that node's "official" address (MacAddressA) so that upper * layers recognize where it came from. */ -void hsr_addr_subst_source(struct hsr_priv *hsr, struct sk_buff *skb) +void hsr_addr_subst_source(struct hsr_node *node, struct sk_buff *skb) { - struct ethhdr *ethhdr; - struct hsr_node *node; - if (!skb_mac_header_was_set(skb)) { WARN_ONCE(1, "%s: Mac header not set\n", __func__); return; } - ethhdr = (struct ethhdr *) skb_mac_header(skb); - rcu_read_lock(); - node = find_node_by_AddrB(&hsr->node_db, ethhdr->h_source); - if (node) - ether_addr_copy(ethhdr->h_source, node->MacAddressA); - rcu_read_unlock(); + memcpy(ð_hdr(skb)->h_source, node->MacAddressA, ETH_ALEN); } - /* 'skb' is a frame meant for another host. - * 'hsr_dev_idx' is the HSR index of the outgoing device + * 'port' is the outgoing interface * * Substitute the target (dest) MAC address if necessary, so the it matches the * recipient interface MAC address, regardless of whether that is the @@ -261,44 +270,49 @@ void hsr_addr_subst_source(struct hsr_priv *hsr, struct sk_buff *skb) * This is needed to keep the packets flowing through switches that learn on * which "side" the different interfaces are. */ -void hsr_addr_subst_dest(struct hsr_priv *hsr, struct ethhdr *ethhdr, +void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb, struct hsr_port *port) { - struct hsr_node *node; + struct hsr_node *node_dst; - rcu_read_lock(); - node = find_node_by_AddrA(&hsr->node_db, ethhdr->h_dest); - if (node && (node->AddrB_port == port->type)) - ether_addr_copy(ethhdr->h_dest, node->MacAddressB); - rcu_read_unlock(); -} + if (!skb_mac_header_was_set(skb)) { + WARN_ONCE(1, "%s: Mac header not set\n", __func__); + return; + } + if (!is_unicast_ether_addr(eth_hdr(skb)->h_dest)) + return; -/* seq_nr_after(a, b) - return true if a is after (higher in sequence than) b, - * false otherwise. - */ -static bool seq_nr_after(u16 a, u16 b) -{ - /* Remove inconsistency where - * seq_nr_after(a, b) == seq_nr_before(a, b) - */ - if ((int) b - a == 32768) - return false; + node_dst = find_node_by_AddrA(&port->hsr->node_db, eth_hdr(skb)->h_dest); + if (!node_dst) { + WARN_ONCE(1, "%s: Unknown node\n", __func__); + return; + } + if (port->type != node_dst->AddrB_port) + return; + if (!node_dst->MacAddressB) { + WARN_ONCE(1, "%s: No MacAddressB\n", __func__); + return; + } - return (((s16) (b - a)) < 0); + ether_addr_copy(eth_hdr(skb)->h_dest, node_dst->MacAddressB); } -#define seq_nr_before(a, b) seq_nr_after((b), (a)) -#define seq_nr_after_or_eq(a, b) (!seq_nr_before((a), (b))) -#define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b))) -void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port) +void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port, + u16 sequence_nr) { + /* Don't register incoming frames without a valid sequence number. This + * ensures entries of restarted nodes gets pruned so that they can + * re-register and resume communications. + */ + if (seq_nr_before(sequence_nr, node->seq_out[port->type])) + return; + node->time_in[port->type] = jiffies; node->time_in_stale[port->type] = false; } - /* 'skb' is a HSR Ethernet frame (with a HSR tag inserted), with a valid * ethhdr->h_source address and skb->mac_header set. * @@ -307,19 +321,9 @@ void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port) * 0 otherwise, or * negative error code on error */ -int hsr_register_frame_out(struct hsr_node *node, struct hsr_port *port, - struct sk_buff *skb) +int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node, + u16 sequence_nr) { - struct hsr_ethhdr *hsr_ethhdr; - u16 sequence_nr; - - if (!skb_mac_header_was_set(skb)) { - WARN_ONCE(1, "%s: Mac header not set\n", __func__); - return -EINVAL; - } - hsr_ethhdr = (struct hsr_ethhdr *) skb_mac_header(skb); - - sequence_nr = ntohs(hsr_ethhdr->hsr_tag.sequence_nr); if (seq_nr_before_or_eq(sequence_nr, node->seq_out[port->type])) return 1; diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h index c87f36fc154c..438b40f98f5a 100644 --- a/net/hsr/hsr_framereg.h +++ b/net/hsr/hsr_framereg.h @@ -16,19 +16,22 @@ struct hsr_node; -struct hsr_node *hsr_find_node(struct list_head *node_db, struct sk_buff *skb); - -struct hsr_node *hsr_merge_node(struct hsr_node *node, struct sk_buff *skb, - struct hsr_port *port); - -void hsr_addr_subst_source(struct hsr_priv *hsr, struct sk_buff *skb); -void hsr_addr_subst_dest(struct hsr_priv *hsr, struct ethhdr *ethhdr, +struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[], + u16 seq_out); +struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb, + bool is_sup); +void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr, + struct hsr_port *port); +bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr); + +void hsr_addr_subst_source(struct hsr_node *node, struct sk_buff *skb); +void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb, struct hsr_port *port); -void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port); - -int hsr_register_frame_out(struct hsr_node *node, struct hsr_port *port, - struct sk_buff *skb); +void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port, + u16 sequence_nr); +int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node, + u16 sequence_nr); void hsr_prune_nodes(unsigned long data); diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c index a06cab57ab68..779d28b65417 100644 --- a/net/hsr/hsr_main.c +++ b/net/hsr/hsr_main.c @@ -20,26 +20,6 @@ #include "hsr_slave.h" -/* List of all registered virtual HSR devices */ -static LIST_HEAD(hsr_list); - -void register_hsr_master(struct hsr_priv *hsr) -{ - list_add_tail_rcu(&hsr->hsr_list, &hsr_list); -} - -void unregister_hsr_master(struct hsr_priv *hsr) -{ - struct hsr_priv *hsr_it; - - list_for_each_entry(hsr_it, &hsr_list, hsr_list) - if (hsr_it == hsr) { - list_del_rcu(&hsr_it->hsr_list); - return; - } -} - - static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event, void *ptr) { diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h index e31c3069fdf8..5a9c69962ded 100644 --- a/net/hsr/hsr_main.h +++ b/net/hsr/hsr_main.h @@ -29,6 +29,7 @@ * each node differ before we notify of communication problem? */ #define MAX_SLAVE_DIFF 3000 /* ms */ +#define HSR_SEQNR_START (USHRT_MAX - 1024) /* How often shall we check for broken ring and remove node entries older than @@ -153,10 +154,9 @@ struct hsr_port { }; struct hsr_priv { - struct list_head hsr_list; /* List of hsr devices */ struct rcu_head rcu_head; struct list_head ports; - struct list_head node_db; /* Other HSR nodes */ + struct list_head node_db; /* Known HSR nodes */ struct list_head self_node_db; /* MACs of slaves */ struct timer_list announce_timer; /* Supervision frame dispatch */ struct timer_list prune_timer; @@ -166,6 +166,18 @@ struct hsr_priv { unsigned char sup_multicast_addr[ETH_ALEN]; }; +#define hsr_for_each_port(hsr, port) \ + list_for_each_entry_rcu((port), &(hsr)->ports, port_list) + struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt); +/* Caller must ensure skb is a valid HSR frame */ +static inline u16 hsr_get_skb_sequence_nr(struct sk_buff *skb) +{ + struct hsr_ethhdr *hsr_ethhdr; + + hsr_ethhdr = (struct hsr_ethhdr *) skb_mac_header(skb); + return ntohs(hsr_ethhdr->hsr_tag.sequence_nr); +} + #endif /* __HSR_PRIVATE_H */ diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index 67082453928c..fbdf53f1d874 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c @@ -358,7 +358,7 @@ fail: return res; } -/* Get a list of MacAddressA of all nodes known to this node (other than self). +/* Get a list of MacAddressA of all nodes known to this node (including self). */ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) { diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index 23817d0b765b..a348dcbcd683 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c @@ -14,9 +14,51 @@ #include #include "hsr_main.h" #include "hsr_device.h" +#include "hsr_forward.h" #include "hsr_framereg.h" +static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct hsr_port *port; + + if (!skb_mac_header_was_set(skb)) { + WARN_ONCE(1, "%s: skb invalid", __func__); + return RX_HANDLER_PASS; + } + + rcu_read_lock(); /* hsr->node_db, hsr->ports */ + port = hsr_port_get_rcu(skb->dev); + + if (hsr_addr_is_self(port->hsr, eth_hdr(skb)->h_source)) { + /* Directly kill frames sent by ourselves */ + kfree_skb(skb); + goto finish_consume; + } + + if (eth_hdr(skb)->h_proto != htons(ETH_P_PRP)) + goto finish_pass; + + skb_push(skb, ETH_HLEN); + + hsr_forward_skb(skb, port); + +finish_consume: + rcu_read_unlock(); /* hsr->node_db, hsr->ports */ + return RX_HANDLER_CONSUMED; + +finish_pass: + rcu_read_unlock(); /* hsr->node_db, hsr->ports */ + return RX_HANDLER_PASS; +} + +bool hsr_port_exists(const struct net_device *dev) +{ + return rcu_access_pointer(dev->rx_handler) == hsr_handle_frame; +} + + static int hsr_check_dev_ok(struct net_device *dev) { /* Don't allow HSR on non-ethernet like devices */ @@ -42,6 +84,11 @@ static int hsr_check_dev_ok(struct net_device *dev) return -EINVAL; } + if (dev->priv_flags & IFF_DONT_BRIDGE) { + netdev_info(dev, "This device does not support bridging.\n"); + return -EOPNOTSUPP; + } + /* HSR over bonded devices has not been tested, but I'm not sure it * won't work... */ @@ -50,232 +97,6 @@ static int hsr_check_dev_ok(struct net_device *dev) } -static struct sk_buff *hsr_pull_tag(struct sk_buff *skb) -{ - struct hsr_tag *hsr_tag; - struct sk_buff *skb2; - - skb2 = skb_share_check(skb, GFP_ATOMIC); - if (unlikely(!skb2)) - goto err_free; - skb = skb2; - - if (unlikely(!pskb_may_pull(skb, HSR_HLEN))) - goto err_free; - - hsr_tag = (struct hsr_tag *) skb->data; - skb->protocol = hsr_tag->encap_proto; - skb_pull(skb, HSR_HLEN); - - return skb; - -err_free: - kfree_skb(skb); - return NULL; -} - - -/* The uses I can see for these HSR supervision frames are: - * 1) Use the frames that are sent after node initialization ("HSR_TLV.Type = - * 22") to reset any sequence_nr counters belonging to that node. Useful if - * the other node's counter has been reset for some reason. - * -- - * Or not - resetting the counter and bridging the frame would create a - * loop, unfortunately. - * - * 2) Use the LifeCheck frames to detect ring breaks. I.e. if no LifeCheck - * frame is received from a particular node, we know something is wrong. - * We just register these (as with normal frames) and throw them away. - * - * 3) Allow different MAC addresses for the two slave interfaces, using the - * MacAddressA field. - */ -static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) -{ - struct hsr_sup_tag *hsr_stag; - - if (!ether_addr_equal(eth_hdr(skb)->h_dest, - hsr->sup_multicast_addr)) - return false; - - hsr_stag = (struct hsr_sup_tag *) skb->data; - if (get_hsr_stag_path(hsr_stag) != 0x0f) - return false; - if ((hsr_stag->HSR_TLV_Type != HSR_TLV_ANNOUNCE) && - (hsr_stag->HSR_TLV_Type != HSR_TLV_LIFE_CHECK)) - return false; - if (hsr_stag->HSR_TLV_Length != 12) - return false; - - return true; -} - - -/* Implementation somewhat according to IEC-62439-3, p. 43 - */ -rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb) -{ - struct sk_buff *skb = *pskb; - struct hsr_port *port, *other_port, *master; - struct hsr_priv *hsr; - struct hsr_node *node; - bool deliver_to_self; - struct sk_buff *skb_deliver; - bool dup_out; - int ret; - - if (eth_hdr(skb)->h_proto != htons(ETH_P_PRP)) - return RX_HANDLER_PASS; - - rcu_read_lock(); /* ports & node */ - - port = hsr_port_get_rcu(skb->dev); - hsr = port->hsr; - master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); - - node = hsr_find_node(&hsr->self_node_db, skb); - if (node) { - /* Always kill frames sent by ourselves */ - kfree_skb(skb); - ret = RX_HANDLER_CONSUMED; - goto finish; - } - - /* Is this frame a candidate for local reception? */ - deliver_to_self = false; - if ((skb->pkt_type == PACKET_HOST) || - (skb->pkt_type == PACKET_MULTICAST) || - (skb->pkt_type == PACKET_BROADCAST)) - deliver_to_self = true; - else if (ether_addr_equal(eth_hdr(skb)->h_dest, - master->dev->dev_addr)) { - skb->pkt_type = PACKET_HOST; - deliver_to_self = true; - } - - node = hsr_find_node(&hsr->node_db, skb); - - if (is_supervision_frame(hsr, skb)) { - skb_pull(skb, sizeof(struct hsr_sup_tag)); - node = hsr_merge_node(node, skb, port); - if (!node) { - kfree_skb(skb); - master->dev->stats.rx_dropped++; - ret = RX_HANDLER_CONSUMED; - goto finish; - } - skb_push(skb, sizeof(struct hsr_sup_tag)); - deliver_to_self = false; - } - - if (!node) { - /* Source node unknown; this might be a HSR frame from - * another net (different multicast address). Ignore it. - */ - kfree_skb(skb); - ret = RX_HANDLER_CONSUMED; - goto finish; - } - - if (port->type == HSR_PT_SLAVE_A) - other_port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); - else - other_port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); - - /* Register ALL incoming frames as outgoing through the other interface. - * This allows us to register frames as incoming only if they are valid - * for the receiving interface, without using a specific counter for - * incoming frames. - */ - if (other_port) - dup_out = hsr_register_frame_out(node, other_port, skb); - else - dup_out = 0; - if (!dup_out) - hsr_register_frame_in(node, port); - - /* Forward this frame? */ - if (dup_out || (skb->pkt_type == PACKET_HOST)) - other_port = NULL; - - if (hsr_register_frame_out(node, master, skb)) - deliver_to_self = false; - - if (!deliver_to_self && !other_port) { - kfree_skb(skb); - /* Circulated frame; silently remove it. */ - ret = RX_HANDLER_CONSUMED; - goto finish; - } - - skb_deliver = skb; - if (deliver_to_self && other_port) { - /* skb_clone() is not enough since we will strip the hsr tag - * and do address substitution below - */ - skb_deliver = pskb_copy(skb, GFP_ATOMIC); - if (!skb_deliver) { - deliver_to_self = false; - master->dev->stats.rx_dropped++; - } - } - - if (deliver_to_self) { - bool multicast_frame; - - skb_deliver = hsr_pull_tag(skb_deliver); - if (!skb_deliver) { - master->dev->stats.rx_dropped++; - goto forward; - } -#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - /* Move everything in the header that is after the HSR tag, - * to work around alignment problems caused by the 6-byte HSR - * tag. In practice, this removes/overwrites the HSR tag in - * the header and restores a "standard" packet. - */ - memmove(skb_deliver->data - HSR_HLEN, skb_deliver->data, - skb_headlen(skb_deliver)); - - /* Adjust skb members so they correspond with the move above. - * This cannot possibly underflow skb->data since hsr_pull_tag() - * above succeeded. - * At this point in the protocol stack, the transport and - * network headers have not been set yet, and we haven't touched - * the mac header nor the head. So we only need to adjust data - * and tail: - */ - skb_deliver->data -= HSR_HLEN; - skb_deliver->tail -= HSR_HLEN; -#endif - skb_deliver->dev = master->dev; - hsr_addr_subst_source(hsr, skb_deliver); - multicast_frame = (skb_deliver->pkt_type == PACKET_MULTICAST); - ret = netif_rx(skb_deliver); - if (ret == NET_RX_DROP) { - master->dev->stats.rx_dropped++; - } else { - master->dev->stats.rx_packets++; - master->dev->stats.rx_bytes += skb->len; - if (multicast_frame) - master->dev->stats.multicast++; - } - } - -forward: - if (other_port) { - skb_push(skb, ETH_HLEN); - skb->dev = other_port->dev; - dev_queue_xmit(skb); - } - - ret = RX_HANDLER_CONSUMED; - -finish: - rcu_read_unlock(); - return ret; -} - /* Setup device to be added to the HSR bridge. */ static int hsr_portdev_setup(struct net_device *dev, struct hsr_port *port) { @@ -285,16 +106,17 @@ static int hsr_portdev_setup(struct net_device *dev, struct hsr_port *port) res = dev_set_promiscuity(dev, 1); if (res) goto fail_promiscuity; - res = netdev_rx_handler_register(dev, hsr_handle_frame, port); - if (res) - goto fail_rx_handler; - dev_disable_lro(dev); /* FIXME: * What does net device "adjacency" mean? Should we do * res = netdev_master_upper_dev_link(port->dev, port->hsr->dev); ? */ + res = netdev_rx_handler_register(dev, hsr_handle_frame, port); + if (res) + goto fail_rx_handler; + dev_disable_lro(dev); + return 0; fail_rx_handler: @@ -339,11 +161,6 @@ int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev, synchronize_rcu(); master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); - - /* Set required header length */ - if (dev->hard_header_len + HSR_HLEN > master->dev->hard_header_len) - master->dev->hard_header_len = dev->hard_header_len + HSR_HLEN; - netdev_update_features(master->dev); dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); diff --git a/net/hsr/hsr_slave.h b/net/hsr/hsr_slave.h index 3055022eddb3..3ccfbf71c92e 100644 --- a/net/hsr/hsr_slave.h +++ b/net/hsr/hsr_slave.h @@ -20,17 +20,7 @@ int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev, enum hsr_port_type pt); void hsr_del_port(struct hsr_port *port); -rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb); - - -#define hsr_for_each_port(hsr, port) \ - list_for_each_entry_rcu((port), &(hsr)->ports, port_list) - - -static inline bool hsr_port_exists(const struct net_device *dev) -{ - return dev->rx_handler == hsr_handle_frame; -} +bool hsr_port_exists(const struct net_device *dev); static inline struct hsr_port *hsr_port_get_rtnl(const struct net_device *dev) { -- cgit v1.2.3 From a718dcc5e56546a62d00f57cc875faac2f42c8bf Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Fri, 4 Jul 2014 23:42:00 +0200 Subject: net/hsr: Fix NULL pointer dereference on incomplete hsr_newlink() params. If none of the slave interfaces are specified, struct nlattr *data[] may be NULL. Make sure to check for that. While I'm at it, fix the horrible error messages displayed when only one of the slave interfaces isn't specified. Signed-off-by: Arvid Brodin Signed-off-by: David S. Miller --- net/hsr/hsr_netlink.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index fbdf53f1d874..a2c7e4c0ac1e 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c @@ -37,13 +37,17 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev, struct net_device *link[2]; unsigned char multicast_spec; + if (!data) { + netdev_info(dev, "HSR: No slave devices specified\n"); + return -EINVAL; + } if (!data[IFLA_HSR_SLAVE1]) { - netdev_info(dev, "IFLA_HSR_SLAVE1 missing!\n"); + netdev_info(dev, "HSR: Slave1 device not specified\n"); return -EINVAL; } link[0] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE1])); if (!data[IFLA_HSR_SLAVE2]) { - netdev_info(dev, "IFLA_HSR_SLAVE2 missing!\n"); + netdev_info(dev, "HSR: Slave2 device not specified\n"); return -EINVAL; } link[1] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE2])); -- cgit v1.2.3 From 3d5baba0ecfdd5de35bb7ce41ef9218f2b17b006 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Thu, 3 Jul 2014 05:56:51 +0100 Subject: declance: Fix 64-bit compilation warnings This fixes compiler warnings: drivers/net/ethernet/amd/declance.c: In function 'lance_init_ring': drivers/net/ethernet/amd/declance.c:478: warning: format '%8.8x' expects type 'unsigned int', but argument 3 has type 'long unsigned int' drivers/net/ethernet/amd/declance.c:487: warning: format '%8.8x' expects type 'unsigned int', but argument 3 has type 'long unsigned int' drivers/net/ethernet/amd/declance.c:503: warning: cast from pointer to integer of different size drivers/net/ethernet/amd/declance.c:520: warning: cast from pointer to integer of different size in 64-bit compilation. Where the value printed is an offset (whose range will always fit) the cast uses a 32-bit type, otherwise, where it is a host memory address, the pointer is output directly with %p. Also the remaining `0x' prefix is dropped for consistency across these messages. Tested with both 32-bit and 64-bit compilation, as well as at the run time (with the debug messages affected enabled). Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/declance.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c index 57397295887c..b584b78237df 100644 --- a/drivers/net/ethernet/amd/declance.c +++ b/drivers/net/ethernet/amd/declance.c @@ -475,7 +475,7 @@ static void lance_init_ring(struct net_device *dev) *lib_ptr(ib, rx_ptr, lp->type) = leptr; if (ZERO) printk("RX ptr: %8.8x(%8.8x)\n", - leptr, lib_off(brx_ring, lp->type)); + leptr, (uint)lib_off(brx_ring, lp->type)); /* Setup tx descriptor pointer */ leptr = offsetof(struct lance_init_block, btx_ring); @@ -484,7 +484,7 @@ static void lance_init_ring(struct net_device *dev) *lib_ptr(ib, tx_ptr, lp->type) = leptr; if (ZERO) printk("TX ptr: %8.8x(%8.8x)\n", - leptr, lib_off(btx_ring, lp->type)); + leptr, (uint)lib_off(btx_ring, lp->type)); if (ZERO) printk("TX rings:\n"); @@ -499,8 +499,8 @@ static void lance_init_ring(struct net_device *dev) /* The ones required by tmd2 */ *lib_ptr(ib, btx_ring[i].misc, lp->type) = 0; if (i < 3 && ZERO) - printk("%d: 0x%8.8x(0x%8.8x)\n", - i, leptr, (uint)lp->tx_buf_ptr_cpu[i]); + printk("%d: %8.8x(%p)\n", + i, leptr, lp->tx_buf_ptr_cpu[i]); } /* Setup the Rx ring entries */ @@ -516,8 +516,8 @@ static void lance_init_ring(struct net_device *dev) 0xf000; *lib_ptr(ib, brx_ring[i].mblength, lp->type) = 0; if (i < 3 && ZERO) - printk("%d: 0x%8.8x(0x%8.8x)\n", - i, leptr, (uint)lp->rx_buf_ptr_cpu[i]); + printk("%d: %8.8x(%p)\n", + i, leptr, lp->rx_buf_ptr_cpu[i]); } iob(); } -- cgit v1.2.3 From 9f12fbe603f7ae346b2b46008e325f0c9a68e55d Mon Sep 17 00:00:00 2001 From: Zi Shen Lim Date: Thu, 3 Jul 2014 07:56:54 -0700 Subject: net: filter: move load_pointer() into filter.h load_pointer() is already a static inline function. Let's move it into filter.h so BPF JIT implementations can reuse this function. Since we're exporting this function, let's also rename it to bpf_load_pointer() for clarity. Signed-off-by: Zi Shen Lim Reviewed-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/filter.h | 13 +++++++++++++ net/core/filter.c | 15 +++------------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index a7e3c48d73a7..b885dcb7eaca 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -406,6 +407,18 @@ static inline u16 bpf_anc_helper(const struct sock_filter *ftest) } } +void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, + int k, unsigned int size); + +static inline void *bpf_load_pointer(const struct sk_buff *skb, int k, + unsigned int size, void *buffer) +{ + if (k >= 0) + return skb_header_pointer(skb, k, size, buffer); + + return bpf_internal_load_pointer_neg_helper(skb, k, size); +} + #ifdef CONFIG_BPF_JIT #include #include diff --git a/net/core/filter.c b/net/core/filter.c index 1dbf6462f766..87af1e3e56c0 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -84,15 +84,6 @@ void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, uns return NULL; } -static inline void *load_pointer(const struct sk_buff *skb, int k, - unsigned int size, void *buffer) -{ - if (k >= 0) - return skb_header_pointer(skb, k, size, buffer); - - return bpf_internal_load_pointer_neg_helper(skb, k, size); -} - /** * sk_filter - run a packet through a socket filter * @sk: sock associated with &sk_buff @@ -537,7 +528,7 @@ load_word: * BPF_R0 - 8/16/32-bit skb data converted to cpu endianness */ - ptr = load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &tmp); + ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &tmp); if (likely(ptr != NULL)) { BPF_R0 = get_unaligned_be32(ptr); CONT; @@ -547,7 +538,7 @@ load_word: LD_ABS_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + imm32)) */ off = IMM; load_half: - ptr = load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &tmp); + ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &tmp); if (likely(ptr != NULL)) { BPF_R0 = get_unaligned_be16(ptr); CONT; @@ -557,7 +548,7 @@ load_half: LD_ABS_B: /* BPF_R0 = *(u8 *) (skb->data + imm32) */ off = IMM; load_byte: - ptr = load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &tmp); + ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &tmp); if (likely(ptr != NULL)) { BPF_R0 = *(u8 *)ptr; CONT; -- cgit v1.2.3 From 63ae88949bc7f6b56438d430c55060d9eda981af Mon Sep 17 00:00:00 2001 From: wangweidong Date: Fri, 4 Jul 2014 15:29:48 +0800 Subject: appletalk: fix a coccinella warning in net/appletalk/ddp.c This warning is introduced by commit 7b30600cc6 ("appletalk: fix checkpatch error with indent"), So fix it. Signed-off-by: Wang Weidong Signed-off-by: David S. Miller --- net/appletalk/ddp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 01a1082e02b3..8ceabc073658 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1808,7 +1808,7 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) long amount = 0; if (skb) - amount = skb->len - sizeof(struct ddpehdr); + amount = skb->len - sizeof(struct ddpehdr); rc = put_user(amount, (int __user *)argp); break; } -- cgit v1.2.3 From be1f4f48cef17c6ea9350db04c774dc8eb252158 Mon Sep 17 00:00:00 2001 From: David Laight Date: Fri, 4 Jul 2014 14:35:51 +0000 Subject: net: sctp: Inline the functions from command.c sctp_init_cmd_seq() and sctp_next_cmd() are only called from one place. The call sequence for sctp_add_cmd_sf() is likely to be longer than the inlined code. With sctp_add_cmd_sf() inlined the compiler can optimise repeated calls. Signed-off-by: David Laight Signed-off-by: David S. Miller --- include/net/sctp/command.h | 27 +++++++++++++++--- net/sctp/Makefile | 2 +- net/sctp/command.c | 68 ---------------------------------------------- 3 files changed, 24 insertions(+), 73 deletions(-) delete mode 100644 net/sctp/command.c diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index 4b7cd695e431..0e91a42065db 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -210,19 +210,38 @@ typedef struct { /* Initialize a block of memory as a command sequence. * Return 0 if the initialization fails. */ -int sctp_init_cmd_seq(sctp_cmd_seq_t *seq); +static inline int sctp_init_cmd_seq(sctp_cmd_seq_t *seq) +{ + memset(seq, 0, sizeof(sctp_cmd_seq_t)); + return 1; /* We always succeed. */ +} + /* Add a command to an sctp_cmd_seq_t. * * Use the SCTP_* constructors defined by SCTP_ARG_CONSTRUCTOR() above * to wrap data which goes in the obj argument. */ -void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj); +static inline void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, + sctp_arg_t obj) +{ + BUG_ON(seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS); + + seq->cmds[seq->next_free_slot].verb = verb; + seq->cmds[seq->next_free_slot++].obj = obj; +} /* Return the next command structure in an sctp_cmd_seq. * Return NULL at the end of the sequence. */ -sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq); +static inline sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq) +{ + sctp_cmd_t *retval = NULL; -#endif /* __net_sctp_command_h__ */ + if (seq->next_cmd < seq->next_free_slot) + retval = &seq->cmds[seq->next_cmd++]; + + return retval; +} +#endif /* __net_sctp_command_h__ */ diff --git a/net/sctp/Makefile b/net/sctp/Makefile index 5c30b7a873df..3b4ffb021cf1 100644 --- a/net/sctp/Makefile +++ b/net/sctp/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_NET_SCTPPROBE) += sctp_probe.o sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ protocol.o endpointola.o associola.o \ transport.o chunk.o sm_make_chunk.o ulpevent.o \ - inqueue.o outqueue.o ulpqueue.o command.o \ + inqueue.o outqueue.o ulpqueue.o \ tsnmap.o bind_addr.o socket.o primitive.o \ output.o input.o debug.o ssnmap.o auth.o diff --git a/net/sctp/command.c b/net/sctp/command.c deleted file mode 100644 index dd7375851618..000000000000 --- a/net/sctp/command.c +++ /dev/null @@ -1,68 +0,0 @@ -/* SCTP kernel implementation Copyright (C) 1999-2001 - * Cisco, Motorola, and IBM - * Copyright 2001 La Monte H.P. Yarroll - * - * This file is part of the SCTP kernel implementation - * - * These functions manipulate sctp command sequences. - * - * This SCTP implementation 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, or (at your option) - * any later version. - * - * This SCTP implementation 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 GNU CC; see the file COPYING. If not, see - * . - * - * Please send any bug reports or fixes you make to the - * email address(es): - * lksctp developers - * - * Written or modified by: - * La Monte H.P. Yarroll - * Karl Knutson - */ - -#include -#include -#include - -/* Initialize a block of memory as a command sequence. */ -int sctp_init_cmd_seq(sctp_cmd_seq_t *seq) -{ - memset(seq, 0, sizeof(sctp_cmd_seq_t)); - return 1; /* We always succeed. */ -} - -/* Add a command to a sctp_cmd_seq_t. - * Return 0 if the command sequence is full. - */ -void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) -{ - BUG_ON(seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS); - - seq->cmds[seq->next_free_slot].verb = verb; - seq->cmds[seq->next_free_slot++].obj = obj; -} - -/* Return the next command structure in a sctp_cmd_seq. - * Returns NULL at the end of the sequence. - */ -sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq) -{ - sctp_cmd_t *retval = NULL; - - if (seq->next_cmd < seq->next_free_slot) - retval = &seq->cmds[seq->next_cmd++]; - - return retval; -} - -- cgit v1.2.3 From b9420e1c87838bcb354ae3495852430413dd9e4b Mon Sep 17 00:00:00 2001 From: David Laight Date: Fri, 4 Jul 2014 14:35:51 +0000 Subject: net: sctp: Optimise the way 'sctp_arg_t' values are initialised. Even if memset() is inlined (as on x86) using it to zero the union generates a memory word write of zero, followed by a write of the smaller field, and then a read of the word. As well as being a lot of instructions the sequence is unlikely to be optimised by the store-load forward hardware so will be slow. Instead allocate a field of the union that is the same size as the entire union and write a zero value to it. The compiler will then generate the required value in a register. Zeroing the union shouldn't be necessary, but this patch series isn't intended to have a behavioural change. Signed-off-by: David Laight Signed-off-by: David S. Miller --- include/net/sctp/command.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index 0e91a42065db..589a1918ad55 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -118,6 +118,7 @@ typedef enum { #define SCTP_MAX_NUM_COMMANDS 14 typedef union { + void *zero_all; /* Set to NULL to clear the entire union */ __s32 i32; __u32 u32; __be32 be32; @@ -154,7 +155,7 @@ typedef union { static inline sctp_arg_t \ SCTP_## name (type arg) \ { sctp_arg_t retval;\ - memset(&retval, 0, sizeof(sctp_arg_t));\ + retval.zero_all = NULL;\ retval.elt = arg;\ return retval;\ } @@ -191,7 +192,7 @@ static inline sctp_arg_t SCTP_NOFORCE(void) static inline sctp_arg_t SCTP_NULL(void) { sctp_arg_t retval; - memset(&retval, 0, sizeof(sctp_arg_t)); + retval.zero_all = NULL; return retval; } @@ -212,7 +213,8 @@ typedef struct { */ static inline int sctp_init_cmd_seq(sctp_cmd_seq_t *seq) { - memset(seq, 0, sizeof(sctp_cmd_seq_t)); + seq->next_free_slot = 0; + seq->next_cmd = 0; return 1; /* We always succeed. */ } -- cgit v1.2.3 From d1a3fe26e97c0f17579c39f8a446c50f7cc3154a Mon Sep 17 00:00:00 2001 From: David Laight Date: Fri, 4 Jul 2014 14:35:57 +0000 Subject: net: sctp: Use pointers (not array indexes) to access sctp_cmd_seq_t.cmds[]. Using pointers into sctp_cmd_seq_t.cmds[] lets the compiler generate much better code. Use the last entry first to optimise the overflow check. Signed-off-by: David Laight Signed-off-by: David S. Miller --- include/net/sctp/command.h | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index 589a1918ad55..f22538e68245 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -203,8 +203,8 @@ typedef struct { typedef struct { sctp_cmd_t cmds[SCTP_MAX_NUM_COMMANDS]; - __u8 next_free_slot; - __u8 next_cmd; + sctp_cmd_t *last_used_slot; + sctp_cmd_t *next_cmd; } sctp_cmd_seq_t; @@ -213,8 +213,9 @@ typedef struct { */ static inline int sctp_init_cmd_seq(sctp_cmd_seq_t *seq) { - seq->next_free_slot = 0; - seq->next_cmd = 0; + /* cmds[] is filled backwards to simplify the overflow BUG() check */ + seq->last_used_slot = seq->cmds + SCTP_MAX_NUM_COMMANDS; + seq->next_cmd = seq->last_used_slot; return 1; /* We always succeed. */ } @@ -227,10 +228,13 @@ static inline int sctp_init_cmd_seq(sctp_cmd_seq_t *seq) static inline void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) { - BUG_ON(seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS); + sctp_cmd_t *cmd = seq->last_used_slot - 1; - seq->cmds[seq->next_free_slot].verb = verb; - seq->cmds[seq->next_free_slot++].obj = obj; + BUG_ON(cmd < seq->cmds); + + cmd->verb = verb; + cmd->obj = obj; + seq->last_used_slot = cmd; } /* Return the next command structure in an sctp_cmd_seq. @@ -238,12 +242,10 @@ static inline void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, */ static inline sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq) { - sctp_cmd_t *retval = NULL; - - if (seq->next_cmd < seq->next_free_slot) - retval = &seq->cmds[seq->next_cmd++]; + if (seq->next_cmd <= seq->last_used_slot) + return NULL; - return retval; + return --seq->next_cmd; } #endif /* __net_sctp_command_h__ */ -- cgit v1.2.3 From d68ab591f874cf752101ac77b08c01123b6f3a2e Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 5 Jul 2014 15:14:22 +0100 Subject: defxx: Correct the receive DMA map size Receive DMA maps are oversized, they include EISA legacy 128-byte alignment padding in size calculation whereas this padding is never used for data. Worse yet, if the skb's data area has been realigned indeed, then data beyond the end of the buffer will be synchronised from the receive DMA bounce buffer, possibly corrupting data structures residing in memory beyond the actual end of this data buffer. Therefore switch to using PI_RCV_DATA_K_SIZE_MAX rather than NEW_SKB_SIZE in DMA mapping, the value the former macro expands to is written to the receive ring DMA descriptor of the PDQ DMA chip and determines the maximum amount of data PDQ will ever transfer to the corresponding data buffer, including all headers and padding. Reported-by: Robert Coerver Tested-by: Robert Coerver Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- drivers/net/fddi/defxx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index eb78203cd58e..4dcfb32983d9 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -2936,7 +2936,7 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers) my_skb_align(newskb, 128); bp->descr_block_virt->rcv_data[i + j].long_1 = (u32)dma_map_single(bp->bus_dev, newskb->data, - NEW_SKB_SIZE, + PI_RCV_DATA_K_SIZE_MAX, DMA_FROM_DEVICE); /* * p_rcv_buff_va is only used inside the @@ -3053,14 +3053,14 @@ static void dfx_rcv_queue_process( skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; dma_unmap_single(bp->bus_dev, bp->descr_block_virt->rcv_data[entry].long_1, - NEW_SKB_SIZE, + PI_RCV_DATA_K_SIZE_MAX, DMA_FROM_DEVICE); skb_reserve(skb, RCV_BUFF_K_PADDING); bp->p_rcv_buff_va[entry] = (char *)newskb; bp->descr_block_virt->rcv_data[entry].long_1 = (u32)dma_map_single(bp->bus_dev, newskb->data, - NEW_SKB_SIZE, + PI_RCV_DATA_K_SIZE_MAX, DMA_FROM_DEVICE); } else skb = NULL; -- cgit v1.2.3 From 6329fe5c4e61655bcb8456805d2c485f791b50cc Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 5 Jul 2014 15:14:30 +0100 Subject: defxx: Discard DMA maps on buffer deallocation Prearranged receive DMA bounce buffer mappings are not released in the card reboot/shutdown path. That does not affect frame reception, but probably explains the random segmentation fault I observed the other day on interface shutdown. Card is rebooted as required by the spec in the process of ring fault recovery when a PC Trace signal has been received. This change fixes the problem in an obvious manner. Reported-by: Robert Coerver Tested-by: Robert Coerver Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- drivers/net/fddi/defxx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index 4dcfb32983d9..0b2e80940b95 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -3447,8 +3447,13 @@ static void dfx_rcv_flush( DFX_board_t *bp ) { struct sk_buff *skb; skb = (struct sk_buff *)bp->p_rcv_buff_va[i+j]; - if (skb) + if (skb) { + dma_unmap_single(bp->bus_dev, + bp->descr_block_virt->rcv_data[i+j].long_1, + PI_RCV_DATA_K_SIZE_MAX, + DMA_FROM_DEVICE); dev_kfree_skb(skb); + } bp->p_rcv_buff_va[i+j] = NULL; } -- cgit v1.2.3 From a630be70771ddbe8253f619ac4b9ca4c3277b13b Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 5 Jul 2014 15:14:36 +0100 Subject: defxx: Use netdev_alloc_skb consistently Switch the two remaining places across the driver that use dev_alloc_skb to netdev_alloc_skb. Another place has already been converted to use __netdev_alloc_skb, no idea why these two have been left behind. Reported-by: Robert Coerver Tested-by: Robert Coerver Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- drivers/net/fddi/defxx.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index 0b2e80940b95..4c5a2fe67dfb 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -3045,7 +3045,8 @@ static void dfx_rcv_queue_process( if (pkt_len > SKBUFF_RX_COPYBREAK) { struct sk_buff *newskb; - newskb = dev_alloc_skb(NEW_SKB_SIZE); + newskb = netdev_alloc_skb(bp->dev, + NEW_SKB_SIZE); if (newskb){ rx_in_place = 1; @@ -3066,7 +3067,10 @@ static void dfx_rcv_queue_process( skb = NULL; } else #endif - skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */ + /* Alloc new buffer to pass up, + * add room for PRH. */ + skb = netdev_alloc_skb(bp->dev, + pkt_len + 3); if (skb == NULL) { printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); -- cgit v1.2.3 From b37cccf031bdcaba2f461cdb5a2b93ebbd0af03c Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 5 Jul 2014 15:14:40 +0100 Subject: defxx: Handle DMA mapping errors This adds error handling for DMA mapping requests; I think there isn't much else to say about it. A good side-effect is the mapping in the transmit path is now made with the board lock released. Also if DMA mapping fails for a newly allocated receive buffer, then data from the old buffer will be copied out (as is presently done for small frames only whose size does not exceed SKBUFF_RX_COPYBREAK) and the original buffer returned, with its mapping unchanged, to the DMA descriptor ring. Reported-by: Robert Coerver Tested-by: Robert Coerver Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- drivers/net/fddi/defxx.c | 84 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index 4c5a2fe67dfb..ed23288d1c55 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -2923,21 +2923,35 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers) for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) { - struct sk_buff *newskb = __netdev_alloc_skb(bp->dev, NEW_SKB_SIZE, GFP_NOIO); + struct sk_buff *newskb; + dma_addr_t dma_addr; + + newskb = __netdev_alloc_skb(bp->dev, NEW_SKB_SIZE, + GFP_NOIO); if (!newskb) return -ENOMEM; - bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | - ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); /* * align to 128 bytes for compatibility with * the old EISA boards. */ my_skb_align(newskb, 128); + dma_addr = dma_map_single(bp->bus_dev, + newskb->data, + PI_RCV_DATA_K_SIZE_MAX, + DMA_FROM_DEVICE); + if (dma_mapping_error(bp->bus_dev, dma_addr)) { + dev_kfree_skb(newskb); + return -ENOMEM; + } + bp->descr_block_virt->rcv_data[i + j].long_0 = + (u32)(PI_RCV_DESCR_M_SOP | + ((PI_RCV_DATA_K_SIZE_MAX / + PI_ALIGN_K_RCV_DATA_BUFF) << + PI_RCV_DESCR_V_SEG_LEN)); bp->descr_block_virt->rcv_data[i + j].long_1 = - (u32)dma_map_single(bp->bus_dev, newskb->data, - PI_RCV_DATA_K_SIZE_MAX, - DMA_FROM_DEVICE); + (u32)dma_addr; + /* * p_rcv_buff_va is only used inside the * kernel so we put the skb pointer here. @@ -3004,7 +3018,7 @@ static void dfx_rcv_queue_process( PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ char *p_buff; /* ptr to start of packet receive buffer (FMC descriptor) */ u32 descr, pkt_len; /* FMC descriptor field and packet length */ - struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */ + struct sk_buff *skb = NULL; /* pointer to a sk_buff to hold incoming packet data */ /* Service all consumed LLC receive frames */ @@ -3042,15 +3056,30 @@ static void dfx_rcv_queue_process( bp->rcv_length_errors++; else{ #ifdef DYNAMIC_BUFFERS + struct sk_buff *newskb = NULL; + if (pkt_len > SKBUFF_RX_COPYBREAK) { - struct sk_buff *newskb; + dma_addr_t new_dma_addr; newskb = netdev_alloc_skb(bp->dev, NEW_SKB_SIZE); if (newskb){ + my_skb_align(newskb, 128); + new_dma_addr = dma_map_single( + bp->bus_dev, + newskb->data, + PI_RCV_DATA_K_SIZE_MAX, + DMA_FROM_DEVICE); + if (dma_mapping_error( + bp->bus_dev, + new_dma_addr)) { + dev_kfree_skb(newskb); + newskb = NULL; + } + } + if (newskb) { rx_in_place = 1; - my_skb_align(newskb, 128); skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; dma_unmap_single(bp->bus_dev, bp->descr_block_virt->rcv_data[entry].long_1, @@ -3058,14 +3087,10 @@ static void dfx_rcv_queue_process( DMA_FROM_DEVICE); skb_reserve(skb, RCV_BUFF_K_PADDING); bp->p_rcv_buff_va[entry] = (char *)newskb; - bp->descr_block_virt->rcv_data[entry].long_1 = - (u32)dma_map_single(bp->bus_dev, - newskb->data, - PI_RCV_DATA_K_SIZE_MAX, - DMA_FROM_DEVICE); - } else - skb = NULL; - } else + bp->descr_block_virt->rcv_data[entry].long_1 = (u32)new_dma_addr; + } + } + if (!newskb) #endif /* Alloc new buffer to pass up, * add room for PRH. */ @@ -3185,6 +3210,7 @@ static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, u8 prod; /* local transmit producer index */ PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ + dma_addr_t dma_addr; unsigned long flags; netif_stop_queue(dev); @@ -3232,6 +3258,20 @@ static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, } } + /* Write the three PRH bytes immediately before the FC byte */ + + skb_push(skb, 3); + skb->data[0] = DFX_PRH0_BYTE; /* these byte values are defined */ + skb->data[1] = DFX_PRH1_BYTE; /* in the Motorola FDDI MAC chip */ + skb->data[2] = DFX_PRH2_BYTE; /* specification */ + + dma_addr = dma_map_single(bp->bus_dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(bp->bus_dev, dma_addr)) { + skb_pull(skb, 3); + return NETDEV_TX_BUSY; + } + spin_lock_irqsave(&bp->lock, flags); /* Get the current producer and the next free xmt data descriptor */ @@ -3252,13 +3292,6 @@ static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]); /* also bump producer index */ - /* Write the three PRH bytes immediately before the FC byte */ - - skb_push(skb,3); - skb->data[0] = DFX_PRH0_BYTE; /* these byte values are defined */ - skb->data[1] = DFX_PRH1_BYTE; /* in the Motorola FDDI MAC chip */ - skb->data[2] = DFX_PRH2_BYTE; /* specification */ - /* * Write the descriptor with buffer info and bump producer * @@ -3287,8 +3320,7 @@ static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, */ p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN)); - p_xmt_descr->long_1 = (u32)dma_map_single(bp->bus_dev, skb->data, - skb->len, DMA_TO_DEVICE); + p_xmt_descr->long_1 = (u32)dma_addr; /* * Verify that descriptor is actually available -- cgit v1.2.3 From 8848761f9432160ad63e28b16f5c4516683ef905 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 5 Jul 2014 15:14:46 +0100 Subject: defxx: Add missing DMA synchronisation calls This adds DMA synchronisation calls needed in the receive path: 1. To retrieve the Receive Status word that is prepended by the PDQ DMA engine in the receive buffer, and provides information about the frame received, including its size and any errors. 2. To make data received available for copying in the small-frame case (size <= SKBUFF_RX_COPYBREAK) where the original DMA buffer will be returned to the receive descriptor ring and therefore its mapping retained. With DMA mapping error handling in place, added by the other patch, this may now also trigger where an attempt to map a newly allocated buffer for DMA has failed. In that case data from the original buffer will be copied out and the buffer returned to the DMA descriptor ring. These calls may do nothing when data is in the host DMA addressing range of the FDDI interface, such as always on 32-bit systems, however their absence makes frame reception stop functioning reliably on systems that have memory beyond the low 4GB of the address space. Reported-by: Robert Coerver Tested-by: Robert Coerver Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- drivers/net/fddi/defxx.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index ed23288d1c55..3d1a878a4ab0 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -196,6 +196,7 @@ * 14 Jun 2005 macro Use irqreturn_t. * 23 Oct 2006 macro Big-endian host support. * 14 Dec 2006 macro TURBOchannel support. + * 01 Jul 2014 macro Fixes for DMA on 64-bit hosts. */ /* Include files */ @@ -224,8 +225,8 @@ /* Version information string should be updated prior to each new release! */ #define DRV_NAME "defxx" -#define DRV_VERSION "v1.10" -#define DRV_RELDATE "2006/12/14" +#define DRV_VERSION "v1.11" +#define DRV_RELDATE "2014/07/01" static char version[] = DRV_NAME ": " DRV_VERSION " " DRV_RELDATE @@ -3026,7 +3027,7 @@ static void dfx_rcv_queue_process( while (bp->rcv_xmt_reg.index.rcv_comp != p_type_2_cons->index.rcv_cons) { /* Process any errors */ - + dma_addr_t dma_addr; int entry; entry = bp->rcv_xmt_reg.index.rcv_comp; @@ -3035,6 +3036,11 @@ static void dfx_rcv_queue_process( #else p_buff = bp->p_rcv_buff_va[entry]; #endif + dma_addr = bp->descr_block_virt->rcv_data[entry].long_1; + dma_sync_single_for_cpu(bp->bus_dev, + dma_addr + RCV_BUFF_K_DESCR, + sizeof(u32), + DMA_FROM_DEVICE); memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32)); if (descr & PI_FMC_DESCR_M_RCC_FLUSH) @@ -3082,7 +3088,7 @@ static void dfx_rcv_queue_process( skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; dma_unmap_single(bp->bus_dev, - bp->descr_block_virt->rcv_data[entry].long_1, + dma_addr, PI_RCV_DATA_K_SIZE_MAX, DMA_FROM_DEVICE); skb_reserve(skb, RCV_BUFF_K_PADDING); @@ -3108,6 +3114,12 @@ static void dfx_rcv_queue_process( #endif { /* Receive buffer allocated, pass receive packet up */ + dma_sync_single_for_cpu( + bp->bus_dev, + dma_addr + + RCV_BUFF_K_PADDING, + pkt_len + 3, + DMA_FROM_DEVICE); skb_copy_to_linear_data(skb, p_buff + RCV_BUFF_K_PADDING, -- cgit v1.2.3 From 51ba0ed17514f9f7cf63a4be21092e8f2d8c558e Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 5 Jul 2014 15:28:22 +0100 Subject: defxx: Fix issues with debug printk calls This fixes issues with debug printk calls across the driver, normally disabled; first compilation errors: drivers/net/fddi/defxx.c:676:1: error: pasting "(" and ""In dfx_bus_init...\n"" does not give a valid preprocessing token drivers/net/fddi/defxx.c:820:1: error: pasting "(" and ""In dfx_bus_uninit...\n"" does not give a valid preprocessing token and so on, and then warnings: drivers/net/fddi/defxx.c: In function 'dfx_driver_init': drivers/net/fddi/defxx.c:1132: warning: format '%0X' expects type 'unsigned int', but argument 4 has type 'dma_addr_t' drivers/net/fddi/defxx.c:1132: warning: format '%0X' expects type 'unsigned int', but argument 4 has type 'dma_addr_t' etc. Additionally casts are removed from virtual addresses and %p used. Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- drivers/net/fddi/defxx.c | 21 ++++++++++----------- drivers/net/fddi/defxx.h | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index 3d1a878a4ab0..6ea59ece7e0b 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -1123,17 +1123,16 @@ static int dfx_driver_init(struct net_device *dev, const char *print_name, /* Display virtual and physical addresses if debug driver */ - DBG_printk("%s: Descriptor block virt = %0lX, phys = %0X\n", - print_name, - (long)bp->descr_block_virt, bp->descr_block_phys); - DBG_printk("%s: Command Request buffer virt = %0lX, phys = %0X\n", - print_name, (long)bp->cmd_req_virt, bp->cmd_req_phys); - DBG_printk("%s: Command Response buffer virt = %0lX, phys = %0X\n", - print_name, (long)bp->cmd_rsp_virt, bp->cmd_rsp_phys); - DBG_printk("%s: Receive buffer block virt = %0lX, phys = %0X\n", - print_name, (long)bp->rcv_block_virt, bp->rcv_block_phys); - DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n", - print_name, (long)bp->cons_block_virt, bp->cons_block_phys); + DBG_printk("%s: Descriptor block virt = %p, phys = %pad\n", + print_name, bp->descr_block_virt, &bp->descr_block_phys); + DBG_printk("%s: Command Request buffer virt = %p, phys = %pad\n", + print_name, bp->cmd_req_virt, &bp->cmd_req_phys); + DBG_printk("%s: Command Response buffer virt = %p, phys = %pad\n", + print_name, bp->cmd_rsp_virt, &bp->cmd_rsp_phys); + DBG_printk("%s: Receive buffer block virt = %p, phys = %pad\n", + print_name, bp->rcv_block_virt, &bp->rcv_block_phys); + DBG_printk("%s: Consumer block virt = %p, phys = %pad\n", + print_name, bp->cons_block_virt, &bp->cons_block_phys); return DFX_K_SUCCESS; } diff --git a/drivers/net/fddi/defxx.h b/drivers/net/fddi/defxx.h index 19a6f64df198..adb63f3f7b4a 100644 --- a/drivers/net/fddi/defxx.h +++ b/drivers/net/fddi/defxx.h @@ -1693,7 +1693,7 @@ typedef union /* Only execute special print call when debug driver was built */ #ifdef DEFXX_DEBUG -#define DBG_printk(args...) printk(## args) +#define DBG_printk(args...) printk(args) #else #define DBG_printk(args...) #endif -- cgit v1.2.3 From 70452dcb6d401349fbd6db55dfab112fb44639be Mon Sep 17 00:00:00 2001 From: Erik Hugne Date: Sun, 6 Jul 2014 20:38:50 -0400 Subject: tipc: fix a memleak when sending data This fixes a regression bug caused by: 067608e9d019d6477fd45dd948e81af0e5bf599f ("tipc: introduce direct iovec to buffer chain fragmentation function") If data is sent on a nonblocking socket and the destination link is congested, the buffer chain is leaked. We fix this by freeing the chain in this case. Signed-off-by: Erik Hugne Signed-off-by: Jon Maloy Acked-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/socket.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index ede78b144dcf..8c5600cfcc3e 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -784,8 +784,9 @@ new_mtu: break; rc = tipc_wait_for_sndmsg(sock, &timeo); + if (rc) + kfree_skb_list(buf); } while (!rc); - exit: if (iocb) release_sock(sk); @@ -898,6 +899,8 @@ next: break; } rc = tipc_wait_for_sndpkt(sock, &timeo); + if (rc) + kfree_skb_list(buf); } while (!rc); exit: if (iocb) -- cgit v1.2.3 From f941a6d9a9e0612eb807af822b0d1ac004da8175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Mon, 7 Jul 2014 05:41:16 +0200 Subject: bridge: adding stubs for multicast exports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make users (e.g. batman-adv soon) load- and runnable even if the bridge was compiled without snooping capabilities - or even if the kernel was compiled without any bridge code at all. Signed-off-by: Linus Lüssing Signed-off-by: David S. Miller --- include/linux/if_bridge.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index fd22789d7b2e..e0c575ca89f7 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -36,8 +36,22 @@ extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __use typedef int br_should_route_hook_t(struct sk_buff *skb); extern br_should_route_hook_t __rcu *br_should_route_hook; + +#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING) int br_multicast_list_adjacent(struct net_device *dev, struct list_head *br_ip_list); bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto); +#else +static inline int br_multicast_list_adjacent(struct net_device *dev, + struct list_head *br_ip_list) +{ + return 0; +} +static inline bool br_multicast_has_querier_adjacent(struct net_device *dev, + int proto) +{ + return false; +} +#endif #endif -- cgit v1.2.3 From c34963e21685659eb513e1c4d847f81d8a8f13f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Mon, 7 Jul 2014 05:41:17 +0200 Subject: bridge: export knowledge about the presence of IGMP/MLD queriers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this patch other modules are able to ask the bridge whether an IGMP or MLD querier exists on the according, bridged link layer. Multicast snooping can only be performed if a valid, selected querier exists on a link. Just like the bridge only enables its multicast snooping if a querier exists, e.g. batman-adv too can only activate its multicast snooping in bridged scenarios if a querier is present. For instance this export avoids having to reimplement IGMP/MLD querier message snooping and parsing in e.g. batman-adv, when multicast optimizations for bridged scenarios are added in the future. Signed-off-by: Linus Lüssing Signed-off-by: David S. Miller --- include/linux/if_bridge.h | 6 ++++++ net/bridge/br_multicast.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index e0c575ca89f7..808dcb8cc04f 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -40,6 +40,7 @@ extern br_should_route_hook_t __rcu *br_should_route_hook; #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING) int br_multicast_list_adjacent(struct net_device *dev, struct list_head *br_ip_list); +bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto); bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto); #else static inline int br_multicast_list_adjacent(struct net_device *dev, @@ -47,6 +48,11 @@ static inline int br_multicast_list_adjacent(struct net_device *dev, { return 0; } +static inline bool br_multicast_has_querier_anywhere(struct net_device *dev, + int proto) +{ + return false; +} static inline bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto) { diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index abfa0b65a111..b4845f4b2bb4 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -2215,6 +2215,43 @@ unlock: } EXPORT_SYMBOL_GPL(br_multicast_list_adjacent); +/** + * br_multicast_has_querier_anywhere - Checks for a querier on a bridge + * @dev: The bridge port providing the bridge on which to check for a querier + * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> ETH_P_IPV6 + * + * Checks whether the given interface has a bridge on top and if so returns + * true if a valid querier exists anywhere on the bridged link layer. + * Otherwise returns false. + */ +bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto) +{ + struct net_bridge *br; + struct net_bridge_port *port; + struct ethhdr eth; + bool ret = false; + + rcu_read_lock(); + if (!br_port_exists(dev)) + goto unlock; + + port = br_port_get_rcu(dev); + if (!port || !port->br) + goto unlock; + + br = port->br; + + memset(ð, 0, sizeof(eth)); + eth.h_proto = htons(proto); + + ret = br_multicast_querier_exists(br, ð); + +unlock: + rcu_read_unlock(); + return ret; +} +EXPORT_SYMBOL_GPL(br_multicast_has_querier_anywhere); + /** * br_multicast_has_querier_adjacent - Checks for a querier behind a bridge port * @dev: The bridge port adjacent to which to check for a querier -- cgit v1.2.3 From 523ece889eeee84a381e16086b81e07a76cff8b6 Mon Sep 17 00:00:00 2001 From: Eugenia Emantayev Date: Tue, 8 Jul 2014 11:25:19 +0300 Subject: net/mlx4_en: Fix set port ratelimit for 40GE In 40GE we can't use the default bw units for set ratelimit (100 Mbps) since the max is 255*100 Mbps = 25 Gbps (not suited for 40GE), thus we need 1 Gbps units. But for 10GE 1 Gbps units might be too bruit so we use the following solution. For user set ratelimit <= 25 Gbps: use 100 Mbps units * user_ratelimit (* 10). For user set ratelimit > 25 Gbps: use 1 Gbps units * user_ratelimit. For user set unlimited ratelimit (0 Gbps): use 1 Gbps units * MAX_RATELIMIT_DEFAULT (57) Note: any value > 58 will damage the FW ratelimit computation, so we allow a max and any higher value will be pulled down to 57. Signed-off-by: Sagi Grimberg Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 5 ----- drivers/net/ethernet/mellanox/mlx4/port.c | 22 +++++++++++++++++----- include/linux/mlx4/device.h | 11 +++++++++++ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 1d8af7336807..13fbcd03c3e4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -62,11 +62,6 @@ #define INIT_HCA_TPT_MW_ENABLE (1 << 7) -#define MLX4_NUM_UP 8 -#define MLX4_NUM_TC 8 -#define MLX4_RATELIMIT_UNITS 3 /* 100 Mbps */ -#define MLX4_RATELIMIT_DEFAULT 0xffff - struct mlx4_set_port_prio2tc_context { u8 prio2tc[4]; }; diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 7ab97174886d..5d76a60ac053 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -1051,14 +1051,26 @@ int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, for (i = 0; i < MLX4_NUM_TC; i++) { struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i]; - u16 r = ratelimit && ratelimit[i] ? ratelimit[i] : - MLX4_RATELIMIT_DEFAULT; + u16 r; + + if (ratelimit && ratelimit[i]) { + if (ratelimit[i] <= MLX4_MAX_100M_UNITS_VAL) { + r = ratelimit[i]; + tc->max_bw_units = + htons(MLX4_RATELIMIT_100M_UNITS); + } else { + r = ratelimit[i]/10; + tc->max_bw_units = + htons(MLX4_RATELIMIT_1G_UNITS); + } + tc->max_bw_value = htons(r); + } else { + tc->max_bw_value = htons(MLX4_RATELIMIT_DEFAULT); + tc->max_bw_units = htons(MLX4_RATELIMIT_1G_UNITS); + } tc->pg = htons(pg[i]); tc->bw_precentage = htons(tc_tx_bw[i]); - - tc->max_bw_units = htons(MLX4_RATELIMIT_UNITS); - tc->max_bw_value = htons(r); } in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port; diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index b12f4bbd064c..db0aef37645f 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -48,6 +48,17 @@ #define MSIX_LEGACY_SZ 4 #define MIN_MSIX_P_PORT 5 +#define MLX4_NUM_UP 8 +#define MLX4_NUM_TC 8 +#define MLX4_MAX_100M_UNITS_VAL 255 /* + * work around: can't set values + * greater then this value when + * using 100 Mbps units. + */ +#define MLX4_RATELIMIT_100M_UNITS 3 /* 100 Mbps */ +#define MLX4_RATELIMIT_1G_UNITS 4 /* 1 Gbps */ +#define MLX4_RATELIMIT_DEFAULT 0x00ff + #define MLX4_ROCE_MAX_GIDS 128 #define MLX4_ROCE_PF_GIDS 16 -- cgit v1.2.3 From 4359db1e0d9f763dfcffbf23fb4a19341aad9b6b Mon Sep 17 00:00:00 2001 From: Eugenia Emantayev Date: Tue, 8 Jul 2014 11:25:20 +0300 Subject: net/mlx4_en: Run loopback test only when port is up Loopback can't work when port is down. Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_selftest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c index 03e5f6ac67e7..49d5afc7cfb8 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c @@ -159,7 +159,8 @@ void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf) if (priv->mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UC_LOOPBACK) { buf[3] = mlx4_en_test_registers(priv); - buf[4] = mlx4_en_test_loopback(priv); + if (priv->port_up) + buf[4] = mlx4_en_test_loopback(priv); } if (carrier_ok) -- cgit v1.2.3 From 143b3efb402d11f64639d5729634825c3934fc4c Mon Sep 17 00:00:00 2001 From: Eugenia Emantayev Date: Tue, 8 Jul 2014 11:25:21 +0300 Subject: net/mlx4: Verify port number in __mlx4_unregister_mac Verify port number to avoid crashes if port number is outside the range. Signed-off-by: Eli Cohen Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/port.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 5d76a60ac053..9ba0c1ca10d5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -244,10 +244,16 @@ EXPORT_SYMBOL_GPL(mlx4_get_base_qpn); void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) { - struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; - struct mlx4_mac_table *table = &info->mac_table; + struct mlx4_port_info *info; + struct mlx4_mac_table *table; int index; + if (port < 1 || port > dev->caps.num_ports) { + mlx4_warn(dev, "invalid port number (%d), aborting...\n", port); + return; + } + info = &mlx4_priv(dev)->port[port]; + table = &info->mac_table; mutex_lock(&table->mutex); index = find_index(dev, table, mac); -- cgit v1.2.3 From 49a1e4f6b7e78fed9ab36ebbb9d88656885255a4 Mon Sep 17 00:00:00 2001 From: Eugenia Emantayev Date: Tue, 8 Jul 2014 11:25:22 +0300 Subject: net/mlx4_en: Do not disable vlan filter during promiscuous mode Promiscous mode is only for MACs. Should not disable/enable VLAN filter when entering/leaving promisuous mode. Signed-off-by: Aviad Yehezkel Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 7d4fb7bf2593..255950adcc6b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -940,11 +940,6 @@ static void mlx4_en_set_promisc_mode(struct mlx4_en_priv *priv, 0, MLX4_MCAST_DISABLE); if (err) en_err(priv, "Failed disabling multicast filter\n"); - - /* Disable port VLAN filter */ - err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); - if (err) - en_err(priv, "Failed disabling VLAN filter\n"); } } @@ -993,11 +988,6 @@ static void mlx4_en_clear_promisc_mode(struct mlx4_en_priv *priv, en_err(priv, "Failed disabling promiscuous mode\n"); break; } - - /* Enable port VLAN filter */ - err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); - if (err) - en_err(priv, "Failed enabling VLAN filter\n"); } static void mlx4_en_do_multicast(struct mlx4_en_priv *priv, -- cgit v1.2.3 From d5b8dff0073d782f3169e510fd9445f1f56994e2 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Tue, 8 Jul 2014 11:25:23 +0300 Subject: net/mlx4_en: Do not count LLC/SNAP in MTU calculation LLC/SNAP 8 bytes should not be added as part of header calculation. If used, payload will be decreased accordingly. For MTU of 1500 we'll set 1522 instead of 1523. Signed-off-by: Yishai Hadas Reviewed-by: Liran Liss Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 2 +- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index d2d415732d99..b8ec9208e12a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -922,7 +922,7 @@ static const int frag_sizes[] = { void mlx4_en_calc_rx_buf(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); - int eff_mtu = dev->mtu + ETH_HLEN + VLAN_HLEN + ETH_LLC_SNAP_SIZE; + int eff_mtu = dev->mtu + ETH_HLEN + VLAN_HLEN; int buf_size = 0; int i = 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 0e15295bedd6..01011d4a7cbb 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -152,8 +152,6 @@ enum { #define MLX4_EN_TX_POLL_MODER 16 #define MLX4_EN_TX_POLL_TIMEOUT (HZ / 4) -#define ETH_LLC_SNAP_SIZE 8 - #define SMALL_PACKET_SIZE (256 - NET_IP_ALIGN) #define HEADER_COPY_SIZE (128 - NET_IP_ALIGN) #define MLX4_LOOPBACK_TEST_PAYLOAD (HEADER_COPY_SIZE - ETH_HLEN) -- cgit v1.2.3 From 2695bab2a6a18f31839c4e862eba3b450c0d2868 Mon Sep 17 00:00:00 2001 From: Noa Osherovich Date: Tue, 8 Jul 2014 11:25:24 +0300 Subject: net/mlx4_en: Fix mac_hash database inconsistency Using a local copy of dev_addr in mlx4_en_set_mac() to prevent dev_addr from being modified during error flow or when dev_addr is modified in another context (which is another problem that is being discussed over the mailing list [1]). Also fixing bad naming of priv->prev_mac into priv->current_mac. [1] - http://patchwork.ozlabs.org/patch/351489/ Reviewed-by: Eyal Perry Signed-off-by: Noa Osherovich Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 23 ++++++++++++++--------- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 255950adcc6b..f384b354c88d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -760,21 +760,22 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn, return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64); } -static int mlx4_en_do_set_mac(struct mlx4_en_priv *priv) +static int mlx4_en_do_set_mac(struct mlx4_en_priv *priv, + unsigned char new_mac[ETH_ALEN + 2]) { int err = 0; if (priv->port_up) { /* Remove old MAC and insert the new one */ err = mlx4_en_replace_mac(priv, priv->base_qpn, - priv->dev->dev_addr, priv->prev_mac); + new_mac, priv->current_mac); if (err) en_err(priv, "Failed changing HW MAC address\n"); } else en_dbg(HW, priv, "Port is down while registering mac, exiting...\n"); - memcpy(priv->prev_mac, priv->dev->dev_addr, - sizeof(priv->prev_mac)); + if (!err) + memcpy(priv->current_mac, new_mac, sizeof(priv->current_mac)); return err; } @@ -784,14 +785,17 @@ static int mlx4_en_set_mac(struct net_device *dev, void *addr) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; struct sockaddr *saddr = addr; + unsigned char new_mac[ETH_ALEN + 2]; int err; if (!is_valid_ether_addr(saddr->sa_data)) return -EADDRNOTAVAIL; mutex_lock(&mdev->state_lock); - memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN); - err = mlx4_en_do_set_mac(priv); + memcpy(new_mac, saddr->sa_data, ETH_ALEN); + err = mlx4_en_do_set_mac(priv, new_mac); + if (!err) + memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN); mutex_unlock(&mdev->state_lock); return err; @@ -1156,7 +1160,8 @@ static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv, } /* MAC address of the port is not in uc list */ - if (ether_addr_equal_64bits(entry->mac, dev->dev_addr)) + if (ether_addr_equal_64bits(entry->mac, + priv->current_mac)) found = true; if (!found) { @@ -1466,7 +1471,7 @@ static void mlx4_en_do_get_stats(struct work_struct *work) queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); } if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) { - mlx4_en_do_set_mac(priv); + mlx4_en_do_set_mac(priv, priv->current_mac); mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0; } mutex_unlock(&mdev->state_lock); @@ -2524,7 +2529,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, } } - memcpy(priv->prev_mac, dev->dev_addr, sizeof(priv->prev_mac)); + memcpy(priv->current_mac, dev->dev_addr, sizeof(priv->current_mac)); priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + DS_SIZE * MLX4_EN_MAX_RX_FRAGS); diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 01011d4a7cbb..7c1b5ec5378f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -530,7 +530,7 @@ struct mlx4_en_priv { int registered; int allocated; int stride; - unsigned char prev_mac[ETH_ALEN + 2]; + unsigned char current_mac[ETH_ALEN + 2]; int mac_index; unsigned max_mtu; int base_qpn; -- cgit v1.2.3 From da1774e5f1974294dcfc2c08363bb103e769d302 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 12:39:57 +0100 Subject: net: fec: improve safety of suspend/resume/transmit timeout paths We should hold the rtnl lock while suspending, resuming or processing the transmit timeout to ensure that nothing will interfere while we bring up, take down or restart the hardware. The transmit timeout could run if we're preempted during suspend. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index f43c388e2eb9..1cd71a8d9996 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1068,8 +1068,10 @@ static void fec_enet_work(struct work_struct *work) if (fep->delay_work.timeout) { fep->delay_work.timeout = false; + rtnl_lock(); fec_restart(fep->netdev, fep->full_duplex); netif_wake_queue(fep->netdev); + rtnl_unlock(); } if (fep->delay_work.trig_tx) { @@ -2680,11 +2682,14 @@ fec_suspend(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct fec_enet_private *fep = netdev_priv(ndev); + rtnl_lock(); if (netif_running(ndev)) { phy_stop(fep->phy_dev); fec_stop(ndev); netif_device_detach(ndev); } + rtnl_unlock(); + fec_enet_clk_enable(ndev, false); pinctrl_pm_select_sleep_state(&fep->pdev->dev); @@ -2712,11 +2717,13 @@ fec_resume(struct device *dev) if (ret) goto failed_clk; + rtnl_lock(); if (netif_running(ndev)) { fec_restart(ndev, fep->full_duplex); netif_device_attach(ndev); phy_start(fep->phy_dev); } + rtnl_unlock(); return 0; -- cgit v1.2.3 From 8bbbd3c19c469a1c6b8e97e9f5a083d029657be5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 12:40:02 +0100 Subject: net: fec: ensure fec_enet_close() copes with resume failure When the FEC is suspended, the device is detached. Upon resume failure, the device is left in detached mode, possibly with some of the required clocks not running. We don't want to be poking the device in that state because as it may cause bus errors. If the device is marked detached, avoid calling fec_stop(). This depends upon: "net:fec: improve safety of suspend/resume paths" Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 1cd71a8d9996..03785cd14b7c 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2197,10 +2197,10 @@ fec_enet_close(struct net_device *ndev) phy_stop(fep->phy_dev); - /* Don't know what to do yet. */ napi_disable(&fep->napi); netif_tx_disable(ndev); - fec_stop(ndev); + if (netif_device_present(ndev)) + fec_stop(ndev); phy_disconnect(fep->phy_dev); fep->phy_dev = NULL; -- cgit v1.2.3 From 8ce5624f5bbb991ae3aea2fcdae86d808351e173 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 12:40:07 +0100 Subject: net: fec: only restart or stop the device if it is present and running Avoid calling fec_restart() or fec_stop() while the device is down or not present (iow suspended.) Although the ndo_timeout method will only be called if the device is present and running, we defer this to a work queue. The work queue can run independently, and so needs to repeat these checks to ensure that a restart doesn't occur after the device has been taken down or detached for suspend. In this case, we call fec_restart() in the resume path, so nothing is lost. For fec_set_features, we add a call to fec_restart() in fec_enet_open() to ensure that the hardware is appropriate programmed when the interface is opened. fec_set_features() call should not occur while we're suspended, so we don't have to worry about that case. The adjust_link needs similar treatment - this also is called from a work queue, which may be run independently after we have taken the device down and detached it. In this case, we just mark the link down and take no further action. We will reset things appropriately once the device is up and running again, at which point we will receive another adjust_link callback. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 03785cd14b7c..bfb2bb00c493 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1065,12 +1065,15 @@ static void fec_enet_work(struct work_struct *work) container_of(work, struct fec_enet_private, delay_work.delay_work.work); + struct net_device *ndev = fep->netdev; if (fep->delay_work.timeout) { fep->delay_work.timeout = false; rtnl_lock(); - fec_restart(fep->netdev, fep->full_duplex); - netif_wake_queue(fep->netdev); + if (netif_device_present(ndev) || netif_running(ndev)) { + fec_restart(ndev, fep->full_duplex); + netif_wake_queue(ndev); + } rtnl_unlock(); } @@ -1504,7 +1507,14 @@ static void fec_enet_adjust_link(struct net_device *ndev) return; } - if (phy_dev->link) { + /* + * If the netdev is down, or is going down, we're not interested + * in link state events, so just mark our idea of the link as down + * and ignore the event. + */ + if (!netif_running(ndev) || !netif_device_present(ndev)) { + fep->link = 0; + } else if (phy_dev->link) { if (!fep->link) { fep->link = phy_dev->link; status_change = 1; @@ -2184,6 +2194,7 @@ fec_enet_open(struct net_device *ndev) return ret; } + fec_restart(ndev, fep->full_duplex); napi_enable(&fep->napi); phy_start(fep->phy_dev); netif_start_queue(ndev); @@ -2350,8 +2361,6 @@ static int fec_set_features(struct net_device *netdev, fec_stop(netdev); fec_restart(netdev, fep->phy_dev->duplex); netif_wake_queue(netdev); - } else { - fec_restart(netdev, fep->phy_dev->duplex); } } -- cgit v1.2.3 From dbc64a8ea231271c580b5a570bc48cf42203fe0e Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 12:40:12 +0100 Subject: net: fec: move calls to quiesce/resume packet processing out of fec_restart() Move the calls to quiesce and resume packet processing out of fec_restart() to its call sites. This is the first step in a two stage clean up of this code, where we just move the calls out of fec_restart() without changing them. Not everywhere needs to issue these calls, and not everywhere needs all of these calls to be issued. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 64 ++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index bfb2bb00c493..b71b7491f38f 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -818,9 +818,10 @@ static void fec_enet_bd_init(struct net_device *dev) fep->dirty_tx = bdp; } -/* This function is called to start or restart the FEC during a link - * change. This only happens when switching between half and full - * duplex. +/* + * This function is called to start or restart the FEC during a link + * change, transmit timeout, or to reconfigure the FEC. The network + * packet processing for this device must be stopped before this call. */ static void fec_restart(struct net_device *ndev, int duplex) @@ -834,13 +835,6 @@ fec_restart(struct net_device *ndev, int duplex) u32 rcntl = OPT_FRAME_SIZE | 0x04; u32 ecntl = 0x2; /* ETHEREN */ - if (netif_running(ndev)) { - netif_device_detach(ndev); - napi_disable(&fep->napi); - netif_tx_disable(ndev); - netif_tx_lock_bh(ndev); - } - /* Whack a reset. We should wait for this. */ writel(1, fep->hwp + FEC_ECNTRL); udelay(10); @@ -1009,13 +1003,6 @@ fec_restart(struct net_device *ndev, int duplex) /* Enable interrupts we wish to service */ writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); - - if (netif_running(ndev)) { - netif_tx_unlock_bh(ndev); - netif_wake_queue(ndev); - napi_enable(&fep->napi); - netif_device_attach(ndev); - } } static void @@ -1071,8 +1058,15 @@ static void fec_enet_work(struct work_struct *work) fep->delay_work.timeout = false; rtnl_lock(); if (netif_device_present(ndev) || netif_running(ndev)) { + netif_device_detach(ndev); + napi_disable(&fep->napi); + netif_tx_disable(ndev); + netif_tx_lock_bh(ndev); fec_restart(ndev, fep->full_duplex); + netif_tx_unlock_bh(ndev); netif_wake_queue(ndev); + napi_enable(&fep->napi); + netif_device_attach(ndev); } rtnl_unlock(); } @@ -1529,8 +1523,17 @@ static void fec_enet_adjust_link(struct net_device *ndev) } /* if any of the above changed restart the FEC */ - if (status_change) + if (status_change) { + netif_device_detach(ndev); + napi_disable(&fep->napi); + netif_tx_disable(ndev); + netif_tx_lock_bh(ndev); fec_restart(ndev, phy_dev->duplex); + netif_tx_unlock_bh(ndev); + netif_wake_queue(ndev); + napi_enable(&fep->napi); + netif_device_attach(ndev); + } } else { if (fep->link) { fec_stop(ndev); @@ -1915,8 +1918,17 @@ static int fec_enet_set_pauseparam(struct net_device *ndev, fec_stop(ndev); phy_start_aneg(fep->phy_dev); } - if (netif_running(ndev)) + if (netif_running(ndev)) { + netif_device_detach(ndev); + napi_disable(&fep->napi); + netif_tx_disable(ndev); + netif_tx_lock_bh(ndev); fec_restart(ndev, fep->full_duplex); + netif_tx_unlock_bh(ndev); + netif_wake_queue(ndev); + napi_enable(&fep->napi); + netif_device_attach(ndev); + } return 0; } @@ -2359,8 +2371,15 @@ static int fec_set_features(struct net_device *netdev, if (netif_running(netdev)) { fec_stop(netdev); + netif_device_detach(netdev); + napi_disable(&fep->napi); + netif_tx_disable(netdev); + netif_tx_lock_bh(netdev); fec_restart(netdev, fep->phy_dev->duplex); + netif_tx_unlock_bh(netdev); netif_wake_queue(netdev); + napi_enable(&fep->napi); + netif_device_attach(netdev); } } @@ -2728,7 +2747,14 @@ fec_resume(struct device *dev) rtnl_lock(); if (netif_running(ndev)) { + netif_device_detach(ndev); + napi_disable(&fep->napi); + netif_tx_disable(ndev); + netif_tx_lock_bh(ndev); fec_restart(ndev, fep->full_duplex); + netif_tx_unlock_bh(ndev); + netif_wake_queue(ndev); + napi_enable(&fep->napi); netif_device_attach(ndev); phy_start(fep->phy_dev); } -- cgit v1.2.3 From 6af42d420bcfa0c837911bd5b518fd4a3cfa4fe4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 12:40:18 +0100 Subject: net: fec: remove inappropriate calls around fec_restart() This is the second stage to "move calls to quiesce/resume packet processing out of fec_restart()", where we remove calls which are not appropriate to the call site. In the majority of cases, there is no need to detach and reattach the interface as we are holding the queue xmit lock across the reset. The exception to that is in fec_resume(), where we are already detached by the suspend function. Here, we can remove the call to detach the interface. We also do not need to stop the transmit queue. Holding the xmit lock is enough to ensure that the transmit packet processing is not running while we perform our task. However, since fec_restart() always cleans the rings, we call netif_wake_queue() (or netif_device_attach() in the case of resume) just before dropping the xmit lock. This prevents the watchdog firing. Lastly, always call napi_enable() after the device has been reattached in the resume path so that we know that the transmit packet processing is already in an enabled state, so we don't call netif_wake_queue() while detached. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index b71b7491f38f..25a9f7fb30da 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1058,15 +1058,12 @@ static void fec_enet_work(struct work_struct *work) fep->delay_work.timeout = false; rtnl_lock(); if (netif_device_present(ndev) || netif_running(ndev)) { - netif_device_detach(ndev); napi_disable(&fep->napi); - netif_tx_disable(ndev); netif_tx_lock_bh(ndev); fec_restart(ndev, fep->full_duplex); - netif_tx_unlock_bh(ndev); netif_wake_queue(ndev); + netif_tx_unlock_bh(ndev); napi_enable(&fep->napi); - netif_device_attach(ndev); } rtnl_unlock(); } @@ -1524,15 +1521,12 @@ static void fec_enet_adjust_link(struct net_device *ndev) /* if any of the above changed restart the FEC */ if (status_change) { - netif_device_detach(ndev); napi_disable(&fep->napi); - netif_tx_disable(ndev); netif_tx_lock_bh(ndev); fec_restart(ndev, phy_dev->duplex); - netif_tx_unlock_bh(ndev); netif_wake_queue(ndev); + netif_tx_unlock_bh(ndev); napi_enable(&fep->napi); - netif_device_attach(ndev); } } else { if (fep->link) { @@ -1919,15 +1913,12 @@ static int fec_enet_set_pauseparam(struct net_device *ndev, phy_start_aneg(fep->phy_dev); } if (netif_running(ndev)) { - netif_device_detach(ndev); napi_disable(&fep->napi); - netif_tx_disable(ndev); netif_tx_lock_bh(ndev); fec_restart(ndev, fep->full_duplex); - netif_tx_unlock_bh(ndev); netif_wake_queue(ndev); + netif_tx_unlock_bh(ndev); napi_enable(&fep->napi); - netif_device_attach(ndev); } return 0; @@ -2371,15 +2362,12 @@ static int fec_set_features(struct net_device *netdev, if (netif_running(netdev)) { fec_stop(netdev); - netif_device_detach(netdev); napi_disable(&fep->napi); - netif_tx_disable(netdev); netif_tx_lock_bh(netdev); fec_restart(netdev, fep->phy_dev->duplex); - netif_tx_unlock_bh(netdev); netif_wake_queue(netdev); + netif_tx_unlock_bh(netdev); napi_enable(&fep->napi); - netif_device_attach(netdev); } } @@ -2747,15 +2735,13 @@ fec_resume(struct device *dev) rtnl_lock(); if (netif_running(ndev)) { - netif_device_detach(ndev); napi_disable(&fep->napi); - netif_tx_disable(ndev); netif_tx_lock_bh(ndev); fec_restart(ndev, fep->full_duplex); + netif_device_attach(ndev); netif_tx_unlock_bh(ndev); - netif_wake_queue(ndev); - napi_enable(&fep->napi); netif_device_attach(ndev); + napi_enable(&fep->napi); phy_start(fep->phy_dev); } rtnl_unlock(); -- cgit v1.2.3 From 31a6de34f3daa9b1f412931befd9f82fd4a1b968 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 12:40:23 +0100 Subject: net: fec: quiesce packet processing before stopping device in fec_suspend() fec_suspend() calls fec_stop() to stop the transmit ring while the transmit packet processing is still active. This can lead to the transmit queue being restarted by an intervening packet queued for transmission, or by the tx quirk timer expiring. Fix this by disabling NAPI first, which will ensure that the NAPI handlers are not running. Then, take the transmit lock before detaching the netif device. This ensures that there are no races with the transmit path - and also ensures that the watchdog won't fire. We can then safely stop the ethernet device itself, knowing that the rest of the driver is safely shut down. On resume, we bring the device back up in reverse order - we restart the device, reattach the device (under the tx lock), and then enable the NAPI handlers. We also need to adjust the close function to cope with this new sequence, so that it's possible to cleanly close down the driver after the hardware fails to resume (eg, due to the regulator_enable() or pinctrl calls in the resume path returning an error.) Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 25a9f7fb30da..fc9f6f465e7a 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2211,10 +2211,11 @@ fec_enet_close(struct net_device *ndev) phy_stop(fep->phy_dev); - napi_disable(&fep->napi); - netif_tx_disable(ndev); - if (netif_device_present(ndev)) + if (netif_device_present(ndev)) { + napi_disable(&fep->napi); + netif_tx_disable(ndev); fec_stop(ndev); + } phy_disconnect(fep->phy_dev); fep->phy_dev = NULL; @@ -2701,8 +2702,11 @@ fec_suspend(struct device *dev) rtnl_lock(); if (netif_running(ndev)) { phy_stop(fep->phy_dev); - fec_stop(ndev); + napi_disable(&fep->napi); + netif_tx_lock_bh(ndev); netif_device_detach(ndev); + netif_tx_unlock_bh(ndev); + fec_stop(ndev); } rtnl_unlock(); @@ -2735,12 +2739,10 @@ fec_resume(struct device *dev) rtnl_lock(); if (netif_running(ndev)) { - napi_disable(&fep->napi); - netif_tx_lock_bh(ndev); fec_restart(ndev, fep->full_duplex); + netif_tx_lock_bh(ndev); netif_device_attach(ndev); netif_tx_unlock_bh(ndev); - netif_device_attach(ndev); napi_enable(&fep->napi); phy_start(fep->phy_dev); } -- cgit v1.2.3 From 9a7ba4381af4defa7834c73c8a015532c06f4e8e Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 12:40:28 +0100 Subject: net: fec: quiesce packet processing before stopping device in fec_set_features() fec_set_features() calls fec_stop() to stop the transmit ring while the transmit queue is still active. This can lead to the transmit ring being restarted by an intervening packet queued for transmission, or by the tx quirk timer expiring. Fix this by disabling NAPI (which ensures that the NAPI handlers are not running), and then take the transmit lock while we stop and restart the adapter (which prevents new packets being queued). Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index fc9f6f465e7a..2945cf6e65cf 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2362,9 +2362,9 @@ static int fec_set_features(struct net_device *netdev, fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED; if (netif_running(netdev)) { - fec_stop(netdev); napi_disable(&fep->napi); netif_tx_lock_bh(netdev); + fec_stop(netdev); fec_restart(netdev, fep->phy_dev->duplex); netif_wake_queue(netdev); netif_tx_unlock_bh(netdev); -- cgit v1.2.3 From 8506fa1d8eb36fbf96ab5e2a7e4b87826853f1be Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 12:40:33 +0100 Subject: net: fec: quiesce packet processing before changing features Changing the features (receive checksumming) requires the hardware to be reprogrammed, and also changes the checks in the receive packet processing. The current implementation has a race - fec_set_features() changes the flags which alter the receive packet processing while the adapter is active, and potentially receiving frames. Only after we've modified the software flag do we shutdown and reconfigure the hardware. This can lead to packets being received and marked with a valid checksum (via CHECKSUM_UNNECESSARY) when the hardware checksum validation has not yet been enabled. We must quiesce the device, then change the software configuration for this feature, and then resume the device if it was previously running. The resulting code structure also allows us to add other configuration features in this path without having to quiesce and resume the network interface and device. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 2945cf6e65cf..124d3c5f8046 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2346,12 +2346,21 @@ static void fec_poll_controller(struct net_device *dev) } #endif +#define FEATURES_NEED_QUIESCE NETIF_F_RXCSUM + static int fec_set_features(struct net_device *netdev, netdev_features_t features) { struct fec_enet_private *fep = netdev_priv(netdev); netdev_features_t changed = features ^ netdev->features; + /* Quiesce the device if necessary */ + if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) { + napi_disable(&fep->napi); + netif_tx_lock_bh(netdev); + fec_stop(netdev); + } + netdev->features = features; /* Receive checksum has been changed */ @@ -2360,16 +2369,14 @@ static int fec_set_features(struct net_device *netdev, fep->csum_flags |= FLAG_RX_CSUM_ENABLED; else fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED; + } - if (netif_running(netdev)) { - napi_disable(&fep->napi); - netif_tx_lock_bh(netdev); - fec_stop(netdev); - fec_restart(netdev, fep->phy_dev->duplex); - netif_wake_queue(netdev); - netif_tx_unlock_bh(netdev); - napi_enable(&fep->napi); - } + /* Resume the device after updates */ + if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) { + fec_restart(netdev, fep->phy_dev->duplex); + netif_wake_queue(netdev); + netif_tx_unlock_bh(netdev); + napi_enable(&fep->napi); } return 0; -- cgit v1.2.3 From f208ce10046888052d3a5e9fc88b7c1b819877d2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 12:40:38 +0100 Subject: net: fec: quiesce packet processing when taking link down in fec_enet_adjust_link() When the link goes down, the adjust_link method will be called, but there is no synchronisation to ensure that we won't be processing some last remaining packets via the NAPI handlers while performing a reset of the device. Add the necessary synchronisation to ensure that packet processing is complete before we stop and reset the FEC. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 124d3c5f8046..0186fec1f7f9 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1530,7 +1530,11 @@ static void fec_enet_adjust_link(struct net_device *ndev) } } else { if (fep->link) { + napi_disable(&fep->napi); + netif_tx_lock_bh(ndev); fec_stop(ndev); + netif_tx_unlock_bh(ndev); + napi_enable(&fep->napi); fep->link = phy_dev->link; status_change = 1; } -- cgit v1.2.3 From ef83337d138354e3d1e32d9f929e0afefe5552aa Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 12:40:43 +0100 Subject: net: fec: clean up duplex mode handling Many places call fec_restart() with the second parameter being some kind of previously saved duplex value, but only two places call it with some other setting. This is at odds with how the other link settings are handled, and used to be racy before the rtnl locks were added to fec_restart()'s various call paths. Clean this up so all link capabilities are handled in the same way - saved into the fec_enet_private structure, and then fec_restart() acts on those settings. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 0186fec1f7f9..9d82d915b06d 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -824,7 +824,7 @@ static void fec_enet_bd_init(struct net_device *dev) * packet processing for this device must be stopped before this call. */ static void -fec_restart(struct net_device *ndev, int duplex) +fec_restart(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); const struct platform_device_id *id_entry = @@ -875,7 +875,7 @@ fec_restart(struct net_device *ndev, int duplex) } /* Enable MII mode */ - if (duplex) { + if (fep->full_duplex == DUPLEX_FULL) { /* FD enable */ writel(0x04, fep->hwp + FEC_X_CNTRL); } else { @@ -884,8 +884,6 @@ fec_restart(struct net_device *ndev, int duplex) writel(0x0, fep->hwp + FEC_X_CNTRL); } - fep->full_duplex = duplex; - /* Set MII speed */ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); @@ -1060,7 +1058,7 @@ static void fec_enet_work(struct work_struct *work) if (netif_device_present(ndev) || netif_running(ndev)) { napi_disable(&fep->napi); netif_tx_lock_bh(ndev); - fec_restart(ndev, fep->full_duplex); + fec_restart(ndev); netif_wake_queue(ndev); netif_tx_unlock_bh(ndev); napi_enable(&fep->napi); @@ -1511,8 +1509,10 @@ static void fec_enet_adjust_link(struct net_device *ndev) status_change = 1; } - if (fep->full_duplex != phy_dev->duplex) + if (fep->full_duplex != phy_dev->duplex) { + fep->full_duplex = phy_dev->duplex; status_change = 1; + } if (phy_dev->speed != fep->speed) { fep->speed = phy_dev->speed; @@ -1523,7 +1523,7 @@ static void fec_enet_adjust_link(struct net_device *ndev) if (status_change) { napi_disable(&fep->napi); netif_tx_lock_bh(ndev); - fec_restart(ndev, phy_dev->duplex); + fec_restart(ndev); netif_wake_queue(ndev); netif_tx_unlock_bh(ndev); napi_enable(&fep->napi); @@ -1919,7 +1919,7 @@ static int fec_enet_set_pauseparam(struct net_device *ndev, if (netif_running(ndev)) { napi_disable(&fep->napi); netif_tx_lock_bh(ndev); - fec_restart(ndev, fep->full_duplex); + fec_restart(ndev); netif_wake_queue(ndev); netif_tx_unlock_bh(ndev); napi_enable(&fep->napi); @@ -2201,7 +2201,7 @@ fec_enet_open(struct net_device *ndev) return ret; } - fec_restart(ndev, fep->full_duplex); + fec_restart(ndev); napi_enable(&fep->napi); phy_start(fep->phy_dev); netif_start_queue(ndev); @@ -2377,7 +2377,7 @@ static int fec_set_features(struct net_device *netdev, /* Resume the device after updates */ if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) { - fec_restart(netdev, fep->phy_dev->duplex); + fec_restart(netdev); netif_wake_queue(netdev); netif_tx_unlock_bh(netdev); napi_enable(&fep->napi); @@ -2481,7 +2481,7 @@ static int fec_enet_init(struct net_device *ndev) ndev->hw_features = ndev->features; - fec_restart(ndev, 0); + fec_restart(ndev); return 0; } @@ -2750,7 +2750,7 @@ fec_resume(struct device *dev) rtnl_lock(); if (netif_running(ndev)) { - fec_restart(ndev, fep->full_duplex); + fec_restart(ndev); netif_tx_lock_bh(ndev); netif_device_attach(ndev); netif_tx_unlock_bh(ndev); -- cgit v1.2.3 From a37934fc0d0c087dd120dba229077048f1abfd37 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 8 Jul 2014 11:15:03 -0700 Subject: net: provide stubs for ip6_set_txhash and ip6_make_flowlabel Commit cb1ce2ef387b ("ipv6: Implement automatic flow label generation on transmit") introduced ip6_make_flowlabel, while commit b73c3d0e4f0e ("net: Save TX flow hash in sock and set in skbuf on xmit") introduced ip6_set_txhash. ip6_set_tx_hash() uses sk_v6_daddr which references __sk_common.skc_v6_daddr from struct sock_common, which is gated with IS_ENABLED(CONFIG_IPV6). ip6_make_flowlabel() uses the ipv6 member from struct net which is also gated with IS_ENABLED(CONFIG_IPV6). When CONFIG_IPV6 is disabled, we will hit a build failure that looks like this when the compiler attempts inlining these functions: CC [M] drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.o In file included from include/net/inet_sock.h:27:0, from include/net/ip.h:30, from drivers/net/ethernet/broadcom/cnic.c:37: include/net/ipv6.h: In function 'ip6_set_txhash': include/net/sock.h:327:33: error: 'struct sock_common' has no member named 'skc_v6_daddr' #define sk_v6_daddr __sk_common.skc_v6_daddr ^ include/net/ipv6.h:696:49: note: in expansion of macro 'sk_v6_daddr' keys.dst = (__force __be32)ipv6_addr_hash(&sk->sk_v6_daddr); ^ In file included from include/net/inetpeer.h:15:0, from include/net/route.h:28, from include/net/ip.h:31, from drivers/net/ethernet/broadcom/cnic.c:37: include/net/ipv6.h: In function 'ip6_make_flowlabel': include/net/ipv6.h:706:37: error: 'struct net' has no member named 'ipv6' if (!flowlabel && (autolabel || net->ipv6.sysctl.auto_flowlabels)) { ^ Fixes: cb1ce2ef387b ("ipv6: Implement automatic flow label generation on transmit") Fixes: b73c3d0e4f0e ("net: Save TX flow hash in sock and set in skbuf on xmit") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/ipv6.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 4308f2ada8b3..b9ac2357e7db 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -685,6 +685,7 @@ static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6, return hlimit; } +#if IS_ENABLED(CONFIG_IPV6) static inline void ip6_set_txhash(struct sock *sk) { struct inet_sock *inet = inet_sk(sk); @@ -718,6 +719,15 @@ static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, return flowlabel; } +#else +static inline void ip6_set_txhash(struct sock *sk) { } +static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, + __be32 flowlabel, bool autolabel) +{ + return flowlabel; +} +#endif + /* * Header manipulation -- cgit v1.2.3 From f51de24356e49e4dcb5095e87717065580912120 Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Tue, 8 Jul 2014 19:49:14 +0100 Subject: xen-netback: Adding debugfs "io_ring_qX" files This patch adds debugfs capabilities to netback. There used to be a similar patch floating around for classic kernel, but it used procfs. It is based on a very similar blkback patch. It creates xen-netback/[vifname]/io_ring_q[queueno] files, reading them output various ring variables etc. Writing "kick" into it imitates an interrupt happened, it can be useful to check whether the ring is just stalled due to a missed interrupt. Signed-off-by: Zoltan Kiss Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: xen-devel@lists.xenproject.org Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 11 +++ drivers/net/xen-netback/interface.c | 2 +- drivers/net/xen-netback/netback.c | 11 +++ drivers/net/xen-netback/xenbus.c | 178 +++++++++++++++++++++++++++++++++++- 4 files changed, 200 insertions(+), 2 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 2532ce85d718..28c98229e95f 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -44,6 +44,7 @@ #include #include #include +#include typedef unsigned int pending_ring_idx_t; #define INVALID_PENDING_RING_IDX (~0U) @@ -224,6 +225,10 @@ struct xenvif { struct xenvif_queue *queues; unsigned int num_queues; /* active queues, resource allocated */ +#ifdef CONFIG_DEBUG_FS + struct dentry *xenvif_dbg_root; +#endif + /* Miscellaneous private stuff. */ struct net_device *dev; }; @@ -297,10 +302,16 @@ static inline pending_ring_idx_t nr_pending_reqs(struct xenvif_queue *queue) /* Callback from stack when TX packet can be released */ void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success); +irqreturn_t xenvif_interrupt(int irq, void *dev_id); + extern bool separate_tx_rx_irq; extern unsigned int rx_drain_timeout_msecs; extern unsigned int rx_drain_timeout_jiffies; extern unsigned int xenvif_max_queues; +#ifdef CONFIG_DEBUG_FS +extern struct dentry *xen_netback_dbg_root; +#endif + #endif /* __XEN_NETBACK__COMMON_H__ */ diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 9e97c7ca0ddd..ef75b45e5085 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -102,7 +102,7 @@ static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static irqreturn_t xenvif_interrupt(int irq, void *dev_id) +irqreturn_t xenvif_interrupt(int irq, void *dev_id) { xenvif_tx_interrupt(irq, dev_id); xenvif_rx_interrupt(irq, dev_id); diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 1844a47636b6..77127ca08ca4 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1987,6 +1987,13 @@ static int __init netback_init(void) rx_drain_timeout_jiffies = msecs_to_jiffies(rx_drain_timeout_msecs); +#ifdef CONFIG_DEBUG_FS + xen_netback_dbg_root = debugfs_create_dir("xen-netback", NULL); + if (IS_ERR_OR_NULL(xen_netback_dbg_root)) + pr_warn("Init of debugfs returned %ld!\n", + PTR_ERR(xen_netback_dbg_root)); +#endif /* CONFIG_DEBUG_FS */ + return 0; failed_init: @@ -1997,6 +2004,10 @@ module_init(netback_init); static void __exit netback_fini(void) { +#ifdef CONFIG_DEBUG_FS + if (!IS_ERR_OR_NULL(xen_netback_dbg_root)) + debugfs_remove_recursive(xen_netback_dbg_root); +#endif /* CONFIG_DEBUG_FS */ xenvif_xenbus_fini(); } module_exit(netback_fini); diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 3d85acd84bad..580517d857bf 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -44,6 +44,175 @@ static void unregister_hotplug_status_watch(struct backend_info *be); static void set_backend_state(struct backend_info *be, enum xenbus_state state); +#ifdef CONFIG_DEBUG_FS +struct dentry *xen_netback_dbg_root = NULL; + +static int xenvif_read_io_ring(struct seq_file *m, void *v) +{ + struct xenvif_queue *queue = m->private; + struct xen_netif_tx_back_ring *tx_ring = &queue->tx; + struct xen_netif_rx_back_ring *rx_ring = &queue->rx; + + if (tx_ring->sring) { + struct xen_netif_tx_sring *sring = tx_ring->sring; + + seq_printf(m, "Queue %d\nTX: nr_ents %u\n", queue->id, + tx_ring->nr_ents); + seq_printf(m, "req prod %u (%d) cons %u (%d) event %u (%d)\n", + sring->req_prod, + sring->req_prod - sring->rsp_prod, + tx_ring->req_cons, + tx_ring->req_cons - sring->rsp_prod, + sring->req_event, + sring->req_event - sring->rsp_prod); + seq_printf(m, "rsp prod %u (base) pvt %u (%d) event %u (%d)\n", + sring->rsp_prod, + tx_ring->rsp_prod_pvt, + tx_ring->rsp_prod_pvt - sring->rsp_prod, + sring->rsp_event, + sring->rsp_event - sring->rsp_prod); + seq_printf(m, "pending prod %u pending cons %u nr_pending_reqs %u\n", + queue->pending_prod, + queue->pending_cons, + nr_pending_reqs(queue)); + seq_printf(m, "dealloc prod %u dealloc cons %u dealloc_queue %u\n\n", + queue->dealloc_prod, + queue->dealloc_cons, + queue->dealloc_prod - queue->dealloc_cons); + } + + if (rx_ring->sring) { + struct xen_netif_rx_sring *sring = rx_ring->sring; + + seq_printf(m, "RX: nr_ents %u\n", rx_ring->nr_ents); + seq_printf(m, "req prod %u (%d) cons %u (%d) event %u (%d)\n", + sring->req_prod, + sring->req_prod - sring->rsp_prod, + rx_ring->req_cons, + rx_ring->req_cons - sring->rsp_prod, + sring->req_event, + sring->req_event - sring->rsp_prod); + seq_printf(m, "rsp prod %u (base) pvt %u (%d) event %u (%d)\n\n", + sring->rsp_prod, + rx_ring->rsp_prod_pvt, + rx_ring->rsp_prod_pvt - sring->rsp_prod, + sring->rsp_event, + sring->rsp_event - sring->rsp_prod); + } + + seq_printf(m, "NAPI state: %lx NAPI weight: %d TX queue len %u\n" + "Credit timer_pending: %d, credit: %lu, usec: %lu\n" + "remaining: %lu, expires: %lu, now: %lu\n", + queue->napi.state, queue->napi.weight, + skb_queue_len(&queue->tx_queue), + timer_pending(&queue->credit_timeout), + queue->credit_bytes, + queue->credit_usec, + queue->remaining_credit, + queue->credit_timeout.expires, + jiffies); + + return 0; +} + +#define XENVIF_KICK_STR "kick" + +static ssize_t +xenvif_write_io_ring(struct file *filp, const char __user *buf, size_t count, + loff_t *ppos) +{ + struct xenvif_queue *queue = + ((struct seq_file *)filp->private_data)->private; + int len; + char write[sizeof(XENVIF_KICK_STR)]; + + /* don't allow partial writes and check the length */ + if (*ppos != 0) + return 0; + if (count < sizeof(XENVIF_KICK_STR) - 1) + return -ENOSPC; + + len = simple_write_to_buffer(write, + sizeof(write), + ppos, + buf, + count); + if (len < 0) + return len; + + if (!strncmp(write, XENVIF_KICK_STR, sizeof(XENVIF_KICK_STR) - 1)) + xenvif_interrupt(0, (void *)queue); + else { + pr_warn("Unknown command to io_ring_q%d. Available: kick\n", + queue->id); + count = -EINVAL; + } + return count; +} + +static int xenvif_dump_open(struct inode *inode, struct file *filp) +{ + int ret; + void *queue = NULL; + + if (inode->i_private) + queue = inode->i_private; + ret = single_open(filp, xenvif_read_io_ring, queue); + filp->f_mode |= FMODE_PWRITE; + return ret; +} + +static const struct file_operations xenvif_dbg_io_ring_ops_fops = { + .owner = THIS_MODULE, + .open = xenvif_dump_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = xenvif_write_io_ring, +}; + +static void xenvif_debugfs_addif(struct xenvif_queue *queue) +{ + struct dentry *pfile; + struct xenvif *vif = queue->vif; + int i; + + if (IS_ERR_OR_NULL(xen_netback_dbg_root)) + return; + + vif->xenvif_dbg_root = debugfs_create_dir(vif->dev->name, + xen_netback_dbg_root); + if (!IS_ERR_OR_NULL(vif->xenvif_dbg_root)) { + for (i = 0; i < vif->num_queues; ++i) { + char filename[sizeof("io_ring_q") + 4]; + + snprintf(filename, sizeof(filename), "io_ring_q%d", i); + pfile = debugfs_create_file(filename, + S_IRUSR | S_IWUSR, + vif->xenvif_dbg_root, + &vif->queues[i], + &xenvif_dbg_io_ring_ops_fops); + if (IS_ERR_OR_NULL(pfile)) + pr_warn("Creation of io_ring file returned %ld!\n", + PTR_ERR(pfile)); + } + } else + netdev_warn(vif->dev, + "Creation of vif debugfs dir returned %ld!\n", + PTR_ERR(vif->xenvif_dbg_root)); +} + +static void xenvif_debugfs_delif(struct xenvif *vif) +{ + if (IS_ERR_OR_NULL(xen_netback_dbg_root)) + return; + + if (!IS_ERR_OR_NULL(vif->xenvif_dbg_root)) + debugfs_remove_recursive(vif->xenvif_dbg_root); + vif->xenvif_dbg_root = NULL; +} +#endif /* CONFIG_DEBUG_FS */ + static int netback_remove(struct xenbus_device *dev) { struct backend_info *be = dev_get_drvdata(&dev->dev); @@ -246,8 +415,12 @@ static void backend_create_xenvif(struct backend_info *be) static void backend_disconnect(struct backend_info *be) { - if (be->vif) + if (be->vif) { +#ifdef CONFIG_DEBUG_FS + xenvif_debugfs_delif(be->vif); +#endif /* CONFIG_DEBUG_FS */ xenvif_disconnect(be->vif); + } } static void backend_connect(struct backend_info *be) @@ -560,6 +733,9 @@ static void connect(struct backend_info *be) be->vif->num_queues = queue_index; goto err; } +#ifdef CONFIG_DEBUG_FS + xenvif_debugfs_addif(queue); +#endif /* CONFIG_DEBUG_FS */ } /* Initialisation completed, tell core driver the number of -- cgit v1.2.3 From efa95b01da18ad22af62f6d99a3243f3be8fd264 Mon Sep 17 00:00:00 2001 From: david decotigny Date: Tue, 8 Jul 2014 15:14:41 -0700 Subject: netpoll: fix use after free After a bonding master reclaims the netpoll info struct, slaves could still hold a pointer to the reclaimed data. This patch fixes it: as soon as netpoll_async_cleanup is called for a slave (eg. when un-enslaved), we make sure that this slave doesn't point to the data. Signed-off-by: David Decotigny Signed-off-by: David S. Miller --- net/core/netpoll.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index e33937fb32a0..907fb5e36c02 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -822,7 +822,8 @@ void __netpoll_cleanup(struct netpoll *np) RCU_INIT_POINTER(np->dev->npinfo, NULL); call_rcu_bh(&npinfo->rcu, rcu_cleanup_netpoll_info); - } + } else + RCU_INIT_POINTER(np->dev->npinfo, NULL); } EXPORT_SYMBOL_GPL(__netpoll_cleanup); -- cgit v1.2.3 From ccea2968398c959493cdce503ae94206d2026fbe Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 13:01:38 +0100 Subject: net: fec: better implementation of iMX6 ERR006358 quirk Using a (delayed) workqueue for ERR006358 is not correct - a work queue is a single-trigger device. Once the work queue has been scheduled, it can't be re-scheduled until it has been run. This can cause problems - with an appropriate packet timing, we can end up with packets queued, but not sent by the hardware, resulting in the transmit timeout firing. Re-implement this as per the workaround detailed in the ERR006358 documentation - if there are packets waiting to be sent when we service the transmit ring, and we see that the transmitter is not running, kick the transmitter to run the pending entries in the ring. Testing here with a 10Mbit half duplex link sees the resulting iperf TCP bandwidth increase from between 1 to 2Mbps to between 8 to 9Mbps. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec.h | 1 - drivers/net/ethernet/freescale/fec_main.c | 30 ++++-------------------------- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 96d2a18f1b99..17e294970207 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -259,7 +259,6 @@ 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 9d82d915b06d..8cfc3a3de7fb 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -342,22 +342,6 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev) return 0; } -static void -fec_enet_submit_work(struct bufdesc *bdp, struct fec_enet_private *fep) -{ - const struct platform_device_id *id_entry = - platform_get_device_id(fep->pdev); - struct bufdesc *bdp_pre; - - bdp_pre = fec_enet_get_prevdesc(bdp, fep); - 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)); - } -} - static int fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev) { @@ -545,8 +529,6 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev) status |= (BD_ENET_TX_READY | BD_ENET_TX_TC); bdp->cbd_sc = status; - fec_enet_submit_work(bdp, fep); - /* If this was the last BD in the ring, start at the beginning again. */ bdp = fec_enet_get_nextdesc(last_bdp, fep); @@ -735,8 +717,6 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev) /* Save skb pointer */ fep->tx_skbuff[index] = skb; - fec_enet_submit_work(bdp, fep); - skb_tx_timestamp(skb); fep->cur_tx = bdp; @@ -1065,11 +1045,6 @@ static void fec_enet_work(struct work_struct *work) } rtnl_unlock(); } - - if (fep->delay_work.trig_tx) { - fep->delay_work.trig_tx = false; - writel(0, fep->hwp + FEC_X_DES_ACTIVE); - } } static void @@ -1166,7 +1141,10 @@ fec_enet_tx(struct net_device *ndev) netif_wake_queue(ndev); } } - return; + + /* ERR006538: Keep the transmitter going */ + if (bdp != fep->cur_tx && readl(fep->hwp + FEC_X_DES_ACTIVE) == 0) + writel(0, fep->hwp + FEC_X_DES_ACTIVE); } /* During a receive, the cur_rx points to the current incoming buffer. -- cgit v1.2.3 From 36cdc743a320e78a5d12ca9765ec0f7d9f07b1f5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 13:01:44 +0100 Subject: net: fec: replace delayed work with standard work As of "better implementation of iMX6 ERR006358 quirk", we no longer have a requirement for a delayed work. Moreover, the work is now only used for timeout purposes, so the timeout flag is also pointless - we set it each time we queue the work, and the work clears it. Replace the fec_enet_delayed_work struct with a standard work_struct, resulting in simplified timeout handling code. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec.h | 8 ++------ drivers/net/ethernet/freescale/fec_main.c | 34 +++++++++++++------------------ 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 17e294970207..bd53caf1c1eb 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -256,11 +256,6 @@ struct bufdesc_ex { #define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR) #define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR) -struct fec_enet_delayed_work { - struct delayed_work delay_work; - bool timeout; -}; - /* The FEC buffer descriptors track the ring buffers. The rx_bd_base and * tx_bd_base always point to the base of the buffer descriptors. The * cur_rx and cur_tx point to the currently available buffer. @@ -326,6 +321,8 @@ struct fec_enet_private { struct napi_struct napi; int csum_flags; + struct work_struct tx_timeout_work; + struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_caps; unsigned long last_overflow_check; @@ -338,7 +335,6 @@ struct fec_enet_private { int hwts_rx_en; int hwts_tx_en; struct timer_list time_keep; - struct fec_enet_delayed_work delay_work; struct regulator *reg_phy; }; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 8cfc3a3de7fb..b2ae7e706d5e 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1020,31 +1020,25 @@ fec_timeout(struct net_device *ndev) ndev->stats.tx_errors++; - fep->delay_work.timeout = true; - schedule_delayed_work(&(fep->delay_work.delay_work), 0); + schedule_work(&fep->tx_timeout_work); } -static void fec_enet_work(struct work_struct *work) +static void fec_enet_timeout_work(struct work_struct *work) { struct fec_enet_private *fep = - container_of(work, - struct fec_enet_private, - delay_work.delay_work.work); + container_of(work, struct fec_enet_private, tx_timeout_work); struct net_device *ndev = fep->netdev; - if (fep->delay_work.timeout) { - fep->delay_work.timeout = false; - rtnl_lock(); - if (netif_device_present(ndev) || netif_running(ndev)) { - napi_disable(&fep->napi); - netif_tx_lock_bh(ndev); - fec_restart(ndev); - netif_wake_queue(ndev); - netif_tx_unlock_bh(ndev); - napi_enable(&fep->napi); - } - rtnl_unlock(); + rtnl_lock(); + if (netif_device_present(ndev) || netif_running(ndev)) { + napi_disable(&fep->napi); + netif_tx_lock_bh(ndev); + fec_restart(ndev); + netif_wake_queue(ndev); + netif_tx_unlock_bh(ndev); + napi_enable(&fep->napi); } + rtnl_unlock(); } static void @@ -2642,7 +2636,7 @@ fec_probe(struct platform_device *pdev) if (fep->bufdesc_ex && fep->ptp_clock) netdev_info(ndev, "registered PHC device %d\n", fep->dev_id); - INIT_DELAYED_WORK(&(fep->delay_work.delay_work), fec_enet_work); + INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work); return 0; failed_register: @@ -2667,7 +2661,7 @@ fec_drv_remove(struct platform_device *pdev) struct net_device *ndev = platform_get_drvdata(pdev); struct fec_enet_private *fep = netdev_priv(ndev); - cancel_delayed_work_sync(&(fep->delay_work.delay_work)); + cancel_work_sync(&fep->tx_timeout_work); unregister_netdev(ndev); fec_enet_mii_remove(fep); del_timer_sync(&fep->time_keep); -- cgit v1.2.3 From db3421c114cfa6326861bc95e604785f4c64293b Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 13:01:49 +0100 Subject: net: fec: clear receive interrupts before processing a packet Clear any pending receive interrupt before we process a pending packet. This helps to avoid any spurious interrupts being raised after we have fully cleaned the receive ring, while still allowing an interrupt to be raised if we receive another packet. The position of this is critical: we must do this prior to reading the next packet status to avoid potentially dropping an interrupt when a packet is still pending. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index b2ae7e706d5e..79d578d6db8a 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1184,6 +1184,8 @@ fec_enet_rx(struct net_device *ndev, int budget) if ((status & BD_ENET_RX_LAST) == 0) netdev_err(ndev, "rcv is not +last\n"); + writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT); + /* Check for errors. */ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { -- cgit v1.2.3 From c1d7c48ff769021fab0591cfe331c0061186cb31 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 13:01:54 +0100 Subject: net: fec: reorder ethtool ops to match order in struct declaration This allows us to merge two separate preprocessor conditionals together. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 79d578d6db8a..c6b1bf797a39 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2014,21 +2014,19 @@ static int fec_enet_nway_reset(struct net_device *dev) } static const struct ethtool_ops fec_enet_ethtool_ops = { -#if !defined(CONFIG_M5272) - .get_pauseparam = fec_enet_get_pauseparam, - .set_pauseparam = fec_enet_set_pauseparam, -#endif .get_settings = fec_enet_get_settings, .set_settings = fec_enet_set_settings, .get_drvinfo = fec_enet_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_ts_info = fec_enet_get_ts_info, .nway_reset = fec_enet_nway_reset, + .get_link = ethtool_op_get_link, #ifndef CONFIG_M5272 - .get_ethtool_stats = fec_enet_get_ethtool_stats, + .get_pauseparam = fec_enet_get_pauseparam, + .set_pauseparam = fec_enet_set_pauseparam, .get_strings = fec_enet_get_strings, + .get_ethtool_stats = fec_enet_get_ethtool_stats, .get_sset_count = fec_enet_get_sset_count, #endif + .get_ts_info = fec_enet_get_ts_info, }; static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) -- cgit v1.2.3 From 344756f6e36b056ed361eedbd68244b108bdb1c6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 13:01:59 +0100 Subject: net: fec: add support for dumping transmit ring on timeout When we timeout on transmit, it would be useful to dump the transmit ring, so we can see the ring state. This can be helpful to diagnose the cause of transmit timeouts. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index c6b1bf797a39..09fcdc768931 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -320,6 +320,27 @@ static void *swap_buffer(void *bufaddr, int len) return bufaddr; } +static void fec_dump(struct net_device *ndev) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + struct bufdesc *bdp = fep->tx_bd_base; + unsigned int index = 0; + + netdev_info(ndev, "TX ring dump\n"); + pr_info("Nr SC addr len SKB\n"); + + do { + pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n", + index, + bdp == fep->cur_tx ? 'S' : ' ', + bdp == fep->dirty_tx ? 'H' : ' ', + bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen, + fep->tx_skbuff[index]); + bdp = fec_enet_get_nextdesc(bdp, fep); + index++; + } while (bdp != fep->tx_bd_base); +} + static inline bool is_ipv4_pkt(struct sk_buff *skb) { return skb->protocol == htons(ETH_P_IP) && ip_hdr(skb)->version == 4; @@ -1018,6 +1039,8 @@ fec_timeout(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); + fec_dump(ndev); + ndev->stats.tx_errors++; schedule_work(&fep->tx_timeout_work); -- cgit v1.2.3 From 96018f52c532b69424d354a848ac7812136650f6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 13:02:04 +0100 Subject: net: fec: remove useless status check in tx reap path Remove a useless status check in the transmit reap path - we have already checked that the BD_ENET_TX_READY bit is clear, and as the hardware only ever clears this bit, there is no way this test can ever be true. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 09fcdc768931..8679c919419c 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1133,9 +1133,6 @@ fec_enet_tx(struct net_device *ndev) skb_tstamp_tx(skb, &shhwtstamps); } - if (status & BD_ENET_TX_READY) - netdev_err(ndev, "HEY! Enet xmit interrupt and TX_READY\n"); - /* Deferred means some collisions occurred during transmit, * but we eventually sent the packet OK. */ -- cgit v1.2.3 From bfd4ecdd87d350e19457fe0d02fa1e046774c44e Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 8 Jul 2014 13:02:09 +0100 Subject: net: fec: consolidate hwtstamp implementation Both transmit and receive use the same infrastructure for calculating the packet timestamp. Rather than duplicating the code, provide a function to do this common work. Model this function in the Intel e1000e version which avoids calling ns_to_ktime() within the spinlock; the spinlock is critical for timecounter_cyc2time() but not ns_to_ktime(). Acked-by: Richard Cochran Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 37 ++++++++++++++++--------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 8679c919419c..e0efb212223f 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1064,6 +1064,21 @@ static void fec_enet_timeout_work(struct work_struct *work) rtnl_unlock(); } +static void +fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts, + struct skb_shared_hwtstamps *hwtstamps) +{ + unsigned long flags; + u64 ns; + + spin_lock_irqsave(&fep->tmreg_lock, flags); + ns = timecounter_cyc2time(&fep->tc, ts); + spin_unlock_irqrestore(&fep->tmreg_lock, flags); + + memset(hwtstamps, 0, sizeof(*hwtstamps)); + hwtstamps->hwtstamp = ns_to_ktime(ns); +} + static void fec_enet_tx(struct net_device *ndev) { @@ -1122,14 +1137,9 @@ fec_enet_tx(struct net_device *ndev) if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) && fep->bufdesc_ex) { struct skb_shared_hwtstamps shhwtstamps; - unsigned long flags; struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; - memset(&shhwtstamps, 0, sizeof(shhwtstamps)); - spin_lock_irqsave(&fep->tmreg_lock, flags); - shhwtstamps.hwtstamp = ns_to_ktime( - timecounter_cyc2time(&fep->tc, ebdp->ts)); - spin_unlock_irqrestore(&fep->tmreg_lock, flags); + fec_enet_hwtstamp(fep, ebdp->ts, &shhwtstamps); skb_tstamp_tx(skb, &shhwtstamps); } @@ -1288,18 +1298,9 @@ fec_enet_rx(struct net_device *ndev, int budget) skb->protocol = eth_type_trans(skb, ndev); /* Get receive timestamp from the skb */ - if (fep->hwts_rx_en && fep->bufdesc_ex) { - struct skb_shared_hwtstamps *shhwtstamps = - skb_hwtstamps(skb); - unsigned long flags; - - memset(shhwtstamps, 0, sizeof(*shhwtstamps)); - - spin_lock_irqsave(&fep->tmreg_lock, flags); - shhwtstamps->hwtstamp = ns_to_ktime( - timecounter_cyc2time(&fep->tc, ebdp->ts)); - spin_unlock_irqrestore(&fep->tmreg_lock, flags); - } + if (fep->hwts_rx_en && fep->bufdesc_ex) + fec_enet_hwtstamp(fep, ebdp->ts, + skb_hwtstamps(skb)); if (fep->bufdesc_ex && (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { -- cgit v1.2.3 From ca12769748ba48fce14a3b3b47da00c3eac635d0 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 8 Jul 2014 10:38:36 -0700 Subject: net: phy: export phy_suspend and phy_resume phy_suspend and phy_resume are two commonly used helper functions that need to be exported for Ethernet drivers to be built as modules Fixes: 40755a0fce17 ("net: systemport: add suspend and resume support") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 35d753d22f78..4f4568ef124e 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -696,6 +696,7 @@ int phy_suspend(struct phy_device *phydev) return phydrv->suspend(phydev); return 0; } +EXPORT_SYMBOL(phy_suspend); int phy_resume(struct phy_device *phydev) { @@ -705,6 +706,7 @@ int phy_resume(struct phy_device *phydev) return phydrv->resume(phydev); return 0; } +EXPORT_SYMBOL(phy_resume); /* Generic PHY support and helper functions */ -- cgit v1.2.3 From cd7ca0ec5e046c570497b387332560eb42908cc4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 9 Jul 2014 09:49:05 +0200 Subject: Bluetooth: Fix enabling Authenticated Payload Timeout Expired event The Authenticated Payload Timeout Expired event is valid for controllers with BR/EDR Secure Connections support, but also for LE only controllers supporting LE Ping feature. When either of them is available enable this event. Previous it was not enabled when the controller was only supporting LE operation. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6ed1f7288f13..a01236e2df13 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -357,6 +357,7 @@ enum { /* LE features */ #define HCI_LE_CONN_PARAM_REQ_PROC 0x02 +#define HCI_LE_PING 0x10 /* Connection modes */ #define HCI_CM_ACTIVE 0x0000 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8ffaca0290f8..421faf5fa1f5 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1569,7 +1569,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req) } /* Enable Authenticated Payload Timeout Expired event if supported */ - if (lmp_ping_capable(hdev)) + if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING) events[2] |= 0x80; hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events); -- cgit v1.2.3 From dcc36c16c2f1c9800146c8416ee5a4c3dc974623 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 12:59:13 +0300 Subject: Bluetooth: Unify helpers for bdaddr_list manipulations We already have several lists with struct bdaddr_list entries, and there will be more in the future. Since the operations for adding, removing, looking up and clearing entries in these lists are exactly the same it doesn't make sense to define new functions for every single list. This patch unifies the functions by passing the list_head to them instead of a hci_dev pointer. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 15 +++---- net/bluetooth/hci_core.c | 85 ++++++---------------------------------- net/bluetooth/hci_event.c | 15 ++++--- net/bluetooth/hci_sock.c | 4 +- net/bluetooth/l2cap_core.c | 7 ++-- net/bluetooth/mgmt.c | 6 ++- 6 files changed, 36 insertions(+), 96 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c98de309967e..3a1caf10cc8d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -849,16 +849,11 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg); int hci_get_auth_info(struct hci_dev *hdev, void __user *arg); int hci_inquiry(void __user *arg); -struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 type); -int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); -int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); - -struct bdaddr_list *hci_white_list_lookup(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 type); -void hci_white_list_clear(struct hci_dev *hdev); -int hci_white_list_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); -int hci_white_list_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *list, + bdaddr_t *bdaddr, u8 type); +int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type); +int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type); +void hci_bdaddr_list_clear(struct list_head *list); struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 421faf5fa1f5..705f8df7af96 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3351,12 +3351,12 @@ int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr, return 0; } -struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, +struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list, bdaddr_t *bdaddr, u8 type) { struct bdaddr_list *b; - list_for_each_entry(b, &hdev->blacklist, list) { + list_for_each_entry(b, bdaddr_list, list) { if (!bacmp(&b->bdaddr, bdaddr) && b->bdaddr_type == type) return b; } @@ -3364,11 +3364,11 @@ struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, return NULL; } -static void hci_blacklist_clear(struct hci_dev *hdev) +void hci_bdaddr_list_clear(struct list_head *bdaddr_list) { struct list_head *p, *n; - list_for_each_safe(p, n, &hdev->blacklist) { + list_for_each_safe(p, n, bdaddr_list) { struct bdaddr_list *b = list_entry(p, struct bdaddr_list, list); list_del(p); @@ -3376,14 +3376,14 @@ static void hci_blacklist_clear(struct hci_dev *hdev) } } -int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) +int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type) { struct bdaddr_list *entry; if (!bacmp(bdaddr, BDADDR_ANY)) return -EBADF; - if (hci_blacklist_lookup(hdev, bdaddr, type)) + if (hci_bdaddr_list_lookup(list, bdaddr, type)) return -EEXIST; entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); @@ -3393,82 +3393,21 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) bacpy(&entry->bdaddr, bdaddr); entry->bdaddr_type = type; - list_add(&entry->list, &hdev->blacklist); + list_add(&entry->list, list); return 0; } -int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) +int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type) { struct bdaddr_list *entry; if (!bacmp(bdaddr, BDADDR_ANY)) { - hci_blacklist_clear(hdev); + hci_bdaddr_list_clear(list); return 0; } - entry = hci_blacklist_lookup(hdev, bdaddr, type); - if (!entry) - return -ENOENT; - - list_del(&entry->list); - kfree(entry); - - return 0; -} - -struct bdaddr_list *hci_white_list_lookup(struct hci_dev *hdev, - bdaddr_t *bdaddr, u8 type) -{ - struct bdaddr_list *b; - - list_for_each_entry(b, &hdev->le_white_list, list) { - if (!bacmp(&b->bdaddr, bdaddr) && b->bdaddr_type == type) - return b; - } - - return NULL; -} - -void hci_white_list_clear(struct hci_dev *hdev) -{ - struct list_head *p, *n; - - list_for_each_safe(p, n, &hdev->le_white_list) { - struct bdaddr_list *b = list_entry(p, struct bdaddr_list, list); - - list_del(p); - kfree(b); - } -} - -int hci_white_list_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) -{ - struct bdaddr_list *entry; - - if (!bacmp(bdaddr, BDADDR_ANY)) - return -EBADF; - - entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); - if (!entry) - return -ENOMEM; - - bacpy(&entry->bdaddr, bdaddr); - entry->bdaddr_type = type; - - list_add(&entry->list, &hdev->le_white_list); - - return 0; -} - -int hci_white_list_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) -{ - struct bdaddr_list *entry; - - if (!bacmp(bdaddr, BDADDR_ANY)) - return -EBADF; - - entry = hci_white_list_lookup(hdev, bdaddr, type); + entry = hci_bdaddr_list_lookup(list, bdaddr, type); if (!entry) return -ENOENT; @@ -4096,13 +4035,13 @@ void hci_unregister_dev(struct hci_dev *hdev) destroy_workqueue(hdev->req_workqueue); hci_dev_lock(hdev); - hci_blacklist_clear(hdev); + hci_bdaddr_list_clear(&hdev->blacklist); hci_uuids_clear(hdev); hci_link_keys_clear(hdev); hci_smp_ltks_clear(hdev); hci_smp_irks_clear(hdev); hci_remote_oob_data_clear(hdev); - hci_white_list_clear(hdev); + hci_bdaddr_list_clear(&hdev->le_white_list); hci_conn_params_clear_all(hdev); hci_dev_unlock(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f6997901bdd7..381c631423f1 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1222,7 +1222,7 @@ static void hci_cc_le_clear_white_list(struct hci_dev *hdev, if (status) return; - hci_white_list_clear(hdev); + hci_bdaddr_list_clear(&hdev->le_white_list); } static void hci_cc_le_add_to_white_list(struct hci_dev *hdev, @@ -1240,7 +1240,8 @@ static void hci_cc_le_add_to_white_list(struct hci_dev *hdev, if (!sent) return; - hci_white_list_add(hdev, &sent->bdaddr, sent->bdaddr_type); + hci_bdaddr_list_add(&hdev->le_white_list, &sent->bdaddr, + sent->bdaddr_type); } static void hci_cc_le_del_from_white_list(struct hci_dev *hdev, @@ -1258,7 +1259,8 @@ static void hci_cc_le_del_from_white_list(struct hci_dev *hdev, if (!sent) return; - hci_white_list_del(hdev, &sent->bdaddr, sent->bdaddr_type); + hci_bdaddr_list_del(&hdev->le_white_list, &sent->bdaddr, + sent->bdaddr_type); } static void hci_cc_le_read_supported_states(struct hci_dev *hdev, @@ -2132,7 +2134,8 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) &flags); if ((mask & HCI_LM_ACCEPT) && - !hci_blacklist_lookup(hdev, &ev->bdaddr, BDADDR_BREDR)) { + !hci_bdaddr_list_lookup(&hdev->blacklist, &ev->bdaddr, + BDADDR_BREDR)) { /* Connection accepted */ struct inquiry_entry *ie; struct hci_conn *conn; @@ -4184,7 +4187,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) addr_type = BDADDR_LE_RANDOM; /* Drop the connection if he device is blocked */ - if (hci_blacklist_lookup(hdev, &conn->dst, addr_type)) { + if (hci_bdaddr_list_lookup(&hdev->blacklist, &conn->dst, addr_type)) { hci_conn_drop(conn); goto unlock; } @@ -4253,7 +4256,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, return; /* Ignore if the device is blocked */ - if (hci_blacklist_lookup(hdev, addr, addr_type)) + if (hci_bdaddr_list_lookup(&hdev->blacklist, addr, addr_type)) return; /* If we're connectable, always connect any ADV_DIRECT_IND event */ diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 802665751cc4..c64728d571ae 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -481,7 +481,7 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg) hci_dev_lock(hdev); - err = hci_blacklist_add(hdev, &bdaddr, BDADDR_BREDR); + err = hci_bdaddr_list_add(&hdev->blacklist, &bdaddr, BDADDR_BREDR); hci_dev_unlock(hdev); @@ -498,7 +498,7 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) hci_dev_lock(hdev); - err = hci_blacklist_del(hdev, &bdaddr, BDADDR_BREDR); + err = hci_bdaddr_list_del(&hdev->blacklist, &bdaddr, BDADDR_BREDR); hci_dev_unlock(hdev); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index bf379a379fa0..d006e6c0e3b4 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1460,6 +1460,7 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, static void l2cap_le_conn_ready(struct l2cap_conn *conn) { struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; struct l2cap_chan *chan, *pchan; u8 dst_type; @@ -1478,7 +1479,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) dst_type = bdaddr_type(hcon, hcon->dst_type); /* If device is blocked, do not create a channel for it */ - if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, dst_type)) + if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type)) return; /* For LE slave connections, make sure the connection interval @@ -6918,8 +6919,8 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) * at least ensure that we ignore incoming data from them. */ if (hcon->type == LE_LINK && - hci_blacklist_lookup(hcon->hdev, &hcon->dst, - bdaddr_type(hcon, hcon->dst_type))) { + hci_bdaddr_list_lookup(&hcon->hdev->blacklist, &hcon->dst, + bdaddr_type(hcon, hcon->dst_type))) { kfree_skb(skb); return; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 216aa93514b6..592e73eea76d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3956,7 +3956,8 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data, hci_dev_lock(hdev); - err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type); + err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr, + cp->addr.type); if (err < 0) { status = MGMT_STATUS_FAILED; goto done; @@ -3991,7 +3992,8 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, hci_dev_lock(hdev); - err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type); + err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr, + cp->addr.type); if (err < 0) { status = MGMT_STATUS_INVALID_PARAMS; goto done; -- cgit v1.2.3 From 6659358efe617bb46237e62f7303c76e10568d70 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 12:59:14 +0300 Subject: Bluetooth: Introduce a whitelist for BR/EDR devices This patch extends the Add/Remove device commands by letting user space pass BR/EDR addresses to them. The resulting entries get stored in a new hdev->whitelist list. The idea is that we can now selectively accept connections from devices in the list even though HCI_CONNECTABLE is not set (the actual implementation of this is coming in a subsequent patch). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 29 +++++++++++++++++++++++++ net/bluetooth/mgmt.c | 46 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3a1caf10cc8d..cba4837dcaa5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -305,6 +305,7 @@ struct hci_dev { struct list_head mgmt_pending; struct list_head blacklist; + struct list_head whitelist; struct list_head uuids; struct list_head link_keys; struct list_head long_term_keys; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 705f8df7af96..728a6ee471ea 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -191,6 +191,31 @@ static const struct file_operations blacklist_fops = { .release = single_release, }; +static int whitelist_show(struct seq_file *f, void *p) +{ + struct hci_dev *hdev = f->private; + struct bdaddr_list *b; + + hci_dev_lock(hdev); + list_for_each_entry(b, &hdev->whitelist, list) + seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); + hci_dev_unlock(hdev); + + return 0; +} + +static int whitelist_open(struct inode *inode, struct file *file) +{ + return single_open(file, whitelist_show, inode->i_private); +} + +static const struct file_operations whitelist_fops = { + .open = whitelist_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int uuids_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; @@ -1707,6 +1732,8 @@ static int __hci_init(struct hci_dev *hdev) debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev); debugfs_create_file("blacklist", 0444, hdev->debugfs, hdev, &blacklist_fops); + debugfs_create_file("whitelist", 0444, hdev->debugfs, hdev, + &whitelist_fops); debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); debugfs_create_file("conn_info_min_age", 0644, hdev->debugfs, hdev, @@ -3825,6 +3852,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->mgmt_pending); INIT_LIST_HEAD(&hdev->blacklist); + INIT_LIST_HEAD(&hdev->whitelist); INIT_LIST_HEAD(&hdev->uuids); INIT_LIST_HEAD(&hdev->link_keys); INIT_LIST_HEAD(&hdev->long_term_keys); @@ -4036,6 +4064,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_dev_lock(hdev); hci_bdaddr_list_clear(&hdev->blacklist); + hci_bdaddr_list_clear(&hdev->whitelist); hci_uuids_clear(hdev); hci_link_keys_clear(hdev); hci_smp_ltks_clear(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 592e73eea76d..49581e99685c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5219,7 +5219,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, BT_DBG("%s", hdev->name); - if (!bdaddr_type_is_le(cp->addr.type) || + if (!bdaddr_type_is_valid(cp->addr.type) || !bacmp(&cp->addr.bdaddr, BDADDR_ANY)) return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, MGMT_STATUS_INVALID_PARAMS, @@ -5232,6 +5232,22 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, hci_dev_lock(hdev); + if (cp->addr.type == BDADDR_BREDR) { + /* Only "connect" action supported for now */ + if (cp->action != 0x01) { + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); + goto unlock; + } + + err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr, + cp->addr.type); + if (err) + goto unlock; + goto added; + } + if (cp->addr.type == BDADDR_LE_PUBLIC) addr_type = ADDR_LE_DEV_PUBLIC; else @@ -5253,6 +5269,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } +added: device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action); err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, @@ -5288,13 +5305,30 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, struct hci_conn_params *params; u8 addr_type; - if (!bdaddr_type_is_le(cp->addr.type)) { + if (!bdaddr_type_is_valid(cp->addr.type)) { err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, MGMT_STATUS_INVALID_PARAMS, &cp->addr, sizeof(cp->addr)); goto unlock; } + if (cp->addr.type == BDADDR_BREDR) { + err = hci_bdaddr_list_del(&hdev->whitelist, + &cp->addr.bdaddr, + cp->addr.type); + if (err) { + err = cmd_complete(sk, hdev->id, + MGMT_OP_REMOVE_DEVICE, + MGMT_STATUS_INVALID_PARAMS, + &cp->addr, sizeof(cp->addr)); + goto unlock; + } + + device_removed(sk, hdev, &cp->addr.bdaddr, + cp->addr.type); + goto complete; + } + if (cp->addr.type == BDADDR_LE_PUBLIC) addr_type = ADDR_LE_DEV_PUBLIC; else @@ -5324,6 +5358,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); } else { struct hci_conn_params *p, *tmp; + struct bdaddr_list *b, *btmp; if (cp->addr.type) { err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, @@ -5332,6 +5367,12 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } + list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) { + device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type); + list_del(&b->list); + kfree(b); + } + list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) { if (p->auto_connect == HCI_AUTO_CONN_DISABLED) continue; @@ -5346,6 +5387,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, hci_update_background_scan(hdev); } +complete: err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr)); -- cgit v1.2.3 From a397407f266f8dcb6ea7b28cbff9d9cbd87b6ca8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 12:59:15 +0300 Subject: Bluetooth: Update page scan when necessary for Add/Remove Device When we're removing the last item in the white list or adding the first one to it and HCI_CONNECTABLE is not set we need to update the current page scan. This patch adds a simple helper function for the purpose and calls it from the respective mgmt command handlers. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 49581e99685c..72ff19f26991 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5198,6 +5198,27 @@ unlock: return err; } +/* Helper for Add/Remove Device commands */ +static void update_page_scan(struct hci_dev *hdev, u8 scan) +{ + if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) + return; + + if (!hdev_is_powered(hdev)) + return; + + /* If HCI_CONNECTABLE is set then Add/Remove Device should not + * make any changes to page scanning. + */ + if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + return; + + if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) + scan |= SCAN_INQUIRY; + + hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); +} + static void device_added(struct sock *sk, struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type, u8 action) { @@ -5233,6 +5254,8 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, hci_dev_lock(hdev); if (cp->addr.type == BDADDR_BREDR) { + bool update_scan; + /* Only "connect" action supported for now */ if (cp->action != 0x01) { err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, @@ -5241,10 +5264,16 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } + update_scan = list_empty(&hdev->whitelist); + err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr, cp->addr.type); if (err) goto unlock; + + if (update_scan) + update_page_scan(hdev, SCAN_PAGE); + goto added; } @@ -5324,6 +5353,9 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } + if (list_empty(&hdev->whitelist)) + update_page_scan(hdev, SCAN_DISABLED); + device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); goto complete; @@ -5373,6 +5405,8 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, kfree(b); } + update_page_scan(hdev, SCAN_DISABLED); + list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) { if (p->auto_connect == HCI_AUTO_CONN_DISABLED) continue; -- cgit v1.2.3 From dee58c1ed5e29eb57fa9358a8ff27848b72f3b7d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 12:59:16 +0300 Subject: Bluetooth: Fix incorrectly setting HCI_CONNECTABLE Since page scan might be enabled by Add Device we should not implicitly set connectable whenever something else than Set Connectable changes it. This patch makes sure that we don't set HCI_CONNECTABLE for these cases if there are any entries in the white list. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 72ff19f26991..5a866b65371c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6076,6 +6076,14 @@ void mgmt_connectable(struct hci_dev *hdev, u8 connectable) if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) return; + /* If something else than mgmt changed the page scan state we + * can't differentiate this from a change triggered by adding + * the first element to the whitelist. Therefore, avoid + * incorrectly setting HCI_CONNECTABLE. + */ + if (connectable && !list_empty(&hdev->whitelist)) + return; + if (connectable) changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); else -- cgit v1.2.3 From 70c464256310e1c3716099b9d02ece4169272f73 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 12:59:17 +0300 Subject: Bluetooth: Refactor connection request handling The conditions for accepting an incoming connections are already non-trivial and will become more so once a white list is added. This patch breaks up the checks for when to reject the request by creating a helper function for it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 112 +++++++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 52 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 381c631423f1..6d1d5b3e9cd4 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2121,10 +2121,21 @@ unlock: hci_conn_check_pending(hdev); } +static void hci_reject_conn(struct hci_dev *hdev, bdaddr_t *bdaddr) +{ + struct hci_cp_reject_conn_req cp; + + bacpy(&cp.bdaddr, bdaddr); + cp.reason = HCI_ERROR_REJ_BAD_ADDR; + hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp); +} + static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_request *ev = (void *) skb->data; int mask = hdev->link_mode; + struct inquiry_entry *ie; + struct hci_conn *conn; __u8 flags = 0; BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr, @@ -2133,74 +2144,71 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type, &flags); - if ((mask & HCI_LM_ACCEPT) && - !hci_bdaddr_list_lookup(&hdev->blacklist, &ev->bdaddr, + if (!(mask & HCI_LM_ACCEPT)) { + hci_reject_conn(hdev, &ev->bdaddr); + return; + } + + if (!hci_bdaddr_list_lookup(&hdev->blacklist, &ev->bdaddr, BDADDR_BREDR)) { - /* Connection accepted */ - struct inquiry_entry *ie; - struct hci_conn *conn; + hci_reject_conn(hdev, &ev->bdaddr); + return; + } - hci_dev_lock(hdev); + /* Connection accepted */ - ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr); - if (ie) - memcpy(ie->data.dev_class, ev->dev_class, 3); + hci_dev_lock(hdev); - conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, - &ev->bdaddr); + ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr); + if (ie) + memcpy(ie->data.dev_class, ev->dev_class, 3); + + conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, + &ev->bdaddr); + if (!conn) { + conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr); if (!conn) { - conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr); - if (!conn) { - BT_ERR("No memory for new connection"); - hci_dev_unlock(hdev); - return; - } + BT_ERR("No memory for new connection"); + hci_dev_unlock(hdev); + return; } + } - memcpy(conn->dev_class, ev->dev_class, 3); + memcpy(conn->dev_class, ev->dev_class, 3); - hci_dev_unlock(hdev); + hci_dev_unlock(hdev); - if (ev->link_type == ACL_LINK || - (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { - struct hci_cp_accept_conn_req cp; - conn->state = BT_CONNECT; + if (ev->link_type == ACL_LINK || + (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { + struct hci_cp_accept_conn_req cp; + conn->state = BT_CONNECT; - bacpy(&cp.bdaddr, &ev->bdaddr); + bacpy(&cp.bdaddr, &ev->bdaddr); - if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) - cp.role = 0x00; /* Become master */ - else - cp.role = 0x01; /* Remain slave */ + if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) + cp.role = 0x00; /* Become master */ + else + cp.role = 0x01; /* Remain slave */ - hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), - &cp); - } else if (!(flags & HCI_PROTO_DEFER)) { - struct hci_cp_accept_sync_conn_req cp; - conn->state = BT_CONNECT; + hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp); + } else if (!(flags & HCI_PROTO_DEFER)) { + struct hci_cp_accept_sync_conn_req cp; + conn->state = BT_CONNECT; - bacpy(&cp.bdaddr, &ev->bdaddr); - cp.pkt_type = cpu_to_le16(conn->pkt_type); + bacpy(&cp.bdaddr, &ev->bdaddr); + cp.pkt_type = cpu_to_le16(conn->pkt_type); - cp.tx_bandwidth = cpu_to_le32(0x00001f40); - cp.rx_bandwidth = cpu_to_le32(0x00001f40); - cp.max_latency = cpu_to_le16(0xffff); - cp.content_format = cpu_to_le16(hdev->voice_setting); - cp.retrans_effort = 0xff; + cp.tx_bandwidth = cpu_to_le32(0x00001f40); + cp.rx_bandwidth = cpu_to_le32(0x00001f40); + cp.max_latency = cpu_to_le16(0xffff); + cp.content_format = cpu_to_le16(hdev->voice_setting); + cp.retrans_effort = 0xff; - hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, - sizeof(cp), &cp); - } else { - conn->state = BT_CONNECT2; - hci_proto_connect_cfm(conn, 0); - } + hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, sizeof(cp), + &cp); } else { - /* Connection rejected */ - struct hci_cp_reject_conn_req cp; - - bacpy(&cp.bdaddr, &ev->bdaddr); - cp.reason = HCI_ERROR_REJ_BAD_ADDR; - hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp); + conn->state = BT_CONNECT2; + hci_proto_connect_cfm(conn, 0); } } -- cgit v1.2.3 From 6cebb9e73a88a4ffea586a2bf2873c0901f4e912 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 12:59:18 +0300 Subject: Bluetooth: Enable page scan also if there are white list entries Page scan should be enabled either if the connectable setting is set or if there are any entries in the BR/EDR white list. This patch implements such behavior by updating the two places that were making decisions on whether to enable page scan or not. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5a866b65371c..98392d61b78f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4357,7 +4357,8 @@ static void set_bredr_scan(struct hci_request *req) */ write_fast_connectable(req, false); - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || + !list_empty(&hdev->whitelist)) scan |= SCAN_PAGE; if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) scan |= SCAN_INQUIRY; @@ -4471,7 +4472,8 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) hci_req_init(&req, hdev); - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) + if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || + !list_empty(&hdev->whitelist)) set_bredr_scan(&req); /* Since only the advertising data flags will change, there -- cgit v1.2.3 From a55bd29d522729e0cb125474396acdc2a107d4d9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 12:59:19 +0300 Subject: Bluetooth: Add white list lookup for incoming connection requests This patch adds support for looking up entries in the white list when HCI_CONNECTABLE is not set. The logic is fairly simple: if we're connectable check the black list, if we're not connectable check the white list. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 6d1d5b3e9cd4..c8ae9ee3cb12 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2149,10 +2149,18 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) return; } - if (!hci_bdaddr_list_lookup(&hdev->blacklist, &ev->bdaddr, - BDADDR_BREDR)) { - hci_reject_conn(hdev, &ev->bdaddr); - return; + if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) { + if (hci_bdaddr_list_lookup(&hdev->blacklist, &ev->bdaddr, + BDADDR_BREDR)) { + hci_reject_conn(hdev, &ev->bdaddr); + return; + } + } else { + if (!hci_bdaddr_list_lookup(&hdev->whitelist, &ev->bdaddr, + BDADDR_BREDR)) { + hci_reject_conn(hdev, &ev->bdaddr); + return; + } } /* Connection accepted */ -- cgit v1.2.3 From 91a668b0565dddc9f556f9bce65da58264c74623 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 13:28:26 +0300 Subject: Bluetooth: Fix setting HCI_CONNECTABLE from ioctl code When the white list is in use the code would not update the HCI_CONNECTABLE flag if it gets changed through the ioctl code (e.g. hciconfig hci0 pscan). Since the flag is important for properly accepting incoming connections add code to fix it up if necessary and emit a New Settings mgmt event. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 17 +++++++++++++++++ net/bluetooth/mgmt.c | 5 +++++ 3 files changed, 23 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index cba4837dcaa5..e69c2b08c0c6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1281,6 +1281,7 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event); #define DISCOV_BREDR_INQUIRY_LEN 0x08 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len); +int mgmt_new_settings(struct hci_dev *hdev); void mgmt_index_added(struct hci_dev *hdev); void mgmt_index_removed(struct hci_dev *hdev); void mgmt_set_powered_failed(struct hci_dev *hdev, int err); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 728a6ee471ea..84431b86af96 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2715,6 +2715,23 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) case HCISETSCAN: err = hci_req_sync(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); + + /* Ensure that the connectable state gets correctly + * notified if the whitelist is in use. + */ + if (!err && !list_empty(&hdev->whitelist)) { + bool changed; + + if ((dr.dev_opt & SCAN_PAGE)) + changed = !test_and_set_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + else + changed = test_and_set_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + + if (changed) + mgmt_new_settings(hdev); + } break; case HCISETLINKPOL: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 98392d61b78f..91b1f92c681e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1427,6 +1427,11 @@ static int new_settings(struct hci_dev *hdev, struct sock *skip) return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip); } +int mgmt_new_settings(struct hci_dev *hdev) +{ + return new_settings(hdev, NULL); +} + struct cmd_lookup { struct sock *sk; struct hci_dev *hdev; -- cgit v1.2.3 From 6fea7ad1d338dba592d65423427a997f1b7ff485 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 9 Jul 2014 11:53:35 +0200 Subject: Bluetooth: Don't send ERTM configuration option when disabled When ERTM support is disabled, then do not even send ERTM configuration option even if the remote side supports it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d006e6c0e3b4..8680aae678ce 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3234,6 +3234,9 @@ done: switch (chan->mode) { case L2CAP_MODE_BASIC: + if (disable_ertm) + break; + if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) && !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING)) break; -- cgit v1.2.3 From 2bcd4003b8fafe200eb31f43d50e305e5dc44058 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 19:18:09 +0300 Subject: Bluetooth: Always confirm incoming SMP just-works requests For incoming requests we want to let the user know that pairing is happening since otherwise there could be access to MEDIUM security services without any user interaction at all. Therefore, set the selected method to JUST_CFM instead of JUST_WORKS and let it be converted back to JUST_WORKS later if we are the initators. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 55c41de2f5a0..a17761c83820 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -391,10 +391,12 @@ static const u8 gen_method[5][5] = { static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io) { - /* If either side has unknown io_caps, use JUST WORKS */ + /* If either side has unknown io_caps, use JUST_CFM (which gets + * converted later to JUST_WORKS if we're initiators. + */ if (local_io > SMP_IO_KEYBOARD_DISPLAY || remote_io > SMP_IO_KEYBOARD_DISPLAY) - return JUST_WORKS; + return JUST_CFM; return gen_method[remote_io][local_io]; } @@ -414,10 +416,14 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io); - /* If neither side wants MITM, use JUST WORKS */ - /* Otherwise, look up method from the table */ + /* If neither side wants MITM, either "just" confirm an incoming + * request or use just-works for outgoing ones. The JUST_CFM + * will be converted to JUST_WORKS if necessary later in this + * function. If either side has MITM look up the method from the + * table. + */ if (!(auth & SMP_AUTH_MITM)) - method = JUST_WORKS; + method = JUST_CFM; else method = get_auth_method(smp, local_io, remote_io); -- cgit v1.2.3 From e247605a6247aff887d435d2334ffe0e581dae24 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 19:18:10 +0300 Subject: Bluetooth: Fix forcing SMP just-works with no-bonding Whether we bond or not should not have any impact on the user interaction model. This patch removes an incorrect fall-back from JUST_CFM to JUST_WORKS in case we're not bonding. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index a17761c83820..a5e51c686469 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -427,10 +427,6 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, else method = get_auth_method(smp, local_io, remote_io); - /* If not bonding, don't ask user to confirm a Zero TK */ - if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM) - method = JUST_WORKS; - /* Don't confirm locally initiated pairing attempts */ if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR, &smp->flags)) method = JUST_WORKS; -- cgit v1.2.3 From c072d546c20390fea0e5332d00fd1b67366ca013 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 19:18:11 +0300 Subject: Bluetooth: Fix incorrect clearing of SMP_FLAG_INITIATOR When the SMP context is created all flags default to zero. To determine that we are the initiators it's therefore best to simply change the flag value when we know we're sending the first SMP PDU. Clearing the flag when receiving a Pairing Request is not correct since the request may be a response to a previous Security Request from us (for which we would already have correctly set the flag). Same goes for receiving a Security Request which may be coming after us already starting pairing by sending a Pairing Request. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index a5e51c686469..627d683203cf 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -735,8 +735,6 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (ret) return SMP_UNSPECIFIED; - clear_bit(SMP_FLAG_INITIATOR, &smp->flags); - return 0; } @@ -927,8 +925,6 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); - clear_bit(SMP_FLAG_INITIATOR, &smp->flags); - return 0; } -- cgit v1.2.3 From 21621e93f24b5f8de8262ace269a5f692a826bed Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 9 Jul 2014 20:35:21 +0200 Subject: ipconfig: move ic_dev_xid under IPCONFIG_BOOTP ic_dev_xid is only used in __init ic_bootp_recv under IPCONFIG_BOOTP and __init ic_dynamic under IPCONFIG_DYNAMIC(which is itself defined with the same IPCONFIG_BOOTP) This patch fixes the following warning when IPCONFIG_BOOTP is not set: >> net/ipv4/ipconfig.c:146:15: warning: 'ic_dev_xid' defined but not used [-Wunused-variable] static __be32 ic_dev_xid; /* Device under configuration */ Reported-by: Fengguang Wu Cc: Fengguang Wu Cc: "David S. Miller" Cc: Alexey Kuznetsov Cc: netdev@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/ipv4/ipconfig.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index f0f3f9f77b30..f02f594d04c5 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -143,8 +143,6 @@ __be32 ic_servaddr = NONE; /* Boot server IP address */ __be32 root_server_addr = NONE; /* Address of NFS server */ u8 root_server_path[256] = { 0, }; /* Path to mount as root */ -static __be32 ic_dev_xid; /* Device under configuration */ - /* vendor class identifier */ static char vendor_class_identifier[253] __initdata; @@ -654,6 +652,7 @@ static struct packet_type bootp_packet_type __initdata = { .func = ic_bootp_recv, }; +static __be32 ic_dev_xid; /* Device under configuration */ /* * Initialize DHCP/BOOTP extension fields in the request. -- cgit v1.2.3 From ff458f6f1e464ee5239bcf37af4028c01d0ccf45 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 9 Jul 2014 11:07:37 +0200 Subject: arc_emac: Use net_device_stats from struct net_device Instead of using a private copy of struct net_device_stats in struct arc_emac_priv, use stats from struct net_device. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller --- drivers/net/ethernet/arc/emac.h | 2 -- drivers/net/ethernet/arc/emac_main.c | 10 +++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h index 53f85bf71526..8e7c1a101af7 100644 --- a/drivers/net/ethernet/arc/emac.h +++ b/drivers/net/ethernet/arc/emac.h @@ -110,7 +110,6 @@ struct buffer_state { * @bus: Pointer to the current MII bus. * @regs: Base address of EMAC memory-mapped control registers. * @napi: Structure for NAPI. - * @stats: Network device statistics. * @rxbd: Pointer to Rx BD ring. * @txbd: Pointer to Tx BD ring. * @rxbd_dma: DMA handle for Rx BD ring. @@ -135,7 +134,6 @@ struct arc_emac_priv { struct clk *clk; struct napi_struct napi; - struct net_device_stats stats; struct arc_emac_bd *rxbd; struct arc_emac_bd *txbd; diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index 18e2faccebb0..6cfcd3826df0 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -140,7 +140,7 @@ static const struct ethtool_ops arc_emac_ethtool_ops = { static void arc_emac_tx_clean(struct net_device *ndev) { struct arc_emac_priv *priv = netdev_priv(ndev); - struct net_device_stats *stats = &priv->stats; + struct net_device_stats *stats = &ndev->stats; unsigned int i; for (i = 0; i < TX_BD_NUM; i++) { @@ -202,7 +202,7 @@ static int arc_emac_rx(struct net_device *ndev, int budget) for (work_done = 0; work_done < budget; work_done++) { unsigned int *last_rx_bd = &priv->last_rx_bd; - struct net_device_stats *stats = &priv->stats; + struct net_device_stats *stats = &ndev->stats; struct buffer_state *rx_buff = &priv->rx_buff[*last_rx_bd]; struct arc_emac_bd *rxbd = &priv->rxbd[*last_rx_bd]; unsigned int pktlen, info = le32_to_cpu(rxbd->info); @@ -318,7 +318,7 @@ static irqreturn_t arc_emac_intr(int irq, void *dev_instance) { struct net_device *ndev = dev_instance; struct arc_emac_priv *priv = netdev_priv(ndev); - struct net_device_stats *stats = &priv->stats; + struct net_device_stats *stats = &ndev->stats; unsigned int status; status = arc_reg_get(priv, R_STATUS); @@ -529,7 +529,7 @@ static int arc_emac_stop(struct net_device *ndev) static struct net_device_stats *arc_emac_stats(struct net_device *ndev) { struct arc_emac_priv *priv = netdev_priv(ndev); - struct net_device_stats *stats = &priv->stats; + struct net_device_stats *stats = &ndev->stats; unsigned long miss, rxerr; u8 rxcrc, rxfram, rxoflow; @@ -565,7 +565,7 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev) { struct arc_emac_priv *priv = netdev_priv(ndev); unsigned int len, *txbd_curr = &priv->txbd_curr; - struct net_device_stats *stats = &priv->stats; + struct net_device_stats *stats = &ndev->stats; __le32 *info = &priv->txbd[*txbd_curr].info; dma_addr_t addr; -- cgit v1.2.3 From 917ac48d94dfc9879197e70300230440bd820d3c Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 9 Jul 2014 11:07:56 +0200 Subject: arc_emac: Remove unused pointer to net_device from arc_emac_priv The pointer to the struct net_device in the private data is only assigned but never used, so delete it. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller --- drivers/net/ethernet/arc/emac.h | 2 -- drivers/net/ethernet/arc/emac_main.c | 1 - 2 files changed, 3 deletions(-) diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h index 8e7c1a101af7..36cc9bd07c47 100644 --- a/drivers/net/ethernet/arc/emac.h +++ b/drivers/net/ethernet/arc/emac.h @@ -105,7 +105,6 @@ struct buffer_state { /** * struct arc_emac_priv - Storage of EMAC's private information. * @dev: Pointer to the current device. - * @ndev: Pointer to the current network device. * @phy_dev: Pointer to attached PHY device. * @bus: Pointer to the current MII bus. * @regs: Base address of EMAC memory-mapped control registers. @@ -126,7 +125,6 @@ struct buffer_state { struct arc_emac_priv { /* Devices */ struct device *dev; - struct net_device *ndev; struct phy_device *phy_dev; struct mii_bus *bus; diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index 6cfcd3826df0..fe5cfeace6e3 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -720,7 +720,6 @@ static int arc_emac_probe(struct platform_device *pdev) priv = netdev_priv(ndev); priv->dev = &pdev->dev; - priv->ndev = ndev; priv->regs = devm_ioremap_resource(&pdev->dev, &res_regs); if (IS_ERR(priv->regs)) { -- cgit v1.2.3 From 316158feff0078b266d6e423adb016d12eb96a5a Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 9 Jul 2014 16:23:59 +0200 Subject: hyperv: Add netpoll support In order to have at least a netconsole to debug kernel issues on Windows Azure this patch implements netpoll support. Sending packets is easy, netvsc_start_xmit() does already everything needed. Signed-off-by: Richard Weinberger Acked-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 9b27ca8c1d39..a9c5eaadc426 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -749,6 +749,14 @@ static int netvsc_set_mac_addr(struct net_device *ndev, void *p) return err; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void netvsc_poll_controller(struct net_device *net) +{ + /* As netvsc_start_xmit() works synchronous we don't have to + * trigger anything here. + */ +} +#endif static const struct ethtool_ops ethtool_ops = { .get_drvinfo = netvsc_get_drvinfo, @@ -764,6 +772,9 @@ static const struct net_device_ops device_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = netvsc_set_mac_addr, .ndo_select_queue = netvsc_select_queue, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = netvsc_poll_controller, +#endif }; /* -- cgit v1.2.3 From 23acb2fc32ccf511368db38ac4af42ffa8a929bb Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 9 Jul 2014 17:36:46 -0700 Subject: net: systemport: align multiple lines correctly checkpatch.pl flagged a bunch of: "CHECK: Alignment should match open parenthesis" problems, fix all of them. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 117 ++++++++++++++--------------- 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 7a1bd2b3bc26..b6e4c7b418be 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -81,14 +81,14 @@ static inline void dma_desc_set_addr(struct bcm_sysport_priv *priv, { #ifdef CONFIG_PHYS_ADDR_T_64BIT __raw_writel(upper_32_bits(addr) & DESC_ADDR_HI_MASK, - d + DESC_ADDR_HI_STATUS_LEN); + d + DESC_ADDR_HI_STATUS_LEN); #endif __raw_writel(lower_32_bits(addr), d + DESC_ADDR_LO); } static inline void tdma_port_write_desc_addr(struct bcm_sysport_priv *priv, - struct dma_desc *desc, - unsigned int port) + struct dma_desc *desc, + unsigned int port) { /* Ports are latched, so write upper address first */ tdma_writel(priv, desc->addr_status_len, TDMA_WRITE_PORT_HI(port)); @@ -108,7 +108,7 @@ static int bcm_sysport_set_settings(struct net_device *dev, } static int bcm_sysport_get_settings(struct net_device *dev, - struct ethtool_cmd *cmd) + struct ethtool_cmd *cmd) { struct bcm_sysport_priv *priv = netdev_priv(dev); @@ -119,7 +119,7 @@ static int bcm_sysport_get_settings(struct net_device *dev, } static int bcm_sysport_set_rx_csum(struct net_device *dev, - netdev_features_t wanted) + netdev_features_t wanted) { struct bcm_sysport_priv *priv = netdev_priv(dev); u32 reg; @@ -145,7 +145,7 @@ static int bcm_sysport_set_rx_csum(struct net_device *dev, } static int bcm_sysport_set_tx_csum(struct net_device *dev, - netdev_features_t wanted) + netdev_features_t wanted) { struct bcm_sysport_priv *priv = netdev_priv(dev); u32 reg; @@ -165,7 +165,7 @@ static int bcm_sysport_set_tx_csum(struct net_device *dev, } static int bcm_sysport_set_features(struct net_device *dev, - netdev_features_t features) + netdev_features_t features) { netdev_features_t changed = features ^ dev->features; netdev_features_t wanted = dev->wanted_features; @@ -261,7 +261,7 @@ static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = { /* RXCHK misc statistics */ STAT_RXCHK("rxchk_bad_csum", mib.rxchk_bad_csum, RXCHK_BAD_CSUM_CNTR), STAT_RXCHK("rxchk_other_pkt_disc", mib.rxchk_other_pkt_disc, - RXCHK_OTHER_DISC_CNTR), + RXCHK_OTHER_DISC_CNTR), /* RBUF misc statistics */ STAT_RBUF("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt, RBUF_OVFL_DISC_CNTR), STAT_RBUF("rbuf_err_cnt", mib.rbuf_err_cnt, RBUF_ERR_PKT_CNTR), @@ -270,7 +270,7 @@ static const struct bcm_sysport_stats bcm_sysport_gstrings_stats[] = { #define BCM_SYSPORT_STATS_LEN ARRAY_SIZE(bcm_sysport_gstrings_stats) static void bcm_sysport_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) + struct ethtool_drvinfo *info) { strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); strlcpy(info->version, "0.1", sizeof(info->version)); @@ -303,7 +303,7 @@ static int bcm_sysport_get_sset_count(struct net_device *dev, int string_set) } static void bcm_sysport_get_strings(struct net_device *dev, - u32 stringset, u8 *data) + u32 stringset, u8 *data) { int i; @@ -311,8 +311,8 @@ static void bcm_sysport_get_strings(struct net_device *dev, case ETH_SS_STATS: for (i = 0; i < BCM_SYSPORT_STATS_LEN; i++) { memcpy(data + i * ETH_GSTRING_LEN, - bcm_sysport_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); + bcm_sysport_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); } break; default: @@ -362,7 +362,7 @@ static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv) } static void bcm_sysport_get_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) + struct ethtool_stats *stats, u64 *data) { struct bcm_sysport_priv *priv = netdev_priv(dev); int i; @@ -404,7 +404,7 @@ static void bcm_sysport_get_wol(struct net_device *dev, } static int bcm_sysport_set_wol(struct net_device *dev, - struct ethtool_wolinfo *wol) + struct ethtool_wolinfo *wol) { struct bcm_sysport_priv *priv = netdev_priv(dev); struct device *kdev = &priv->pdev->dev; @@ -419,9 +419,9 @@ static int bcm_sysport_set_wol(struct net_device *dev, /* Program the SecureOn password */ if (wol->wolopts & WAKE_MAGICSECURE) { umac_writel(priv, get_unaligned_be16(&wol->sopass[0]), - UMAC_PSW_MS); + UMAC_PSW_MS); umac_writel(priv, get_unaligned_be32(&wol->sopass[2]), - UMAC_PSW_LS); + UMAC_PSW_LS); } /* Flag the device and relevant IRQ as wakeup capable */ @@ -464,7 +464,7 @@ static int bcm_sysport_rx_refill(struct bcm_sysport_priv *priv, } mapping = dma_map_single(kdev, cb->skb->data, - RX_BUF_LENGTH, DMA_FROM_DEVICE); + RX_BUF_LENGTH, DMA_FROM_DEVICE); ret = dma_mapping_error(kdev, mapping); if (ret) { bcm_sysport_free_cb(cb); @@ -528,22 +528,20 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, to_process = p_index - priv->rx_c_index; netif_dbg(priv, rx_status, ndev, - "p_index=%d rx_c_index=%d to_process=%d\n", - p_index, priv->rx_c_index, to_process); - - while ((processed < to_process) && - (processed < budget)) { + "p_index=%d rx_c_index=%d to_process=%d\n", + p_index, priv->rx_c_index, to_process); + while ((processed < to_process) && (processed < budget)) { cb = &priv->rx_cbs[priv->rx_read_ptr]; skb = cb->skb; dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr), - RX_BUF_LENGTH, DMA_FROM_DEVICE); + RX_BUF_LENGTH, DMA_FROM_DEVICE); /* Extract the Receive Status Block prepended */ rsb = (struct bcm_rsb *)skb->data; len = (rsb->rx_status_len >> DESC_LEN_SHIFT) & DESC_LEN_MASK; status = (rsb->rx_status_len >> DESC_STATUS_SHIFT) & - DESC_STATUS_MASK; + DESC_STATUS_MASK; processed++; priv->rx_read_ptr++; @@ -551,9 +549,9 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv, priv->rx_read_ptr = 0; netif_dbg(priv, rx_status, ndev, - "p=%d, c=%d, rd_ptr=%d, len=%d, flag=0x%04x\n", - p_index, priv->rx_c_index, priv->rx_read_ptr, - len, status); + "p=%d, c=%d, rd_ptr=%d, len=%d, flag=0x%04x\n", + p_index, priv->rx_c_index, priv->rx_read_ptr, + len, status); if (unlikely(!skb)) { netif_err(priv, rx_err, ndev, "out of memory!\n"); @@ -612,9 +610,9 @@ refill: } static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_priv *priv, - struct bcm_sysport_cb *cb, - unsigned int *bytes_compl, - unsigned int *pkts_compl) + struct bcm_sysport_cb *cb, + unsigned int *bytes_compl, + unsigned int *pkts_compl) { struct device *kdev = &priv->pdev->dev; struct net_device *ndev = priv->netdev; @@ -623,8 +621,8 @@ static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_priv *priv, ndev->stats.tx_bytes += cb->skb->len; *bytes_compl += cb->skb->len; dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr), - dma_unmap_len(cb, dma_len), - DMA_TO_DEVICE); + dma_unmap_len(cb, dma_len), + DMA_TO_DEVICE); ndev->stats.tx_packets++; (*pkts_compl)++; bcm_sysport_free_cb(cb); @@ -632,7 +630,7 @@ static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_priv *priv, } else if (dma_unmap_addr(cb, dma_addr)) { ndev->stats.tx_bytes += dma_unmap_len(cb, dma_len); dma_unmap_page(kdev, dma_unmap_addr(cb, dma_addr), - dma_unmap_len(cb, dma_len), DMA_TO_DEVICE); + dma_unmap_len(cb, dma_len), DMA_TO_DEVICE); dma_unmap_addr_set(cb, dma_addr, 0); } } @@ -666,8 +664,8 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, last_tx_cn = num_tx_cbs - last_c_index + c_index; netif_dbg(priv, tx_done, ndev, - "ring=%d c_index=%d last_tx_cn=%d last_c_index=%d\n", - ring->index, c_index, last_tx_cn, last_c_index); + "ring=%d c_index=%d last_tx_cn=%d last_c_index=%d\n", + ring->index, c_index, last_tx_cn, last_c_index); while (last_tx_cn-- > 0) { cb = ring->cbs + last_c_index; @@ -684,8 +682,8 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, netif_tx_wake_queue(txq); netif_dbg(priv, tx_done, ndev, - "ring=%d c_index=%d pkts_compl=%d, bytes_compl=%d\n", - ring->index, ring->c_index, pkts_compl, bytes_compl); + "ring=%d c_index=%d pkts_compl=%d, bytes_compl=%d\n", + ring->index, ring->c_index, pkts_compl, bytes_compl); return pkts_compl; } @@ -890,8 +888,9 @@ static int bcm_sysport_insert_tsb(struct sk_buff *skb, struct net_device *dev) csum_info |= L4_LENGTH_VALID; if (ip_proto == IPPROTO_UDP && ip_ver == ETH_P_IP) csum_info |= L4_UDP; - } else + } else { csum_info = 0; + } tsb->l4_ptr_dest_map = csum_info; } @@ -955,7 +954,7 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb, mapping = dma_map_single(kdev, skb->data, skb_len, DMA_TO_DEVICE); if (dma_mapping_error(kdev, mapping)) { netif_err(priv, tx_err, dev, "DMA map failed at %p (len=%d)\n", - skb->data, skb_len); + skb->data, skb_len); ret = NETDEV_TX_OK; goto out; } @@ -973,7 +972,7 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb, len_status = upper_32_bits(mapping) & DESC_ADDR_HI_MASK; len_status |= (skb_len << DESC_LEN_SHIFT); len_status |= (DESC_SOP | DESC_EOP | TX_STATUS_APP_CRC) << - DESC_STATUS_SHIFT; + DESC_STATUS_SHIFT; if (skb->ip_summed == CHECKSUM_PARTIAL) len_status |= (DESC_L4_CSUM << DESC_STATUS_SHIFT); @@ -998,7 +997,7 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb, netif_tx_stop_queue(txq); netif_dbg(priv, tx_queued, dev, "ring=%d desc_count=%d, curr_desc=%d\n", - ring->index, ring->desc_count, ring->curr_desc); + ring->index, ring->desc_count, ring->curr_desc); ret = NETDEV_TX_OK; out: @@ -1136,14 +1135,14 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv, napi_enable(&ring->napi); netif_dbg(priv, hw, priv->netdev, - "TDMA cfg, size=%d, desc_cpu=%p\n", - ring->size, ring->desc_cpu); + "TDMA cfg, size=%d, desc_cpu=%p\n", + ring->size, ring->desc_cpu); return 0; } static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv, - unsigned int index) + unsigned int index) { struct bcm_sysport_tx_ring *ring = &priv->tx_rings[index]; struct device *kdev = &priv->pdev->dev; @@ -1174,7 +1173,7 @@ static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv, /* RDMA helper */ static inline int rdma_enable_set(struct bcm_sysport_priv *priv, - unsigned int enable) + unsigned int enable) { unsigned int timeout = 1000; u32 reg; @@ -1201,7 +1200,7 @@ static inline int rdma_enable_set(struct bcm_sysport_priv *priv, /* TDMA helper */ static inline int tdma_enable_set(struct bcm_sysport_priv *priv, - unsigned int enable) + unsigned int enable) { unsigned int timeout = 1000; u32 reg; @@ -1272,8 +1271,8 @@ static int bcm_sysport_init_rx_ring(struct bcm_sysport_priv *priv) rdma_writel(priv, 1, RDMA_MBDONE_INTR); netif_dbg(priv, hw, priv->netdev, - "RDMA cfg, num_rx_bds=%d, rx_bds=%p\n", - priv->num_rx_bds, priv->rx_bds); + "RDMA cfg, num_rx_bds=%d, rx_bds=%p\n", + priv->num_rx_bds, priv->rx_bds); return 0; } @@ -1293,8 +1292,8 @@ static void bcm_sysport_fini_rx_ring(struct bcm_sysport_priv *priv) cb = &priv->rx_cbs[i]; if (dma_unmap_addr(cb, dma_addr)) dma_unmap_single(&priv->pdev->dev, - dma_unmap_addr(cb, dma_addr), - RX_BUF_LENGTH, DMA_FROM_DEVICE); + dma_unmap_addr(cb, dma_addr), + RX_BUF_LENGTH, DMA_FROM_DEVICE); bcm_sysport_free_cb(cb); } @@ -1322,7 +1321,7 @@ static void bcm_sysport_set_rx_mode(struct net_device *dev) } static inline void umac_enable_set(struct bcm_sysport_priv *priv, - u32 mask, unsigned int enable) + u32 mask, unsigned int enable) { u32 reg; @@ -1365,7 +1364,7 @@ static inline int umac_reset(struct bcm_sysport_priv *priv) } static void umac_set_hw_addr(struct bcm_sysport_priv *priv, - unsigned char *addr) + unsigned char *addr) { umac_writel(priv, (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3], UMAC_MAC0); @@ -1474,7 +1473,7 @@ static int bcm_sysport_open(struct net_device *dev) ret = bcm_sysport_init_tx_ring(priv, i); if (ret) { netdev_err(dev, "failed to initialize TX ring %d\n", - i); + i); goto out_free_tx_ring; } } @@ -1692,7 +1691,7 @@ static int bcm_sysport_probe(struct platform_device *pdev) /* Request the WOL interrupt and advertise suspend if available */ priv->wol_irq_disabled = 1; ret = devm_request_irq(&pdev->dev, priv->wol_irq, - bcm_sysport_wol_isr, 0, dev->name, priv); + bcm_sysport_wol_isr, 0, dev->name, priv); if (!ret) device_set_wakeup_capable(&pdev->dev, 1); @@ -1717,10 +1716,10 @@ static int bcm_sysport_probe(struct platform_device *pdev) priv->rev = topctrl_readl(priv, REV_CNTL) & REV_MASK; dev_info(&pdev->dev, - "Broadcom SYSTEMPORT" REV_FMT - " at 0x%p (irqs: %d, %d, TXQs: %d, RXQs: %d)\n", - (priv->rev >> 8) & 0xff, priv->rev & 0xff, - priv->base, priv->irq0, priv->irq1, txq, rxq); + "Broadcom SYSTEMPORT" REV_FMT + " at 0x%p (irqs: %d, %d, TXQs: %d, RXQs: %d)\n", + (priv->rev >> 8) & 0xff, priv->rev & 0xff, + priv->base, priv->irq0, priv->irq1, txq, rxq); return 0; err: @@ -1869,7 +1868,7 @@ static int bcm_sysport_resume(struct device *d) ret = bcm_sysport_init_tx_ring(priv, i); if (ret) { netdev_err(dev, "failed to initialize TX ring %d\n", - i); + i); goto out_free_tx_rings; } } -- cgit v1.2.3 From 40a8a317a02ea516e89ee71d8d355babf0617e5f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 9 Jul 2014 17:36:47 -0700 Subject: net: systemport: use kcalloc instead of kzalloc checkpatch.pl flagged two uses of kzalloc() for allocating and zeroing arrays, use kcalloc() instead as recommended. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index b6e4c7b418be..31b5340c685e 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1095,7 +1095,7 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv, return -ENOMEM; } - ring->cbs = kzalloc(sizeof(struct bcm_sysport_cb) * size, GFP_KERNEL); + ring->cbs = kcalloc(size, sizeof(struct bcm_sysport_cb), GFP_KERNEL); if (!ring->cbs) { netif_err(priv, hw, priv->netdev, "CB allocation failed\n"); return -ENOMEM; @@ -1238,8 +1238,8 @@ static int bcm_sysport_init_rx_ring(struct bcm_sysport_priv *priv) priv->rx_bd_assign_index = 0; priv->rx_c_index = 0; priv->rx_read_ptr = 0; - priv->rx_cbs = kzalloc(priv->num_rx_bds * - sizeof(struct bcm_sysport_cb), GFP_KERNEL); + priv->rx_cbs = kcalloc(priv->num_rx_bds, sizeof(struct bcm_sysport_cb), + GFP_KERNEL); if (!priv->rx_cbs) { netif_err(priv, hw, priv->netdev, "CB allocation failed\n"); return -ENOMEM; -- cgit v1.2.3 From 405fd707196d596f59a510d176dedc979c1ae34b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 9 Jul 2014 22:25:18 -0700 Subject: ipconfig: Only bootp paths should reference ic_dev_xid. It is only tested, and declared, in the bootp code. So, in ic_dynamic() guard it's setting with IPCONFIG_BOOTP. Signed-off-by: David S. Miller --- net/ipv4/ipconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index f02f594d04c5..5bbef4fdcb43 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -1217,10 +1217,10 @@ static int __init ic_dynamic(void) get_random_bytes(&timeout, sizeof(timeout)); timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned int) CONF_TIMEOUT_RANDOM); for (;;) { +#ifdef IPCONFIG_BOOTP /* Track the device we are configuring */ ic_dev_xid = d->xid; -#ifdef IPCONFIG_BOOTP if (do_bootp && (d->able & IC_BOOTP)) ic_bootp_send_if(d, jiffies - start_jiffies); #endif -- cgit v1.2.3 From af5951545164d0849f86e1a9ab8948ff17170395 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 10 Jul 2014 11:05:39 +0530 Subject: net: cpmac: remove space in macro defination This patch fix the space after '#' in macro defination Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpmac.c | 82 ++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index 7399a52f7c26..61eb69145b30 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -67,42 +67,42 @@ MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus"); #define CPMAC_RX_CONTROL 0x0014 #define CPMAC_RX_TEARDOWN 0x0018 #define CPMAC_MBP 0x0100 -# define MBP_RXPASSCRC 0x40000000 -# define MBP_RXQOS 0x20000000 -# define MBP_RXNOCHAIN 0x10000000 -# define MBP_RXCMF 0x01000000 -# define MBP_RXSHORT 0x00800000 -# define MBP_RXCEF 0x00400000 -# define MBP_RXPROMISC 0x00200000 -# define MBP_PROMISCCHAN(channel) (((channel) & 0x7) << 16) -# define MBP_RXBCAST 0x00002000 -# define MBP_BCASTCHAN(channel) (((channel) & 0x7) << 8) -# define MBP_RXMCAST 0x00000020 -# define MBP_MCASTCHAN(channel) ((channel) & 0x7) +#define MBP_RXPASSCRC 0x40000000 +#define MBP_RXQOS 0x20000000 +#define MBP_RXNOCHAIN 0x10000000 +#define MBP_RXCMF 0x01000000 +#define MBP_RXSHORT 0x00800000 +#define MBP_RXCEF 0x00400000 +#define MBP_RXPROMISC 0x00200000 +#define MBP_PROMISCCHAN(channel) (((channel) & 0x7) << 16) +#define MBP_RXBCAST 0x00002000 +#define MBP_BCASTCHAN(channel) (((channel) & 0x7) << 8) +#define MBP_RXMCAST 0x00000020 +#define MBP_MCASTCHAN(channel) ((channel) & 0x7) #define CPMAC_UNICAST_ENABLE 0x0104 #define CPMAC_UNICAST_CLEAR 0x0108 #define CPMAC_MAX_LENGTH 0x010c #define CPMAC_BUFFER_OFFSET 0x0110 #define CPMAC_MAC_CONTROL 0x0160 -# define MAC_TXPTYPE 0x00000200 -# define MAC_TXPACE 0x00000040 -# define MAC_MII 0x00000020 -# define MAC_TXFLOW 0x00000010 -# define MAC_RXFLOW 0x00000008 -# define MAC_MTEST 0x00000004 -# define MAC_LOOPBACK 0x00000002 -# define MAC_FDX 0x00000001 +#define MAC_TXPTYPE 0x00000200 +#define MAC_TXPACE 0x00000040 +#define MAC_MII 0x00000020 +#define MAC_TXFLOW 0x00000010 +#define MAC_RXFLOW 0x00000008 +#define MAC_MTEST 0x00000004 +#define MAC_LOOPBACK 0x00000002 +#define MAC_FDX 0x00000001 #define CPMAC_MAC_STATUS 0x0164 -# define MAC_STATUS_QOS 0x00000004 -# define MAC_STATUS_RXFLOW 0x00000002 -# define MAC_STATUS_TXFLOW 0x00000001 +#define MAC_STATUS_QOS 0x00000004 +#define MAC_STATUS_RXFLOW 0x00000002 +#define MAC_STATUS_TXFLOW 0x00000001 #define CPMAC_TX_INT_ENABLE 0x0178 #define CPMAC_TX_INT_CLEAR 0x017c #define CPMAC_MAC_INT_VECTOR 0x0180 -# define MAC_INT_STATUS 0x00080000 -# define MAC_INT_HOST 0x00040000 -# define MAC_INT_RX 0x00020000 -# define MAC_INT_TX 0x00010000 +#define MAC_INT_STATUS 0x00080000 +#define MAC_INT_HOST 0x00040000 +#define MAC_INT_RX 0x00020000 +#define MAC_INT_TX 0x00010000 #define CPMAC_MAC_EOI_VECTOR 0x0184 #define CPMAC_RX_INT_ENABLE 0x0198 #define CPMAC_RX_INT_CLEAR 0x019c @@ -157,24 +157,24 @@ MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus"); /* MDIO bus */ #define CPMAC_MDIO_VERSION 0x0000 #define CPMAC_MDIO_CONTROL 0x0004 -# define MDIOC_IDLE 0x80000000 -# define MDIOC_ENABLE 0x40000000 -# define MDIOC_PREAMBLE 0x00100000 -# define MDIOC_FAULT 0x00080000 -# define MDIOC_FAULTDETECT 0x00040000 -# define MDIOC_INTTEST 0x00020000 -# define MDIOC_CLKDIV(div) ((div) & 0xff) +#define MDIOC_IDLE 0x80000000 +#define MDIOC_ENABLE 0x40000000 +#define MDIOC_PREAMBLE 0x00100000 +#define MDIOC_FAULT 0x00080000 +#define MDIOC_FAULTDETECT 0x00040000 +#define MDIOC_INTTEST 0x00020000 +#define MDIOC_CLKDIV(div) ((div) & 0xff) #define CPMAC_MDIO_ALIVE 0x0008 #define CPMAC_MDIO_LINK 0x000c #define CPMAC_MDIO_ACCESS(channel) (0x0080 + (channel) * 8) -# define MDIO_BUSY 0x80000000 -# define MDIO_WRITE 0x40000000 -# define MDIO_REG(reg) (((reg) & 0x1f) << 21) -# define MDIO_PHY(phy) (((phy) & 0x1f) << 16) -# define MDIO_DATA(data) ((data) & 0xffff) +#define MDIO_BUSY 0x80000000 +#define MDIO_WRITE 0x40000000 +#define MDIO_REG(reg) (((reg) & 0x1f) << 21) +#define MDIO_PHY(phy) (((phy) & 0x1f) << 16) +#define MDIO_DATA(data) ((data) & 0xffff) #define CPMAC_MDIO_PHYSEL(channel) (0x0084 + (channel) * 8) -# define PHYSEL_LINKSEL 0x00000040 -# define PHYSEL_LINKINT 0x00000020 +#define PHYSEL_LINKSEL 0x00000040 +#define PHYSEL_LINKINT 0x00000020 struct cpmac_desc { u32 hw_next; -- cgit v1.2.3 From 8bcd5c6d513274f93d81584ad5b2d6b1841f63aa Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 10 Jul 2014 11:05:40 +0530 Subject: net: cpmac: fix comments This patch convert the normal comments to networking subsystem style comments. Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpmac.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index 61eb69145b30..1d8ef39f370f 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -118,8 +118,8 @@ MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus"); #define CPMAC_TX_ACK(channel) (0x0640 + (channel) * 4) #define CPMAC_RX_ACK(channel) (0x0660 + (channel) * 4) #define CPMAC_REG_END 0x0680 -/* - * Rx/Tx statistics + +/* Rx/Tx statistics * TODO: use some of them to fill stats in cpmac_stats() */ #define CPMAC_STATS_RX_GOOD 0x0200 @@ -331,8 +331,7 @@ static void cpmac_set_multicast_list(struct net_device *dev) cpmac_write(priv->regs, CPMAC_MAC_HASH_LO, 0xffffffff); cpmac_write(priv->regs, CPMAC_MAC_HASH_HI, 0xffffffff); } else { - /* - * cpmac uses some strange mac address hashing + /* cpmac uses some strange mac address hashing * (not crc32) */ netdev_for_each_mc_addr(ha, dev) { @@ -432,10 +431,10 @@ static int cpmac_poll(struct napi_struct *napi, int budget) if ((desc->dataflags & CPMAC_EOQ) != 0) { /* The last update to eoq->hw_next didn't happen - * soon enough, and the receiver stopped here. - *Remember this descriptor so we can restart - * the receiver after freeing some space. - */ + * soon enough, and the receiver stopped here. + * Remember this descriptor so we can restart + * the receiver after freeing some space. + */ if (unlikely(restart)) { if (netif_msg_rx_err(priv)) printk(KERN_ERR "%s: poll found a" @@ -457,25 +456,27 @@ static int cpmac_poll(struct napi_struct *napi, int budget) if (desc != priv->rx_head) { /* We freed some buffers, but not the whole ring, - * add what we did free to the rx list */ + * add what we did free to the rx list + */ desc->prev->hw_next = (u32)0; priv->rx_head->prev->hw_next = priv->rx_head->mapping; } /* Optimization: If we did not actually process an EOQ (perhaps because * of quota limits), check to see if the tail of the queue has EOQ set. - * We should immediately restart in that case so that the receiver can - * restart and run in parallel with more packet processing. - * This lets us handle slightly larger bursts before running - * out of ring space (assuming dev->weight < ring_size) */ + * We should immediately restart in that case so that the receiver can + * restart and run in parallel with more packet processing. + * This lets us handle slightly larger bursts before running + * out of ring space (assuming dev->weight < ring_size) + */ if (!restart && (priv->rx_head->prev->dataflags & (CPMAC_OWN|CPMAC_EOQ)) == CPMAC_EOQ && (priv->rx_head->dataflags & CPMAC_OWN) != 0) { /* reset EOQ so the poll loop (above) doesn't try to - * restart this when it eventually gets to this descriptor. - */ + * restart this when it eventually gets to this descriptor. + */ priv->rx_head->prev->dataflags &= ~CPMAC_EOQ; restart = priv->rx_head; } @@ -506,7 +507,8 @@ static int cpmac_poll(struct napi_struct *napi, int budget) priv->dev->name, received); if (processed == 0) { /* we ran out of packets to read, - * revert to interrupt-driven mode */ + * revert to interrupt-driven mode + */ napi_complete(napi); cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1); return 0; @@ -516,8 +518,8 @@ static int cpmac_poll(struct napi_struct *napi, int budget) fatal_error: /* Something went horribly wrong. - * Reset hardware to try to recover rather than wedging. */ - + * Reset hardware to try to recover rather than wedging. + */ if (netif_msg_drv(priv)) { printk(KERN_ERR "%s: cpmac_poll is confused. " "Resetting hardware\n", priv->dev->name); @@ -751,7 +753,7 @@ static void cpmac_check_status(struct net_device *dev) if (rx_code || tx_code) { if (netif_msg_drv(priv) && net_ratelimit()) { /* Can't find any documentation on what these - *error codes actually are. So just log them and hope.. + * error codes actually are. So just log them and hope.. */ if (rx_code) printk(KERN_WARNING "%s: host error %d on rx " -- cgit v1.2.3 From f160a2d0b524eeebd97a68e2fbb59fad4cdd3fee Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 10 Jul 2014 11:05:41 +0530 Subject: net: cpmac: dynamic debug fixes This patch does the following changes 1. convert printk(KERN_DEBUG.. to netdev_dbg() if we have net_device object or convert to dev_dbg() if we have device object. 2. convert printk(KERN_WARNING.. to netdev_warn() if we have net_device object or convert to dev_warn() if we have device object 3. convert printk() to pr_* Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpmac.c | 136 ++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 74 deletions(-) diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index 1d8ef39f370f..9faf6699561e 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -228,21 +228,20 @@ static void cpmac_dump_regs(struct net_device *dev) if (i % 16 == 0) { if (i) pr_cont("\n"); - printk(KERN_DEBUG "%s: reg[%p]:", dev->name, - priv->regs + i); + netdev_dbg(dev, "reg[%p]:", priv->regs + i); } - printk(" %08x", cpmac_read(priv->regs, i)); + pr_debug(" %08x", cpmac_read(priv->regs, i)); } - printk("\n"); + pr_debug("\n"); } static void cpmac_dump_desc(struct net_device *dev, struct cpmac_desc *desc) { int i; - printk(KERN_DEBUG "%s: desc[%p]:", dev->name, desc); + netdev_dbg(dev, "desc[%p]:", desc); for (i = 0; i < sizeof(*desc) / 4; i++) - printk(" %08x", ((u32 *)desc)[i]); - printk("\n"); + pr_debug(" %08x", ((u32 *)desc)[i]); + pr_debug("\n"); } static void cpmac_dump_all_desc(struct net_device *dev) @@ -258,17 +257,16 @@ static void cpmac_dump_all_desc(struct net_device *dev) static void cpmac_dump_skb(struct net_device *dev, struct sk_buff *skb) { int i; - printk(KERN_DEBUG "%s: skb 0x%p, len=%d\n", dev->name, skb, skb->len); + netdev_dbg(dev, "skb 0x%p, len=%d\n", skb, skb->len); for (i = 0; i < skb->len; i++) { if (i % 16 == 0) { if (i) pr_cont("\n"); - printk(KERN_DEBUG "%s: data[%p]:", dev->name, - skb->data + i); + netdev_dbg(dev, "data[%p]:", skb->data + i); } - printk(" %02x", ((u8 *)skb->data)[i]); + pr_debug(" %02x", ((u8 *)skb->data)[i]); } - printk("\n"); + pr_debug("\n"); } static int cpmac_mdio_read(struct mii_bus *bus, int phy_id, int reg) @@ -300,7 +298,7 @@ static int cpmac_mdio_reset(struct mii_bus *bus) cpmac_clk = clk_get(&bus->dev, "cpmac"); if (IS_ERR(cpmac_clk)) { - printk(KERN_ERR "unable to get cpmac clock\n"); + pr_err("unable to get cpmac clock\n"); return -1; } ar7_device_reset(AR7_RESET_BIT_MDIO); @@ -368,8 +366,8 @@ static struct sk_buff *cpmac_rx_one(struct cpmac_priv *priv, cpmac_write(priv->regs, CPMAC_RX_ACK(0), (u32)desc->mapping); if (unlikely(!desc->datalen)) { if (netif_msg_rx_err(priv) && net_ratelimit()) - printk(KERN_WARNING "%s: rx: spurious interrupt\n", - priv->dev->name); + netdev_warn(priv->dev, "rx: spurious interrupt\n"); + return NULL; } @@ -389,15 +387,14 @@ static struct sk_buff *cpmac_rx_one(struct cpmac_priv *priv, DMA_FROM_DEVICE); desc->hw_data = (u32)desc->data_mapping; if (unlikely(netif_msg_pktdata(priv))) { - printk(KERN_DEBUG "%s: received packet:\n", - priv->dev->name); + netdev_dbg(priv->dev, "received packet:\n"); cpmac_dump_skb(priv->dev, result); } } else { if (netif_msg_rx_err(priv) && net_ratelimit()) - printk(KERN_WARNING - "%s: low on skbs, dropping packet\n", - priv->dev->name); + netdev_warn(priv->dev, + "low on skbs, dropping packet\n"); + priv->dev->stats.rx_dropped++; } @@ -417,8 +414,8 @@ static int cpmac_poll(struct napi_struct *napi, int budget) spin_lock(&priv->rx_lock); if (unlikely(!priv->rx_head)) { if (netif_msg_rx_err(priv) && net_ratelimit()) - printk(KERN_WARNING "%s: rx: polling, but no queue\n", - priv->dev->name); + netdev_warn(priv->dev, "rx: polling, but no queue\n"); + spin_unlock(&priv->rx_lock); napi_complete(napi); return 0; @@ -437,9 +434,9 @@ static int cpmac_poll(struct napi_struct *napi, int budget) */ if (unlikely(restart)) { if (netif_msg_rx_err(priv)) - printk(KERN_ERR "%s: poll found a" - " duplicate EOQ: %p and %p\n", - priv->dev->name, restart, desc); + netdev_err(priv->dev, "poll found a" + " duplicate EOQ: %p and %p\n", + restart, desc); goto fatal_error; } @@ -485,15 +482,13 @@ static int cpmac_poll(struct napi_struct *napi, int budget) priv->dev->stats.rx_errors++; priv->dev->stats.rx_fifo_errors++; if (netif_msg_rx_err(priv) && net_ratelimit()) - printk(KERN_WARNING "%s: rx dma ring overrun\n", - priv->dev->name); + netdev_warn(priv->dev, "rx dma ring overrun\n"); if (unlikely((restart->dataflags & CPMAC_OWN) == 0)) { if (netif_msg_drv(priv)) - printk(KERN_ERR "%s: cpmac_poll is trying to " - "restart rx from a descriptor that's " - "not free: %p\n", - priv->dev->name, restart); + netdev_err(priv->dev, "cpmac_poll is trying " + "to restart rx from a descriptor " + "that's not free: %p\n", restart); goto fatal_error; } @@ -503,8 +498,8 @@ static int cpmac_poll(struct napi_struct *napi, int budget) priv->rx_head = desc; spin_unlock(&priv->rx_lock); if (unlikely(netif_msg_rx_status(priv))) - printk(KERN_DEBUG "%s: poll processed %d packets\n", - priv->dev->name, received); + netdev_dbg(priv->dev, "poll processed %d packets\n", received); + if (processed == 0) { /* we ran out of packets to read, * revert to interrupt-driven mode @@ -521,13 +516,12 @@ fatal_error: * Reset hardware to try to recover rather than wedging. */ if (netif_msg_drv(priv)) { - printk(KERN_ERR "%s: cpmac_poll is confused. " - "Resetting hardware\n", priv->dev->name); + netdev_err(priv->dev, "cpmac_poll is confused. " + "Resetting hardware\n"); cpmac_dump_all_desc(priv->dev); - printk(KERN_DEBUG "%s: RX_PTR(0)=0x%08x RX_ACK(0)=0x%08x\n", - priv->dev->name, - cpmac_read(priv->regs, CPMAC_RX_PTR(0)), - cpmac_read(priv->regs, CPMAC_RX_ACK(0))); + netdev_dbg(priv->dev, "RX_PTR(0)=0x%08x RX_ACK(0)=0x%08x\n", + cpmac_read(priv->regs, CPMAC_RX_PTR(0)), + cpmac_read(priv->regs, CPMAC_RX_ACK(0))); } spin_unlock(&priv->rx_lock); @@ -562,8 +556,8 @@ static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev) desc = &priv->desc_ring[queue]; if (unlikely(desc->dataflags & CPMAC_OWN)) { if (netif_msg_tx_err(priv) && net_ratelimit()) - printk(KERN_WARNING "%s: tx dma ring full\n", - dev->name); + netdev_warn(dev, "tx dma ring full\n"); + return NETDEV_TX_BUSY; } @@ -577,8 +571,7 @@ static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev) desc->datalen = len; desc->buflen = len; if (unlikely(netif_msg_tx_queued(priv))) - printk(KERN_DEBUG "%s: sending 0x%p, len=%d\n", dev->name, skb, - skb->len); + netdev_dbg(dev, "sending 0x%p, len=%d\n", skb, skb->len); if (unlikely(netif_msg_hw(priv))) cpmac_dump_desc(dev, desc); if (unlikely(netif_msg_pktdata(priv))) @@ -604,8 +597,8 @@ static void cpmac_end_xmit(struct net_device *dev, int queue) DMA_TO_DEVICE); if (unlikely(netif_msg_tx_done(priv))) - printk(KERN_DEBUG "%s: sent 0x%p, len=%d\n", dev->name, - desc->skb, desc->skb->len); + netdev_dbg(dev, "sent 0x%p, len=%d\n", + desc->skb, desc->skb->len); dev_kfree_skb_irq(desc->skb); desc->skb = NULL; @@ -613,8 +606,7 @@ static void cpmac_end_xmit(struct net_device *dev, int queue) netif_wake_subqueue(dev, queue); } else { if (netif_msg_tx_err(priv) && net_ratelimit()) - printk(KERN_WARNING - "%s: end_xmit: spurious interrupt\n", dev->name); + netdev_warn(dev, "end_xmit: spurious interrupt\n"); if (__netif_subqueue_stopped(dev, queue)) netif_wake_subqueue(dev, queue); } @@ -695,8 +687,7 @@ static void cpmac_clear_rx(struct net_device *dev) for (i = 0; i < priv->ring_size; i++) { if ((desc->dataflags & CPMAC_OWN) == 0) { if (netif_msg_rx_err(priv) && net_ratelimit()) - printk(KERN_WARNING "%s: packet dropped\n", - dev->name); + netdev_warn(dev, "packet dropped\n"); if (unlikely(netif_msg_hw(priv))) cpmac_dump_desc(dev, desc); desc->dataflags = CPMAC_OWN; @@ -756,13 +747,13 @@ static void cpmac_check_status(struct net_device *dev) * error codes actually are. So just log them and hope.. */ if (rx_code) - printk(KERN_WARNING "%s: host error %d on rx " - "channel %d (macstatus %08x), resetting\n", - dev->name, rx_code, rx_channel, macstatus); + netdev_warn(dev, "host error %d on rx " + "channel %d (macstatus %08x), resetting\n", + rx_code, rx_channel, macstatus); if (tx_code) - printk(KERN_WARNING "%s: host error %d on tx " - "channel %d (macstatus %08x), resetting\n", - dev->name, tx_code, tx_channel, macstatus); + netdev_warn(dev, "host error %d on tx " + "channel %d (macstatus %08x), resetting\n", + tx_code, tx_channel, macstatus); } netif_tx_stop_all_queues(dev); @@ -787,8 +778,7 @@ static irqreturn_t cpmac_irq(int irq, void *dev_id) status = cpmac_read(priv->regs, CPMAC_MAC_INT_VECTOR); if (unlikely(netif_msg_intr(priv))) - printk(KERN_DEBUG "%s: interrupt status: 0x%08x\n", dev->name, - status); + netdev_dbg(dev, "interrupt status: 0x%08x\n", status); if (status & MAC_INT_TX) cpmac_end_xmit(dev, (status & 7)); @@ -817,7 +807,7 @@ static void cpmac_tx_timeout(struct net_device *dev) dev->stats.tx_errors++; spin_unlock(&priv->lock); if (netif_msg_tx_err(priv) && net_ratelimit()) - printk(KERN_WARNING "%s: transmit timeout\n", dev->name); + netdev_warn(dev, "transmit timeout\n"); atomic_inc(&priv->reset_pending); barrier(); @@ -953,8 +943,8 @@ static int cpmac_open(struct net_device *dev) mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs"); if (!request_mem_region(mem->start, resource_size(mem), dev->name)) { if (netif_msg_drv(priv)) - printk(KERN_ERR "%s: failed to request registers\n", - dev->name); + netdev_err(dev, "failed to request registers\n"); + res = -ENXIO; goto fail_reserve; } @@ -962,8 +952,8 @@ static int cpmac_open(struct net_device *dev) priv->regs = ioremap(mem->start, resource_size(mem)); if (!priv->regs) { if (netif_msg_drv(priv)) - printk(KERN_ERR "%s: failed to remap registers\n", - dev->name); + netdev_err(dev, "failed to remap registers\n"); + res = -ENXIO; goto fail_remap; } @@ -1005,8 +995,8 @@ static int cpmac_open(struct net_device *dev) res = request_irq(dev->irq, cpmac_irq, IRQF_SHARED, dev->name, dev); if (res) { if (netif_msg_drv(priv)) - printk(KERN_ERR "%s: failed to obtain irq\n", - dev->name); + netdev_err(dev, "failed to obtain irq\n"); + goto fail_irq; } @@ -1123,7 +1113,7 @@ static int cpmac_probe(struct platform_device *pdev) if (phy_id == PHY_MAX_ADDR) { dev_err(&pdev->dev, "no PHY present, falling back " - "to switch on MDIO bus 0\n"); + "to switch on MDIO bus 0\n"); strncpy(mdio_bus_id, "fixed-0", MII_BUS_ID_SIZE); /* fixed phys bus */ phy_id = pdev->id; } @@ -1164,24 +1154,22 @@ static int cpmac_probe(struct platform_device *pdev) if (IS_ERR(priv->phy)) { if (netif_msg_drv(priv)) - printk(KERN_ERR "%s: Could not attach to PHY\n", - dev->name); + dev_err(&pdev->dev, "Could not attach to PHY\n"); + rc = PTR_ERR(priv->phy); goto fail; } rc = register_netdev(dev); if (rc) { - printk(KERN_ERR "cpmac: error %i registering device %s\n", rc, - dev->name); + dev_err(&pdev->dev, "Could not register net device\n"); goto fail; } if (netif_msg_probe(priv)) { - printk(KERN_INFO - "cpmac: device %s (regs: %p, irq: %d, phy: %s, " - "mac: %pM)\n", dev->name, (void *)mem->start, dev->irq, - priv->phy_name, dev->dev_addr); + dev_info(&pdev->dev, "regs: %p, irq: %d, phy: %s, " + "mac: %pM\n", (void *)mem->start, dev->irq, + priv->phy_name, dev->dev_addr); } return 0; @@ -1223,7 +1211,7 @@ int cpmac_init(void) cpmac_mii->priv = ioremap(AR7_REGS_MDIO, 256); if (!cpmac_mii->priv) { - printk(KERN_ERR "Can't ioremap mdio registers\n"); + pr_err("Can't ioremap mdio registers\n"); res = -ENXIO; goto fail_alloc; } -- cgit v1.2.3 From 96a8d3c141f23264281a48917eb2189a1566fda5 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 10 Jul 2014 11:05:42 +0530 Subject: net: cpmac: fix cpmac driver structure This patch changes to style of declarattion which follows every driver Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpmac.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index 9faf6699561e..1520c190cfd3 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -1187,9 +1187,11 @@ static int cpmac_remove(struct platform_device *pdev) } static struct platform_driver cpmac_driver = { - .driver.name = "cpmac", - .driver.owner = THIS_MODULE, - .probe = cpmac_probe, + .driver = { + .name = "cpmac", + .owner = THIS_MODULE, + }, + .probe = cpmac_probe, .remove = cpmac_remove, }; -- cgit v1.2.3 From 59329d8bc4c6b52a7f8d146fa782c6346bc409f0 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 10 Jul 2014 11:05:43 +0530 Subject: net: cpmac: fix missing a blank line after declarations This patch insert a blank line after declaration Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpmac.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index 1520c190cfd3..3d3ead4a0f6f 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -224,6 +224,7 @@ static void cpmac_dump_regs(struct net_device *dev) { int i; struct cpmac_priv *priv = netdev_priv(dev); + for (i = 0; i < CPMAC_REG_END; i += 4) { if (i % 16 == 0) { if (i) @@ -238,6 +239,7 @@ static void cpmac_dump_regs(struct net_device *dev) static void cpmac_dump_desc(struct net_device *dev, struct cpmac_desc *desc) { int i; + netdev_dbg(dev, "desc[%p]:", desc); for (i = 0; i < sizeof(*desc) / 4; i++) pr_debug(" %08x", ((u32 *)desc)[i]); @@ -248,6 +250,7 @@ static void cpmac_dump_all_desc(struct net_device *dev) { struct cpmac_priv *priv = netdev_priv(dev); struct cpmac_desc *dump = priv->rx_head; + do { cpmac_dump_desc(dev, dump); dump = dump->next; @@ -257,6 +260,7 @@ static void cpmac_dump_all_desc(struct net_device *dev) static void cpmac_dump_skb(struct net_device *dev, struct sk_buff *skb) { int i; + netdev_dbg(dev, "skb 0x%p, len=%d\n", skb, skb->len); for (i = 0; i < skb->len; i++) { if (i % 16 == 0) { @@ -681,6 +685,7 @@ static void cpmac_clear_rx(struct net_device *dev) struct cpmac_priv *priv = netdev_priv(dev); struct cpmac_desc *desc; int i; + if (unlikely(!priv->rx_head)) return; desc = priv->rx_head; @@ -703,6 +708,7 @@ static void cpmac_clear_tx(struct net_device *dev) { struct cpmac_priv *priv = netdev_priv(dev); int i; + if (unlikely(!priv->desc_ring)) return; for (i = 0; i < CPMAC_QUEUES; i++) { @@ -821,6 +827,7 @@ static void cpmac_tx_timeout(struct net_device *dev) static int cpmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct cpmac_priv *priv = netdev_priv(dev); + if (!(netif_running(dev))) return -EINVAL; if (!priv->phy) @@ -1181,6 +1188,7 @@ fail: static int cpmac_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); + unregister_netdev(dev); free_netdev(dev); return 0; -- cgit v1.2.3 From 55064efd24d094fc3cb767535a3c5890276ec0bc Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 10 Jul 2014 11:05:44 +0530 Subject: net: cpmac: fix proper spacing before return statement This patch insert proper spaces before return statement. Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpmac.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index 3d3ead4a0f6f..b6efe3e0f1ee 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -283,6 +283,7 @@ static int cpmac_mdio_read(struct mii_bus *bus, int phy_id, int reg) MDIO_PHY(phy_id)); while ((val = cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0))) & MDIO_BUSY) cpu_relax(); + return MDIO_DATA(val); } @@ -293,6 +294,7 @@ static int cpmac_mdio_write(struct mii_bus *bus, int phy_id, cpu_relax(); cpmac_write(bus->priv, CPMAC_MDIO_ACCESS(0), MDIO_BUSY | MDIO_WRITE | MDIO_REG(reg) | MDIO_PHY(phy_id) | MDIO_DATA(val)); + return 0; } @@ -308,6 +310,7 @@ static int cpmac_mdio_reset(struct mii_bus *bus) ar7_device_reset(AR7_RESET_BIT_MDIO); cpmac_write(bus->priv, CPMAC_MDIO_CONTROL, MDIOC_ENABLE | MDIOC_CLKDIV(clk_get_rate(cpmac_clk) / 2200000 - 1)); + return 0; } @@ -537,6 +540,7 @@ fatal_error: cpmac_hw_stop(priv->dev); if (!schedule_work(&priv->reset_work)) atomic_dec(&priv->reset_pending); + return 0; } @@ -883,6 +887,7 @@ static int cpmac_set_ringparam(struct net_device *dev, if (netif_running(dev)) return -EBUSY; priv->ring_size = ring->rx_pending; + return 0; } @@ -1076,6 +1081,7 @@ static int cpmac_stop(struct net_device *dev) dma_free_coherent(&dev->dev, sizeof(struct cpmac_desc) * (CPMAC_QUEUES + priv->ring_size), priv->desc_ring, priv->dma_ring); + return 0; } @@ -1178,6 +1184,7 @@ static int cpmac_probe(struct platform_device *pdev) "mac: %pM\n", (void *)mem->start, dev->irq, priv->phy_name, dev->dev_addr); } + return 0; fail: @@ -1191,6 +1198,7 @@ static int cpmac_remove(struct platform_device *pdev) unregister_netdev(dev); free_netdev(dev); + return 0; } -- cgit v1.2.3 From 0465be8f4f1ddb251b25da26f1247581bcb98dbf Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 10 Jul 2014 11:05:45 +0530 Subject: net: cpmac: fix in releasing resources before registering the the net device this code freeing net device by using the label 'fail' fixed by introducing an another label 'out' Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpmac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index b6efe3e0f1ee..b68c5b588742 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -1142,7 +1142,7 @@ static int cpmac_probe(struct platform_device *pdev) mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); if (!mem) { rc = -ENODEV; - goto fail; + goto out; } dev->irq = platform_get_irq_byname(pdev, "irq"); @@ -1170,7 +1170,7 @@ static int cpmac_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Could not attach to PHY\n"); rc = PTR_ERR(priv->phy); - goto fail; + goto out; } rc = register_netdev(dev); @@ -1189,6 +1189,7 @@ static int cpmac_probe(struct platform_device *pdev) fail: free_netdev(dev); +out: return rc; } -- cgit v1.2.3 From 69b4b7a4148e94a3fe7f06f72ee70113a6c61837 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 10 Jul 2014 10:58:54 +0800 Subject: r8152: support jumbo frame for RTL8153 The maximum jumbo frame size for RTL8153 is 9K bytes. Change the max rx packet size to 9K. Change the use of the shared fifo from 6K (default) to 12K for tx. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index e9685ce98327..7d2dd80c4a7a 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -59,6 +59,7 @@ #define PLA_WDT6_CTRL 0xe428 #define PLA_TCR0 0xe610 #define PLA_TCR1 0xe612 +#define PLA_MTPS 0xe615 #define PLA_TXFIFO_CTRL 0xe618 #define PLA_RSTTALLY 0xe800 #define PLA_CR 0xe813 @@ -180,6 +181,10 @@ /* PLA_TCR1 */ #define VERSION_MASK 0x7cf0 +/* PLA_MTPS */ +#define MTPS_JUMBO (12 * 1024 / 64) +#define MTPS_DEFAULT (6 * 1024 / 64) + /* PLA_RSTTALLY */ #define TALLY_RESET 0x0001 @@ -440,7 +445,10 @@ enum rtl_register_content { #define BYTE_EN_START_MASK 0x0f #define BYTE_EN_END_MASK 0xf0 +#define RTL8153_MAX_PACKET 9216 /* 9K */ +#define RTL8153_MAX_MTU (RTL8153_MAX_PACKET - VLAN_ETH_HLEN - VLAN_HLEN) #define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN) +#define RTL8153_RMS RTL8153_MAX_PACKET #define RTL8152_TX_TIMEOUT (5 * HZ) /* rtl8152 flags */ @@ -2522,7 +2530,8 @@ static void r8153_first_init(struct r8152 *tp) ocp_data &= ~CPCR_RX_VLAN; ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS); + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0); ocp_data |= TCR0_AUTO_FIFO; @@ -2572,7 +2581,7 @@ static void r8153_enter_oob(struct r8152 *tp) mdelay(1); } - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); ocp_data &= ~TEREDO_WAKE_MASK; @@ -3284,6 +3293,26 @@ out: return res; } +static int rtl8152_change_mtu(struct net_device *dev, int new_mtu) +{ + struct r8152 *tp = netdev_priv(dev); + + switch (tp->version) { + case RTL_VER_01: + case RTL_VER_02: + return eth_change_mtu(dev, new_mtu); + default: + break; + } + + if (new_mtu < 68 || new_mtu > RTL8153_MAX_MTU) + return -EINVAL; + + dev->mtu = new_mtu; + + return 0; +} + static const struct net_device_ops rtl8152_netdev_ops = { .ndo_open = rtl8152_open, .ndo_stop = rtl8152_close, @@ -3292,8 +3321,7 @@ static const struct net_device_ops rtl8152_netdev_ops = { .ndo_tx_timeout = rtl8152_tx_timeout, .ndo_set_rx_mode = rtl8152_set_rx_mode, .ndo_set_mac_address = rtl8152_set_mac_address, - - .ndo_change_mtu = eth_change_mtu, + .ndo_change_mtu = rtl8152_change_mtu, .ndo_validate_addr = eth_validate_addr, }; -- cgit v1.2.3 From e8b1202ce6ab67341660812e7d66db4c3e2a5649 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 10:51:27 +0300 Subject: Bluetooth: Fix advertising parameter update when toggling connectable When we change the connectable state and have advertising enabled we should update the advertising parameters no matter what. The code was incorrectly only updating them if advertising was not already active. This patch fixes the issue. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 91b1f92c681e..38f05386bc0c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1882,8 +1882,8 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) write_fast_connectable(&req, false); - if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && - !test_bit(HCI_LE_ADV, &hdev->dev_flags)) + /* Update the advertising parameters if necessary */ + if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) enable_advertising(&req); err = hci_req_run(&req, set_connectable_complete); -- cgit v1.2.3 From b3c6410b8c75cd48e4242af0173bb55701939b9b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 11:02:07 +0300 Subject: Bluteooth: Reject SMP bonding if HCI_PAIRABLE is not set If the remote device tries to initiate bonding with us and we don't have HCI_PAIRABLE set we should just flat out reject the request. This brings SMP in line with how the flag is used for BR/EDR SSP. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 627d683203cf..bf3568c46847 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -676,6 +676,7 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; + struct hci_dev *hdev = conn->hcon->hdev; struct smp_chan *smp; u8 key_size, auth, sec_level; int ret; @@ -696,6 +697,10 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (!smp) return SMP_UNSPECIFIED; + if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags) && + (req->auth_req & SMP_AUTH_BONDING)) + return SMP_PAIRING_NOTSUPP; + smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); @@ -911,6 +916,10 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; + if (!test_bit(HCI_PAIRABLE, &hcon->hdev->dev_flags) && + (rp->auth_req & SMP_AUTH_BONDING)) + return SMP_PAIRING_NOTSUPP; + smp = smp_chan_create(conn); if (!smp) return SMP_UNSPECIFIED; -- cgit v1.2.3 From 7fabc0f4c7bd2206c368a79e3ed79b7d36625cfd Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 11:50:27 +0300 Subject: Bluetooth: Fix using test_and_clear instead of test_and_set The code for updating the HCI_CONNECTABLE flag was incorrectly using test_and_set_bit instead of test_and_clear_bit when HCI_CONNECTABLE is to be cleared. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 84431b86af96..8f9df768f250 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2726,8 +2726,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); else - changed = test_and_set_bit(HCI_CONNECTABLE, - &hdev->dev_flags); + changed = test_and_clear_bit(HCI_CONNECTABLE, + &hdev->dev_flags); if (changed) mgmt_new_settings(hdev); -- cgit v1.2.3 From 031547d8688a0fc5da875b504bf11e6c2e18390e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 12:09:06 +0300 Subject: Bluetooth: Remove unneeded mgmt_connectable function The mgmt_connectable function has been used to ensure that the right actions to HCI_CONNECTABLE are taken when the HCI_Write_Scan_Enable command is triggered by something else than mgmt. The only other user that we really care about is the HCISETSCAN ioctl code, so we can actually more simply perform the needed changes there instead. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_core.c | 6 +++--- net/bluetooth/hci_event.c | 6 +----- net/bluetooth/mgmt.c | 32 -------------------------------- 4 files changed, 4 insertions(+), 41 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e69c2b08c0c6..76675c55be15 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1288,7 +1288,6 @@ void mgmt_set_powered_failed(struct hci_dev *hdev, int err); int mgmt_powered(struct hci_dev *hdev, u8 powered); void mgmt_discoverable_timeout(struct hci_dev *hdev); void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); -void mgmt_connectable(struct hci_dev *hdev, u8 connectable); void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8f9df768f250..3844eeb85453 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2717,9 +2717,9 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) HCI_INIT_TIMEOUT); /* Ensure that the connectable state gets correctly - * notified if the whitelist is in use. + * modified as this was a non-mgmt change. */ - if (!err && !list_empty(&hdev->whitelist)) { + if (!err) { bool changed; if ((dr.dev_opt & SCAN_PAGE)) @@ -2729,7 +2729,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); - if (changed) + if (changed && test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_new_settings(hdev); } break; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c8ae9ee3cb12..38a0e457eaf9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -330,12 +330,8 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) } else if (old_iscan) mgmt_discoverable(hdev, 0); - if (param & SCAN_PAGE) { + if (param & SCAN_PAGE) set_bit(HCI_PSCAN, &hdev->flags); - if (!old_pscan) - mgmt_connectable(hdev, 1); - } else if (old_pscan) - mgmt_connectable(hdev, 0); done: hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 38f05386bc0c..9f9f11c8488b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6068,38 +6068,6 @@ void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) } } -void mgmt_connectable(struct hci_dev *hdev, u8 connectable) -{ - bool changed; - - /* Nothing needed here if there's a pending command since that - * commands request completion callback takes care of everything - * necessary. - */ - if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) - return; - - /* Powering off may clear the scan mode - don't let that interfere */ - if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) - return; - - /* If something else than mgmt changed the page scan state we - * can't differentiate this from a change triggered by adding - * the first element to the whitelist. Therefore, avoid - * incorrectly setting HCI_CONNECTABLE. - */ - if (connectable && !list_empty(&hdev->whitelist)) - return; - - if (connectable) - changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); - else - changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); - - if (changed) - new_settings(hdev, NULL); -} - void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) { u8 mgmt_err = mgmt_status(status); -- cgit v1.2.3 From 123abc0833181aec4796c628d9ffd608b2b41d5c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 12:09:07 +0300 Subject: Bluetooth: Refactor ioctl scan state update to its own function With subsequent patches we'll also need to update the discoverable state. As the code grows bigger it's better to move this out from the switch statement into its own function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3844eeb85453..27c40e4901a3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2655,6 +2655,26 @@ done: return ret; } +static void hci_update_scan_state(struct hci_dev *hdev, u8 scan) +{ + bool conn_changed; + + BT_DBG("%s scan 0x%02x", hdev->name, scan); + + if ((scan & SCAN_PAGE)) + conn_changed = !test_and_set_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + else + conn_changed = test_and_clear_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + return; + + if (conn_changed) + mgmt_new_settings(hdev); +} + int hci_dev_cmd(unsigned int cmd, void __user *arg) { struct hci_dev *hdev; @@ -2719,19 +2739,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) /* Ensure that the connectable state gets correctly * modified as this was a non-mgmt change. */ - if (!err) { - bool changed; - - if ((dr.dev_opt & SCAN_PAGE)) - changed = !test_and_set_bit(HCI_CONNECTABLE, - &hdev->dev_flags); - else - changed = test_and_clear_bit(HCI_CONNECTABLE, - &hdev->dev_flags); - - if (changed && test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_new_settings(hdev); - } + if (!err) + hci_update_scan_state(hdev, dr.dev_opt); break; case HCISETLINKPOL: -- cgit v1.2.3 From bc6d2d04182877b198c1a945b7c401decbbb8c02 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 12:09:08 +0300 Subject: Bluetooth: Remove unneeded mgmt_discoverable function Since the HCISETSCAN ioctl is the only non-mgmt user we care about for setting the right discoverable state we can simply do the necessary updates in the ioctl handler function instead. This then allows the removal of the mgmt_discoverable function and should simplify that state handling considerably. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 24 +++++++++++--- net/bluetooth/hci_event.c | 19 +++--------- net/bluetooth/mgmt.c | 67 ++++++++++++++-------------------------- 4 files changed, 50 insertions(+), 62 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 76675c55be15..b65efb22be54 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1286,8 +1286,8 @@ void mgmt_index_added(struct hci_dev *hdev); void mgmt_index_removed(struct hci_dev *hdev); void mgmt_set_powered_failed(struct hci_dev *hdev, int err); int mgmt_powered(struct hci_dev *hdev, u8 powered); +int mgmt_update_adv_data(struct hci_dev *hdev); void mgmt_discoverable_timeout(struct hci_dev *hdev); -void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 27c40e4901a3..3321c65c73ac 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2657,7 +2657,7 @@ done: static void hci_update_scan_state(struct hci_dev *hdev, u8 scan) { - bool conn_changed; + bool conn_changed, discov_changed; BT_DBG("%s scan 0x%02x", hdev->name, scan); @@ -2668,11 +2668,27 @@ static void hci_update_scan_state(struct hci_dev *hdev, u8 scan) conn_changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); + if ((scan & SCAN_INQUIRY)) { + discov_changed = !test_and_set_bit(HCI_DISCOVERABLE, + &hdev->dev_flags); + } else { + clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); + discov_changed = test_and_clear_bit(HCI_DISCOVERABLE, + &hdev->dev_flags); + } + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) return; - if (conn_changed) + if (conn_changed || discov_changed) { + /* In case this was disabled through mgmt */ + set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags); + + if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) + mgmt_update_adv_data(hdev); + mgmt_new_settings(hdev); + } } int hci_dev_cmd(unsigned int cmd, void __user *arg) @@ -2736,8 +2752,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) err = hci_req_sync(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); - /* Ensure that the connectable state gets correctly - * modified as this was a non-mgmt change. + /* Ensure that the connectable and discoverable states + * get correctly modified as this was a non-mgmt change. */ if (!err) hci_update_scan_state(hdev, dr.dev_opt); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 38a0e457eaf9..760bbd88f3c5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -296,7 +296,6 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); __u8 param; - int old_pscan, old_iscan; void *sent; BT_DBG("%s status 0x%2.2x", hdev->name, status); @@ -315,23 +314,15 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) goto done; } - /* We need to ensure that we set this back on if someone changed - * the scan mode through a raw HCI socket. - */ - set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags); - - old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags); - old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags); - - if (param & SCAN_INQUIRY) { + if (param & SCAN_INQUIRY) set_bit(HCI_ISCAN, &hdev->flags); - if (!old_iscan) - mgmt_discoverable(hdev, 1); - } else if (old_iscan) - mgmt_discoverable(hdev, 0); + else + clear_bit(HCI_ISCAN, &hdev->flags); if (param & SCAN_PAGE) set_bit(HCI_PSCAN, &hdev->flags); + else + clear_bit(HCI_ISCAN, &hdev->flags); done: hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9f9f11c8488b..1dad7bffc6af 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -906,6 +906,16 @@ static void update_adv_data(struct hci_request *req) hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); } +int mgmt_update_adv_data(struct hci_dev *hdev) +{ + struct hci_request req; + + hci_req_init(&req, hdev); + update_adv_data(&req); + + return hci_req_run(&req, NULL); +} + static void create_eir(struct hci_dev *hdev, u8 *data) { u8 *ptr = data; @@ -1743,7 +1753,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status) { struct pending_cmd *cmd; struct mgmt_mode *cp; - bool changed; + bool conn_changed, discov_changed; BT_DBG("status 0x%02x", status); @@ -1760,15 +1770,23 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status) } cp = cmd->param; - if (cp->val) - changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); - else - changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); + if (cp->val) { + conn_changed = !test_and_set_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + discov_changed = false; + } else { + conn_changed = test_and_clear_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + discov_changed = test_and_clear_bit(HCI_DISCOVERABLE, + &hdev->dev_flags); + } send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev); - if (changed) { + if (conn_changed || discov_changed) { new_settings(hdev, cmd->sk); + if (discov_changed) + mgmt_update_adv_data(hdev); hci_update_background_scan(hdev); } @@ -6031,43 +6049,6 @@ void mgmt_discoverable_timeout(struct hci_dev *hdev) hci_dev_unlock(hdev); } -void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) -{ - bool changed; - - /* Nothing needed here if there's a pending command since that - * commands request completion callback takes care of everything - * necessary. - */ - if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev)) - return; - - /* Powering off may clear the scan mode - don't let that interfere */ - if (!discoverable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) - return; - - if (discoverable) { - changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags); - } else { - clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); - changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); - } - - if (changed) { - struct hci_request req; - - /* In case this change in discoverable was triggered by - * a disabling of connectable there could be a need to - * update the advertising flags. - */ - hci_req_init(&req, hdev); - update_adv_data(&req); - hci_req_run(&req, NULL); - - new_settings(hdev, NULL); - } -} - void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) { u8 mgmt_err = mgmt_status(status); -- cgit v1.2.3 From 13a779e42251184d0f53a8f8299ced614faa028f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 12:09:09 +0300 Subject: Bluetooth: Remove unneeded mgmt_write_scan_failed function The Set Connectable/Discoverable mgmt handlers use a hci_request with a proper callback to handle the HCI command sending. It makes therefore little sense to have this extra function to be called from hci_event.c for command failures. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_event.c | 1 - net/bluetooth/mgmt.c | 13 ------------- 3 files changed, 15 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b65efb22be54..7e9e95633a85 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1288,7 +1288,6 @@ void mgmt_set_powered_failed(struct hci_dev *hdev, int err); int mgmt_powered(struct hci_dev *hdev, u8 powered); int mgmt_update_adv_data(struct hci_dev *hdev); void mgmt_discoverable_timeout(struct hci_dev *hdev); -void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent); void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 760bbd88f3c5..a62e918d2641 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -309,7 +309,6 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); if (status) { - mgmt_write_scan_failed(hdev, param, status); hdev->discov_timeout = 0; goto done; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1dad7bffc6af..7703b72653ff 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6049,19 +6049,6 @@ void mgmt_discoverable_timeout(struct hci_dev *hdev) hci_dev_unlock(hdev); } -void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) -{ - u8 mgmt_err = mgmt_status(status); - - if (scan & SCAN_PAGE) - mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, - cmd_status_rsp, &mgmt_err); - - if (scan & SCAN_INQUIRY) - mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, - cmd_status_rsp, &mgmt_err); -} - void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent) { -- cgit v1.2.3 From 2e84d8db91e45964c2b54ccc7da1f9b4bfb1222b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 10 Jul 2014 13:17:37 +0200 Subject: Bluetooth: Mark controller is down when HCI_AUTO_OFF is set During the initial setup phase, the controller is powered on and will be powered off again if it is not used within the auto-off timeout. Userspace using ioctl does not know about the difference between the initial setup phase and a controller being present. It is a bad idea to keep the controller powered by just looking at the device list or device information. Instead just tell userspace that the controller is still down. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3321c65c73ac..96e0acc3fc92 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2817,14 +2817,20 @@ int hci_get_dev_list(void __user *arg) read_lock(&hci_dev_list_lock); list_for_each_entry(hdev, &hci_dev_list, list) { - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - cancel_delayed_work(&hdev->power_off); + unsigned long flags = hdev->flags; + + /* When the auto-off is configured it means the transport + * is running, but in that case still indicate that the + * device is actually down. + */ + if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + flags &= ~BIT(HCI_UP); if (!test_bit(HCI_MGMT, &hdev->dev_flags)) set_bit(HCI_PAIRABLE, &hdev->dev_flags); (dr + n)->dev_id = hdev->id; - (dr + n)->dev_opt = hdev->flags; + (dr + n)->dev_opt = flags; if (++n >= dev_num) break; @@ -2844,6 +2850,7 @@ int hci_get_dev_info(void __user *arg) { struct hci_dev *hdev; struct hci_dev_info di; + unsigned long flags; int err = 0; if (copy_from_user(&di, arg, sizeof(di))) @@ -2853,8 +2860,14 @@ int hci_get_dev_info(void __user *arg) if (!hdev) return -ENODEV; - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - cancel_delayed_work_sync(&hdev->power_off); + /* When the auto-off is configured it means the transport + * is running, but in that case still indicate that the + * device is actually down. + */ + if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + flags = hdev->flags & ~BIT(HCI_UP); + else + flags = hdev->flags; if (!test_bit(HCI_MGMT, &hdev->dev_flags)) set_bit(HCI_PAIRABLE, &hdev->dev_flags); @@ -2862,7 +2875,7 @@ int hci_get_dev_info(void __user *arg) strcpy(di.name, hdev->name); di.bdaddr = hdev->bdaddr; di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4); - di.flags = hdev->flags; + di.flags = flags; di.pkt_type = hdev->pkt_type; if (lmp_bredr_capable(hdev)) { di.acl_mtu = hdev->acl_mtu; -- cgit v1.2.3 From 12aa4f0a3d0576c554efc770a6e16c8bb897b966 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 10 Jul 2014 15:25:22 +0200 Subject: Bluetooth: Set HCI_PAIRABLE during power on for legacy ioctl When the controller is brought up using legacy ioctl, the setting of the HCI_PAIRABLE flag should happen then. Previously it was set during enumeration and when retrieving device information. This change also will not set the HCI_PAIRABLE flag when the controller is used with the HCI User Channel operation. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 96e0acc3fc92..52e8c91ea3e9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2435,6 +2435,16 @@ int hci_dev_open(__u16 dev) */ flush_workqueue(hdev->req_workqueue); + /* For controllers not using the management interface and that + * are brought up using legacy ioctl, set the HCI_PAIRABLE bit + * so that pairing works for them. Once the management interface + * is in use this bit will be cleared again and userspace has + * to explicitly enable it. + */ + if (!test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && + !test_bit(HCI_MGMT, &hdev->dev_flags)) + set_bit(HCI_PAIRABLE, &hdev->dev_flags); + err = hci_dev_do_open(hdev); done: @@ -2826,9 +2836,6 @@ int hci_get_dev_list(void __user *arg) if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) flags &= ~BIT(HCI_UP); - if (!test_bit(HCI_MGMT, &hdev->dev_flags)) - set_bit(HCI_PAIRABLE, &hdev->dev_flags); - (dr + n)->dev_id = hdev->id; (dr + n)->dev_opt = flags; @@ -2869,9 +2876,6 @@ int hci_get_dev_info(void __user *arg) else flags = hdev->flags; - if (!test_bit(HCI_MGMT, &hdev->dev_flags)) - set_bit(HCI_PAIRABLE, &hdev->dev_flags); - strcpy(di.name, hdev->name); di.bdaddr = hdev->bdaddr; di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4); -- cgit v1.2.3 From 5d5eacb34c9e1fdc0a47b885d832eaa4de860dc7 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Thu, 10 Jul 2014 07:01:58 -0400 Subject: bridge: fdb dumping takes a filter device Dumping a bridge fdb dumps every fdb entry held. With this change we are going to filter on selected bridge port. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_main.c | 3 ++- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 7 ++++--- drivers/net/vxlan.c | 3 ++- include/linux/netdevice.h | 4 +++- include/linux/rtnetlink.h | 1 + net/bridge/br_fdb.c | 5 +++++ net/bridge/br_private.h | 2 +- net/core/rtnetlink.c | 9 ++++++--- 8 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index e49352d68ede..2899f783ee1d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7095,13 +7095,14 @@ static int i40e_ndo_fdb_del(struct ndmsg *ndm, static int i40e_ndo_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *dev, + struct net_device *filter_dev, int idx) { struct i40e_netdev_priv *np = netdev_priv(dev); struct i40e_pf *pf = np->vsi->back; if (pf->flags & I40E_FLAG_SRIOV_ENABLED) - idx = ndo_dflt_fdb_dump(skb, cb, dev, idx); + idx = ndo_dflt_fdb_dump(skb, cb, dev, filter_dev, idx); return idx; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index f8de2ae01a5a..0fdbcc8319f7 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -427,16 +427,17 @@ static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], } static int qlcnic_fdb_dump(struct sk_buff *skb, struct netlink_callback *ncb, - struct net_device *netdev, int idx) + struct net_device *netdev, + struct net_device *filter_dev, int idx) { struct qlcnic_adapter *adapter = netdev_priv(netdev); if (!adapter->fdb_mac_learn) - return ndo_dflt_fdb_dump(skb, ncb, netdev, idx); + return ndo_dflt_fdb_dump(skb, ncb, netdev, filter_dev, idx); if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) || qlcnic_sriov_check(adapter)) - idx = ndo_dflt_fdb_dump(skb, ncb, netdev, idx); + idx = ndo_dflt_fdb_dump(skb, ncb, netdev, filter_dev, idx); return idx; } diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index c2d360150804..e6808f7e4e32 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -933,7 +933,8 @@ out: /* Dump forwarding table */ static int vxlan_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct net_device *dev, int idx) + struct net_device *dev, + struct net_device *filter_dev, int idx) { struct vxlan_dev *vxlan = netdev_priv(dev); unsigned int h; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8b43a28ee0bc..3a320db96180 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -943,7 +943,8 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev, * const unsigned char *addr) * Deletes the FDB entry from dev coresponding to addr. * int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb, - * struct net_device *dev, int idx) + * struct net_device *dev, struct net_device *filter_dev, + * int idx) * Used to add FDB entries to dump requests. Implementers should add * entries to skb and update idx with the number of entries. * @@ -1114,6 +1115,7 @@ struct net_device_ops { int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *dev, + struct net_device *filter_dev, int idx); int (*ndo_bridge_setlink)(struct net_device *dev, diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 953937ea5233..167bae7bdfa4 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -78,6 +78,7 @@ extern void __rtnl_unlock(void); extern int ndo_dflt_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *dev, + struct net_device *filter_dev, int idx); extern int ndo_dflt_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 7be33667a839..6edecd11ecf0 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -676,6 +676,7 @@ errout: int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *dev, + struct net_device *filter_dev, int idx) { struct net_bridge *br = netdev_priv(dev); @@ -691,6 +692,10 @@ int br_fdb_dump(struct sk_buff *skb, if (idx < cb->args[0]) goto skip; + if (filter_dev && (!f->dst || !f->dst->dev || + f->dst->dev != filter_dev)) + goto skip; + if (fdb_fill_info(skb, br, f, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 23caf5b0309e..62a7fa2e3569 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -399,7 +399,7 @@ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 nlh_flags); int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct net_device *dev, int idx); + struct net_device *dev, struct net_device *fdev, int idx); int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p); void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 27acaf7ff6d7..90a906e7ac26 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2517,6 +2517,7 @@ skip: int ndo_dflt_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *dev, + struct net_device *filter_dev, int idx) { int err; @@ -2547,13 +2548,15 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) br_dev = netdev_master_upper_dev_get(dev); ops = br_dev->netdev_ops; if (ops->ndo_fdb_dump) - idx = ops->ndo_fdb_dump(skb, cb, dev, idx); + idx = ops->ndo_fdb_dump(skb, cb, dev, NULL, + idx); } if (dev->netdev_ops->ndo_fdb_dump) - idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx); + idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, NULL, + idx); else - idx = ndo_dflt_fdb_dump(skb, cb, dev, idx); + idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx); } rcu_read_unlock(); -- cgit v1.2.3 From 5e6d243587990a588143b9da3974833649595587 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Thu, 10 Jul 2014 07:01:59 -0400 Subject: bridge: netlink dump interface at par with brctl Actually better than brctl showmacs because we can filter by bridge port in the kernel. The current bridge netlink interface doesnt scale when you have many bridges each with large fdbs or even bridges with many bridge ports And now for the science non-fiction novel you have all been waiting for.. //lets see what bridge ports we have root@moja-1:/configs/may30-iprt/bridge# ./bridge link show 8: eth1 state DOWN : mtu 1500 master br0 state disabled priority 32 cost 19 17: sw1-p1 state DOWN : mtu 1500 master br0 state disabled priority 32 cost 100 // show all.. root@moja-1:/configs/may30-iprt/bridge# ./bridge fdb show 33:33:00:00:00:01 dev bond0 self permanent 33:33:00:00:00:01 dev dummy0 self permanent 33:33:00:00:00:01 dev ifb0 self permanent 33:33:00:00:00:01 dev ifb1 self permanent 33:33:00:00:00:01 dev eth0 self permanent 01:00:5e:00:00:01 dev eth0 self permanent 33:33:ff:22:01:01 dev eth0 self permanent 02:00:00:12:01:02 dev eth1 vlan 0 master br0 permanent 00:17:42:8a:b4:05 dev eth1 vlan 0 master br0 permanent 00:17:42:8a:b4:07 dev eth1 self permanent 33:33:00:00:00:01 dev eth1 self permanent 33:33:00:00:00:01 dev gretap0 self permanent da:ac:46:27:d9:53 dev sw1-p1 vlan 0 master br0 permanent 33:33:00:00:00:01 dev sw1-p1 self permanent //filter by bridge root@moja-1:/configs/may30-iprt/bridge# ./bridge fdb show br br0 02:00:00:12:01:02 dev eth1 vlan 0 master br0 permanent 00:17:42:8a:b4:05 dev eth1 vlan 0 master br0 permanent 00:17:42:8a:b4:07 dev eth1 self permanent 33:33:00:00:00:01 dev eth1 self permanent da:ac:46:27:d9:53 dev sw1-p1 vlan 0 master br0 permanent 33:33:00:00:00:01 dev sw1-p1 self permanent // bridge sw1 has no ports attached.. root@moja-1:/configs/may30-iprt/bridge# ./bridge fdb show br sw1 //filter by port root@moja-1:/configs/may30-iprt/bridge# ./bridge fdb show brport eth1 02:00:00:12:01:02 vlan 0 master br0 permanent 00:17:42:8a:b4:05 vlan 0 master br0 permanent 00:17:42:8a:b4:07 self permanent 33:33:00:00:00:01 self permanent // filter by port + bridge root@moja-1:/configs/may30-iprt/bridge# ./bridge fdb show br br0 brport sw1-p1 da:ac:46:27:d9:53 vlan 0 master br0 permanent 33:33:00:00:00:01 self permanent // for shits and giggles (as they say in New Brunswick), lets // change the mac that br0 uses // Note: a magical fdb entry with no brport is added ... root@moja-1:/configs/may30-iprt/bridge# ip link set dev br0 address 02:00:00:12:01:04 // lets see if we can see the unicorn .. root@moja-1:/configs/may30-iprt/bridge# ./bridge fdb show 33:33:00:00:00:01 dev bond0 self permanent 33:33:00:00:00:01 dev dummy0 self permanent 33:33:00:00:00:01 dev ifb0 self permanent 33:33:00:00:00:01 dev ifb1 self permanent 33:33:00:00:00:01 dev eth0 self permanent 01:00:5e:00:00:01 dev eth0 self permanent 33:33:ff:22:01:01 dev eth0 self permanent 02:00:00:12:01:02 dev eth1 vlan 0 master br0 permanent 00:17:42:8a:b4:05 dev eth1 vlan 0 master br0 permanent 00:17:42:8a:b4:07 dev eth1 self permanent 33:33:00:00:00:01 dev eth1 self permanent 33:33:00:00:00:01 dev gretap0 self permanent 02:00:00:12:01:04 dev br0 vlan 0 master br0 permanent <=== there it is da:ac:46:27:d9:53 dev sw1-p1 vlan 0 master br0 permanent 33:33:00:00:00:01 dev sw1-p1 self permanent //can we see it if we filter by bridge? root@moja-1:/configs/may30-iprt/bridge# ./bridge fdb show br br0 02:00:00:12:01:02 dev eth1 vlan 0 master br0 permanent 00:17:42:8a:b4:05 dev eth1 vlan 0 master br0 permanent 00:17:42:8a:b4:07 dev eth1 self permanent 33:33:00:00:00:01 dev eth1 self permanent 02:00:00:12:01:04 dev br0 vlan 0 master br0 permanent <=== there it is da:ac:46:27:d9:53 dev sw1-p1 vlan 0 master br0 permanent 33:33:00:00:00:01 dev sw1-p1 self permanent Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/bridge/br_fdb.c | 15 ++++++++--- net/core/rtnetlink.c | 74 ++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 70 insertions(+), 19 deletions(-) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 6edecd11ecf0..0bb9d8b63dd2 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -692,9 +692,18 @@ int br_fdb_dump(struct sk_buff *skb, if (idx < cb->args[0]) goto skip; - if (filter_dev && (!f->dst || !f->dst->dev || - f->dst->dev != filter_dev)) - goto skip; + if (filter_dev && + (!f->dst || f->dst->dev != filter_dev)) { + if (filter_dev != dev) + goto skip; + /* !f->dst is a speacial case for bridge + * It means the MAC belongs to the bridge + * Therefore need a little more filtering + * we only want to dump the !f->dst case + */ + if (f->dst) + goto skip; + } if (fdb_fill_info(skb, br, f, NETLINK_CB(cb->skb).portid, diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 90a906e7ac26..1f8a59e02c48 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2535,30 +2535,72 @@ EXPORT_SYMBOL(ndo_dflt_fdb_dump); static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) { - int idx = 0; - struct net *net = sock_net(skb->sk); struct net_device *dev; + struct nlattr *tb[IFLA_MAX+1]; + struct net_device *bdev = NULL; + struct net_device *br_dev = NULL; + const struct net_device_ops *ops = NULL; + const struct net_device_ops *cops = NULL; + struct ifinfomsg *ifm = nlmsg_data(cb->nlh); + struct net *net = sock_net(skb->sk); + int brport_idx = 0; + int br_idx = 0; + int idx = 0; + + if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, + ifla_policy) == 0) { + if (tb[IFLA_MASTER]) + br_idx = nla_get_u32(tb[IFLA_MASTER]); + } + + brport_idx = ifm->ifi_index; + + if (br_idx) { + br_dev = __dev_get_by_index(net, br_idx); + if (!br_dev) + return -ENODEV; + + ops = br_dev->netdev_ops; + bdev = br_dev; + } + + for_each_netdev(net, dev) { + if (brport_idx && (dev->ifindex != brport_idx)) + continue; + + if (!br_idx) { /* user did not specify a specific bridge */ + if (dev->priv_flags & IFF_BRIDGE_PORT) { + br_dev = netdev_master_upper_dev_get(dev); + cops = br_dev->netdev_ops; + } + + bdev = dev; + } else { + if (dev != br_dev && + !(dev->priv_flags & IFF_BRIDGE_PORT)) + continue; + + if (br_dev != netdev_master_upper_dev_get(dev) && + !(dev->priv_flags & IFF_EBRIDGE)) + continue; + + bdev = br_dev; + cops = ops; + } - rcu_read_lock(); - for_each_netdev_rcu(net, dev) { if (dev->priv_flags & IFF_BRIDGE_PORT) { - struct net_device *br_dev; - const struct net_device_ops *ops; - - br_dev = netdev_master_upper_dev_get(dev); - ops = br_dev->netdev_ops; - if (ops->ndo_fdb_dump) - idx = ops->ndo_fdb_dump(skb, cb, dev, NULL, - idx); + if (cops && cops->ndo_fdb_dump) + idx = cops->ndo_fdb_dump(skb, cb, br_dev, dev, + idx); } + idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx); if (dev->netdev_ops->ndo_fdb_dump) - idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, NULL, + idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, bdev, dev, idx); - else - idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx); + + cops = NULL; } - rcu_read_unlock(); cb->args[0] = idx; return skb->len; -- cgit v1.2.3 From ff32045e7a1ec9eb35dbf057374b1bc5bf99bc1f Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 10 Jul 2014 15:29:38 +0530 Subject: net: cpmac: fix in debug messages This patch fix the debug message format. This patch changes to the commit f160a2d0b524eeebd97a68e2fbb59fad4cdd3fee: net: cpmac: dynamic debug fixes When we use pr_debug()/netdev_dbg() new lines are inserting in b/w the values. The format when i use the printk() These formats used in skb dump and reg dump. This functions called from the entire code. So this will be enabled all the lines. Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpmac.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index b68c5b588742..3809f4ec2820 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -228,22 +228,22 @@ static void cpmac_dump_regs(struct net_device *dev) for (i = 0; i < CPMAC_REG_END; i += 4) { if (i % 16 == 0) { if (i) - pr_cont("\n"); - netdev_dbg(dev, "reg[%p]:", priv->regs + i); + printk("\n"); + printk("%s: reg[%p]:", dev->name, priv->regs + i); } - pr_debug(" %08x", cpmac_read(priv->regs, i)); + printk(" %08x", cpmac_read(priv->regs, i)); } - pr_debug("\n"); + printk("\n"); } static void cpmac_dump_desc(struct net_device *dev, struct cpmac_desc *desc) { int i; - netdev_dbg(dev, "desc[%p]:", desc); + printk("%s: desc[%p]:", dev->name, desc); for (i = 0; i < sizeof(*desc) / 4; i++) - pr_debug(" %08x", ((u32 *)desc)[i]); - pr_debug("\n"); + printk(" %08x", ((u32 *)desc)[i]); + printk("\n"); } static void cpmac_dump_all_desc(struct net_device *dev) @@ -261,16 +261,16 @@ static void cpmac_dump_skb(struct net_device *dev, struct sk_buff *skb) { int i; - netdev_dbg(dev, "skb 0x%p, len=%d\n", skb, skb->len); + printk("%s: skb 0x%p, len=%d\n", dev->name, skb, skb->len); for (i = 0; i < skb->len; i++) { if (i % 16 == 0) { if (i) - pr_cont("\n"); - netdev_dbg(dev, "data[%p]:", skb->data + i); + printk("\n"); + printk("%s: data[%p]:", dev->name, skb->data + i); } - pr_debug(" %02x", ((u8 *)skb->data)[i]); + printk(" %02x", ((u8 *)skb->data)[i]); } - pr_debug("\n"); + printk("\n"); } static int cpmac_mdio_read(struct mii_bus *bus, int phy_id, int reg) -- cgit v1.2.3 From b6428817190c5444294e0cc45bd571bfafbbb537 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Thu, 10 Jul 2014 18:02:46 +0800 Subject: ipv6: fix the check when handle RA d9333196572(ipv6: Allow accepting RA from local IP addresses.) made the wrong check, whether or not to accept RA with source-addr found on local machine, when accept_ra_from_local is 0. Fixes: d9333196572(ipv6: Allow accepting RA from local IP addresses.) Cc: Ben Greear Cc: Hannes Frederic Sowa Signed-off-by: Li RongQing Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index a845e3d2057e..b7ece278dd49 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1151,9 +1151,9 @@ static void ndisc_router_discovery(struct sk_buff *skb) /* Do not accept RA with source-addr found on local machine unless * accept_ra_from_local is set to true. */ - if (!(in6_dev->cnf.accept_ra_from_local || - ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, - NULL, 0))) { + if (!in6_dev->cnf.accept_ra_from_local && + ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, + NULL, 0)) { ND_PRINTK(2, info, "RA from local address detected on dev: %s: default router ignored\n", skb->dev->name); @@ -1294,9 +1294,9 @@ skip_linkparms: } #ifdef CONFIG_IPV6_ROUTE_INFO - if (!(in6_dev->cnf.accept_ra_from_local || - ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, - NULL, 0))) { + if (!in6_dev->cnf.accept_ra_from_local && + ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, + NULL, 0)) { ND_PRINTK(2, info, "RA from local address detected on dev: %s: router info ignored.\n", skb->dev->name); -- cgit v1.2.3 From 3f518509dedc99f0b755d2ce68d24f610e3a005a Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Thu, 10 Jul 2014 16:52:13 -0300 Subject: ethernet: Add new driver for Marvell Armada 375 network unit This commit adds a new network driver for the network controller in Marvell Armada 375 SoC. Given the controller is very different from the ones in the other Marvell SoCs that use the mv643xx_eth (Kirkwood, Orion, Discovery) and mvneta (Armada 370/38x/XP) drivers, a new driver is needed. Signed-off-by: Marcin Wojtas [Ezequiel: coding style cleanup] Signed-off-by: Ezequiel Garcia Signed-off-by: David S. Miller --- .../devicetree/bindings/net/marvell-pp2.txt | 61 + drivers/net/ethernet/marvell/Kconfig | 8 + drivers/net/ethernet/marvell/Makefile | 1 + drivers/net/ethernet/marvell/mvpp2.c | 6393 ++++++++++++++++++++ 4 files changed, 6463 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/marvell-pp2.txt create mode 100644 drivers/net/ethernet/marvell/mvpp2.c diff --git a/Documentation/devicetree/bindings/net/marvell-pp2.txt b/Documentation/devicetree/bindings/net/marvell-pp2.txt new file mode 100644 index 000000000000..aa4f4230bfd7 --- /dev/null +++ b/Documentation/devicetree/bindings/net/marvell-pp2.txt @@ -0,0 +1,61 @@ +* Marvell Armada 375 Ethernet Controller (PPv2) + +Required properties: + +- compatible: should be "marvell,armada-375-pp2" +- reg: addresses and length of the register sets for the device. + Must contain the following register sets: + - common controller registers + - LMS registers + In addition, at least one port register set is required. +- clocks: a pointer to the reference clocks for this device, consequently: + - main controller clock + - GOP clock +- clock-names: names of used clocks, must be "pp_clk" and "gop_clk". + +The ethernet ports are represented by subnodes. At least one port is +required. + +Required properties (port): + +- interrupts: interrupt for the port +- port-id: should be '0' or '1' for ethernet ports, and '2' for the + loopback port +- phy-mode: See ethernet.txt file in the same directory + +Optional properties (port): + +- marvell,loopback: port is loopback mode +- phy: a phandle to a phy node defining the PHY address (as the reg + property, a single integer). Note: if this property isn't present, + then fixed link is assumed, and the 'fixed-link' property is + mandatory. + +Example: + +ethernet@f0000 { + compatible = "marvell,armada-375-pp2"; + reg = <0xf0000 0xa000>, + <0xc0000 0x3060>, + <0xc4000 0x100>, + <0xc5000 0x100>; + clocks = <&gateclk 3>, <&gateclk 19>; + clock-names = "pp_clk", "gop_clk"; + status = "okay"; + + eth0: eth0@c4000 { + interrupts = ; + port-id = <0>; + status = "okay"; + phy = <&phy0>; + phy-mode = "gmii"; + }; + + eth1: eth1@c5000 { + interrupts = ; + port-id = <1>; + status = "okay"; + phy = <&phy3>; + phy-mode = "gmii"; + }; +}; diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index 68e6a6613e9a..1b4fc7c639e6 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -54,6 +54,14 @@ config MVNETA driver, which should be used for the older Marvell SoCs (Dove, Orion, Discovery, Kirkwood). +config MVPP2 + tristate "Marvell Armada 375 network interface support" + depends on MACH_ARMADA_375 + select MVMDIO + ---help--- + This driver supports the network interface units in the + Marvell ARMADA 375 SoC. + config PXA168_ETH tristate "Marvell pxa168 ethernet support" depends on CPU_PXA168 diff --git a/drivers/net/ethernet/marvell/Makefile b/drivers/net/ethernet/marvell/Makefile index 5c4a7765ff0e..f6425bd2884b 100644 --- a/drivers/net/ethernet/marvell/Makefile +++ b/drivers/net/ethernet/marvell/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_MVMDIO) += mvmdio.o obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o obj-$(CONFIG_MVNETA) += mvneta.o +obj-$(CONFIG_MVPP2) += mvpp2.o obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SKY2) += sky2.o diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c new file mode 100644 index 000000000000..9463ede32e6a --- /dev/null +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -0,0 +1,6393 @@ +/* + * Driver for Marvell PPv2 network controller for Armada 375 SoC. + * + * Copyright (C) 2014 Marvell + * + * Marcin Wojtas + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* RX Fifo Registers */ +#define MVPP2_RX_DATA_FIFO_SIZE_REG(port) (0x00 + 4 * (port)) +#define MVPP2_RX_ATTR_FIFO_SIZE_REG(port) (0x20 + 4 * (port)) +#define MVPP2_RX_MIN_PKT_SIZE_REG 0x60 +#define MVPP2_RX_FIFO_INIT_REG 0x64 + +/* RX DMA Top Registers */ +#define MVPP2_RX_CTRL_REG(port) (0x140 + 4 * (port)) +#define MVPP2_RX_LOW_LATENCY_PKT_SIZE(s) (((s) & 0xfff) << 16) +#define MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK BIT(31) +#define MVPP2_POOL_BUF_SIZE_REG(pool) (0x180 + 4 * (pool)) +#define MVPP2_POOL_BUF_SIZE_OFFSET 5 +#define MVPP2_RXQ_CONFIG_REG(rxq) (0x800 + 4 * (rxq)) +#define MVPP2_SNOOP_PKT_SIZE_MASK 0x1ff +#define MVPP2_SNOOP_BUF_HDR_MASK BIT(9) +#define MVPP2_RXQ_POOL_SHORT_OFFS 20 +#define MVPP2_RXQ_POOL_SHORT_MASK 0x700000 +#define MVPP2_RXQ_POOL_LONG_OFFS 24 +#define MVPP2_RXQ_POOL_LONG_MASK 0x7000000 +#define MVPP2_RXQ_PACKET_OFFSET_OFFS 28 +#define MVPP2_RXQ_PACKET_OFFSET_MASK 0x70000000 +#define MVPP2_RXQ_DISABLE_MASK BIT(31) + +/* Parser Registers */ +#define MVPP2_PRS_INIT_LOOKUP_REG 0x1000 +#define MVPP2_PRS_PORT_LU_MAX 0xf +#define MVPP2_PRS_PORT_LU_MASK(port) (0xff << ((port) * 4)) +#define MVPP2_PRS_PORT_LU_VAL(port, val) ((val) << ((port) * 4)) +#define MVPP2_PRS_INIT_OFFS_REG(port) (0x1004 + ((port) & 4)) +#define MVPP2_PRS_INIT_OFF_MASK(port) (0x3f << (((port) % 4) * 8)) +#define MVPP2_PRS_INIT_OFF_VAL(port, val) ((val) << (((port) % 4) * 8)) +#define MVPP2_PRS_MAX_LOOP_REG(port) (0x100c + ((port) & 4)) +#define MVPP2_PRS_MAX_LOOP_MASK(port) (0xff << (((port) % 4) * 8)) +#define MVPP2_PRS_MAX_LOOP_VAL(port, val) ((val) << (((port) % 4) * 8)) +#define MVPP2_PRS_TCAM_IDX_REG 0x1100 +#define MVPP2_PRS_TCAM_DATA_REG(idx) (0x1104 + (idx) * 4) +#define MVPP2_PRS_TCAM_INV_MASK BIT(31) +#define MVPP2_PRS_SRAM_IDX_REG 0x1200 +#define MVPP2_PRS_SRAM_DATA_REG(idx) (0x1204 + (idx) * 4) +#define MVPP2_PRS_TCAM_CTRL_REG 0x1230 +#define MVPP2_PRS_TCAM_EN_MASK BIT(0) + +/* Classifier Registers */ +#define MVPP2_CLS_MODE_REG 0x1800 +#define MVPP2_CLS_MODE_ACTIVE_MASK BIT(0) +#define MVPP2_CLS_PORT_WAY_REG 0x1810 +#define MVPP2_CLS_PORT_WAY_MASK(port) (1 << (port)) +#define MVPP2_CLS_LKP_INDEX_REG 0x1814 +#define MVPP2_CLS_LKP_INDEX_WAY_OFFS 6 +#define MVPP2_CLS_LKP_TBL_REG 0x1818 +#define MVPP2_CLS_LKP_TBL_RXQ_MASK 0xff +#define MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK BIT(25) +#define MVPP2_CLS_FLOW_INDEX_REG 0x1820 +#define MVPP2_CLS_FLOW_TBL0_REG 0x1824 +#define MVPP2_CLS_FLOW_TBL1_REG 0x1828 +#define MVPP2_CLS_FLOW_TBL2_REG 0x182c +#define MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(port) (0x1980 + ((port) * 4)) +#define MVPP2_CLS_OVERSIZE_RXQ_LOW_BITS 3 +#define MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK 0x7 +#define MVPP2_CLS_SWFWD_P2HQ_REG(port) (0x19b0 + ((port) * 4)) +#define MVPP2_CLS_SWFWD_PCTRL_REG 0x19d0 +#define MVPP2_CLS_SWFWD_PCTRL_MASK(port) (1 << (port)) + +/* Descriptor Manager Top Registers */ +#define MVPP2_RXQ_NUM_REG 0x2040 +#define MVPP2_RXQ_DESC_ADDR_REG 0x2044 +#define MVPP2_RXQ_DESC_SIZE_REG 0x2048 +#define MVPP2_RXQ_DESC_SIZE_MASK 0x3ff0 +#define MVPP2_RXQ_STATUS_UPDATE_REG(rxq) (0x3000 + 4 * (rxq)) +#define MVPP2_RXQ_NUM_PROCESSED_OFFSET 0 +#define MVPP2_RXQ_NUM_NEW_OFFSET 16 +#define MVPP2_RXQ_STATUS_REG(rxq) (0x3400 + 4 * (rxq)) +#define MVPP2_RXQ_OCCUPIED_MASK 0x3fff +#define MVPP2_RXQ_NON_OCCUPIED_OFFSET 16 +#define MVPP2_RXQ_NON_OCCUPIED_MASK 0x3fff0000 +#define MVPP2_RXQ_THRESH_REG 0x204c +#define MVPP2_OCCUPIED_THRESH_OFFSET 0 +#define MVPP2_OCCUPIED_THRESH_MASK 0x3fff +#define MVPP2_RXQ_INDEX_REG 0x2050 +#define MVPP2_TXQ_NUM_REG 0x2080 +#define MVPP2_TXQ_DESC_ADDR_REG 0x2084 +#define MVPP2_TXQ_DESC_SIZE_REG 0x2088 +#define MVPP2_TXQ_DESC_SIZE_MASK 0x3ff0 +#define MVPP2_AGGR_TXQ_UPDATE_REG 0x2090 +#define MVPP2_TXQ_THRESH_REG 0x2094 +#define MVPP2_TRANSMITTED_THRESH_OFFSET 16 +#define MVPP2_TRANSMITTED_THRESH_MASK 0x3fff0000 +#define MVPP2_TXQ_INDEX_REG 0x2098 +#define MVPP2_TXQ_PREF_BUF_REG 0x209c +#define MVPP2_PREF_BUF_PTR(desc) ((desc) & 0xfff) +#define MVPP2_PREF_BUF_SIZE_4 (BIT(12) | BIT(13)) +#define MVPP2_PREF_BUF_SIZE_16 (BIT(12) | BIT(14)) +#define MVPP2_PREF_BUF_THRESH(val) ((val) << 17) +#define MVPP2_TXQ_DRAIN_EN_MASK BIT(31) +#define MVPP2_TXQ_PENDING_REG 0x20a0 +#define MVPP2_TXQ_PENDING_MASK 0x3fff +#define MVPP2_TXQ_INT_STATUS_REG 0x20a4 +#define MVPP2_TXQ_SENT_REG(txq) (0x3c00 + 4 * (txq)) +#define MVPP2_TRANSMITTED_COUNT_OFFSET 16 +#define MVPP2_TRANSMITTED_COUNT_MASK 0x3fff0000 +#define MVPP2_TXQ_RSVD_REQ_REG 0x20b0 +#define MVPP2_TXQ_RSVD_REQ_Q_OFFSET 16 +#define MVPP2_TXQ_RSVD_RSLT_REG 0x20b4 +#define MVPP2_TXQ_RSVD_RSLT_MASK 0x3fff +#define MVPP2_TXQ_RSVD_CLR_REG 0x20b8 +#define MVPP2_TXQ_RSVD_CLR_OFFSET 16 +#define MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu) (0x2100 + 4 * (cpu)) +#define MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu) (0x2140 + 4 * (cpu)) +#define MVPP2_AGGR_TXQ_DESC_SIZE_MASK 0x3ff0 +#define MVPP2_AGGR_TXQ_STATUS_REG(cpu) (0x2180 + 4 * (cpu)) +#define MVPP2_AGGR_TXQ_PENDING_MASK 0x3fff +#define MVPP2_AGGR_TXQ_INDEX_REG(cpu) (0x21c0 + 4 * (cpu)) + +/* MBUS bridge registers */ +#define MVPP2_WIN_BASE(w) (0x4000 + ((w) << 2)) +#define MVPP2_WIN_SIZE(w) (0x4020 + ((w) << 2)) +#define MVPP2_WIN_REMAP(w) (0x4040 + ((w) << 2)) +#define MVPP2_BASE_ADDR_ENABLE 0x4060 + +/* Interrupt Cause and Mask registers */ +#define MVPP2_ISR_RX_THRESHOLD_REG(rxq) (0x5200 + 4 * (rxq)) +#define MVPP2_ISR_RXQ_GROUP_REG(rxq) (0x5400 + 4 * (rxq)) +#define MVPP2_ISR_ENABLE_REG(port) (0x5420 + 4 * (port)) +#define MVPP2_ISR_ENABLE_INTERRUPT(mask) ((mask) & 0xffff) +#define MVPP2_ISR_DISABLE_INTERRUPT(mask) (((mask) << 16) & 0xffff0000) +#define MVPP2_ISR_RX_TX_CAUSE_REG(port) (0x5480 + 4 * (port)) +#define MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK 0xffff +#define MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK 0xff0000 +#define MVPP2_CAUSE_RX_FIFO_OVERRUN_MASK BIT(24) +#define MVPP2_CAUSE_FCS_ERR_MASK BIT(25) +#define MVPP2_CAUSE_TX_FIFO_UNDERRUN_MASK BIT(26) +#define MVPP2_CAUSE_TX_EXCEPTION_SUM_MASK BIT(29) +#define MVPP2_CAUSE_RX_EXCEPTION_SUM_MASK BIT(30) +#define MVPP2_CAUSE_MISC_SUM_MASK BIT(31) +#define MVPP2_ISR_RX_TX_MASK_REG(port) (0x54a0 + 4 * (port)) +#define MVPP2_ISR_PON_RX_TX_MASK_REG 0x54bc +#define MVPP2_PON_CAUSE_RXQ_OCCUP_DESC_ALL_MASK 0xffff +#define MVPP2_PON_CAUSE_TXP_OCCUP_DESC_ALL_MASK 0x3fc00000 +#define MVPP2_PON_CAUSE_MISC_SUM_MASK BIT(31) +#define MVPP2_ISR_MISC_CAUSE_REG 0x55b0 + +/* Buffer Manager registers */ +#define MVPP2_BM_POOL_BASE_REG(pool) (0x6000 + ((pool) * 4)) +#define MVPP2_BM_POOL_BASE_ADDR_MASK 0xfffff80 +#define MVPP2_BM_POOL_SIZE_REG(pool) (0x6040 + ((pool) * 4)) +#define MVPP2_BM_POOL_SIZE_MASK 0xfff0 +#define MVPP2_BM_POOL_READ_PTR_REG(pool) (0x6080 + ((pool) * 4)) +#define MVPP2_BM_POOL_GET_READ_PTR_MASK 0xfff0 +#define MVPP2_BM_POOL_PTRS_NUM_REG(pool) (0x60c0 + ((pool) * 4)) +#define MVPP2_BM_POOL_PTRS_NUM_MASK 0xfff0 +#define MVPP2_BM_BPPI_READ_PTR_REG(pool) (0x6100 + ((pool) * 4)) +#define MVPP2_BM_BPPI_PTRS_NUM_REG(pool) (0x6140 + ((pool) * 4)) +#define MVPP2_BM_BPPI_PTR_NUM_MASK 0x7ff +#define MVPP2_BM_BPPI_PREFETCH_FULL_MASK BIT(16) +#define MVPP2_BM_POOL_CTRL_REG(pool) (0x6200 + ((pool) * 4)) +#define MVPP2_BM_START_MASK BIT(0) +#define MVPP2_BM_STOP_MASK BIT(1) +#define MVPP2_BM_STATE_MASK BIT(4) +#define MVPP2_BM_LOW_THRESH_OFFS 8 +#define MVPP2_BM_LOW_THRESH_MASK 0x7f00 +#define MVPP2_BM_LOW_THRESH_VALUE(val) ((val) << \ + MVPP2_BM_LOW_THRESH_OFFS) +#define MVPP2_BM_HIGH_THRESH_OFFS 16 +#define MVPP2_BM_HIGH_THRESH_MASK 0x7f0000 +#define MVPP2_BM_HIGH_THRESH_VALUE(val) ((val) << \ + MVPP2_BM_HIGH_THRESH_OFFS) +#define MVPP2_BM_INTR_CAUSE_REG(pool) (0x6240 + ((pool) * 4)) +#define MVPP2_BM_RELEASED_DELAY_MASK BIT(0) +#define MVPP2_BM_ALLOC_FAILED_MASK BIT(1) +#define MVPP2_BM_BPPE_EMPTY_MASK BIT(2) +#define MVPP2_BM_BPPE_FULL_MASK BIT(3) +#define MVPP2_BM_AVAILABLE_BP_LOW_MASK BIT(4) +#define MVPP2_BM_INTR_MASK_REG(pool) (0x6280 + ((pool) * 4)) +#define MVPP2_BM_PHY_ALLOC_REG(pool) (0x6400 + ((pool) * 4)) +#define MVPP2_BM_PHY_ALLOC_GRNTD_MASK BIT(0) +#define MVPP2_BM_VIRT_ALLOC_REG 0x6440 +#define MVPP2_BM_PHY_RLS_REG(pool) (0x6480 + ((pool) * 4)) +#define MVPP2_BM_PHY_RLS_MC_BUFF_MASK BIT(0) +#define MVPP2_BM_PHY_RLS_PRIO_EN_MASK BIT(1) +#define MVPP2_BM_PHY_RLS_GRNTD_MASK BIT(2) +#define MVPP2_BM_VIRT_RLS_REG 0x64c0 +#define MVPP2_BM_MC_RLS_REG 0x64c4 +#define MVPP2_BM_MC_ID_MASK 0xfff +#define MVPP2_BM_FORCE_RELEASE_MASK BIT(12) + +/* TX Scheduler registers */ +#define MVPP2_TXP_SCHED_PORT_INDEX_REG 0x8000 +#define MVPP2_TXP_SCHED_Q_CMD_REG 0x8004 +#define MVPP2_TXP_SCHED_ENQ_MASK 0xff +#define MVPP2_TXP_SCHED_DISQ_OFFSET 8 +#define MVPP2_TXP_SCHED_CMD_1_REG 0x8010 +#define MVPP2_TXP_SCHED_PERIOD_REG 0x8018 +#define MVPP2_TXP_SCHED_MTU_REG 0x801c +#define MVPP2_TXP_MTU_MAX 0x7FFFF +#define MVPP2_TXP_SCHED_REFILL_REG 0x8020 +#define MVPP2_TXP_REFILL_TOKENS_ALL_MASK 0x7ffff +#define MVPP2_TXP_REFILL_PERIOD_ALL_MASK 0x3ff00000 +#define MVPP2_TXP_REFILL_PERIOD_MASK(v) ((v) << 20) +#define MVPP2_TXP_SCHED_TOKEN_SIZE_REG 0x8024 +#define MVPP2_TXP_TOKEN_SIZE_MAX 0xffffffff +#define MVPP2_TXQ_SCHED_REFILL_REG(q) (0x8040 + ((q) << 2)) +#define MVPP2_TXQ_REFILL_TOKENS_ALL_MASK 0x7ffff +#define MVPP2_TXQ_REFILL_PERIOD_ALL_MASK 0x3ff00000 +#define MVPP2_TXQ_REFILL_PERIOD_MASK(v) ((v) << 20) +#define MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(q) (0x8060 + ((q) << 2)) +#define MVPP2_TXQ_TOKEN_SIZE_MAX 0x7fffffff +#define MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(q) (0x8080 + ((q) << 2)) +#define MVPP2_TXQ_TOKEN_CNTR_MAX 0xffffffff + +/* TX general registers */ +#define MVPP2_TX_SNOOP_REG 0x8800 +#define MVPP2_TX_PORT_FLUSH_REG 0x8810 +#define MVPP2_TX_PORT_FLUSH_MASK(port) (1 << (port)) + +/* LMS registers */ +#define MVPP2_SRC_ADDR_MIDDLE 0x24 +#define MVPP2_SRC_ADDR_HIGH 0x28 +#define MVPP2_MIB_COUNTERS_BASE(port) (0x1000 + ((port) >> 1) * \ + 0x400 + (port) * 0x400) +#define MVPP2_MIB_LATE_COLLISION 0x7c +#define MVPP2_ISR_SUM_MASK_REG 0x220c +#define MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG 0x305c +#define MVPP2_EXT_GLOBAL_CTRL_DEFAULT 0x27 + +/* Per-port registers */ +#define MVPP2_GMAC_CTRL_0_REG 0x0 +#define MVPP2_GMAC_PORT_EN_MASK BIT(0) +#define MVPP2_GMAC_MAX_RX_SIZE_OFFS 2 +#define MVPP2_GMAC_MAX_RX_SIZE_MASK 0x7ffc +#define MVPP2_GMAC_MIB_CNTR_EN_MASK BIT(15) +#define MVPP2_GMAC_CTRL_1_REG 0x4 +#define MVPP2_GMAC_PERIODIC_XON_EN_MASK BIT(0) +#define MVPP2_GMAC_GMII_LB_EN_MASK BIT(5) +#define MVPP2_GMAC_PCS_LB_EN_BIT 6 +#define MVPP2_GMAC_PCS_LB_EN_MASK BIT(6) +#define MVPP2_GMAC_SA_LOW_OFFS 7 +#define MVPP2_GMAC_CTRL_2_REG 0x8 +#define MVPP2_GMAC_INBAND_AN_MASK BIT(0) +#define MVPP2_GMAC_PCS_ENABLE_MASK BIT(3) +#define MVPP2_GMAC_PORT_RGMII_MASK BIT(4) +#define MVPP2_GMAC_PORT_RESET_MASK BIT(6) +#define MVPP2_GMAC_AUTONEG_CONFIG 0xc +#define MVPP2_GMAC_FORCE_LINK_DOWN BIT(0) +#define MVPP2_GMAC_FORCE_LINK_PASS BIT(1) +#define MVPP2_GMAC_CONFIG_MII_SPEED BIT(5) +#define MVPP2_GMAC_CONFIG_GMII_SPEED BIT(6) +#define MVPP2_GMAC_AN_SPEED_EN BIT(7) +#define MVPP2_GMAC_CONFIG_FULL_DUPLEX BIT(12) +#define MVPP2_GMAC_AN_DUPLEX_EN BIT(13) +#define MVPP2_GMAC_PORT_FIFO_CFG_1_REG 0x1c +#define MVPP2_GMAC_TX_FIFO_MIN_TH_OFFS 6 +#define MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK 0x1fc0 +#define MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(v) (((v) << 6) & \ + MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK) + +#define MVPP2_CAUSE_TXQ_SENT_DESC_ALL_MASK 0xff + +/* Descriptor ring Macros */ +#define MVPP2_QUEUE_NEXT_DESC(q, index) \ + (((index) < (q)->last_desc) ? ((index) + 1) : 0) + +/* Various constants */ + +/* Coalescing */ +#define MVPP2_TXDONE_COAL_PKTS_THRESH 15 +#define MVPP2_RX_COAL_PKTS 32 +#define MVPP2_RX_COAL_USEC 100 + +/* The two bytes Marvell header. Either contains a special value used + * by Marvell switches when a specific hardware mode is enabled (not + * supported by this driver) or is filled automatically by zeroes on + * the RX side. Those two bytes being at the front of the Ethernet + * header, they allow to have the IP header aligned on a 4 bytes + * boundary automatically: the hardware skips those two bytes on its + * own. + */ +#define MVPP2_MH_SIZE 2 +#define MVPP2_ETH_TYPE_LEN 2 +#define MVPP2_PPPOE_HDR_SIZE 8 +#define MVPP2_VLAN_TAG_LEN 4 + +/* Lbtd 802.3 type */ +#define MVPP2_IP_LBDT_TYPE 0xfffa + +#define MVPP2_CPU_D_CACHE_LINE_SIZE 32 +#define MVPP2_TX_CSUM_MAX_SIZE 9800 + +/* Timeout constants */ +#define MVPP2_TX_DISABLE_TIMEOUT_MSEC 1000 +#define MVPP2_TX_PENDING_TIMEOUT_MSEC 1000 + +#define MVPP2_TX_MTU_MAX 0x7ffff + +/* Maximum number of T-CONTs of PON port */ +#define MVPP2_MAX_TCONT 16 + +/* Maximum number of supported ports */ +#define MVPP2_MAX_PORTS 4 + +/* Maximum number of TXQs used by single port */ +#define MVPP2_MAX_TXQ 8 + +/* Maximum number of RXQs used by single port */ +#define MVPP2_MAX_RXQ 8 + +/* Dfault number of RXQs in use */ +#define MVPP2_DEFAULT_RXQ 4 + +/* Total number of RXQs available to all ports */ +#define MVPP2_RXQ_TOTAL_NUM (MVPP2_MAX_PORTS * MVPP2_MAX_RXQ) + +/* Max number of Rx descriptors */ +#define MVPP2_MAX_RXD 128 + +/* Max number of Tx descriptors */ +#define MVPP2_MAX_TXD 1024 + +/* Amount of Tx descriptors that can be reserved at once by CPU */ +#define MVPP2_CPU_DESC_CHUNK 64 + +/* Max number of Tx descriptors in each aggregated queue */ +#define MVPP2_AGGR_TXQ_SIZE 256 + +/* Descriptor aligned size */ +#define MVPP2_DESC_ALIGNED_SIZE 32 + +/* Descriptor alignment mask */ +#define MVPP2_TX_DESC_ALIGN (MVPP2_DESC_ALIGNED_SIZE - 1) + +/* RX FIFO constants */ +#define MVPP2_RX_FIFO_PORT_DATA_SIZE 0x2000 +#define MVPP2_RX_FIFO_PORT_ATTR_SIZE 0x80 +#define MVPP2_RX_FIFO_PORT_MIN_PKT 0x80 + +/* RX buffer constants */ +#define MVPP2_SKB_SHINFO_SIZE \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + +#define MVPP2_RX_PKT_SIZE(mtu) \ + ALIGN((mtu) + MVPP2_MH_SIZE + MVPP2_VLAN_TAG_LEN + \ + ETH_HLEN + ETH_FCS_LEN, MVPP2_CPU_D_CACHE_LINE_SIZE) + +#define MVPP2_RX_BUF_SIZE(pkt_size) ((pkt_size) + NET_SKB_PAD) +#define MVPP2_RX_TOTAL_SIZE(buf_size) ((buf_size) + MVPP2_SKB_SHINFO_SIZE) +#define MVPP2_RX_MAX_PKT_SIZE(total_size) \ + ((total_size) - NET_SKB_PAD - MVPP2_SKB_SHINFO_SIZE) + +#define MVPP2_BIT_TO_BYTE(bit) ((bit) / 8) + +/* IPv6 max L3 address size */ +#define MVPP2_MAX_L3_ADDR_SIZE 16 + +/* Port flags */ +#define MVPP2_F_LOOPBACK BIT(0) + +/* Marvell tag types */ +enum mvpp2_tag_type { + MVPP2_TAG_TYPE_NONE = 0, + MVPP2_TAG_TYPE_MH = 1, + MVPP2_TAG_TYPE_DSA = 2, + MVPP2_TAG_TYPE_EDSA = 3, + MVPP2_TAG_TYPE_VLAN = 4, + MVPP2_TAG_TYPE_LAST = 5 +}; + +/* Parser constants */ +#define MVPP2_PRS_TCAM_SRAM_SIZE 256 +#define MVPP2_PRS_TCAM_WORDS 6 +#define MVPP2_PRS_SRAM_WORDS 4 +#define MVPP2_PRS_FLOW_ID_SIZE 64 +#define MVPP2_PRS_FLOW_ID_MASK 0x3f +#define MVPP2_PRS_TCAM_ENTRY_INVALID 1 +#define MVPP2_PRS_TCAM_DSA_TAGGED_BIT BIT(5) +#define MVPP2_PRS_IPV4_HEAD 0x40 +#define MVPP2_PRS_IPV4_HEAD_MASK 0xf0 +#define MVPP2_PRS_IPV4_MC 0xe0 +#define MVPP2_PRS_IPV4_MC_MASK 0xf0 +#define MVPP2_PRS_IPV4_BC_MASK 0xff +#define MVPP2_PRS_IPV4_IHL 0x5 +#define MVPP2_PRS_IPV4_IHL_MASK 0xf +#define MVPP2_PRS_IPV6_MC 0xff +#define MVPP2_PRS_IPV6_MC_MASK 0xff +#define MVPP2_PRS_IPV6_HOP_MASK 0xff +#define MVPP2_PRS_TCAM_PROTO_MASK 0xff +#define MVPP2_PRS_TCAM_PROTO_MASK_L 0x3f +#define MVPP2_PRS_DBL_VLANS_MAX 100 + +/* Tcam structure: + * - lookup ID - 4 bits + * - port ID - 1 byte + * - additional information - 1 byte + * - header data - 8 bytes + * The fields are represented by MVPP2_PRS_TCAM_DATA_REG(5)->(0). + */ +#define MVPP2_PRS_AI_BITS 8 +#define MVPP2_PRS_PORT_MASK 0xff +#define MVPP2_PRS_LU_MASK 0xf +#define MVPP2_PRS_TCAM_DATA_BYTE(offs) \ + (((offs) - ((offs) % 2)) * 2 + ((offs) % 2)) +#define MVPP2_PRS_TCAM_DATA_BYTE_EN(offs) \ + (((offs) * 2) - ((offs) % 2) + 2) +#define MVPP2_PRS_TCAM_AI_BYTE 16 +#define MVPP2_PRS_TCAM_PORT_BYTE 17 +#define MVPP2_PRS_TCAM_LU_BYTE 20 +#define MVPP2_PRS_TCAM_EN_OFFS(offs) ((offs) + 2) +#define MVPP2_PRS_TCAM_INV_WORD 5 +/* Tcam entries ID */ +#define MVPP2_PE_DROP_ALL 0 +#define MVPP2_PE_FIRST_FREE_TID 1 +#define MVPP2_PE_LAST_FREE_TID (MVPP2_PRS_TCAM_SRAM_SIZE - 31) +#define MVPP2_PE_IP6_EXT_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 30) +#define MVPP2_PE_MAC_MC_IP6 (MVPP2_PRS_TCAM_SRAM_SIZE - 29) +#define MVPP2_PE_IP6_ADDR_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 28) +#define MVPP2_PE_IP4_ADDR_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 27) +#define MVPP2_PE_LAST_DEFAULT_FLOW (MVPP2_PRS_TCAM_SRAM_SIZE - 26) +#define MVPP2_PE_FIRST_DEFAULT_FLOW (MVPP2_PRS_TCAM_SRAM_SIZE - 19) +#define MVPP2_PE_EDSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 18) +#define MVPP2_PE_EDSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 17) +#define MVPP2_PE_DSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 16) +#define MVPP2_PE_DSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 15) +#define MVPP2_PE_ETYPE_EDSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 14) +#define MVPP2_PE_ETYPE_EDSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 13) +#define MVPP2_PE_ETYPE_DSA_TAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 12) +#define MVPP2_PE_ETYPE_DSA_UNTAGGED (MVPP2_PRS_TCAM_SRAM_SIZE - 11) +#define MVPP2_PE_MH_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 10) +#define MVPP2_PE_DSA_DEFAULT (MVPP2_PRS_TCAM_SRAM_SIZE - 9) +#define MVPP2_PE_IP6_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 8) +#define MVPP2_PE_IP4_PROTO_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 7) +#define MVPP2_PE_ETH_TYPE_UN (MVPP2_PRS_TCAM_SRAM_SIZE - 6) +#define MVPP2_PE_VLAN_DBL (MVPP2_PRS_TCAM_SRAM_SIZE - 5) +#define MVPP2_PE_VLAN_NONE (MVPP2_PRS_TCAM_SRAM_SIZE - 4) +#define MVPP2_PE_MAC_MC_ALL (MVPP2_PRS_TCAM_SRAM_SIZE - 3) +#define MVPP2_PE_MAC_PROMISCUOUS (MVPP2_PRS_TCAM_SRAM_SIZE - 2) +#define MVPP2_PE_MAC_NON_PROMISCUOUS (MVPP2_PRS_TCAM_SRAM_SIZE - 1) + +/* Sram structure + * The fields are represented by MVPP2_PRS_TCAM_DATA_REG(3)->(0). + */ +#define MVPP2_PRS_SRAM_RI_OFFS 0 +#define MVPP2_PRS_SRAM_RI_WORD 0 +#define MVPP2_PRS_SRAM_RI_CTRL_OFFS 32 +#define MVPP2_PRS_SRAM_RI_CTRL_WORD 1 +#define MVPP2_PRS_SRAM_RI_CTRL_BITS 32 +#define MVPP2_PRS_SRAM_SHIFT_OFFS 64 +#define MVPP2_PRS_SRAM_SHIFT_SIGN_BIT 72 +#define MVPP2_PRS_SRAM_UDF_OFFS 73 +#define MVPP2_PRS_SRAM_UDF_BITS 8 +#define MVPP2_PRS_SRAM_UDF_MASK 0xff +#define MVPP2_PRS_SRAM_UDF_SIGN_BIT 81 +#define MVPP2_PRS_SRAM_UDF_TYPE_OFFS 82 +#define MVPP2_PRS_SRAM_UDF_TYPE_MASK 0x7 +#define MVPP2_PRS_SRAM_UDF_TYPE_L3 1 +#define MVPP2_PRS_SRAM_UDF_TYPE_L4 4 +#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS 85 +#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_MASK 0x3 +#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD 1 +#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_IP4_ADD 2 +#define MVPP2_PRS_SRAM_OP_SEL_SHIFT_IP6_ADD 3 +#define MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS 87 +#define MVPP2_PRS_SRAM_OP_SEL_UDF_BITS 2 +#define MVPP2_PRS_SRAM_OP_SEL_UDF_MASK 0x3 +#define MVPP2_PRS_SRAM_OP_SEL_UDF_ADD 0 +#define MVPP2_PRS_SRAM_OP_SEL_UDF_IP4_ADD 2 +#define MVPP2_PRS_SRAM_OP_SEL_UDF_IP6_ADD 3 +#define MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS 89 +#define MVPP2_PRS_SRAM_AI_OFFS 90 +#define MVPP2_PRS_SRAM_AI_CTRL_OFFS 98 +#define MVPP2_PRS_SRAM_AI_CTRL_BITS 8 +#define MVPP2_PRS_SRAM_AI_MASK 0xff +#define MVPP2_PRS_SRAM_NEXT_LU_OFFS 106 +#define MVPP2_PRS_SRAM_NEXT_LU_MASK 0xf +#define MVPP2_PRS_SRAM_LU_DONE_BIT 110 +#define MVPP2_PRS_SRAM_LU_GEN_BIT 111 + +/* Sram result info bits assignment */ +#define MVPP2_PRS_RI_MAC_ME_MASK 0x1 +#define MVPP2_PRS_RI_DSA_MASK 0x2 +#define MVPP2_PRS_RI_VLAN_MASK 0xc +#define MVPP2_PRS_RI_VLAN_NONE ~(BIT(2) | BIT(3)) +#define MVPP2_PRS_RI_VLAN_SINGLE BIT(2) +#define MVPP2_PRS_RI_VLAN_DOUBLE BIT(3) +#define MVPP2_PRS_RI_VLAN_TRIPLE (BIT(2) | BIT(3)) +#define MVPP2_PRS_RI_CPU_CODE_MASK 0x70 +#define MVPP2_PRS_RI_CPU_CODE_RX_SPEC BIT(4) +#define MVPP2_PRS_RI_L2_CAST_MASK 0x600 +#define MVPP2_PRS_RI_L2_UCAST ~(BIT(9) | BIT(10)) +#define MVPP2_PRS_RI_L2_MCAST BIT(9) +#define MVPP2_PRS_RI_L2_BCAST BIT(10) +#define MVPP2_PRS_RI_PPPOE_MASK 0x800 +#define MVPP2_PRS_RI_L3_PROTO_MASK 0x7000 +#define MVPP2_PRS_RI_L3_UN ~(BIT(12) | BIT(13) | BIT(14)) +#define MVPP2_PRS_RI_L3_IP4 BIT(12) +#define MVPP2_PRS_RI_L3_IP4_OPT BIT(13) +#define MVPP2_PRS_RI_L3_IP4_OTHER (BIT(12) | BIT(13)) +#define MVPP2_PRS_RI_L3_IP6 BIT(14) +#define MVPP2_PRS_RI_L3_IP6_EXT (BIT(12) | BIT(14)) +#define MVPP2_PRS_RI_L3_ARP (BIT(13) | BIT(14)) +#define MVPP2_PRS_RI_L3_ADDR_MASK 0x18000 +#define MVPP2_PRS_RI_L3_UCAST ~(BIT(15) | BIT(16)) +#define MVPP2_PRS_RI_L3_MCAST BIT(15) +#define MVPP2_PRS_RI_L3_BCAST (BIT(15) | BIT(16)) +#define MVPP2_PRS_RI_IP_FRAG_MASK 0x20000 +#define MVPP2_PRS_RI_UDF3_MASK 0x300000 +#define MVPP2_PRS_RI_UDF3_RX_SPECIAL BIT(21) +#define MVPP2_PRS_RI_L4_PROTO_MASK 0x1c00000 +#define MVPP2_PRS_RI_L4_TCP BIT(22) +#define MVPP2_PRS_RI_L4_UDP BIT(23) +#define MVPP2_PRS_RI_L4_OTHER (BIT(22) | BIT(23)) +#define MVPP2_PRS_RI_UDF7_MASK 0x60000000 +#define MVPP2_PRS_RI_UDF7_IP6_LITE BIT(29) +#define MVPP2_PRS_RI_DROP_MASK 0x80000000 + +/* Sram additional info bits assignment */ +#define MVPP2_PRS_IPV4_DIP_AI_BIT BIT(0) +#define MVPP2_PRS_IPV6_NO_EXT_AI_BIT BIT(0) +#define MVPP2_PRS_IPV6_EXT_AI_BIT BIT(1) +#define MVPP2_PRS_IPV6_EXT_AH_AI_BIT BIT(2) +#define MVPP2_PRS_IPV6_EXT_AH_LEN_AI_BIT BIT(3) +#define MVPP2_PRS_IPV6_EXT_AH_L4_AI_BIT BIT(4) +#define MVPP2_PRS_SINGLE_VLAN_AI 0 +#define MVPP2_PRS_DBL_VLAN_AI_BIT BIT(7) + +/* DSA/EDSA type */ +#define MVPP2_PRS_TAGGED true +#define MVPP2_PRS_UNTAGGED false +#define MVPP2_PRS_EDSA true +#define MVPP2_PRS_DSA false + +/* MAC entries, shadow udf */ +enum mvpp2_prs_udf { + MVPP2_PRS_UDF_MAC_DEF, + MVPP2_PRS_UDF_MAC_RANGE, + MVPP2_PRS_UDF_L2_DEF, + MVPP2_PRS_UDF_L2_DEF_COPY, + MVPP2_PRS_UDF_L2_USER, +}; + +/* Lookup ID */ +enum mvpp2_prs_lookup { + MVPP2_PRS_LU_MH, + MVPP2_PRS_LU_MAC, + MVPP2_PRS_LU_DSA, + MVPP2_PRS_LU_VLAN, + MVPP2_PRS_LU_L2, + MVPP2_PRS_LU_PPPOE, + MVPP2_PRS_LU_IP4, + MVPP2_PRS_LU_IP6, + MVPP2_PRS_LU_FLOWS, + MVPP2_PRS_LU_LAST, +}; + +/* L3 cast enum */ +enum mvpp2_prs_l3_cast { + MVPP2_PRS_L3_UNI_CAST, + MVPP2_PRS_L3_MULTI_CAST, + MVPP2_PRS_L3_BROAD_CAST +}; + +/* Classifier constants */ +#define MVPP2_CLS_FLOWS_TBL_SIZE 512 +#define MVPP2_CLS_FLOWS_TBL_DATA_WORDS 3 +#define MVPP2_CLS_LKP_TBL_SIZE 64 + +/* BM constants */ +#define MVPP2_BM_POOLS_NUM 8 +#define MVPP2_BM_LONG_BUF_NUM 1024 +#define MVPP2_BM_SHORT_BUF_NUM 2048 +#define MVPP2_BM_POOL_SIZE_MAX (16*1024 - MVPP2_BM_POOL_PTR_ALIGN/4) +#define MVPP2_BM_POOL_PTR_ALIGN 128 +#define MVPP2_BM_SWF_LONG_POOL(port) ((port > 2) ? 2 : port) +#define MVPP2_BM_SWF_SHORT_POOL 3 + +/* BM cookie (32 bits) definition */ +#define MVPP2_BM_COOKIE_POOL_OFFS 8 +#define MVPP2_BM_COOKIE_CPU_OFFS 24 + +/* BM short pool packet size + * These value assure that for SWF the total number + * of bytes allocated for each buffer will be 512 + */ +#define MVPP2_BM_SHORT_PKT_SIZE MVPP2_RX_MAX_PKT_SIZE(512) + +enum mvpp2_bm_type { + MVPP2_BM_FREE, + MVPP2_BM_SWF_LONG, + MVPP2_BM_SWF_SHORT +}; + +/* Definitions */ + +/* Shared Packet Processor resources */ +struct mvpp2 { + /* Shared registers' base addresses */ + void __iomem *base; + void __iomem *lms_base; + + /* Common clocks */ + struct clk *pp_clk; + struct clk *gop_clk; + + /* List of pointers to port structures */ + struct mvpp2_port **port_list; + + /* Aggregated TXQs */ + struct mvpp2_tx_queue *aggr_txqs; + + /* BM pools */ + struct mvpp2_bm_pool *bm_pools; + + /* PRS shadow table */ + struct mvpp2_prs_shadow *prs_shadow; + /* PRS auxiliary table for double vlan entries control */ + bool *prs_double_vlans; + + /* Tclk value */ + u32 tclk; +}; + +struct mvpp2_pcpu_stats { + struct u64_stats_sync syncp; + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; +}; + +struct mvpp2_port { + u8 id; + + int irq; + + struct mvpp2 *priv; + + /* Per-port registers' base address */ + void __iomem *base; + + struct mvpp2_rx_queue **rxqs; + struct mvpp2_tx_queue **txqs; + struct net_device *dev; + + int pkt_size; + + u32 pending_cause_rx; + struct napi_struct napi; + + /* Flags */ + unsigned long flags; + + u16 tx_ring_size; + u16 rx_ring_size; + struct mvpp2_pcpu_stats __percpu *stats; + + struct phy_device *phy_dev; + phy_interface_t phy_interface; + struct device_node *phy_node; + unsigned int link; + unsigned int duplex; + unsigned int speed; + + struct mvpp2_bm_pool *pool_long; + struct mvpp2_bm_pool *pool_short; + + /* Index of first port's physical RXQ */ + u8 first_rxq; +}; + +/* The mvpp2_tx_desc and mvpp2_rx_desc structures describe the + * layout of the transmit and reception DMA descriptors, and their + * layout is therefore defined by the hardware design + */ + +#define MVPP2_TXD_L3_OFF_SHIFT 0 +#define MVPP2_TXD_IP_HLEN_SHIFT 8 +#define MVPP2_TXD_L4_CSUM_FRAG BIT(13) +#define MVPP2_TXD_L4_CSUM_NOT BIT(14) +#define MVPP2_TXD_IP_CSUM_DISABLE BIT(15) +#define MVPP2_TXD_PADDING_DISABLE BIT(23) +#define MVPP2_TXD_L4_UDP BIT(24) +#define MVPP2_TXD_L3_IP6 BIT(26) +#define MVPP2_TXD_L_DESC BIT(28) +#define MVPP2_TXD_F_DESC BIT(29) + +#define MVPP2_RXD_ERR_SUMMARY BIT(15) +#define MVPP2_RXD_ERR_CODE_MASK (BIT(13) | BIT(14)) +#define MVPP2_RXD_ERR_CRC 0x0 +#define MVPP2_RXD_ERR_OVERRUN BIT(13) +#define MVPP2_RXD_ERR_RESOURCE (BIT(13) | BIT(14)) +#define MVPP2_RXD_BM_POOL_ID_OFFS 16 +#define MVPP2_RXD_BM_POOL_ID_MASK (BIT(16) | BIT(17) | BIT(18)) +#define MVPP2_RXD_HWF_SYNC BIT(21) +#define MVPP2_RXD_L4_CSUM_OK BIT(22) +#define MVPP2_RXD_IP4_HEADER_ERR BIT(24) +#define MVPP2_RXD_L4_TCP BIT(25) +#define MVPP2_RXD_L4_UDP BIT(26) +#define MVPP2_RXD_L3_IP4 BIT(28) +#define MVPP2_RXD_L3_IP6 BIT(30) +#define MVPP2_RXD_BUF_HDR BIT(31) + +struct mvpp2_tx_desc { + u32 command; /* Options used by HW for packet transmitting.*/ + u8 packet_offset; /* the offset from the buffer beginning */ + u8 phys_txq; /* destination queue ID */ + u16 data_size; /* data size of transmitted packet in bytes */ + u32 buf_phys_addr; /* physical addr of transmitted buffer */ + u32 buf_cookie; /* cookie for access to TX buffer in tx path */ + u32 reserved1[3]; /* hw_cmd (for future use, BM, PON, PNC) */ + u32 reserved2; /* reserved (for future use) */ +}; + +struct mvpp2_rx_desc { + u32 status; /* info about received packet */ + u16 reserved1; /* parser_info (for future use, PnC) */ + u16 data_size; /* size of received packet in bytes */ + u32 buf_phys_addr; /* physical address of the buffer */ + u32 buf_cookie; /* cookie for access to RX buffer in rx path */ + u16 reserved2; /* gem_port_id (for future use, PON) */ + u16 reserved3; /* csum_l4 (for future use, PnC) */ + u8 reserved4; /* bm_qset (for future use, BM) */ + u8 reserved5; + u16 reserved6; /* classify_info (for future use, PnC) */ + u32 reserved7; /* flow_id (for future use, PnC) */ + u32 reserved8; +}; + +/* Per-CPU Tx queue control */ +struct mvpp2_txq_pcpu { + int cpu; + + /* Number of Tx DMA descriptors in the descriptor ring */ + int size; + + /* Number of currently used Tx DMA descriptor in the + * descriptor ring + */ + int count; + + /* Number of Tx DMA descriptors reserved for each CPU */ + int reserved_num; + + /* Array of transmitted skb */ + struct sk_buff **tx_skb; + + /* Index of last TX DMA descriptor that was inserted */ + int txq_put_index; + + /* Index of the TX DMA descriptor to be cleaned up */ + int txq_get_index; +}; + +struct mvpp2_tx_queue { + /* Physical number of this Tx queue */ + u8 id; + + /* Logical number of this Tx queue */ + u8 log_id; + + /* Number of Tx DMA descriptors in the descriptor ring */ + int size; + + /* Number of currently used Tx DMA descriptor in the descriptor ring */ + int count; + + /* Per-CPU control of physical Tx queues */ + struct mvpp2_txq_pcpu __percpu *pcpu; + + /* Array of transmitted skb */ + struct sk_buff **tx_skb; + + u32 done_pkts_coal; + + /* Virtual address of thex Tx DMA descriptors array */ + struct mvpp2_tx_desc *descs; + + /* DMA address of the Tx DMA descriptors array */ + dma_addr_t descs_phys; + + /* Index of the last Tx DMA descriptor */ + int last_desc; + + /* Index of the next Tx DMA descriptor to process */ + int next_desc_to_proc; +}; + +struct mvpp2_rx_queue { + /* RX queue number, in the range 0-31 for physical RXQs */ + u8 id; + + /* Num of rx descriptors in the rx descriptor ring */ + int size; + + u32 pkts_coal; + u32 time_coal; + + /* Virtual address of the RX DMA descriptors array */ + struct mvpp2_rx_desc *descs; + + /* DMA address of the RX DMA descriptors array */ + dma_addr_t descs_phys; + + /* Index of the last RX DMA descriptor */ + int last_desc; + + /* Index of the next RX DMA descriptor to process */ + int next_desc_to_proc; + + /* ID of port to which physical RXQ is mapped */ + int port; + + /* Port's logic RXQ number to which physical RXQ is mapped */ + int logic_rxq; +}; + +union mvpp2_prs_tcam_entry { + u32 word[MVPP2_PRS_TCAM_WORDS]; + u8 byte[MVPP2_PRS_TCAM_WORDS * 4]; +}; + +union mvpp2_prs_sram_entry { + u32 word[MVPP2_PRS_SRAM_WORDS]; + u8 byte[MVPP2_PRS_SRAM_WORDS * 4]; +}; + +struct mvpp2_prs_entry { + u32 index; + union mvpp2_prs_tcam_entry tcam; + union mvpp2_prs_sram_entry sram; +}; + +struct mvpp2_prs_shadow { + bool valid; + bool finish; + + /* Lookup ID */ + int lu; + + /* User defined offset */ + int udf; + + /* Result info */ + u32 ri; + u32 ri_mask; +}; + +struct mvpp2_cls_flow_entry { + u32 index; + u32 data[MVPP2_CLS_FLOWS_TBL_DATA_WORDS]; +}; + +struct mvpp2_cls_lookup_entry { + u32 lkpid; + u32 way; + u32 data; +}; + +struct mvpp2_bm_pool { + /* Pool number in the range 0-7 */ + int id; + enum mvpp2_bm_type type; + + /* Buffer Pointers Pool External (BPPE) size */ + int size; + /* Number of buffers for this pool */ + int buf_num; + /* Pool buffer size */ + int buf_size; + /* Packet size */ + int pkt_size; + + /* BPPE virtual base address */ + u32 *virt_addr; + /* BPPE physical base address */ + dma_addr_t phys_addr; + + /* Ports using BM pool */ + u32 port_map; + + /* Occupied buffers indicator */ + atomic_t in_use; + int in_use_thresh; + + spinlock_t lock; +}; + +struct mvpp2_buff_hdr { + u32 next_buff_phys_addr; + u32 next_buff_virt_addr; + u16 byte_count; + u16 info; + u8 reserved1; /* bm_qset (for future use, BM) */ +}; + +/* Buffer header info bits */ +#define MVPP2_B_HDR_INFO_MC_ID_MASK 0xfff +#define MVPP2_B_HDR_INFO_MC_ID(info) ((info) & MVPP2_B_HDR_INFO_MC_ID_MASK) +#define MVPP2_B_HDR_INFO_LAST_OFFS 12 +#define MVPP2_B_HDR_INFO_LAST_MASK BIT(12) +#define MVPP2_B_HDR_INFO_IS_LAST(info) \ + ((info & MVPP2_B_HDR_INFO_LAST_MASK) >> MVPP2_B_HDR_INFO_LAST_OFFS) + +/* Static declaractions */ + +/* Number of RXQs used by single port */ +static int rxq_number = MVPP2_DEFAULT_RXQ; +/* Number of TXQs used by single port */ +static int txq_number = MVPP2_MAX_TXQ; + +#define MVPP2_DRIVER_NAME "mvpp2" +#define MVPP2_DRIVER_VERSION "1.0" + +/* Utility/helper methods */ + +static void mvpp2_write(struct mvpp2 *priv, u32 offset, u32 data) +{ + writel(data, priv->base + offset); +} + +static u32 mvpp2_read(struct mvpp2 *priv, u32 offset) +{ + return readl(priv->base + offset); +} + +static void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu) +{ + txq_pcpu->txq_get_index++; + if (txq_pcpu->txq_get_index == txq_pcpu->size) + txq_pcpu->txq_get_index = 0; +} + +static void mvpp2_txq_inc_put(struct mvpp2_txq_pcpu *txq_pcpu, + struct sk_buff *skb) +{ + txq_pcpu->tx_skb[txq_pcpu->txq_put_index] = skb; + txq_pcpu->txq_put_index++; + if (txq_pcpu->txq_put_index == txq_pcpu->size) + txq_pcpu->txq_put_index = 0; +} + +/* Get number of physical egress port */ +static inline int mvpp2_egress_port(struct mvpp2_port *port) +{ + return MVPP2_MAX_TCONT + port->id; +} + +/* Get number of physical TXQ */ +static inline int mvpp2_txq_phys(int port, int txq) +{ + return (MVPP2_MAX_TCONT + port) * MVPP2_MAX_TXQ + txq; +} + +/* Parser configuration routines */ + +/* Update parser tcam and sram hw entries */ +static int mvpp2_prs_hw_write(struct mvpp2 *priv, struct mvpp2_prs_entry *pe) +{ + int i; + + if (pe->index > MVPP2_PRS_TCAM_SRAM_SIZE - 1) + return -EINVAL; + + /* Clear entry invalidation bit */ + pe->tcam.word[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK; + + /* Write tcam index - indirect access */ + mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index); + for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) + mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam.word[i]); + + /* Write sram index - indirect access */ + mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index); + for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) + mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), pe->sram.word[i]); + + return 0; +} + +/* Read tcam entry from hw */ +static int mvpp2_prs_hw_read(struct mvpp2 *priv, struct mvpp2_prs_entry *pe) +{ + int i; + + if (pe->index > MVPP2_PRS_TCAM_SRAM_SIZE - 1) + return -EINVAL; + + /* Write tcam index - indirect access */ + mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index); + + pe->tcam.word[MVPP2_PRS_TCAM_INV_WORD] = mvpp2_read(priv, + MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD)); + if (pe->tcam.word[MVPP2_PRS_TCAM_INV_WORD] & MVPP2_PRS_TCAM_INV_MASK) + return MVPP2_PRS_TCAM_ENTRY_INVALID; + + for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) + pe->tcam.word[i] = mvpp2_read(priv, MVPP2_PRS_TCAM_DATA_REG(i)); + + /* Write sram index - indirect access */ + mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index); + for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) + pe->sram.word[i] = mvpp2_read(priv, MVPP2_PRS_SRAM_DATA_REG(i)); + + return 0; +} + +/* Invalidate tcam hw entry */ +static void mvpp2_prs_hw_inv(struct mvpp2 *priv, int index) +{ + /* Write index - indirect access */ + mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, index); + mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD), + MVPP2_PRS_TCAM_INV_MASK); +} + +/* Enable shadow table entry and set its lookup ID */ +static void mvpp2_prs_shadow_set(struct mvpp2 *priv, int index, int lu) +{ + priv->prs_shadow[index].valid = true; + priv->prs_shadow[index].lu = lu; +} + +/* Update ri fields in shadow table entry */ +static void mvpp2_prs_shadow_ri_set(struct mvpp2 *priv, int index, + unsigned int ri, unsigned int ri_mask) +{ + priv->prs_shadow[index].ri_mask = ri_mask; + priv->prs_shadow[index].ri = ri; +} + +/* Update lookup field in tcam sw entry */ +static void mvpp2_prs_tcam_lu_set(struct mvpp2_prs_entry *pe, unsigned int lu) +{ + int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_LU_BYTE); + + pe->tcam.byte[MVPP2_PRS_TCAM_LU_BYTE] = lu; + pe->tcam.byte[enable_off] = MVPP2_PRS_LU_MASK; +} + +/* Update mask for single port in tcam sw entry */ +static void mvpp2_prs_tcam_port_set(struct mvpp2_prs_entry *pe, + unsigned int port, bool add) +{ + int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_PORT_BYTE); + + if (add) + pe->tcam.byte[enable_off] &= ~(1 << port); + else + pe->tcam.byte[enable_off] |= 1 << port; +} + +/* Update port map in tcam sw entry */ +static void mvpp2_prs_tcam_port_map_set(struct mvpp2_prs_entry *pe, + unsigned int ports) +{ + unsigned char port_mask = MVPP2_PRS_PORT_MASK; + int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_PORT_BYTE); + + pe->tcam.byte[MVPP2_PRS_TCAM_PORT_BYTE] = 0; + pe->tcam.byte[enable_off] &= ~port_mask; + pe->tcam.byte[enable_off] |= ~ports & MVPP2_PRS_PORT_MASK; +} + +/* Obtain port map from tcam sw entry */ +static unsigned int mvpp2_prs_tcam_port_map_get(struct mvpp2_prs_entry *pe) +{ + int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_PORT_BYTE); + + return ~(pe->tcam.byte[enable_off]) & MVPP2_PRS_PORT_MASK; +} + +/* Set byte of data and its enable bits in tcam sw entry */ +static void mvpp2_prs_tcam_data_byte_set(struct mvpp2_prs_entry *pe, + unsigned int offs, unsigned char byte, + unsigned char enable) +{ + pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE(offs)] = byte; + pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(offs)] = enable; +} + +/* Get byte of data and its enable bits from tcam sw entry */ +static void mvpp2_prs_tcam_data_byte_get(struct mvpp2_prs_entry *pe, + unsigned int offs, unsigned char *byte, + unsigned char *enable) +{ + *byte = pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE(offs)]; + *enable = pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(offs)]; +} + +/* Compare tcam data bytes with a pattern */ +static bool mvpp2_prs_tcam_data_cmp(struct mvpp2_prs_entry *pe, int offs, + u16 data) +{ + int off = MVPP2_PRS_TCAM_DATA_BYTE(offs); + u16 tcam_data; + + tcam_data = (8 << pe->tcam.byte[off + 1]) | pe->tcam.byte[off]; + if (tcam_data != data) + return false; + return true; +} + +/* Update ai bits in tcam sw entry */ +static void mvpp2_prs_tcam_ai_update(struct mvpp2_prs_entry *pe, + unsigned int bits, unsigned int enable) +{ + int i, ai_idx = MVPP2_PRS_TCAM_AI_BYTE; + + for (i = 0; i < MVPP2_PRS_AI_BITS; i++) { + + if (!(enable & BIT(i))) + continue; + + if (bits & BIT(i)) + pe->tcam.byte[ai_idx] |= 1 << i; + else + pe->tcam.byte[ai_idx] &= ~(1 << i); + } + + pe->tcam.byte[MVPP2_PRS_TCAM_EN_OFFS(ai_idx)] |= enable; +} + +/* Get ai bits from tcam sw entry */ +static int mvpp2_prs_tcam_ai_get(struct mvpp2_prs_entry *pe) +{ + return pe->tcam.byte[MVPP2_PRS_TCAM_AI_BYTE]; +} + +/* Set ethertype in tcam sw entry */ +static void mvpp2_prs_match_etype(struct mvpp2_prs_entry *pe, int offset, + unsigned short ethertype) +{ + mvpp2_prs_tcam_data_byte_set(pe, offset + 0, ethertype >> 8, 0xff); + mvpp2_prs_tcam_data_byte_set(pe, offset + 1, ethertype & 0xff, 0xff); +} + +/* Set bits in sram sw entry */ +static void mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry *pe, int bit_num, + int val) +{ + pe->sram.byte[MVPP2_BIT_TO_BYTE(bit_num)] |= (val << (bit_num % 8)); +} + +/* Clear bits in sram sw entry */ +static void mvpp2_prs_sram_bits_clear(struct mvpp2_prs_entry *pe, int bit_num, + int val) +{ + pe->sram.byte[MVPP2_BIT_TO_BYTE(bit_num)] &= ~(val << (bit_num % 8)); +} + +/* Update ri bits in sram sw entry */ +static void mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry *pe, + unsigned int bits, unsigned int mask) +{ + unsigned int i; + + for (i = 0; i < MVPP2_PRS_SRAM_RI_CTRL_BITS; i++) { + int ri_off = MVPP2_PRS_SRAM_RI_OFFS; + + if (!(mask & BIT(i))) + continue; + + if (bits & BIT(i)) + mvpp2_prs_sram_bits_set(pe, ri_off + i, 1); + else + mvpp2_prs_sram_bits_clear(pe, ri_off + i, 1); + + mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_RI_CTRL_OFFS + i, 1); + } +} + +/* Obtain ri bits from sram sw entry */ +static int mvpp2_prs_sram_ri_get(struct mvpp2_prs_entry *pe) +{ + return pe->sram.word[MVPP2_PRS_SRAM_RI_WORD]; +} + +/* Update ai bits in sram sw entry */ +static void mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry *pe, + unsigned int bits, unsigned int mask) +{ + unsigned int i; + int ai_off = MVPP2_PRS_SRAM_AI_OFFS; + + for (i = 0; i < MVPP2_PRS_SRAM_AI_CTRL_BITS; i++) { + + if (!(mask & BIT(i))) + continue; + + if (bits & BIT(i)) + mvpp2_prs_sram_bits_set(pe, ai_off + i, 1); + else + mvpp2_prs_sram_bits_clear(pe, ai_off + i, 1); + + mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_AI_CTRL_OFFS + i, 1); + } +} + +/* Read ai bits from sram sw entry */ +static int mvpp2_prs_sram_ai_get(struct mvpp2_prs_entry *pe) +{ + u8 bits; + int ai_off = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_AI_OFFS); + int ai_en_off = ai_off + 1; + int ai_shift = MVPP2_PRS_SRAM_AI_OFFS % 8; + + bits = (pe->sram.byte[ai_off] >> ai_shift) | + (pe->sram.byte[ai_en_off] << (8 - ai_shift)); + + return bits; +} + +/* In sram sw entry set lookup ID field of the tcam key to be used in the next + * lookup interation + */ +static void mvpp2_prs_sram_next_lu_set(struct mvpp2_prs_entry *pe, + unsigned int lu) +{ + int sram_next_off = MVPP2_PRS_SRAM_NEXT_LU_OFFS; + + mvpp2_prs_sram_bits_clear(pe, sram_next_off, + MVPP2_PRS_SRAM_NEXT_LU_MASK); + mvpp2_prs_sram_bits_set(pe, sram_next_off, lu); +} + +/* In the sram sw entry set sign and value of the next lookup offset + * and the offset value generated to the classifier + */ +static void mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry *pe, int shift, + unsigned int op) +{ + /* Set sign */ + if (shift < 0) { + mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1); + shift = 0 - shift; + } else { + mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1); + } + + /* Set value */ + pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_SHIFT_OFFS)] = + (unsigned char)shift; + + /* Reset and set operation */ + mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_MASK); + mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, op); + + /* Set base offset as current */ + mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1); +} + +/* In the sram sw entry set sign and value of the user defined offset + * generated to the classifier + */ +static void mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry *pe, + unsigned int type, int offset, + unsigned int op) +{ + /* Set sign */ + if (offset < 0) { + mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1); + offset = 0 - offset; + } else { + mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1); + } + + /* Set value */ + mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_OFFS, + MVPP2_PRS_SRAM_UDF_MASK); + mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_OFFS, offset); + pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_UDF_OFFS + + MVPP2_PRS_SRAM_UDF_BITS)] &= + ~(MVPP2_PRS_SRAM_UDF_MASK >> (8 - (MVPP2_PRS_SRAM_UDF_OFFS % 8))); + pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_UDF_OFFS + + MVPP2_PRS_SRAM_UDF_BITS)] |= + (offset >> (8 - (MVPP2_PRS_SRAM_UDF_OFFS % 8))); + + /* Set offset type */ + mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, + MVPP2_PRS_SRAM_UDF_TYPE_MASK); + mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, type); + + /* Set offset operation */ + mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS, + MVPP2_PRS_SRAM_OP_SEL_UDF_MASK); + mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS, op); + + pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS + + MVPP2_PRS_SRAM_OP_SEL_UDF_BITS)] &= + ~(MVPP2_PRS_SRAM_OP_SEL_UDF_MASK >> + (8 - (MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS % 8))); + + pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS + + MVPP2_PRS_SRAM_OP_SEL_UDF_BITS)] |= + (op >> (8 - (MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS % 8))); + + /* Set base offset as current */ + mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1); +} + +/* Find parser flow entry */ +static struct mvpp2_prs_entry *mvpp2_prs_flow_find(struct mvpp2 *priv, int flow) +{ + struct mvpp2_prs_entry *pe; + int tid; + + pe = kzalloc(sizeof(*pe), GFP_KERNEL); + if (!pe) + return NULL; + mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_FLOWS); + + /* Go through the all entires with MVPP2_PRS_LU_FLOWS */ + for (tid = MVPP2_PRS_TCAM_SRAM_SIZE - 1; tid >= 0; tid--) { + u8 bits; + + if (!priv->prs_shadow[tid].valid || + priv->prs_shadow[tid].lu != MVPP2_PRS_LU_FLOWS) + continue; + + pe->index = tid; + mvpp2_prs_hw_read(priv, pe); + bits = mvpp2_prs_sram_ai_get(pe); + + /* Sram store classification lookup ID in AI bits [5:0] */ + if ((bits & MVPP2_PRS_FLOW_ID_MASK) == flow) + return pe; + } + kfree(pe); + + return NULL; +} + +/* Return first free tcam index, seeking from start to end */ +static int mvpp2_prs_tcam_first_free(struct mvpp2 *priv, unsigned char start, + unsigned char end) +{ + int tid; + + if (start > end) + swap(start, end); + + if (end >= MVPP2_PRS_TCAM_SRAM_SIZE) + end = MVPP2_PRS_TCAM_SRAM_SIZE - 1; + + for (tid = start; tid <= end; tid++) { + if (!priv->prs_shadow[tid].valid) + return tid; + } + + return -EINVAL; +} + +/* Enable/disable dropping all mac da's */ +static void mvpp2_prs_mac_drop_all_set(struct mvpp2 *priv, int port, bool add) +{ + struct mvpp2_prs_entry pe; + + if (priv->prs_shadow[MVPP2_PE_DROP_ALL].valid) { + /* Entry exist - update port only */ + pe.index = MVPP2_PE_DROP_ALL; + mvpp2_prs_hw_read(priv, &pe); + } else { + /* Entry doesn't exist - create new */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC); + pe.index = MVPP2_PE_DROP_ALL; + + /* Non-promiscuous mode for all ports - DROP unknown packets */ + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK, + MVPP2_PRS_RI_DROP_MASK); + + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + + /* Update shadow table */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC); + + /* Mask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, 0); + } + + /* Update port mask */ + mvpp2_prs_tcam_port_set(&pe, port, add); + + mvpp2_prs_hw_write(priv, &pe); +} + +/* Set port to promiscuous mode */ +static void mvpp2_prs_mac_promisc_set(struct mvpp2 *priv, int port, bool add) +{ + struct mvpp2_prs_entry pe; + + /* Promiscous mode - Accept unknown packets */ + + if (priv->prs_shadow[MVPP2_PE_MAC_PROMISCUOUS].valid) { + /* Entry exist - update port only */ + pe.index = MVPP2_PE_MAC_PROMISCUOUS; + mvpp2_prs_hw_read(priv, &pe); + } else { + /* Entry doesn't exist - create new */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC); + pe.index = MVPP2_PE_MAC_PROMISCUOUS; + + /* Continue - set next lookup */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA); + + /* Set result info bits */ + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L2_UCAST, + MVPP2_PRS_RI_L2_CAST_MASK); + + /* Shift to ethertype */ + mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Mask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, 0); + + /* Update shadow table */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC); + } + + /* Update port mask */ + mvpp2_prs_tcam_port_set(&pe, port, add); + + mvpp2_prs_hw_write(priv, &pe); +} + +/* Accept multicast */ +static void mvpp2_prs_mac_multi_set(struct mvpp2 *priv, int port, int index, + bool add) +{ + struct mvpp2_prs_entry pe; + unsigned char da_mc; + + /* Ethernet multicast address first byte is + * 0x01 for IPv4 and 0x33 for IPv6 + */ + da_mc = (index == MVPP2_PE_MAC_MC_ALL) ? 0x01 : 0x33; + + if (priv->prs_shadow[index].valid) { + /* Entry exist - update port only */ + pe.index = index; + mvpp2_prs_hw_read(priv, &pe); + } else { + /* Entry doesn't exist - create new */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC); + pe.index = index; + + /* Continue - set next lookup */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA); + + /* Set result info bits */ + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L2_MCAST, + MVPP2_PRS_RI_L2_CAST_MASK); + + /* Update tcam entry data first byte */ + mvpp2_prs_tcam_data_byte_set(&pe, 0, da_mc, 0xff); + + /* Shift to ethertype */ + mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Mask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, 0); + + /* Update shadow table */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC); + } + + /* Update port mask */ + mvpp2_prs_tcam_port_set(&pe, port, add); + + mvpp2_prs_hw_write(priv, &pe); +} + +/* Set entry for dsa packets */ +static void mvpp2_prs_dsa_tag_set(struct mvpp2 *priv, int port, bool add, + bool tagged, bool extend) +{ + struct mvpp2_prs_entry pe; + int tid, shift; + + if (extend) { + tid = tagged ? MVPP2_PE_EDSA_TAGGED : MVPP2_PE_EDSA_UNTAGGED; + shift = 8; + } else { + tid = tagged ? MVPP2_PE_DSA_TAGGED : MVPP2_PE_DSA_UNTAGGED; + shift = 4; + } + + if (priv->prs_shadow[tid].valid) { + /* Entry exist - update port only */ + pe.index = tid; + mvpp2_prs_hw_read(priv, &pe); + } else { + /* Entry doesn't exist - create new */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA); + pe.index = tid; + + /* Shift 4 bytes if DSA tag or 8 bytes in case of EDSA tag*/ + mvpp2_prs_sram_shift_set(&pe, shift, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Update shadow table */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_DSA); + + if (tagged) { + /* Set tagged bit in DSA tag */ + mvpp2_prs_tcam_data_byte_set(&pe, 0, + MVPP2_PRS_TCAM_DSA_TAGGED_BIT, + MVPP2_PRS_TCAM_DSA_TAGGED_BIT); + /* Clear all ai bits for next iteration */ + mvpp2_prs_sram_ai_update(&pe, 0, + MVPP2_PRS_SRAM_AI_MASK); + /* If packet is tagged continue check vlans */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN); + } else { + /* Set result info bits to 'no vlans' */ + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE, + MVPP2_PRS_RI_VLAN_MASK); + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2); + } + + /* Mask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, 0); + } + + /* Update port mask */ + mvpp2_prs_tcam_port_set(&pe, port, add); + + mvpp2_prs_hw_write(priv, &pe); +} + +/* Set entry for dsa ethertype */ +static void mvpp2_prs_dsa_tag_ethertype_set(struct mvpp2 *priv, int port, + bool add, bool tagged, bool extend) +{ + struct mvpp2_prs_entry pe; + int tid, shift, port_mask; + + if (extend) { + tid = tagged ? MVPP2_PE_ETYPE_EDSA_TAGGED : + MVPP2_PE_ETYPE_EDSA_UNTAGGED; + port_mask = 0; + shift = 8; + } else { + tid = tagged ? MVPP2_PE_ETYPE_DSA_TAGGED : + MVPP2_PE_ETYPE_DSA_UNTAGGED; + port_mask = MVPP2_PRS_PORT_MASK; + shift = 4; + } + + if (priv->prs_shadow[tid].valid) { + /* Entry exist - update port only */ + pe.index = tid; + mvpp2_prs_hw_read(priv, &pe); + } else { + /* Entry doesn't exist - create new */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA); + pe.index = tid; + + /* Set ethertype */ + mvpp2_prs_match_etype(&pe, 0, ETH_P_EDSA); + mvpp2_prs_match_etype(&pe, 2, 0); + + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DSA_MASK, + MVPP2_PRS_RI_DSA_MASK); + /* Shift ethertype + 2 byte reserved + tag*/ + mvpp2_prs_sram_shift_set(&pe, 2 + MVPP2_ETH_TYPE_LEN + shift, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Update shadow table */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_DSA); + + if (tagged) { + /* Set tagged bit in DSA tag */ + mvpp2_prs_tcam_data_byte_set(&pe, + MVPP2_ETH_TYPE_LEN + 2 + 3, + MVPP2_PRS_TCAM_DSA_TAGGED_BIT, + MVPP2_PRS_TCAM_DSA_TAGGED_BIT); + /* Clear all ai bits for next iteration */ + mvpp2_prs_sram_ai_update(&pe, 0, + MVPP2_PRS_SRAM_AI_MASK); + /* If packet is tagged continue check vlans */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN); + } else { + /* Set result info bits to 'no vlans' */ + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE, + MVPP2_PRS_RI_VLAN_MASK); + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2); + } + /* Mask/unmask all ports, depending on dsa type */ + mvpp2_prs_tcam_port_map_set(&pe, port_mask); + } + + /* Update port mask */ + mvpp2_prs_tcam_port_set(&pe, port, add); + + mvpp2_prs_hw_write(priv, &pe); +} + +/* Search for existing single/triple vlan entry */ +static struct mvpp2_prs_entry *mvpp2_prs_vlan_find(struct mvpp2 *priv, + unsigned short tpid, int ai) +{ + struct mvpp2_prs_entry *pe; + int tid; + + pe = kzalloc(sizeof(*pe), GFP_KERNEL); + if (!pe) + return NULL; + mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_VLAN); + + /* Go through the all entries with MVPP2_PRS_LU_VLAN */ + for (tid = MVPP2_PE_FIRST_FREE_TID; + tid <= MVPP2_PE_LAST_FREE_TID; tid++) { + unsigned int ri_bits, ai_bits; + bool match; + + if (!priv->prs_shadow[tid].valid || + priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN) + continue; + + pe->index = tid; + + mvpp2_prs_hw_read(priv, pe); + match = mvpp2_prs_tcam_data_cmp(pe, 0, swab16(tpid)); + if (!match) + continue; + + /* Get vlan type */ + ri_bits = mvpp2_prs_sram_ri_get(pe); + ri_bits &= MVPP2_PRS_RI_VLAN_MASK; + + /* Get current ai value from tcam */ + ai_bits = mvpp2_prs_tcam_ai_get(pe); + /* Clear double vlan bit */ + ai_bits &= ~MVPP2_PRS_DBL_VLAN_AI_BIT; + + if (ai != ai_bits) + continue; + + if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE || + ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE) + return pe; + } + kfree(pe); + + return NULL; +} + +/* Add/update single/triple vlan entry */ +static int mvpp2_prs_vlan_add(struct mvpp2 *priv, unsigned short tpid, int ai, + unsigned int port_map) +{ + struct mvpp2_prs_entry *pe; + int tid_aux, tid; + + pe = mvpp2_prs_vlan_find(priv, tpid, ai); + + if (!pe) { + /* Create new tcam entry */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_LAST_FREE_TID, + MVPP2_PE_FIRST_FREE_TID); + if (tid < 0) + return tid; + + pe = kzalloc(sizeof(*pe), GFP_KERNEL); + if (!pe) + return -ENOMEM; + + /* Get last double vlan tid */ + for (tid_aux = MVPP2_PE_LAST_FREE_TID; + tid_aux >= MVPP2_PE_FIRST_FREE_TID; tid_aux--) { + unsigned int ri_bits; + + if (!priv->prs_shadow[tid_aux].valid || + priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN) + continue; + + pe->index = tid_aux; + mvpp2_prs_hw_read(priv, pe); + ri_bits = mvpp2_prs_sram_ri_get(pe); + if ((ri_bits & MVPP2_PRS_RI_VLAN_MASK) == + MVPP2_PRS_RI_VLAN_DOUBLE) + break; + } + + if (tid <= tid_aux) + return -EINVAL; + + memset(pe, 0 , sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_VLAN); + pe->index = tid; + + mvpp2_prs_match_etype(pe, 0, tpid); + + mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_L2); + /* Shift 4 bytes - skip 1 vlan tag */ + mvpp2_prs_sram_shift_set(pe, MVPP2_VLAN_TAG_LEN, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + /* Clear all ai bits for next iteration */ + mvpp2_prs_sram_ai_update(pe, 0, MVPP2_PRS_SRAM_AI_MASK); + + if (ai == MVPP2_PRS_SINGLE_VLAN_AI) { + mvpp2_prs_sram_ri_update(pe, MVPP2_PRS_RI_VLAN_SINGLE, + MVPP2_PRS_RI_VLAN_MASK); + } else { + ai |= MVPP2_PRS_DBL_VLAN_AI_BIT; + mvpp2_prs_sram_ri_update(pe, MVPP2_PRS_RI_VLAN_TRIPLE, + MVPP2_PRS_RI_VLAN_MASK); + } + mvpp2_prs_tcam_ai_update(pe, ai, MVPP2_PRS_SRAM_AI_MASK); + + mvpp2_prs_shadow_set(priv, pe->index, MVPP2_PRS_LU_VLAN); + } + /* Update ports' mask */ + mvpp2_prs_tcam_port_map_set(pe, port_map); + + mvpp2_prs_hw_write(priv, pe); + + kfree(pe); + + return 0; +} + +/* Get first free double vlan ai number */ +static int mvpp2_prs_double_vlan_ai_free_get(struct mvpp2 *priv) +{ + int i; + + for (i = 1; i < MVPP2_PRS_DBL_VLANS_MAX; i++) { + if (!priv->prs_double_vlans[i]) + return i; + } + + return -EINVAL; +} + +/* Search for existing double vlan entry */ +static struct mvpp2_prs_entry *mvpp2_prs_double_vlan_find(struct mvpp2 *priv, + unsigned short tpid1, + unsigned short tpid2) +{ + struct mvpp2_prs_entry *pe; + int tid; + + pe = kzalloc(sizeof(*pe), GFP_KERNEL); + if (!pe) + return NULL; + mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_VLAN); + + /* Go through the all entries with MVPP2_PRS_LU_VLAN */ + for (tid = MVPP2_PE_FIRST_FREE_TID; + tid <= MVPP2_PE_LAST_FREE_TID; tid++) { + unsigned int ri_mask; + bool match; + + if (!priv->prs_shadow[tid].valid || + priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN) + continue; + + pe->index = tid; + mvpp2_prs_hw_read(priv, pe); + + match = mvpp2_prs_tcam_data_cmp(pe, 0, swab16(tpid1)) + && mvpp2_prs_tcam_data_cmp(pe, 4, swab16(tpid2)); + + if (!match) + continue; + + ri_mask = mvpp2_prs_sram_ri_get(pe) & MVPP2_PRS_RI_VLAN_MASK; + if (ri_mask == MVPP2_PRS_RI_VLAN_DOUBLE) + return pe; + } + kfree(pe); + + return NULL; +} + +/* Add or update double vlan entry */ +static int mvpp2_prs_double_vlan_add(struct mvpp2 *priv, unsigned short tpid1, + unsigned short tpid2, + unsigned int port_map) +{ + struct mvpp2_prs_entry *pe; + int tid_aux, tid, ai; + + pe = mvpp2_prs_double_vlan_find(priv, tpid1, tpid2); + + if (!pe) { + /* Create new tcam entry */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + pe = kzalloc(sizeof(*pe), GFP_KERNEL); + if (!pe) + return -ENOMEM; + + /* Set ai value for new double vlan entry */ + ai = mvpp2_prs_double_vlan_ai_free_get(priv); + if (ai < 0) + return ai; + + /* Get first single/triple vlan tid */ + for (tid_aux = MVPP2_PE_FIRST_FREE_TID; + tid_aux <= MVPP2_PE_LAST_FREE_TID; tid_aux++) { + unsigned int ri_bits; + + if (!priv->prs_shadow[tid_aux].valid || + priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN) + continue; + + pe->index = tid_aux; + mvpp2_prs_hw_read(priv, pe); + ri_bits = mvpp2_prs_sram_ri_get(pe); + ri_bits &= MVPP2_PRS_RI_VLAN_MASK; + if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE || + ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE) + break; + } + + if (tid >= tid_aux) + return -ERANGE; + + memset(pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_VLAN); + pe->index = tid; + + priv->prs_double_vlans[ai] = true; + + mvpp2_prs_match_etype(pe, 0, tpid1); + mvpp2_prs_match_etype(pe, 4, tpid2); + + mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_VLAN); + /* Shift 8 bytes - skip 2 vlan tags */ + mvpp2_prs_sram_shift_set(pe, 2 * MVPP2_VLAN_TAG_LEN, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + mvpp2_prs_sram_ri_update(pe, MVPP2_PRS_RI_VLAN_DOUBLE, + MVPP2_PRS_RI_VLAN_MASK); + mvpp2_prs_sram_ai_update(pe, ai | MVPP2_PRS_DBL_VLAN_AI_BIT, + MVPP2_PRS_SRAM_AI_MASK); + + mvpp2_prs_shadow_set(priv, pe->index, MVPP2_PRS_LU_VLAN); + } + + /* Update ports' mask */ + mvpp2_prs_tcam_port_map_set(pe, port_map); + mvpp2_prs_hw_write(priv, pe); + + kfree(pe); + return 0; +} + +/* IPv4 header parsing for fragmentation and L4 offset */ +static int mvpp2_prs_ip4_proto(struct mvpp2 *priv, unsigned short proto, + unsigned int ri, unsigned int ri_mask) +{ + struct mvpp2_prs_entry pe; + int tid; + + if ((proto != IPPROTO_TCP) && (proto != IPPROTO_UDP) && + (proto != IPPROTO_IGMP)) + return -EINVAL; + + /* Fragmented packet */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4); + pe.index = tid; + + /* Set next lu to IPv4 */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4); + mvpp2_prs_sram_shift_set(&pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + /* Set L4 offset */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4, + sizeof(struct iphdr) - 4, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT, + MVPP2_PRS_IPV4_DIP_AI_BIT); + mvpp2_prs_sram_ri_update(&pe, ri | MVPP2_PRS_RI_IP_FRAG_MASK, + ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK); + + mvpp2_prs_tcam_data_byte_set(&pe, 5, proto, MVPP2_PRS_TCAM_PROTO_MASK); + mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT); + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4); + mvpp2_prs_hw_write(priv, &pe); + + /* Not fragmented packet */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + pe.index = tid; + /* Clear ri before updating */ + pe.sram.word[MVPP2_PRS_SRAM_RI_WORD] = 0x0; + pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0; + mvpp2_prs_sram_ri_update(&pe, ri, ri_mask); + + mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00, MVPP2_PRS_TCAM_PROTO_MASK_L); + mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00, MVPP2_PRS_TCAM_PROTO_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4); + mvpp2_prs_hw_write(priv, &pe); + + return 0; +} + +/* IPv4 L3 multicast or broadcast */ +static int mvpp2_prs_ip4_cast(struct mvpp2 *priv, unsigned short l3_cast) +{ + struct mvpp2_prs_entry pe; + int mask, tid; + + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4); + pe.index = tid; + + switch (l3_cast) { + case MVPP2_PRS_L3_MULTI_CAST: + mvpp2_prs_tcam_data_byte_set(&pe, 0, MVPP2_PRS_IPV4_MC, + MVPP2_PRS_IPV4_MC_MASK); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_MCAST, + MVPP2_PRS_RI_L3_ADDR_MASK); + break; + case MVPP2_PRS_L3_BROAD_CAST: + mask = MVPP2_PRS_IPV4_BC_MASK; + mvpp2_prs_tcam_data_byte_set(&pe, 0, mask, mask); + mvpp2_prs_tcam_data_byte_set(&pe, 1, mask, mask); + mvpp2_prs_tcam_data_byte_set(&pe, 2, mask, mask); + mvpp2_prs_tcam_data_byte_set(&pe, 3, mask, mask); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_BCAST, + MVPP2_PRS_RI_L3_ADDR_MASK); + break; + default: + return -EINVAL; + } + + /* Finished: go to flowid generation */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + + mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT, + MVPP2_PRS_IPV4_DIP_AI_BIT); + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4); + mvpp2_prs_hw_write(priv, &pe); + + return 0; +} + +/* Set entries for protocols over IPv6 */ +static int mvpp2_prs_ip6_proto(struct mvpp2 *priv, unsigned short proto, + unsigned int ri, unsigned int ri_mask) +{ + struct mvpp2_prs_entry pe; + int tid; + + if ((proto != IPPROTO_TCP) && (proto != IPPROTO_UDP) && + (proto != IPPROTO_ICMPV6) && (proto != IPPROTO_IPIP)) + return -EINVAL; + + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6); + pe.index = tid; + + /* Finished: go to flowid generation */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + mvpp2_prs_sram_ri_update(&pe, ri, ri_mask); + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4, + sizeof(struct ipv6hdr) - 6, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + mvpp2_prs_tcam_data_byte_set(&pe, 0, proto, MVPP2_PRS_TCAM_PROTO_MASK); + mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, + MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Write HW */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6); + mvpp2_prs_hw_write(priv, &pe); + + return 0; +} + +/* IPv6 L3 multicast entry */ +static int mvpp2_prs_ip6_cast(struct mvpp2 *priv, unsigned short l3_cast) +{ + struct mvpp2_prs_entry pe; + int tid; + + if (l3_cast != MVPP2_PRS_L3_MULTI_CAST) + return -EINVAL; + + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6); + pe.index = tid; + + /* Finished: go to flowid generation */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_MCAST, + MVPP2_PRS_RI_L3_ADDR_MASK); + mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, + MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + /* Shift back to IPv6 NH */ + mvpp2_prs_sram_shift_set(&pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + mvpp2_prs_tcam_data_byte_set(&pe, 0, MVPP2_PRS_IPV6_MC, + MVPP2_PRS_IPV6_MC_MASK); + mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6); + mvpp2_prs_hw_write(priv, &pe); + + return 0; +} + +/* Parser per-port initialization */ +static void mvpp2_prs_hw_port_init(struct mvpp2 *priv, int port, int lu_first, + int lu_max, int offset) +{ + u32 val; + + /* Set lookup ID */ + val = mvpp2_read(priv, MVPP2_PRS_INIT_LOOKUP_REG); + val &= ~MVPP2_PRS_PORT_LU_MASK(port); + val |= MVPP2_PRS_PORT_LU_VAL(port, lu_first); + mvpp2_write(priv, MVPP2_PRS_INIT_LOOKUP_REG, val); + + /* Set maximum number of loops for packet received from port */ + val = mvpp2_read(priv, MVPP2_PRS_MAX_LOOP_REG(port)); + val &= ~MVPP2_PRS_MAX_LOOP_MASK(port); + val |= MVPP2_PRS_MAX_LOOP_VAL(port, lu_max); + mvpp2_write(priv, MVPP2_PRS_MAX_LOOP_REG(port), val); + + /* Set initial offset for packet header extraction for the first + * searching loop + */ + val = mvpp2_read(priv, MVPP2_PRS_INIT_OFFS_REG(port)); + val &= ~MVPP2_PRS_INIT_OFF_MASK(port); + val |= MVPP2_PRS_INIT_OFF_VAL(port, offset); + mvpp2_write(priv, MVPP2_PRS_INIT_OFFS_REG(port), val); +} + +/* Default flow entries initialization for all ports */ +static void mvpp2_prs_def_flow_init(struct mvpp2 *priv) +{ + struct mvpp2_prs_entry pe; + int port; + + for (port = 0; port < MVPP2_MAX_PORTS; port++) { + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + pe.index = MVPP2_PE_FIRST_DEFAULT_FLOW - port; + + /* Mask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, 0); + + /* Set flow ID*/ + mvpp2_prs_sram_ai_update(&pe, port, MVPP2_PRS_FLOW_ID_MASK); + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_FLOWS); + mvpp2_prs_hw_write(priv, &pe); + } +} + +/* Set default entry for Marvell Header field */ +static void mvpp2_prs_mh_init(struct mvpp2 *priv) +{ + struct mvpp2_prs_entry pe; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + + pe.index = MVPP2_PE_MH_DEFAULT; + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MH); + mvpp2_prs_sram_shift_set(&pe, MVPP2_MH_SIZE, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_MAC); + + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MH); + mvpp2_prs_hw_write(priv, &pe); +} + +/* Set default entires (place holder) for promiscuous, non-promiscuous and + * multicast MAC addresses + */ +static void mvpp2_prs_mac_init(struct mvpp2 *priv) +{ + struct mvpp2_prs_entry pe; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + + /* Non-promiscuous mode for all ports - DROP unknown packets */ + pe.index = MVPP2_PE_MAC_NON_PROMISCUOUS; + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC); + + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK, + MVPP2_PRS_RI_DROP_MASK); + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC); + mvpp2_prs_hw_write(priv, &pe); + + /* place holders only - no ports */ + mvpp2_prs_mac_drop_all_set(priv, 0, false); + mvpp2_prs_mac_promisc_set(priv, 0, false); + mvpp2_prs_mac_multi_set(priv, MVPP2_PE_MAC_MC_ALL, 0, false); + mvpp2_prs_mac_multi_set(priv, MVPP2_PE_MAC_MC_IP6, 0, false); +} + +/* Set default entries for various types of dsa packets */ +static void mvpp2_prs_dsa_init(struct mvpp2 *priv) +{ + struct mvpp2_prs_entry pe; + + /* None tagged EDSA entry - place holder */ + mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_UNTAGGED, + MVPP2_PRS_EDSA); + + /* Tagged EDSA entry - place holder */ + mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA); + + /* None tagged DSA entry - place holder */ + mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_UNTAGGED, + MVPP2_PRS_DSA); + + /* Tagged DSA entry - place holder */ + mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA); + + /* None tagged EDSA ethertype entry - place holder*/ + mvpp2_prs_dsa_tag_ethertype_set(priv, 0, false, + MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA); + + /* Tagged EDSA ethertype entry - place holder*/ + mvpp2_prs_dsa_tag_ethertype_set(priv, 0, false, + MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA); + + /* None tagged DSA ethertype entry */ + mvpp2_prs_dsa_tag_ethertype_set(priv, 0, true, + MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA); + + /* Tagged DSA ethertype entry */ + mvpp2_prs_dsa_tag_ethertype_set(priv, 0, true, + MVPP2_PRS_TAGGED, MVPP2_PRS_DSA); + + /* Set default entry, in case DSA or EDSA tag not found */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA); + pe.index = MVPP2_PE_DSA_DEFAULT; + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN); + + /* Shift 0 bytes */ + mvpp2_prs_sram_shift_set(&pe, 0, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC); + + /* Clear all sram ai bits for next iteration */ + mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK); + + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + mvpp2_prs_hw_write(priv, &pe); +} + +/* Match basic ethertypes */ +static int mvpp2_prs_etype_init(struct mvpp2 *priv) +{ + struct mvpp2_prs_entry pe; + int tid; + + /* Ethertype: PPPoE */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2); + pe.index = tid; + + mvpp2_prs_match_etype(&pe, 0, ETH_P_PPP_SES); + + mvpp2_prs_sram_shift_set(&pe, MVPP2_PPPOE_HDR_SIZE, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_PPPOE); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_PPPOE_MASK, + MVPP2_PRS_RI_PPPOE_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2); + priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF; + priv->prs_shadow[pe.index].finish = false; + mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_PPPOE_MASK, + MVPP2_PRS_RI_PPPOE_MASK); + mvpp2_prs_hw_write(priv, &pe); + + /* Ethertype: ARP */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2); + pe.index = tid; + + mvpp2_prs_match_etype(&pe, 0, ETH_P_ARP); + + /* Generate flow in the next iteration*/ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_ARP, + MVPP2_PRS_RI_L3_PROTO_MASK); + /* Set L3 offset */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, + MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2); + priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF; + priv->prs_shadow[pe.index].finish = true; + mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_ARP, + MVPP2_PRS_RI_L3_PROTO_MASK); + mvpp2_prs_hw_write(priv, &pe); + + /* Ethertype: LBTD */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2); + pe.index = tid; + + mvpp2_prs_match_etype(&pe, 0, MVPP2_IP_LBDT_TYPE); + + /* Generate flow in the next iteration*/ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_CPU_CODE_RX_SPEC | + MVPP2_PRS_RI_UDF3_RX_SPECIAL, + MVPP2_PRS_RI_CPU_CODE_MASK | + MVPP2_PRS_RI_UDF3_MASK); + /* Set L3 offset */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, + MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2); + priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF; + priv->prs_shadow[pe.index].finish = true; + mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_CPU_CODE_RX_SPEC | + MVPP2_PRS_RI_UDF3_RX_SPECIAL, + MVPP2_PRS_RI_CPU_CODE_MASK | + MVPP2_PRS_RI_UDF3_MASK); + mvpp2_prs_hw_write(priv, &pe); + + /* Ethertype: IPv4 without options */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2); + pe.index = tid; + + mvpp2_prs_match_etype(&pe, 0, ETH_P_IP); + mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL, + MVPP2_PRS_IPV4_HEAD_MASK | + MVPP2_PRS_IPV4_IHL_MASK); + + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4, + MVPP2_PRS_RI_L3_PROTO_MASK); + /* Skip eth_type + 4 bytes of IP header */ + mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 4, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + /* Set L3 offset */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, + MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2); + priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF; + priv->prs_shadow[pe.index].finish = false; + mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP4, + MVPP2_PRS_RI_L3_PROTO_MASK); + mvpp2_prs_hw_write(priv, &pe); + + /* Ethertype: IPv4 with options */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + pe.index = tid; + + /* Clear tcam data before updating */ + pe.tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE(MVPP2_ETH_TYPE_LEN)] = 0x0; + pe.tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(MVPP2_ETH_TYPE_LEN)] = 0x0; + + mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_IPV4_HEAD, + MVPP2_PRS_IPV4_HEAD_MASK); + + /* Clear ri before updating */ + pe.sram.word[MVPP2_PRS_SRAM_RI_WORD] = 0x0; + pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0; + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT, + MVPP2_PRS_RI_L3_PROTO_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2); + priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF; + priv->prs_shadow[pe.index].finish = false; + mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP4_OPT, + MVPP2_PRS_RI_L3_PROTO_MASK); + mvpp2_prs_hw_write(priv, &pe); + + /* Ethertype: IPv6 without options */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2); + pe.index = tid; + + mvpp2_prs_match_etype(&pe, 0, ETH_P_IPV6); + + /* Skip DIP of IPV6 header */ + mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 8 + + MVPP2_MAX_L3_ADDR_SIZE, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6, + MVPP2_PRS_RI_L3_PROTO_MASK); + /* Set L3 offset */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, + MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2); + priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF; + priv->prs_shadow[pe.index].finish = false; + mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP6, + MVPP2_PRS_RI_L3_PROTO_MASK); + mvpp2_prs_hw_write(priv, &pe); + + /* Default entry for MVPP2_PRS_LU_L2 - Unknown ethtype */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2); + pe.index = MVPP2_PE_ETH_TYPE_UN; + + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Generate flow in the next iteration*/ + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN, + MVPP2_PRS_RI_L3_PROTO_MASK); + /* Set L3 offset even it's unknown L3 */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, + MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2); + priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF; + priv->prs_shadow[pe.index].finish = true; + mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_UN, + MVPP2_PRS_RI_L3_PROTO_MASK); + mvpp2_prs_hw_write(priv, &pe); + + return 0; +} + +/* Configure vlan entries and detect up to 2 successive VLAN tags. + * Possible options: + * 0x8100, 0x88A8 + * 0x8100, 0x8100 + * 0x8100 + * 0x88A8 + */ +static int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv) +{ + struct mvpp2_prs_entry pe; + int err; + + priv->prs_double_vlans = devm_kcalloc(&pdev->dev, sizeof(bool), + MVPP2_PRS_DBL_VLANS_MAX, + GFP_KERNEL); + if (!priv->prs_double_vlans) + return -ENOMEM; + + /* Double VLAN: 0x8100, 0x88A8 */ + err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021Q, ETH_P_8021AD, + MVPP2_PRS_PORT_MASK); + if (err) + return err; + + /* Double VLAN: 0x8100, 0x8100 */ + err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021Q, ETH_P_8021Q, + MVPP2_PRS_PORT_MASK); + if (err) + return err; + + /* Single VLAN: 0x88a8 */ + err = mvpp2_prs_vlan_add(priv, ETH_P_8021AD, MVPP2_PRS_SINGLE_VLAN_AI, + MVPP2_PRS_PORT_MASK); + if (err) + return err; + + /* Single VLAN: 0x8100 */ + err = mvpp2_prs_vlan_add(priv, ETH_P_8021Q, MVPP2_PRS_SINGLE_VLAN_AI, + MVPP2_PRS_PORT_MASK); + if (err) + return err; + + /* Set default double vlan entry */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN); + pe.index = MVPP2_PE_VLAN_DBL; + + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2); + /* Clear ai for next iterations */ + mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE, + MVPP2_PRS_RI_VLAN_MASK); + + mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_DBL_VLAN_AI_BIT, + MVPP2_PRS_DBL_VLAN_AI_BIT); + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN); + mvpp2_prs_hw_write(priv, &pe); + + /* Set default vlan none entry */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN); + pe.index = MVPP2_PE_VLAN_NONE; + + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE, + MVPP2_PRS_RI_VLAN_MASK); + + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN); + mvpp2_prs_hw_write(priv, &pe); + + return 0; +} + +/* Set entries for PPPoE ethertype */ +static int mvpp2_prs_pppoe_init(struct mvpp2 *priv) +{ + struct mvpp2_prs_entry pe; + int tid; + + /* IPv4 over PPPoE with options */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE); + pe.index = tid; + + mvpp2_prs_match_etype(&pe, 0, PPP_IP); + + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT, + MVPP2_PRS_RI_L3_PROTO_MASK); + /* Skip eth_type + 4 bytes of IP header */ + mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 4, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + /* Set L3 offset */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, + MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE); + mvpp2_prs_hw_write(priv, &pe); + + /* IPv4 over PPPoE without options */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + pe.index = tid; + + mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL, + MVPP2_PRS_IPV4_HEAD_MASK | + MVPP2_PRS_IPV4_IHL_MASK); + + /* Clear ri before updating */ + pe.sram.word[MVPP2_PRS_SRAM_RI_WORD] = 0x0; + pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0; + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4, + MVPP2_PRS_RI_L3_PROTO_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE); + mvpp2_prs_hw_write(priv, &pe); + + /* IPv6 over PPPoE */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE); + pe.index = tid; + + mvpp2_prs_match_etype(&pe, 0, PPP_IPV6); + + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6, + MVPP2_PRS_RI_L3_PROTO_MASK); + /* Skip eth_type + 4 bytes of IPv6 header */ + mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 4, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + /* Set L3 offset */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, + MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE); + mvpp2_prs_hw_write(priv, &pe); + + /* Non-IP over PPPoE */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE); + pe.index = tid; + + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN, + MVPP2_PRS_RI_L3_PROTO_MASK); + + /* Finished: go to flowid generation */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + /* Set L3 offset even if it's unknown L3 */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, + MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE); + mvpp2_prs_hw_write(priv, &pe); + + return 0; +} + +/* Initialize entries for IPv4 */ +static int mvpp2_prs_ip4_init(struct mvpp2 *priv) +{ + struct mvpp2_prs_entry pe; + int err; + + /* Set entries for TCP, UDP and IGMP over IPv4 */ + err = mvpp2_prs_ip4_proto(priv, IPPROTO_TCP, MVPP2_PRS_RI_L4_TCP, + MVPP2_PRS_RI_L4_PROTO_MASK); + if (err) + return err; + + err = mvpp2_prs_ip4_proto(priv, IPPROTO_UDP, MVPP2_PRS_RI_L4_UDP, + MVPP2_PRS_RI_L4_PROTO_MASK); + if (err) + return err; + + err = mvpp2_prs_ip4_proto(priv, IPPROTO_IGMP, + MVPP2_PRS_RI_CPU_CODE_RX_SPEC | + MVPP2_PRS_RI_UDF3_RX_SPECIAL, + MVPP2_PRS_RI_CPU_CODE_MASK | + MVPP2_PRS_RI_UDF3_MASK); + if (err) + return err; + + /* IPv4 Broadcast */ + err = mvpp2_prs_ip4_cast(priv, MVPP2_PRS_L3_BROAD_CAST); + if (err) + return err; + + /* IPv4 Multicast */ + err = mvpp2_prs_ip4_cast(priv, MVPP2_PRS_L3_MULTI_CAST); + if (err) + return err; + + /* Default IPv4 entry for unknown protocols */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4); + pe.index = MVPP2_PE_IP4_PROTO_UN; + + /* Set next lu to IPv4 */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4); + mvpp2_prs_sram_shift_set(&pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + /* Set L4 offset */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4, + sizeof(struct iphdr) - 4, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT, + MVPP2_PRS_IPV4_DIP_AI_BIT); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER, + MVPP2_PRS_RI_L4_PROTO_MASK); + + mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT); + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4); + mvpp2_prs_hw_write(priv, &pe); + + /* Default IPv4 entry for unicast address */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4); + pe.index = MVPP2_PE_IP4_ADDR_UN; + + /* Finished: go to flowid generation */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UCAST, + MVPP2_PRS_RI_L3_ADDR_MASK); + + mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT, + MVPP2_PRS_IPV4_DIP_AI_BIT); + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4); + mvpp2_prs_hw_write(priv, &pe); + + return 0; +} + +/* Initialize entries for IPv6 */ +static int mvpp2_prs_ip6_init(struct mvpp2 *priv) +{ + struct mvpp2_prs_entry pe; + int tid, err; + + /* Set entries for TCP, UDP and ICMP over IPv6 */ + err = mvpp2_prs_ip6_proto(priv, IPPROTO_TCP, + MVPP2_PRS_RI_L4_TCP, + MVPP2_PRS_RI_L4_PROTO_MASK); + if (err) + return err; + + err = mvpp2_prs_ip6_proto(priv, IPPROTO_UDP, + MVPP2_PRS_RI_L4_UDP, + MVPP2_PRS_RI_L4_PROTO_MASK); + if (err) + return err; + + err = mvpp2_prs_ip6_proto(priv, IPPROTO_ICMPV6, + MVPP2_PRS_RI_CPU_CODE_RX_SPEC | + MVPP2_PRS_RI_UDF3_RX_SPECIAL, + MVPP2_PRS_RI_CPU_CODE_MASK | + MVPP2_PRS_RI_UDF3_MASK); + if (err) + return err; + + /* IPv4 is the last header. This is similar case as 6-TCP or 17-UDP */ + /* Result Info: UDF7=1, DS lite */ + err = mvpp2_prs_ip6_proto(priv, IPPROTO_IPIP, + MVPP2_PRS_RI_UDF7_IP6_LITE, + MVPP2_PRS_RI_UDF7_MASK); + if (err) + return err; + + /* IPv6 multicast */ + err = mvpp2_prs_ip6_cast(priv, MVPP2_PRS_L3_MULTI_CAST); + if (err) + return err; + + /* Entry for checking hop limit */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; + + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6); + pe.index = tid; + + /* Finished: go to flowid generation */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN | + MVPP2_PRS_RI_DROP_MASK, + MVPP2_PRS_RI_L3_PROTO_MASK | + MVPP2_PRS_RI_DROP_MASK); + + mvpp2_prs_tcam_data_byte_set(&pe, 1, 0x00, MVPP2_PRS_IPV6_HOP_MASK); + mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, + MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4); + mvpp2_prs_hw_write(priv, &pe); + + /* Default IPv6 entry for unknown protocols */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6); + pe.index = MVPP2_PE_IP6_PROTO_UN; + + /* Finished: go to flowid generation */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER, + MVPP2_PRS_RI_L4_PROTO_MASK); + /* Set L4 offset relatively to our current place */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4, + sizeof(struct ipv6hdr) - 4, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + + mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, + MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4); + mvpp2_prs_hw_write(priv, &pe); + + /* Default IPv6 entry for unknown ext protocols */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6); + pe.index = MVPP2_PE_IP6_EXT_PROTO_UN; + + /* Finished: go to flowid generation */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS); + mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER, + MVPP2_PRS_RI_L4_PROTO_MASK); + + mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_EXT_AI_BIT, + MVPP2_PRS_IPV6_EXT_AI_BIT); + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4); + mvpp2_prs_hw_write(priv, &pe); + + /* Default IPv6 entry for unicast address */ + memset(&pe, 0, sizeof(struct mvpp2_prs_entry)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6); + pe.index = MVPP2_PE_IP6_ADDR_UN; + + /* Finished: go to IPv6 again */ + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UCAST, + MVPP2_PRS_RI_L3_ADDR_MASK); + mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, + MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + /* Shift back to IPV6 NH */ + mvpp2_prs_sram_shift_set(&pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT); + /* Unmask all ports */ + mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK); + + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6); + mvpp2_prs_hw_write(priv, &pe); + + return 0; +} + +/* Parser default initialization */ +static int mvpp2_prs_default_init(struct platform_device *pdev, + struct mvpp2 *priv) +{ + int err, index, i; + + /* Enable tcam table */ + mvpp2_write(priv, MVPP2_PRS_TCAM_CTRL_REG, MVPP2_PRS_TCAM_EN_MASK); + + /* Clear all tcam and sram entries */ + for (index = 0; index < MVPP2_PRS_TCAM_SRAM_SIZE; index++) { + mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, index); + for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) + mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), 0); + + mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, index); + for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) + mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), 0); + } + + /* Invalidate all tcam entries */ + for (index = 0; index < MVPP2_PRS_TCAM_SRAM_SIZE; index++) + mvpp2_prs_hw_inv(priv, index); + + priv->prs_shadow = devm_kcalloc(&pdev->dev, MVPP2_PRS_TCAM_SRAM_SIZE, + sizeof(struct mvpp2_prs_shadow), + GFP_KERNEL); + if (!priv->prs_shadow) + return -ENOMEM; + + /* Always start from lookup = 0 */ + for (index = 0; index < MVPP2_MAX_PORTS; index++) + mvpp2_prs_hw_port_init(priv, index, MVPP2_PRS_LU_MH, + MVPP2_PRS_PORT_LU_MAX, 0); + + mvpp2_prs_def_flow_init(priv); + + mvpp2_prs_mh_init(priv); + + mvpp2_prs_mac_init(priv); + + mvpp2_prs_dsa_init(priv); + + err = mvpp2_prs_etype_init(priv); + if (err) + return err; + + err = mvpp2_prs_vlan_init(pdev, priv); + if (err) + return err; + + err = mvpp2_prs_pppoe_init(priv); + if (err) + return err; + + err = mvpp2_prs_ip6_init(priv); + if (err) + return err; + + err = mvpp2_prs_ip4_init(priv); + if (err) + return err; + + return 0; +} + +/* Compare MAC DA with tcam entry data */ +static bool mvpp2_prs_mac_range_equals(struct mvpp2_prs_entry *pe, + const u8 *da, unsigned char *mask) +{ + unsigned char tcam_byte, tcam_mask; + int index; + + for (index = 0; index < ETH_ALEN; index++) { + mvpp2_prs_tcam_data_byte_get(pe, index, &tcam_byte, &tcam_mask); + if (tcam_mask != mask[index]) + return false; + + if ((tcam_mask & tcam_byte) != (da[index] & mask[index])) + return false; + } + + return true; +} + +/* Find tcam entry with matched pair */ +static struct mvpp2_prs_entry * +mvpp2_prs_mac_da_range_find(struct mvpp2 *priv, int pmap, const u8 *da, + unsigned char *mask, int udf_type) +{ + struct mvpp2_prs_entry *pe; + int tid; + + pe = kzalloc(sizeof(*pe), GFP_KERNEL); + if (!pe) + return NULL; + mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC); + + /* Go through the all entires with MVPP2_PRS_LU_MAC */ + for (tid = MVPP2_PE_FIRST_FREE_TID; + tid <= MVPP2_PE_LAST_FREE_TID; tid++) { + unsigned int entry_pmap; + + if (!priv->prs_shadow[tid].valid || + (priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) || + (priv->prs_shadow[tid].udf != udf_type)) + continue; + + pe->index = tid; + mvpp2_prs_hw_read(priv, pe); + entry_pmap = mvpp2_prs_tcam_port_map_get(pe); + + if (mvpp2_prs_mac_range_equals(pe, da, mask) && + entry_pmap == pmap) + return pe; + } + kfree(pe); + + return NULL; +} + +/* Update parser's mac da entry */ +static int mvpp2_prs_mac_da_accept(struct mvpp2 *priv, int port, + const u8 *da, bool add) +{ + struct mvpp2_prs_entry *pe; + unsigned int pmap, len, ri; + unsigned char mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + int tid; + + /* Scan TCAM and see if entry with this already exist */ + pe = mvpp2_prs_mac_da_range_find(priv, (1 << port), da, mask, + MVPP2_PRS_UDF_MAC_DEF); + + /* No such entry */ + if (!pe) { + if (!add) + return 0; + + /* Create new TCAM entry */ + /* Find first range mac entry*/ + for (tid = MVPP2_PE_FIRST_FREE_TID; + tid <= MVPP2_PE_LAST_FREE_TID; tid++) + if (priv->prs_shadow[tid].valid && + (priv->prs_shadow[tid].lu == MVPP2_PRS_LU_MAC) && + (priv->prs_shadow[tid].udf == + MVPP2_PRS_UDF_MAC_RANGE)) + break; + + /* Go through the all entries from first to last */ + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + tid - 1); + if (tid < 0) + return tid; + + pe = kzalloc(sizeof(*pe), GFP_KERNEL); + if (!pe) + return -1; + mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC); + pe->index = tid; + + /* Mask all ports */ + mvpp2_prs_tcam_port_map_set(pe, 0); + } + + /* Update port mask */ + mvpp2_prs_tcam_port_set(pe, port, add); + + /* Invalidate the entry if no ports are left enabled */ + pmap = mvpp2_prs_tcam_port_map_get(pe); + if (pmap == 0) { + if (add) { + kfree(pe); + return -1; + } + mvpp2_prs_hw_inv(priv, pe->index); + priv->prs_shadow[pe->index].valid = false; + kfree(pe); + return 0; + } + + /* Continue - set next lookup */ + mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_DSA); + + /* Set match on DA */ + len = ETH_ALEN; + while (len--) + mvpp2_prs_tcam_data_byte_set(pe, len, da[len], 0xff); + + /* Set result info bits */ + if (is_broadcast_ether_addr(da)) + ri = MVPP2_PRS_RI_L2_BCAST; + else if (is_multicast_ether_addr(da)) + ri = MVPP2_PRS_RI_L2_MCAST; + else + ri = MVPP2_PRS_RI_L2_UCAST | MVPP2_PRS_RI_MAC_ME_MASK; + + mvpp2_prs_sram_ri_update(pe, ri, MVPP2_PRS_RI_L2_CAST_MASK | + MVPP2_PRS_RI_MAC_ME_MASK); + mvpp2_prs_shadow_ri_set(priv, pe->index, ri, MVPP2_PRS_RI_L2_CAST_MASK | + MVPP2_PRS_RI_MAC_ME_MASK); + + /* Shift to ethertype */ + mvpp2_prs_sram_shift_set(pe, 2 * ETH_ALEN, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + + /* Update shadow table and hw entry */ + priv->prs_shadow[pe->index].udf = MVPP2_PRS_UDF_MAC_DEF; + mvpp2_prs_shadow_set(priv, pe->index, MVPP2_PRS_LU_MAC); + mvpp2_prs_hw_write(priv, pe); + + kfree(pe); + + return 0; +} + +static int mvpp2_prs_update_mac_da(struct net_device *dev, const u8 *da) +{ + struct mvpp2_port *port = netdev_priv(dev); + int err; + + /* Remove old parser entry */ + err = mvpp2_prs_mac_da_accept(port->priv, port->id, dev->dev_addr, + false); + if (err) + return err; + + /* Add new parser entry */ + err = mvpp2_prs_mac_da_accept(port->priv, port->id, da, true); + if (err) + return err; + + /* Set addr in the device */ + ether_addr_copy(dev->dev_addr, da); + + return 0; +} + +/* Delete all port's multicast simple (not range) entries */ +static void mvpp2_prs_mcast_del_all(struct mvpp2 *priv, int port) +{ + struct mvpp2_prs_entry pe; + int index, tid; + + for (tid = MVPP2_PE_FIRST_FREE_TID; + tid <= MVPP2_PE_LAST_FREE_TID; tid++) { + unsigned char da[ETH_ALEN], da_mask[ETH_ALEN]; + + if (!priv->prs_shadow[tid].valid || + (priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) || + (priv->prs_shadow[tid].udf != MVPP2_PRS_UDF_MAC_DEF)) + continue; + + /* Only simple mac entries */ + pe.index = tid; + mvpp2_prs_hw_read(priv, &pe); + + /* Read mac addr from entry */ + for (index = 0; index < ETH_ALEN; index++) + mvpp2_prs_tcam_data_byte_get(&pe, index, &da[index], + &da_mask[index]); + + if (is_multicast_ether_addr(da) && !is_broadcast_ether_addr(da)) + /* Delete this entry */ + mvpp2_prs_mac_da_accept(priv, port, da, false); + } +} + +static int mvpp2_prs_tag_mode_set(struct mvpp2 *priv, int port, int type) +{ + switch (type) { + case MVPP2_TAG_TYPE_EDSA: + /* Add port to EDSA entries */ + mvpp2_prs_dsa_tag_set(priv, port, true, + MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA); + mvpp2_prs_dsa_tag_set(priv, port, true, + MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA); + /* Remove port from DSA entries */ + mvpp2_prs_dsa_tag_set(priv, port, false, + MVPP2_PRS_TAGGED, MVPP2_PRS_DSA); + mvpp2_prs_dsa_tag_set(priv, port, false, + MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA); + break; + + case MVPP2_TAG_TYPE_DSA: + /* Add port to DSA entries */ + mvpp2_prs_dsa_tag_set(priv, port, true, + MVPP2_PRS_TAGGED, MVPP2_PRS_DSA); + mvpp2_prs_dsa_tag_set(priv, port, true, + MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA); + /* Remove port from EDSA entries */ + mvpp2_prs_dsa_tag_set(priv, port, false, + MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA); + mvpp2_prs_dsa_tag_set(priv, port, false, + MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA); + break; + + case MVPP2_TAG_TYPE_MH: + case MVPP2_TAG_TYPE_NONE: + /* Remove port form EDSA and DSA entries */ + mvpp2_prs_dsa_tag_set(priv, port, false, + MVPP2_PRS_TAGGED, MVPP2_PRS_DSA); + mvpp2_prs_dsa_tag_set(priv, port, false, + MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA); + mvpp2_prs_dsa_tag_set(priv, port, false, + MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA); + mvpp2_prs_dsa_tag_set(priv, port, false, + MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA); + break; + + default: + if ((type < 0) || (type > MVPP2_TAG_TYPE_EDSA)) + return -EINVAL; + } + + return 0; +} + +/* Set prs flow for the port */ +static int mvpp2_prs_def_flow(struct mvpp2_port *port) +{ + struct mvpp2_prs_entry *pe; + int tid; + + pe = mvpp2_prs_flow_find(port->priv, port->id); + + /* Such entry not exist */ + if (!pe) { + /* Go through the all entires from last to first */ + tid = mvpp2_prs_tcam_first_free(port->priv, + MVPP2_PE_LAST_FREE_TID, + MVPP2_PE_FIRST_FREE_TID); + if (tid < 0) + return tid; + + pe = kzalloc(sizeof(*pe), GFP_KERNEL); + if (!pe) + return -ENOMEM; + + mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_FLOWS); + pe->index = tid; + + /* Set flow ID*/ + mvpp2_prs_sram_ai_update(pe, port->id, MVPP2_PRS_FLOW_ID_MASK); + mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1); + + /* Update shadow table */ + mvpp2_prs_shadow_set(port->priv, pe->index, MVPP2_PRS_LU_FLOWS); + } + + mvpp2_prs_tcam_port_map_set(pe, (1 << port->id)); + mvpp2_prs_hw_write(port->priv, pe); + kfree(pe); + + return 0; +} + +/* Classifier configuration routines */ + +/* Update classification flow table registers */ +static void mvpp2_cls_flow_write(struct mvpp2 *priv, + struct mvpp2_cls_flow_entry *fe) +{ + mvpp2_write(priv, MVPP2_CLS_FLOW_INDEX_REG, fe->index); + mvpp2_write(priv, MVPP2_CLS_FLOW_TBL0_REG, fe->data[0]); + mvpp2_write(priv, MVPP2_CLS_FLOW_TBL1_REG, fe->data[1]); + mvpp2_write(priv, MVPP2_CLS_FLOW_TBL2_REG, fe->data[2]); +} + +/* Update classification lookup table register */ +static void mvpp2_cls_lookup_write(struct mvpp2 *priv, + struct mvpp2_cls_lookup_entry *le) +{ + u32 val; + + val = (le->way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | le->lkpid; + mvpp2_write(priv, MVPP2_CLS_LKP_INDEX_REG, val); + mvpp2_write(priv, MVPP2_CLS_LKP_TBL_REG, le->data); +} + +/* Classifier default initialization */ +static void mvpp2_cls_init(struct mvpp2 *priv) +{ + struct mvpp2_cls_lookup_entry le; + struct mvpp2_cls_flow_entry fe; + int index; + + /* Enable classifier */ + mvpp2_write(priv, MVPP2_CLS_MODE_REG, MVPP2_CLS_MODE_ACTIVE_MASK); + + /* Clear classifier flow table */ + memset(&fe.data, 0, MVPP2_CLS_FLOWS_TBL_DATA_WORDS); + for (index = 0; index < MVPP2_CLS_FLOWS_TBL_SIZE; index++) { + fe.index = index; + mvpp2_cls_flow_write(priv, &fe); + } + + /* Clear classifier lookup table */ + le.data = 0; + for (index = 0; index < MVPP2_CLS_LKP_TBL_SIZE; index++) { + le.lkpid = index; + le.way = 0; + mvpp2_cls_lookup_write(priv, &le); + + le.way = 1; + mvpp2_cls_lookup_write(priv, &le); + } +} + +static void mvpp2_cls_port_config(struct mvpp2_port *port) +{ + struct mvpp2_cls_lookup_entry le; + u32 val; + + /* Set way for the port */ + val = mvpp2_read(port->priv, MVPP2_CLS_PORT_WAY_REG); + val &= ~MVPP2_CLS_PORT_WAY_MASK(port->id); + mvpp2_write(port->priv, MVPP2_CLS_PORT_WAY_REG, val); + + /* Pick the entry to be accessed in lookup ID decoding table + * according to the way and lkpid. + */ + le.lkpid = port->id; + le.way = 0; + le.data = 0; + + /* Set initial CPU queue for receiving packets */ + le.data &= ~MVPP2_CLS_LKP_TBL_RXQ_MASK; + le.data |= port->first_rxq; + + /* Disable classification engines */ + le.data &= ~MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK; + + /* Update lookup ID table entry */ + mvpp2_cls_lookup_write(port->priv, &le); +} + +/* Set CPU queue number for oversize packets */ +static void mvpp2_cls_oversize_rxq_set(struct mvpp2_port *port) +{ + u32 val; + + mvpp2_write(port->priv, MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(port->id), + port->first_rxq & MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK); + + mvpp2_write(port->priv, MVPP2_CLS_SWFWD_P2HQ_REG(port->id), + (port->first_rxq >> MVPP2_CLS_OVERSIZE_RXQ_LOW_BITS)); + + val = mvpp2_read(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG); + val |= MVPP2_CLS_SWFWD_PCTRL_MASK(port->id); + mvpp2_write(port->priv, MVPP2_CLS_SWFWD_PCTRL_REG, val); +} + +/* Buffer Manager configuration routines */ + +/* Create pool */ +static int mvpp2_bm_pool_create(struct platform_device *pdev, + struct mvpp2 *priv, + struct mvpp2_bm_pool *bm_pool, int size) +{ + int size_bytes; + u32 val; + + size_bytes = sizeof(u32) * size; + bm_pool->virt_addr = dma_alloc_coherent(&pdev->dev, size_bytes, + &bm_pool->phys_addr, + GFP_KERNEL); + if (!bm_pool->virt_addr) + return -ENOMEM; + + if (!IS_ALIGNED((u32)bm_pool->virt_addr, MVPP2_BM_POOL_PTR_ALIGN)) { + dma_free_coherent(&pdev->dev, size_bytes, bm_pool->virt_addr, + bm_pool->phys_addr); + dev_err(&pdev->dev, "BM pool %d is not %d bytes aligned\n", + bm_pool->id, MVPP2_BM_POOL_PTR_ALIGN); + return -ENOMEM; + } + + mvpp2_write(priv, MVPP2_BM_POOL_BASE_REG(bm_pool->id), + bm_pool->phys_addr); + mvpp2_write(priv, MVPP2_BM_POOL_SIZE_REG(bm_pool->id), size); + + val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id)); + val |= MVPP2_BM_START_MASK; + mvpp2_write(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id), val); + + bm_pool->type = MVPP2_BM_FREE; + bm_pool->size = size; + bm_pool->pkt_size = 0; + bm_pool->buf_num = 0; + atomic_set(&bm_pool->in_use, 0); + spin_lock_init(&bm_pool->lock); + + return 0; +} + +/* Set pool buffer size */ +static void mvpp2_bm_pool_bufsize_set(struct mvpp2 *priv, + struct mvpp2_bm_pool *bm_pool, + int buf_size) +{ + u32 val; + + bm_pool->buf_size = buf_size; + + val = ALIGN(buf_size, 1 << MVPP2_POOL_BUF_SIZE_OFFSET); + mvpp2_write(priv, MVPP2_POOL_BUF_SIZE_REG(bm_pool->id), val); +} + +/* Free "num" buffers from the pool */ +static int mvpp2_bm_bufs_free(struct mvpp2 *priv, + struct mvpp2_bm_pool *bm_pool, int num) +{ + int i; + + if (num >= bm_pool->buf_num) + /* Free all buffers from the pool */ + num = bm_pool->buf_num; + + for (i = 0; i < num; i++) { + u32 vaddr; + + /* Get buffer virtual adress (indirect access) */ + mvpp2_read(priv, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id)); + vaddr = mvpp2_read(priv, MVPP2_BM_VIRT_ALLOC_REG); + if (!vaddr) + break; + dev_kfree_skb_any((struct sk_buff *)vaddr); + } + + /* Update BM driver with number of buffers removed from pool */ + bm_pool->buf_num -= i; + return i; +} + +/* Cleanup pool */ +static int mvpp2_bm_pool_destroy(struct platform_device *pdev, + struct mvpp2 *priv, + struct mvpp2_bm_pool *bm_pool) +{ + int num; + u32 val; + + num = mvpp2_bm_bufs_free(priv, bm_pool, bm_pool->buf_num); + if (num != bm_pool->buf_num) { + WARN(1, "cannot free all buffers in pool %d\n", bm_pool->id); + return 0; + } + + val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id)); + val |= MVPP2_BM_STOP_MASK; + mvpp2_write(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id), val); + + dma_free_coherent(&pdev->dev, sizeof(u32) * bm_pool->size, + bm_pool->virt_addr, + bm_pool->phys_addr); + return 0; +} + +static int mvpp2_bm_pools_init(struct platform_device *pdev, + struct mvpp2 *priv) +{ + int i, err, size; + struct mvpp2_bm_pool *bm_pool; + + /* Create all pools with maximum size */ + size = MVPP2_BM_POOL_SIZE_MAX; + for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) { + bm_pool = &priv->bm_pools[i]; + bm_pool->id = i; + err = mvpp2_bm_pool_create(pdev, priv, bm_pool, size); + if (err) + goto err_unroll_pools; + mvpp2_bm_pool_bufsize_set(priv, bm_pool, 0); + } + return 0; + +err_unroll_pools: + dev_err(&pdev->dev, "failed to create BM pool %d, size %d\n", i, size); + for (i = i - 1; i >= 0; i--) + mvpp2_bm_pool_destroy(pdev, priv, &priv->bm_pools[i]); + return err; +} + +static int mvpp2_bm_init(struct platform_device *pdev, struct mvpp2 *priv) +{ + int i, err; + + for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) { + /* Mask BM all interrupts */ + mvpp2_write(priv, MVPP2_BM_INTR_MASK_REG(i), 0); + /* Clear BM cause register */ + mvpp2_write(priv, MVPP2_BM_INTR_CAUSE_REG(i), 0); + } + + /* Allocate and initialize BM pools */ + priv->bm_pools = devm_kcalloc(&pdev->dev, MVPP2_BM_POOLS_NUM, + sizeof(struct mvpp2_bm_pool), GFP_KERNEL); + if (!priv->bm_pools) + return -ENOMEM; + + err = mvpp2_bm_pools_init(pdev, priv); + if (err < 0) + return err; + return 0; +} + +/* Attach long pool to rxq */ +static void mvpp2_rxq_long_pool_set(struct mvpp2_port *port, + int lrxq, int long_pool) +{ + u32 val; + int prxq; + + /* Get queue physical ID */ + prxq = port->rxqs[lrxq]->id; + + val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq)); + val &= ~MVPP2_RXQ_POOL_LONG_MASK; + val |= ((long_pool << MVPP2_RXQ_POOL_LONG_OFFS) & + MVPP2_RXQ_POOL_LONG_MASK); + + mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(prxq), val); +} + +/* Attach short pool to rxq */ +static void mvpp2_rxq_short_pool_set(struct mvpp2_port *port, + int lrxq, int short_pool) +{ + u32 val; + int prxq; + + /* Get queue physical ID */ + prxq = port->rxqs[lrxq]->id; + + val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq)); + val &= ~MVPP2_RXQ_POOL_SHORT_MASK; + val |= ((short_pool << MVPP2_RXQ_POOL_SHORT_OFFS) & + MVPP2_RXQ_POOL_SHORT_MASK); + + mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(prxq), val); +} + +/* Allocate skb for BM pool */ +static struct sk_buff *mvpp2_skb_alloc(struct mvpp2_port *port, + struct mvpp2_bm_pool *bm_pool, + dma_addr_t *buf_phys_addr, + gfp_t gfp_mask) +{ + struct sk_buff *skb; + dma_addr_t phys_addr; + + skb = __dev_alloc_skb(bm_pool->pkt_size, gfp_mask); + if (!skb) + return NULL; + + phys_addr = dma_map_single(port->dev->dev.parent, skb->head, + MVPP2_RX_BUF_SIZE(bm_pool->pkt_size), + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(port->dev->dev.parent, phys_addr))) { + dev_kfree_skb_any(skb); + return NULL; + } + *buf_phys_addr = phys_addr; + + return skb; +} + +/* Set pool number in a BM cookie */ +static inline u32 mvpp2_bm_cookie_pool_set(u32 cookie, int pool) +{ + u32 bm; + + bm = cookie & ~(0xFF << MVPP2_BM_COOKIE_POOL_OFFS); + bm |= ((pool & 0xFF) << MVPP2_BM_COOKIE_POOL_OFFS); + + return bm; +} + +/* Get pool number from a BM cookie */ +static inline int mvpp2_bm_cookie_pool_get(u32 cookie) +{ + return (cookie >> MVPP2_BM_COOKIE_POOL_OFFS) & 0xFF; +} + +/* Release buffer to BM */ +static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, + u32 buf_phys_addr, u32 buf_virt_addr) +{ + mvpp2_write(port->priv, MVPP2_BM_VIRT_RLS_REG, buf_virt_addr); + mvpp2_write(port->priv, MVPP2_BM_PHY_RLS_REG(pool), buf_phys_addr); +} + +/* Release multicast buffer */ +static void mvpp2_bm_pool_mc_put(struct mvpp2_port *port, int pool, + u32 buf_phys_addr, u32 buf_virt_addr, + int mc_id) +{ + u32 val = 0; + + val |= (mc_id & MVPP2_BM_MC_ID_MASK); + mvpp2_write(port->priv, MVPP2_BM_MC_RLS_REG, val); + + mvpp2_bm_pool_put(port, pool, + buf_phys_addr | MVPP2_BM_PHY_RLS_MC_BUFF_MASK, + buf_virt_addr); +} + +/* Refill BM pool */ +static void mvpp2_pool_refill(struct mvpp2_port *port, u32 bm, + u32 phys_addr, u32 cookie) +{ + int pool = mvpp2_bm_cookie_pool_get(bm); + + mvpp2_bm_pool_put(port, pool, phys_addr, cookie); +} + +/* Allocate buffers for the pool */ +static int mvpp2_bm_bufs_add(struct mvpp2_port *port, + struct mvpp2_bm_pool *bm_pool, int buf_num) +{ + struct sk_buff *skb; + int i, buf_size, total_size; + u32 bm; + dma_addr_t phys_addr; + + buf_size = MVPP2_RX_BUF_SIZE(bm_pool->pkt_size); + total_size = MVPP2_RX_TOTAL_SIZE(buf_size); + + if (buf_num < 0 || + (buf_num + bm_pool->buf_num > bm_pool->size)) { + netdev_err(port->dev, + "cannot allocate %d buffers for pool %d\n", + buf_num, bm_pool->id); + return 0; + } + + bm = mvpp2_bm_cookie_pool_set(0, bm_pool->id); + for (i = 0; i < buf_num; i++) { + skb = mvpp2_skb_alloc(port, bm_pool, &phys_addr, GFP_KERNEL); + if (!skb) + break; + + mvpp2_pool_refill(port, bm, (u32)phys_addr, (u32)skb); + } + + /* Update BM driver with number of buffers added to pool */ + bm_pool->buf_num += i; + bm_pool->in_use_thresh = bm_pool->buf_num / 4; + + netdev_dbg(port->dev, + "%s pool %d: pkt_size=%4d, buf_size=%4d, total_size=%4d\n", + bm_pool->type == MVPP2_BM_SWF_SHORT ? "short" : " long", + bm_pool->id, bm_pool->pkt_size, buf_size, total_size); + + netdev_dbg(port->dev, + "%s pool %d: %d of %d buffers added\n", + bm_pool->type == MVPP2_BM_SWF_SHORT ? "short" : " long", + bm_pool->id, i, buf_num); + return i; +} + +/* Notify the driver that BM pool is being used as specific type and return the + * pool pointer on success + */ +static struct mvpp2_bm_pool * +mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type, + int pkt_size) +{ + unsigned long flags = 0; + struct mvpp2_bm_pool *new_pool = &port->priv->bm_pools[pool]; + int num; + + if (new_pool->type != MVPP2_BM_FREE && new_pool->type != type) { + netdev_err(port->dev, "mixing pool types is forbidden\n"); + return NULL; + } + + spin_lock_irqsave(&new_pool->lock, flags); + + if (new_pool->type == MVPP2_BM_FREE) + new_pool->type = type; + + /* Allocate buffers in case BM pool is used as long pool, but packet + * size doesn't match MTU or BM pool hasn't being used yet + */ + if (((type == MVPP2_BM_SWF_LONG) && (pkt_size > new_pool->pkt_size)) || + (new_pool->pkt_size == 0)) { + int pkts_num; + + /* Set default buffer number or free all the buffers in case + * the pool is not empty + */ + pkts_num = new_pool->buf_num; + if (pkts_num == 0) + pkts_num = type == MVPP2_BM_SWF_LONG ? + MVPP2_BM_LONG_BUF_NUM : + MVPP2_BM_SHORT_BUF_NUM; + else + mvpp2_bm_bufs_free(port->priv, new_pool, pkts_num); + + new_pool->pkt_size = pkt_size; + + /* Allocate buffers for this pool */ + num = mvpp2_bm_bufs_add(port, new_pool, pkts_num); + if (num != pkts_num) { + WARN(1, "pool %d: %d of %d allocated\n", + new_pool->id, num, pkts_num); + /* We need to undo the bufs_add() allocations */ + spin_unlock_irqrestore(&new_pool->lock, flags); + return NULL; + } + } + + mvpp2_bm_pool_bufsize_set(port->priv, new_pool, + MVPP2_RX_BUF_SIZE(new_pool->pkt_size)); + + spin_unlock_irqrestore(&new_pool->lock, flags); + + return new_pool; +} + +/* Initialize pools for swf */ +static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port) +{ + unsigned long flags = 0; + int rxq; + + if (!port->pool_long) { + port->pool_long = + mvpp2_bm_pool_use(port, MVPP2_BM_SWF_LONG_POOL(port->id), + MVPP2_BM_SWF_LONG, + port->pkt_size); + if (!port->pool_long) + return -ENOMEM; + + spin_lock_irqsave(&port->pool_long->lock, flags); + port->pool_long->port_map |= (1 << port->id); + spin_unlock_irqrestore(&port->pool_long->lock, flags); + + for (rxq = 0; rxq < rxq_number; rxq++) + mvpp2_rxq_long_pool_set(port, rxq, port->pool_long->id); + } + + if (!port->pool_short) { + port->pool_short = + mvpp2_bm_pool_use(port, MVPP2_BM_SWF_SHORT_POOL, + MVPP2_BM_SWF_SHORT, + MVPP2_BM_SHORT_PKT_SIZE); + if (!port->pool_short) + return -ENOMEM; + + spin_lock_irqsave(&port->pool_short->lock, flags); + port->pool_short->port_map |= (1 << port->id); + spin_unlock_irqrestore(&port->pool_short->lock, flags); + + for (rxq = 0; rxq < rxq_number; rxq++) + mvpp2_rxq_short_pool_set(port, rxq, + port->pool_short->id); + } + + return 0; +} + +static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu) +{ + struct mvpp2_port *port = netdev_priv(dev); + struct mvpp2_bm_pool *port_pool = port->pool_long; + int num, pkts_num = port_pool->buf_num; + int pkt_size = MVPP2_RX_PKT_SIZE(mtu); + + /* Update BM pool with new buffer size */ + num = mvpp2_bm_bufs_free(port->priv, port_pool, pkts_num); + if (num != pkts_num) { + WARN(1, "cannot free all buffers in pool %d\n", port_pool->id); + return -EIO; + } + + port_pool->pkt_size = pkt_size; + num = mvpp2_bm_bufs_add(port, port_pool, pkts_num); + if (num != pkts_num) { + WARN(1, "pool %d: %d of %d allocated\n", + port_pool->id, num, pkts_num); + return -EIO; + } + + mvpp2_bm_pool_bufsize_set(port->priv, port_pool, + MVPP2_RX_BUF_SIZE(port_pool->pkt_size)); + dev->mtu = mtu; + netdev_update_features(dev); + return 0; +} + +static inline void mvpp2_interrupts_enable(struct mvpp2_port *port) +{ + int cpu, cpu_mask = 0; + + for_each_present_cpu(cpu) + cpu_mask |= 1 << cpu; + mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id), + MVPP2_ISR_ENABLE_INTERRUPT(cpu_mask)); +} + +static inline void mvpp2_interrupts_disable(struct mvpp2_port *port) +{ + int cpu, cpu_mask = 0; + + for_each_present_cpu(cpu) + cpu_mask |= 1 << cpu; + mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id), + MVPP2_ISR_DISABLE_INTERRUPT(cpu_mask)); +} + +/* Mask the current CPU's Rx/Tx interrupts */ +static void mvpp2_interrupts_mask(void *arg) +{ + struct mvpp2_port *port = arg; + + mvpp2_write(port->priv, MVPP2_ISR_RX_TX_MASK_REG(port->id), 0); +} + +/* Unmask the current CPU's Rx/Tx interrupts */ +static void mvpp2_interrupts_unmask(void *arg) +{ + struct mvpp2_port *port = arg; + + mvpp2_write(port->priv, MVPP2_ISR_RX_TX_MASK_REG(port->id), + (MVPP2_CAUSE_MISC_SUM_MASK | + MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK | + MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK)); +} + +/* Port configuration routines */ + +static void mvpp2_port_mii_set(struct mvpp2_port *port) +{ + u32 reg, val = 0; + + if (port->phy_interface == PHY_INTERFACE_MODE_SGMII) + val = MVPP2_GMAC_PCS_ENABLE_MASK | + MVPP2_GMAC_INBAND_AN_MASK; + else if (port->phy_interface == PHY_INTERFACE_MODE_RGMII) + val = MVPP2_GMAC_PORT_RGMII_MASK; + + reg = readl(port->base + MVPP2_GMAC_CTRL_2_REG); + writel(reg | val, port->base + MVPP2_GMAC_CTRL_2_REG); +} + +static void mvpp2_port_enable(struct mvpp2_port *port) +{ + u32 val; + + val = readl(port->base + MVPP2_GMAC_CTRL_0_REG); + val |= MVPP2_GMAC_PORT_EN_MASK; + val |= MVPP2_GMAC_MIB_CNTR_EN_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_0_REG); +} + +static void mvpp2_port_disable(struct mvpp2_port *port) +{ + u32 val; + + val = readl(port->base + MVPP2_GMAC_CTRL_0_REG); + val &= ~(MVPP2_GMAC_PORT_EN_MASK); + writel(val, port->base + MVPP2_GMAC_CTRL_0_REG); +} + +/* Set IEEE 802.3x Flow Control Xon Packet Transmission Mode */ +static void mvpp2_port_periodic_xon_disable(struct mvpp2_port *port) +{ + u32 val; + + val = readl(port->base + MVPP2_GMAC_CTRL_1_REG) & + ~MVPP2_GMAC_PERIODIC_XON_EN_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_1_REG); +} + +/* Configure loopback port */ +static void mvpp2_port_loopback_set(struct mvpp2_port *port) +{ + u32 val; + + val = readl(port->base + MVPP2_GMAC_CTRL_1_REG); + + if (port->speed == 1000) + val |= MVPP2_GMAC_GMII_LB_EN_MASK; + else + val &= ~MVPP2_GMAC_GMII_LB_EN_MASK; + + if (port->phy_interface == PHY_INTERFACE_MODE_SGMII) + val |= MVPP2_GMAC_PCS_LB_EN_MASK; + else + val &= ~MVPP2_GMAC_PCS_LB_EN_MASK; + + writel(val, port->base + MVPP2_GMAC_CTRL_1_REG); +} + +static void mvpp2_port_reset(struct mvpp2_port *port) +{ + u32 val; + + val = readl(port->base + MVPP2_GMAC_CTRL_2_REG) & + ~MVPP2_GMAC_PORT_RESET_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_2_REG); + + while (readl(port->base + MVPP2_GMAC_CTRL_2_REG) & + MVPP2_GMAC_PORT_RESET_MASK) + continue; +} + +/* Change maximum receive size of the port */ +static inline void mvpp2_gmac_max_rx_size_set(struct mvpp2_port *port) +{ + u32 val; + + val = readl(port->base + MVPP2_GMAC_CTRL_0_REG); + val &= ~MVPP2_GMAC_MAX_RX_SIZE_MASK; + val |= (((port->pkt_size - MVPP2_MH_SIZE) / 2) << + MVPP2_GMAC_MAX_RX_SIZE_OFFS); + writel(val, port->base + MVPP2_GMAC_CTRL_0_REG); +} + +/* Set defaults to the MVPP2 port */ +static void mvpp2_defaults_set(struct mvpp2_port *port) +{ + int tx_port_num, val, queue, ptxq, lrxq; + + /* Configure port to loopback if needed */ + if (port->flags & MVPP2_F_LOOPBACK) + mvpp2_port_loopback_set(port); + + /* Update TX FIFO MIN Threshold */ + val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG); + val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK; + /* Min. TX threshold must be less than minimal packet length */ + val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(64 - 4 - 2); + writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG); + + /* Disable Legacy WRR, Disable EJP, Release from reset */ + tx_port_num = mvpp2_egress_port(port); + mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, + tx_port_num); + mvpp2_write(port->priv, MVPP2_TXP_SCHED_CMD_1_REG, 0); + + /* Close bandwidth for all queues */ + for (queue = 0; queue < MVPP2_MAX_TXQ; queue++) { + ptxq = mvpp2_txq_phys(port->id, queue); + mvpp2_write(port->priv, + MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(ptxq), 0); + } + + /* Set refill period to 1 usec, refill tokens + * and bucket size to maximum + */ + mvpp2_write(port->priv, MVPP2_TXP_SCHED_PERIOD_REG, + port->priv->tclk / USEC_PER_SEC); + val = mvpp2_read(port->priv, MVPP2_TXP_SCHED_REFILL_REG); + val &= ~MVPP2_TXP_REFILL_PERIOD_ALL_MASK; + val |= MVPP2_TXP_REFILL_PERIOD_MASK(1); + val |= MVPP2_TXP_REFILL_TOKENS_ALL_MASK; + mvpp2_write(port->priv, MVPP2_TXP_SCHED_REFILL_REG, val); + val = MVPP2_TXP_TOKEN_SIZE_MAX; + mvpp2_write(port->priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, val); + + /* Set MaximumLowLatencyPacketSize value to 256 */ + mvpp2_write(port->priv, MVPP2_RX_CTRL_REG(port->id), + MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK | + MVPP2_RX_LOW_LATENCY_PKT_SIZE(256)); + + /* Enable Rx cache snoop */ + for (lrxq = 0; lrxq < rxq_number; lrxq++) { + queue = port->rxqs[lrxq]->id; + val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue)); + val |= MVPP2_SNOOP_PKT_SIZE_MASK | + MVPP2_SNOOP_BUF_HDR_MASK; + mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val); + } + + /* At default, mask all interrupts to all present cpus */ + mvpp2_interrupts_disable(port); +} + +/* Enable/disable receiving packets */ +static void mvpp2_ingress_enable(struct mvpp2_port *port) +{ + u32 val; + int lrxq, queue; + + for (lrxq = 0; lrxq < rxq_number; lrxq++) { + queue = port->rxqs[lrxq]->id; + val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue)); + val &= ~MVPP2_RXQ_DISABLE_MASK; + mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val); + } +} + +static void mvpp2_ingress_disable(struct mvpp2_port *port) +{ + u32 val; + int lrxq, queue; + + for (lrxq = 0; lrxq < rxq_number; lrxq++) { + queue = port->rxqs[lrxq]->id; + val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue)); + val |= MVPP2_RXQ_DISABLE_MASK; + mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val); + } +} + +/* Enable transmit via physical egress queue + * - HW starts take descriptors from DRAM + */ +static void mvpp2_egress_enable(struct mvpp2_port *port) +{ + u32 qmap; + int queue; + int tx_port_num = mvpp2_egress_port(port); + + /* Enable all initialized TXs. */ + qmap = 0; + for (queue = 0; queue < txq_number; queue++) { + struct mvpp2_tx_queue *txq = port->txqs[queue]; + + if (txq->descs != NULL) + qmap |= (1 << queue); + } + + mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num); + mvpp2_write(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG, qmap); +} + +/* Disable transmit via physical egress queue + * - HW doesn't take descriptors from DRAM + */ +static void mvpp2_egress_disable(struct mvpp2_port *port) +{ + u32 reg_data; + int delay; + int tx_port_num = mvpp2_egress_port(port); + + /* Issue stop command for active channels only */ + mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num); + reg_data = (mvpp2_read(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG)) & + MVPP2_TXP_SCHED_ENQ_MASK; + if (reg_data != 0) + mvpp2_write(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG, + (reg_data << MVPP2_TXP_SCHED_DISQ_OFFSET)); + + /* Wait for all Tx activity to terminate. */ + delay = 0; + do { + if (delay >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) { + netdev_warn(port->dev, + "Tx stop timed out, status=0x%08x\n", + reg_data); + break; + } + mdelay(1); + delay++; + + /* Check port TX Command register that all + * Tx queues are stopped + */ + reg_data = mvpp2_read(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG); + } while (reg_data & MVPP2_TXP_SCHED_ENQ_MASK); +} + +/* Rx descriptors helper methods */ + +/* Get number of Rx descriptors occupied by received packets */ +static inline int +mvpp2_rxq_received(struct mvpp2_port *port, int rxq_id) +{ + u32 val = mvpp2_read(port->priv, MVPP2_RXQ_STATUS_REG(rxq_id)); + + return val & MVPP2_RXQ_OCCUPIED_MASK; +} + +/* Update Rx queue status with the number of occupied and available + * Rx descriptor slots. + */ +static inline void +mvpp2_rxq_status_update(struct mvpp2_port *port, int rxq_id, + int used_count, int free_count) +{ + /* Decrement the number of used descriptors and increment count + * increment the number of free descriptors. + */ + u32 val = used_count | (free_count << MVPP2_RXQ_NUM_NEW_OFFSET); + + mvpp2_write(port->priv, MVPP2_RXQ_STATUS_UPDATE_REG(rxq_id), val); +} + +/* Get pointer to next RX descriptor to be processed by SW */ +static inline struct mvpp2_rx_desc * +mvpp2_rxq_next_desc_get(struct mvpp2_rx_queue *rxq) +{ + int rx_desc = rxq->next_desc_to_proc; + + rxq->next_desc_to_proc = MVPP2_QUEUE_NEXT_DESC(rxq, rx_desc); + prefetch(rxq->descs + rxq->next_desc_to_proc); + return rxq->descs + rx_desc; +} + +/* Set rx queue offset */ +static void mvpp2_rxq_offset_set(struct mvpp2_port *port, + int prxq, int offset) +{ + u32 val; + + /* Convert offset from bytes to units of 32 bytes */ + offset = offset >> 5; + + val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq)); + val &= ~MVPP2_RXQ_PACKET_OFFSET_MASK; + + /* Offset is in */ + val |= ((offset << MVPP2_RXQ_PACKET_OFFSET_OFFS) & + MVPP2_RXQ_PACKET_OFFSET_MASK); + + mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(prxq), val); +} + +/* Obtain BM cookie information from descriptor */ +static u32 mvpp2_bm_cookie_build(struct mvpp2_rx_desc *rx_desc) +{ + int pool = (rx_desc->status & MVPP2_RXD_BM_POOL_ID_MASK) >> + MVPP2_RXD_BM_POOL_ID_OFFS; + int cpu = smp_processor_id(); + + return ((pool & 0xFF) << MVPP2_BM_COOKIE_POOL_OFFS) | + ((cpu & 0xFF) << MVPP2_BM_COOKIE_CPU_OFFS); +} + +/* Tx descriptors helper methods */ + +/* Get number of Tx descriptors waiting to be transmitted by HW */ +static int mvpp2_txq_pend_desc_num_get(struct mvpp2_port *port, + struct mvpp2_tx_queue *txq) +{ + u32 val; + + mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id); + val = mvpp2_read(port->priv, MVPP2_TXQ_PENDING_REG); + + return val & MVPP2_TXQ_PENDING_MASK; +} + +/* Get pointer to next Tx descriptor to be processed (send) by HW */ +static struct mvpp2_tx_desc * +mvpp2_txq_next_desc_get(struct mvpp2_tx_queue *txq) +{ + int tx_desc = txq->next_desc_to_proc; + + txq->next_desc_to_proc = MVPP2_QUEUE_NEXT_DESC(txq, tx_desc); + return txq->descs + tx_desc; +} + +/* Update HW with number of aggregated Tx descriptors to be sent */ +static void mvpp2_aggr_txq_pend_desc_add(struct mvpp2_port *port, int pending) +{ + /* aggregated access - relevant TXQ number is written in TX desc */ + mvpp2_write(port->priv, MVPP2_AGGR_TXQ_UPDATE_REG, pending); +} + + +/* Check if there are enough free descriptors in aggregated txq. + * If not, update the number of occupied descriptors and repeat the check. + */ +static int mvpp2_aggr_desc_num_check(struct mvpp2 *priv, + struct mvpp2_tx_queue *aggr_txq, int num) +{ + if ((aggr_txq->count + num) > aggr_txq->size) { + /* Update number of occupied aggregated Tx descriptors */ + int cpu = smp_processor_id(); + u32 val = mvpp2_read(priv, MVPP2_AGGR_TXQ_STATUS_REG(cpu)); + + aggr_txq->count = val & MVPP2_AGGR_TXQ_PENDING_MASK; + } + + if ((aggr_txq->count + num) > aggr_txq->size) + return -ENOMEM; + + return 0; +} + +/* Reserved Tx descriptors allocation request */ +static int mvpp2_txq_alloc_reserved_desc(struct mvpp2 *priv, + struct mvpp2_tx_queue *txq, int num) +{ + u32 val; + + val = (txq->id << MVPP2_TXQ_RSVD_REQ_Q_OFFSET) | num; + mvpp2_write(priv, MVPP2_TXQ_RSVD_REQ_REG, val); + + val = mvpp2_read(priv, MVPP2_TXQ_RSVD_RSLT_REG); + + return val & MVPP2_TXQ_RSVD_RSLT_MASK; +} + +/* Check if there are enough reserved descriptors for transmission. + * If not, request chunk of reserved descriptors and check again. + */ +static int mvpp2_txq_reserved_desc_num_proc(struct mvpp2 *priv, + struct mvpp2_tx_queue *txq, + struct mvpp2_txq_pcpu *txq_pcpu, + int num) +{ + int req, cpu, desc_count; + + if (txq_pcpu->reserved_num >= num) + return 0; + + /* Not enough descriptors reserved! Update the reserved descriptor + * count and check again. + */ + + desc_count = 0; + /* Compute total of used descriptors */ + for_each_present_cpu(cpu) { + struct mvpp2_txq_pcpu *txq_pcpu_aux; + + txq_pcpu_aux = per_cpu_ptr(txq->pcpu, cpu); + desc_count += txq_pcpu_aux->count; + desc_count += txq_pcpu_aux->reserved_num; + } + + req = max(MVPP2_CPU_DESC_CHUNK, num - txq_pcpu->reserved_num); + desc_count += req; + + if (desc_count > + (txq->size - (num_present_cpus() * MVPP2_CPU_DESC_CHUNK))) + return -ENOMEM; + + txq_pcpu->reserved_num += mvpp2_txq_alloc_reserved_desc(priv, txq, req); + + /* OK, the descriptor cound has been updated: check again. */ + if (txq_pcpu->reserved_num < num) + return -ENOMEM; + return 0; +} + +/* Release the last allocated Tx descriptor. Useful to handle DMA + * mapping failures in the Tx path. + */ +static void mvpp2_txq_desc_put(struct mvpp2_tx_queue *txq) +{ + if (txq->next_desc_to_proc == 0) + txq->next_desc_to_proc = txq->last_desc - 1; + else + txq->next_desc_to_proc--; +} + +/* Set Tx descriptors fields relevant for CSUM calculation */ +static u32 mvpp2_txq_desc_csum(int l3_offs, int l3_proto, + int ip_hdr_len, int l4_proto) +{ + u32 command; + + /* fields: L3_offset, IP_hdrlen, L3_type, G_IPv4_chk, + * G_L4_chk, L4_type required only for checksum calculation + */ + command = (l3_offs << MVPP2_TXD_L3_OFF_SHIFT); + command |= (ip_hdr_len << MVPP2_TXD_IP_HLEN_SHIFT); + command |= MVPP2_TXD_IP_CSUM_DISABLE; + + if (l3_proto == swab16(ETH_P_IP)) { + command &= ~MVPP2_TXD_IP_CSUM_DISABLE; /* enable IPv4 csum */ + command &= ~MVPP2_TXD_L3_IP6; /* enable IPv4 */ + } else { + command |= MVPP2_TXD_L3_IP6; /* enable IPv6 */ + } + + if (l4_proto == IPPROTO_TCP) { + command &= ~MVPP2_TXD_L4_UDP; /* enable TCP */ + command &= ~MVPP2_TXD_L4_CSUM_FRAG; /* generate L4 csum */ + } else if (l4_proto == IPPROTO_UDP) { + command |= MVPP2_TXD_L4_UDP; /* enable UDP */ + command &= ~MVPP2_TXD_L4_CSUM_FRAG; /* generate L4 csum */ + } else { + command |= MVPP2_TXD_L4_CSUM_NOT; + } + + return command; +} + +/* Get number of sent descriptors and decrement counter. + * The number of sent descriptors is returned. + * Per-CPU access + */ +static inline int mvpp2_txq_sent_desc_proc(struct mvpp2_port *port, + struct mvpp2_tx_queue *txq) +{ + u32 val; + + /* Reading status reg resets transmitted descriptor counter */ + val = mvpp2_read(port->priv, MVPP2_TXQ_SENT_REG(txq->id)); + + return (val & MVPP2_TRANSMITTED_COUNT_MASK) >> + MVPP2_TRANSMITTED_COUNT_OFFSET; +} + +static void mvpp2_txq_sent_counter_clear(void *arg) +{ + struct mvpp2_port *port = arg; + int queue; + + for (queue = 0; queue < txq_number; queue++) { + int id = port->txqs[queue]->id; + + mvpp2_read(port->priv, MVPP2_TXQ_SENT_REG(id)); + } +} + +/* Set max sizes for Tx queues */ +static void mvpp2_txp_max_tx_size_set(struct mvpp2_port *port) +{ + u32 val, size, mtu; + int txq, tx_port_num; + + mtu = port->pkt_size * 8; + if (mtu > MVPP2_TXP_MTU_MAX) + mtu = MVPP2_TXP_MTU_MAX; + + /* WA for wrong Token bucket update: Set MTU value = 3*real MTU value */ + mtu = 3 * mtu; + + /* Indirect access to registers */ + tx_port_num = mvpp2_egress_port(port); + mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num); + + /* Set MTU */ + val = mvpp2_read(port->priv, MVPP2_TXP_SCHED_MTU_REG); + val &= ~MVPP2_TXP_MTU_MAX; + val |= mtu; + mvpp2_write(port->priv, MVPP2_TXP_SCHED_MTU_REG, val); + + /* TXP token size and all TXQs token size must be larger that MTU */ + val = mvpp2_read(port->priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG); + size = val & MVPP2_TXP_TOKEN_SIZE_MAX; + if (size < mtu) { + size = mtu; + val &= ~MVPP2_TXP_TOKEN_SIZE_MAX; + val |= size; + mvpp2_write(port->priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, val); + } + + for (txq = 0; txq < txq_number; txq++) { + val = mvpp2_read(port->priv, + MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq)); + size = val & MVPP2_TXQ_TOKEN_SIZE_MAX; + + if (size < mtu) { + size = mtu; + val &= ~MVPP2_TXQ_TOKEN_SIZE_MAX; + val |= size; + mvpp2_write(port->priv, + MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq), + val); + } + } +} + +/* Set the number of packets that will be received before Rx interrupt + * will be generated by HW. + */ +static void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, + struct mvpp2_rx_queue *rxq, u32 pkts) +{ + u32 val; + + val = (pkts & MVPP2_OCCUPIED_THRESH_MASK); + mvpp2_write(port->priv, MVPP2_RXQ_NUM_REG, rxq->id); + mvpp2_write(port->priv, MVPP2_RXQ_THRESH_REG, val); + + rxq->pkts_coal = pkts; +} + +/* Set the time delay in usec before Rx interrupt */ +static void mvpp2_rx_time_coal_set(struct mvpp2_port *port, + struct mvpp2_rx_queue *rxq, u32 usec) +{ + u32 val; + + val = (port->priv->tclk / USEC_PER_SEC) * usec; + mvpp2_write(port->priv, MVPP2_ISR_RX_THRESHOLD_REG(rxq->id), val); + + rxq->time_coal = usec; +} + +/* Set threshold for TX_DONE pkts coalescing */ +static void mvpp2_tx_done_pkts_coal_set(void *arg) +{ + struct mvpp2_port *port = arg; + int queue; + u32 val; + + for (queue = 0; queue < txq_number; queue++) { + struct mvpp2_tx_queue *txq = port->txqs[queue]; + + val = (txq->done_pkts_coal << MVPP2_TRANSMITTED_THRESH_OFFSET) & + MVPP2_TRANSMITTED_THRESH_MASK; + mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id); + mvpp2_write(port->priv, MVPP2_TXQ_THRESH_REG, val); + } +} + +/* Free Tx queue skbuffs */ +static void mvpp2_txq_bufs_free(struct mvpp2_port *port, + struct mvpp2_tx_queue *txq, + struct mvpp2_txq_pcpu *txq_pcpu, int num) +{ + int i; + + for (i = 0; i < num; i++) { + struct mvpp2_tx_desc *tx_desc = txq->descs + + txq_pcpu->txq_get_index; + struct sk_buff *skb = txq_pcpu->tx_skb[txq_pcpu->txq_get_index]; + + mvpp2_txq_inc_get(txq_pcpu); + + if (!skb) + continue; + + dma_unmap_single(port->dev->dev.parent, tx_desc->buf_phys_addr, + tx_desc->data_size, DMA_TO_DEVICE); + dev_kfree_skb_any(skb); + } +} + +static inline struct mvpp2_rx_queue *mvpp2_get_rx_queue(struct mvpp2_port *port, + u32 cause) +{ + int queue = fls(cause) - 1; + + return port->rxqs[queue]; +} + +static inline struct mvpp2_tx_queue *mvpp2_get_tx_queue(struct mvpp2_port *port, + u32 cause) +{ + int queue = fls(cause >> 16) - 1; + + return port->txqs[queue]; +} + +/* Handle end of transmission */ +static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq, + struct mvpp2_txq_pcpu *txq_pcpu) +{ + struct netdev_queue *nq = netdev_get_tx_queue(port->dev, txq->log_id); + int tx_done; + + if (txq_pcpu->cpu != smp_processor_id()) + netdev_err(port->dev, "wrong cpu on the end of Tx processing\n"); + + tx_done = mvpp2_txq_sent_desc_proc(port, txq); + if (!tx_done) + return; + mvpp2_txq_bufs_free(port, txq, txq_pcpu, tx_done); + + txq_pcpu->count -= tx_done; + + if (netif_tx_queue_stopped(nq)) + if (txq_pcpu->size - txq_pcpu->count >= MAX_SKB_FRAGS + 1) + netif_tx_wake_queue(nq); +} + +/* Rx/Tx queue initialization/cleanup methods */ + +/* Allocate and initialize descriptors for aggr TXQ */ +static int mvpp2_aggr_txq_init(struct platform_device *pdev, + struct mvpp2_tx_queue *aggr_txq, + int desc_num, int cpu, + struct mvpp2 *priv) +{ + /* Allocate memory for TX descriptors */ + aggr_txq->descs = dma_alloc_coherent(&pdev->dev, + desc_num * MVPP2_DESC_ALIGNED_SIZE, + &aggr_txq->descs_phys, GFP_KERNEL); + if (!aggr_txq->descs) + return -ENOMEM; + + /* Make sure descriptor address is cache line size aligned */ + BUG_ON(aggr_txq->descs != + PTR_ALIGN(aggr_txq->descs, MVPP2_CPU_D_CACHE_LINE_SIZE)); + + aggr_txq->last_desc = aggr_txq->size - 1; + + /* Aggr TXQ no reset WA */ + aggr_txq->next_desc_to_proc = mvpp2_read(priv, + MVPP2_AGGR_TXQ_INDEX_REG(cpu)); + + /* Set Tx descriptors queue starting address */ + /* indirect access */ + mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu), + aggr_txq->descs_phys); + mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu), desc_num); + + return 0; +} + +/* Create a specified Rx queue */ +static int mvpp2_rxq_init(struct mvpp2_port *port, + struct mvpp2_rx_queue *rxq) + +{ + rxq->size = port->rx_ring_size; + + /* Allocate memory for RX descriptors */ + rxq->descs = dma_alloc_coherent(port->dev->dev.parent, + rxq->size * MVPP2_DESC_ALIGNED_SIZE, + &rxq->descs_phys, GFP_KERNEL); + if (!rxq->descs) + return -ENOMEM; + + BUG_ON(rxq->descs != + PTR_ALIGN(rxq->descs, MVPP2_CPU_D_CACHE_LINE_SIZE)); + + rxq->last_desc = rxq->size - 1; + + /* Zero occupied and non-occupied counters - direct access */ + mvpp2_write(port->priv, MVPP2_RXQ_STATUS_REG(rxq->id), 0); + + /* Set Rx descriptors queue starting address - indirect access */ + mvpp2_write(port->priv, MVPP2_RXQ_NUM_REG, rxq->id); + mvpp2_write(port->priv, MVPP2_RXQ_DESC_ADDR_REG, rxq->descs_phys); + mvpp2_write(port->priv, MVPP2_RXQ_DESC_SIZE_REG, rxq->size); + mvpp2_write(port->priv, MVPP2_RXQ_INDEX_REG, 0); + + /* Set Offset */ + mvpp2_rxq_offset_set(port, rxq->id, NET_SKB_PAD); + + /* Set coalescing pkts and time */ + mvpp2_rx_pkts_coal_set(port, rxq, rxq->pkts_coal); + mvpp2_rx_time_coal_set(port, rxq, rxq->time_coal); + + /* Add number of descriptors ready for receiving packets */ + mvpp2_rxq_status_update(port, rxq->id, 0, rxq->size); + + return 0; +} + +/* Push packets received by the RXQ to BM pool */ +static void mvpp2_rxq_drop_pkts(struct mvpp2_port *port, + struct mvpp2_rx_queue *rxq) +{ + int rx_received, i; + + rx_received = mvpp2_rxq_received(port, rxq->id); + if (!rx_received) + return; + + for (i = 0; i < rx_received; i++) { + struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq); + u32 bm = mvpp2_bm_cookie_build(rx_desc); + + mvpp2_pool_refill(port, bm, rx_desc->buf_phys_addr, + rx_desc->buf_cookie); + } + mvpp2_rxq_status_update(port, rxq->id, rx_received, rx_received); +} + +/* Cleanup Rx queue */ +static void mvpp2_rxq_deinit(struct mvpp2_port *port, + struct mvpp2_rx_queue *rxq) +{ + mvpp2_rxq_drop_pkts(port, rxq); + + if (rxq->descs) + dma_free_coherent(port->dev->dev.parent, + rxq->size * MVPP2_DESC_ALIGNED_SIZE, + rxq->descs, + rxq->descs_phys); + + rxq->descs = NULL; + rxq->last_desc = 0; + rxq->next_desc_to_proc = 0; + rxq->descs_phys = 0; + + /* Clear Rx descriptors queue starting address and size; + * free descriptor number + */ + mvpp2_write(port->priv, MVPP2_RXQ_STATUS_REG(rxq->id), 0); + mvpp2_write(port->priv, MVPP2_RXQ_NUM_REG, rxq->id); + mvpp2_write(port->priv, MVPP2_RXQ_DESC_ADDR_REG, 0); + mvpp2_write(port->priv, MVPP2_RXQ_DESC_SIZE_REG, 0); +} + +/* Create and initialize a Tx queue */ +static int mvpp2_txq_init(struct mvpp2_port *port, + struct mvpp2_tx_queue *txq) +{ + u32 val; + int cpu, desc, desc_per_txq, tx_port_num; + struct mvpp2_txq_pcpu *txq_pcpu; + + txq->size = port->tx_ring_size; + + /* Allocate memory for Tx descriptors */ + txq->descs = dma_alloc_coherent(port->dev->dev.parent, + txq->size * MVPP2_DESC_ALIGNED_SIZE, + &txq->descs_phys, GFP_KERNEL); + if (!txq->descs) + return -ENOMEM; + + /* Make sure descriptor address is cache line size aligned */ + BUG_ON(txq->descs != + PTR_ALIGN(txq->descs, MVPP2_CPU_D_CACHE_LINE_SIZE)); + + txq->last_desc = txq->size - 1; + + /* Set Tx descriptors queue starting address - indirect access */ + mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id); + mvpp2_write(port->priv, MVPP2_TXQ_DESC_ADDR_REG, txq->descs_phys); + mvpp2_write(port->priv, MVPP2_TXQ_DESC_SIZE_REG, txq->size & + MVPP2_TXQ_DESC_SIZE_MASK); + mvpp2_write(port->priv, MVPP2_TXQ_INDEX_REG, 0); + mvpp2_write(port->priv, MVPP2_TXQ_RSVD_CLR_REG, + txq->id << MVPP2_TXQ_RSVD_CLR_OFFSET); + val = mvpp2_read(port->priv, MVPP2_TXQ_PENDING_REG); + val &= ~MVPP2_TXQ_PENDING_MASK; + mvpp2_write(port->priv, MVPP2_TXQ_PENDING_REG, val); + + /* Calculate base address in prefetch buffer. We reserve 16 descriptors + * for each existing TXQ. + * TCONTS for PON port must be continuous from 0 to MVPP2_MAX_TCONT + * GBE ports assumed to be continious from 0 to MVPP2_MAX_PORTS + */ + desc_per_txq = 16; + desc = (port->id * MVPP2_MAX_TXQ * desc_per_txq) + + (txq->log_id * desc_per_txq); + + mvpp2_write(port->priv, MVPP2_TXQ_PREF_BUF_REG, + MVPP2_PREF_BUF_PTR(desc) | MVPP2_PREF_BUF_SIZE_16 | + MVPP2_PREF_BUF_THRESH(desc_per_txq/2)); + + /* WRR / EJP configuration - indirect access */ + tx_port_num = mvpp2_egress_port(port); + mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num); + + val = mvpp2_read(port->priv, MVPP2_TXQ_SCHED_REFILL_REG(txq->log_id)); + val &= ~MVPP2_TXQ_REFILL_PERIOD_ALL_MASK; + val |= MVPP2_TXQ_REFILL_PERIOD_MASK(1); + val |= MVPP2_TXQ_REFILL_TOKENS_ALL_MASK; + mvpp2_write(port->priv, MVPP2_TXQ_SCHED_REFILL_REG(txq->log_id), val); + + val = MVPP2_TXQ_TOKEN_SIZE_MAX; + mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq->log_id), + val); + + for_each_present_cpu(cpu) { + txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); + txq_pcpu->size = txq->size; + txq_pcpu->tx_skb = kmalloc(txq_pcpu->size * + sizeof(*txq_pcpu->tx_skb), + GFP_KERNEL); + if (!txq_pcpu->tx_skb) { + dma_free_coherent(port->dev->dev.parent, + txq->size * MVPP2_DESC_ALIGNED_SIZE, + txq->descs, txq->descs_phys); + return -ENOMEM; + } + + txq_pcpu->count = 0; + txq_pcpu->reserved_num = 0; + txq_pcpu->txq_put_index = 0; + txq_pcpu->txq_get_index = 0; + } + + return 0; +} + +/* Free allocated TXQ resources */ +static void mvpp2_txq_deinit(struct mvpp2_port *port, + struct mvpp2_tx_queue *txq) +{ + struct mvpp2_txq_pcpu *txq_pcpu; + int cpu; + + for_each_present_cpu(cpu) { + txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); + kfree(txq_pcpu->tx_skb); + } + + if (txq->descs) + dma_free_coherent(port->dev->dev.parent, + txq->size * MVPP2_DESC_ALIGNED_SIZE, + txq->descs, txq->descs_phys); + + txq->descs = NULL; + txq->last_desc = 0; + txq->next_desc_to_proc = 0; + txq->descs_phys = 0; + + /* Set minimum bandwidth for disabled TXQs */ + mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(txq->id), 0); + + /* Set Tx descriptors queue starting address and size */ + mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id); + mvpp2_write(port->priv, MVPP2_TXQ_DESC_ADDR_REG, 0); + mvpp2_write(port->priv, MVPP2_TXQ_DESC_SIZE_REG, 0); +} + +/* Cleanup Tx ports */ +static void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) +{ + struct mvpp2_txq_pcpu *txq_pcpu; + int delay, pending, cpu; + u32 val; + + mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id); + val = mvpp2_read(port->priv, MVPP2_TXQ_PREF_BUF_REG); + val |= MVPP2_TXQ_DRAIN_EN_MASK; + mvpp2_write(port->priv, MVPP2_TXQ_PREF_BUF_REG, val); + + /* The napi queue has been stopped so wait for all packets + * to be transmitted. + */ + delay = 0; + do { + if (delay >= MVPP2_TX_PENDING_TIMEOUT_MSEC) { + netdev_warn(port->dev, + "port %d: cleaning queue %d timed out\n", + port->id, txq->log_id); + break; + } + mdelay(1); + delay++; + + pending = mvpp2_txq_pend_desc_num_get(port, txq); + } while (pending); + + val &= ~MVPP2_TXQ_DRAIN_EN_MASK; + mvpp2_write(port->priv, MVPP2_TXQ_PREF_BUF_REG, val); + + for_each_present_cpu(cpu) { + txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); + + /* Release all packets */ + mvpp2_txq_bufs_free(port, txq, txq_pcpu, txq_pcpu->count); + + /* Reset queue */ + txq_pcpu->count = 0; + txq_pcpu->txq_put_index = 0; + txq_pcpu->txq_get_index = 0; + } +} + +/* Cleanup all Tx queues */ +static void mvpp2_cleanup_txqs(struct mvpp2_port *port) +{ + struct mvpp2_tx_queue *txq; + int queue; + u32 val; + + val = mvpp2_read(port->priv, MVPP2_TX_PORT_FLUSH_REG); + + /* Reset Tx ports and delete Tx queues */ + val |= MVPP2_TX_PORT_FLUSH_MASK(port->id); + mvpp2_write(port->priv, MVPP2_TX_PORT_FLUSH_REG, val); + + for (queue = 0; queue < txq_number; queue++) { + txq = port->txqs[queue]; + mvpp2_txq_clean(port, txq); + mvpp2_txq_deinit(port, txq); + } + + on_each_cpu(mvpp2_txq_sent_counter_clear, port, 1); + + val &= ~MVPP2_TX_PORT_FLUSH_MASK(port->id); + mvpp2_write(port->priv, MVPP2_TX_PORT_FLUSH_REG, val); +} + +/* Cleanup all Rx queues */ +static void mvpp2_cleanup_rxqs(struct mvpp2_port *port) +{ + int queue; + + for (queue = 0; queue < rxq_number; queue++) + mvpp2_rxq_deinit(port, port->rxqs[queue]); +} + +/* Init all Rx queues for port */ +static int mvpp2_setup_rxqs(struct mvpp2_port *port) +{ + int queue, err; + + for (queue = 0; queue < rxq_number; queue++) { + err = mvpp2_rxq_init(port, port->rxqs[queue]); + if (err) + goto err_cleanup; + } + return 0; + +err_cleanup: + mvpp2_cleanup_rxqs(port); + return err; +} + +/* Init all tx queues for port */ +static int mvpp2_setup_txqs(struct mvpp2_port *port) +{ + struct mvpp2_tx_queue *txq; + int queue, err; + + for (queue = 0; queue < txq_number; queue++) { + txq = port->txqs[queue]; + err = mvpp2_txq_init(port, txq); + if (err) + goto err_cleanup; + } + + on_each_cpu(mvpp2_tx_done_pkts_coal_set, port, 1); + on_each_cpu(mvpp2_txq_sent_counter_clear, port, 1); + return 0; + +err_cleanup: + mvpp2_cleanup_txqs(port); + return err; +} + +/* The callback for per-port interrupt */ +static irqreturn_t mvpp2_isr(int irq, void *dev_id) +{ + struct mvpp2_port *port = (struct mvpp2_port *)dev_id; + + mvpp2_interrupts_disable(port); + + napi_schedule(&port->napi); + + return IRQ_HANDLED; +} + +/* Adjust link */ +static void mvpp2_link_event(struct net_device *dev) +{ + struct mvpp2_port *port = netdev_priv(dev); + struct phy_device *phydev = port->phy_dev; + int status_change = 0; + u32 val; + + if (phydev->link) { + if ((port->speed != phydev->speed) || + (port->duplex != phydev->duplex)) { + u32 val; + + val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG); + val &= ~(MVPP2_GMAC_CONFIG_MII_SPEED | + MVPP2_GMAC_CONFIG_GMII_SPEED | + MVPP2_GMAC_CONFIG_FULL_DUPLEX | + MVPP2_GMAC_AN_SPEED_EN | + MVPP2_GMAC_AN_DUPLEX_EN); + + if (phydev->duplex) + val |= MVPP2_GMAC_CONFIG_FULL_DUPLEX; + + if (phydev->speed == SPEED_1000) + val |= MVPP2_GMAC_CONFIG_GMII_SPEED; + else + val |= MVPP2_GMAC_CONFIG_MII_SPEED; + + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG); + + port->duplex = phydev->duplex; + port->speed = phydev->speed; + } + } + + if (phydev->link != port->link) { + if (!phydev->link) { + port->duplex = -1; + port->speed = 0; + } + + port->link = phydev->link; + status_change = 1; + } + + if (status_change) { + if (phydev->link) { + val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG); + val |= (MVPP2_GMAC_FORCE_LINK_PASS | + MVPP2_GMAC_FORCE_LINK_DOWN); + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG); + mvpp2_egress_enable(port); + mvpp2_ingress_enable(port); + } else { + mvpp2_ingress_disable(port); + mvpp2_egress_disable(port); + } + phy_print_status(phydev); + } +} + +/* Main RX/TX processing routines */ + +/* Display more error info */ +static void mvpp2_rx_error(struct mvpp2_port *port, + struct mvpp2_rx_desc *rx_desc) +{ + u32 status = rx_desc->status; + + switch (status & MVPP2_RXD_ERR_CODE_MASK) { + case MVPP2_RXD_ERR_CRC: + netdev_err(port->dev, "bad rx status %08x (crc error), size=%d\n", + status, rx_desc->data_size); + break; + case MVPP2_RXD_ERR_OVERRUN: + netdev_err(port->dev, "bad rx status %08x (overrun error), size=%d\n", + status, rx_desc->data_size); + break; + case MVPP2_RXD_ERR_RESOURCE: + netdev_err(port->dev, "bad rx status %08x (resource error), size=%d\n", + status, rx_desc->data_size); + break; + } +} + +/* Handle RX checksum offload */ +static void mvpp2_rx_csum(struct mvpp2_port *port, u32 status, + struct sk_buff *skb) +{ + if (((status & MVPP2_RXD_L3_IP4) && + !(status & MVPP2_RXD_IP4_HEADER_ERR)) || + (status & MVPP2_RXD_L3_IP6)) + if (((status & MVPP2_RXD_L4_UDP) || + (status & MVPP2_RXD_L4_TCP)) && + (status & MVPP2_RXD_L4_CSUM_OK)) { + skb->csum = 0; + skb->ip_summed = CHECKSUM_UNNECESSARY; + return; + } + + skb->ip_summed = CHECKSUM_NONE; +} + +/* Reuse skb if possible, or allocate a new skb and add it to BM pool */ +static int mvpp2_rx_refill(struct mvpp2_port *port, + struct mvpp2_bm_pool *bm_pool, + u32 bm, int is_recycle) +{ + struct sk_buff *skb; + dma_addr_t phys_addr; + + if (is_recycle && + (atomic_read(&bm_pool->in_use) < bm_pool->in_use_thresh)) + return 0; + + /* No recycle or too many buffers are in use, so allocate a new skb */ + skb = mvpp2_skb_alloc(port, bm_pool, &phys_addr, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + mvpp2_pool_refill(port, bm, (u32)phys_addr, (u32)skb); + atomic_dec(&bm_pool->in_use); + return 0; +} + +/* Handle tx checksum */ +static u32 mvpp2_skb_tx_csum(struct mvpp2_port *port, struct sk_buff *skb) +{ + if (skb->ip_summed == CHECKSUM_PARTIAL) { + int ip_hdr_len = 0; + u8 l4_proto; + + if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *ip4h = ip_hdr(skb); + + /* Calculate IPv4 checksum and L4 checksum */ + ip_hdr_len = ip4h->ihl; + l4_proto = ip4h->protocol; + } else if (skb->protocol == htons(ETH_P_IPV6)) { + struct ipv6hdr *ip6h = ipv6_hdr(skb); + + /* Read l4_protocol from one of IPv6 extra headers */ + if (skb_network_header_len(skb) > 0) + ip_hdr_len = (skb_network_header_len(skb) >> 2); + l4_proto = ip6h->nexthdr; + } else { + return MVPP2_TXD_L4_CSUM_NOT; + } + + return mvpp2_txq_desc_csum(skb_network_offset(skb), + skb->protocol, ip_hdr_len, l4_proto); + } + + return MVPP2_TXD_L4_CSUM_NOT | MVPP2_TXD_IP_CSUM_DISABLE; +} + +static void mvpp2_buff_hdr_rx(struct mvpp2_port *port, + struct mvpp2_rx_desc *rx_desc) +{ + struct mvpp2_buff_hdr *buff_hdr; + struct sk_buff *skb; + u32 rx_status = rx_desc->status; + u32 buff_phys_addr; + u32 buff_virt_addr; + u32 buff_phys_addr_next; + u32 buff_virt_addr_next; + int mc_id; + int pool_id; + + pool_id = (rx_status & MVPP2_RXD_BM_POOL_ID_MASK) >> + MVPP2_RXD_BM_POOL_ID_OFFS; + buff_phys_addr = rx_desc->buf_phys_addr; + buff_virt_addr = rx_desc->buf_cookie; + + do { + skb = (struct sk_buff *)buff_virt_addr; + buff_hdr = (struct mvpp2_buff_hdr *)skb->head; + + mc_id = MVPP2_B_HDR_INFO_MC_ID(buff_hdr->info); + + buff_phys_addr_next = buff_hdr->next_buff_phys_addr; + buff_virt_addr_next = buff_hdr->next_buff_virt_addr; + + /* Release buffer */ + mvpp2_bm_pool_mc_put(port, pool_id, buff_phys_addr, + buff_virt_addr, mc_id); + + buff_phys_addr = buff_phys_addr_next; + buff_virt_addr = buff_virt_addr_next; + + } while (!MVPP2_B_HDR_INFO_IS_LAST(buff_hdr->info)); +} + +/* Main rx processing */ +static int mvpp2_rx(struct mvpp2_port *port, int rx_todo, + struct mvpp2_rx_queue *rxq) +{ + struct net_device *dev = port->dev; + int rx_received, rx_filled, i; + u32 rcvd_pkts = 0; + u32 rcvd_bytes = 0; + + /* Get number of received packets and clamp the to-do */ + rx_received = mvpp2_rxq_received(port, rxq->id); + if (rx_todo > rx_received) + rx_todo = rx_received; + + rx_filled = 0; + for (i = 0; i < rx_todo; i++) { + struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq); + struct mvpp2_bm_pool *bm_pool; + struct sk_buff *skb; + u32 bm, rx_status; + int pool, rx_bytes, err; + + rx_filled++; + rx_status = rx_desc->status; + rx_bytes = rx_desc->data_size - MVPP2_MH_SIZE; + + bm = mvpp2_bm_cookie_build(rx_desc); + pool = mvpp2_bm_cookie_pool_get(bm); + bm_pool = &port->priv->bm_pools[pool]; + /* Check if buffer header is used */ + if (rx_status & MVPP2_RXD_BUF_HDR) { + mvpp2_buff_hdr_rx(port, rx_desc); + continue; + } + + /* In case of an error, release the requested buffer pointer + * to the Buffer Manager. This request process is controlled + * by the hardware, and the information about the buffer is + * comprised by the RX descriptor. + */ + if (rx_status & MVPP2_RXD_ERR_SUMMARY) { + dev->stats.rx_errors++; + mvpp2_rx_error(port, rx_desc); + mvpp2_pool_refill(port, bm, rx_desc->buf_phys_addr, + rx_desc->buf_cookie); + continue; + } + + skb = (struct sk_buff *)rx_desc->buf_cookie; + + rcvd_pkts++; + rcvd_bytes += rx_bytes; + atomic_inc(&bm_pool->in_use); + + skb_reserve(skb, MVPP2_MH_SIZE); + skb_put(skb, rx_bytes); + skb->protocol = eth_type_trans(skb, dev); + mvpp2_rx_csum(port, rx_status, skb); + + napi_gro_receive(&port->napi, skb); + + err = mvpp2_rx_refill(port, bm_pool, bm, 0); + if (err) { + netdev_err(port->dev, "failed to refill BM pools\n"); + rx_filled--; + } + } + + if (rcvd_pkts) { + struct mvpp2_pcpu_stats *stats = this_cpu_ptr(port->stats); + + u64_stats_update_begin(&stats->syncp); + stats->rx_packets += rcvd_pkts; + stats->rx_bytes += rcvd_bytes; + u64_stats_update_end(&stats->syncp); + } + + /* Update Rx queue management counters */ + wmb(); + mvpp2_rxq_status_update(port, rxq->id, rx_todo, rx_filled); + + return rx_todo; +} + +static inline void +tx_desc_unmap_put(struct device *dev, struct mvpp2_tx_queue *txq, + struct mvpp2_tx_desc *desc) +{ + dma_unmap_single(dev, desc->buf_phys_addr, + desc->data_size, DMA_TO_DEVICE); + mvpp2_txq_desc_put(txq); +} + +/* Handle tx fragmentation processing */ +static int mvpp2_tx_frag_process(struct mvpp2_port *port, struct sk_buff *skb, + struct mvpp2_tx_queue *aggr_txq, + struct mvpp2_tx_queue *txq) +{ + struct mvpp2_txq_pcpu *txq_pcpu = this_cpu_ptr(txq->pcpu); + struct mvpp2_tx_desc *tx_desc; + int i; + dma_addr_t buf_phys_addr; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + void *addr = page_address(frag->page.p) + frag->page_offset; + + tx_desc = mvpp2_txq_next_desc_get(aggr_txq); + tx_desc->phys_txq = txq->id; + tx_desc->data_size = frag->size; + + buf_phys_addr = dma_map_single(port->dev->dev.parent, addr, + tx_desc->data_size, + DMA_TO_DEVICE); + if (dma_mapping_error(port->dev->dev.parent, buf_phys_addr)) { + mvpp2_txq_desc_put(txq); + goto error; + } + + tx_desc->packet_offset = buf_phys_addr & MVPP2_TX_DESC_ALIGN; + tx_desc->buf_phys_addr = buf_phys_addr & (~MVPP2_TX_DESC_ALIGN); + + if (i == (skb_shinfo(skb)->nr_frags - 1)) { + /* Last descriptor */ + tx_desc->command = MVPP2_TXD_L_DESC; + mvpp2_txq_inc_put(txq_pcpu, skb); + } else { + /* Descriptor in the middle: Not First, Not Last */ + tx_desc->command = 0; + mvpp2_txq_inc_put(txq_pcpu, NULL); + } + } + + return 0; + +error: + /* Release all descriptors that were used to map fragments of + * this packet, as well as the corresponding DMA mappings + */ + for (i = i - 1; i >= 0; i--) { + tx_desc = txq->descs + i; + tx_desc_unmap_put(port->dev->dev.parent, txq, tx_desc); + } + + return -ENOMEM; +} + +/* Main tx processing */ +static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct mvpp2_port *port = netdev_priv(dev); + struct mvpp2_tx_queue *txq, *aggr_txq; + struct mvpp2_txq_pcpu *txq_pcpu; + struct mvpp2_tx_desc *tx_desc; + dma_addr_t buf_phys_addr; + int frags = 0; + u16 txq_id; + u32 tx_cmd; + + txq_id = skb_get_queue_mapping(skb); + txq = port->txqs[txq_id]; + txq_pcpu = this_cpu_ptr(txq->pcpu); + aggr_txq = &port->priv->aggr_txqs[smp_processor_id()]; + + frags = skb_shinfo(skb)->nr_frags + 1; + + /* Check number of available descriptors */ + if (mvpp2_aggr_desc_num_check(port->priv, aggr_txq, frags) || + mvpp2_txq_reserved_desc_num_proc(port->priv, txq, + txq_pcpu, frags)) { + frags = 0; + goto out; + } + + /* Get a descriptor for the first part of the packet */ + tx_desc = mvpp2_txq_next_desc_get(aggr_txq); + tx_desc->phys_txq = txq->id; + tx_desc->data_size = skb_headlen(skb); + + buf_phys_addr = dma_map_single(dev->dev.parent, skb->data, + tx_desc->data_size, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(dev->dev.parent, buf_phys_addr))) { + mvpp2_txq_desc_put(txq); + frags = 0; + goto out; + } + tx_desc->packet_offset = buf_phys_addr & MVPP2_TX_DESC_ALIGN; + tx_desc->buf_phys_addr = buf_phys_addr & ~MVPP2_TX_DESC_ALIGN; + + tx_cmd = mvpp2_skb_tx_csum(port, skb); + + if (frags == 1) { + /* First and Last descriptor */ + tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC; + tx_desc->command = tx_cmd; + mvpp2_txq_inc_put(txq_pcpu, skb); + } else { + /* First but not Last */ + tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_PADDING_DISABLE; + tx_desc->command = tx_cmd; + mvpp2_txq_inc_put(txq_pcpu, NULL); + + /* Continue with other skb fragments */ + if (mvpp2_tx_frag_process(port, skb, aggr_txq, txq)) { + tx_desc_unmap_put(port->dev->dev.parent, txq, tx_desc); + frags = 0; + goto out; + } + } + + txq_pcpu->reserved_num -= frags; + txq_pcpu->count += frags; + aggr_txq->count += frags; + + /* Enable transmit */ + wmb(); + mvpp2_aggr_txq_pend_desc_add(port, frags); + + if (txq_pcpu->size - txq_pcpu->count < MAX_SKB_FRAGS + 1) { + struct netdev_queue *nq = netdev_get_tx_queue(dev, txq_id); + + netif_tx_stop_queue(nq); + } +out: + if (frags > 0) { + struct mvpp2_pcpu_stats *stats = this_cpu_ptr(port->stats); + + u64_stats_update_begin(&stats->syncp); + stats->tx_packets++; + stats->tx_bytes += skb->len; + u64_stats_update_end(&stats->syncp); + } else { + dev->stats.tx_dropped++; + dev_kfree_skb_any(skb); + } + + return NETDEV_TX_OK; +} + +static inline void mvpp2_cause_error(struct net_device *dev, int cause) +{ + if (cause & MVPP2_CAUSE_FCS_ERR_MASK) + netdev_err(dev, "FCS error\n"); + if (cause & MVPP2_CAUSE_RX_FIFO_OVERRUN_MASK) + netdev_err(dev, "rx fifo overrun error\n"); + if (cause & MVPP2_CAUSE_TX_FIFO_UNDERRUN_MASK) + netdev_err(dev, "tx fifo underrun error\n"); +} + +static void mvpp2_txq_done_percpu(void *arg) +{ + struct mvpp2_port *port = arg; + u32 cause_rx_tx, cause_tx, cause_misc; + + /* Rx/Tx cause register + * + * Bits 0-15: each bit indicates received packets on the Rx queue + * (bit 0 is for Rx queue 0). + * + * Bits 16-23: each bit indicates transmitted packets on the Tx queue + * (bit 16 is for Tx queue 0). + * + * Each CPU has its own Rx/Tx cause register + */ + cause_rx_tx = mvpp2_read(port->priv, + MVPP2_ISR_RX_TX_CAUSE_REG(port->id)); + cause_tx = cause_rx_tx & MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK; + cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK; + + if (cause_misc) { + mvpp2_cause_error(port->dev, cause_misc); + + /* Clear the cause register */ + mvpp2_write(port->priv, MVPP2_ISR_MISC_CAUSE_REG, 0); + mvpp2_write(port->priv, MVPP2_ISR_RX_TX_CAUSE_REG(port->id), + cause_rx_tx & ~MVPP2_CAUSE_MISC_SUM_MASK); + } + + /* Release TX descriptors */ + if (cause_tx) { + struct mvpp2_tx_queue *txq = mvpp2_get_tx_queue(port, cause_tx); + struct mvpp2_txq_pcpu *txq_pcpu = this_cpu_ptr(txq->pcpu); + + if (txq_pcpu->count) + mvpp2_txq_done(port, txq, txq_pcpu); + } +} + +static int mvpp2_poll(struct napi_struct *napi, int budget) +{ + u32 cause_rx_tx, cause_rx; + int rx_done = 0; + struct mvpp2_port *port = netdev_priv(napi->dev); + + on_each_cpu(mvpp2_txq_done_percpu, port, 1); + + cause_rx_tx = mvpp2_read(port->priv, + MVPP2_ISR_RX_TX_CAUSE_REG(port->id)); + cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK; + + /* Process RX packets */ + cause_rx |= port->pending_cause_rx; + while (cause_rx && budget > 0) { + int count; + struct mvpp2_rx_queue *rxq; + + rxq = mvpp2_get_rx_queue(port, cause_rx); + if (!rxq) + break; + + count = mvpp2_rx(port, budget, rxq); + rx_done += count; + budget -= count; + if (budget > 0) { + /* Clear the bit associated to this Rx queue + * so that next iteration will continue from + * the next Rx queue. + */ + cause_rx &= ~(1 << rxq->logic_rxq); + } + } + + if (budget > 0) { + cause_rx = 0; + napi_complete(napi); + + mvpp2_interrupts_enable(port); + } + port->pending_cause_rx = cause_rx; + return rx_done; +} + +/* Set hw internals when starting port */ +static void mvpp2_start_dev(struct mvpp2_port *port) +{ + mvpp2_gmac_max_rx_size_set(port); + mvpp2_txp_max_tx_size_set(port); + + napi_enable(&port->napi); + + /* Enable interrupts on all CPUs */ + mvpp2_interrupts_enable(port); + + mvpp2_port_enable(port); + phy_start(port->phy_dev); + netif_tx_start_all_queues(port->dev); +} + +/* Set hw internals when stopping port */ +static void mvpp2_stop_dev(struct mvpp2_port *port) +{ + /* Stop new packets from arriving to RXQs */ + mvpp2_ingress_disable(port); + + mdelay(10); + + /* Disable interrupts on all CPUs */ + mvpp2_interrupts_disable(port); + + napi_disable(&port->napi); + + netif_carrier_off(port->dev); + netif_tx_stop_all_queues(port->dev); + + mvpp2_egress_disable(port); + mvpp2_port_disable(port); + phy_stop(port->phy_dev); +} + +/* Return positive if MTU is valid */ +static inline int mvpp2_check_mtu_valid(struct net_device *dev, int mtu) +{ + if (mtu < 68) { + netdev_err(dev, "cannot change mtu to less than 68\n"); + return -EINVAL; + } + + /* 9676 == 9700 - 20 and rounding to 8 */ + if (mtu > 9676) { + netdev_info(dev, "illegal MTU value %d, round to 9676\n", mtu); + mtu = 9676; + } + + if (!IS_ALIGNED(MVPP2_RX_PKT_SIZE(mtu), 8)) { + netdev_info(dev, "illegal MTU value %d, round to %d\n", mtu, + ALIGN(MVPP2_RX_PKT_SIZE(mtu), 8)); + mtu = ALIGN(MVPP2_RX_PKT_SIZE(mtu), 8); + } + + return mtu; +} + +static int mvpp2_check_ringparam_valid(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + u16 new_rx_pending = ring->rx_pending; + u16 new_tx_pending = ring->tx_pending; + + if (ring->rx_pending == 0 || ring->tx_pending == 0) + return -EINVAL; + + if (ring->rx_pending > MVPP2_MAX_RXD) + new_rx_pending = MVPP2_MAX_RXD; + else if (!IS_ALIGNED(ring->rx_pending, 16)) + new_rx_pending = ALIGN(ring->rx_pending, 16); + + if (ring->tx_pending > MVPP2_MAX_TXD) + new_tx_pending = MVPP2_MAX_TXD; + else if (!IS_ALIGNED(ring->tx_pending, 32)) + new_tx_pending = ALIGN(ring->tx_pending, 32); + + if (ring->rx_pending != new_rx_pending) { + netdev_info(dev, "illegal Rx ring size value %d, round to %d\n", + ring->rx_pending, new_rx_pending); + ring->rx_pending = new_rx_pending; + } + + if (ring->tx_pending != new_tx_pending) { + netdev_info(dev, "illegal Tx ring size value %d, round to %d\n", + ring->tx_pending, new_tx_pending); + ring->tx_pending = new_tx_pending; + } + + return 0; +} + +static void mvpp2_get_mac_address(struct mvpp2_port *port, unsigned char *addr) +{ + u32 mac_addr_l, mac_addr_m, mac_addr_h; + + mac_addr_l = readl(port->base + MVPP2_GMAC_CTRL_1_REG); + mac_addr_m = readl(port->priv->lms_base + MVPP2_SRC_ADDR_MIDDLE); + mac_addr_h = readl(port->priv->lms_base + MVPP2_SRC_ADDR_HIGH); + addr[0] = (mac_addr_h >> 24) & 0xFF; + addr[1] = (mac_addr_h >> 16) & 0xFF; + addr[2] = (mac_addr_h >> 8) & 0xFF; + addr[3] = mac_addr_h & 0xFF; + addr[4] = mac_addr_m & 0xFF; + addr[5] = (mac_addr_l >> MVPP2_GMAC_SA_LOW_OFFS) & 0xFF; +} + +static int mvpp2_phy_connect(struct mvpp2_port *port) +{ + struct phy_device *phy_dev; + + phy_dev = of_phy_connect(port->dev, port->phy_node, mvpp2_link_event, 0, + port->phy_interface); + if (!phy_dev) { + netdev_err(port->dev, "cannot connect to phy\n"); + return -ENODEV; + } + phy_dev->supported &= PHY_GBIT_FEATURES; + phy_dev->advertising = phy_dev->supported; + + port->phy_dev = phy_dev; + port->link = 0; + port->duplex = 0; + port->speed = 0; + + return 0; +} + +static void mvpp2_phy_disconnect(struct mvpp2_port *port) +{ + phy_disconnect(port->phy_dev); + port->phy_dev = NULL; +} + +static int mvpp2_open(struct net_device *dev) +{ + struct mvpp2_port *port = netdev_priv(dev); + unsigned char mac_bcast[ETH_ALEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + int err; + + err = mvpp2_prs_mac_da_accept(port->priv, port->id, mac_bcast, true); + if (err) { + netdev_err(dev, "mvpp2_prs_mac_da_accept BC failed\n"); + return err; + } + err = mvpp2_prs_mac_da_accept(port->priv, port->id, + dev->dev_addr, true); + if (err) { + netdev_err(dev, "mvpp2_prs_mac_da_accept MC failed\n"); + return err; + } + err = mvpp2_prs_tag_mode_set(port->priv, port->id, MVPP2_TAG_TYPE_MH); + if (err) { + netdev_err(dev, "mvpp2_prs_tag_mode_set failed\n"); + return err; + } + err = mvpp2_prs_def_flow(port); + if (err) { + netdev_err(dev, "mvpp2_prs_def_flow failed\n"); + return err; + } + + /* Allocate the Rx/Tx queues */ + err = mvpp2_setup_rxqs(port); + if (err) { + netdev_err(port->dev, "cannot allocate Rx queues\n"); + return err; + } + + err = mvpp2_setup_txqs(port); + if (err) { + netdev_err(port->dev, "cannot allocate Tx queues\n"); + goto err_cleanup_rxqs; + } + + err = request_irq(port->irq, mvpp2_isr, 0, dev->name, port); + if (err) { + netdev_err(port->dev, "cannot request IRQ %d\n", port->irq); + goto err_cleanup_txqs; + } + + /* In default link is down */ + netif_carrier_off(port->dev); + + err = mvpp2_phy_connect(port); + if (err < 0) + goto err_free_irq; + + /* Unmask interrupts on all CPUs */ + on_each_cpu(mvpp2_interrupts_unmask, port, 1); + + mvpp2_start_dev(port); + + return 0; + +err_free_irq: + free_irq(port->irq, port); +err_cleanup_txqs: + mvpp2_cleanup_txqs(port); +err_cleanup_rxqs: + mvpp2_cleanup_rxqs(port); + return err; +} + +static int mvpp2_stop(struct net_device *dev) +{ + struct mvpp2_port *port = netdev_priv(dev); + + mvpp2_stop_dev(port); + mvpp2_phy_disconnect(port); + + /* Mask interrupts on all CPUs */ + on_each_cpu(mvpp2_interrupts_mask, port, 1); + + free_irq(port->irq, port); + mvpp2_cleanup_rxqs(port); + mvpp2_cleanup_txqs(port); + + return 0; +} + +static void mvpp2_set_rx_mode(struct net_device *dev) +{ + struct mvpp2_port *port = netdev_priv(dev); + struct mvpp2 *priv = port->priv; + struct netdev_hw_addr *ha; + int id = port->id; + bool allmulti = dev->flags & IFF_ALLMULTI; + + mvpp2_prs_mac_promisc_set(priv, id, dev->flags & IFF_PROMISC); + mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_ALL, allmulti); + mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_IP6, allmulti); + + /* Remove all port->id's mcast enries */ + mvpp2_prs_mcast_del_all(priv, id); + + if (allmulti && !netdev_mc_empty(dev)) { + netdev_for_each_mc_addr(ha, dev) + mvpp2_prs_mac_da_accept(priv, id, ha->addr, true); + } +} + +static int mvpp2_set_mac_address(struct net_device *dev, void *p) +{ + struct mvpp2_port *port = netdev_priv(dev); + const struct sockaddr *addr = p; + int err; + + if (!is_valid_ether_addr(addr->sa_data)) { + err = -EADDRNOTAVAIL; + goto error; + } + + if (!netif_running(dev)) { + err = mvpp2_prs_update_mac_da(dev, addr->sa_data); + if (!err) + return 0; + /* Reconfigure parser to accept the original MAC address */ + err = mvpp2_prs_update_mac_da(dev, dev->dev_addr); + if (err) + goto error; + } + + mvpp2_stop_dev(port); + + err = mvpp2_prs_update_mac_da(dev, addr->sa_data); + if (!err) + goto out_start; + + /* Reconfigure parser accept the original MAC address */ + err = mvpp2_prs_update_mac_da(dev, dev->dev_addr); + if (err) + goto error; +out_start: + mvpp2_start_dev(port); + mvpp2_egress_enable(port); + mvpp2_ingress_enable(port); + return 0; + +error: + netdev_err(dev, "fail to change MAC address\n"); + return err; +} + +static int mvpp2_change_mtu(struct net_device *dev, int mtu) +{ + struct mvpp2_port *port = netdev_priv(dev); + int err; + + mtu = mvpp2_check_mtu_valid(dev, mtu); + if (mtu < 0) { + err = mtu; + goto error; + } + + if (!netif_running(dev)) { + err = mvpp2_bm_update_mtu(dev, mtu); + if (!err) { + port->pkt_size = MVPP2_RX_PKT_SIZE(mtu); + return 0; + } + + /* Reconfigure BM to the original MTU */ + err = mvpp2_bm_update_mtu(dev, dev->mtu); + if (err) + goto error; + } + + mvpp2_stop_dev(port); + + err = mvpp2_bm_update_mtu(dev, mtu); + if (!err) { + port->pkt_size = MVPP2_RX_PKT_SIZE(mtu); + goto out_start; + } + + /* Reconfigure BM to the original MTU */ + err = mvpp2_bm_update_mtu(dev, dev->mtu); + if (err) + goto error; + +out_start: + mvpp2_start_dev(port); + mvpp2_egress_enable(port); + mvpp2_ingress_enable(port); + + return 0; + +error: + netdev_err(dev, "fail to change MTU\n"); + return err; +} + +static struct rtnl_link_stats64 * +mvpp2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) +{ + struct mvpp2_port *port = netdev_priv(dev); + unsigned int start; + int cpu; + + for_each_possible_cpu(cpu) { + struct mvpp2_pcpu_stats *cpu_stats; + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + + cpu_stats = per_cpu_ptr(port->stats, cpu); + do { + start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); + rx_packets = cpu_stats->rx_packets; + rx_bytes = cpu_stats->rx_bytes; + tx_packets = cpu_stats->tx_packets; + tx_bytes = cpu_stats->tx_bytes; + } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; + stats->tx_packets += tx_packets; + stats->tx_bytes += tx_bytes; + } + + stats->rx_errors = dev->stats.rx_errors; + stats->rx_dropped = dev->stats.rx_dropped; + stats->tx_dropped = dev->stats.tx_dropped; + + return stats; +} + +/* Ethtool methods */ + +/* Get settings (phy address, speed) for ethtools */ +static int mvpp2_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct mvpp2_port *port = netdev_priv(dev); + + if (!port->phy_dev) + return -ENODEV; + return phy_ethtool_gset(port->phy_dev, cmd); +} + +/* Set settings (phy address, speed) for ethtools */ +static int mvpp2_ethtool_set_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct mvpp2_port *port = netdev_priv(dev); + + if (!port->phy_dev) + return -ENODEV; + return phy_ethtool_sset(port->phy_dev, cmd); +} + +/* Set interrupt coalescing for ethtools */ +static int mvpp2_ethtool_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *c) +{ + struct mvpp2_port *port = netdev_priv(dev); + int queue; + + for (queue = 0; queue < rxq_number; queue++) { + struct mvpp2_rx_queue *rxq = port->rxqs[queue]; + + rxq->time_coal = c->rx_coalesce_usecs; + rxq->pkts_coal = c->rx_max_coalesced_frames; + mvpp2_rx_pkts_coal_set(port, rxq, rxq->pkts_coal); + mvpp2_rx_time_coal_set(port, rxq, rxq->time_coal); + } + + for (queue = 0; queue < txq_number; queue++) { + struct mvpp2_tx_queue *txq = port->txqs[queue]; + + txq->done_pkts_coal = c->tx_max_coalesced_frames; + } + + on_each_cpu(mvpp2_tx_done_pkts_coal_set, port, 1); + return 0; +} + +/* get coalescing for ethtools */ +static int mvpp2_ethtool_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *c) +{ + struct mvpp2_port *port = netdev_priv(dev); + + c->rx_coalesce_usecs = port->rxqs[0]->time_coal; + c->rx_max_coalesced_frames = port->rxqs[0]->pkts_coal; + c->tx_max_coalesced_frames = port->txqs[0]->done_pkts_coal; + return 0; +} + +static void mvpp2_ethtool_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) +{ + strlcpy(drvinfo->driver, MVPP2_DRIVER_NAME, + sizeof(drvinfo->driver)); + strlcpy(drvinfo->version, MVPP2_DRIVER_VERSION, + sizeof(drvinfo->version)); + strlcpy(drvinfo->bus_info, dev_name(&dev->dev), + sizeof(drvinfo->bus_info)); +} + +static void mvpp2_ethtool_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct mvpp2_port *port = netdev_priv(dev); + + ring->rx_max_pending = MVPP2_MAX_RXD; + ring->tx_max_pending = MVPP2_MAX_TXD; + ring->rx_pending = port->rx_ring_size; + ring->tx_pending = port->tx_ring_size; +} + +static int mvpp2_ethtool_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct mvpp2_port *port = netdev_priv(dev); + u16 prev_rx_ring_size = port->rx_ring_size; + u16 prev_tx_ring_size = port->tx_ring_size; + int err; + + err = mvpp2_check_ringparam_valid(dev, ring); + if (err) + return err; + + if (!netif_running(dev)) { + port->rx_ring_size = ring->rx_pending; + port->tx_ring_size = ring->tx_pending; + return 0; + } + + /* The interface is running, so we have to force a + * reallocation of the queues + */ + mvpp2_stop_dev(port); + mvpp2_cleanup_rxqs(port); + mvpp2_cleanup_txqs(port); + + port->rx_ring_size = ring->rx_pending; + port->tx_ring_size = ring->tx_pending; + + err = mvpp2_setup_rxqs(port); + if (err) { + /* Reallocate Rx queues with the original ring size */ + port->rx_ring_size = prev_rx_ring_size; + ring->rx_pending = prev_rx_ring_size; + err = mvpp2_setup_rxqs(port); + if (err) + goto err_out; + } + err = mvpp2_setup_txqs(port); + if (err) { + /* Reallocate Tx queues with the original ring size */ + port->tx_ring_size = prev_tx_ring_size; + ring->tx_pending = prev_tx_ring_size; + err = mvpp2_setup_txqs(port); + if (err) + goto err_clean_rxqs; + } + + mvpp2_start_dev(port); + mvpp2_egress_enable(port); + mvpp2_ingress_enable(port); + + return 0; + +err_clean_rxqs: + mvpp2_cleanup_rxqs(port); +err_out: + netdev_err(dev, "fail to change ring parameters"); + return err; +} + +/* Device ops */ + +static const struct net_device_ops mvpp2_netdev_ops = { + .ndo_open = mvpp2_open, + .ndo_stop = mvpp2_stop, + .ndo_start_xmit = mvpp2_tx, + .ndo_set_rx_mode = mvpp2_set_rx_mode, + .ndo_set_mac_address = mvpp2_set_mac_address, + .ndo_change_mtu = mvpp2_change_mtu, + .ndo_get_stats64 = mvpp2_get_stats64, +}; + +static const struct ethtool_ops mvpp2_eth_tool_ops = { + .get_link = ethtool_op_get_link, + .get_settings = mvpp2_ethtool_get_settings, + .set_settings = mvpp2_ethtool_set_settings, + .set_coalesce = mvpp2_ethtool_set_coalesce, + .get_coalesce = mvpp2_ethtool_get_coalesce, + .get_drvinfo = mvpp2_ethtool_get_drvinfo, + .get_ringparam = mvpp2_ethtool_get_ringparam, + .set_ringparam = mvpp2_ethtool_set_ringparam, +}; + +/* Driver initialization */ + +static void mvpp2_port_power_up(struct mvpp2_port *port) +{ + mvpp2_port_mii_set(port); + mvpp2_port_periodic_xon_disable(port); + mvpp2_port_reset(port); +} + +/* Initialize port HW */ +static int mvpp2_port_init(struct mvpp2_port *port) +{ + struct device *dev = port->dev->dev.parent; + struct mvpp2 *priv = port->priv; + struct mvpp2_txq_pcpu *txq_pcpu; + int queue, cpu, err; + + if (port->first_rxq + rxq_number > MVPP2_RXQ_TOTAL_NUM) + return -EINVAL; + + /* Disable port */ + mvpp2_egress_disable(port); + mvpp2_port_disable(port); + + port->txqs = devm_kcalloc(dev, txq_number, sizeof(*port->txqs), + GFP_KERNEL); + if (!port->txqs) + return -ENOMEM; + + /* Associate physical Tx queues to this port and initialize. + * The mapping is predefined. + */ + for (queue = 0; queue < txq_number; queue++) { + int queue_phy_id = mvpp2_txq_phys(port->id, queue); + struct mvpp2_tx_queue *txq; + + txq = devm_kzalloc(dev, sizeof(*txq), GFP_KERNEL); + if (!txq) + return -ENOMEM; + + txq->pcpu = alloc_percpu(struct mvpp2_txq_pcpu); + if (!txq->pcpu) { + err = -ENOMEM; + goto err_free_percpu; + } + + txq->id = queue_phy_id; + txq->log_id = queue; + txq->done_pkts_coal = MVPP2_TXDONE_COAL_PKTS_THRESH; + for_each_present_cpu(cpu) { + txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); + txq_pcpu->cpu = cpu; + } + + port->txqs[queue] = txq; + } + + port->rxqs = devm_kcalloc(dev, rxq_number, sizeof(*port->rxqs), + GFP_KERNEL); + if (!port->rxqs) { + err = -ENOMEM; + goto err_free_percpu; + } + + /* Allocate and initialize Rx queue for this port */ + for (queue = 0; queue < rxq_number; queue++) { + struct mvpp2_rx_queue *rxq; + + /* Map physical Rx queue to port's logical Rx queue */ + rxq = devm_kzalloc(dev, sizeof(*rxq), GFP_KERNEL); + if (!rxq) + goto err_free_percpu; + /* Map this Rx queue to a physical queue */ + rxq->id = port->first_rxq + queue; + rxq->port = port->id; + rxq->logic_rxq = queue; + + port->rxqs[queue] = rxq; + } + + /* Configure Rx queue group interrupt for this port */ + mvpp2_write(priv, MVPP2_ISR_RXQ_GROUP_REG(port->id), rxq_number); + + /* Create Rx descriptor rings */ + for (queue = 0; queue < rxq_number; queue++) { + struct mvpp2_rx_queue *rxq = port->rxqs[queue]; + + rxq->size = port->rx_ring_size; + rxq->pkts_coal = MVPP2_RX_COAL_PKTS; + rxq->time_coal = MVPP2_RX_COAL_USEC; + } + + mvpp2_ingress_disable(port); + + /* Port default configuration */ + mvpp2_defaults_set(port); + + /* Port's classifier configuration */ + mvpp2_cls_oversize_rxq_set(port); + mvpp2_cls_port_config(port); + + /* Provide an initial Rx packet size */ + port->pkt_size = MVPP2_RX_PKT_SIZE(port->dev->mtu); + + /* Initialize pools for swf */ + err = mvpp2_swf_bm_pool_init(port); + if (err) + goto err_free_percpu; + + return 0; + +err_free_percpu: + for (queue = 0; queue < txq_number; queue++) { + if (!port->txqs[queue]) + continue; + free_percpu(port->txqs[queue]->pcpu); + } + return err; +} + +/* Ports initialization */ +static int mvpp2_port_probe(struct platform_device *pdev, + struct device_node *port_node, + struct mvpp2 *priv, + int *next_first_rxq) +{ + struct device_node *phy_node; + struct mvpp2_port *port; + struct net_device *dev; + struct resource *res; + const char *dt_mac_addr; + const char *mac_from; + char hw_mac_addr[ETH_ALEN]; + u32 id; + int features; + int phy_mode; + int priv_common_regs_num = 2; + int err, i; + + dev = alloc_etherdev_mqs(sizeof(struct mvpp2_port), txq_number, + rxq_number); + if (!dev) + return -ENOMEM; + + phy_node = of_parse_phandle(port_node, "phy", 0); + if (!phy_node) { + dev_err(&pdev->dev, "missing phy\n"); + err = -ENODEV; + goto err_free_netdev; + } + + phy_mode = of_get_phy_mode(port_node); + if (phy_mode < 0) { + dev_err(&pdev->dev, "incorrect phy mode\n"); + err = phy_mode; + goto err_free_netdev; + } + + if (of_property_read_u32(port_node, "port-id", &id)) { + err = -EINVAL; + dev_err(&pdev->dev, "missing port-id value\n"); + goto err_free_netdev; + } + + dev->tx_queue_len = MVPP2_MAX_TXD; + dev->watchdog_timeo = 5 * HZ; + dev->netdev_ops = &mvpp2_netdev_ops; + dev->ethtool_ops = &mvpp2_eth_tool_ops; + + port = netdev_priv(dev); + + port->irq = irq_of_parse_and_map(port_node, 0); + if (port->irq <= 0) { + err = -EINVAL; + goto err_free_netdev; + } + + if (of_property_read_bool(port_node, "marvell,loopback")) + port->flags |= MVPP2_F_LOOPBACK; + + port->priv = priv; + port->id = id; + port->first_rxq = *next_first_rxq; + port->phy_node = phy_node; + port->phy_interface = phy_mode; + + res = platform_get_resource(pdev, IORESOURCE_MEM, + priv_common_regs_num + id); + port->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(port->base)) { + err = PTR_ERR(port->base); + dev_err(&pdev->dev, "cannot obtain port base address\n"); + goto err_free_irq; + } + + /* Alloc per-cpu stats */ + port->stats = netdev_alloc_pcpu_stats(struct mvpp2_pcpu_stats); + if (!port->stats) { + err = -ENOMEM; + goto err_free_irq; + } + + dt_mac_addr = of_get_mac_address(port_node); + if (dt_mac_addr && is_valid_ether_addr(dt_mac_addr)) { + mac_from = "device tree"; + ether_addr_copy(dev->dev_addr, dt_mac_addr); + } else { + mvpp2_get_mac_address(port, hw_mac_addr); + if (is_valid_ether_addr(hw_mac_addr)) { + mac_from = "hardware"; + ether_addr_copy(dev->dev_addr, hw_mac_addr); + } else { + mac_from = "random"; + eth_hw_addr_random(dev); + } + } + + port->tx_ring_size = MVPP2_MAX_TXD; + port->rx_ring_size = MVPP2_MAX_RXD; + port->dev = dev; + SET_NETDEV_DEV(dev, &pdev->dev); + + err = mvpp2_port_init(port); + if (err < 0) { + dev_err(&pdev->dev, "failed to init port %d\n", id); + goto err_free_stats; + } + mvpp2_port_power_up(port); + + netif_napi_add(dev, &port->napi, mvpp2_poll, NAPI_POLL_WEIGHT); + features = NETIF_F_SG | NETIF_F_IP_CSUM; + dev->features = features | NETIF_F_RXCSUM; + dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO; + dev->vlan_features |= features; + + err = register_netdev(dev); + if (err < 0) { + dev_err(&pdev->dev, "failed to register netdev\n"); + goto err_free_txq_pcpu; + } + netdev_info(dev, "Using %s mac address %pM\n", mac_from, dev->dev_addr); + + /* Increment the first Rx queue number to be used by the next port */ + *next_first_rxq += rxq_number; + priv->port_list[id] = port; + return 0; + +err_free_txq_pcpu: + for (i = 0; i < txq_number; i++) + free_percpu(port->txqs[i]->pcpu); +err_free_stats: + free_percpu(port->stats); +err_free_irq: + irq_dispose_mapping(port->irq); +err_free_netdev: + free_netdev(dev); + return err; +} + +/* Ports removal routine */ +static void mvpp2_port_remove(struct mvpp2_port *port) +{ + int i; + + unregister_netdev(port->dev); + free_percpu(port->stats); + for (i = 0; i < txq_number; i++) + free_percpu(port->txqs[i]->pcpu); + irq_dispose_mapping(port->irq); + free_netdev(port->dev); +} + +/* Initialize decoding windows */ +static void mvpp2_conf_mbus_windows(const struct mbus_dram_target_info *dram, + struct mvpp2 *priv) +{ + u32 win_enable; + int i; + + for (i = 0; i < 6; i++) { + mvpp2_write(priv, MVPP2_WIN_BASE(i), 0); + mvpp2_write(priv, MVPP2_WIN_SIZE(i), 0); + + if (i < 4) + mvpp2_write(priv, MVPP2_WIN_REMAP(i), 0); + } + + win_enable = 0; + + for (i = 0; i < dram->num_cs; i++) { + const struct mbus_dram_window *cs = dram->cs + i; + + mvpp2_write(priv, MVPP2_WIN_BASE(i), + (cs->base & 0xffff0000) | (cs->mbus_attr << 8) | + dram->mbus_dram_target_id); + + mvpp2_write(priv, MVPP2_WIN_SIZE(i), + (cs->size - 1) & 0xffff0000); + + win_enable |= (1 << i); + } + + mvpp2_write(priv, MVPP2_BASE_ADDR_ENABLE, win_enable); +} + +/* Initialize Rx FIFO's */ +static void mvpp2_rx_fifo_init(struct mvpp2 *priv) +{ + int port; + + for (port = 0; port < MVPP2_MAX_PORTS; port++) { + mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(port), + MVPP2_RX_FIFO_PORT_DATA_SIZE); + mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(port), + MVPP2_RX_FIFO_PORT_ATTR_SIZE); + } + + mvpp2_write(priv, MVPP2_RX_MIN_PKT_SIZE_REG, + MVPP2_RX_FIFO_PORT_MIN_PKT); + mvpp2_write(priv, MVPP2_RX_FIFO_INIT_REG, 0x1); +} + +/* Initialize network controller common part HW */ +static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv) +{ + const struct mbus_dram_target_info *dram_target_info; + int err, i; + + /* Checks for hardware constraints */ + if (rxq_number % 4 || (rxq_number > MVPP2_MAX_RXQ) || + (txq_number > MVPP2_MAX_TXQ)) { + dev_err(&pdev->dev, "invalid queue size parameter\n"); + return -EINVAL; + } + + /* MBUS windows configuration */ + dram_target_info = mv_mbus_dram_info(); + if (dram_target_info) + mvpp2_conf_mbus_windows(dram_target_info, priv); + + /* Allocate and initialize aggregated TXQs */ + priv->aggr_txqs = devm_kcalloc(&pdev->dev, num_present_cpus(), + sizeof(struct mvpp2_tx_queue), + GFP_KERNEL); + if (!priv->aggr_txqs) + return -ENOMEM; + + for_each_present_cpu(i) { + priv->aggr_txqs[i].id = i; + priv->aggr_txqs[i].size = MVPP2_AGGR_TXQ_SIZE; + err = mvpp2_aggr_txq_init(pdev, &priv->aggr_txqs[i], + MVPP2_AGGR_TXQ_SIZE, i, priv); + if (err < 0) + return err; + } + + /* Rx Fifo Init */ + mvpp2_rx_fifo_init(priv); + + /* Reset Rx queue group interrupt configuration */ + for (i = 0; i < MVPP2_MAX_PORTS; i++) + mvpp2_write(priv, MVPP2_ISR_RXQ_GROUP_REG(i), rxq_number); + + writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT, + priv->lms_base + MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG); + + /* Allow cache snoop when transmiting packets */ + mvpp2_write(priv, MVPP2_TX_SNOOP_REG, 0x1); + + /* Buffer Manager initialization */ + err = mvpp2_bm_init(pdev, priv); + if (err < 0) + return err; + + /* Parser default initialization */ + err = mvpp2_prs_default_init(pdev, priv); + if (err < 0) + return err; + + /* Classifier default initialization */ + mvpp2_cls_init(priv); + + return 0; +} + +static int mvpp2_probe(struct platform_device *pdev) +{ + struct device_node *dn = pdev->dev.of_node; + struct device_node *port_node; + struct mvpp2 *priv; + struct resource *res; + int port_count, first_rxq; + int err; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct mvpp2), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + priv->lms_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->lms_base)) + return PTR_ERR(priv->lms_base); + + priv->pp_clk = devm_clk_get(&pdev->dev, "pp_clk"); + if (IS_ERR(priv->pp_clk)) + return PTR_ERR(priv->pp_clk); + err = clk_prepare_enable(priv->pp_clk); + if (err < 0) + return err; + + priv->gop_clk = devm_clk_get(&pdev->dev, "gop_clk"); + if (IS_ERR(priv->gop_clk)) { + err = PTR_ERR(priv->gop_clk); + goto err_pp_clk; + } + err = clk_prepare_enable(priv->gop_clk); + if (err < 0) + goto err_pp_clk; + + /* Get system's tclk rate */ + priv->tclk = clk_get_rate(priv->pp_clk); + + /* Initialize network controller */ + err = mvpp2_init(pdev, priv); + if (err < 0) { + dev_err(&pdev->dev, "failed to initialize controller\n"); + goto err_gop_clk; + } + + port_count = of_get_available_child_count(dn); + if (port_count == 0) { + dev_err(&pdev->dev, "no ports enabled\n"); + goto err_gop_clk; + } + + priv->port_list = devm_kcalloc(&pdev->dev, port_count, + sizeof(struct mvpp2_port *), + GFP_KERNEL); + if (!priv->port_list) { + err = -ENOMEM; + goto err_gop_clk; + } + + /* Initialize ports */ + first_rxq = 0; + for_each_available_child_of_node(dn, port_node) { + err = mvpp2_port_probe(pdev, port_node, priv, &first_rxq); + if (err < 0) + goto err_gop_clk; + } + + platform_set_drvdata(pdev, priv); + return 0; + +err_gop_clk: + clk_disable_unprepare(priv->gop_clk); +err_pp_clk: + clk_disable_unprepare(priv->pp_clk); + return err; +} + +static int mvpp2_remove(struct platform_device *pdev) +{ + struct mvpp2 *priv = platform_get_drvdata(pdev); + struct device_node *dn = pdev->dev.of_node; + struct device_node *port_node; + int i = 0; + + for_each_available_child_of_node(dn, port_node) { + if (priv->port_list[i]) + mvpp2_port_remove(priv->port_list[i]); + i++; + } + + for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) { + struct mvpp2_bm_pool *bm_pool = &priv->bm_pools[i]; + + mvpp2_bm_pool_destroy(pdev, priv, bm_pool); + } + + for_each_present_cpu(i) { + struct mvpp2_tx_queue *aggr_txq = &priv->aggr_txqs[i]; + + dma_free_coherent(&pdev->dev, + MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE, + aggr_txq->descs, + aggr_txq->descs_phys); + } + + clk_disable_unprepare(priv->pp_clk); + clk_disable_unprepare(priv->gop_clk); + + return 0; +} + +static const struct of_device_id mvpp2_match[] = { + { .compatible = "marvell,armada-375-pp2" }, + { } +}; +MODULE_DEVICE_TABLE(of, mvpp2_match); + +static struct platform_driver mvpp2_driver = { + .probe = mvpp2_probe, + .remove = mvpp2_remove, + .driver = { + .name = MVPP2_DRIVER_NAME, + .of_match_table = mvpp2_match, + }, +}; + +module_platform_driver(mvpp2_driver); + +MODULE_DESCRIPTION("Marvell PPv2 Ethernet Driver - www.marvell.com"); +MODULE_AUTHOR("Marcin Wojtas "); +MODULE_LICENSE("GPLv2"); -- cgit v1.2.3 From f49daa8190ebf25eae907048266b590a9cdccb95 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 04:58:29 +0200 Subject: Bluetooth: Move HCI socket definitions into its own header file All the HCI sockets and ioctl based definitions have been in a global header file that also includes all the HCI protocol structures. To make this a bit cleaner, move them into its own file. This also adjusts fs/compat_ioctl.c to only include this new file and not all the protocol structures that are not needed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- fs/compat_ioctl.c | 2 +- include/net/bluetooth/hci.h | 149 --------------------------------- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/hci_sock.h | 175 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+), 150 deletions(-) create mode 100644 include/net/bluetooth/hci_sock.h diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index e82289047272..afec6450450f 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -59,7 +59,7 @@ #include #include -#include +#include #include #include diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index a01236e2df13..7f754a246ca5 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -202,33 +202,6 @@ enum { #define HCI_PERSISTENT_MASK (BIT(HCI_LE_SCAN) | BIT(HCI_PERIODIC_INQ) | \ BIT(HCI_FAST_CONNECTABLE) | BIT(HCI_LE_ADV)) -/* HCI ioctl defines */ -#define HCIDEVUP _IOW('H', 201, int) -#define HCIDEVDOWN _IOW('H', 202, int) -#define HCIDEVRESET _IOW('H', 203, int) -#define HCIDEVRESTAT _IOW('H', 204, int) - -#define HCIGETDEVLIST _IOR('H', 210, int) -#define HCIGETDEVINFO _IOR('H', 211, int) -#define HCIGETCONNLIST _IOR('H', 212, int) -#define HCIGETCONNINFO _IOR('H', 213, int) -#define HCIGETAUTHINFO _IOR('H', 215, int) - -#define HCISETRAW _IOW('H', 220, int) -#define HCISETSCAN _IOW('H', 221, int) -#define HCISETAUTH _IOW('H', 222, int) -#define HCISETENCRYPT _IOW('H', 223, int) -#define HCISETPTYPE _IOW('H', 224, int) -#define HCISETLINKPOL _IOW('H', 225, int) -#define HCISETLINKMODE _IOW('H', 226, int) -#define HCISETACLMTU _IOW('H', 227, int) -#define HCISETSCOMTU _IOW('H', 228, int) - -#define HCIBLOCKADDR _IOW('H', 230, int) -#define HCIUNBLOCKADDR _IOW('H', 231, int) - -#define HCIINQUIRY _IOR('H', 240, int) - /* HCI timeouts */ #define HCI_DISCONN_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ #define HCI_PAIRING_TIMEOUT msecs_to_jiffies(60000) /* 60 seconds */ @@ -1871,126 +1844,4 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb) #define hci_handle(h) (h & 0x0fff) #define hci_flags(h) (h >> 12) -/* ---- HCI Sockets ---- */ - -/* Socket options */ -#define HCI_DATA_DIR 1 -#define HCI_FILTER 2 -#define HCI_TIME_STAMP 3 - -/* CMSG flags */ -#define HCI_CMSG_DIR 0x0001 -#define HCI_CMSG_TSTAMP 0x0002 - -struct sockaddr_hci { - sa_family_t hci_family; - unsigned short hci_dev; - unsigned short hci_channel; -}; -#define HCI_DEV_NONE 0xffff - -#define HCI_CHANNEL_RAW 0 -#define HCI_CHANNEL_USER 1 -#define HCI_CHANNEL_MONITOR 2 -#define HCI_CHANNEL_CONTROL 3 - -struct hci_filter { - unsigned long type_mask; - unsigned long event_mask[2]; - __le16 opcode; -}; - -struct hci_ufilter { - __u32 type_mask; - __u32 event_mask[2]; - __le16 opcode; -}; - -#define HCI_FLT_TYPE_BITS 31 -#define HCI_FLT_EVENT_BITS 63 -#define HCI_FLT_OGF_BITS 63 -#define HCI_FLT_OCF_BITS 127 - -/* ---- HCI Ioctl requests structures ---- */ -struct hci_dev_stats { - __u32 err_rx; - __u32 err_tx; - __u32 cmd_tx; - __u32 evt_rx; - __u32 acl_tx; - __u32 acl_rx; - __u32 sco_tx; - __u32 sco_rx; - __u32 byte_rx; - __u32 byte_tx; -}; - -struct hci_dev_info { - __u16 dev_id; - char name[8]; - - bdaddr_t bdaddr; - - __u32 flags; - __u8 type; - - __u8 features[8]; - - __u32 pkt_type; - __u32 link_policy; - __u32 link_mode; - - __u16 acl_mtu; - __u16 acl_pkts; - __u16 sco_mtu; - __u16 sco_pkts; - - struct hci_dev_stats stat; -}; - -struct hci_conn_info { - __u16 handle; - bdaddr_t bdaddr; - __u8 type; - __u8 out; - __u16 state; - __u32 link_mode; -}; - -struct hci_dev_req { - __u16 dev_id; - __u32 dev_opt; -}; - -struct hci_dev_list_req { - __u16 dev_num; - struct hci_dev_req dev_req[0]; /* hci_dev_req structures */ -}; - -struct hci_conn_list_req { - __u16 dev_id; - __u16 conn_num; - struct hci_conn_info conn_info[0]; -}; - -struct hci_conn_info_req { - bdaddr_t bdaddr; - __u8 type; - struct hci_conn_info conn_info[0]; -}; - -struct hci_auth_info_req { - bdaddr_t bdaddr; - __u8 type; -}; - -struct hci_inquiry_req { - __u16 dev_id; - __u16 flags; - __u8 lap[3]; - __u8 length; - __u8 num_rsp; -}; -#define IREQ_CACHE_FLUSH 0x0001 - #endif /* __HCI_H */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7e9e95633a85..5c52a17d6326 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -26,6 +26,7 @@ #define __HCI_CORE_H #include +#include /* HCI priority */ #define HCI_PRIO_MAX 7 diff --git a/include/net/bluetooth/hci_sock.h b/include/net/bluetooth/hci_sock.h new file mode 100644 index 000000000000..9a46d665c1b5 --- /dev/null +++ b/include/net/bluetooth/hci_sock.h @@ -0,0 +1,175 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + 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; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +#ifndef __HCI_SOCK_H +#define __HCI_SOCK_H + +/* Socket options */ +#define HCI_DATA_DIR 1 +#define HCI_FILTER 2 +#define HCI_TIME_STAMP 3 + +/* CMSG flags */ +#define HCI_CMSG_DIR 0x0001 +#define HCI_CMSG_TSTAMP 0x0002 + +struct sockaddr_hci { + sa_family_t hci_family; + unsigned short hci_dev; + unsigned short hci_channel; +}; +#define HCI_DEV_NONE 0xffff + +#define HCI_CHANNEL_RAW 0 +#define HCI_CHANNEL_USER 1 +#define HCI_CHANNEL_MONITOR 2 +#define HCI_CHANNEL_CONTROL 3 + +struct hci_filter { + unsigned long type_mask; + unsigned long event_mask[2]; + __le16 opcode; +}; + +struct hci_ufilter { + __u32 type_mask; + __u32 event_mask[2]; + __le16 opcode; +}; + +#define HCI_FLT_TYPE_BITS 31 +#define HCI_FLT_EVENT_BITS 63 +#define HCI_FLT_OGF_BITS 63 +#define HCI_FLT_OCF_BITS 127 + +/* Ioctl defines */ +#define HCIDEVUP _IOW('H', 201, int) +#define HCIDEVDOWN _IOW('H', 202, int) +#define HCIDEVRESET _IOW('H', 203, int) +#define HCIDEVRESTAT _IOW('H', 204, int) + +#define HCIGETDEVLIST _IOR('H', 210, int) +#define HCIGETDEVINFO _IOR('H', 211, int) +#define HCIGETCONNLIST _IOR('H', 212, int) +#define HCIGETCONNINFO _IOR('H', 213, int) +#define HCIGETAUTHINFO _IOR('H', 215, int) + +#define HCISETRAW _IOW('H', 220, int) +#define HCISETSCAN _IOW('H', 221, int) +#define HCISETAUTH _IOW('H', 222, int) +#define HCISETENCRYPT _IOW('H', 223, int) +#define HCISETPTYPE _IOW('H', 224, int) +#define HCISETLINKPOL _IOW('H', 225, int) +#define HCISETLINKMODE _IOW('H', 226, int) +#define HCISETACLMTU _IOW('H', 227, int) +#define HCISETSCOMTU _IOW('H', 228, int) + +#define HCIBLOCKADDR _IOW('H', 230, int) +#define HCIUNBLOCKADDR _IOW('H', 231, int) + +#define HCIINQUIRY _IOR('H', 240, int) + +/* Ioctl requests structures */ +struct hci_dev_stats { + __u32 err_rx; + __u32 err_tx; + __u32 cmd_tx; + __u32 evt_rx; + __u32 acl_tx; + __u32 acl_rx; + __u32 sco_tx; + __u32 sco_rx; + __u32 byte_rx; + __u32 byte_tx; +}; + +struct hci_dev_info { + __u16 dev_id; + char name[8]; + + bdaddr_t bdaddr; + + __u32 flags; + __u8 type; + + __u8 features[8]; + + __u32 pkt_type; + __u32 link_policy; + __u32 link_mode; + + __u16 acl_mtu; + __u16 acl_pkts; + __u16 sco_mtu; + __u16 sco_pkts; + + struct hci_dev_stats stat; +}; + +struct hci_conn_info { + __u16 handle; + bdaddr_t bdaddr; + __u8 type; + __u8 out; + __u16 state; + __u32 link_mode; +}; + +struct hci_dev_req { + __u16 dev_id; + __u32 dev_opt; +}; + +struct hci_dev_list_req { + __u16 dev_num; + struct hci_dev_req dev_req[0]; /* hci_dev_req structures */ +}; + +struct hci_conn_list_req { + __u16 dev_id; + __u16 conn_num; + struct hci_conn_info conn_info[0]; +}; + +struct hci_conn_info_req { + bdaddr_t bdaddr; + __u8 type; + struct hci_conn_info conn_info[0]; +}; + +struct hci_auth_info_req { + bdaddr_t bdaddr; + __u8 type; +}; + +struct hci_inquiry_req { + __u16 dev_id; + __u16 flags; + __u8 lap[3]; + __u8 length; + __u8 num_rsp; +}; +#define IREQ_CACHE_FLUSH 0x0001 + +#endif /* __HCI_SOCK_H */ -- cgit v1.2.3 From 3ad254f7f6fd3b66ce47a156cbb92cb02002103e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 05:36:39 +0200 Subject: Bluetooth: Move struct hci_sec_filter next to its user There is only single location using struct hci_sec_filter and with that there is no point in putting this declaration into a global header file. So move it right next to its user and make the code a lot more simpler. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 9 --------- net/bluetooth/hci_sock.c | 8 ++++++++ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5c52a17d6326..e1930749fac7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1360,15 +1360,6 @@ struct hci_pinfo { unsigned short channel; }; -/* HCI security filter */ -#define HCI_SFLT_MAX_OGF 5 - -struct hci_sec_filter { - __u32 type_mask; - __u32 event_mask[2]; - __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; -}; - /* ----- HCI requests ----- */ #define HCI_REQ_DONE 0 #define HCI_REQ_PEND 1 diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index c64728d571ae..7805fd1b4a78 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -41,6 +41,14 @@ static inline int hci_test_bit(int nr, void *addr) } /* Security filter */ +#define HCI_SFLT_MAX_OGF 5 + +struct hci_sec_filter { + __u32 type_mask; + __u32 event_mask[2]; + __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; +}; + static struct hci_sec_filter hci_sec_filter = { /* Packet types */ 0x10, -- cgit v1.2.3 From 7e67c112a007fafef6dd36c33d1029a65250ca9b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 05:36:40 +0200 Subject: Bluetooth: Delcare the hci_sec_filter as const The hci_sec_filter socket filter details do not change. They are fixed and with that they can also be delcared as const. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 7805fd1b4a78..0753fa4970c0 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -49,7 +49,7 @@ struct hci_sec_filter { __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; }; -static struct hci_sec_filter hci_sec_filter = { +static const struct hci_sec_filter hci_sec_filter = { /* Packet types */ 0x10, /* Events */ -- cgit v1.2.3 From 863def58fec2fa494c8e9ca45471819c6d731ec3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 05:41:00 +0200 Subject: Bluetooth: Move struct hci_pinfo into net/bluetooth/hci_sock.c There exists no external user of struct hci_pinfo and hci_pi and thus move it into the one place that is actually using it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 11 ----------- net/bluetooth/hci_sock.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e1930749fac7..fffd0da2e0fc 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1349,17 +1349,6 @@ void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr, void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_smp_complete(struct hci_conn *conn, bool complete); -/* HCI info for socket */ -#define hci_pi(sk) ((struct hci_pinfo *) sk) - -struct hci_pinfo { - struct bt_sock bt; - struct hci_dev *hdev; - struct hci_filter filter; - __u32 cmsg_mask; - unsigned short channel; -}; - /* ----- HCI requests ----- */ #define HCI_REQ_DONE 0 #define HCI_REQ_PEND 1 diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 0753fa4970c0..115f149362ba 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -35,6 +35,17 @@ static atomic_t monitor_promisc = ATOMIC_INIT(0); /* ----- HCI socket interface ----- */ +/* Socket info */ +#define hci_pi(sk) ((struct hci_pinfo *) sk) + +struct hci_pinfo { + struct bt_sock bt; + struct hci_dev *hdev; + struct hci_filter filter; + __u32 cmsg_mask; + unsigned short channel; +}; + static inline int hci_test_bit(int nr, void *addr) { return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31)); -- cgit v1.2.3 From 899de765667b63bb51526f0a31693aed6ad5f828 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 05:51:58 +0200 Subject: Bluetooth: Move HCI request internals to net/bluetooth/hci_core.c The internals of the HCI request framework should not be leaking to its users. Move them all into net/bluetooth/hci_core.c and provide a simple hci_req_pending helper function for the one user outside the framework. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 9 +-------- net/bluetooth/hci_core.c | 14 ++++++++++++++ net/bluetooth/hci_event.c | 2 +- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index fffd0da2e0fc..b52c2ef3f56d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1240,6 +1240,7 @@ void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen, const void *param, u8 event); void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status); +bool hci_req_pending(struct hci_dev *hdev); void hci_req_add_le_scan_disable(struct hci_request *req); void hci_req_add_le_passive_scan(struct hci_request *req); @@ -1349,14 +1350,6 @@ void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr, void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_smp_complete(struct hci_conn *conn, bool complete); -/* ----- HCI requests ----- */ -#define HCI_REQ_DONE 0 -#define HCI_REQ_PEND 1 -#define HCI_REQ_CANCELED 2 - -#define hci_req_lock(d) mutex_lock(&d->req_lock) -#define hci_req_unlock(d) mutex_unlock(&d->req_lock) - u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 52e8c91ea3e9..347f84fb66f9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -54,6 +54,15 @@ DEFINE_RWLOCK(hci_cb_list_lock); /* HCI ID Numbering */ static DEFINE_IDA(hci_index_ida); +/* ----- HCI requests ----- */ + +#define HCI_REQ_DONE 0 +#define HCI_REQ_PEND 1 +#define HCI_REQ_CANCELED 2 + +#define hci_req_lock(d) mutex_lock(&d->req_lock) +#define hci_req_unlock(d) mutex_unlock(&d->req_lock) + /* ---- HCI notifications ---- */ static void hci_notify(struct hci_dev *hdev, int event) @@ -4432,6 +4441,11 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete) return 0; } +bool hci_req_pending(struct hci_dev *hdev) +{ + return (hdev->req_status == HCI_REQ_PEND); +} + static struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a62e918d2641..f0f220057f21 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4624,7 +4624,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) /* Received events are (currently) only needed when a request is * ongoing so avoid unnecessary memory allocation. */ - if (hdev->req_status == HCI_REQ_PEND) { + if (hci_req_pending(hdev)) { kfree_skb(hdev->recv_evt); hdev->recv_evt = skb_clone(skb, GFP_KERNEL); } -- cgit v1.2.3 From a6801ca9856c24298cba2c1fafd3da818acdaab6 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 06:03:08 +0200 Subject: Bluetooth: Update the list of L2CAP fixed channels The list of L2CAP fixed channels increased with newer versions of the specification. This just updates the constants for it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 5 ++++- net/bluetooth/l2cap_core.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index e0c6a9abdb62..d8e7b9330ab8 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -134,9 +134,12 @@ struct l2cap_conninfo { #define L2CAP_FCS_CRC16 0x01 /* L2CAP fixed channels */ -#define L2CAP_FC_L2CAP 0x02 +#define L2CAP_FC_SIG_BREDR 0x02 #define L2CAP_FC_CONNLESS 0x04 #define L2CAP_FC_A2MP 0x08 +#define L2CAP_FC_ATT 0x10 +#define L2CAP_FC_SIG_LE 0x20 +#define L2CAP_FC_SMP_LE 0x40 /* L2CAP Control Field bit masks */ #define L2CAP_CTRL_SAR 0xC000 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8680aae678ce..0c3c4935f635 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -46,7 +46,7 @@ bool disable_ertm; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD; -static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP | L2CAP_FC_CONNLESS, }; +static u8 l2cap_fixed_chan[8] = { L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS, }; static LIST_HEAD(chan_list); static DEFINE_RWLOCK(chan_list_lock); -- cgit v1.2.3 From 2a0dccb3df2c8775d1a6e962aa88c4c22693c887 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 06:19:41 +0200 Subject: Bluetooth: Move struct sco_pinfo into net/bluetooth/sco.c There exists no external user of struct sco_pinfo and sco_pi and thus move it into the one place that is actually using it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/sco.h | 12 ------------ net/bluetooth/sco.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index 2019d1a0996a..7fec7cbd7396 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h @@ -64,16 +64,4 @@ struct sco_conn { #define sco_conn_lock(c) spin_lock(&c->lock); #define sco_conn_unlock(c) spin_unlock(&c->lock); -/* ----- SCO socket info ----- */ -#define sco_pi(sk) ((struct sco_pinfo *) sk) - -struct sco_pinfo { - struct bt_sock bt; - bdaddr_t src; - bdaddr_t dst; - __u32 flags; - __u16 setting; - struct sco_conn *conn; -}; - #endif /* __SCO_H */ diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c06dbd3938e8..c71698642ec6 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -46,6 +46,18 @@ static void sco_chan_del(struct sock *sk, int err); static void sco_sock_close(struct sock *sk); static void sco_sock_kill(struct sock *sk); +/* ----- SCO socket info ----- */ +#define sco_pi(sk) ((struct sco_pinfo *) sk) + +struct sco_pinfo { + struct bt_sock bt; + bdaddr_t src; + bdaddr_t dst; + __u32 flags; + __u16 setting; + struct sco_conn *conn; +}; + /* ---- SCO timers ---- */ static void sco_sock_timeout(unsigned long arg) { -- cgit v1.2.3 From fc8f525a6f7c81743bec6b5d497988313b211383 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 06:19:42 +0200 Subject: Bluetooth: Move struct sco_conn into net/bluetooth/sco.c There exists no external user of struct sco_conn and thus move it into the one place that is actually using it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/sco.h | 13 ------------- net/bluetooth/sco.c | 13 +++++++++++++ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index 7fec7cbd7396..42a0d089d715 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h @@ -51,17 +51,4 @@ struct sco_conninfo { __u8 dev_class[3]; }; -/* ---- SCO connections ---- */ -struct sco_conn { - struct hci_conn *hcon; - - spinlock_t lock; - struct sock *sk; - - unsigned int mtu; -}; - -#define sco_conn_lock(c) spin_lock(&c->lock); -#define sco_conn_unlock(c) spin_unlock(&c->lock); - #endif /* __SCO_H */ diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c71698642ec6..9868ec7c7dc4 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -40,6 +40,19 @@ static struct bt_sock_list sco_sk_list = { .lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock) }; +/* ---- SCO connections ---- */ +struct sco_conn { + struct hci_conn *hcon; + + spinlock_t lock; + struct sock *sk; + + unsigned int mtu; +}; + +#define sco_conn_lock(c) spin_lock(&c->lock); +#define sco_conn_unlock(c) spin_unlock(&c->lock); + static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); static void sco_chan_del(struct sock *sk, int err); -- cgit v1.2.3 From 6190ae7a184bf488aeb051a5713aa57b07d4c59b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 06:19:43 +0200 Subject: Bluetooth: Remove unused SCO_DEFAULT_FLUSH_TO constant The SCO_DEFAULT_FLUSH_TO constant has been defined, but it is not used anywhere and so just remove it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/sco.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index 42a0d089d715..ab8b1ed550d2 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h @@ -27,7 +27,6 @@ /* SCO defaults */ #define SCO_DEFAULT_MTU 500 -#define SCO_DEFAULT_FLUSH_TO 0xFFFF #define SCO_CONN_TIMEOUT (HZ * 40) #define SCO_DISCONN_TIMEOUT (HZ * 2) -- cgit v1.2.3 From 068d69e5bbd85291aa8ad0d81062f047609a173c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 06:19:44 +0200 Subject: Bluetooth: Move SCO timeout constants into net/bluetooth/sco.c There is no external user of the SCO timeout constants and thus move them into net/bluetooth/sco.c where they are actuallu used. In addition just remove SCO_CONN_IDLE_TIMEOUT since it is unused. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/sco.h | 4 ---- net/bluetooth/sco.c | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index ab8b1ed550d2..f40ddb4264fc 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h @@ -28,10 +28,6 @@ /* SCO defaults */ #define SCO_DEFAULT_MTU 500 -#define SCO_CONN_TIMEOUT (HZ * 40) -#define SCO_DISCONN_TIMEOUT (HZ * 2) -#define SCO_CONN_IDLE_TIMEOUT (HZ * 60) - /* SCO socket address */ struct sockaddr_sco { sa_family_t sco_family; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 9868ec7c7dc4..e6c7b636b901 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -72,6 +72,9 @@ struct sco_pinfo { }; /* ---- SCO timers ---- */ +#define SCO_CONN_TIMEOUT (HZ * 40) +#define SCO_DISCONN_TIMEOUT (HZ * 2) + static void sco_sock_timeout(unsigned long arg) { struct sock *sk = (struct sock *) arg; -- cgit v1.2.3 From bb72bd68fd87a4347b2a891ab16aac6014e69a00 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 07:12:57 +0200 Subject: Bluetooth: Check for valid HCI UART driver flags Providing unknown or invalid flags to the HCI UART driver should result in an error. So check which flags are valid and otherwise return an error. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ldisc.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index e00f8f5b5c8e..a49ee1b42439 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -477,6 +477,21 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id) return 0; } +static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) +{ + unsigned long valid_flags = BIT(HCI_UART_RAW_DEVICE) | + BIT(HCI_UART_RESET_ON_INIT) | + BIT(HCI_UART_CREATE_AMP) | + BIT(HCI_UART_INIT_PENDING); + + if ((flags & ~valid_flags)) + return -EINVAL; + + hu->hdev_flags = flags; + + return 0; +} + /* hci_uart_tty_ioctl() * * Process IOCTL system call for the tty device. @@ -527,7 +542,9 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, case HCIUARTSETFLAGS: if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) return -EBUSY; - hu->hdev_flags = arg; + err = hci_uart_set_flags(hu, arg); + if (err) + return err; break; case HCIUARTGETFLAGS: -- cgit v1.2.3 From 6afd04ad6b6608fe2d9abce120bd8c0bc6aba287 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 07:12:58 +0200 Subject: Bluetooth: Add support for external configuration with UART driver The quirk for enabling external configuration with UART needs to be provided via the HCI UART flags. Add a new flag for it and declare it as valid. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ldisc.c | 6 +++++- drivers/bluetooth/hci_uart.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index a49ee1b42439..401a3be57cda 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -431,6 +431,9 @@ static int hci_uart_register_dev(struct hci_uart *hu) if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags)) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); + if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags)) + set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks); + if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags)) set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); @@ -482,7 +485,8 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) unsigned long valid_flags = BIT(HCI_UART_RAW_DEVICE) | BIT(HCI_UART_RESET_ON_INIT) | BIT(HCI_UART_CREATE_AMP) | - BIT(HCI_UART_INIT_PENDING); + BIT(HCI_UART_INIT_PENDING) | + BIT(HCI_UART_EXT_CONFIG); if ((flags & ~valid_flags)) return -EINVAL; diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 12df101ca942..247488edcbf9 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -48,6 +48,7 @@ #define HCI_UART_RESET_ON_INIT 1 #define HCI_UART_CREATE_AMP 2 #define HCI_UART_INIT_PENDING 3 +#define HCI_UART_EXT_CONFIG 4 struct hci_uart; -- cgit v1.2.3 From 6c53823ae0e10e723131055e1e65dd6a328a228e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 11 Jul 2014 15:32:23 +0300 Subject: Bluetooth: Fix tracking local SSP authentication requirement When we need to make the decision whether to perform just-works or real user confirmation we need to know the exact local authentication requirement that was passed to the controller. So far conn->auth_type (the local requirement) wasn't in one case updated appropriately in fear of the user confirmation being rejected later. The real problem however was not really that conn->auth_type couldn't represent the true value but that we were checking the local MITM requirement in an incorrect way. It's perfectly fine to let auth_type follow what we tell the controller since we're still tracking the target security level with conn->pending_sec_level. This patch updates the check for local MITM requirement in the hci_user_confirm_request_evt function to use the locally requested security level and ensures that auth_type always represents what we tell the controller. All other code in hci_user_confirm_request_evt still uses the auth_type instead of pending_sec_level for determining whether to do just-works or not, since that's the only value that's in sync with what the remote device knows. Signed-off-by: Johan Hedberg Tested-by: Szymon Janc Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org # 3.16 --- net/bluetooth/hci_event.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f0f220057f21..8980bd24b8c0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3664,18 +3664,14 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) /* If we are initiators, there is no remote information yet */ if (conn->remote_auth == 0xff) { - cp.authentication = conn->auth_type; - /* Request MITM protection if our IO caps allow it * except for the no-bonding case. - * conn->auth_type is not updated here since - * that might cause the user confirmation to be - * rejected in case the remote doesn't have the - * IO capabilities for MITM. */ if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && cp.authentication != HCI_AT_NO_BONDING) - cp.authentication |= 0x01; + conn->auth_type |= 0x01; + + cp.authentication = conn->auth_type; } else { conn->auth_type = hci_get_auth_req(conn); cp.authentication = conn->auth_type; @@ -3747,9 +3743,12 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, rem_mitm = (conn->remote_auth & 0x01); /* If we require MITM but the remote device can't provide that - * (it has NoInputNoOutput) then reject the confirmation request + * (it has NoInputNoOutput) then reject the confirmation + * request. We check the security level here since it doesn't + * necessarily match conn->auth_type. */ - if (loc_mitm && conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) { + if (conn->pending_sec_level > BT_SECURITY_MEDIUM && + conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) { BT_DBG("Rejecting request: remote device can't provide MITM"); hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); -- cgit v1.2.3 From a0077a9fa3fef18ab0890e79a367270c5ae5fe54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Fri, 11 Jul 2014 08:18:26 +0200 Subject: dp83640: Adjust ptp event timestamps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Event timestamp values should be adjusted by 3*reference clock period + 11 ns = 35 ns to compensate for input path and synchronization delays. So subtract 35ns from event timestamps. Signed-off-by: Stefan Sørensen Acked-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/phy/dp83640.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 53bd1af68422..76fbd3948736 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -755,6 +755,9 @@ static int decode_evnt(struct dp83640_private *dp83640, event.type = PTP_CLOCK_EXTTS; event.timestamp = phy2txts(&dp83640->edata); + /* Compensate for input path and synchronization delays */ + event.timestamp -= 35; + for (i = 0; i < N_EXT_TS; i++) { if (ext_status & exts_chan_to_edata(i)) { event.index = i; -- cgit v1.2.3 From a2f983f83b0f66a74a045d36eb84e2f01bb950c7 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Fri, 11 Jul 2014 14:32:17 +0800 Subject: ipv4: remove the unnecessary variable in udp_mcast_next Signed-off-by: Li RongQing Signed-off-by: David S. Miller --- net/ipv4/udp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d92f94b7e402..ac30e106a884 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -600,19 +600,18 @@ static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk, int dif) { struct hlist_nulls_node *node; - struct sock *s = sk; unsigned short hnum = ntohs(loc_port); - sk_nulls_for_each_from(s, node) { - if (__udp_is_mcast_sock(net, s, + sk_nulls_for_each_from(sk, node) { + if (__udp_is_mcast_sock(net, sk, loc_port, loc_addr, rmt_port, rmt_addr, dif, hnum)) goto found; } - s = NULL; + sk = NULL; found: - return s; + return sk; } /* -- cgit v1.2.3 From 5888d3fc45facf13c51b7c056778ac8424a057f3 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 11 Jul 2014 16:25:56 +0800 Subject: r8169: split rtl8169_tso_csum According to the txd_version, split rtl8169_tso_csum() into rtl8169_tso_csum_v1() and rtl8169_tso_csum_v2(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 71 +++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index be425ad5e824..6b7e21a8da57 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -633,32 +633,6 @@ enum rtl_tx_desc_bit_1 { TD1_UDP_CS = (1 << 31), /* Calculate UDP/IP checksum */ }; -static const struct rtl_tx_desc_info { - struct { - u32 udp; - u32 tcp; - } checksum; - u16 mss_shift; - u16 opts_offset; -} tx_desc_info [] = { - [RTL_TD_0] = { - .checksum = { - .udp = TD0_IP_CS | TD0_UDP_CS, - .tcp = TD0_IP_CS | TD0_TCP_CS - }, - .mss_shift = TD0_MSS_SHIFT, - .opts_offset = 0 - }, - [RTL_TD_1] = { - .checksum = { - .udp = TD1_IP_CS | TD1_UDP_CS, - .tcp = TD1_IP_CS | TD1_TCP_CS - }, - .mss_shift = TD1_MSS_SHIFT, - .opts_offset = 1 - } -}; - enum rtl_rx_desc_bit { /* Rx private */ PID1 = (1 << 18), /* Protocol ID bit 1/2 */ @@ -782,6 +756,7 @@ struct rtl8169_private { unsigned int (*phy_reset_pending)(struct rtl8169_private *tp); unsigned int (*link_ok)(void __iomem *); int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd); + bool (*tso_csum)(struct rtl8169_private *, struct sk_buff *, u32 *); struct { DECLARE_BITMAP(flags, RTL_FLAG_MAX); @@ -5941,16 +5916,36 @@ static bool rtl_test_hw_pad_bug(struct rtl8169_private *tp, struct sk_buff *skb) return skb->len < ETH_ZLEN && tp->mac_version == RTL_GIGA_MAC_VER_34; } -static inline bool rtl8169_tso_csum(struct rtl8169_private *tp, - struct sk_buff *skb, u32 *opts) +static bool rtl8169_tso_csum_v1(struct rtl8169_private *tp, + struct sk_buff *skb, u32 *opts) { - const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version; u32 mss = skb_shinfo(skb)->gso_size; - int offset = info->opts_offset; if (mss) { opts[0] |= TD_LSO; - opts[offset] |= min(mss, TD_MSS_MAX) << info->mss_shift; + opts[0] |= min(mss, TD_MSS_MAX) << TD0_MSS_SHIFT; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + const struct iphdr *ip = ip_hdr(skb); + + if (ip->protocol == IPPROTO_TCP) + opts[0] |= TD0_IP_CS | TD0_TCP_CS; + else if (ip->protocol == IPPROTO_UDP) + opts[0] |= TD0_IP_CS | TD0_UDP_CS; + else + WARN_ON_ONCE(1); + } + + return true; +} + +static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp, + struct sk_buff *skb, u32 *opts) +{ + u32 mss = skb_shinfo(skb)->gso_size; + + if (mss) { + opts[0] |= TD_LSO; + opts[1] |= min(mss, TD_MSS_MAX) << TD1_MSS_SHIFT; } else if (skb->ip_summed == CHECKSUM_PARTIAL) { const struct iphdr *ip = ip_hdr(skb); @@ -5958,15 +5953,16 @@ static inline bool rtl8169_tso_csum(struct rtl8169_private *tp, return skb_checksum_help(skb) == 0 && rtl_skb_pad(skb); if (ip->protocol == IPPROTO_TCP) - opts[offset] |= info->checksum.tcp; + opts[1] |= TD1_IP_CS | TD1_TCP_CS; else if (ip->protocol == IPPROTO_UDP) - opts[offset] |= info->checksum.udp; + opts[1] |= TD1_IP_CS | TD1_UDP_CS; else WARN_ON_ONCE(1); } else { if (unlikely(rtl_test_hw_pad_bug(tp, skb))) return rtl_skb_pad(skb); } + return true; } @@ -5994,7 +5990,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb)); opts[0] = DescOwn; - if (!rtl8169_tso_csum(tp, skb, opts)) + if (!tp->tso_csum(tp, skb, opts)) goto err_update_stats; len = skb_headlen(skb); @@ -7145,6 +7141,13 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* 8110SCd requires hardware Rx VLAN - disallow toggling */ dev->hw_features &= ~NETIF_F_HW_VLAN_CTAG_RX; + if (tp->txd_version == RTL_TD_0) + tp->tso_csum = rtl8169_tso_csum_v1; + else if (tp->txd_version == RTL_TD_1) + tp->tso_csum = rtl8169_tso_csum_v2; + else + WARN_ON_ONCE(1); + dev->hw_features |= NETIF_F_RXALL; dev->hw_features |= NETIF_F_RXFCS; -- cgit v1.2.3 From bdfa4ed68187c436caee8adc1ef1d4b0d75ca0ae Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 11 Jul 2014 16:25:57 +0800 Subject: r8169: use Giant Send Replace large send with giant send for TSO for RTL8111C and later ICs. The large send setting of the RTL8111DP is different from the other chips. However, the giant send setting is the same for all the chips which support it. Use the giant send to synchronize the settings. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 6b7e21a8da57..e5a0bdbfbb2b 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -626,6 +626,10 @@ enum rtl_tx_desc_bit_0 { /* 8102e, 8168c and beyond. */ enum rtl_tx_desc_bit_1 { + /* First doubleword. */ + TD1_GTSENV4 = (1 << 26), /* Giant Send for IPv4 */ +#define GTTCPHO_SHIFT 18 + /* Second doubleword. */ #define TD1_MSS_SHIFT 18 /* MSS position (11 bits) */ TD1_IP_CS = (1 << 29), /* Calculate IP checksum */ @@ -5941,10 +5945,12 @@ static bool rtl8169_tso_csum_v1(struct rtl8169_private *tp, static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp, struct sk_buff *skb, u32 *opts) { + u32 transport_offset = (u32)skb_transport_offset(skb); u32 mss = skb_shinfo(skb)->gso_size; if (mss) { - opts[0] |= TD_LSO; + opts[0] |= TD1_GTSENV4; + opts[0] |= transport_offset << GTTCPHO_SHIFT; opts[1] |= min(mss, TD_MSS_MAX) << TD1_MSS_SHIFT; } else if (skb->ip_summed == CHECKSUM_PARTIAL) { const struct iphdr *ip = ip_hdr(skb); -- cgit v1.2.3 From e974604b453e87f8d864371786375d3d511fdf56 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 11 Jul 2014 16:25:58 +0800 Subject: r8169: support IPv6 Support the IPv6 hw checksum for RTL8111C and later chips. Note that the hw has the limitation for the transport offset. The checksum must be calculated by sw, when the transport offset is out of the range which the hw accepts. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 157 ++++++++++++++++++++++++++++++++--- 1 file changed, 145 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index e5a0bdbfbb2b..51c78ce27b37 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -628,11 +630,16 @@ enum rtl_tx_desc_bit_0 { enum rtl_tx_desc_bit_1 { /* First doubleword. */ TD1_GTSENV4 = (1 << 26), /* Giant Send for IPv4 */ + TD1_GTSENV6 = (1 << 25), /* Giant Send for IPv6 */ #define GTTCPHO_SHIFT 18 +#define GTTCPHO_MAX 0x7fU /* Second doubleword. */ +#define TCPHO_SHIFT 18 +#define TCPHO_MAX 0x3ffU #define TD1_MSS_SHIFT 18 /* MSS position (11 bits) */ - TD1_IP_CS = (1 << 29), /* Calculate IP checksum */ + TD1_IPv6_CS = (1 << 28), /* Calculate IPv6 checksum */ + TD1_IPv4_CS = (1 << 29), /* Calculate IPv4 checksum */ TD1_TCP_CS = (1 << 30), /* Calculate TCP/IP checksum */ TD1_UDP_CS = (1 << 31), /* Calculate UDP/IP checksum */ }; @@ -5920,6 +5927,82 @@ static bool rtl_test_hw_pad_bug(struct rtl8169_private *tp, struct sk_buff *skb) return skb->len < ETH_ZLEN && tp->mac_version == RTL_GIGA_MAC_VER_34; } +static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + struct net_device *dev); +/* r8169_csum_workaround() + * The hw limites the value the transport offset. When the offset is out of the + * range, calculate the checksum by sw. + */ +static void r8169_csum_workaround(struct rtl8169_private *tp, + struct sk_buff *skb) +{ + if (skb_shinfo(skb)->gso_size) { + netdev_features_t features = tp->dev->features; + struct sk_buff *segs, *nskb; + + features &= ~(NETIF_F_SG | NETIF_F_IPV6_CSUM | NETIF_F_TSO6); + segs = skb_gso_segment(skb, features); + if (IS_ERR(segs) || !segs) + goto drop; + + do { + nskb = segs; + segs = segs->next; + nskb->next = NULL; + rtl8169_start_xmit(nskb, tp->dev); + } while (segs); + + dev_kfree_skb(skb); + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (skb_checksum_help(skb) < 0) + goto drop; + + rtl8169_start_xmit(skb, tp->dev); + } else { + struct net_device_stats *stats; + +drop: + stats = &tp->dev->stats; + stats->tx_dropped++; + dev_kfree_skb(skb); + } +} + +/* msdn_giant_send_check() + * According to the document of microsoft, the TCP Pseudo Header excludes the + * packet length for IPv6 TCP large packets. + */ +static int msdn_giant_send_check(struct sk_buff *skb) +{ + const struct ipv6hdr *ipv6h; + struct tcphdr *th; + int ret; + + ret = skb_cow_head(skb, 0); + if (ret) + return ret; + + ipv6h = ipv6_hdr(skb); + th = tcp_hdr(skb); + + th->check = 0; + th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0); + + return ret; +} + +static inline __be16 get_protocol(struct sk_buff *skb) +{ + __be16 protocol; + + if (skb->protocol == htons(ETH_P_8021Q)) + protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; + else + protocol = skb->protocol; + + return protocol; +} + static bool rtl8169_tso_csum_v1(struct rtl8169_private *tp, struct sk_buff *skb, u32 *opts) { @@ -5949,21 +6032,69 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp, u32 mss = skb_shinfo(skb)->gso_size; if (mss) { - opts[0] |= TD1_GTSENV4; + if (transport_offset > GTTCPHO_MAX) { + netif_warn(tp, tx_err, tp->dev, + "Invalid transport offset 0x%x for TSO\n", + transport_offset); + return false; + } + + switch (get_protocol(skb)) { + case htons(ETH_P_IP): + opts[0] |= TD1_GTSENV4; + break; + + case htons(ETH_P_IPV6): + if (msdn_giant_send_check(skb)) + return false; + + opts[0] |= TD1_GTSENV6; + break; + + default: + WARN_ON_ONCE(1); + break; + } + opts[0] |= transport_offset << GTTCPHO_SHIFT; opts[1] |= min(mss, TD_MSS_MAX) << TD1_MSS_SHIFT; } else if (skb->ip_summed == CHECKSUM_PARTIAL) { - const struct iphdr *ip = ip_hdr(skb); + u8 ip_protocol; if (unlikely(rtl_test_hw_pad_bug(tp, skb))) return skb_checksum_help(skb) == 0 && rtl_skb_pad(skb); - if (ip->protocol == IPPROTO_TCP) - opts[1] |= TD1_IP_CS | TD1_TCP_CS; - else if (ip->protocol == IPPROTO_UDP) - opts[1] |= TD1_IP_CS | TD1_UDP_CS; + if (transport_offset > TCPHO_MAX) { + netif_warn(tp, tx_err, tp->dev, + "Invalid transport offset 0x%x\n", + transport_offset); + return false; + } + + switch (get_protocol(skb)) { + case htons(ETH_P_IP): + opts[1] |= TD1_IPv4_CS; + ip_protocol = ip_hdr(skb)->protocol; + break; + + case htons(ETH_P_IPV6): + opts[1] |= TD1_IPv6_CS; + ip_protocol = ipv6_hdr(skb)->nexthdr; + break; + + default: + ip_protocol = IPPROTO_RAW; + break; + } + + if (ip_protocol == IPPROTO_TCP) + opts[1] |= TD1_TCP_CS; + else if (ip_protocol == IPPROTO_UDP) + opts[1] |= TD1_UDP_CS; else WARN_ON_ONCE(1); + + opts[1] |= transport_offset << TCPHO_SHIFT; } else { if (unlikely(rtl_test_hw_pad_bug(tp, skb))) return rtl_skb_pad(skb); @@ -5996,8 +6127,10 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb)); opts[0] = DescOwn; - if (!tp->tso_csum(tp, skb, opts)) - goto err_update_stats; + if (!tp->tso_csum(tp, skb, opts)) { + r8169_csum_workaround(tp, skb); + return NETDEV_TX_OK; + } len = skb_headlen(skb); mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE); @@ -6062,7 +6195,6 @@ err_dma_1: rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd); err_dma_0: dev_kfree_skb_any(skb); -err_update_stats: dev->stats.tx_dropped++; return NETDEV_TX_OK; @@ -7149,9 +7281,10 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (tp->txd_version == RTL_TD_0) tp->tso_csum = rtl8169_tso_csum_v1; - else if (tp->txd_version == RTL_TD_1) + else if (tp->txd_version == RTL_TD_1) { tp->tso_csum = rtl8169_tso_csum_v2; - else + dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + } else WARN_ON_ONCE(1); dev->hw_features |= NETIF_F_RXALL; -- cgit v1.2.3 From 279f64b7a771d84cbdea51ac2f794becfb06bcd4 Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Fri, 11 Jul 2014 18:21:12 +0200 Subject: net/hsr: Remove left-over never-true conditional code. MacAddressB is an array (unsigned char MacAddressB[ETH_ALEN]) and is allocated as a part of *node_dst (which is a struct hsr_node). So the condition is always false. Detected by Dan Carpenter. Signed-off-by: Arvid Brodin Signed-off-by: David S. Miller --- net/hsr/hsr_framereg.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index c709c13842cb..bace124d14ef 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c @@ -290,10 +290,6 @@ void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb, } if (port->type != node_dst->AddrB_port) return; - if (!node_dst->MacAddressB) { - WARN_ONCE(1, "%s: No MacAddressB\n", __func__); - return; - } ether_addr_copy(eth_hdr(skb)->h_dest, node_dst->MacAddressB); } -- cgit v1.2.3 From bc91b0f07ada5535427373a4e2050877bcc12218 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 11 Jul 2014 21:10:18 +0200 Subject: ipv6: addrconf: implement address generation modes This patch introduces a possibility for userspace to set various (so far two) modes of generating addresses. This is useful for example for NetworkManager because it can set the mode to NONE and take care of link local addresses itself. That allow it to have the interface up, monitoring carrier but still don't have any addresses on it. One more use-case by Dan Williams: WWAN devices often have their LL address provided by the firmware of the device, which sometimes refuses to respond to incorrect LL addresses when doing DHCPv6 or IPv6 ND. The kernel cannot generate the correct LL address for two reasons: 1) WWAN pseudo-ethernet interfaces often construct a fake MAC address, or read a meaningless MAC address from the firmware. Thus the EUI64 and the IPv6LL address the kernel assigns will be wrong. The real LL address is often retrieved from the firmware with AT or proprietary commands. 2) WWAN PPP interfaces receive their LL address from IPV6CP, not from kernel assignments. Only after IPV6CP has completed do we know the LL address of the PPP interface and its peer. But the kernel has already assigned an incorrect LL address to the interface. So being able to suppress the kernel LL address generation and assign the one retrieved from the firmware is less complicated and more robust. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/if_inet6.h | 1 + include/uapi/linux/if_link.h | 6 +++++ net/ipv6/addrconf.c | 56 ++++++++++++++++++++++++++++++-------------- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index b4956a5fcc3f..d07b1a64b4e7 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -205,6 +205,7 @@ struct inet6_dev { struct timer_list rs_timer; __u8 rs_probes; + __u8 addr_gen_mode; unsigned long tstamp; /* ipv6InterfaceTable update timestamp */ struct rcu_head rcu; }; diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index b38534895db5..ff957604a721 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -204,11 +204,17 @@ enum { IFLA_INET6_CACHEINFO, /* time values and max reasm size */ IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */ IFLA_INET6_TOKEN, /* device token */ + IFLA_INET6_ADDR_GEN_MODE, /* implicit address generator mode */ __IFLA_INET6_MAX }; #define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) +enum in6_addr_gen_mode { + IN6_ADDR_GEN_MODE_EUI64, + IN6_ADDR_GEN_MODE_NONE, +}; + enum { BRIDGE_MODE_UNSPEC, BRIDGE_MODE_HAIRPIN, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 358edd2272ac..4c03c2843094 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2730,9 +2730,25 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr } } +static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route) +{ + if (idev->addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64) { + struct in6_addr addr; + + ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); + /* addrconf_add_linklocal also adds a prefix_route and we + * only need to care about prefix routes if ipv6_generate_eui64 + * couldn't generate one. + */ + if (ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) == 0) + addrconf_add_linklocal(idev, &addr); + else if (prefix_route) + addrconf_prefix_route(&addr, 64, idev->dev, 0, 0); + } +} + static void addrconf_dev_config(struct net_device *dev) { - struct in6_addr addr; struct inet6_dev *idev; ASSERT_RTNL(); @@ -2753,11 +2769,7 @@ static void addrconf_dev_config(struct net_device *dev) if (IS_ERR(idev)) return; - memset(&addr, 0, sizeof(struct in6_addr)); - addr.s6_addr32[0] = htonl(0xFE800000); - - if (ipv6_generate_eui64(addr.s6_addr + 8, dev) == 0) - addrconf_add_linklocal(idev, &addr); + addrconf_addr_gen(idev, false); } #if IS_ENABLED(CONFIG_IPV6_SIT) @@ -2779,11 +2791,7 @@ static void addrconf_sit_config(struct net_device *dev) } if (dev->priv_flags & IFF_ISATAP) { - struct in6_addr addr; - - ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); - if (!ipv6_generate_eui64(addr.s6_addr + 8, dev)) - addrconf_add_linklocal(idev, &addr); + addrconf_addr_gen(idev, false); return; } @@ -2798,7 +2806,6 @@ static void addrconf_sit_config(struct net_device *dev) static void addrconf_gre_config(struct net_device *dev) { struct inet6_dev *idev; - struct in6_addr addr; ASSERT_RTNL(); @@ -2807,11 +2814,7 @@ static void addrconf_gre_config(struct net_device *dev) return; } - ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); - if (!ipv6_generate_eui64(addr.s6_addr + 8, dev)) - addrconf_add_linklocal(idev, &addr); - else - addrconf_prefix_route(&addr, 64, dev, 0, 0); + addrconf_addr_gen(idev, true); } #endif @@ -4423,6 +4426,10 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev) nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr)); if (nla == NULL) goto nla_put_failure; + + if (nla_put_u8(skb, IFLA_INET6_ADDR_GEN_MODE, idev->addr_gen_mode)) + goto nla_put_failure; + read_lock_bh(&idev->lock); memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla)); read_unlock_bh(&idev->lock); @@ -4527,8 +4534,21 @@ static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla) if (nla_parse_nested(tb, IFLA_INET6_MAX, nla, NULL) < 0) BUG(); - if (tb[IFLA_INET6_TOKEN]) + if (tb[IFLA_INET6_TOKEN]) { err = inet6_set_iftoken(idev, nla_data(tb[IFLA_INET6_TOKEN])); + if (err) + return err; + } + + if (tb[IFLA_INET6_ADDR_GEN_MODE]) { + u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE]); + + if (mode != IN6_ADDR_GEN_MODE_EUI64 && + mode != IN6_ADDR_GEN_MODE_NONE) + return -EINVAL; + idev->addr_gen_mode = mode; + err = 0; + } return err; } -- cgit v1.2.3 From 8242fc33925c8da802b651a702a902a204142e22 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sat, 12 Jul 2014 01:55:38 +0530 Subject: net: ipv6: Use BUG_ON The semantic patch that makes the transformation is as follows: // @@ expression e; @@ -if (e) BUG(); +BUG_ON(e); // Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- net/ipv6/raw.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index b2dc60b0c764..dee80fb1aa86 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -588,8 +588,7 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, } offset += skb_transport_offset(skb); - if (skb_copy_bits(skb, offset, &csum, 2)) - BUG(); + BUG_ON(skb_copy_bits(skb, offset, &csum, 2)); /* in case cksum was not initialized */ if (unlikely(csum)) @@ -601,8 +600,7 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, if (csum == 0 && fl6->flowi6_proto == IPPROTO_UDP) csum = CSUM_MANGLED_0; - if (skb_store_bits(skb, offset, &csum, 2)) - BUG(); + BUG_ON(skb_store_bits(skb, offset, &csum, 2)); send: err = ip6_push_pending_frames(sk); -- cgit v1.2.3 From e3f0b86b996d86940357e5ca9788771618d731f1 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sat, 12 Jul 2014 01:57:17 +0530 Subject: ipv6: Use BUG_ON The semantic patch that makes this transformation is as follows: // @@ expression e; @@ -if (e) BUG(); +BUG_ON(e); // Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- net/ipv6/ip6_output.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index fa83bdd4c3dd..9b395c639a07 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -801,8 +801,8 @@ slow_path: /* * Copy a block of the IP datagram. */ - if (skb_copy_bits(skb, ptr, skb_transport_header(frag), len)) - BUG(); + BUG_ON(skb_copy_bits(skb, ptr, skb_transport_header(frag), + len)); left -= len; fh->frag_off = htons(offset); -- cgit v1.2.3 From 2c6bed7cfcd3f594ed9e4d6919fa2ebea2243d19 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 11 Jul 2014 10:24:18 +0200 Subject: 6lowpan: introduce new net/6lowpan directory This patch moves generic code which is used by bluetooth and ieee802154 6lowpan to a new net/6lowpan directory. This directory contains generic 6LoWPAN code which is shared between bluetooth and ieee802154 MAC-Layer. This is the IPHC - "IPv6 Header Compression" format at the moment. Which is described by RFC 6282 [0]. The BLTE 6LoWPAN draft describes that the IPHC is the same format like IEEE 802.15.4, see [1]. Futuremore we can put more code into this directory which is shared between BLTE and IEEE 802.15.4 6LoWPAN like RFC 6775 or the routing protocol RPL RFC 6550. To avoid naming conflicts I renamed 6lowpan-y to ieee802154_6lowpan-y in net/ieee802154/Makefile. [0] http://tools.ietf.org/html/rfc6282 [1] http://tools.ietf.org/html/draft-ietf-6lowpan-btle-12#section-3.2 [2] http://tools.ietf.org/html/rfc6775 [3] http://tools.ietf.org/html/rfc6550 Signed-off-by: Alexander Aring Acked-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- net/6lowpan/Kconfig | 6 + net/6lowpan/Makefile | 3 + net/6lowpan/iphc.c | 801 ++++++++++++++++++++++++++++++++++++++++++ net/Kconfig | 1 + net/Makefile | 3 +- net/bluetooth/Kconfig | 3 +- net/ieee802154/6lowpan_iphc.c | 801 ------------------------------------------ net/ieee802154/Kconfig | 9 +- net/ieee802154/Makefile | 5 +- 9 files changed, 817 insertions(+), 815 deletions(-) create mode 100644 net/6lowpan/Kconfig create mode 100644 net/6lowpan/Makefile create mode 100644 net/6lowpan/iphc.c delete mode 100644 net/ieee802154/6lowpan_iphc.c diff --git a/net/6lowpan/Kconfig b/net/6lowpan/Kconfig new file mode 100644 index 000000000000..028a5c6d1f61 --- /dev/null +++ b/net/6lowpan/Kconfig @@ -0,0 +1,6 @@ +config 6LOWPAN + bool "6LoWPAN Support" + depends on IPV6 + ---help--- + This enables IPv6 over Low power Wireless Personal Area Network - + "6LoWPAN" which is supported by IEEE 802.15.4 or Bluetooth stacks. diff --git a/net/6lowpan/Makefile b/net/6lowpan/Makefile new file mode 100644 index 000000000000..415886bb456a --- /dev/null +++ b/net/6lowpan/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_6LOWPAN) := 6lowpan.o + +6lowpan-y := iphc.o diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c new file mode 100644 index 000000000000..211b5686d719 --- /dev/null +++ b/net/6lowpan/iphc.c @@ -0,0 +1,801 @@ +/* + * Copyright 2011, Siemens AG + * written by Alexander Smirnov + */ + +/* + * Based on patches from Jon Smirl + * Copyright (c) 2011 Jon Smirl + * + * 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. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* Jon's code is based on 6lowpan implementation for Contiki which is: + * Copyright (c) 2008, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Uncompress address function for source and + * destination address(non-multicast). + * + * address_mode is sam value or dam value. + */ +static int uncompress_addr(struct sk_buff *skb, + struct in6_addr *ipaddr, const u8 address_mode, + const u8 *lladdr, const u8 addr_type, + const u8 addr_len) +{ + bool fail; + + switch (address_mode) { + case LOWPAN_IPHC_ADDR_00: + /* for global link addresses */ + fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); + break; + case LOWPAN_IPHC_ADDR_01: + /* fe:80::XXXX:XXXX:XXXX:XXXX */ + ipaddr->s6_addr[0] = 0xFE; + ipaddr->s6_addr[1] = 0x80; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8); + break; + case LOWPAN_IPHC_ADDR_02: + /* fe:80::ff:fe00:XXXX */ + ipaddr->s6_addr[0] = 0xFE; + ipaddr->s6_addr[1] = 0x80; + ipaddr->s6_addr[11] = 0xFF; + ipaddr->s6_addr[12] = 0xFE; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2); + break; + case LOWPAN_IPHC_ADDR_03: + fail = false; + switch (addr_type) { + case IEEE802154_ADDR_LONG: + /* fe:80::XXXX:XXXX:XXXX:XXXX + * \_________________/ + * hwaddr + */ + ipaddr->s6_addr[0] = 0xFE; + ipaddr->s6_addr[1] = 0x80; + memcpy(&ipaddr->s6_addr[8], lladdr, addr_len); + /* second bit-flip (Universe/Local) + * is done according RFC2464 + */ + ipaddr->s6_addr[8] ^= 0x02; + break; + case IEEE802154_ADDR_SHORT: + /* fe:80::ff:fe00:XXXX + * \__/ + * short_addr + * + * Universe/Local bit is zero. + */ + ipaddr->s6_addr[0] = 0xFE; + ipaddr->s6_addr[1] = 0x80; + ipaddr->s6_addr[11] = 0xFF; + ipaddr->s6_addr[12] = 0xFE; + ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr)); + break; + default: + pr_debug("Invalid addr_type set\n"); + return -EINVAL; + } + break; + default: + pr_debug("Invalid address mode value: 0x%x\n", address_mode); + return -EINVAL; + } + + if (fail) { + pr_debug("Failed to fetch skb data\n"); + return -EIO; + } + + raw_dump_inline(NULL, "Reconstructed ipv6 addr is", + ipaddr->s6_addr, 16); + + return 0; +} + +/* + * Uncompress address function for source context + * based address(non-multicast). + */ +static int uncompress_context_based_src_addr(struct sk_buff *skb, + struct in6_addr *ipaddr, + const u8 sam) +{ + switch (sam) { + case LOWPAN_IPHC_ADDR_00: + /* unspec address :: + * Do nothing, address is already :: + */ + break; + case LOWPAN_IPHC_ADDR_01: + /* TODO */ + case LOWPAN_IPHC_ADDR_02: + /* TODO */ + case LOWPAN_IPHC_ADDR_03: + /* TODO */ + netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam); + return -EINVAL; + default: + pr_debug("Invalid sam value: 0x%x\n", sam); + return -EINVAL; + } + + raw_dump_inline(NULL, + "Reconstructed context based ipv6 src addr is", + ipaddr->s6_addr, 16); + + return 0; +} + +static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, + struct net_device *dev, skb_delivery_cb deliver_skb) +{ + struct sk_buff *new; + int stat; + + new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), + GFP_ATOMIC); + kfree_skb(skb); + + if (!new) + return -ENOMEM; + + skb_push(new, sizeof(struct ipv6hdr)); + skb_reset_network_header(new); + skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr)); + + new->protocol = htons(ETH_P_IPV6); + new->pkt_type = PACKET_HOST; + new->dev = dev; + + raw_dump_table(__func__, "raw skb data dump before receiving", + new->data, new->len); + + stat = deliver_skb(new, dev); + + kfree_skb(new); + + return stat; +} + +/* Uncompress function for multicast destination address, + * when M bit is set. + */ +static int +lowpan_uncompress_multicast_daddr(struct sk_buff *skb, + struct in6_addr *ipaddr, + const u8 dam) +{ + bool fail; + + switch (dam) { + case LOWPAN_IPHC_DAM_00: + /* 00: 128 bits. The full address + * is carried in-line. + */ + fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); + break; + case LOWPAN_IPHC_DAM_01: + /* 01: 48 bits. The address takes + * the form ffXX::00XX:XXXX:XXXX. + */ + ipaddr->s6_addr[0] = 0xFF; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); + fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5); + break; + case LOWPAN_IPHC_DAM_10: + /* 10: 32 bits. The address takes + * the form ffXX::00XX:XXXX. + */ + ipaddr->s6_addr[0] = 0xFF; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); + fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3); + break; + case LOWPAN_IPHC_DAM_11: + /* 11: 8 bits. The address takes + * the form ff02::00XX. + */ + ipaddr->s6_addr[0] = 0xFF; + ipaddr->s6_addr[1] = 0x02; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1); + break; + default: + pr_debug("DAM value has a wrong value: 0x%x\n", dam); + return -EINVAL; + } + + if (fail) { + pr_debug("Failed to fetch skb data\n"); + return -EIO; + } + + raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", + ipaddr->s6_addr, 16); + + return 0; +} + +static int +uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) +{ + bool fail; + u8 tmp = 0, val = 0; + + if (!uh) + goto err; + + fail = lowpan_fetch_skb(skb, &tmp, 1); + + if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { + pr_debug("UDP header uncompression\n"); + switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { + case LOWPAN_NHC_UDP_CS_P_00: + fail |= lowpan_fetch_skb(skb, &uh->source, 2); + fail |= lowpan_fetch_skb(skb, &uh->dest, 2); + break; + case LOWPAN_NHC_UDP_CS_P_01: + fail |= lowpan_fetch_skb(skb, &uh->source, 2); + fail |= lowpan_fetch_skb(skb, &val, 1); + uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); + break; + case LOWPAN_NHC_UDP_CS_P_10: + fail |= lowpan_fetch_skb(skb, &val, 1); + uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); + fail |= lowpan_fetch_skb(skb, &uh->dest, 2); + break; + case LOWPAN_NHC_UDP_CS_P_11: + fail |= lowpan_fetch_skb(skb, &val, 1); + uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT + + (val >> 4)); + uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT + + (val & 0x0f)); + break; + default: + pr_debug("ERROR: unknown UDP format\n"); + goto err; + break; + } + + pr_debug("uncompressed UDP ports: src = %d, dst = %d\n", + ntohs(uh->source), ntohs(uh->dest)); + + /* checksum */ + if (tmp & LOWPAN_NHC_UDP_CS_C) { + pr_debug_ratelimited("checksum elided currently not supported\n"); + goto err; + } else { + fail |= lowpan_fetch_skb(skb, &uh->check, 2); + } + + /* + * UDP lenght needs to be infered from the lower layers + * here, we obtain the hint from the remaining size of the + * frame + */ + uh->len = htons(skb->len + sizeof(struct udphdr)); + pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len)); + } else { + pr_debug("ERROR: unsupported NH format\n"); + goto err; + } + + if (fail) + goto err; + + return 0; +err: + return -EINVAL; +} + +/* TTL uncompression values */ +static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; + +int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, + const u8 *saddr, const u8 saddr_type, const u8 saddr_len, + const u8 *daddr, const u8 daddr_type, const u8 daddr_len, + u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) +{ + struct ipv6hdr hdr = {}; + u8 tmp, num_context = 0; + int err; + + raw_dump_table(__func__, "raw skb data dump uncompressed", + skb->data, skb->len); + + /* another if the CID flag is set */ + if (iphc1 & LOWPAN_IPHC_CID) { + pr_debug("CID flag is set, increase header with one\n"); + if (lowpan_fetch_skb_u8(skb, &num_context)) + goto drop; + } + + hdr.version = 6; + + /* Traffic Class and Flow Label */ + switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) { + /* + * Traffic Class and FLow Label carried in-line + * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) + */ + case 0: /* 00b */ + if (lowpan_fetch_skb_u8(skb, &tmp)) + goto drop; + + memcpy(&hdr.flow_lbl, &skb->data[0], 3); + skb_pull(skb, 3); + hdr.priority = ((tmp >> 2) & 0x0f); + hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | + (hdr.flow_lbl[0] & 0x0f); + break; + /* + * Traffic class carried in-line + * ECN + DSCP (1 byte), Flow Label is elided + */ + case 2: /* 10b */ + if (lowpan_fetch_skb_u8(skb, &tmp)) + goto drop; + + hdr.priority = ((tmp >> 2) & 0x0f); + hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); + break; + /* + * Flow Label carried in-line + * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided + */ + case 1: /* 01b */ + if (lowpan_fetch_skb_u8(skb, &tmp)) + goto drop; + + hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); + memcpy(&hdr.flow_lbl[1], &skb->data[0], 2); + skb_pull(skb, 2); + break; + /* Traffic Class and Flow Label are elided */ + case 3: /* 11b */ + break; + default: + break; + } + + /* Next Header */ + if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { + /* Next header is carried inline */ + if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr))) + goto drop; + + pr_debug("NH flag is set, next header carried inline: %02x\n", + hdr.nexthdr); + } + + /* Hop Limit */ + if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) + hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; + else { + if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit))) + goto drop; + } + + /* Extract SAM to the tmp variable */ + tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03; + + if (iphc1 & LOWPAN_IPHC_SAC) { + /* Source address context based uncompression */ + pr_debug("SAC bit is set. Handle context based source address.\n"); + err = uncompress_context_based_src_addr( + skb, &hdr.saddr, tmp); + } else { + /* Source address uncompression */ + pr_debug("source address stateless compression\n"); + err = uncompress_addr(skb, &hdr.saddr, tmp, saddr, + saddr_type, saddr_len); + } + + /* Check on error of previous branch */ + if (err) + goto drop; + + /* Extract DAM to the tmp variable */ + tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03; + + /* check for Multicast Compression */ + if (iphc1 & LOWPAN_IPHC_M) { + if (iphc1 & LOWPAN_IPHC_DAC) { + pr_debug("dest: context-based mcast compression\n"); + /* TODO: implement this */ + } else { + err = lowpan_uncompress_multicast_daddr( + skb, &hdr.daddr, tmp); + if (err) + goto drop; + } + } else { + err = uncompress_addr(skb, &hdr.daddr, tmp, daddr, + daddr_type, daddr_len); + pr_debug("dest: stateless compression mode %d dest %pI6c\n", + tmp, &hdr.daddr); + if (err) + goto drop; + } + + /* UDP data uncompression */ + if (iphc0 & LOWPAN_IPHC_NH_C) { + struct udphdr uh; + struct sk_buff *new; + if (uncompress_udp_header(skb, &uh)) + goto drop; + + /* + * replace the compressed UDP head by the uncompressed UDP + * header + */ + new = skb_copy_expand(skb, sizeof(struct udphdr), + skb_tailroom(skb), GFP_ATOMIC); + kfree_skb(skb); + + if (!new) + return -ENOMEM; + + skb = new; + + skb_push(skb, sizeof(struct udphdr)); + skb_reset_transport_header(skb); + skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); + + raw_dump_table(__func__, "raw UDP header dump", + (u8 *)&uh, sizeof(uh)); + + hdr.nexthdr = UIP_PROTO_UDP; + } + + hdr.payload_len = htons(skb->len); + + pr_debug("skb headroom size = %d, data length = %d\n", + skb_headroom(skb), skb->len); + + pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t" + "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", + hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, + hdr.hop_limit, &hdr.daddr); + + raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, + sizeof(hdr)); + + return skb_deliver(skb, &hdr, dev, deliver_skb); + +drop: + kfree_skb(skb); + return -EINVAL; +} +EXPORT_SYMBOL_GPL(lowpan_process_data); + +static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, + const struct in6_addr *ipaddr, + const unsigned char *lladdr) +{ + u8 val = 0; + + if (is_addr_mac_addr_based(ipaddr, lladdr)) { + val = 3; /* 0-bits */ + pr_debug("address compression 0 bits\n"); + } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { + /* compress IID to 16 bits xxxx::XXXX */ + memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2); + *hc06_ptr += 2; + val = 2; /* 16-bits */ + raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", + *hc06_ptr - 2, 2); + } else { + /* do not compress IID => xxxx::IID */ + memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8); + *hc06_ptr += 8; + val = 1; /* 64-bits */ + raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", + *hc06_ptr - 8, 8); + } + + return rol8(val, shift); +} + +static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) +{ + struct udphdr *uh = udp_hdr(skb); + u8 tmp; + + if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) == + LOWPAN_NHC_UDP_4BIT_PORT) && + ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) == + LOWPAN_NHC_UDP_4BIT_PORT)) { + pr_debug("UDP header: both ports compression to 4 bits\n"); + /* compression value */ + tmp = LOWPAN_NHC_UDP_CS_P_11; + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + /* source and destination port */ + tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT + + ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4); + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) == + LOWPAN_NHC_UDP_8BIT_PORT) { + pr_debug("UDP header: remove 8 bits of dest\n"); + /* compression value */ + tmp = LOWPAN_NHC_UDP_CS_P_01; + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + /* source port */ + lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); + /* destination port */ + tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT; + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) == + LOWPAN_NHC_UDP_8BIT_PORT) { + pr_debug("UDP header: remove 8 bits of source\n"); + /* compression value */ + tmp = LOWPAN_NHC_UDP_CS_P_10; + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + /* source port */ + tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT; + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + /* destination port */ + lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); + } else { + pr_debug("UDP header: can't compress\n"); + /* compression value */ + tmp = LOWPAN_NHC_UDP_CS_P_00; + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + /* source port */ + lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); + /* destination port */ + lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); + } + + /* checksum is always inline */ + lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check)); + + /* skip the UDP header */ + skb_pull(skb, sizeof(struct udphdr)); +} + +int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *_daddr, + const void *_saddr, unsigned int len) +{ + u8 tmp, iphc0, iphc1, *hc06_ptr; + struct ipv6hdr *hdr; + u8 head[100] = {}; + + if (type != ETH_P_IPV6) + return -EINVAL; + + hdr = ipv6_hdr(skb); + hc06_ptr = head + 2; + + pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" + "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", + hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, + hdr->hop_limit, &hdr->daddr); + + raw_dump_table(__func__, "raw skb network header dump", + skb_network_header(skb), sizeof(struct ipv6hdr)); + + /* + * As we copy some bit-length fields, in the IPHC encoding bytes, + * we sometimes use |= + * If the field is 0, and the current bit value in memory is 1, + * this does not work. We therefore reset the IPHC encoding here + */ + iphc0 = LOWPAN_DISPATCH_IPHC; + iphc1 = 0; + + /* TODO: context lookup */ + + raw_dump_inline(__func__, "saddr", + (unsigned char *)_saddr, IEEE802154_ADDR_LEN); + raw_dump_inline(__func__, "daddr", + (unsigned char *)_daddr, IEEE802154_ADDR_LEN); + + raw_dump_table(__func__, + "sending raw skb network uncompressed packet", + skb->data, skb->len); + + /* + * Traffic class, flow label + * If flow label is 0, compress it. If traffic class is 0, compress it + * We have to process both in the same time as the offset of traffic + * class depends on the presence of version and flow label + */ + + /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */ + tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4); + tmp = ((tmp & 0x03) << 6) | (tmp >> 2); + + if (((hdr->flow_lbl[0] & 0x0F) == 0) && + (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { + /* flow label can be compressed */ + iphc0 |= LOWPAN_IPHC_FL_C; + if ((hdr->priority == 0) && + ((hdr->flow_lbl[0] & 0xF0) == 0)) { + /* compress (elide) all */ + iphc0 |= LOWPAN_IPHC_TC_C; + } else { + /* compress only the flow label */ + *hc06_ptr = tmp; + hc06_ptr += 1; + } + } else { + /* Flow label cannot be compressed */ + if ((hdr->priority == 0) && + ((hdr->flow_lbl[0] & 0xF0) == 0)) { + /* compress only traffic class */ + iphc0 |= LOWPAN_IPHC_TC_C; + *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); + memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2); + hc06_ptr += 3; + } else { + /* compress nothing */ + memcpy(hc06_ptr, hdr, 4); + /* replace the top byte with new ECN | DSCP format */ + *hc06_ptr = tmp; + hc06_ptr += 4; + } + } + + /* NOTE: payload length is always compressed */ + + /* Next Header is compress if UDP */ + if (hdr->nexthdr == UIP_PROTO_UDP) + iphc0 |= LOWPAN_IPHC_NH_C; + + if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { + *hc06_ptr = hdr->nexthdr; + hc06_ptr += 1; + } + + /* + * Hop limit + * if 1: compress, encoding is 01 + * if 64: compress, encoding is 10 + * if 255: compress, encoding is 11 + * else do not compress + */ + switch (hdr->hop_limit) { + case 1: + iphc0 |= LOWPAN_IPHC_TTL_1; + break; + case 64: + iphc0 |= LOWPAN_IPHC_TTL_64; + break; + case 255: + iphc0 |= LOWPAN_IPHC_TTL_255; + break; + default: + *hc06_ptr = hdr->hop_limit; + hc06_ptr += 1; + break; + } + + /* source address compression */ + if (is_addr_unspecified(&hdr->saddr)) { + pr_debug("source address is unspecified, setting SAC\n"); + iphc1 |= LOWPAN_IPHC_SAC; + /* TODO: context lookup */ + } else if (is_addr_link_local(&hdr->saddr)) { + iphc1 |= lowpan_compress_addr_64(&hc06_ptr, + LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr); + pr_debug("source address unicast link-local %pI6c " + "iphc1 0x%02x\n", &hdr->saddr, iphc1); + } else { + pr_debug("send the full source address\n"); + memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16); + hc06_ptr += 16; + } + + /* destination address compression */ + if (is_addr_mcast(&hdr->daddr)) { + pr_debug("destination address is multicast: "); + iphc1 |= LOWPAN_IPHC_M; + if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) { + pr_debug("compressed to 1 octet\n"); + iphc1 |= LOWPAN_IPHC_DAM_11; + /* use last byte */ + *hc06_ptr = hdr->daddr.s6_addr[15]; + hc06_ptr += 1; + } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { + pr_debug("compressed to 4 octets\n"); + iphc1 |= LOWPAN_IPHC_DAM_10; + /* second byte + the last three */ + *hc06_ptr = hdr->daddr.s6_addr[1]; + memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3); + hc06_ptr += 4; + } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { + pr_debug("compressed to 6 octets\n"); + iphc1 |= LOWPAN_IPHC_DAM_01; + /* second byte + the last five */ + *hc06_ptr = hdr->daddr.s6_addr[1]; + memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5); + hc06_ptr += 6; + } else { + pr_debug("using full address\n"); + iphc1 |= LOWPAN_IPHC_DAM_00; + memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16); + hc06_ptr += 16; + } + } else { + /* TODO: context lookup */ + if (is_addr_link_local(&hdr->daddr)) { + iphc1 |= lowpan_compress_addr_64(&hc06_ptr, + LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr); + pr_debug("dest address unicast link-local %pI6c " + "iphc1 0x%02x\n", &hdr->daddr, iphc1); + } else { + pr_debug("dest address unicast %pI6c\n", &hdr->daddr); + memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16); + hc06_ptr += 16; + } + } + + /* UDP header compression */ + if (hdr->nexthdr == UIP_PROTO_UDP) + compress_udp_header(&hc06_ptr, skb); + + head[0] = iphc0; + head[1] = iphc1; + + skb_pull(skb, sizeof(struct ipv6hdr)); + skb_reset_transport_header(skb); + memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); + skb_reset_network_header(skb); + + pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len); + + raw_dump_table(__func__, "raw skb data dump compressed", + skb->data, skb->len); + return 0; +} +EXPORT_SYMBOL_GPL(lowpan_header_compress); + +MODULE_LICENSE("GPL"); diff --git a/net/Kconfig b/net/Kconfig index d92afe4204d9..4051fdfa4367 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -214,6 +214,7 @@ source "drivers/net/appletalk/Kconfig" source "net/x25/Kconfig" source "net/lapb/Kconfig" source "net/phonet/Kconfig" +source "net/6lowpan/Kconfig" source "net/ieee802154/Kconfig" source "net/mac802154/Kconfig" source "net/sched/Kconfig" diff --git a/net/Makefile b/net/Makefile index cbbbe6d657ca..7ed1970074b0 100644 --- a/net/Makefile +++ b/net/Makefile @@ -57,7 +57,8 @@ obj-$(CONFIG_CAIF) += caif/ ifneq ($(CONFIG_DCB),) obj-y += dcb/ endif -obj-y += ieee802154/ +obj-$(CONFIG_6LOWPAN) += 6lowpan/ +obj-$(CONFIG_IEEE802154) += ieee802154/ obj-$(CONFIG_MAC802154) += mac802154/ ifeq ($(CONFIG_NET),y) diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index f5afaa22f6ec..600fb29288f4 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -41,8 +41,7 @@ menuconfig BT config BT_6LOWPAN tristate "Bluetooth 6LoWPAN support" - depends on BT && IPV6 - select 6LOWPAN_IPHC if BT_6LOWPAN + depends on BT && 6LOWPAN help IPv6 compression over Bluetooth Low Energy. diff --git a/net/ieee802154/6lowpan_iphc.c b/net/ieee802154/6lowpan_iphc.c deleted file mode 100644 index 211b5686d719..000000000000 --- a/net/ieee802154/6lowpan_iphc.c +++ /dev/null @@ -1,801 +0,0 @@ -/* - * Copyright 2011, Siemens AG - * written by Alexander Smirnov - */ - -/* - * Based on patches from Jon Smirl - * Copyright (c) 2011 Jon Smirl - * - * 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. - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* Jon's code is based on 6lowpan implementation for Contiki which is: - * Copyright (c) 2008, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Uncompress address function for source and - * destination address(non-multicast). - * - * address_mode is sam value or dam value. - */ -static int uncompress_addr(struct sk_buff *skb, - struct in6_addr *ipaddr, const u8 address_mode, - const u8 *lladdr, const u8 addr_type, - const u8 addr_len) -{ - bool fail; - - switch (address_mode) { - case LOWPAN_IPHC_ADDR_00: - /* for global link addresses */ - fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); - break; - case LOWPAN_IPHC_ADDR_01: - /* fe:80::XXXX:XXXX:XXXX:XXXX */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8); - break; - case LOWPAN_IPHC_ADDR_02: - /* fe:80::ff:fe00:XXXX */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - ipaddr->s6_addr[11] = 0xFF; - ipaddr->s6_addr[12] = 0xFE; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2); - break; - case LOWPAN_IPHC_ADDR_03: - fail = false; - switch (addr_type) { - case IEEE802154_ADDR_LONG: - /* fe:80::XXXX:XXXX:XXXX:XXXX - * \_________________/ - * hwaddr - */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - memcpy(&ipaddr->s6_addr[8], lladdr, addr_len); - /* second bit-flip (Universe/Local) - * is done according RFC2464 - */ - ipaddr->s6_addr[8] ^= 0x02; - break; - case IEEE802154_ADDR_SHORT: - /* fe:80::ff:fe00:XXXX - * \__/ - * short_addr - * - * Universe/Local bit is zero. - */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - ipaddr->s6_addr[11] = 0xFF; - ipaddr->s6_addr[12] = 0xFE; - ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr)); - break; - default: - pr_debug("Invalid addr_type set\n"); - return -EINVAL; - } - break; - default: - pr_debug("Invalid address mode value: 0x%x\n", address_mode); - return -EINVAL; - } - - if (fail) { - pr_debug("Failed to fetch skb data\n"); - return -EIO; - } - - raw_dump_inline(NULL, "Reconstructed ipv6 addr is", - ipaddr->s6_addr, 16); - - return 0; -} - -/* - * Uncompress address function for source context - * based address(non-multicast). - */ -static int uncompress_context_based_src_addr(struct sk_buff *skb, - struct in6_addr *ipaddr, - const u8 sam) -{ - switch (sam) { - case LOWPAN_IPHC_ADDR_00: - /* unspec address :: - * Do nothing, address is already :: - */ - break; - case LOWPAN_IPHC_ADDR_01: - /* TODO */ - case LOWPAN_IPHC_ADDR_02: - /* TODO */ - case LOWPAN_IPHC_ADDR_03: - /* TODO */ - netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam); - return -EINVAL; - default: - pr_debug("Invalid sam value: 0x%x\n", sam); - return -EINVAL; - } - - raw_dump_inline(NULL, - "Reconstructed context based ipv6 src addr is", - ipaddr->s6_addr, 16); - - return 0; -} - -static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, - struct net_device *dev, skb_delivery_cb deliver_skb) -{ - struct sk_buff *new; - int stat; - - new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), - GFP_ATOMIC); - kfree_skb(skb); - - if (!new) - return -ENOMEM; - - skb_push(new, sizeof(struct ipv6hdr)); - skb_reset_network_header(new); - skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr)); - - new->protocol = htons(ETH_P_IPV6); - new->pkt_type = PACKET_HOST; - new->dev = dev; - - raw_dump_table(__func__, "raw skb data dump before receiving", - new->data, new->len); - - stat = deliver_skb(new, dev); - - kfree_skb(new); - - return stat; -} - -/* Uncompress function for multicast destination address, - * when M bit is set. - */ -static int -lowpan_uncompress_multicast_daddr(struct sk_buff *skb, - struct in6_addr *ipaddr, - const u8 dam) -{ - bool fail; - - switch (dam) { - case LOWPAN_IPHC_DAM_00: - /* 00: 128 bits. The full address - * is carried in-line. - */ - fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); - break; - case LOWPAN_IPHC_DAM_01: - /* 01: 48 bits. The address takes - * the form ffXX::00XX:XXXX:XXXX. - */ - ipaddr->s6_addr[0] = 0xFF; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); - fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5); - break; - case LOWPAN_IPHC_DAM_10: - /* 10: 32 bits. The address takes - * the form ffXX::00XX:XXXX. - */ - ipaddr->s6_addr[0] = 0xFF; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); - fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3); - break; - case LOWPAN_IPHC_DAM_11: - /* 11: 8 bits. The address takes - * the form ff02::00XX. - */ - ipaddr->s6_addr[0] = 0xFF; - ipaddr->s6_addr[1] = 0x02; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1); - break; - default: - pr_debug("DAM value has a wrong value: 0x%x\n", dam); - return -EINVAL; - } - - if (fail) { - pr_debug("Failed to fetch skb data\n"); - return -EIO; - } - - raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", - ipaddr->s6_addr, 16); - - return 0; -} - -static int -uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) -{ - bool fail; - u8 tmp = 0, val = 0; - - if (!uh) - goto err; - - fail = lowpan_fetch_skb(skb, &tmp, 1); - - if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { - pr_debug("UDP header uncompression\n"); - switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { - case LOWPAN_NHC_UDP_CS_P_00: - fail |= lowpan_fetch_skb(skb, &uh->source, 2); - fail |= lowpan_fetch_skb(skb, &uh->dest, 2); - break; - case LOWPAN_NHC_UDP_CS_P_01: - fail |= lowpan_fetch_skb(skb, &uh->source, 2); - fail |= lowpan_fetch_skb(skb, &val, 1); - uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); - break; - case LOWPAN_NHC_UDP_CS_P_10: - fail |= lowpan_fetch_skb(skb, &val, 1); - uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); - fail |= lowpan_fetch_skb(skb, &uh->dest, 2); - break; - case LOWPAN_NHC_UDP_CS_P_11: - fail |= lowpan_fetch_skb(skb, &val, 1); - uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT + - (val >> 4)); - uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT + - (val & 0x0f)); - break; - default: - pr_debug("ERROR: unknown UDP format\n"); - goto err; - break; - } - - pr_debug("uncompressed UDP ports: src = %d, dst = %d\n", - ntohs(uh->source), ntohs(uh->dest)); - - /* checksum */ - if (tmp & LOWPAN_NHC_UDP_CS_C) { - pr_debug_ratelimited("checksum elided currently not supported\n"); - goto err; - } else { - fail |= lowpan_fetch_skb(skb, &uh->check, 2); - } - - /* - * UDP lenght needs to be infered from the lower layers - * here, we obtain the hint from the remaining size of the - * frame - */ - uh->len = htons(skb->len + sizeof(struct udphdr)); - pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len)); - } else { - pr_debug("ERROR: unsupported NH format\n"); - goto err; - } - - if (fail) - goto err; - - return 0; -err: - return -EINVAL; -} - -/* TTL uncompression values */ -static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; - -int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, - const u8 *saddr, const u8 saddr_type, const u8 saddr_len, - const u8 *daddr, const u8 daddr_type, const u8 daddr_len, - u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) -{ - struct ipv6hdr hdr = {}; - u8 tmp, num_context = 0; - int err; - - raw_dump_table(__func__, "raw skb data dump uncompressed", - skb->data, skb->len); - - /* another if the CID flag is set */ - if (iphc1 & LOWPAN_IPHC_CID) { - pr_debug("CID flag is set, increase header with one\n"); - if (lowpan_fetch_skb_u8(skb, &num_context)) - goto drop; - } - - hdr.version = 6; - - /* Traffic Class and Flow Label */ - switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) { - /* - * Traffic Class and FLow Label carried in-line - * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) - */ - case 0: /* 00b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) - goto drop; - - memcpy(&hdr.flow_lbl, &skb->data[0], 3); - skb_pull(skb, 3); - hdr.priority = ((tmp >> 2) & 0x0f); - hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | - (hdr.flow_lbl[0] & 0x0f); - break; - /* - * Traffic class carried in-line - * ECN + DSCP (1 byte), Flow Label is elided - */ - case 2: /* 10b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) - goto drop; - - hdr.priority = ((tmp >> 2) & 0x0f); - hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); - break; - /* - * Flow Label carried in-line - * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided - */ - case 1: /* 01b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) - goto drop; - - hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); - memcpy(&hdr.flow_lbl[1], &skb->data[0], 2); - skb_pull(skb, 2); - break; - /* Traffic Class and Flow Label are elided */ - case 3: /* 11b */ - break; - default: - break; - } - - /* Next Header */ - if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { - /* Next header is carried inline */ - if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr))) - goto drop; - - pr_debug("NH flag is set, next header carried inline: %02x\n", - hdr.nexthdr); - } - - /* Hop Limit */ - if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) - hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; - else { - if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit))) - goto drop; - } - - /* Extract SAM to the tmp variable */ - tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03; - - if (iphc1 & LOWPAN_IPHC_SAC) { - /* Source address context based uncompression */ - pr_debug("SAC bit is set. Handle context based source address.\n"); - err = uncompress_context_based_src_addr( - skb, &hdr.saddr, tmp); - } else { - /* Source address uncompression */ - pr_debug("source address stateless compression\n"); - err = uncompress_addr(skb, &hdr.saddr, tmp, saddr, - saddr_type, saddr_len); - } - - /* Check on error of previous branch */ - if (err) - goto drop; - - /* Extract DAM to the tmp variable */ - tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03; - - /* check for Multicast Compression */ - if (iphc1 & LOWPAN_IPHC_M) { - if (iphc1 & LOWPAN_IPHC_DAC) { - pr_debug("dest: context-based mcast compression\n"); - /* TODO: implement this */ - } else { - err = lowpan_uncompress_multicast_daddr( - skb, &hdr.daddr, tmp); - if (err) - goto drop; - } - } else { - err = uncompress_addr(skb, &hdr.daddr, tmp, daddr, - daddr_type, daddr_len); - pr_debug("dest: stateless compression mode %d dest %pI6c\n", - tmp, &hdr.daddr); - if (err) - goto drop; - } - - /* UDP data uncompression */ - if (iphc0 & LOWPAN_IPHC_NH_C) { - struct udphdr uh; - struct sk_buff *new; - if (uncompress_udp_header(skb, &uh)) - goto drop; - - /* - * replace the compressed UDP head by the uncompressed UDP - * header - */ - new = skb_copy_expand(skb, sizeof(struct udphdr), - skb_tailroom(skb), GFP_ATOMIC); - kfree_skb(skb); - - if (!new) - return -ENOMEM; - - skb = new; - - skb_push(skb, sizeof(struct udphdr)); - skb_reset_transport_header(skb); - skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); - - raw_dump_table(__func__, "raw UDP header dump", - (u8 *)&uh, sizeof(uh)); - - hdr.nexthdr = UIP_PROTO_UDP; - } - - hdr.payload_len = htons(skb->len); - - pr_debug("skb headroom size = %d, data length = %d\n", - skb_headroom(skb), skb->len); - - pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t" - "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", - hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, - hdr.hop_limit, &hdr.daddr); - - raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, - sizeof(hdr)); - - return skb_deliver(skb, &hdr, dev, deliver_skb); - -drop: - kfree_skb(skb); - return -EINVAL; -} -EXPORT_SYMBOL_GPL(lowpan_process_data); - -static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, - const struct in6_addr *ipaddr, - const unsigned char *lladdr) -{ - u8 val = 0; - - if (is_addr_mac_addr_based(ipaddr, lladdr)) { - val = 3; /* 0-bits */ - pr_debug("address compression 0 bits\n"); - } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { - /* compress IID to 16 bits xxxx::XXXX */ - memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2); - *hc06_ptr += 2; - val = 2; /* 16-bits */ - raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", - *hc06_ptr - 2, 2); - } else { - /* do not compress IID => xxxx::IID */ - memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8); - *hc06_ptr += 8; - val = 1; /* 64-bits */ - raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", - *hc06_ptr - 8, 8); - } - - return rol8(val, shift); -} - -static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) -{ - struct udphdr *uh = udp_hdr(skb); - u8 tmp; - - if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) == - LOWPAN_NHC_UDP_4BIT_PORT) && - ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) == - LOWPAN_NHC_UDP_4BIT_PORT)) { - pr_debug("UDP header: both ports compression to 4 bits\n"); - /* compression value */ - tmp = LOWPAN_NHC_UDP_CS_P_11; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - /* source and destination port */ - tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT + - ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4); - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) == - LOWPAN_NHC_UDP_8BIT_PORT) { - pr_debug("UDP header: remove 8 bits of dest\n"); - /* compression value */ - tmp = LOWPAN_NHC_UDP_CS_P_01; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - /* source port */ - lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); - /* destination port */ - tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) == - LOWPAN_NHC_UDP_8BIT_PORT) { - pr_debug("UDP header: remove 8 bits of source\n"); - /* compression value */ - tmp = LOWPAN_NHC_UDP_CS_P_10; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - /* source port */ - tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - /* destination port */ - lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); - } else { - pr_debug("UDP header: can't compress\n"); - /* compression value */ - tmp = LOWPAN_NHC_UDP_CS_P_00; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - /* source port */ - lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); - /* destination port */ - lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); - } - - /* checksum is always inline */ - lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check)); - - /* skip the UDP header */ - skb_pull(skb, sizeof(struct udphdr)); -} - -int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *_daddr, - const void *_saddr, unsigned int len) -{ - u8 tmp, iphc0, iphc1, *hc06_ptr; - struct ipv6hdr *hdr; - u8 head[100] = {}; - - if (type != ETH_P_IPV6) - return -EINVAL; - - hdr = ipv6_hdr(skb); - hc06_ptr = head + 2; - - pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" - "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", - hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, - hdr->hop_limit, &hdr->daddr); - - raw_dump_table(__func__, "raw skb network header dump", - skb_network_header(skb), sizeof(struct ipv6hdr)); - - /* - * As we copy some bit-length fields, in the IPHC encoding bytes, - * we sometimes use |= - * If the field is 0, and the current bit value in memory is 1, - * this does not work. We therefore reset the IPHC encoding here - */ - iphc0 = LOWPAN_DISPATCH_IPHC; - iphc1 = 0; - - /* TODO: context lookup */ - - raw_dump_inline(__func__, "saddr", - (unsigned char *)_saddr, IEEE802154_ADDR_LEN); - raw_dump_inline(__func__, "daddr", - (unsigned char *)_daddr, IEEE802154_ADDR_LEN); - - raw_dump_table(__func__, - "sending raw skb network uncompressed packet", - skb->data, skb->len); - - /* - * Traffic class, flow label - * If flow label is 0, compress it. If traffic class is 0, compress it - * We have to process both in the same time as the offset of traffic - * class depends on the presence of version and flow label - */ - - /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */ - tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4); - tmp = ((tmp & 0x03) << 6) | (tmp >> 2); - - if (((hdr->flow_lbl[0] & 0x0F) == 0) && - (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { - /* flow label can be compressed */ - iphc0 |= LOWPAN_IPHC_FL_C; - if ((hdr->priority == 0) && - ((hdr->flow_lbl[0] & 0xF0) == 0)) { - /* compress (elide) all */ - iphc0 |= LOWPAN_IPHC_TC_C; - } else { - /* compress only the flow label */ - *hc06_ptr = tmp; - hc06_ptr += 1; - } - } else { - /* Flow label cannot be compressed */ - if ((hdr->priority == 0) && - ((hdr->flow_lbl[0] & 0xF0) == 0)) { - /* compress only traffic class */ - iphc0 |= LOWPAN_IPHC_TC_C; - *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); - memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2); - hc06_ptr += 3; - } else { - /* compress nothing */ - memcpy(hc06_ptr, hdr, 4); - /* replace the top byte with new ECN | DSCP format */ - *hc06_ptr = tmp; - hc06_ptr += 4; - } - } - - /* NOTE: payload length is always compressed */ - - /* Next Header is compress if UDP */ - if (hdr->nexthdr == UIP_PROTO_UDP) - iphc0 |= LOWPAN_IPHC_NH_C; - - if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { - *hc06_ptr = hdr->nexthdr; - hc06_ptr += 1; - } - - /* - * Hop limit - * if 1: compress, encoding is 01 - * if 64: compress, encoding is 10 - * if 255: compress, encoding is 11 - * else do not compress - */ - switch (hdr->hop_limit) { - case 1: - iphc0 |= LOWPAN_IPHC_TTL_1; - break; - case 64: - iphc0 |= LOWPAN_IPHC_TTL_64; - break; - case 255: - iphc0 |= LOWPAN_IPHC_TTL_255; - break; - default: - *hc06_ptr = hdr->hop_limit; - hc06_ptr += 1; - break; - } - - /* source address compression */ - if (is_addr_unspecified(&hdr->saddr)) { - pr_debug("source address is unspecified, setting SAC\n"); - iphc1 |= LOWPAN_IPHC_SAC; - /* TODO: context lookup */ - } else if (is_addr_link_local(&hdr->saddr)) { - iphc1 |= lowpan_compress_addr_64(&hc06_ptr, - LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr); - pr_debug("source address unicast link-local %pI6c " - "iphc1 0x%02x\n", &hdr->saddr, iphc1); - } else { - pr_debug("send the full source address\n"); - memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16); - hc06_ptr += 16; - } - - /* destination address compression */ - if (is_addr_mcast(&hdr->daddr)) { - pr_debug("destination address is multicast: "); - iphc1 |= LOWPAN_IPHC_M; - if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) { - pr_debug("compressed to 1 octet\n"); - iphc1 |= LOWPAN_IPHC_DAM_11; - /* use last byte */ - *hc06_ptr = hdr->daddr.s6_addr[15]; - hc06_ptr += 1; - } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { - pr_debug("compressed to 4 octets\n"); - iphc1 |= LOWPAN_IPHC_DAM_10; - /* second byte + the last three */ - *hc06_ptr = hdr->daddr.s6_addr[1]; - memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3); - hc06_ptr += 4; - } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { - pr_debug("compressed to 6 octets\n"); - iphc1 |= LOWPAN_IPHC_DAM_01; - /* second byte + the last five */ - *hc06_ptr = hdr->daddr.s6_addr[1]; - memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5); - hc06_ptr += 6; - } else { - pr_debug("using full address\n"); - iphc1 |= LOWPAN_IPHC_DAM_00; - memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16); - hc06_ptr += 16; - } - } else { - /* TODO: context lookup */ - if (is_addr_link_local(&hdr->daddr)) { - iphc1 |= lowpan_compress_addr_64(&hc06_ptr, - LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr); - pr_debug("dest address unicast link-local %pI6c " - "iphc1 0x%02x\n", &hdr->daddr, iphc1); - } else { - pr_debug("dest address unicast %pI6c\n", &hdr->daddr); - memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16); - hc06_ptr += 16; - } - } - - /* UDP header compression */ - if (hdr->nexthdr == UIP_PROTO_UDP) - compress_udp_header(&hc06_ptr, skb); - - head[0] = iphc0; - head[1] = iphc1; - - skb_pull(skb, sizeof(struct ipv6hdr)); - skb_reset_transport_header(skb); - memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); - skb_reset_network_header(skb); - - pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len); - - raw_dump_table(__func__, "raw skb data dump compressed", - skb->data, skb->len); - return 0; -} -EXPORT_SYMBOL_GPL(lowpan_header_compress); - -MODULE_LICENSE("GPL"); diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig index 8af1330b3137..c0d4154d144f 100644 --- a/net/ieee802154/Kconfig +++ b/net/ieee802154/Kconfig @@ -12,13 +12,6 @@ config IEEE802154 config IEEE802154_6LOWPAN tristate "6lowpan support over IEEE 802.15.4" - depends on IEEE802154 && IPV6 - select 6LOWPAN_IPHC + depends on IEEE802154 && 6LOWPAN ---help--- IPv6 compression over IEEE 802.15.4. - -config 6LOWPAN_IPHC - tristate - ---help--- - 6lowpan compression code which is shared between IEEE 802.15.4 and Bluetooth - stacks. diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index bf1b51497a41..3914b1ed4274 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -1,8 +1,7 @@ obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o -obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o -obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o +obj-$(CONFIG_IEEE802154_6LOWPAN) += ieee802154_6lowpan.o -6lowpan-y := 6lowpan_rtnl.o reassembly.o +ieee802154_6lowpan-y := 6lowpan_rtnl.o reassembly.o ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o \ header_ops.o af_802154-y := af_ieee802154.o raw.o dgram.o -- cgit v1.2.3 From 68d96dcfc6c09b565d57897c127b61afbab74c6f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 11 Jul 2014 10:24:19 +0200 Subject: MAINTAINERS: add net/6lowpan/ maintainer entry This patch add a maintainer entry for "net/6lowpan". Also add the current IEEE 802.15.4 mailing list and bluetooth mailinglist to this branch, because this code is shared between them. Signed-off-by: Alexander Aring Acked-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 54ba0e643c39..0057ff580536 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -148,6 +148,13 @@ L: linux-scsi@vger.kernel.org S: Maintained F: drivers/scsi/53c700* +6LOWPAN GENERIC (BTLE/IEEE 802.15.4) +M: Alexander Aring +L: linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers) +L: linux-bluetooth@vger.kernel.org +S: Maintained +F: net/6lowpan/ + 6PACK NETWORK DRIVER FOR AX.25 M: Andreas Koensgen L: linux-hams@vger.kernel.org -- cgit v1.2.3 From c7e0c14115db67063a5f68fd9d4a12a54e649dc7 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 12 Jul 2014 17:00:29 +0200 Subject: Bluetooth: Fix HCIUARTGETDEVICE ioctl when UART is not registered The protocol for the UART might be configured, but that does not mean the HCI device is registered. Return an error in that case and only return the index number when HCI_UART_REGISTERED is set. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ldisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 401a3be57cda..dc487b5d1156 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -539,7 +539,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, return -EUNATCH; case HCIUARTGETDEVICE: - if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) + if (test_bit(HCI_UART_REGISTERED, &hu->flags)) return hu->hdev->id; return -EUNATCH; -- cgit v1.2.3 From 15a49cca98c3380271ced8db2ea69ee95db5c709 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 12 Jul 2014 23:20:50 +0200 Subject: Bluetooth: Read LE Advertising Channel TX Power only when available The Read LE Advertising Channel TX Power command is not mandatory for a Bluetooth HCI controller only supporting receiption. Move the command to the third stage of the controller initialization and only execute it when support for it has been indicated. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 347f84fb66f9..b29a984f7dd4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1348,9 +1348,6 @@ static void le_setup(struct hci_request *req) /* Read LE Supported States */ hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL); - /* Read LE Advertising Channel TX Power */ - hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); - /* Read LE White List Size */ hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL); @@ -1657,6 +1654,11 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events), events); + if (hdev->commands[25] & 0x40) { + /* Read LE Advertising Channel TX Power */ + hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); + } + hci_set_le_support(req); } -- cgit v1.2.3 From 0da71f1bf90f259debf50aaaa547e2cc31b5cf67 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 12 Jul 2014 23:36:16 +0200 Subject: Bluetooth: Enable LE encryption events only when supported The support for LE encryption is optional. When encryption is not supported then also do not enable the encryption related events. This moves the event mask setting to the third initialization stage to ensure that the LE features are available. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 7f754a246ca5..2fee852816ee 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -329,6 +329,7 @@ enum { #define LMP_HOST_SC 0x08 /* LE features */ +#define HCI_LE_ENCRYPTION 0x01 #define HCI_LE_CONN_PARAM_REQ_PROC 0x02 #define HCI_LE_PING 0x10 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b29a984f7dd4..ff150e3c7ad1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1422,14 +1422,17 @@ static void hci_setup_event_mask(struct hci_request *req) /* Use a different default for LE-only devices */ memset(events, 0, sizeof(events)); events[0] |= 0x10; /* Disconnection Complete */ - events[0] |= 0x80; /* Encryption Change */ events[1] |= 0x08; /* Read Remote Version Information Complete */ events[1] |= 0x20; /* Command Complete */ events[1] |= 0x40; /* Command Status */ events[1] |= 0x80; /* Hardware Error */ events[2] |= 0x04; /* Number of Completed Packets */ events[3] |= 0x02; /* Data Buffer Overflow */ - events[5] |= 0x80; /* Encryption Key Refresh Complete */ + + if (hdev->le_features[0] & HCI_LE_ENCRYPTION) { + events[0] |= 0x80; /* Encryption Change */ + events[5] |= 0x80; /* Encryption Key Refresh Complete */ + } } if (lmp_inq_rssi_capable(hdev)) @@ -1482,8 +1485,6 @@ static void hci_init2_req(struct hci_request *req, unsigned long opt) if (lmp_le_capable(hdev)) le_setup(req); - hci_setup_event_mask(req); - /* AVM Berlin (31), aka "BlueFRITZ!", doesn't support the read * local supported commands HCI command. */ @@ -1611,6 +1612,8 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) struct hci_dev *hdev = req->hdev; u8 p; + hci_setup_event_mask(req); + /* Some Broadcom based Bluetooth controllers do not support the * Delete Stored Link Key command. They are clearly indicating its * absence in the bit mask of supported commands. -- cgit v1.2.3 From 4d6c705bbd9e845bcfbe119bb017a5653c0d9efb Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 13 Jul 2014 00:29:22 +0200 Subject: Bluetooth: Enable LE Long Term Key Request event only when supported The support for LE encryption is optional and with that also the LE Long Term Key Request event. If encryption is not supported, then do not bother enabling this event. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ff150e3c7ad1..188bfd3d7c43 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1644,7 +1644,10 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) u8 events[8]; memset(events, 0, sizeof(events)); - events[0] = 0x1f; + events[0] = 0x0f; + + if (hdev->le_features[0] & HCI_LE_ENCRYPTION) + events[0] |= 0x10; /* LE Long Term Key Request */ /* If controller supports the Connection Parameters Request * Link Layer Procedure, enable the corresponding event. -- cgit v1.2.3 From 395365eaf125e53b9d7e1c11c91ee01bf5a4b792 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 13 Jul 2014 17:22:25 +0200 Subject: Bluetooth: Allocate struct inquiry_entry with GFP_KERNEL The allocation of inquiry cache entries is triggered as a result of processing HCI events. Since the processing is done in the context of a workqueue, there is no needed to allocate with GFP_ATOMIC in that case. Switch it to GFP_KERNEL. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 188bfd3d7c43..172041e2b15a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2088,7 +2088,7 @@ u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, } /* Entry not in the cache. Add new one. */ - ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); + ie = kzalloc(sizeof(struct inquiry_entry), GFP_KERNEL); if (!ie) { flags |= MGMT_DEV_FOUND_CONFIRM_NAME; goto done; -- cgit v1.2.3 From 015b01cbca20276a6b09ad25ce4002e811a53130 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 13 Jul 2014 19:54:48 +0200 Subject: Bluetooth: Remove unneeded forward declaration of __sco_chan_add The forward declaration of __sco_chan_add is not needed and thus just remove it. Move __sco_chan_add into the proper location. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/sco.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index e6c7b636b901..75cffc14ab6e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -53,7 +53,6 @@ struct sco_conn { #define sco_conn_lock(c) spin_lock(&c->lock); #define sco_conn_unlock(c) spin_unlock(&c->lock); -static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); static void sco_chan_del(struct sock *sk, int err); static void sco_sock_close(struct sock *sk); @@ -164,6 +163,17 @@ static int sco_conn_del(struct hci_conn *hcon, int err) return 0; } +static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) +{ + BT_DBG("conn %p", conn); + + sco_pi(sk)->conn = conn; + conn->sk = sk; + + if (parent) + bt_accept_enqueue(parent, sk); +} + static int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) { @@ -968,17 +978,6 @@ static int sco_sock_release(struct socket *sock) return err; } -static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) -{ - BT_DBG("conn %p", conn); - - sco_pi(sk)->conn = conn; - conn->sk = sk; - - if (parent) - bt_accept_enqueue(parent, sk); -} - /* Delete channel. * Must be called on the locked socket. */ static void sco_chan_del(struct sock *sk, int err) -- cgit v1.2.3 From e03ab5199df597d3f1737ef638a7f692daaaef9f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 13 Jul 2014 19:54:49 +0200 Subject: Bluetooth: Remove unneeded forward declaration of sco_chan_del The forward declaration of sco_chan_del is not needed and thus just remove it. Move sco_chan_del into the proper location. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/sco.c | 56 ++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 75cffc14ab6e..4d67b0354d23 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -53,8 +53,6 @@ struct sco_conn { #define sco_conn_lock(c) spin_lock(&c->lock); #define sco_conn_unlock(c) spin_unlock(&c->lock); -static void sco_chan_del(struct sock *sk, int err); - static void sco_sock_close(struct sock *sk); static void sco_sock_kill(struct sock *sk); @@ -138,6 +136,33 @@ static struct sock *sco_chan_get(struct sco_conn *conn) return sk; } +/* Delete channel. + * Must be called on the locked socket. */ +static void sco_chan_del(struct sock *sk, int err) +{ + struct sco_conn *conn; + + conn = sco_pi(sk)->conn; + + BT_DBG("sk %p, conn %p, err %d", sk, conn, err); + + if (conn) { + sco_conn_lock(conn); + conn->sk = NULL; + sco_pi(sk)->conn = NULL; + sco_conn_unlock(conn); + + if (conn->hcon) + hci_conn_drop(conn->hcon); + } + + sk->sk_state = BT_CLOSED; + sk->sk_err = err; + sk->sk_state_change(sk); + + sock_set_flag(sk, SOCK_ZAPPED); +} + static int sco_conn_del(struct hci_conn *hcon, int err) { struct sco_conn *conn = hcon->sco_data; @@ -978,33 +1003,6 @@ static int sco_sock_release(struct socket *sock) return err; } -/* Delete channel. - * Must be called on the locked socket. */ -static void sco_chan_del(struct sock *sk, int err) -{ - struct sco_conn *conn; - - conn = sco_pi(sk)->conn; - - BT_DBG("sk %p, conn %p, err %d", sk, conn, err); - - if (conn) { - sco_conn_lock(conn); - conn->sk = NULL; - sco_pi(sk)->conn = NULL; - sco_conn_unlock(conn); - - if (conn->hcon) - hci_conn_drop(conn->hcon); - } - - sk->sk_state = BT_CLOSED; - sk->sk_err = err; - sk->sk_state_change(sk); - - sock_set_flag(sk, SOCK_ZAPPED); -} - static void sco_conn_ready(struct sco_conn *conn) { struct sock *parent; -- cgit v1.2.3 From 5a54e7c85b8303b84a9b2fbf978a74d625f85a99 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 13 Jul 2014 20:50:15 +0200 Subject: Bluetooth: Convert L2CAP ident spinlock into a mutex The spinlock protecting the L2CAP ident number can be converted into a mutex since the whole processing is run in a workqueue. So instead of using a spinlock, just use a mutex here. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 3 +-- net/bluetooth/l2cap_core.c | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d8e7b9330ab8..1fffd92808b0 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -625,11 +625,10 @@ struct l2cap_conn { struct delayed_work info_timer; - spinlock_t lock; - struct sk_buff *rx_skb; __u32 rx_len; __u8 tx_ident; + struct mutex ident_lock; struct sk_buff_head pending_rx; struct work_struct pending_rx_work; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0c3c4935f635..8538cb07b0c0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -798,14 +798,14 @@ static u8 l2cap_get_ident(struct l2cap_conn *conn) * 200 - 254 are used by utilities like l2ping, etc. */ - spin_lock(&conn->lock); + mutex_lock(&conn->ident_lock); if (++conn->tx_ident > 128) conn->tx_ident = 1; id = conn->tx_ident; - spin_unlock(&conn->lock); + mutex_unlock(&conn->ident_lock); return id; } @@ -7016,7 +7016,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) conn->hs_enabled = test_bit(HCI_HS_ENABLED, &hcon->hdev->dev_flags); - spin_lock_init(&conn->lock); + mutex_init(&conn->ident_lock); mutex_init(&conn->chan_lock); INIT_LIST_HEAD(&conn->chan_l); -- cgit v1.2.3 From ec31a05c4dfa95149b1754d9de92831a5a95c636 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 12 Jul 2014 15:49:16 +0200 Subject: net: filter: sk_chk_filter() no longer mangles filter Add const attribute to filter argument to make clear it is no longer modified. Signed-off-by: Eric Dumazet Acked-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/filter.h | 2 +- net/core/filter.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index b885dcb7eaca..c43c8258e682 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -362,7 +362,7 @@ void sk_unattached_filter_destroy(struct sk_filter *fp); int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); int sk_detach_filter(struct sock *sk); -int sk_chk_filter(struct sock_filter *filter, unsigned int flen); +int sk_chk_filter(const struct sock_filter *filter, unsigned int flen); int sk_get_filter(struct sock *sk, struct sock_filter __user *filter, unsigned int len); diff --git a/net/core/filter.c b/net/core/filter.c index 87af1e3e56c0..b90ae7fb3b89 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1085,7 +1085,7 @@ err: * a cell if not previously written, and we check all branches to be sure * a malicious user doesn't try to abuse us. */ -static int check_load_and_stores(struct sock_filter *filter, int flen) +static int check_load_and_stores(const struct sock_filter *filter, int flen) { u16 *masks, memvalid = 0; /* One bit per cell, 16 cells */ int pc, ret = 0; @@ -1218,7 +1218,7 @@ static bool chk_code_allowed(u16 code_to_probe) * * Returns 0 if the rule set is legal or -EINVAL if not. */ -int sk_chk_filter(struct sock_filter *filter, unsigned int flen) +int sk_chk_filter(const struct sock_filter *filter, unsigned int flen) { bool anc_found; int pc; @@ -1228,7 +1228,7 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen) /* Check the filter code now */ for (pc = 0; pc < flen; pc++) { - struct sock_filter *ftest = &filter[pc]; + const struct sock_filter *ftest = &filter[pc]; /* May we actually operate on this code? */ if (!chk_code_allowed(ftest->code)) -- cgit v1.2.3 From a4a07624927743df7f4414e7f368b49ff19271b9 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Jul 2014 20:09:40 +0200 Subject: igb: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/igb/e1000_82575.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index a2db388cc31e..168a5ee5e0ba 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -837,7 +837,6 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw) default: ret_val = -E1000_ERR_PHY; goto out; - break; } ret_val = igb_get_phy_id(hw); goto out; -- cgit v1.2.3 From 3a087b217138ce3c7fbbf01807c957ad91d6d5b8 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Jul 2014 20:09:41 +0200 Subject: ixgbe: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c | 1 - drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c | 4 ---- drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 2 -- 3 files changed, 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index 15609331ec17..206171f732fb 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -430,7 +430,6 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = IXGBE_ERR_CONFIG; goto out; - break; } /* Set 802.3x based flow control settings. */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index bc7c924240a5..0373a5b9219f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -432,7 +432,6 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, default: status = IXGBE_ERR_LINK_SETUP; goto out; - break; } if (hw->phy.multispeed_fiber) { @@ -2035,7 +2034,6 @@ static u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) else if (pma_pmd_10g_parallel == IXGBE_AUTOC_10G_XAUI) physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_XAUI; goto out; - break; case IXGBE_AUTOC_LMS_10G_SERIAL: if (pma_pmd_10g_serial == IXGBE_AUTOC2_10G_KR) { physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KR; @@ -2052,10 +2050,8 @@ static u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) if (autoc & IXGBE_AUTOC_KR_SUPP) physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_KR; goto out; - break; default: goto out; - break; } sfp_check: diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 4e5385a2a465..3f318c52e053 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -216,7 +216,6 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = IXGBE_ERR_CONFIG; goto out; - break; } if (hw->mac.type != ixgbe_mac_X540) { @@ -2179,7 +2178,6 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = IXGBE_ERR_CONFIG; goto out; - break; } /* Set 802.3x based flow control settings. */ -- cgit v1.2.3 From 3ec9fa753543d17d9a21c85bd2bb6f0d02f7f02f Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Jul 2014 20:09:42 +0200 Subject: i40e: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c index 0d74b46d177f..4627588f4613 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c @@ -417,7 +417,6 @@ static i40e_status i40e_create_lan_hmc_object(struct i40e_hw *hw, default: ret_code = I40E_ERR_INVALID_SD_TYPE; goto exit; - break; } } } @@ -502,7 +501,6 @@ try_type_paged: hw_dbg(hw, "i40e_configure_lan_hmc: Unknown SD type: %d\n", ret_code); goto configure_lan_hmc_out; - break; } /* Configure and program the FPM registers so objects can be created */ -- cgit v1.2.3 From 11029d03bf5ddea9726513bd499dc35e398bffa3 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Jul 2014 20:09:43 +0200 Subject: i40evf: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 1b980fb88cdd..ed1eb1230522 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2013,7 +2013,6 @@ static void i40evf_init_task(struct work_struct *work) } adapter->state = __I40EVF_INIT_VERSION_CHECK; goto restart; - break; case __I40EVF_INIT_VERSION_CHECK: if (!i40evf_asq_done(hw)) { dev_err(&pdev->dev, "Admin queue command never completed\n"); @@ -2039,7 +2038,6 @@ static void i40evf_init_task(struct work_struct *work) } adapter->state = __I40EVF_INIT_GET_RESOURCES; goto restart; - break; case __I40EVF_INIT_GET_RESOURCES: /* aq msg sent, awaiting reply */ if (!adapter->vf_res) { -- cgit v1.2.3 From 1205d38d862dd7ae0f4349045cac511b11603736 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Jul 2014 20:09:44 +0200 Subject: ps3_gelic: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/toshiba/ps3_gelic_wireless.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c index d568af1eb4f4..2553ed5d2ece 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c +++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c @@ -723,13 +723,10 @@ static int gelic_wl_get_scan(struct net_device *netdev, /* If a scan in progress, caller should call me again */ ret = -EAGAIN; goto out; - break; - case GELIC_WL_SCAN_STAT_INIT: /* last scan request failed or never issued */ ret = -ENODEV; goto out; - break; case GELIC_WL_SCAN_STAT_GOT_LIST: /* ok, use current list */ break; -- cgit v1.2.3 From a9fdfb30cf4077851d4344eb73a968fa70168dfa Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Jul 2014 20:09:45 +0200 Subject: orinoco_usb: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/orinoco/orinoco_usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c index c90939ced0e4..d3cf7c3ebfd6 100644 --- a/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/orinoco/orinoco_usb.c @@ -921,7 +921,6 @@ static int ezusb_access_ltv(struct ezusb_priv *upriv, retval = -EFAULT; } goto exit; - break; } if (ctx->in_rid) { struct ezusb_packet *ans = ctx->buf; -- cgit v1.2.3 From f778b769d9df3b078084ccdd1d447906a4f4ba67 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Jul 2014 20:09:46 +0200 Subject: wcn36xx: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/ath/wcn36xx/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 4ab5370ab7a6..b71d2b33532d 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -488,7 +488,6 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, wcn36xx_err("Unsupported key cmd 0x%x\n", cmd); ret = -EOPNOTSUPP; goto out; - break; } out: -- cgit v1.2.3 From 7dec26f866f5ac43ee0672cb971c2f8f79f3a207 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Jul 2014 20:09:47 +0200 Subject: rtlwifi: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/rtlwifi/rtl8192se/fw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c index 380e7d4b1ccf..73fa4a1de4df 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c @@ -438,7 +438,6 @@ int rtl92s_download_fw(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Unexpected Download step!!\n"); goto fail; - break; } /* <2> Download image file */ -- cgit v1.2.3 From 8904120b52e0ca35597ca743bb67db5d273ecd2c Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Jul 2014 20:09:48 +0200 Subject: slip: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/slip/slhc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c index 1252d9c726a7..079f7adfcde5 100644 --- a/drivers/net/slip/slhc.c +++ b/drivers/net/slip/slhc.c @@ -396,7 +396,6 @@ found: ntohs(cs->cs_ip.tot_len) == hlen) break; goto uncompressed; - break; case SPECIAL_I: case SPECIAL_D: /* actual changes match one of our special case encodings -- -- cgit v1.2.3 From eb5a4de80f266d0bb7edd43c61894da74faaa91a Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 Jul 2014 01:30:15 +0200 Subject: Bluetooth: Remove sco_chan_get helper function The sco_chan_get helper function is only used in two places and really only protects conn->sk with a lock. So instead of hiding that fact, just put the actual code in place where it is used. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/sco.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 4d67b0354d23..ebf7ee6a446c 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -127,15 +127,6 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon) return conn; } -static struct sock *sco_chan_get(struct sco_conn *conn) -{ - struct sock *sk = NULL; - sco_conn_lock(conn); - sk = conn->sk; - sco_conn_unlock(conn); - return sk; -} - /* Delete channel. * Must be called on the locked socket. */ static void sco_chan_del(struct sock *sk, int err) @@ -174,7 +165,10 @@ static int sco_conn_del(struct hci_conn *hcon, int err) BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); /* Kill socket */ - sk = sco_chan_get(conn); + sco_conn_lock(conn); + sk = conn->sk; + sco_conn_unlock(conn); + if (sk) { bh_lock_sock(sk); sco_sock_clear_timer(sk); @@ -303,7 +297,11 @@ static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) { - struct sock *sk = sco_chan_get(conn); + struct sock *sk; + + sco_conn_lock(conn); + sk = conn->sk; + sco_conn_unlock(conn); if (!sk) goto drop; -- cgit v1.2.3 From b2d5e254ebfe9e4a926265c23bc5943f212fd1ac Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 14 Jul 2014 14:34:55 +0300 Subject: Bluetooth: Fix trying LTK re-encryption when we don't have an LTK In the case that the key distribution bits cause us not to generate a local LTK we should not try to re-encrypt if we're currently encrypted with an STK. This patch fixes the check for this in the smp_sufficient_security function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index bf3568c46847..8339d6b0f2b8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -876,9 +876,12 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) /* If we're encrypted with an STK always claim insufficient * security. This way we allow the connection to be re-encrypted * with an LTK, even if the LTK provides the same level of - * security. + * security. Only exception is if we don't have an LTK (e.g. + * because of key distribution bits). */ - if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags)) + if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) && + hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, + hcon->out)) return false; if (hcon->sec_level >= sec_level) -- cgit v1.2.3 From d385623a78145889692074c170ecac7232e547ab Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Mon, 2 Jun 2014 21:19:46 +0300 Subject: ath10k: add implementation for configure max amsdu, ampdu Allow to setup maximum subframes for AMSDU and AMPDU aggregation via debugfs htt_max_amsdu_ampdu file. Eg. echo "2 64" > htt_max_amsdu_ampdu will setup maximum amsdu subframes equal 2 and maximum ampdu subframes equal to 64. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 3 ++ drivers/net/wireless/ath/ath10k/debug.c | 73 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/htt.h | 13 +++--- drivers/net/wireless/ath/ath10k/htt_tx.c | 46 ++++++++++++++++++++ 4 files changed, 127 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 68ceef61933d..83a5fa91531d 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -290,6 +290,9 @@ struct ath10k_debug { struct ath_dfs_pool_stats dfs_pool_stats; u32 fw_dbglog_mask; + + u8 htt_max_amsdu; + u8 htt_max_ampdu; }; enum ath10k_state { diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 1b7ff4ba122c..3030158c478e 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -671,6 +671,72 @@ static const struct file_operations fops_htt_stats_mask = { .llseek = default_llseek, }; +static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + char buf[64]; + u8 amsdu = 3, ampdu = 64; + unsigned int len; + + mutex_lock(&ar->conf_mutex); + + if (ar->debug.htt_max_amsdu) + amsdu = ar->debug.htt_max_amsdu; + + if (ar->debug.htt_max_ampdu) + ampdu = ar->debug.htt_max_ampdu; + + mutex_unlock(&ar->conf_mutex); + + len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + int res; + char buf[64]; + unsigned int amsdu, ampdu; + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + + /* make sure that buf is null terminated */ + buf[sizeof(buf) - 1] = 0; + + res = sscanf(buf, "%u %u", &amsdu, &du); + + if (res != 2) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + + res = ath10k_htt_h2t_aggr_cfg_msg(&ar->htt, ampdu, amsdu); + if (res) + goto out; + + res = count; + ar->debug.htt_max_amsdu = amsdu; + ar->debug.htt_max_ampdu = ampdu; + +out: + mutex_unlock(&ar->conf_mutex); + return res; +} + +static const struct file_operations fops_htt_max_amsdu_ampdu = { + .read = ath10k_read_htt_max_amsdu_ampdu, + .write = ath10k_write_htt_max_amsdu_ampdu, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static ssize_t ath10k_read_fw_dbglog(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -757,6 +823,9 @@ void ath10k_debug_stop(struct ath10k *ar) * warning from del_timer(). */ if (ar->debug.htt_stats_mask != 0) cancel_delayed_work(&ar->debug.htt_stats_dwork); + + ar->debug.htt_max_amsdu = 0; + ar->debug.htt_max_ampdu = 0; } static ssize_t ath10k_write_simulate_radar(struct file *file, @@ -867,6 +936,10 @@ int ath10k_debug_create(struct ath10k *ar) debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_htt_stats_mask); + debugfs_create_file("htt_max_amsdu_ampdu", S_IRUSR | S_IWUSR, + ar->debug.debugfs_phy, ar, + &fops_htt_max_amsdu_ampdu); + debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_fw_dbglog); diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 9a263462c793..6c93f3885ee5 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -240,16 +240,10 @@ struct htt_oob_sync_req { __le16 rsvd0; } __packed; -#define HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_MASK 0x1F -#define HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_LSB 0 - struct htt_aggr_conf { u8 max_num_ampdu_subframes; - union { - /* dont use bitfields; undefined behaviour */ - u8 flags; /* see %HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_ */ - u8 max_num_amsdu_subframes:5; - } __packed; + /* amsdu_subframes is limited by 0x1F mask */ + u8 max_num_amsdu_subframes; } __packed; #define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32 @@ -1343,6 +1337,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb); int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt); int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie); int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt); +int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, + u8 max_subfrms_ampdu, + u8 max_subfrms_amsdu); void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt); int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt); diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 7064354d1f4f..accb6b4f6faf 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -307,6 +307,52 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt) return 0; } +int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, + u8 max_subfrms_ampdu, + u8 max_subfrms_amsdu) +{ + struct htt_aggr_conf *aggr_conf; + struct sk_buff *skb; + struct htt_cmd *cmd; + int len; + int ret; + + /* Firmware defaults are: amsdu = 3 and ampdu = 64 */ + + if (max_subfrms_ampdu == 0 || max_subfrms_ampdu > 64) + return -EINVAL; + + if (max_subfrms_amsdu == 0 || max_subfrms_amsdu > 31) + return -EINVAL; + + len = sizeof(cmd->hdr); + len += sizeof(cmd->aggr_conf); + + skb = ath10k_htc_alloc_skb(len); + if (!skb) + return -ENOMEM; + + skb_put(skb, len); + cmd = (struct htt_cmd *)skb->data; + cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_AGGR_CFG; + + aggr_conf = &cmd->aggr_conf; + aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu; + aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu; + + ath10k_dbg(ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d", + aggr_conf->max_num_amsdu_subframes, + aggr_conf->max_num_ampdu_subframes); + + ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); + if (ret) { + dev_kfree_skb_any(skb); + return ret; + } + + return 0; +} + int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) { struct device *dev = htt->ar->dev; -- cgit v1.2.3 From 1c3d95edf026c6fb446f53913c61ff1036c469cd Mon Sep 17 00:00:00 2001 From: Frederic Danis Date: Mon, 2 Jun 2014 21:19:46 +0300 Subject: ath6kl: Fix ath6kl_bmi_read_hi32 macro tmp may be used uninitialized if ath6kl_bmi_read() returns an error. Signed-off-by: Frederic Danis Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/bmi.h | 3 ++- drivers/net/wireless/ath/ath6kl/init.c | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h index 18fdd69e1f71..397a52f2628b 100644 --- a/drivers/net/wireless/ath/ath6kl/bmi.h +++ b/drivers/net/wireless/ath/ath6kl/bmi.h @@ -242,7 +242,8 @@ struct ath6kl_bmi_target_info { (void) (check_type == val); \ addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4); \ - *val = le32_to_cpu(tmp); \ + if (!ret) \ + *val = le32_to_cpu(tmp); \ ret; \ }) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index d5ef211f261c..6e1e6995a634 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1161,11 +1161,19 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) ath6kl_bmi_write_hi32(ar, hi_board_data, board_address); } else { - ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address); + ret = ath6kl_bmi_read_hi32(ar, hi_board_data, &board_address); + if (ret) { + ath6kl_err("Failed to get board file target address.\n"); + return ret; + } } /* determine where in target ram to write extended board data */ - ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address); + ret = ath6kl_bmi_read_hi32(ar, hi_board_ext_data, &board_ext_address); + if (ret) { + ath6kl_err("Failed to get extended board file target address.\n"); + return ret; + } if (ar->target_type == TARGET_TYPE_AR6003 && board_ext_address == 0) { -- cgit v1.2.3 From eba95bceb4c9f537c6c8a5aeba4277e76599e269 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 17 Jun 2014 12:40:52 +0300 Subject: ath6kl: convert ar6004 hardware flags to firmware feature flags The functionality defined through these flags were actually firmware features which can change between firmware versions. To make it possible to support different firmware versions with the same driver, convert the flags to firmware feature flags. For backwards compatibility support for old ar6004 firmware FW API 3 or smaller images we forcefully set the feature bits in the driver. Starting from FW API 5 the firmware image needs to set them. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 6 ++++-- drivers/net/wireless/ath/ath6kl/core.c | 16 ++++++++++++++++ drivers/net/wireless/ath/ath6kl/core.h | 12 +++++++++--- drivers/net/wireless/ath/ath6kl/init.c | 16 +++++++--------- drivers/net/wireless/ath/ath6kl/usb.c | 6 ++++-- drivers/net/wireless/ath/ath6kl/wmi.c | 3 ++- 6 files changed, 42 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 0e26f4a34fda..d139f2a7160a 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2899,7 +2899,8 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, if (info->inactivity_timeout) { inactivity_timeout = info->inactivity_timeout; - if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS) + if (test_bit(ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS, + ar->fw_capabilities)) inactivity_timeout = DIV_ROUND_UP(inactivity_timeout, 60); @@ -3782,7 +3783,8 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) ath6kl_band_5ghz.ht_cap.ht_supported = false; } - if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) { + if (test_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES, + ar->fw_capabilities)) { ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff; diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index b0b652042760..0df74b245af4 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -123,6 +123,22 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) /* FIXME: we should free all firmwares in the error cases below */ + /* + * Backwards compatibility support for older ar6004 firmware images + * which do not set these feature flags. + */ + if (ar->target_type == TARGET_TYPE_AR6004 && + ar->fw_api <= 4) { + __set_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES, + ar->fw_capabilities); + __set_bit(ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS, + ar->fw_capabilities); + + if (ar->hw.id == AR6004_HW_1_3_VERSION) + __set_bit(ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, + ar->fw_capabilities); + } + /* Indicate that WMI is enabled (although not ready yet) */ set_bit(WMI_ENABLED, &ar->flag); ar->wmi = ath6kl_wmi_init(ar); diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 26b0f92424e1..bd91c4465580 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -136,6 +136,15 @@ enum ath6kl_fw_capability { */ ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, + /* WMI_SET_TX_SELECT_RATES_CMDID uses 64 bit size rate table */ + ATH6KL_FW_CAPABILITY_64BIT_RATES, + + /* WMI_AP_CONN_INACT_CMDID uses minutes as units */ + ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS, + + /* use low priority endpoint for all data */ + ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; @@ -149,9 +158,6 @@ struct ath6kl_fw_ie { }; enum ath6kl_hw_flags { - ATH6KL_HW_64BIT_RATES = BIT(0), - ATH6KL_HW_AP_INACTIVITY_MINS = BIT(1), - ATH6KL_HW_MAP_LP_ENDPOINT = BIT(2), ATH6KL_HW_SDIO_CRC_ERROR_WAR = BIT(3), }; diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 6e1e6995a634..ed086ead2601 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -93,8 +93,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x433900, .refclk_hz = 26000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_64BIT_RATES | - ATH6KL_HW_AP_INACTIVITY_MINS, + .flags = 0, .fw = { .dir = AR6004_HW_1_0_FW_DIR, @@ -114,8 +113,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x43d400, .refclk_hz = 40000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_64BIT_RATES | - ATH6KL_HW_AP_INACTIVITY_MINS, + .flags = 0, .fw = { .dir = AR6004_HW_1_1_FW_DIR, .fw = AR6004_HW_1_1_FIRMWARE_FILE, @@ -134,8 +132,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x435c00, .refclk_hz = 40000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_64BIT_RATES | - ATH6KL_HW_AP_INACTIVITY_MINS, + .flags = 0, .fw = { .dir = AR6004_HW_1_2_FW_DIR, @@ -154,9 +151,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x436400, .refclk_hz = 40000000, .uarttx_pin = 11, - .flags = ATH6KL_HW_64BIT_RATES | - ATH6KL_HW_AP_INACTIVITY_MINS | - ATH6KL_HW_MAP_LP_ENDPOINT, + .flags = 0, .fw = { .dir = AR6004_HW_1_3_FW_DIR, @@ -1575,6 +1570,9 @@ static const struct fw_capa_str_map { { ATH6KL_FW_CAPABILITY_REGDOMAIN, "regdomain" }, { ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, "sched-scan-v2" }, { ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, "hb-poll" }, + { ATH6KL_FW_CAPABILITY_64BIT_RATES, "64bit-rates" }, + { ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS, "ap-inactivity-mins" }, + { ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, "map-lp-endpoint" }, }; static const char *ath6kl_init_get_fw_capa_name(unsigned int id) diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 3afc5a463d06..e5a9e7fe2cea 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -802,7 +802,8 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, break; case WMI_DATA_VI_SVC: - if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT) + if (test_bit(ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, + ar->fw_capabilities)) *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; else *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; @@ -814,7 +815,8 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, break; case WMI_DATA_VO_SVC: - if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT) + if (test_bit(ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, + ar->fw_capabilities)) *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; else *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 4d7f9e4712e9..6ecc0a419c1a 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2838,7 +2838,8 @@ int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx, { struct ath6kl *ar = wmi->parent_dev; - if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) + if (test_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES, + ar->fw_capabilities)) return ath6kl_set_bitrate_mask64(wmi, if_idx, mask); else return ath6kl_set_bitrate_mask32(wmi, if_idx, mask); -- cgit v1.2.3 From b056397e98a9d7fb8fed9f5c837461f3dd8b0132 Mon Sep 17 00:00:00 2001 From: Jessica Wu Date: Tue, 17 Jun 2014 12:40:58 +0300 Subject: ath6kl: implement rx flush for htc pipe rx flush was not implemented for htc pipe, add that now. Doesn't fix any known issues. Also free the skb if htc control messages get canceled. Signed-off-by: Jessica Wu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc_pipe.c | 32 +++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index 756fe52a12c8..ca1a18c86c0d 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -1170,8 +1170,12 @@ static int htc_wait_recv_ctrl_message(struct htc_target *target) static void htc_rxctrl_complete(struct htc_target *context, struct htc_packet *packet) { - /* TODO, can't really receive HTC control messages yet.... */ - ath6kl_dbg(ATH6KL_DBG_HTC, "%s: invalid call function\n", __func__); + struct sk_buff *skb = packet->skb; + + if (packet->endpoint == ENDPOINT_0 && + packet->status == -ECANCELED && + skb != NULL) + dev_kfree_skb(skb); } /* htc pipe initialization */ @@ -1678,7 +1682,29 @@ static void ath6kl_htc_pipe_activity_changed(struct htc_target *target, static void ath6kl_htc_pipe_flush_rx_buf(struct htc_target *target) { - /* TODO */ + struct htc_endpoint *endpoint; + struct htc_packet *packet, *tmp_pkt; + int i; + + for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { + endpoint = &target->endpoint[i]; + + spin_lock_bh(&target->rx_lock); + + list_for_each_entry_safe(packet, tmp_pkt, + &endpoint->rx_bufq, list) { + list_del(&packet->list); + spin_unlock_bh(&target->rx_lock); + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc rx flush pkt 0x%p len %d ep %d\n", + packet, packet->buf_len, + packet->endpoint); + dev_kfree_skb(packet->pkt_cntxt); + spin_lock_bh(&target->rx_lock); + } + + spin_unlock_bh(&target->rx_lock); + } } static int ath6kl_htc_pipe_credit_setup(struct htc_target *target, -- cgit v1.2.3 From 958e1be848c92006ee4b95190d3725daf3a70034 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 17 Jun 2014 12:41:04 +0300 Subject: ath6kl: don't set hi_refclk_hz if hardware version doesn't need it Needed for ar6004 hw3.0 support. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/init.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index ed086ead2601..a0400a12b592 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -624,9 +624,12 @@ int ath6kl_configure_target(struct ath6kl *ar) return status; /* Configure target refclk_hz */ - status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz, ar->hw.refclk_hz); - if (status) - return status; + if (ar->hw.refclk_hz != 0) { + status = ath6kl_bmi_write_hi32(ar, hi_refclk_hz, + ar->hw.refclk_hz); + if (status) + return status; + } return 0; } -- cgit v1.2.3 From c1d32d3038ff4d366b837cedb95aeb1801730f2c Mon Sep 17 00:00:00 2001 From: Jessica Wu Date: Tue, 17 Jun 2014 12:41:10 +0300 Subject: ath6kl: add support wmi rate tables with mcs15 Some of the firmware versions support rate tables up to mcs15, add support for that. Signed-off-by: Jessica Wu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 3 ++ drivers/net/wireless/ath/ath6kl/init.c | 1 + drivers/net/wireless/ath/ath6kl/main.c | 11 ++++-- drivers/net/wireless/ath/ath6kl/wmi.c | 69 ++++++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath6kl/wmi.h | 2 +- 5 files changed, 77 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index bd91c4465580..23a776391e44 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -145,6 +145,9 @@ enum ath6kl_fw_capability { /* use low priority endpoint for all data */ ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, + /* ratetable is the 2 stream version (max MCS15) */ + ATH6KL_FW_CAPABILITY_RATETABLE_MCS15, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index a0400a12b592..8cd0cdfdb800 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1576,6 +1576,7 @@ static const struct fw_capa_str_map { { ATH6KL_FW_CAPABILITY_64BIT_RATES, "64bit-rates" }, { ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS, "ap-inactivity-mins" }, { ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, "map-lp-endpoint" }, + { ATH6KL_FW_CAPABILITY_RATETABLE_MCS15, "ratetable-mcs15" }, }; static const char *ath6kl_init_get_fw_capa_name(unsigned int id) diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index d56554674da4..baa447f50fda 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -702,6 +702,7 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) struct ath6kl *ar = vif->ar; struct target_stats *stats = &vif->target_stats; struct tkip_ccmp_stats *ccmp_stats; + s32 rate; u8 ac; if (len < sizeof(*tgt_stats)) @@ -731,8 +732,9 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) le32_to_cpu(tgt_stats->stats.tx.mult_retry_cnt); stats->tx_rts_fail_cnt += le32_to_cpu(tgt_stats->stats.tx.rts_fail_cnt); - stats->tx_ucast_rate = - ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.tx.ucast_rate)); + + rate = a_sle32_to_cpu(tgt_stats->stats.tx.ucast_rate); + stats->tx_ucast_rate = ath6kl_wmi_get_rate(ar->wmi, rate); stats->rx_pkt += le32_to_cpu(tgt_stats->stats.rx.pkt); stats->rx_byte += le32_to_cpu(tgt_stats->stats.rx.byte); @@ -749,8 +751,9 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) le32_to_cpu(tgt_stats->stats.rx.key_cache_miss); stats->rx_decrypt_err += le32_to_cpu(tgt_stats->stats.rx.decrypt_err); stats->rx_dupl_frame += le32_to_cpu(tgt_stats->stats.rx.dupl_frame); - stats->rx_ucast_rate = - ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.rx.ucast_rate)); + + rate = a_sle32_to_cpu(tgt_stats->stats.rx.ucast_rate); + stats->rx_ucast_rate = ath6kl_wmi_get_rate(ar->wmi, rate); ccmp_stats = &tgt_stats->stats.tkip_ccmp_stats; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 6ecc0a419c1a..94df345d08c2 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -59,6 +59,55 @@ static const s32 wmi_rate_tbl[][2] = { {0, 0} }; +static const s32 wmi_rate_tbl_mcs15[][2] = { + /* {W/O SGI, with SGI} */ + {1000, 1000}, + {2000, 2000}, + {5500, 5500}, + {11000, 11000}, + {6000, 6000}, + {9000, 9000}, + {12000, 12000}, + {18000, 18000}, + {24000, 24000}, + {36000, 36000}, + {48000, 48000}, + {54000, 54000}, + {6500, 7200}, /* HT 20, MCS 0 */ + {13000, 14400}, + {19500, 21700}, + {26000, 28900}, + {39000, 43300}, + {52000, 57800}, + {58500, 65000}, + {65000, 72200}, + {13000, 14400}, /* HT 20, MCS 8 */ + {26000, 28900}, + {39000, 43300}, + {52000, 57800}, + {78000, 86700}, + {104000, 115600}, + {117000, 130000}, + {130000, 144400}, /* HT 20, MCS 15 */ + {13500, 15000}, /*HT 40, MCS 0 */ + {27000, 30000}, + {40500, 45000}, + {54000, 60000}, + {81000, 90000}, + {108000, 120000}, + {121500, 135000}, + {135000, 150000}, + {27000, 30000}, /*HT 40, MCS 8 */ + {54000, 60000}, + {81000, 90000}, + {108000, 120000}, + {162000, 180000}, + {216000, 240000}, + {243000, 270000}, + {270000, 300000}, /*HT 40, MCS 15 */ + {0, 0} +}; + /* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */ static const u8 up_to_ac[] = { WMM_AC_BE, @@ -3280,9 +3329,11 @@ int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2) NO_SYNC_WMIFLAG); } -s32 ath6kl_wmi_get_rate(s8 rate_index) +s32 ath6kl_wmi_get_rate(struct wmi *wmi, s8 rate_index) { + struct ath6kl *ar = wmi->parent_dev; u8 sgi = 0; + s32 ret; if (rate_index == RATE_AUTO) return 0; @@ -3293,10 +3344,20 @@ s32 ath6kl_wmi_get_rate(s8 rate_index) sgi = 1; } - if (WARN_ON(rate_index > RATE_MCS_7_40)) - rate_index = RATE_MCS_7_40; + if (test_bit(ATH6KL_FW_CAPABILITY_RATETABLE_MCS15, + ar->fw_capabilities)) { + if (WARN_ON(rate_index >= ARRAY_SIZE(wmi_rate_tbl_mcs15))) + return 0; + + ret = wmi_rate_tbl_mcs15[(u32) rate_index][sgi]; + } else { + if (WARN_ON(rate_index >= ARRAY_SIZE(wmi_rate_tbl))) + return 0; - return wmi_rate_tbl[(u32) rate_index][sgi]; + ret = wmi_rate_tbl[(u32) rate_index][sgi]; + } + + return ret; } static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 7809afbb3e93..8d4d88531404 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -2632,7 +2632,7 @@ int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx, struct ath6kl_htcap *htcap); int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); -s32 ath6kl_wmi_get_rate(s8 rate_index); +s32 ath6kl_wmi_get_rate(struct wmi *wmi, s8 rate_index); int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx, __be32 ips0, __be32 ips1); -- cgit v1.2.3 From 7880377012ef48bf75498648c3bcbcb60460ff28 Mon Sep 17 00:00:00 2001 From: Jessica Wu Date: Tue, 17 Jun 2014 12:41:16 +0300 Subject: ath6kl: add support for ar6004 hw3.0 This change enables ath6kl driver to support ar6004 hw3.0. At the same time do some fixes in firmware initialisation which applies to ar6004 hw1.3 as well. Signed-off-by: Jessica Wu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 21 ++++++++++++-- drivers/net/wireless/ath/ath6kl/init.c | 52 +++++++++++++++++++++++++++++++--- drivers/net/wireless/ath/ath6kl/main.c | 6 +++- drivers/net/wireless/ath/ath6kl/usb.c | 1 + 4 files changed, 73 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 23a776391e44..2b78c863d030 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -148,6 +148,9 @@ enum ath6kl_fw_capability { /* ratetable is the 2 stream version (max MCS15) */ ATH6KL_FW_CAPABILITY_RATETABLE_MCS15, + /* firmare doesn't support IP checksumming */ + ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; @@ -167,6 +170,7 @@ enum ath6kl_hw_flags { #define ATH6KL_FW_API2_FILE "fw-2.bin" #define ATH6KL_FW_API3_FILE "fw-3.bin" #define ATH6KL_FW_API4_FILE "fw-4.bin" +#define ATH6KL_FW_API5_FILE "fw-5.bin" /* AR6003 1.0 definitions */ #define AR6003_HW_1_0_VERSION 0x300002ba @@ -224,8 +228,21 @@ enum ath6kl_hw_flags { #define AR6004_HW_1_3_VERSION 0x31c8088a #define AR6004_HW_1_3_FW_DIR "ath6k/AR6004/hw1.3" #define AR6004_HW_1_3_FIRMWARE_FILE "fw.ram.bin" -#define AR6004_HW_1_3_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin" -#define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin" +#define AR6004_HW_1_3_TCMD_FIRMWARE_FILE "utf.bin" +#define AR6004_HW_1_3_UTF_FIRMWARE_FILE "utf.bin" +#define AR6004_HW_1_3_TESTSCRIPT_FILE "nullTestFlow.bin" +#define AR6004_HW_1_3_BOARD_DATA_FILE AR6004_HW_1_3_FW_DIR "/bdata.bin" +#define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE AR6004_HW_1_3_FW_DIR "/bdata.bin" + +/* AR6004 3.0 definitions */ +#define AR6004_HW_3_0_VERSION 0x31C809F8 +#define AR6004_HW_3_0_FW_DIR "ath6k/AR6004/hw3.0" +#define AR6004_HW_3_0_FIRMWARE_FILE "fw.ram.bin" +#define AR6004_HW_3_0_TCMD_FIRMWARE_FILE "utf.bin" +#define AR6004_HW_3_0_UTF_FIRMWARE_FILE "utf.bin" +#define AR6004_HW_3_0_TESTSCRIPT_FILE "nullTestFlow.bin" +#define AR6004_HW_3_0_BOARD_DATA_FILE AR6004_HW_3_0_FW_DIR "/bdata.bin" +#define AR6004_HW_3_0_DEFAULT_BOARD_DATA_FILE AR6004_HW_3_0_FW_DIR "/bdata.bin" /* Per STA data, used in AP mode */ #define STA_PS_AWAKE BIT(0) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 8cd0cdfdb800..a61118484de6 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -149,18 +149,43 @@ static const struct ath6kl_hw hw_list[] = { .board_ext_data_addr = 0x437000, .reserved_ram_size = 7168, .board_addr = 0x436400, - .refclk_hz = 40000000, + .refclk_hz = 0, .uarttx_pin = 11, .flags = 0, .fw = { .dir = AR6004_HW_1_3_FW_DIR, .fw = AR6004_HW_1_3_FIRMWARE_FILE, + .tcmd = AR6004_HW_1_3_TCMD_FIRMWARE_FILE, + .utf = AR6004_HW_1_3_UTF_FIRMWARE_FILE, + .testscript = AR6004_HW_1_3_TESTSCRIPT_FILE, }, .fw_board = AR6004_HW_1_3_BOARD_DATA_FILE, .fw_default_board = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE, }, + { + .id = AR6004_HW_3_0_VERSION, + .name = "ar6004 hw 3.0", + .dataset_patch_addr = 0, + .app_load_addr = 0x1234, + .board_ext_data_addr = 0, + .reserved_ram_size = 7168, + .board_addr = 0x436400, + .testscript_addr = 0, + .flags = 0, + + .fw = { + .dir = AR6004_HW_3_0_FW_DIR, + .fw = AR6004_HW_3_0_FIRMWARE_FILE, + .tcmd = AR6004_HW_3_0_TCMD_FIRMWARE_FILE, + .utf = AR6004_HW_3_0_UTF_FIRMWARE_FILE, + .testscript = AR6004_HW_3_0_TESTSCRIPT_FILE, + }, + + .fw_board = AR6004_HW_3_0_BOARD_DATA_FILE, + .fw_default_board = AR6004_HW_3_0_DEFAULT_BOARD_DATA_FILE, + }, }; /* @@ -596,7 +621,9 @@ int ath6kl_configure_target(struct ath6kl *ar) * but possible in theory. */ - if (ar->target_type == TARGET_TYPE_AR6003) { + if ((ar->target_type == TARGET_TYPE_AR6003) || + (ar->version.target_ver == AR6004_HW_1_3_VERSION) || + (ar->version.target_ver == AR6004_HW_3_0_VERSION)) { param = ar->hw.board_ext_data_addr; ram_reserved_size = ar->hw.reserved_ram_size; @@ -1110,6 +1137,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar) if (ret) return ret; + ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API5_FILE); + if (ret == 0) { + ar->fw_api = 5; + goto out; + } + ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE); if (ret == 0) { ar->fw_api = 4; @@ -1236,7 +1269,13 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) } /* record the fact that Board Data IS initialized */ - ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, 1); + if ((ar->version.target_ver == AR6004_HW_1_3_VERSION) || + (ar->version.target_ver == AR6004_HW_3_0_VERSION)) + param = board_data_size; + else + param = 1; + + ath6kl_bmi_write_hi32(ar, hi_board_data_initialized, param); return ret; } @@ -1367,7 +1406,11 @@ static int ath6kl_upload_testscript(struct ath6kl *ar) } ath6kl_bmi_write_hi32(ar, hi_ota_testscript, address); - ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096); + + if ((ar->version.target_ver != AR6004_HW_1_3_VERSION) && + (ar->version.target_ver != AR6004_HW_3_0_VERSION)) + ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, 4096); + ath6kl_bmi_write_hi32(ar, hi_test_apps_related, 1); return 0; @@ -1577,6 +1620,7 @@ static const struct fw_capa_str_map { { ATH6KL_FW_CAPABILITY_AP_INACTIVITY_MINS, "ap-inactivity-mins" }, { ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, "map-lp-endpoint" }, { ATH6KL_FW_CAPABILITY_RATETABLE_MCS15, "ratetable-mcs15" }, + { ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM, "no-ip-checksum" }, }; static const char *ath6kl_init_get_fw_capa_name(unsigned int id) diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index baa447f50fda..21516bc65785 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -1293,6 +1293,8 @@ static const struct net_device_ops ath6kl_netdev_ops = { void init_netdev(struct net_device *dev) { + struct ath6kl *ar = ath6kl_priv(dev); + dev->netdev_ops = &ath6kl_netdev_ops; dev->destructor = free_netdev; dev->watchdog_timeo = ATH6KL_TX_TIMEOUT; @@ -1304,7 +1306,9 @@ void init_netdev(struct net_device *dev) WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES, 4); - dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; + if (!test_bit(ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM, + ar->fw_capabilities)) + dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; return; } diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index e5a9e7fe2cea..c44325856b81 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -1210,6 +1210,7 @@ static int ath6kl_usb_pm_reset_resume(struct usb_interface *intf) /* table of devices that work with this driver */ static struct usb_device_id ath6kl_usb_ids[] = { + {USB_DEVICE(0x0cf3, 0x9375)}, {USB_DEVICE(0x0cf3, 0x9374)}, { /* Terminating entry */ }, }; -- cgit v1.2.3 From a491a920ff5c22cc09700a2660f6eac55b1ce4c1 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 14 Jul 2014 16:07:29 +0300 Subject: ath10k: fix unregister deadlock when fw probe fails If firmware probing worker failed it called device_release_driver() which synchronously called remove() pci callback. The callback in turn waited for the worker that called it to finish resulting in a deadlock. Waiting for a completion instead of a worker, like some other drivers do, doesn't seem like the best idea either: Syscall Worker probe_fw() rmmod dev_lock() pci->remove() wait_for_completion() complete_all() device_release_driver() dev_lock() [sleep] free(ar) dev_unlock() [resume] There's no guarantee that Worker upon resuming can still access any data/code of the module. Leaving device bound to a driver is not as harmful as deadlocking so remove the call to device_release_driver() while a proper solution is figured out. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 68bed4e5c9f4..aaf5f0eea2dc 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -990,7 +990,9 @@ err_unregister_mac: err_release_fw: ath10k_core_free_firmware_files(ar); err: - device_release_driver(ar->dev); + /* TODO: It's probably a good idea to release device from the driver + * but calling device_release_driver() here will cause a deadlock. + */ return; } -- cgit v1.2.3 From 4d042654afb342386cb5c33e29843b76d598ab61 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Tue, 15 Jul 2014 02:04:13 +0530 Subject: Bluetooth: cmtp: Remove unnecessary null test This patch removes the null test on ctrl. ctrl is initialized at the beginning of the function to &session->ctrl. Since session is dereferenced prior to the null test, session must be a valid pointer, and &session->ctrl cannot be null. The following Coccinelle script is used for detecting the change: @r@ expression e,f; identifier g,y; statement S1,S2; @@ *e = &f->g <+... f->y ...+> *if (e != NULL || ...) S1 else S2 Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Marcel Holtmann --- net/bluetooth/cmtp/capi.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index cd75e4d64b90..1ca8a87a0787 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -362,12 +362,6 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb) CAPIMSG_SETCONTROL(skb->data, contr); } - if (!ctrl) { - BT_ERR("Can't find controller %d for message", session->num); - kfree_skb(skb); - return; - } - capi_ctr_handle_message(ctrl, appl, skb); } -- cgit v1.2.3 From 8024e02879ddd5042be02c70557f74cdc70b44b4 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Sun, 13 Jul 2014 19:49:37 -0700 Subject: udp: Add udp_sock_create for UDP tunnels to open listener socket Added udp_tunnel.c which can contain some common functions for UDP tunnels. The first function in this is udp_sock_create which is used to open the listener port for a UDP tunnel. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/udp_tunnel.h | 32 +++++++++++++++ net/ipv4/Kconfig | 4 ++ net/ipv4/Makefile | 1 + net/ipv4/udp_tunnel.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 include/net/udp_tunnel.h create mode 100644 net/ipv4/udp_tunnel.c diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h new file mode 100644 index 000000000000..ffd69cbded35 --- /dev/null +++ b/include/net/udp_tunnel.h @@ -0,0 +1,32 @@ +#ifndef __NET_UDP_TUNNEL_H +#define __NET_UDP_TUNNEL_H + +struct udp_port_cfg { + u8 family; + + /* Used only for kernel-created sockets */ + union { + struct in_addr local_ip; +#if IS_ENABLED(CONFIG_IPV6) + struct in6_addr local_ip6; +#endif + }; + + union { + struct in_addr peer_ip; +#if IS_ENABLED(CONFIG_IPV6) + struct in6_addr peer_ip6; +#endif + }; + + __be16 local_udp_port; + __be16 peer_udp_port; + unsigned int use_udp_checksums:1, + use_udp6_tx_checksums:1, + use_udp6_rx_checksums:1; +}; + +int udp_sock_create(struct net *net, struct udp_port_cfg *cfg, + struct socket **sockp); + +#endif diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 05c57f0fcabe..dbc10d84161f 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -307,6 +307,10 @@ config NET_IPVTI the notion of a secure tunnel for IPSEC and then use routing protocol on top. +config NET_UDP_TUNNEL + tristate + default n + config INET_AH tristate "IP: AH transformation" select XFRM_ALGO diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index f032688d20d3..8ee1cd4053ee 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_NET_IPIP) += ipip.o gre-y := gre_demux.o obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o obj-$(CONFIG_NET_IPGRE) += ip_gre.o +obj-$(CONFIG_NET_UDP_TUNNEL) += udp_tunnel.o obj-$(CONFIG_NET_IPVTI) += ip_vti.o obj-$(CONFIG_SYN_COOKIES) += syncookies.o obj-$(CONFIG_INET_AH) += ah4.o diff --git a/net/ipv4/udp_tunnel.c b/net/ipv4/udp_tunnel.c new file mode 100644 index 000000000000..61ec1a65207e --- /dev/null +++ b/net/ipv4/udp_tunnel.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int udp_sock_create(struct net *net, struct udp_port_cfg *cfg, + struct socket **sockp) +{ + int err = -EINVAL; + struct socket *sock = NULL; + +#if IS_ENABLED(CONFIG_IPV6) + if (cfg->family == AF_INET6) { + struct sockaddr_in6 udp6_addr; + + err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock); + if (err < 0) + goto error; + + sk_change_net(sock->sk, net); + + udp6_addr.sin6_family = AF_INET6; + memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6, + sizeof(udp6_addr.sin6_addr)); + udp6_addr.sin6_port = cfg->local_udp_port; + err = kernel_bind(sock, (struct sockaddr *)&udp6_addr, + sizeof(udp6_addr)); + if (err < 0) + goto error; + + if (cfg->peer_udp_port) { + udp6_addr.sin6_family = AF_INET6; + memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6, + sizeof(udp6_addr.sin6_addr)); + udp6_addr.sin6_port = cfg->peer_udp_port; + err = kernel_connect(sock, + (struct sockaddr *)&udp6_addr, + sizeof(udp6_addr), 0); + } + if (err < 0) + goto error; + + udp_set_no_check6_tx(sock->sk, !cfg->use_udp6_tx_checksums); + udp_set_no_check6_rx(sock->sk, !cfg->use_udp6_rx_checksums); + } else +#endif + if (cfg->family == AF_INET) { + struct sockaddr_in udp_addr; + + err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock); + if (err < 0) + goto error; + + sk_change_net(sock->sk, net); + + udp_addr.sin_family = AF_INET; + udp_addr.sin_addr = cfg->local_ip; + udp_addr.sin_port = cfg->local_udp_port; + err = kernel_bind(sock, (struct sockaddr *)&udp_addr, + sizeof(udp_addr)); + if (err < 0) + goto error; + + if (cfg->peer_udp_port) { + udp_addr.sin_family = AF_INET; + udp_addr.sin_addr = cfg->peer_ip; + udp_addr.sin_port = cfg->peer_udp_port; + err = kernel_connect(sock, + (struct sockaddr *)&udp_addr, + sizeof(udp_addr), 0); + if (err < 0) + goto error; + } + + sock->sk->sk_no_check_tx = !cfg->use_udp_checksums; + } else { + return -EPFNOSUPPORT; + } + + + *sockp = sock; + + return 0; + +error: + if (sock) { + kernel_sock_shutdown(sock, SHUT_RDWR); + sk_release_kernel(sock->sk); + } + *sockp = NULL; + return err; +} +EXPORT_SYMBOL(udp_sock_create); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 3ee64f39bebe1a181a1af3e4b641a9b0aae1799a Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Sun, 13 Jul 2014 19:49:42 -0700 Subject: vxlan: Call udp_sock_create In vxlan driver call common function udp_sock_create to create the listener UDP port. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/Kconfig | 1 + drivers/net/vxlan.c | 115 +++++++++++----------------------------------------- 2 files changed, 25 insertions(+), 91 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 89402c3b64f8..c6f6f69f8961 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -148,6 +148,7 @@ config VXLAN tristate "Virtual eXtensible Local Area Network (VXLAN)" depends on INET select NET_IP_TUNNEL + select NET_UDP_TUNNEL ---help--- This allows one to create vxlan virtual interfaces that provide Layer 2 Networks over Layer 3 Networks. VXLAN is often used diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index e6808f7e4e32..d3f3e5d21874 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -2339,102 +2340,37 @@ static void vxlan_del_work(struct work_struct *work) kfree_rcu(vs, rcu); } -#if IS_ENABLED(CONFIG_IPV6) -/* Create UDP socket for encapsulation receive. AF_INET6 socket - * could be used for both IPv4 and IPv6 communications, but - * users may set bindv6only=1. - */ -static struct socket *create_v6_sock(struct net *net, __be16 port, u32 flags) +static struct socket *vxlan_create_sock(struct net *net, bool ipv6, + __be16 port, u32 flags) { - struct sock *sk; struct socket *sock; - struct sockaddr_in6 vxlan_addr = { - .sin6_family = AF_INET6, - .sin6_port = port, - }; - int rc, val = 1; - - rc = sock_create_kern(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock); - if (rc < 0) { - pr_debug("UDPv6 socket create failed\n"); - return ERR_PTR(rc); - } - - /* Put in proper namespace */ - sk = sock->sk; - sk_change_net(sk, net); - - kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY, - (char *)&val, sizeof(val)); - rc = kernel_bind(sock, (struct sockaddr *)&vxlan_addr, - sizeof(struct sockaddr_in6)); - if (rc < 0) { - pr_debug("bind for UDPv6 socket %pI6:%u (%d)\n", - &vxlan_addr.sin6_addr, ntohs(vxlan_addr.sin6_port), rc); - sk_release_kernel(sk); - return ERR_PTR(rc); - } - /* At this point, IPv6 module should have been loaded in - * sock_create_kern(). - */ - BUG_ON(!ipv6_stub); - - /* Disable multicast loopback */ - inet_sk(sk)->mc_loop = 0; - - if (flags & VXLAN_F_UDP_ZERO_CSUM6_TX) - udp_set_no_check6_tx(sk, true); - - if (flags & VXLAN_F_UDP_ZERO_CSUM6_RX) - udp_set_no_check6_rx(sk, true); - - return sock; -} - -#else + struct udp_port_cfg udp_conf; + int err; -static struct socket *create_v6_sock(struct net *net, __be16 port, u32 flags) -{ - return ERR_PTR(-EPFNOSUPPORT); -} -#endif + memset(&udp_conf, 0, sizeof(udp_conf)); -static struct socket *create_v4_sock(struct net *net, __be16 port, u32 flags) -{ - struct sock *sk; - struct socket *sock; - struct sockaddr_in vxlan_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = htonl(INADDR_ANY), - .sin_port = port, - }; - int rc; - - /* Create UDP socket for encapsulation receive. */ - rc = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); - if (rc < 0) { - pr_debug("UDP socket create failed\n"); - return ERR_PTR(rc); + if (ipv6) { + udp_conf.family = AF_INET6; + udp_conf.use_udp6_tx_checksums = + !!(flags & VXLAN_F_UDP_ZERO_CSUM6_TX); + udp_conf.use_udp6_rx_checksums = + !!(flags & VXLAN_F_UDP_ZERO_CSUM6_RX); + } else { + udp_conf.family = AF_INET; + udp_conf.local_ip.s_addr = INADDR_ANY; + udp_conf.use_udp_checksums = + !!(flags & VXLAN_F_UDP_CSUM); } - /* Put in proper namespace */ - sk = sock->sk; - sk_change_net(sk, net); + udp_conf.local_udp_port = port; - rc = kernel_bind(sock, (struct sockaddr *) &vxlan_addr, - sizeof(vxlan_addr)); - if (rc < 0) { - pr_debug("bind for UDP socket %pI4:%u (%d)\n", - &vxlan_addr.sin_addr, ntohs(vxlan_addr.sin_port), rc); - sk_release_kernel(sk); - return ERR_PTR(rc); - } + /* Open UDP socket */ + err = udp_sock_create(net, &udp_conf, &sock); + if (err < 0) + return ERR_PTR(err); /* Disable multicast loopback */ - inet_sk(sk)->mc_loop = 0; - - if (!(flags & VXLAN_F_UDP_CSUM)) - sock->sk->sk_no_check_tx = 1; + inet_sk(sock->sk)->mc_loop = 0; return sock; } @@ -2460,10 +2396,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, INIT_WORK(&vs->del_work, vxlan_del_work); - if (ipv6) - sock = create_v6_sock(net, port, flags); - else - sock = create_v4_sock(net, port, flags); + sock = vxlan_create_sock(net, ipv6, port, flags); if (IS_ERR(sock)) { kfree(vs); return ERR_CAST(sock); -- cgit v1.2.3 From 85644b4d0c6f7be64dad461057d78a484b45bf5b Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Sun, 13 Jul 2014 19:49:48 -0700 Subject: l2tp: Call udp_sock_create In l2tp driver call common function udp_sock_create to create the listener UDP port. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/l2tp/Kconfig | 1 + net/l2tp/l2tp_core.c | 86 +++++++++++++++++----------------------------------- 2 files changed, 28 insertions(+), 59 deletions(-) diff --git a/net/l2tp/Kconfig b/net/l2tp/Kconfig index adb9843dd7cf..378c73b26093 100644 --- a/net/l2tp/Kconfig +++ b/net/l2tp/Kconfig @@ -6,6 +6,7 @@ menuconfig L2TP tristate "Layer Two Tunneling Protocol (L2TP)" depends on (IPV6 || IPV6=n) depends on INET + select NET_UDP_TUNNEL ---help--- Layer Two Tunneling Protocol diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index bea259043205..1109d3bb8dac 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -1358,81 +1359,46 @@ static int l2tp_tunnel_sock_create(struct net *net, { int err = -EINVAL; struct socket *sock = NULL; - struct sockaddr_in udp_addr = {0}; - struct sockaddr_l2tpip ip_addr = {0}; -#if IS_ENABLED(CONFIG_IPV6) - struct sockaddr_in6 udp6_addr = {0}; - struct sockaddr_l2tpip6 ip6_addr = {0}; -#endif + struct udp_port_cfg udp_conf; switch (cfg->encap) { case L2TP_ENCAPTYPE_UDP: + memset(&udp_conf, 0, sizeof(udp_conf)); + #if IS_ENABLED(CONFIG_IPV6) if (cfg->local_ip6 && cfg->peer_ip6) { - err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock); - if (err < 0) - goto out; - - sk_change_net(sock->sk, net); - - udp6_addr.sin6_family = AF_INET6; - memcpy(&udp6_addr.sin6_addr, cfg->local_ip6, - sizeof(udp6_addr.sin6_addr)); - udp6_addr.sin6_port = htons(cfg->local_udp_port); - err = kernel_bind(sock, (struct sockaddr *) &udp6_addr, - sizeof(udp6_addr)); - if (err < 0) - goto out; - - udp6_addr.sin6_family = AF_INET6; - memcpy(&udp6_addr.sin6_addr, cfg->peer_ip6, - sizeof(udp6_addr.sin6_addr)); - udp6_addr.sin6_port = htons(cfg->peer_udp_port); - err = kernel_connect(sock, - (struct sockaddr *) &udp6_addr, - sizeof(udp6_addr), 0); - if (err < 0) - goto out; - - if (cfg->udp6_zero_tx_checksums) - udp_set_no_check6_tx(sock->sk, true); - if (cfg->udp6_zero_rx_checksums) - udp_set_no_check6_rx(sock->sk, true); + udp_conf.family = AF_INET6; + memcpy(&udp_conf.local_ip6, cfg->local_ip6, + sizeof(udp_conf.local_ip6)); + memcpy(&udp_conf.peer_ip6, cfg->peer_ip6, + sizeof(udp_conf.peer_ip6)); + udp_conf.use_udp6_tx_checksums = + cfg->udp6_zero_tx_checksums; + udp_conf.use_udp6_rx_checksums = + cfg->udp6_zero_rx_checksums; } else #endif { - err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock); - if (err < 0) - goto out; - - sk_change_net(sock->sk, net); - - udp_addr.sin_family = AF_INET; - udp_addr.sin_addr = cfg->local_ip; - udp_addr.sin_port = htons(cfg->local_udp_port); - err = kernel_bind(sock, (struct sockaddr *) &udp_addr, - sizeof(udp_addr)); - if (err < 0) - goto out; - - udp_addr.sin_family = AF_INET; - udp_addr.sin_addr = cfg->peer_ip; - udp_addr.sin_port = htons(cfg->peer_udp_port); - err = kernel_connect(sock, - (struct sockaddr *) &udp_addr, - sizeof(udp_addr), 0); - if (err < 0) - goto out; + udp_conf.family = AF_INET; + udp_conf.local_ip = cfg->local_ip; + udp_conf.peer_ip = cfg->peer_ip; + udp_conf.use_udp_checksums = cfg->use_udp_checksums; } - if (!cfg->use_udp_checksums) - sock->sk->sk_no_check_tx = 1; + udp_conf.local_udp_port = htons(cfg->local_udp_port); + udp_conf.peer_udp_port = htons(cfg->peer_udp_port); + + err = udp_sock_create(net, &udp_conf, &sock); + if (err < 0) + goto out; break; case L2TP_ENCAPTYPE_IP: #if IS_ENABLED(CONFIG_IPV6) if (cfg->local_ip6 && cfg->peer_ip6) { + struct sockaddr_l2tpip6 ip6_addr = {0}; + err = sock_create_kern(AF_INET6, SOCK_DGRAM, IPPROTO_L2TP, &sock); if (err < 0) @@ -1461,6 +1427,8 @@ static int l2tp_tunnel_sock_create(struct net *net, } else #endif { + struct sockaddr_l2tpip ip_addr = {0}; + err = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_L2TP, &sock); if (err < 0) -- cgit v1.2.3 From 155e010edbc168f43bb332887c43e8579ee3894a Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Sun, 13 Jul 2014 19:49:56 -0700 Subject: udp: Move udp_tunnel_segment into udp_offload.c Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/ipv4/udp.c | 76 -------------------------------------------------- net/ipv4/udp_offload.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 76 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ac30e106a884..f6dfe525584f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2522,79 +2522,3 @@ void __init udp_init(void) sysctl_udp_rmem_min = SK_MEM_QUANTUM; sysctl_udp_wmem_min = SK_MEM_QUANTUM; } - -struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, - netdev_features_t features) -{ - struct sk_buff *segs = ERR_PTR(-EINVAL); - u16 mac_offset = skb->mac_header; - int mac_len = skb->mac_len; - int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb); - __be16 protocol = skb->protocol; - netdev_features_t enc_features; - int udp_offset, outer_hlen; - unsigned int oldlen; - bool need_csum; - - oldlen = (u16)~skb->len; - - if (unlikely(!pskb_may_pull(skb, tnl_hlen))) - goto out; - - skb->encapsulation = 0; - __skb_pull(skb, tnl_hlen); - skb_reset_mac_header(skb); - skb_set_network_header(skb, skb_inner_network_offset(skb)); - skb->mac_len = skb_inner_network_offset(skb); - skb->protocol = htons(ETH_P_TEB); - - need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM); - if (need_csum) - skb->encap_hdr_csum = 1; - - /* segment inner packet. */ - enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); - segs = skb_mac_gso_segment(skb, enc_features); - if (!segs || IS_ERR(segs)) { - skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset, - mac_len); - goto out; - } - - outer_hlen = skb_tnl_header_len(skb); - udp_offset = outer_hlen - tnl_hlen; - skb = segs; - do { - struct udphdr *uh; - int len; - - skb_reset_inner_headers(skb); - skb->encapsulation = 1; - - skb->mac_len = mac_len; - - skb_push(skb, outer_hlen); - skb_reset_mac_header(skb); - skb_set_network_header(skb, mac_len); - skb_set_transport_header(skb, udp_offset); - len = skb->len - udp_offset; - uh = udp_hdr(skb); - uh->len = htons(len); - - if (need_csum) { - __be32 delta = htonl(oldlen + len); - - uh->check = ~csum_fold((__force __wsum) - ((__force u32)uh->check + - (__force u32)delta)); - uh->check = gso_make_checksum(skb, ~uh->check); - - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - } - - skb->protocol = protocol; - } while ((skb = skb->next)); -out: - return segs; -} diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 546d2d439dda..4807544d018b 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -47,6 +47,82 @@ static int udp4_ufo_send_check(struct sk_buff *skb) return 0; } +struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, + netdev_features_t features) +{ + struct sk_buff *segs = ERR_PTR(-EINVAL); + u16 mac_offset = skb->mac_header; + int mac_len = skb->mac_len; + int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb); + __be16 protocol = skb->protocol; + netdev_features_t enc_features; + int udp_offset, outer_hlen; + unsigned int oldlen; + bool need_csum; + + oldlen = (u16)~skb->len; + + if (unlikely(!pskb_may_pull(skb, tnl_hlen))) + goto out; + + skb->encapsulation = 0; + __skb_pull(skb, tnl_hlen); + skb_reset_mac_header(skb); + skb_set_network_header(skb, skb_inner_network_offset(skb)); + skb->mac_len = skb_inner_network_offset(skb); + skb->protocol = htons(ETH_P_TEB); + + need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM); + if (need_csum) + skb->encap_hdr_csum = 1; + + /* segment inner packet. */ + enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); + segs = skb_mac_gso_segment(skb, enc_features); + if (!segs || IS_ERR(segs)) { + skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset, + mac_len); + goto out; + } + + outer_hlen = skb_tnl_header_len(skb); + udp_offset = outer_hlen - tnl_hlen; + skb = segs; + do { + struct udphdr *uh; + int len; + + skb_reset_inner_headers(skb); + skb->encapsulation = 1; + + skb->mac_len = mac_len; + + skb_push(skb, outer_hlen); + skb_reset_mac_header(skb); + skb_set_network_header(skb, mac_len); + skb_set_transport_header(skb, udp_offset); + len = skb->len - udp_offset; + uh = udp_hdr(skb); + uh->len = htons(len); + + if (need_csum) { + __be32 delta = htonl(oldlen + len); + + uh->check = ~csum_fold((__force __wsum) + ((__force u32)uh->check + + (__force u32)delta)); + uh->check = gso_make_checksum(skb, ~uh->check); + + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + } + + skb->protocol = protocol; + } while ((skb = skb->next)); +out: + return segs; +} + static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, netdev_features_t features) { -- cgit v1.2.3 From 3b06a00e65fbb5c526371143beaaa2221d39d577 Mon Sep 17 00:00:00 2001 From: Mateusz Wrzesinski Date: Mon, 14 Jul 2014 08:38:49 +0100 Subject: sfc: Adding PCI ID for Solarflare 7000 series 40G network adapter. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/efx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 1e274045970f..2d8622430012 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -2607,6 +2607,8 @@ static DEFINE_PCI_DEVICE_TABLE(efx_pci_table) = { .driver_data = (unsigned long) &siena_a0_nic_type}, {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x0903), /* SFC9120 PF */ .driver_data = (unsigned long) &efx_hunt_a0_nic_type}, + {PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x0923), /* SFC9140 PF */ + .driver_data = (unsigned long) &efx_hunt_a0_nic_type}, {0} /* end of list */ }; -- cgit v1.2.3 From ac331e948346f2706cd82b2d259800621b9db04f Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Mon, 14 Jul 2014 08:39:07 +0100 Subject: sfc: Add 40G link capability decoding Needed to select 40G mode on a 10G/40G capable card. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/mcdi_port.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/ethernet/sfc/mcdi_port.c b/drivers/net/ethernet/sfc/mcdi_port.c index e5fc4e1574b5..fb19b70eac01 100644 --- a/drivers/net/ethernet/sfc/mcdi_port.c +++ b/drivers/net/ethernet/sfc/mcdi_port.c @@ -183,6 +183,8 @@ static u32 mcdi_to_ethtool_cap(u32 media, u32 cap) result |= SUPPORTED_1000baseKX_Full; if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) result |= SUPPORTED_10000baseKX4_Full; + if (cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) + result |= SUPPORTED_40000baseKR4_Full; break; case MC_CMD_MEDIA_XFP: @@ -190,6 +192,12 @@ static u32 mcdi_to_ethtool_cap(u32 media, u32 cap) result |= SUPPORTED_FIBRE; break; + case MC_CMD_MEDIA_QSFP_PLUS: + result |= SUPPORTED_FIBRE; + if (cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) + result |= SUPPORTED_40000baseCR4_Full; + break; + case MC_CMD_MEDIA_BASE_T: result |= SUPPORTED_TP; if (cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) @@ -237,6 +245,8 @@ static u32 ethtool_to_mcdi_cap(u32 cap) result |= (1 << MC_CMD_PHY_CAP_1000FDX_LBN); if (cap & (SUPPORTED_10000baseT_Full | SUPPORTED_10000baseKX4_Full)) result |= (1 << MC_CMD_PHY_CAP_10000FDX_LBN); + if (cap & (SUPPORTED_40000baseCR4_Full | SUPPORTED_40000baseKR4_Full)) + result |= (1 << MC_CMD_PHY_CAP_40000FDX_LBN); if (cap & SUPPORTED_Pause) result |= (1 << MC_CMD_PHY_CAP_PAUSE_LBN); if (cap & SUPPORTED_Asym_Pause) @@ -285,6 +295,7 @@ static u32 mcdi_to_ethtool_media(u32 media) case MC_CMD_MEDIA_XFP: case MC_CMD_MEDIA_SFP_PLUS: + case MC_CMD_MEDIA_QSFP_PLUS: return PORT_FIBRE; case MC_CMD_MEDIA_BASE_T: -- cgit v1.2.3 From 43519e60ef8020e7b4f99d20b6663fab50af21dc Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 14 Jul 2014 14:09:04 +0530 Subject: ethernet: amd: move amd111e_remove_one after probe This patch moves the remove functionalities after the probe so that we can see the registered and released resources properly. Every driver follows the same concept. Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/amd8111e.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index 068dc7cad5fa..ddd09e830527 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -1701,18 +1701,6 @@ static int amd8111e_resume(struct pci_dev *pci_dev) return 0; } - -static void amd8111e_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - if (dev) { - unregister_netdev(dev); - iounmap(((struct amd8111e_priv *)netdev_priv(dev))->mmio); - free_netdev(dev); - pci_release_regions(pdev); - pci_disable_device(pdev); - } -} static void amd8111e_config_ipg(struct net_device* dev) { struct amd8111e_priv *lp = netdev_priv(dev); @@ -1970,6 +1958,19 @@ err_disable_pdev: } +static void amd8111e_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + unregister_netdev(dev); + iounmap(((struct amd8111e_priv *)netdev_priv(dev))->mmio); + free_netdev(dev); + pci_release_regions(pdev); + pci_disable_device(pdev); + } +} + static struct pci_driver amd8111e_driver = { .name = MODULE_NAME, .id_table = amd8111e_pci_tbl, -- cgit v1.2.3 From 711fec5d22e15f24b11b6c7f79cc39cb96f52b13 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 14 Jul 2014 14:09:05 +0530 Subject: ethernet: amd: use devm_ioremap() This patch replace ioremap() with the devm_ioremap() so that the resource will be freed automatically with the probe failed. Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/amd8111e.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index ddd09e830527..433107c3cd2b 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -1866,7 +1866,7 @@ static int amd8111e_probe_one(struct pci_dev *pdev, spin_lock_init(&lp->lock); - lp->mmio = ioremap(reg_addr, reg_len); + lp->mmio = devm_ioremap(&pdev->dev, reg_addr, reg_len); if (!lp->mmio) { printk(KERN_ERR "amd8111e: Cannot map device registers, " "exiting\n"); @@ -1913,7 +1913,7 @@ static int amd8111e_probe_one(struct pci_dev *pdev, if (err) { printk(KERN_ERR "amd8111e: Cannot register net device, " "exiting.\n"); - goto err_iounmap; + goto err_free_dev; } pci_set_drvdata(pdev, dev); @@ -1943,8 +1943,6 @@ static int amd8111e_probe_one(struct pci_dev *pdev, printk(KERN_INFO "%s: Couldn't detect MII PHY, assuming address 0x01\n", dev->name); return 0; -err_iounmap: - iounmap(lp->mmio); err_free_dev: free_netdev(dev); @@ -1964,7 +1962,6 @@ static void amd8111e_remove_one(struct pci_dev *pdev) if (dev) { unregister_netdev(dev); - iounmap(((struct amd8111e_priv *)netdev_priv(dev))->mmio); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); -- cgit v1.2.3 From f7afbaa557337d059603ef8c3519831c9e0d1591 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 14 Jul 2014 14:09:06 +0530 Subject: ethernet: amd: dynamic debug fixes This patch convert printk() to netdev_dbg/info/err or dev_info/err/dbg Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/amd8111e.c | 58 +++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index 433107c3cd2b..c322aa77ad1c 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -501,8 +501,7 @@ static int amd8111e_restart(struct net_device *dev) /* Enable interrupt coalesce */ if(lp->options & OPTION_INTR_COAL_ENABLE){ - printk(KERN_INFO "%s: Interrupt Coalescing Enabled.\n", - dev->name); + netdev_info(dev, "Interrupt Coalescing Enabled.\n"); amd8111e_set_coalesce(dev,ENABLE_COAL); } @@ -860,16 +859,19 @@ static int amd8111e_link_change(struct net_device* dev) else if(speed == PHY_SPEED_100) lp->link_config.speed = SPEED_100; - printk(KERN_INFO "%s: Link is Up. Speed is %s Mbps %s Duplex\n", dev->name, - (lp->link_config.speed == SPEED_100) ? "100": "10", - (lp->link_config.duplex == DUPLEX_FULL)? "Full": "Half"); + netdev_info(dev, "Link is Up. Speed is %s Mbps %s Duplex\n", + (lp->link_config.speed == SPEED_100) ? + "100" : "10", + (lp->link_config.duplex == DUPLEX_FULL) ? + "Full" : "Half"); + netif_carrier_on(dev); } else{ lp->link_config.speed = SPEED_INVALID; lp->link_config.duplex = DUPLEX_INVALID; lp->link_config.autoneg = AUTONEG_INVALID; - printk(KERN_INFO "%s: Link is Down.\n",dev->name); + netdev_info(dev, "Link is Down.\n"); netif_carrier_off(dev); } @@ -1168,7 +1170,7 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id) /* Schedule a polling routine */ __napi_schedule(&lp->napi); } else if (intren0 & RINTEN0) { - printk("************Driver bug! interrupt while in poll\n"); + netdev_dbg(dev, "************Driver bug! interrupt while in poll\n"); /* Fix by disable receive interrupts */ writel(RINTEN0, mmio + INTEN0); } @@ -1264,7 +1266,7 @@ static int amd8111e_open(struct net_device * dev ) /* Start ipg timer */ if(lp->options & OPTION_DYN_IPG_ENABLE){ add_timer(&lp->ipg_data.ipg_timer); - printk(KERN_INFO "%s: Dynamic IPG Enabled.\n",dev->name); + netdev_info(dev, "Dynamic IPG Enabled\n"); } lp->opened = 1; @@ -1623,8 +1625,8 @@ static void amd8111e_tx_timeout(struct net_device *dev) struct amd8111e_priv* lp = netdev_priv(dev); int err; - printk(KERN_ERR "%s: transmit timed out, resetting\n", - dev->name); + netdev_err(dev, "transmit timed out, resetting\n"); + spin_lock_irq(&lp->lock); err = amd8111e_restart(dev); spin_unlock_irq(&lp->lock); @@ -1807,22 +1809,19 @@ static int amd8111e_probe_one(struct pci_dev *pdev, err = pci_enable_device(pdev); if(err){ - printk(KERN_ERR "amd8111e: Cannot enable new PCI device, " - "exiting.\n"); + dev_err(&pdev->dev, "Cannot enable new PCI device\n"); return err; } if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)){ - printk(KERN_ERR "amd8111e: Cannot find PCI base address, " - "exiting.\n"); + dev_err(&pdev->dev, "Cannot find PCI base address\n"); err = -ENODEV; goto err_disable_pdev; } err = pci_request_regions(pdev, MODULE_NAME); if(err){ - printk(KERN_ERR "amd8111e: Cannot obtain PCI resources, " - "exiting.\n"); + dev_err(&pdev->dev, "Cannot obtain PCI resources\n"); goto err_disable_pdev; } @@ -1830,16 +1829,14 @@ static int amd8111e_probe_one(struct pci_dev *pdev, /* Find power-management capability. */ if (!pdev->pm_cap) { - printk(KERN_ERR "amd8111e: No Power Management capability, " - "exiting.\n"); + dev_err(&pdev->dev, "No Power Management capability\n"); err = -ENODEV; goto err_free_reg; } /* Initialize DMA */ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) < 0) { - printk(KERN_ERR "amd8111e: DMA not supported," - "exiting.\n"); + dev_err(&pdev->dev, "DMA not supported\n"); err = -ENODEV; goto err_free_reg; } @@ -1868,8 +1865,7 @@ static int amd8111e_probe_one(struct pci_dev *pdev, lp->mmio = devm_ioremap(&pdev->dev, reg_addr, reg_len); if (!lp->mmio) { - printk(KERN_ERR "amd8111e: Cannot map device registers, " - "exiting\n"); + dev_err(&pdev->dev, "Cannot map device registers\n"); err = -ENOMEM; goto err_free_dev; } @@ -1911,8 +1907,7 @@ static int amd8111e_probe_one(struct pci_dev *pdev, err = register_netdev(dev); if (err) { - printk(KERN_ERR "amd8111e: Cannot register net device, " - "exiting.\n"); + dev_err(&pdev->dev, "Cannot register net device\n"); goto err_free_dev; } @@ -1932,16 +1927,15 @@ static int amd8111e_probe_one(struct pci_dev *pdev, /* display driver and device information */ chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28; - printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n", - dev->name,MODULE_VERS); - printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet %pM\n", - dev->name, chip_version, dev->dev_addr); + dev_info(&pdev->dev, "AMD-8111e Driver Version: %s\n", MODULE_VERS); + dev_info(&pdev->dev, "[ Rev %x ] PCI 10/100BaseT Ethernet %pM\n", + chip_version, dev->dev_addr); if (lp->ext_phy_id) - printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n", - dev->name, lp->ext_phy_id, lp->ext_phy_addr); + dev_info(&pdev->dev, "Found MII PHY ID 0x%08x at address 0x%02x\n", + lp->ext_phy_id, lp->ext_phy_addr); else - printk(KERN_INFO "%s: Couldn't detect MII PHY, assuming address 0x01\n", - dev->name); + dev_info(&pdev->dev, "Couldn't detect MII PHY, assuming address 0x01\n"); + return 0; err_free_dev: -- cgit v1.2.3 From 13a4fa43bff03b745904fb1c6baaca42dd0fbf2c Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 14 Jul 2014 14:09:07 +0530 Subject: ethernet: amd: fix comment styles This patch fixes the comment style issues Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/amd8111e.c | 181 +++++++++++++++++------------------- 1 file changed, 86 insertions(+), 95 deletions(-) diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index c322aa77ad1c..a8f5c496c6cf 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -116,9 +116,8 @@ static DEFINE_PCI_DEVICE_TABLE(amd8111e_pci_tbl) = { { 0, } }; -/* -This function will read the PHY registers. -*/ + +/* This function will read the PHY registers. */ static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val) { void __iomem *mmio = lp->mmio; @@ -146,9 +145,7 @@ err_phy_read: } -/* -This function will write into PHY registers. -*/ +/* This function will write into PHY registers. */ static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32 val) { unsigned int repeat = REPEAT_CNT; @@ -176,9 +173,8 @@ err_phy_write: return -EINVAL; } -/* -This is the mii register read function provided to the mii interface. -*/ + +/* This is the mii register read function provided to the mii interface. */ static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num) { struct amd8111e_priv* lp = netdev_priv(dev); @@ -189,9 +185,7 @@ static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num) } -/* -This is the mii register write function provided to the mii interface. -*/ +/* This is the mii register write function provided to the mii interface. */ static void amd8111e_mdio_write(struct net_device * dev, int phy_id, int reg_num, int val) { struct amd8111e_priv* lp = netdev_priv(dev); @@ -199,9 +193,9 @@ static void amd8111e_mdio_write(struct net_device * dev, int phy_id, int reg_num amd8111e_write_phy(lp, phy_id, reg_num, val); } -/* -This function will set PHY speed. During initialization sets the original speed to 100 full. -*/ +/* This function will set PHY speed. During initialization sets + * the original speed to 100 full + */ static void amd8111e_set_ext_phy(struct net_device *dev) { struct amd8111e_priv *lp = netdev_priv(dev); @@ -240,10 +234,9 @@ static void amd8111e_set_ext_phy(struct net_device *dev) } -/* -This function will unmap skb->data space and will free -all transmit and receive skbuffs. -*/ +/* This function will unmap skb->data space and will free + * all transmit and receive skbuffs. + */ static int amd8111e_free_skbs(struct net_device *dev) { struct amd8111e_priv *lp = netdev_priv(dev); @@ -274,9 +267,9 @@ static int amd8111e_free_skbs(struct net_device *dev) return 0; } -/* -This will set the receive buffer length corresponding to the mtu size of networkinterface. -*/ +/* This will set the receive buffer length corresponding + * to the mtu size of networkinterface. + */ static inline void amd8111e_set_rx_buff_len(struct net_device* dev) { struct amd8111e_priv* lp = netdev_priv(dev); @@ -284,8 +277,8 @@ static inline void amd8111e_set_rx_buff_len(struct net_device* dev) if (mtu > ETH_DATA_LEN){ /* MTU + ethernet header + FCS - + optional VLAN tag + skb reserve space 2 */ - + * + optional VLAN tag + skb reserve space 2 + */ lp->rx_buff_len = mtu + ETH_HLEN + 10; lp->options |= OPTION_JUMBO_ENABLE; } else{ @@ -294,8 +287,10 @@ static inline void amd8111e_set_rx_buff_len(struct net_device* dev) } } -/* -This function will free all the previously allocated buffers, determine new receive buffer length and will allocate new receive buffers. This function also allocates and initializes both the transmitter and receive hardware descriptors. +/* This function will free all the previously allocated buffers, + * determine new receive buffer length and will allocate new receive buffers. + * This function also allocates and initializes both the transmitter + * and receive hardware descriptors. */ static int amd8111e_init_ring(struct net_device *dev) { @@ -376,7 +371,10 @@ err_free_tx_ring: err_no_mem: return -ENOMEM; } -/* This function will set the interrupt coalescing according to the input arguments */ + +/* This function will set the interrupt coalescing according + * to the input arguments + */ static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod) { unsigned int timeout; @@ -435,9 +433,7 @@ static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod) } -/* -This function initializes the device registers and starts the device. -*/ +/* This function initializes the device registers and starts the device. */ static int amd8111e_restart(struct net_device *dev) { struct amd8111e_priv *lp = netdev_priv(dev); @@ -513,9 +509,8 @@ static int amd8111e_restart(struct net_device *dev) readl(mmio+CMD0); return 0; } -/* -This function clears necessary the device registers. -*/ + +/* This function clears necessary the device registers. */ static void amd8111e_init_hw_default( struct amd8111e_priv* lp) { unsigned int reg_val; @@ -604,9 +599,8 @@ static void amd8111e_init_hw_default( struct amd8111e_priv* lp) } -/* -This function disables the interrupt and clears all the pending -interrupts in INT0 +/* This function disables the interrupt and clears all the pending + * interrupts in INT0 */ static void amd8111e_disable_interrupt(struct amd8111e_priv* lp) { @@ -624,9 +618,7 @@ static void amd8111e_disable_interrupt(struct amd8111e_priv* lp) } -/* -This function stops the chip. -*/ +/* This function stops the chip. */ static void amd8111e_stop_chip(struct amd8111e_priv* lp) { writel(RUN, lp->mmio + CMD0); @@ -635,9 +627,7 @@ static void amd8111e_stop_chip(struct amd8111e_priv* lp) readl(lp->mmio + CMD0); } -/* -This function frees the transmiter and receiver descriptor rings. -*/ +/* This function frees the transmiter and receiver descriptor rings. */ static void amd8111e_free_ring(struct amd8111e_priv* lp) { /* Free transmit and receive descriptor rings */ @@ -658,9 +648,10 @@ static void amd8111e_free_ring(struct amd8111e_priv* lp) } -/* -This function will free all the transmit skbs that are actually transmitted by the device. It will check the ownership of the skb before freeing the skb. -*/ +/* This function will free all the transmit skbs that are actually + * transmitted by the device. It will check the ownership of the + * skb before freeing the skb. + */ static int amd8111e_tx(struct net_device *dev) { struct amd8111e_priv* lp = netdev_priv(dev); @@ -723,21 +714,20 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget) goto rx_not_empty; do{ - /* process receive packets until we use the quota*/ - /* If we own the next entry, it's a new packet. Send it up. */ + /* process receive packets until we use the quota. + * If we own the next entry, it's a new packet. Send it up. + */ while(1) { status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags); if (status & OWN_BIT) break; - /* - * There is a tricky error noted by John Murphy, + /* There is a tricky error noted by John Murphy, * to Russ Nelson: Even with * full-sized * buffers it's possible for a * jabber packet to use two buffers, with only * the last correctly noting the error. */ - if(status & ERR_BIT) { /* reseting flags */ lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; @@ -770,7 +760,8 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget) new_skb = netdev_alloc_skb(dev, lp->rx_buff_len); if (!new_skb) { /* if allocation fail, - ignore that pkt and go to next one */ + * ignore that pkt and go to next one + */ lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; lp->drv_rx_errors++; goto err_next_pkt; @@ -811,8 +802,8 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget) rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK; } /* Check the interrupt status register for more packets in the - mean time. Process them since we have not used up our quota.*/ - + * mean time. Process them since we have not used up our quota. + */ intr0 = readl(mmio + INT0); /*Ack receive packets */ writel(intr0 & RINT0,mmio + INT0); @@ -832,9 +823,7 @@ rx_not_empty: return num_rx_pkt; } -/* -This function will indicate the link status to the kernel. -*/ +/* This function will indicate the link status to the kernel. */ static int amd8111e_link_change(struct net_device* dev) { struct amd8111e_priv *lp = netdev_priv(dev); @@ -877,9 +866,8 @@ static int amd8111e_link_change(struct net_device* dev) return 0; } -/* -This function reads the mib counters. -*/ + +/* This function reads the mib counters. */ static int amd8111e_read_mib(void __iomem *mmio, u8 MIB_COUNTER) { unsigned int status; @@ -897,8 +885,7 @@ static int amd8111e_read_mib(void __iomem *mmio, u8 MIB_COUNTER) return data; } -/* - * This function reads the mib registers and returns the hardware statistics. +/* This function reads the mib registers and returns the hardware statistics. * It updates previous internal driver statistics with new values. */ static struct net_device_stats *amd8111e_get_stats(struct net_device *dev) @@ -994,9 +981,10 @@ static struct net_device_stats *amd8111e_get_stats(struct net_device *dev) return new_stats; } + /* This function recalculate the interrupt coalescing mode on every interrupt -according to the datarate and the packet rate. -*/ + * according to the datarate and the packet rate. + */ static int amd8111e_calc_coalesce(struct net_device *dev) { struct amd8111e_priv *lp = netdev_priv(dev); @@ -1128,9 +1116,10 @@ static int amd8111e_calc_coalesce(struct net_device *dev) return 0; } -/* -This is device interrupt function. It handles transmit, receive,link change and hardware timer interrupts. -*/ + +/* This is device interrupt function. It handles transmit, + * receive,link change and hardware timer interrupts. + */ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id) { @@ -1207,9 +1196,10 @@ static void amd8111e_poll(struct net_device *dev) #endif -/* -This function closes the network interface and updates the statistics so that most recent statistics will be available after the interface is down. -*/ +/* This function closes the network interface and updates + * the statistics so that most recent statistics will be + * available after the interface is down. + */ static int amd8111e_close(struct net_device * dev) { struct amd8111e_priv *lp = netdev_priv(dev); @@ -1240,8 +1230,10 @@ static int amd8111e_close(struct net_device * dev) lp->opened = 0; return 0; } -/* This function opens new interface.It requests irq for the device, initializes the device,buffers and descriptors, and starts the device. -*/ + +/* This function opens new interface.It requests irq for the device, + * initializes the device,buffers and descriptors, and starts the device. + */ static int amd8111e_open(struct net_device * dev ) { struct amd8111e_priv *lp = netdev_priv(dev); @@ -1277,9 +1269,10 @@ static int amd8111e_open(struct net_device * dev ) return 0; } -/* -This function checks if there is any transmit descriptors available to queue more packet. -*/ + +/* This function checks if there is any transmit descriptors + * available to queue more packet. + */ static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp ) { int tx_index = lp->tx_idx & TX_BUFF_MOD_MASK; @@ -1289,10 +1282,12 @@ static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp ) return 0; } -/* -This function will queue the transmit packets to the descriptors and will trigger the send operation. It also initializes the transmit descriptors with buffer physical address, byte count, ownership to hardware etc. -*/ +/* This function will queue the transmit packets to the + * descriptors and will trigger the send operation. It also + * initializes the transmit descriptors with buffer physical address, + * byte count, ownership to hardware etc. + */ static netdev_tx_t amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) { @@ -1340,9 +1335,7 @@ static netdev_tx_t amd8111e_start_xmit(struct sk_buff *skb, spin_unlock_irqrestore(&lp->lock, flags); return NETDEV_TX_OK; } -/* -This function returns all the memory mapped registers of the device. -*/ +/* This function returns all the memory mapped registers of the device. */ static void amd8111e_read_regs(struct amd8111e_priv *lp, u32 *buf) { void __iomem *mmio = lp->mmio; @@ -1363,10 +1356,9 @@ static void amd8111e_read_regs(struct amd8111e_priv *lp, u32 *buf) } -/* -This function sets promiscuos mode, all-multi mode or the multicast address -list to the device. -*/ +/* This function sets promiscuos mode, all-multi mode or the multicast address + * list to the device. + */ static void amd8111e_set_multicast_list(struct net_device *dev) { struct netdev_hw_addr *ha; @@ -1503,10 +1495,10 @@ static const struct ethtool_ops ops = { .set_wol = amd8111e_set_wol, }; -/* -This function handles all the ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application. -*/ - +/* This function handles all the ethtool ioctls. It gives driver info, + * gets/sets driver speed, gets memory mapped register values, forces + * auto negotiation, sets/gets WOL options for ethtool application. + */ static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd) { struct mii_ioctl_data *data = if_mii(ifr); @@ -1561,9 +1553,9 @@ static int amd8111e_set_mac_address(struct net_device *dev, void *p) return 0; } -/* -This function changes the mtu of the device. It restarts the device to initialize the descriptor with new receive buffers. -*/ +/* This function changes the mtu of the device. It restarts the device to + * initialize the descriptor with new receive buffers. + */ static int amd8111e_change_mtu(struct net_device *dev, int new_mtu) { struct amd8111e_priv *lp = netdev_priv(dev); @@ -1574,7 +1566,8 @@ static int amd8111e_change_mtu(struct net_device *dev, int new_mtu) if (!netif_running(dev)) { /* new_mtu will be used - when device starts netxt time */ + * when device starts netxt time + */ dev->mtu = new_mtu; return 0; } @@ -1614,8 +1607,7 @@ static int amd8111e_enable_link_change(struct amd8111e_priv* lp) return 0; } -/* - * This function is called when a packet transmission fails to complete +/* This function is called when a packet transmission fails to complete * within a reasonable period, on the assumption that an interrupt have * failed or the interface is locked up. This function will reinitialize * the hardware. @@ -1925,7 +1917,6 @@ static int amd8111e_probe_one(struct pci_dev *pdev, } /* display driver and device information */ - chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28; dev_info(&pdev->dev, "AMD-8111e Driver Version: %s\n", MODULE_VERS); dev_info(&pdev->dev, "[ Rev %x ] PCI 10/100BaseT Ethernet %pM\n", -- cgit v1.2.3 From ba69a3d78e4f51e65933a86b8b107c86709bb2f5 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 14 Jul 2014 14:09:08 +0530 Subject: ethernet: amd: fix pci device ids Normally any device ids will be above the corresponding device driver structure. This patch moves the pci device ids and MODULE_DEVICE_TABLE() above the pci driver structure. Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/amd8111e.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index a8f5c496c6cf..9f8a15e3b8bb 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -101,7 +101,6 @@ Revision History: MODULE_AUTHOR("Advanced Micro Devices, Inc."); MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version "MODULE_VERS); MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl); module_param_array(speed_duplex, int, NULL, 0); MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotiate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); module_param_array(coalesce, bool, NULL, 0); @@ -109,14 +108,6 @@ MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0 module_param_array(dynamic_ipg, bool, NULL, 0); MODULE_PARM_DESC(dynamic_ipg, "Enable or Disable dynamic IPG, 1: Enable, 0: Disable"); -static DEFINE_PCI_DEVICE_TABLE(amd8111e_pci_tbl) = { - - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD8111E_7462, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { 0, } - -}; - /* This function will read the PHY registers. */ static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val) { @@ -1953,6 +1944,17 @@ static void amd8111e_remove_one(struct pci_dev *pdev) } } +static const struct pci_device_id amd8111e_pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_AMD, + .device = PCI_DEVICE_ID_AMD8111E_7462, + }, + { + .vendor = 0, + } +}; +MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl); + static struct pci_driver amd8111e_driver = { .name = MODULE_NAME, .id_table = amd8111e_pci_tbl, -- cgit v1.2.3 From 46c73ecc6168586c7628b87ac1d0436eca9574dd Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 14 Jul 2014 14:09:09 +0530 Subject: ethernet: amd: fix 'foo* bar' This patch fix the 'foo*' bar with 'foo *bar' and (foo*) with (foo *). Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/amd8111e.c | 76 +++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index 9f8a15e3b8bb..841e6558db68 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -109,7 +109,8 @@ module_param_array(dynamic_ipg, bool, NULL, 0); MODULE_PARM_DESC(dynamic_ipg, "Enable or Disable dynamic IPG, 1: Enable, 0: Disable"); /* This function will read the PHY registers. */ -static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val) +static int amd8111e_read_phy(struct amd8111e_priv *lp, + int phy_id, int reg, u32 *val) { void __iomem *mmio = lp->mmio; unsigned int reg_val; @@ -137,7 +138,8 @@ err_phy_read: } /* This function will write into PHY registers. */ -static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32 val) +static int amd8111e_write_phy(struct amd8111e_priv *lp, + int phy_id, int reg, u32 val) { unsigned int repeat = REPEAT_CNT; void __iomem *mmio = lp->mmio; @@ -166,9 +168,9 @@ err_phy_write: } /* This is the mii register read function provided to the mii interface. */ -static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num) +static int amd8111e_mdio_read(struct net_device *dev, int phy_id, int reg_num) { - struct amd8111e_priv* lp = netdev_priv(dev); + struct amd8111e_priv *lp = netdev_priv(dev); unsigned int reg_val; amd8111e_read_phy(lp,phy_id,reg_num,®_val); @@ -177,9 +179,10 @@ static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num) } /* This is the mii register write function provided to the mii interface. */ -static void amd8111e_mdio_write(struct net_device * dev, int phy_id, int reg_num, int val) +static void amd8111e_mdio_write(struct net_device *dev, + int phy_id, int reg_num, int val) { - struct amd8111e_priv* lp = netdev_priv(dev); + struct amd8111e_priv *lp = netdev_priv(dev); amd8111e_write_phy(lp, phy_id, reg_num, val); } @@ -231,7 +234,7 @@ static void amd8111e_set_ext_phy(struct net_device *dev) static int amd8111e_free_skbs(struct net_device *dev) { struct amd8111e_priv *lp = netdev_priv(dev); - struct sk_buff* rx_skbuff; + struct sk_buff *rx_skbuff; int i; /* Freeing transmit skbs */ @@ -261,9 +264,9 @@ static int amd8111e_free_skbs(struct net_device *dev) /* This will set the receive buffer length corresponding * to the mtu size of networkinterface. */ -static inline void amd8111e_set_rx_buff_len(struct net_device* dev) +static inline void amd8111e_set_rx_buff_len(struct net_device *dev) { - struct amd8111e_priv* lp = netdev_priv(dev); + struct amd8111e_priv *lp = netdev_priv(dev); unsigned int mtu = dev->mtu; if (mtu > ETH_DATA_LEN){ @@ -366,14 +369,14 @@ err_no_mem: /* This function will set the interrupt coalescing according * to the input arguments */ -static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod) +static int amd8111e_set_coalesce(struct net_device *dev, enum coal_mode cmod) { unsigned int timeout; unsigned int event_count; struct amd8111e_priv *lp = netdev_priv(dev); void __iomem *mmio = lp->mmio; - struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf; + struct amd8111e_coalesce_conf *coal_conf = &lp->coal_conf; switch(cmod) @@ -502,7 +505,7 @@ static int amd8111e_restart(struct net_device *dev) } /* This function clears necessary the device registers. */ -static void amd8111e_init_hw_default( struct amd8111e_priv* lp) +static void amd8111e_init_hw_default(struct amd8111e_priv *lp) { unsigned int reg_val; unsigned int logic_filter[2] ={0,}; @@ -572,7 +575,7 @@ static void amd8111e_init_hw_default( struct amd8111e_priv* lp) writew(MIB_CLEAR, mmio + MIB_ADDR); /* Clear LARF */ - amd8111e_writeq(*(u64*)logic_filter,mmio+LADRF); + amd8111e_writeq(*(u64 *)logic_filter, mmio + LADRF); /* SRAM_SIZE register */ reg_val = readl(mmio + SRAM_SIZE); @@ -593,7 +596,7 @@ static void amd8111e_init_hw_default( struct amd8111e_priv* lp) /* This function disables the interrupt and clears all the pending * interrupts in INT0 */ -static void amd8111e_disable_interrupt(struct amd8111e_priv* lp) +static void amd8111e_disable_interrupt(struct amd8111e_priv *lp) { u32 intr0; @@ -610,7 +613,7 @@ static void amd8111e_disable_interrupt(struct amd8111e_priv* lp) } /* This function stops the chip. */ -static void amd8111e_stop_chip(struct amd8111e_priv* lp) +static void amd8111e_stop_chip(struct amd8111e_priv *lp) { writel(RUN, lp->mmio + CMD0); @@ -619,7 +622,7 @@ static void amd8111e_stop_chip(struct amd8111e_priv* lp) } /* This function frees the transmiter and receiver descriptor rings. */ -static void amd8111e_free_ring(struct amd8111e_priv* lp) +static void amd8111e_free_ring(struct amd8111e_priv *lp) { /* Free transmit and receive descriptor rings */ if(lp->rx_ring){ @@ -645,7 +648,7 @@ static void amd8111e_free_ring(struct amd8111e_priv* lp) */ static int amd8111e_tx(struct net_device *dev) { - struct amd8111e_priv* lp = netdev_priv(dev); + struct amd8111e_priv *lp = netdev_priv(dev); int tx_index = lp->tx_complete_idx & TX_RING_DR_MOD_MASK; int status; /* Complete all the transmit packet */ @@ -815,7 +818,7 @@ rx_not_empty: } /* This function will indicate the link status to the kernel. */ -static int amd8111e_link_change(struct net_device* dev) +static int amd8111e_link_change(struct net_device *dev) { struct amd8111e_priv *lp = netdev_priv(dev); int status0,speed; @@ -979,7 +982,7 @@ static struct net_device_stats *amd8111e_get_stats(struct net_device *dev) static int amd8111e_calc_coalesce(struct net_device *dev) { struct amd8111e_priv *lp = netdev_priv(dev); - struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf; + struct amd8111e_coalesce_conf *coal_conf = &lp->coal_conf; int tx_pkt_rate; int rx_pkt_rate; int tx_data_rate; @@ -1114,7 +1117,7 @@ static int amd8111e_calc_coalesce(struct net_device *dev) static irqreturn_t amd8111e_interrupt(int irq, void *dev_id) { - struct net_device * dev = (struct net_device *) dev_id; + struct net_device *dev = (struct net_device *)dev_id; struct amd8111e_priv *lp = netdev_priv(dev); void __iomem *mmio = lp->mmio; unsigned int intr0, intren0; @@ -1191,7 +1194,7 @@ static void amd8111e_poll(struct net_device *dev) * the statistics so that most recent statistics will be * available after the interface is down. */ -static int amd8111e_close(struct net_device * dev) +static int amd8111e_close(struct net_device *dev) { struct amd8111e_priv *lp = netdev_priv(dev); netif_stop_queue(dev); @@ -1225,7 +1228,7 @@ static int amd8111e_close(struct net_device * dev) /* This function opens new interface.It requests irq for the device, * initializes the device,buffers and descriptors, and starts the device. */ -static int amd8111e_open(struct net_device * dev ) +static int amd8111e_open(struct net_device *dev) { struct amd8111e_priv *lp = netdev_priv(dev); @@ -1264,7 +1267,7 @@ static int amd8111e_open(struct net_device * dev ) /* This function checks if there is any transmit descriptors * available to queue more packet. */ -static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp ) +static int amd8111e_tx_queue_avail(struct amd8111e_priv *lp) { int tx_index = lp->tx_idx & TX_BUFF_MOD_MASK; if (lp->tx_skbuff[tx_index]) @@ -1280,7 +1283,7 @@ static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp ) * byte count, ownership to hardware etc. */ static netdev_tx_t amd8111e_start_xmit(struct sk_buff *skb, - struct net_device * dev) + struct net_device *dev) { struct amd8111e_priv *lp = netdev_priv(dev); int tx_index; @@ -1368,14 +1371,14 @@ static void amd8111e_set_multicast_list(struct net_device *dev) /* get all multicast packet */ mc_filter[1] = mc_filter[0] = 0xffffffff; lp->options |= OPTION_MULTICAST_ENABLE; - amd8111e_writeq(*(u64*)mc_filter,lp->mmio + LADRF); + amd8111e_writeq(*(u64 *)mc_filter, lp->mmio + LADRF); return; } if (netdev_mc_empty(dev)) { /* get only own packets */ mc_filter[1] = mc_filter[0] = 0; lp->options &= ~OPTION_MULTICAST_ENABLE; - amd8111e_writeq(*(u64*)mc_filter,lp->mmio + LADRF); + amd8111e_writeq(*(u64 *)mc_filter, lp->mmio + LADRF); /* disable promiscuous mode */ writel(PROM, lp->mmio + CMD2); return; @@ -1387,14 +1390,15 @@ static void amd8111e_set_multicast_list(struct net_device *dev) bit_num = (ether_crc_le(ETH_ALEN, ha->addr) >> 26) & 0x3f; mc_filter[bit_num >> 5] |= 1 << (bit_num & 31); } - amd8111e_writeq(*(u64*)mc_filter,lp->mmio+ LADRF); + amd8111e_writeq(*(u64 *)mc_filter, lp->mmio + LADRF); /* To eliminate PCI posting bug */ readl(lp->mmio + CMD2); } -static void amd8111e_get_drvinfo(struct net_device* dev, struct ethtool_drvinfo *info) +static void amd8111e_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) { struct amd8111e_priv *lp = netdev_priv(dev); struct pci_dev *pci_dev = lp->pci_dev; @@ -1490,7 +1494,7 @@ static const struct ethtool_ops ops = { * gets/sets driver speed, gets memory mapped register values, forces * auto negotiation, sets/gets WOL options for ethtool application. */ -static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd) +static int amd8111e_ioctl(struct net_device *dev , struct ifreq *ifr, int cmd) { struct mii_ioctl_data *data = if_mii(ifr); struct amd8111e_priv *lp = netdev_priv(dev); @@ -1577,7 +1581,7 @@ static int amd8111e_change_mtu(struct net_device *dev, int new_mtu) return err; } -static int amd8111e_enable_magicpkt(struct amd8111e_priv* lp) +static int amd8111e_enable_magicpkt(struct amd8111e_priv *lp) { writel( VAL1|MPPLBA, lp->mmio + CMD3); writel( VAL0|MPEN_SW, lp->mmio + CMD7); @@ -1587,7 +1591,7 @@ static int amd8111e_enable_magicpkt(struct amd8111e_priv* lp) return 0; } -static int amd8111e_enable_link_change(struct amd8111e_priv* lp) +static int amd8111e_enable_link_change(struct amd8111e_priv *lp) { /* Adapter is already stoped/suspended/interrupt-disabled */ @@ -1605,7 +1609,7 @@ static int amd8111e_enable_link_change(struct amd8111e_priv* lp) */ static void amd8111e_tx_timeout(struct net_device *dev) { - struct amd8111e_priv* lp = netdev_priv(dev); + struct amd8111e_priv *lp = netdev_priv(dev); int err; netdev_err(dev, "transmit timed out, resetting\n"); @@ -1686,10 +1690,10 @@ static int amd8111e_resume(struct pci_dev *pci_dev) return 0; } -static void amd8111e_config_ipg(struct net_device* dev) +static void amd8111e_config_ipg(struct net_device *dev) { struct amd8111e_priv *lp = netdev_priv(dev); - struct ipg_info* ipg_data = &lp->ipg_data; + struct ipg_info *ipg_data = &lp->ipg_data; void __iomem *mmio = lp->mmio; unsigned int prev_col_cnt = ipg_data->col_cnt; unsigned int total_col_cnt; @@ -1787,8 +1791,8 @@ static int amd8111e_probe_one(struct pci_dev *pdev, { int err, i; unsigned long reg_addr,reg_len; - struct amd8111e_priv* lp; - struct net_device* dev; + struct amd8111e_priv *lp; + struct net_device *dev; err = pci_enable_device(pdev); if(err){ -- cgit v1.2.3 From 5bf8a7481d21a669dd9dd874c00f7815a878111a Mon Sep 17 00:00:00 2001 From: Chin-Ran Lo Date: Mon, 14 Jul 2014 21:05:37 -0700 Subject: Bluetooth: btmrvl: avoid sending data to firmware after hs_activated We should suspend hci device and purge remaining data in tx queue before enabling host sleep in firmware. If any data is sent to firmware after host sleep is activated, firmware may end up sending a TX_DONE interrupt to driver. If this interrupt gets delivered to host while the SDIO host controller is suspending, it may crash the system. Conversely, in resume handler, we should resume hci device after host sleep is de-activated. Signed-off-by: Chin-Ran Lo Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_sdio.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index efff06438b02..3e683b153259 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1169,6 +1169,10 @@ static int btmrvl_sdio_suspend(struct device *dev) } priv = card->priv; + hcidev = priv->btmrvl_dev.hcidev; + BT_DBG("%s: SDIO suspend", hcidev->name); + hci_suspend_dev(hcidev); + skb_queue_purge(&priv->adapter->tx_queue); if (priv->adapter->hs_state != HS_ACTIVATED) { if (btmrvl_enable_hs(priv)) { @@ -1176,10 +1180,6 @@ static int btmrvl_sdio_suspend(struct device *dev) return -EBUSY; } } - hcidev = priv->btmrvl_dev.hcidev; - BT_DBG("%s: SDIO suspend", hcidev->name); - hci_suspend_dev(hcidev); - skb_queue_purge(&priv->adapter->tx_queue); priv->adapter->is_suspended = true; @@ -1221,13 +1221,13 @@ static int btmrvl_sdio_resume(struct device *dev) return 0; } - priv->adapter->is_suspended = false; - hcidev = priv->btmrvl_dev.hcidev; - BT_DBG("%s: SDIO resume", hcidev->name); - hci_resume_dev(hcidev); priv->hw_wakeup_firmware(priv); priv->adapter->hs_state = HS_DEACTIVATED; + hcidev = priv->btmrvl_dev.hcidev; BT_DBG("%s: HS DEACTIVATED in resume!", hcidev->name); + priv->adapter->is_suspended = false; + BT_DBG("%s: SDIO resume", hcidev->name); + hci_resume_dev(hcidev); return 0; } -- cgit v1.2.3 From 3a19b6feb26295fe03c9242a72084d2f32dcaac4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 15 Jul 2014 08:07:59 +0300 Subject: Bluetooth: Remove unnecessary params variable from process_adv_report() The params variable was just used for storing the return value from the hci_pend_le_action_lookup() function and then checking whether it's NULL or not. We can simplify the code by checking the return value directly. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8980bd24b8c0..bf2926b2e4a9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4314,14 +4314,11 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, * device found events. */ if (hdev->le_scan_type == LE_SCAN_PASSIVE) { - struct hci_conn_params *param; - if (type == LE_ADV_DIRECT_IND) return; - param = hci_pend_le_action_lookup(&hdev->pend_le_reports, - bdaddr, bdaddr_type); - if (!param) + if (!hci_pend_le_action_lookup(&hdev->pend_le_reports, + bdaddr, bdaddr_type)) return; if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND) -- cgit v1.2.3 From c6bf7e5f4a2588bdee97b28b76f9c3605b11ec03 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Fri, 20 Jun 2014 12:59:34 +0100 Subject: can: c_can: convert to use devm * api This patch uses devm_* APIs as they are device managed and make code simpler. Signed-off-by: Lad, Prabhakar Signed-off-by: Marc Kleine-Budde --- drivers/net/can/c_can/c_can_platform.c | 43 ++++++++-------------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index 824108cd9fd5..e29b6d051103 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -208,40 +208,31 @@ static int c_can_plat_probe(struct platform_device *pdev) } /* get the appropriate clk */ - clk = clk_get(&pdev->dev, NULL); + clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { - dev_err(&pdev->dev, "no clock defined\n"); - ret = -ENODEV; + ret = PTR_ERR(clk); goto exit; } /* get the platform data */ - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); - if (!mem || irq <= 0) { + if (irq <= 0) { ret = -ENODEV; - goto exit_free_clk; - } - - if (!request_mem_region(mem->start, resource_size(mem), - KBUILD_MODNAME)) { - dev_err(&pdev->dev, "resource unavailable\n"); - ret = -ENODEV; - goto exit_free_clk; + goto exit; } - addr = ioremap(mem->start, resource_size(mem)); - if (!addr) { - dev_err(&pdev->dev, "failed to map can port\n"); - ret = -ENOMEM; - goto exit_release_mem; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + addr = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(addr)) { + ret = PTR_ERR(addr); + goto exit; } /* allocate the c_can device */ dev = alloc_c_can_dev(); if (!dev) { ret = -ENOMEM; - goto exit_iounmap; + goto exit; } priv = netdev_priv(dev); @@ -321,12 +312,6 @@ static int c_can_plat_probe(struct platform_device *pdev) exit_free_device: free_c_can_dev(dev); -exit_iounmap: - iounmap(addr); -exit_release_mem: - release_mem_region(mem->start, resource_size(mem)); -exit_free_clk: - clk_put(clk); exit: dev_err(&pdev->dev, "probe failed\n"); @@ -336,18 +321,10 @@ exit: static int c_can_plat_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); - struct c_can_priv *priv = netdev_priv(dev); - struct resource *mem; unregister_c_can_dev(dev); free_c_can_dev(dev); - iounmap(priv->base); - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, resource_size(mem)); - - clk_put(priv->priv); return 0; } -- cgit v1.2.3 From f736d9985e69e72d9a2ebfd131a72ee8f870c6f3 Mon Sep 17 00:00:00 2001 From: Nikita Edward Baruzdin Date: Fri, 11 Jul 2014 16:13:21 +0400 Subject: can: netlink: Remove space before tab Fixes the corresponing checkpatch.pl warning. Signed-off-by: Nikita Edward Baruzdin Acked-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- include/uapi/linux/can/netlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h index 813d11f54977..3bbf5c7e1500 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -92,7 +92,7 @@ struct can_ctrlmode { }; #define CAN_CTRLMODE_LOOPBACK 0x01 /* Loopback mode */ -#define CAN_CTRLMODE_LISTENONLY 0x02 /* Listen-only mode */ +#define CAN_CTRLMODE_LISTENONLY 0x02 /* Listen-only mode */ #define CAN_CTRLMODE_3_SAMPLES 0x04 /* Triple sampling mode */ #define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */ #define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */ -- cgit v1.2.3 From 4b9e1bab12c9b6de965268c2fbe6ebbb35dddd89 Mon Sep 17 00:00:00 2001 From: Nikita Edward Baruzdin Date: Fri, 11 Jul 2014 16:13:22 +0400 Subject: can: netlink: Add CAN_CTRLMODE_PRESUME_ACK flag Most CAN controllers have a support for ignoring ACK absence. Some of them refer to this feature as a self test mode (e. g. SJA1000) and some include it as a part of a loopback mode (e. g. MCP2510). Setting the introduced flag via netlink should make CAN controller perform a successful transmission, even if there is no acknowledgement (dominant ACK bit) received. Signed-off-by: Nikita Edward Baruzdin Acked-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- include/uapi/linux/can/netlink.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h index 3bbf5c7e1500..3e4323a3918d 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -97,6 +97,7 @@ struct can_ctrlmode { #define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */ #define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */ #define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */ +#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */ /* * CAN device statistics -- cgit v1.2.3 From dcf9e152670ea74dec24ec9ad57c495e631edba9 Mon Sep 17 00:00:00 2001 From: Nikita Edward Baruzdin Date: Fri, 11 Jul 2014 16:13:20 +0400 Subject: can: sja1000: Add support for CAN_CTRLMODE_LOOPBACK This adds support for hardware loopback in SJA1000 by utilising its self reception request (SRR) feature. Upon SRR the message is transmitted and received simultaneously, meaning you can't have hardware loopback without actually sending a message to the CAN bus in case of SJA1000. Signed-off-by: Nikita Edward Baruzdin Acked-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/sja1000.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index f31499a32d7d..45400d9aeedb 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -278,6 +278,7 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, uint8_t dlc; canid_t id; uint8_t dreg; + u8 cmd_reg_val = 0x00; int i; if (can_dropped_invalid_skb(dev, skb)) @@ -312,9 +313,14 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb, can_put_echo_skb(skb, dev, 0); if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) - sja1000_write_cmdreg(priv, CMD_TR | CMD_AT); + cmd_reg_val |= CMD_AT; + + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) + cmd_reg_val |= CMD_SRR; else - sja1000_write_cmdreg(priv, CMD_TR); + cmd_reg_val |= CMD_TR; + + sja1000_write_cmdreg(priv, cmd_reg_val); return NETDEV_TX_OK; } @@ -622,9 +628,11 @@ struct net_device *alloc_sja1000dev(int sizeof_priv) priv->can.do_set_bittiming = sja1000_set_bittiming; priv->can.do_set_mode = sja1000_set_mode; priv->can.do_get_berr_counter = sja1000_get_berr_counter; - priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | - CAN_CTRLMODE_BERR_REPORTING | CAN_CTRLMODE_LISTENONLY | - CAN_CTRLMODE_ONE_SHOT; + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | + CAN_CTRLMODE_LISTENONLY | + CAN_CTRLMODE_3_SAMPLES | + CAN_CTRLMODE_ONE_SHOT | + CAN_CTRLMODE_BERR_REPORTING; spin_lock_init(&priv->cmdreg_lock); -- cgit v1.2.3 From 5b853ec3494e34eb4882f65ebbcd04b495ff3c85 Mon Sep 17 00:00:00 2001 From: Nikita Edward Baruzdin Date: Fri, 11 Jul 2014 16:13:23 +0400 Subject: can: sja1000: Add support for CAN_CTRLMODE_PRESUME_ACK SJA1000 has a self test mode (STM) which does not require acknowledgement for the successful message transmission. In this mode a node test is possible without any other active node on the bus. This patch adds a possibility to set STM for SJA1000 controller through specifying the corresponding CAN_CTRLMODE_PRESUME_ACK netlink flag. Signed-off-by: Nikita Edward Baruzdin Acked-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/sja1000.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 45400d9aeedb..d1692154ed1b 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -141,6 +141,7 @@ static void set_normal_mode(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); unsigned char status = priv->read_reg(priv, SJA1000_MOD); + u8 mod_reg_val = 0x00; int i; for (i = 0; i < 100; i++) { @@ -158,9 +159,10 @@ static void set_normal_mode(struct net_device *dev) /* set chip to normal mode */ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) - priv->write_reg(priv, SJA1000_MOD, MOD_LOM); - else - priv->write_reg(priv, SJA1000_MOD, 0x00); + mod_reg_val |= MOD_LOM; + if (priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK) + mod_reg_val |= MOD_STM; + priv->write_reg(priv, SJA1000_MOD, mod_reg_val); udelay(10); @@ -632,7 +634,8 @@ struct net_device *alloc_sja1000dev(int sizeof_priv) CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_ONE_SHOT | - CAN_CTRLMODE_BERR_REPORTING; + CAN_CTRLMODE_BERR_REPORTING | + CAN_CTRLMODE_PRESUME_ACK; spin_lock_init(&priv->cmdreg_lock); -- cgit v1.2.3 From 2374b18684dfed2a0588efe4df716d16554da467 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 14 Jul 2014 16:25:25 +0300 Subject: ath10k: fix bmi exchange tx/rx race It was possible for tx completion not to be processed. In that case an old stack pointer was left on copy engine tx ring. Next bmi exchange would immediately pop it and use complete() on the completion struct there causing corruption. Make sure to wait for both tx and rx completions properly. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 11 +++-------- drivers/net/wireless/ath/ath10k/pci.h | 3 ++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index d0004d59c97e..06840d101c45 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1362,8 +1362,6 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr); } - init_completion(&xfer.done); - ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0); if (ret) goto err_resp; @@ -1414,10 +1412,7 @@ static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state) &nbytes, &transfer_id)) return; - if (xfer->wait_for_resp) - return; - - complete(&xfer->done); + xfer->tx_done = true; } static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) @@ -1438,7 +1433,7 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) } xfer->resp_len = nbytes; - complete(&xfer->done); + xfer->rx_done = true; } static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, @@ -1451,7 +1446,7 @@ static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, ath10k_pci_bmi_send_done(tx_pipe); ath10k_pci_bmi_recv_data(rx_pipe); - if (completion_done(&xfer->done)) + if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp)) return 0; schedule(); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index dfdebb4157aa..940129209990 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -38,7 +38,8 @@ #define DIAG_TRANSFER_LIMIT 2048 struct bmi_xfer { - struct completion done; + bool tx_done; + bool rx_done; bool wait_for_resp; u32 resp_len; }; -- cgit v1.2.3 From 993619443774f7ef4df3b98655df4c3bf298548c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 14 Jul 2014 16:25:25 +0300 Subject: ath10k: sanitize tx ring index access properly The tx ring index was immediately trimmed with a bitmask. This discarded the 0xFFFFFFFF error case (which theoretically can happen when a device is abruptly disconnected) and led to using an invalid tx ring index. This could lead to memory corruption. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index d185dc0cd12b..4333107ecf37 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -603,16 +603,19 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, if (ret) return ret; - src_ring->hw_index = - ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); - src_ring->hw_index &= nentries_mask; + read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); + if (read_index == 0xffffffff) + return -ENODEV; + + read_index &= nentries_mask; + src_ring->hw_index = read_index; ath10k_pci_sleep(ar); } read_index = src_ring->hw_index; - if ((read_index == sw_index) || (read_index == 0xffffffff)) + if (read_index == sw_index) return -EIO; sbase = src_ring->shadow_base; -- cgit v1.2.3 From 2d3c2260e7ef0b21f7f0db0fbfee0b092e1202f8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 15 Jul 2014 11:51:28 +0300 Subject: Bluetooth: Don't try to reject failed LE connections The check for the blacklist in hci_le_conn_complete_evt() should be when we know that we have an actual successful connection (ev->status being non-zero). This patch fixes this ordering. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index bf2926b2e4a9..68d335e193bf 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4187,14 +4187,14 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) else addr_type = BDADDR_LE_RANDOM; - /* Drop the connection if he device is blocked */ - if (hci_bdaddr_list_lookup(&hdev->blacklist, &conn->dst, addr_type)) { - hci_conn_drop(conn); + if (ev->status) { + hci_le_conn_failed(conn, ev->status); goto unlock; } - if (ev->status) { - hci_le_conn_failed(conn, ev->status); + /* Drop the connection if the device is blocked */ + if (hci_bdaddr_list_lookup(&hdev->blacklist, &conn->dst, addr_type)) { + hci_conn_drop(conn); goto unlock; } -- cgit v1.2.3 From 88d825bffd3d537350d0000b7ef15cb00532d417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 2 Jul 2014 19:07:43 +0200 Subject: b43: always print info about radio (manuf, id, revision) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type of radio has a major meaning for the driver. There is quite some code that does initialization/calibration depending on the radio rev. Knowing radio params is quite important to provide help to users, so print it even with debugging disabled. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 15aaeb132a32..83b2d568bcae 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4478,13 +4478,13 @@ static int b43_phy_versioning(struct b43_wldev *dev) B43_WARN_ON(1); } if (unsupported) { - b43err(dev->wl, "FOUND UNSUPPORTED RADIO " - "(Manuf 0x%X, Version 0x%X, Revision %u)\n", + b43err(dev->wl, + "FOUND UNSUPPORTED RADIO (Manuf 0x%X, ID 0x%X, Revision %u)\n", radio_manuf, radio_ver, radio_rev); return -EOPNOTSUPP; } - b43dbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X, Revision %u\n", - radio_manuf, radio_ver, radio_rev); + b43info(dev->wl, "Found Radio: Manuf 0x%X, ID 0x%X, Revision %u\n", + radio_manuf, radio_ver, radio_rev); phy->radio_manuf = radio_manuf; phy->radio_ver = radio_ver; -- cgit v1.2.3 From 0933ecf9ab1f0ff7ae1ff4309aee0b909fc785d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 8 Jul 2014 15:11:04 +0200 Subject: b43: N-PHY: drop reg 0x1 access restriction on new PHY revs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialization of N-PHY radio revs 5 and 7 requires writing to 0x1. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 50ca6f87d5e8..1dba6409a05f 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -5834,7 +5834,7 @@ static void b43_nphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg) { /* Register 1 is a 32-bit register. */ - B43_WARN_ON(reg == 1); + B43_WARN_ON(dev->phy.rev < 7 && reg == 1); if (dev->phy.rev >= 7) reg |= 0x200; /* Radio 0x2057 */ @@ -5848,7 +5848,7 @@ static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg) static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) { /* Register 1 is a 32-bit register. */ - B43_WARN_ON(reg == 1); + B43_WARN_ON(dev->phy.rev < 7 && reg == 1); b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); -- cgit v1.2.3 From 12db5481ba0ed561c9105b7e28528aa2a551e38b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 8 Jul 2014 15:11:05 +0200 Subject: b43: N-PHY: add TX gain tables for devices with specific EPA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/tables_nphy.c | 74 +++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index b28dce950e1f..3a5cd902ff1f 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2408,6 +2408,41 @@ static const u32 b43_ntab_tx_gain_epa_rev3_2g[] = { 0x1041003c, 0x1041003b, 0x10410039, 0x10410037, }; +static const u32 b43_ntab_tx_gain_epa_rev3_hi_pwr_2g[] = { + 0x0f410044, 0x0f410042, 0x0f410040, 0x0f41003e, + 0x0f41003c, 0x0f41003b, 0x0f410039, 0x0f410037, + 0x0e410044, 0x0e410042, 0x0e410040, 0x0e41003e, + 0x0e41003c, 0x0e41003b, 0x0e410039, 0x0e410037, + 0x0d410044, 0x0d410042, 0x0d410040, 0x0d41003e, + 0x0d41003c, 0x0d41003b, 0x0d410039, 0x0d410037, + 0x0c410044, 0x0c410042, 0x0c410040, 0x0c41003e, + 0x0c41003c, 0x0c41003b, 0x0c410039, 0x0c410037, + 0x0b410044, 0x0b410042, 0x0b410040, 0x0b41003e, + 0x0b41003c, 0x0b41003b, 0x0b410039, 0x0b410037, + 0x0a410044, 0x0a410042, 0x0a410040, 0x0a41003e, + 0x0a41003c, 0x0a41003b, 0x0a410039, 0x0a410037, + 0x09410044, 0x09410042, 0x09410040, 0x0941003e, + 0x0941003c, 0x0941003b, 0x09410039, 0x09410037, + 0x08410044, 0x08410042, 0x08410040, 0x0841003e, + 0x0841003c, 0x0841003b, 0x08410039, 0x08410037, + 0x07410044, 0x07410042, 0x07410040, 0x0741003e, + 0x0741003c, 0x0741003b, 0x07410039, 0x07410037, + 0x06410044, 0x06410042, 0x06410040, 0x0641003e, + 0x0641003c, 0x0641003b, 0x06410039, 0x06410037, + 0x05410044, 0x05410042, 0x05410040, 0x0541003e, + 0x0541003c, 0x0541003b, 0x05410039, 0x05410037, + 0x04410044, 0x04410042, 0x04410040, 0x0441003e, + 0x0441003c, 0x0441003b, 0x04410039, 0x04410037, + 0x03410044, 0x03410042, 0x03410040, 0x0341003e, + 0x0341003c, 0x0341003b, 0x03410039, 0x03410037, + 0x02410044, 0x02410042, 0x02410040, 0x0241003e, + 0x0241003c, 0x0241003b, 0x02410039, 0x02410037, + 0x01410044, 0x01410042, 0x01410040, 0x0141003e, + 0x0141003c, 0x0141003b, 0x01410039, 0x01410037, + 0x00410044, 0x00410042, 0x00410040, 0x0041003e, + 0x0041003c, 0x0041003b, 0x00410039, 0x00410037 +}; + /* EPA 5 GHz */ static const u32 b43_ntab_tx_gain_epa_rev3_5g[] = { @@ -2480,6 +2515,41 @@ static const u32 b43_ntab_tx_gain_epa_rev4_5g[] = { 0x20d2003a, 0x20d20038, 0x20d20036, 0x20d20034, }; +static const u32 b43_ntab_tx_gain_epa_rev4_hi_pwr_5g[] = { + 0x2ff10044, 0x2ff10042, 0x2ff10040, 0x2ff1003e, + 0x2ff1003c, 0x2ff1003b, 0x2ff10039, 0x2ff10037, + 0x2ef10044, 0x2ef10042, 0x2ef10040, 0x2ef1003e, + 0x2ef1003c, 0x2ef1003b, 0x2ef10039, 0x2ef10037, + 0x2df10044, 0x2df10042, 0x2df10040, 0x2df1003e, + 0x2df1003c, 0x2df1003b, 0x2df10039, 0x2df10037, + 0x2cf10044, 0x2cf10042, 0x2cf10040, 0x2cf1003e, + 0x2cf1003c, 0x2cf1003b, 0x2cf10039, 0x2cf10037, + 0x2bf10044, 0x2bf10042, 0x2bf10040, 0x2bf1003e, + 0x2bf1003c, 0x2bf1003b, 0x2bf10039, 0x2bf10037, + 0x2af10044, 0x2af10042, 0x2af10040, 0x2af1003e, + 0x2af1003c, 0x2af1003b, 0x2af10039, 0x2af10037, + 0x29f10044, 0x29f10042, 0x29f10040, 0x29f1003e, + 0x29f1003c, 0x29f1003b, 0x29f10039, 0x29f10037, + 0x28f10044, 0x28f10042, 0x28f10040, 0x28f1003e, + 0x28f1003c, 0x28f1003b, 0x28f10039, 0x28f10037, + 0x27f10044, 0x27f10042, 0x27f10040, 0x27f1003e, + 0x27f1003c, 0x27f1003b, 0x27f10039, 0x27f10037, + 0x26f10044, 0x26f10042, 0x26f10040, 0x26f1003e, + 0x26f1003c, 0x26f1003b, 0x26f10039, 0x26f10037, + 0x25f10044, 0x25f10042, 0x25f10040, 0x25f1003e, + 0x25f1003c, 0x25f1003b, 0x25f10039, 0x25f10037, + 0x24f10044, 0x24f10042, 0x24f10040, 0x24f1003e, + 0x24f1003c, 0x24f1003b, 0x24f10039, 0x24f10038, + 0x23f10041, 0x23f10040, 0x23f1003f, 0x23f1003e, + 0x23f1003c, 0x23f1003b, 0x23f10039, 0x23f10037, + 0x22f10044, 0x22f10042, 0x22f10040, 0x22f1003e, + 0x22f1003c, 0x22f1003b, 0x22f10039, 0x22f10037, + 0x21f10044, 0x21f10042, 0x21f10040, 0x21f1003e, + 0x21f1003c, 0x21f1003b, 0x21f10039, 0x21f10037, + 0x20d10043, 0x20d10041, 0x20d1003e, 0x20d1003c, + 0x20d1003a, 0x20d10038, 0x20d10036, 0x20d10034 +}; + static const u32 b43_ntab_tx_gain_epa_rev5_5g[] = { 0x0f62004a, 0x0f620048, 0x0f620046, 0x0f620044, 0x0f620042, 0x0f620040, 0x0f62003e, 0x0f62003c, @@ -3530,7 +3600,7 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev) case 4: return sprom->fem.ghz5.extpa_gain == 3 ? b43_ntab_tx_gain_epa_rev4_5g : - b43_ntab_tx_gain_epa_rev4_5g; /* FIXME */ + b43_ntab_tx_gain_epa_rev4_hi_pwr_5g; case 3: return b43_ntab_tx_gain_epa_rev3_5g; default: @@ -3543,7 +3613,7 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev) case 6: case 5: if (sprom->fem.ghz5.extpa_gain == 3) - return b43_ntab_tx_gain_epa_rev3_2g; /* FIXME */ + return b43_ntab_tx_gain_epa_rev3_hi_pwr_2g; /* fall through */ case 4: case 3: -- cgit v1.2.3 From 303415e2f1c6617db5ae5988e1fceac353b8df4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 8 Jul 2014 15:11:06 +0200 Subject: b43: N-PHY: add placeholders for new devices support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 285 +++++++++++++++++++++++++++++++-------- 1 file changed, 231 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 1dba6409a05f..4bb4d0a3134b 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -140,11 +140,19 @@ ok: b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode); } +static void b43_nphy_rf_ctl_override_rev19(struct b43_wldev *dev, u16 field, + u16 value, u8 core, bool off, + u8 override_id) +{ + /* TODO */ +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverrideRev7 */ static void b43_nphy_rf_ctl_override_rev7(struct b43_wldev *dev, u16 field, u16 value, u8 core, bool off, u8 override) { + struct b43_phy *phy = &dev->phy; const struct nphy_rf_control_override_rev7 *e; u16 en_addrs[3][2] = { { 0x0E7, 0x0EC }, { 0x342, 0x343 }, { 0x346, 0x347 } @@ -154,6 +162,11 @@ static void b43_nphy_rf_ctl_override_rev7(struct b43_wldev *dev, u16 field, u16 val_addr; u8 i; + if (phy->rev >= 19 || phy->rev < 3) { + B43_WARN_ON(1); + return; + } + /* Remember: we can get NULL! */ e = b43_nphy_get_rf_ctl_over_rev7(dev, field, override); @@ -264,6 +277,8 @@ static void b43_nphy_rf_ctl_intc_override_rev7(struct b43_wldev *dev, u16 reg, tmp, tmp2, val; int core; + /* TODO: What about rev19+? Revs 3+ and 7+ are a bit similar */ + for (core = 0; core < 2; core++) { if ((core_sel == 1 && core != 0) || (core_sel == 2 && core != 1)) @@ -1386,6 +1401,7 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, u16 wait, bool iqmode, bool dac_test, bool modify_bbmult) { + struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; int i; u16 seq_mode; @@ -1393,6 +1409,10 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, b43_nphy_stay_in_carrier_search(dev, true); + if (phy->rev >= 7) { + /* TODO */ + } + if ((nphy->bb_mult_save & 0x80000000) == 0) { tmp = b43_ntab_read(dev, B43_NTAB16(15, 87)); nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000; @@ -1520,6 +1540,12 @@ static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale, } } +static void b43_nphy_rssi_select_rev19(struct b43_wldev *dev, u8 code, + enum n_rssi_type rssi_type) +{ + /* TODO */ +} + static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, enum n_rssi_type rssi_type) { @@ -1589,13 +1615,15 @@ static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, enum ieee80211_band band = b43_current_band(dev->wl); - if (b43_nphy_ipa(dev)) - val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE; - else - val = 0x11; - reg = (i == 0) ? 0x2000 : 0x3000; - reg |= B2055_PADDRV; - b43_radio_write(dev, reg, val); + if (dev->phy.rev < 7) { + if (b43_nphy_ipa(dev)) + val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE; + else + val = 0x11; + reg = (i == 0) ? B2056_TX0 : B2056_TX1; + reg |= B2056_TX_TX_SSI_MUX; + b43_radio_write(dev, reg, val); + } reg = (i == 0) ? B43_NPHY_AFECTL_OVER1 : @@ -1682,7 +1710,9 @@ static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, enum n_rssi_type type) { - if (dev->phy.rev >= 3) + if (dev->phy.rev >= 19) + b43_nphy_rssi_select_rev19(dev, code, type); + else if (dev->phy.rev >= 3) b43_nphy_rev3_rssi_select(dev, code, type); else b43_nphy_rev2_rssi_select(dev, code, type); @@ -1726,6 +1756,8 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, enum n_rssi_type rssi_type, u16 save_regs_phy[9]; u16 s[2]; + /* TODO: rev7+ is treated like rev3+, what about rev19+? */ + if (dev->phy.rev >= 3) { save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); @@ -2209,7 +2241,9 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, enum n_rssi_type type) */ static void b43_nphy_rssi_cal(struct b43_wldev *dev) { - if (dev->phy.rev >= 3) { + if (dev->phy.rev >= 19) { + /* TODO */ + } else if (dev->phy.rev >= 3) { b43_nphy_rev3_rssi_cal(dev); } else { b43_nphy_rev2_rssi_cal(dev, N_RSSI_NB); @@ -2222,7 +2256,21 @@ static void b43_nphy_rssi_cal(struct b43_wldev *dev) * Workarounds **************************************************/ -static void b43_nphy_gain_ctl_workarounds_rev3plus(struct b43_wldev *dev) +static void b43_nphy_gain_ctl_workarounds_rev19(struct b43_wldev *dev) +{ + /* TODO */ +} + +static void b43_nphy_gain_ctl_workarounds_rev7(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + switch (phy->rev) { + /* TODO */ + } +} + +static void b43_nphy_gain_ctl_workarounds_rev3(struct b43_wldev *dev) { struct ssb_sprom *sprom = dev->dev->bus_sprom; @@ -2419,10 +2467,12 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */ static void b43_nphy_gain_ctl_workarounds(struct b43_wldev *dev) { - if (dev->phy.rev >= 7) - ; /* TODO */ + if (dev->phy.rev >= 19) + b43_nphy_gain_ctl_workarounds_rev19(dev); + else if (dev->phy.rev >= 7) + b43_nphy_gain_ctl_workarounds_rev7(dev); else if (dev->phy.rev >= 3) - b43_nphy_gain_ctl_workarounds_rev3plus(dev); + b43_nphy_gain_ctl_workarounds_rev3(dev); else b43_nphy_gain_ctl_workarounds_rev1_2(dev); } @@ -3059,6 +3109,7 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) b43_phy_set(dev, B43_NPHY_IQFLIP, B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); + /* TODO: rev19+ */ if (dev->phy.rev >= 7) b43_nphy_workarounds_rev7plus(dev); else if (dev->phy.rev >= 3) @@ -3140,6 +3191,10 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev) nphy->bb_mult_save = 0; } + if (dev->phy.rev >= 7) { + /* TODO */ + } + if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, 0); } @@ -3149,6 +3204,7 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core, struct nphy_txgains target, struct nphy_iqcal_params *params) { + struct b43_phy *phy = &dev->phy; int i, j, indx; u16 gain; @@ -3157,8 +3213,13 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core, params->pga = target.pga[core]; params->pad = target.pad[core]; params->ipa = target.ipa[core]; - params->cal_gain = (params->txgm << 12) | (params->pga << 8) | - (params->pad << 4) | (params->ipa); + if (phy->rev >= 19) { + /* TODO */ + } else if (phy->rev >= 7) { + /* TODO */ + } else { + params->cal_gain = (params->txgm << 12) | (params->pga << 8) | (params->pad << 4) | (params->ipa); + } for (j = 0; j < 5; j++) params->ncorr[j] = 0x79; } else { @@ -3199,6 +3260,7 @@ static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev, /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) { + struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; u8 i; u16 bmask, val, tmp; @@ -3268,12 +3330,20 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, ~(bmask), val); if (band == IEEE80211_BAND_5GHZ) { - b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, - ~B43_NPHY_TXPCTL_CMD_INIT, 0x64); - if (dev->phy.rev > 1) - b43_phy_maskset(dev, B43_NPHY_TXPCTL_INIT, - ~B43_NPHY_TXPCTL_INIT_PIDXI1, + if (phy->rev >= 19) { + /* TODO */ + } else if (phy->rev >= 7) { + /* TODO */ + } else { + b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, + ~B43_NPHY_TXPCTL_CMD_INIT, 0x64); + if (phy->rev > 1) + b43_phy_maskset(dev, + B43_NPHY_TXPCTL_INIT, + ~B43_NPHY_TXPCTL_INIT_PIDXI1, + 0x64); + } } if (dev->phy.rev >= 3) { @@ -3290,6 +3360,10 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) } } + if (phy->rev >= 7) { + /* TODO */ + } + if (dev->phy.rev >= 3) { b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, ~0x100); b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x100); @@ -3331,6 +3405,7 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, 1); + /* TODO: rev19+ */ if (dev->phy.rev >= 7) { txpi[0] = txpi[1] = 30; } else if (dev->phy.rev >= 3) { @@ -3433,7 +3508,9 @@ static void b43_nphy_ipa_internal_tssi_setup(struct b43_wldev *dev) u8 core; u16 r; /* routing */ - if (phy->rev >= 7) { + if (phy->rev >= 19) { + /* TODO */ + } else if (phy->rev >= 7) { for (core = 0; core < 2; core++) { r = core ? 0x190 : 0x170; if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { @@ -3521,7 +3598,9 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev) if (b43_nphy_ipa(dev)) b43_nphy_ipa_internal_tssi_setup(dev); - if (phy->rev >= 7) + if (phy->rev >= 19) + b43_nphy_rf_ctl_override_rev19(dev, 0x2000, 0, 3, false, 0); + else if (phy->rev >= 7) b43_nphy_rf_ctl_override_rev7(dev, 0x2000, 0, 3, false, 0); else if (phy->rev >= 3) b43_nphy_rf_ctl_override(dev, 0x2000, 0, 3, false); @@ -3531,14 +3610,20 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev) udelay(20); tmp = b43_nphy_poll_rssi(dev, N_RSSI_TSSI_2G, rssi, 1); b43_nphy_stop_playback(dev); + b43_nphy_rssi_select(dev, 0, N_RSSI_W1); - if (phy->rev >= 7) + if (phy->rev >= 19) + b43_nphy_rf_ctl_override_rev19(dev, 0x2000, 0, 3, true, 0); + else if (phy->rev >= 7) b43_nphy_rf_ctl_override_rev7(dev, 0x2000, 0, 3, true, 0); else if (phy->rev >= 3) b43_nphy_rf_ctl_override(dev, 0x2000, 0, 3, true); - if (phy->rev >= 3) { + if (phy->rev >= 19) { + /* TODO */ + return; + } else if (phy->rev >= 3) { nphy->pwr_ctl_info[0].idle_tssi_5g = (tmp >> 24) & 0xFF; nphy->pwr_ctl_info[1].idle_tssi_5g = (tmp >> 8) & 0xFF; } else { @@ -3730,7 +3815,9 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev) udelay(1); } - if (dev->phy.rev >= 7) { + if (phy->rev >= 19) { + /* TODO */ + } else if (phy->rev >= 7) { b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, ~B43_NPHY_TXPCTL_CMD_INIT, 0x19); b43_phy_maskset(dev, B43_NPHY_TXPCTL_INIT, @@ -3793,24 +3880,30 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev) b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128, table); b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128, table); - if (phy->rev >= 3) { + if (phy->rev < 3) + return; + #if 0 - nphy->gmval = (table[0] >> 16) & 0x7000; + nphy->gmval = (table[0] >> 16) & 0x7000; #endif - for (i = 0; i < 128; i++) { + for (i = 0; i < 128; i++) { + if (phy->rev >= 19) { + /* TODO */ + return; + } else if (phy->rev >= 7) { + /* TODO */ + return; + } else { pga_gain = (table[i] >> 24) & 0xF; if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) - rfpwr_offset = - b43_ntab_papd_pga_gain_delta_ipa_2g[pga_gain]; + rfpwr_offset = b43_ntab_papd_pga_gain_delta_ipa_2g[pga_gain]; else - rfpwr_offset = - 0; /* FIXME */ - b43_ntab_write(dev, B43_NTAB32(26, 576 + i), - rfpwr_offset); - b43_ntab_write(dev, B43_NTAB32(27, 576 + i), - rfpwr_offset); + rfpwr_offset = 0; /* FIXME */ } + + b43_ntab_write(dev, B43_NTAB32(26, 576 + i), rfpwr_offset); + b43_ntab_write(dev, B43_NTAB32(27, 576 + i), rfpwr_offset); } } @@ -3827,7 +3920,10 @@ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) nphy->rfctrl_intc2_save = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); band = b43_current_band(dev->wl); - if (dev->phy.rev >= 3) { + if (dev->phy.rev >= 7) { + /* TODO */ + return; + } else if (dev->phy.rev >= 3) { if (band == IEEE80211_BAND_5GHZ) tmp = 0x600; else @@ -4274,7 +4370,10 @@ static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev) rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G; } - if (dev->phy.rev >= 7) { + if (dev->phy.rev >= 19) { + /* TODO */ + } else if (dev->phy.rev >= 7) { + /* TODO */ } else { b43_radio_maskset(dev, B2056_RX0 | B2056_RX_RSSI_MISC, 0xE3, rssical_radio_regs[0]); @@ -4298,15 +4397,30 @@ static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, rssical_phy_regs[11]); } +static void b43_nphy_tx_cal_radio_setup_rev19(struct b43_wldev *dev) +{ + /* TODO */ +} + +static void b43_nphy_tx_cal_radio_setup_rev7(struct b43_wldev *dev) +{ + /* TODO */ +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */ static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev) { + struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; u16 *save = nphy->tx_rx_cal_radio_saveregs; u16 tmp; u8 offset, i; - if (dev->phy.rev >= 3) { + if (phy->rev >= 19) { + b43_nphy_tx_cal_radio_setup_rev19(dev); + } else if (phy->rev >= 7) { + b43_nphy_tx_cal_radio_setup_rev7(dev); + } else if (phy->rev >= 3) { for (i = 0; i < 2; i++) { tmp = (i == 0) ? 0x2000 : 0x3000; offset = i * 11; @@ -4547,6 +4661,7 @@ static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhySetup */ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) { + struct b43_phy *phy = &dev->phy; u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; u16 tmp; @@ -4586,6 +4701,21 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1); b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001); b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001); + + if (phy->rev >= 19) + ; /* TODO */ + else if (phy->rev >= 7) + ; /* TODO */ + + if (0 /* FIXME */) { + if (phy->rev >= 19) { + /* TODO */ + } else if (phy->rev >= 8) { + /* TODO */ + } else if (phy->rev == 7) { + /* TODO */ + } + } } else { b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, 0xA000); b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, 0xA000); @@ -4614,6 +4744,7 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SaveCal */ static void b43_nphy_save_cal(struct b43_wldev *dev) { + struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; struct b43_phy_n_iq_comp *rxcal_coeffs = NULL; @@ -4638,7 +4769,11 @@ static void b43_nphy_save_cal(struct b43_wldev *dev) b43_nphy_rx_iq_coeffs(dev, false, rxcal_coeffs); /* TODO use some definitions */ - if (dev->phy.rev >= 3) { + if (phy->rev >= 19) { + /* TODO */ + } else if (phy->rev >= 7) { + /* TODO */ + } else if (phy->rev >= 3) { txcal_radio_regs[0] = b43_radio_read(dev, 0x2021); txcal_radio_regs[1] = b43_radio_read(dev, 0x2022); txcal_radio_regs[2] = b43_radio_read(dev, 0x3021); @@ -4665,6 +4800,7 @@ static void b43_nphy_save_cal(struct b43_wldev *dev) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */ static void b43_nphy_restore_cal(struct b43_wldev *dev) { + struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; u16 coef[4]; @@ -4712,7 +4848,11 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev) } /* TODO use some definitions */ - if (dev->phy.rev >= 3) { + if (phy->rev >= 19) { + /* TODO */ + } else if (phy->rev >= 7) { + /* TODO */ + } else if (phy->rev >= 3) { b43_radio_write(dev, 0x2021, txcal_radio_regs[0]); b43_radio_write(dev, 0x2022, txcal_radio_regs[1]); b43_radio_write(dev, 0x3021, txcal_radio_regs[2]); @@ -4789,7 +4929,13 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, } } - b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9); + if (phy->rev >= 19) { + /* TODO */ + } else if (phy->rev >= 7) { + /* TODO */ + } else { + b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9); + } if (!b43_is_40mhz(dev)) freq = 2500; @@ -5183,6 +5329,9 @@ static int b43_nphy_rev3_cal_rx_iq(struct b43_wldev *dev, static int b43_nphy_cal_rx_iq(struct b43_wldev *dev, struct nphy_txgains target, u8 type, bool debug) { + if (dev->phy.rev >= 7) + type = 0; + if (dev->phy.rev >= 3) return b43_nphy_rev3_cal_rx_iq(dev, target, type, debug); else @@ -5269,6 +5418,9 @@ static void b43_nphy_bphy_init(struct b43_wldev *dev) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SuperSwitchInit */ static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init) { + if (dev->phy.rev >= 7) + return; + if (dev->phy.rev >= 3) { if (!init) return; @@ -5353,6 +5505,13 @@ static int b43_phy_initn(struct b43_wldev *dev) if (dev->phy.rev >= 3) { b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, 0); b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); + if (phy->rev >= 7) { + /* TODO */ + } + if (phy->rev >= 19) { + /* TODO */ + } + b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, 0); b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, 0); } else { @@ -5390,7 +5549,9 @@ static int b43_phy_initn(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x50); b43_phy_write(dev, B43_NPHY_TXRIFS_FRDEL, 0x30); - b43_nphy_update_mimo_config(dev, nphy->preamble_override); + if (phy->rev < 8) + b43_nphy_update_mimo_config(dev, nphy->preamble_override); + b43_nphy_update_txrx_chain(dev); if (phy->rev < 2) { @@ -5422,10 +5583,12 @@ static int b43_phy_initn(struct b43_wldev *dev) b43_mac_phy_clock_set(dev, true); - b43_nphy_pa_override(dev, false); - b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); - b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); - b43_nphy_pa_override(dev, true); + if (phy->rev < 7) { + b43_nphy_pa_override(dev, false); + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); + b43_nphy_pa_override(dev, true); + } b43_nphy_classifier(dev, 0, 0); b43_nphy_read_clip_detection(dev, clip); @@ -5644,7 +5807,10 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, u8 tmp; - if (phy->rev >= 7) { + if (phy->rev >= 19) { + return -ESRCH; + /* TODO */ + } else if (phy->rev >= 7) { r2057_get_chantabent_rev7(dev, channel->center_freq, &tabent_r7, &tabent_r7_2g); if (!tabent_r7 && !tabent_r7_2g) @@ -5681,7 +5847,9 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, b43_phy_mask(dev, 0x310, (u16)~0x8000); } - if (phy->rev >= 7) { + if (phy->rev >= 19) { + /* TODO */ + } else if (phy->rev >= 7) { const struct b43_phy_n_sfo_cfg *phy_regs = tabent_r7 ? &(tabent_r7->phy_regs) : &(tabent_r7_2g->phy_regs); @@ -5858,15 +6026,19 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, bool blocked) { + struct b43_phy *phy = &dev->phy; + if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED) b43err(dev->wl, "MAC not suspended\n"); if (blocked) { b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, ~B43_NPHY_RFCTL_CMD_CHIP0PU); - if (dev->phy.rev >= 7) { + if (phy->rev >= 19) { /* TODO */ - } else if (dev->phy.rev >= 3) { + } else if (phy->rev >= 7) { + /* TODO */ + } else if (phy->rev >= 3) { b43_radio_mask(dev, 0x09, ~0x2); b43_radio_write(dev, 0x204D, 0); @@ -5884,11 +6056,13 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, b43_radio_write(dev, 0x3064, 0); } } else { - if (dev->phy.rev >= 7) { + if (phy->rev >= 19) { + /* TODO */ + } else if (phy->rev >= 7) { if (!dev->phy.radio_on) b43_radio_2057_init(dev); b43_switch_channel(dev, dev->phy.channel); - } else if (dev->phy.rev >= 3) { + } else if (phy->rev >= 3) { if (!dev->phy.radio_on) b43_radio_init2056(dev); b43_switch_channel(dev, dev->phy.channel); @@ -5901,10 +6075,13 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, /* http://bcm-v4.sipsolutions.net/802.11/PHY/Anacore */ static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on) { + struct b43_phy *phy = &dev->phy; u16 override = on ? 0x0 : 0x7FFF; u16 core = on ? 0xD : 0x00FD; - if (dev->phy.rev >= 3) { + if (phy->rev >= 19) { + /* TODO */ + } else if (phy->rev >= 3) { if (on) { b43_phy_write(dev, B43_NPHY_AFECTL_C1, core); b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, override); -- cgit v1.2.3 From 40c68f20e63c9cd589ebfcf672ef912452967caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 8 Jul 2014 15:11:07 +0200 Subject: b43; N-PHY: write most of the missing code for revs 7+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 2 +- drivers/net/wireless/b43/phy_n.c | 306 +++++++++++++++++++++++++++++----- drivers/net/wireless/b43/phy_n.h | 11 ++ drivers/net/wireless/b43/radio_2057.h | 10 ++ 4 files changed, 290 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 83b2d568bcae..8dd69a3ae7ac 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4360,7 +4360,7 @@ static int b43_phy_versioning(struct b43_wldev *dev) #endif #ifdef CONFIG_B43_PHY_N case B43_PHYTYPE_N: - if (phy_rev > 9) + if (phy_rev >= 19) unsupported = 1; break; #endif diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 4bb4d0a3134b..44349f5b99c6 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -36,6 +36,7 @@ #include "main.h" struct nphy_txgains { + u16 tx_lpf[2]; u16 txgm[2]; u16 pga[2]; u16 pad[2]; @@ -43,6 +44,7 @@ struct nphy_txgains { }; struct nphy_iqcal_params { + u16 tx_lpf; u16 txgm; u16 pga; u16 pad; @@ -69,6 +71,14 @@ enum b43_nphy_rf_sequence { B43_RFSEQ_UPDATE_GAINU, }; +enum n_rf_ctl_over_cmd { + N_RF_CTL_OVER_CMD_RXRF_PU = 0, + N_RF_CTL_OVER_CMD_RX_PU = 1, + N_RF_CTL_OVER_CMD_TX_PU = 2, + N_RF_CTL_OVER_CMD_RX_GAIN = 3, + N_RF_CTL_OVER_CMD_TX_GAIN = 4, +}; + enum n_intc_override { N_INTC_OVERRIDE_OFF = 0, N_INTC_OVERRIDE_TRSW = 1, @@ -194,6 +204,50 @@ static void b43_nphy_rf_ctl_override_rev7(struct b43_wldev *dev, u16 field, } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverideOneToMany */ +static void b43_nphy_rf_ctl_override_one_to_many(struct b43_wldev *dev, + enum n_rf_ctl_over_cmd cmd, + u16 value, u8 core, bool off) +{ + struct b43_phy *phy = &dev->phy; + u16 tmp; + + B43_WARN_ON(phy->rev < 7); + + switch (cmd) { + case N_RF_CTL_OVER_CMD_RXRF_PU: + b43_nphy_rf_ctl_override_rev7(dev, 0x20, value, core, off, 1); + b43_nphy_rf_ctl_override_rev7(dev, 0x10, value, core, off, 1); + b43_nphy_rf_ctl_override_rev7(dev, 0x08, value, core, off, 1); + break; + case N_RF_CTL_OVER_CMD_RX_PU: + b43_nphy_rf_ctl_override_rev7(dev, 0x4, value, core, off, 1); + b43_nphy_rf_ctl_override_rev7(dev, 0x2, value, core, off, 1); + b43_nphy_rf_ctl_override_rev7(dev, 0x1, value, core, off, 1); + b43_nphy_rf_ctl_override_rev7(dev, 0x2, value, core, off, 2); + b43_nphy_rf_ctl_override_rev7(dev, 0x0800, value, core, off, 1); + break; + case N_RF_CTL_OVER_CMD_TX_PU: + b43_nphy_rf_ctl_override_rev7(dev, 0x4, value, core, off, 0); + b43_nphy_rf_ctl_override_rev7(dev, 0x2, value, core, off, 1); + b43_nphy_rf_ctl_override_rev7(dev, 0x1, value, core, off, 2); + b43_nphy_rf_ctl_override_rev7(dev, 0x0800, value, core, off, 1); + break; + case N_RF_CTL_OVER_CMD_RX_GAIN: + tmp = value & 0xFF; + b43_nphy_rf_ctl_override_rev7(dev, 0x0800, tmp, core, off, 0); + tmp = value >> 8; + b43_nphy_rf_ctl_override_rev7(dev, 0x6000, tmp, core, off, 0); + break; + case N_RF_CTL_OVER_CMD_TX_GAIN: + tmp = value & 0x7FFF; + b43_nphy_rf_ctl_override_rev7(dev, 0x1000, tmp, core, off, 0); + tmp = value >> 14; + b43_nphy_rf_ctl_override_rev7(dev, 0x4000, tmp, core, off, 0); + break; + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */ static void b43_nphy_rf_ctl_override(struct b43_wldev *dev, u16 field, u16 value, u8 core, bool off) @@ -520,6 +574,14 @@ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable) } } +/* http://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */ +static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset) +{ + if (!offset) + offset = b43_is_40mhz(dev) ? 0x159 : 0x154; + return b43_ntab_read(dev, B43_NTAB16(7, offset)) & 0x7; +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/AdjustLnaGainTbl */ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev) { @@ -1410,7 +1472,23 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, b43_nphy_stay_in_carrier_search(dev, true); if (phy->rev >= 7) { - /* TODO */ + bool lpf_bw3, lpf_bw4; + + lpf_bw3 = b43_phy_read(dev, B43_NPHY_REV7_RF_CTL_OVER3) & 0x80; + lpf_bw4 = b43_phy_read(dev, B43_NPHY_REV7_RF_CTL_OVER3) & 0x80; + + if (lpf_bw3 || lpf_bw4) { + /* TODO */ + } else { + u16 value = b43_nphy_read_lpf_ctl(dev, 0); + if (phy->rev >= 19) + b43_nphy_rf_ctl_override_rev19(dev, 0x80, value, + 0, false, 1); + else + b43_nphy_rf_ctl_override_rev7(dev, 0x80, value, + 0, false, 1); + nphy->lpf_bw_overrode_for_sample_play = true; + } } if ((nphy->bb_mult_save & 0x80000000) == 0) { @@ -1857,12 +1935,14 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) B43_NPHY_AFECTL_OVER1, B43_NPHY_AFECTL_OVER, B43_NPHY_AFECTL_C1, B43_NPHY_AFECTL_C2, B43_NPHY_TXF_40CO_B1S1, B43_NPHY_RFCTL_OVER, - 0x342, 0x343, 0x346, 0x347, + B43_NPHY_REV7_RF_CTL_OVER3, B43_NPHY_REV7_RF_CTL_OVER4, + B43_NPHY_REV7_RF_CTL_OVER5, B43_NPHY_REV7_RF_CTL_OVER6, 0x2ff, B43_NPHY_TXF_40CO_B1S0, B43_NPHY_TXF_40CO_B32S1, B43_NPHY_RFCTL_CMD, B43_NPHY_RFCTL_LUT_TRSW_UP1, B43_NPHY_RFCTL_LUT_TRSW_UP2, - 0x340, 0x341, 0x344, 0x345, + B43_NPHY_REV7_RF_CTL_MISC_REG3, B43_NPHY_REV7_RF_CTL_MISC_REG4, + B43_NPHY_REV7_RF_CTL_MISC_REG5, B43_NPHY_REV7_RF_CTL_MISC_REG6, B43_NPHY_RFCTL_RSSIO1, B43_NPHY_RFCTL_RSSIO2 }; u16 *regs_to_store; @@ -1909,9 +1989,24 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, 1, 7); if (dev->phy.rev >= 7) { - /* TODO */ + b43_nphy_rf_ctl_override_one_to_many(dev, + N_RF_CTL_OVER_CMD_RXRF_PU, + 0, 0, false); + b43_nphy_rf_ctl_override_one_to_many(dev, + N_RF_CTL_OVER_CMD_RX_PU, + 1, 0, false); + b43_nphy_rf_ctl_override_rev7(dev, 0x80, 1, 0, false, 0); + b43_nphy_rf_ctl_override_rev7(dev, 0x80, 1, 0, false, 0); if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { + b43_nphy_rf_ctl_override_rev7(dev, 0x20, 0, 0, false, + 0); + b43_nphy_rf_ctl_override_rev7(dev, 0x10, 1, 0, false, + 0); } else { + b43_nphy_rf_ctl_override_rev7(dev, 0x10, 0, 0, false, + 0); + b43_nphy_rf_ctl_override_rev7(dev, 0x20, 1, 0, false, + 0); } } else { b43_nphy_rf_ctl_override(dev, 0x1, 0, 0, false); @@ -1940,7 +2035,10 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) /* Grab RSSI results for every possible VCM */ for (vcm = 0; vcm < 8; vcm++) { if (dev->phy.rev >= 7) - ; + b43_radio_maskset(dev, + core ? R2057_NB_MASTER_CORE1 : + R2057_NB_MASTER_CORE0, + ~R2057_VCM_MASK, vcm); else b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC, 0xE3, vcm << 2); @@ -1971,7 +2069,10 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) /* Select the best VCM */ if (dev->phy.rev >= 7) - ; + b43_radio_maskset(dev, + core ? R2057_NB_MASTER_CORE1 : + R2057_NB_MASTER_CORE0, + ~R2057_VCM_MASK, vcm); else b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC, 0xE3, vcm_final << 2); @@ -2041,6 +2142,10 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G; } if (dev->phy.rev >= 7) { + rssical_radio_regs[0] = b43_radio_read(dev, + R2057_NB_MASTER_CORE0); + rssical_radio_regs[1] = b43_radio_read(dev, + R2057_NB_MASTER_CORE1); } else { rssical_radio_regs[0] = b43_radio_read(dev, B2056_RX0 | B2056_RX_RSSI_MISC); @@ -2477,14 +2582,6 @@ static void b43_nphy_gain_ctl_workarounds(struct b43_wldev *dev) b43_nphy_gain_ctl_workarounds_rev1_2(dev); } -/* http://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */ -static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset) -{ - if (!offset) - offset = b43_is_40mhz(dev) ? 0x159 : 0x154; - return b43_ntab_read(dev, B43_NTAB16(7, offset)) & 0x7; -} - static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) { struct ssb_sprom *sprom = dev->dev->bus_sprom; @@ -3171,6 +3268,7 @@ static void b43_nphy_update_txrx_chain(struct b43_wldev *dev) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */ static void b43_nphy_stop_playback(struct b43_wldev *dev) { + struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; u16 tmp; @@ -3191,8 +3289,13 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev) nphy->bb_mult_save = 0; } - if (dev->phy.rev >= 7) { - /* TODO */ + if (phy->rev >= 7) { + if (phy->rev >= 19) + b43_nphy_rf_ctl_override_rev19(dev, 0x80, 0, 0, true, + 1); + else + b43_nphy_rf_ctl_override_rev7(dev, 0x80, 0, 0, true, 1); + nphy->lpf_bw_overrode_for_sample_play = false; } if (nphy->hang_avoid) @@ -3209,6 +3312,7 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core, u16 gain; if (dev->phy.rev >= 3) { + params->tx_lpf = target.tx_lpf[core]; /* Rev 7+ */ params->txgm = target.txgm[core]; params->pga = target.pga[core]; params->pad = target.pad[core]; @@ -3216,7 +3320,7 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core, if (phy->rev >= 19) { /* TODO */ } else if (phy->rev >= 7) { - /* TODO */ + params->cal_gain = (params->txgm << 12) | (params->pga << 8) | (params->pad << 3) | (params->ipa) | (params->tx_lpf << 15); } else { params->cal_gain = (params->txgm << 12) | (params->pga << 8) | (params->pad << 4) | (params->ipa); } @@ -3333,7 +3437,12 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) if (phy->rev >= 19) { /* TODO */ } else if (phy->rev >= 7) { - /* TODO */ + b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, + ~B43_NPHY_TXPCTL_CMD_INIT, + 0x32); + b43_phy_maskset(dev, B43_NPHY_TXPCTL_INIT, + ~B43_NPHY_TXPCTL_INIT_PIDXI1, + 0x32); } else { b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, ~B43_NPHY_TXPCTL_CMD_INIT, @@ -3921,8 +4030,7 @@ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) B43_NPHY_RFCTL_INTC2); band = b43_current_band(dev->wl); if (dev->phy.rev >= 7) { - /* TODO */ - return; + tmp = 0x1480; } else if (dev->phy.rev >= 3) { if (band == IEEE80211_BAND_5GHZ) tmp = 0x600; @@ -4373,7 +4481,10 @@ static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev) if (dev->phy.rev >= 19) { /* TODO */ } else if (dev->phy.rev >= 7) { - /* TODO */ + b43_radio_maskset(dev, R2057_NB_MASTER_CORE0, ~R2057_VCM_MASK, + rssical_radio_regs[0]); + b43_radio_maskset(dev, R2057_NB_MASTER_CORE1, ~R2057_VCM_MASK, + rssical_radio_regs[1]); } else { b43_radio_maskset(dev, B2056_RX0 | B2056_RX_RSSI_MISC, 0xE3, rssical_radio_regs[0]); @@ -4404,7 +4515,55 @@ static void b43_nphy_tx_cal_radio_setup_rev19(struct b43_wldev *dev) static void b43_nphy_tx_cal_radio_setup_rev7(struct b43_wldev *dev) { - /* TODO */ + struct b43_phy *phy = &dev->phy; + struct b43_phy_n *nphy = dev->phy.n; + u16 *save = nphy->tx_rx_cal_radio_saveregs; + int core, off; + u16 r, tmp; + + for (core = 0; core < 2; core++) { + r = core ? 0x20 : 0; + off = core * 11; + + save[off + 0] = b43_radio_read(dev, r + R2057_TX0_TX_SSI_MASTER); + save[off + 1] = b43_radio_read(dev, r + R2057_TX0_IQCAL_VCM_HG); + save[off + 2] = b43_radio_read(dev, r + R2057_TX0_IQCAL_IDAC); + save[off + 3] = b43_radio_read(dev, r + R2057_TX0_TSSI_VCM); + save[off + 4] = 0; + save[off + 5] = b43_radio_read(dev, r + R2057_TX0_TX_SSI_MUX); + if (phy->radio_rev != 5) + save[off + 6] = b43_radio_read(dev, r + R2057_TX0_TSSIA); + save[off + 7] = b43_radio_read(dev, r + R2057_TX0_TSSIG); + save[off + 8] = b43_radio_read(dev, r + R2057_TX0_TSSI_MISC1); + + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { + b43_radio_write(dev, r + R2057_TX0_TX_SSI_MASTER, 0xA); + b43_radio_write(dev, r + R2057_TX0_IQCAL_VCM_HG, 0x43); + b43_radio_write(dev, r + R2057_TX0_IQCAL_IDAC, 0x55); + b43_radio_write(dev, r + R2057_TX0_TSSI_VCM, 0); + b43_radio_write(dev, r + R2057_TX0_TSSIG, 0); + if (nphy->use_int_tx_iq_lo_cal) { + b43_radio_write(dev, r + R2057_TX0_TX_SSI_MUX, 0x4); + tmp = true ? 0x31 : 0x21; /* TODO */ + b43_radio_write(dev, r + R2057_TX0_TSSIA, tmp); + } + b43_radio_write(dev, r + R2057_TX0_TSSI_MISC1, 0x00); + } else { + b43_radio_write(dev, r + R2057_TX0_TX_SSI_MASTER, 0x6); + b43_radio_write(dev, r + R2057_TX0_IQCAL_VCM_HG, 0x43); + b43_radio_write(dev, r + R2057_TX0_IQCAL_IDAC, 0x55); + b43_radio_write(dev, r + R2057_TX0_TSSI_VCM, 0); + + if (phy->radio_rev != 5) + b43_radio_write(dev, r + R2057_TX0_TSSIA, 0); + if (nphy->use_int_tx_iq_lo_cal) { + b43_radio_write(dev, r + R2057_TX0_TX_SSI_MUX, 0x6); + tmp = true ? 0x31 : 0x21; /* TODO */ + b43_radio_write(dev, r + R2057_TX0_TSSIG, tmp); + } + b43_radio_write(dev, r + R2057_TX0_TSSI_MISC1, 0); + } + } } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */ @@ -4585,7 +4744,13 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, false); for (i = 0; i < 2; ++i) { - if (dev->phy.rev >= 3) { + if (dev->phy.rev >= 7) { + target.ipa[i] = curr_gain[i] & 0x0007; + target.pad[i] = (curr_gain[i] & 0x00F8) >> 3; + target.pga[i] = (curr_gain[i] & 0x0F00) >> 8; + target.txgm[i] = (curr_gain[i] & 0x7000) >> 12; + target.tx_lpf[i] = (curr_gain[i] & 0x8000) >> 15; + } else if (dev->phy.rev >= 3) { target.ipa[i] = curr_gain[i] & 0x000F; target.pad[i] = (curr_gain[i] & 0x00F0) >> 4; target.pga[i] = (curr_gain[i] & 0x0F00) >> 8; @@ -4612,7 +4777,13 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) if (!table) break; - if (dev->phy.rev >= 3) { + if (dev->phy.rev >= 7) { + target.ipa[i] = (table[index[i]] >> 16) & 0x7; + target.pad[i] = (table[index[i]] >> 19) & 0x1F; + target.pga[i] = (table[index[i]] >> 24) & 0xF; + target.txgm[i] = (table[index[i]] >> 28) & 0x7; + target.tx_lpf[i] = (table[index[i]] >> 31) & 0x1; + } else if (dev->phy.rev >= 3) { target.ipa[i] = (table[index[i]] >> 16) & 0xF; target.pad[i] = (table[index[i]] >> 20) & 0xF; target.pga[i] = (table[index[i]] >> 24) & 0xF; @@ -4662,6 +4833,7 @@ static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev) static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + struct b43_phy_n *nphy = dev->phy.n; u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; u16 tmp; @@ -4693,7 +4865,12 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) regs[7] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); - b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_PA, 1, 3); + if (!nphy->use_int_tx_iq_lo_cal) + b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_PA, + 1, 3); + else + b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_PA, + 0, 3); b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, 2, 1); b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, 8, 2); @@ -4702,18 +4879,30 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001); b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001); + tmp = b43_nphy_read_lpf_ctl(dev, 0); if (phy->rev >= 19) - ; /* TODO */ + b43_nphy_rf_ctl_override_rev19(dev, 0x80, tmp, 0, false, + 1); else if (phy->rev >= 7) - ; /* TODO */ + b43_nphy_rf_ctl_override_rev7(dev, 0x80, tmp, 0, false, + 1); - if (0 /* FIXME */) { + if (nphy->use_int_tx_iq_lo_cal && true /* FIXME */) { if (phy->rev >= 19) { - /* TODO */ + b43_nphy_rf_ctl_override_rev19(dev, 0x8, 0, 0x3, + false, 0); } else if (phy->rev >= 8) { - /* TODO */ + b43_nphy_rf_ctl_override_rev7(dev, 0x8, 0, 0x3, + false, 0); } else if (phy->rev == 7) { - /* TODO */ + b43_radio_maskset(dev, R2057_OVR_REG0, 1 << 4, 1 << 4); + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_radio_maskset(dev, R2057_PAD2G_TUNE_PUS_CORE0, ~1, 0); + b43_radio_maskset(dev, R2057_PAD2G_TUNE_PUS_CORE1, ~1, 0); + } else { + b43_radio_maskset(dev, R2057_IPA5G_CASCOFFV_PU_CORE0, ~1, 0); + b43_radio_maskset(dev, R2057_IPA5G_CASCOFFV_PU_CORE1, ~1, 0); + } } } } else { @@ -4772,7 +4961,22 @@ static void b43_nphy_save_cal(struct b43_wldev *dev) if (phy->rev >= 19) { /* TODO */ } else if (phy->rev >= 7) { - /* TODO */ + txcal_radio_regs[0] = b43_radio_read(dev, + R2057_TX0_LOFT_FINE_I); + txcal_radio_regs[1] = b43_radio_read(dev, + R2057_TX0_LOFT_FINE_Q); + txcal_radio_regs[4] = b43_radio_read(dev, + R2057_TX0_LOFT_COARSE_I); + txcal_radio_regs[5] = b43_radio_read(dev, + R2057_TX0_LOFT_COARSE_Q); + txcal_radio_regs[2] = b43_radio_read(dev, + R2057_TX1_LOFT_FINE_I); + txcal_radio_regs[3] = b43_radio_read(dev, + R2057_TX1_LOFT_FINE_Q); + txcal_radio_regs[6] = b43_radio_read(dev, + R2057_TX1_LOFT_COARSE_I); + txcal_radio_regs[7] = b43_radio_read(dev, + R2057_TX1_LOFT_COARSE_Q); } else if (phy->rev >= 3) { txcal_radio_regs[0] = b43_radio_read(dev, 0x2021); txcal_radio_regs[1] = b43_radio_read(dev, 0x2022); @@ -4851,7 +5055,22 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev) if (phy->rev >= 19) { /* TODO */ } else if (phy->rev >= 7) { - /* TODO */ + b43_radio_write(dev, R2057_TX0_LOFT_FINE_I, + txcal_radio_regs[0]); + b43_radio_write(dev, R2057_TX0_LOFT_FINE_Q, + txcal_radio_regs[1]); + b43_radio_write(dev, R2057_TX0_LOFT_COARSE_I, + txcal_radio_regs[4]); + b43_radio_write(dev, R2057_TX0_LOFT_COARSE_Q, + txcal_radio_regs[5]); + b43_radio_write(dev, R2057_TX1_LOFT_FINE_I, + txcal_radio_regs[2]); + b43_radio_write(dev, R2057_TX1_LOFT_FINE_Q, + txcal_radio_regs[3]); + b43_radio_write(dev, R2057_TX1_LOFT_COARSE_I, + txcal_radio_regs[6]); + b43_radio_write(dev, R2057_TX1_LOFT_COARSE_Q, + txcal_radio_regs[7]); } else if (phy->rev >= 3) { b43_radio_write(dev, 0x2021, txcal_radio_regs[0]); b43_radio_write(dev, 0x2022, txcal_radio_regs[1]); @@ -4932,7 +5151,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, if (phy->rev >= 19) { /* TODO */ } else if (phy->rev >= 7) { - /* TODO */ + b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AD9); } else { b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9); } @@ -5496,6 +5715,10 @@ static int b43_phy_initn(struct b43_wldev *dev) #endif } } + nphy->use_int_tx_iq_lo_cal = b43_nphy_ipa(dev) || + phy->rev >= 7 || + (phy->rev >= 5 && + sprom->boardflags2_hi & B43_BFH2_INTERNDET_TXIQCAL); nphy->deaf_count = 0; b43_nphy_tables_init(dev); nphy->crsminpwr_adjusted = false; @@ -5506,7 +5729,10 @@ static int b43_phy_initn(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, 0); b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); if (phy->rev >= 7) { - /* TODO */ + b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER3, 0); + b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER4, 0); + b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER5, 0); + b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER6, 0); } if (phy->rev >= 19) { /* TODO */ @@ -6032,13 +6258,17 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, b43err(dev->wl, "MAC not suspended\n"); if (blocked) { - b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, - ~B43_NPHY_RFCTL_CMD_CHIP0PU); if (phy->rev >= 19) { /* TODO */ + } else if (phy->rev >= 8) { + b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, + ~B43_NPHY_RFCTL_CMD_CHIP0PU); } else if (phy->rev >= 7) { - /* TODO */ + /* Nothing needed */ } else if (phy->rev >= 3) { + b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, + ~B43_NPHY_RFCTL_CMD_CHIP0PU); + b43_radio_mask(dev, 0x09, ~0x2); b43_radio_write(dev, 0x204D, 0); diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index ecfbf66dbc3b..7fd5d5f9161d 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -857,6 +857,15 @@ #define B43_NPHY_REV3_C2_CLIP2_GAIN_A B43_PHY_N(0x2AF) #define B43_NPHY_REV3_C2_CLIP2_GAIN_B B43_PHY_N(0x2B0) +#define B43_NPHY_REV7_RF_CTL_MISC_REG3 B43_PHY_N(0x340) +#define B43_NPHY_REV7_RF_CTL_MISC_REG4 B43_PHY_N(0x341) +#define B43_NPHY_REV7_RF_CTL_OVER3 B43_PHY_N(0x342) +#define B43_NPHY_REV7_RF_CTL_OVER4 B43_PHY_N(0x343) +#define B43_NPHY_REV7_RF_CTL_MISC_REG5 B43_PHY_N(0x344) +#define B43_NPHY_REV7_RF_CTL_MISC_REG6 B43_PHY_N(0x345) +#define B43_NPHY_REV7_RF_CTL_OVER5 B43_PHY_N(0x346) +#define B43_NPHY_REV7_RF_CTL_OVER6 B43_PHY_N(0x347) + #define B43_PHY_B_BBCFG B43_PHY_N_BMODE(0x001) /* BB config */ #define B43_PHY_B_TEST B43_PHY_N_BMODE(0x00A) @@ -935,6 +944,8 @@ struct b43_phy_n { bool gain_boost; bool elna_gain_config; bool band5g_pwrgain; + bool use_int_tx_iq_lo_cal; + bool lpf_bw_overrode_for_sample_play; u8 mphase_cal_phase_id; u16 mphase_txcal_cmdidx; diff --git a/drivers/net/wireless/b43/radio_2057.h b/drivers/net/wireless/b43/radio_2057.h index 675d1bb64429..220d080238ff 100644 --- a/drivers/net/wireless/b43/radio_2057.h +++ b/drivers/net/wireless/b43/radio_2057.h @@ -84,6 +84,8 @@ #define R2057_CMOSBUF_RX_RCCR 0x04c #define R2057_LOGEN_SEL_PKDET 0x04d #define R2057_CMOSBUF_SHAREIQ_PTAT 0x04e + +/* MISC core 0 */ #define R2057_RXTXBIAS_CONFIG_CORE0 0x04f #define R2057_TXGM_TXRF_PUS_CORE0 0x050 #define R2057_TXGM_IDAC_BLEED_CORE0 0x051 @@ -204,6 +206,8 @@ #define R2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE0 0x0d1 #define R2057_LPF_GAIN_CORE0 0x0d2 #define R2057_DACBUF_IDACS_BW_CORE0 0x0d3 + +/* MISC core 1 */ #define R2057_RXTXBIAS_CONFIG_CORE1 0x0d4 #define R2057_TXGM_TXRF_PUS_CORE1 0x0d5 #define R2057_TXGM_IDAC_BLEED_CORE1 0x0d6 @@ -324,6 +328,7 @@ #define R2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE1 0x156 #define R2057_LPF_GAIN_CORE1 0x157 #define R2057_DACBUF_IDACS_BW_CORE1 0x158 + #define R2057_DACBUF_VINCM_CORE1 0x159 #define R2057_RCCAL_START_R1_Q1_P1 0x15a #define R2057_RCCAL_X1 0x15b @@ -345,6 +350,8 @@ #define R2057_RCCAL_BCAP_VAL 0x16b #define R2057_RCCAL_HPC_VAL 0x16c #define R2057_RCCAL_OVERRIDES 0x16d + +/* TX core 0 */ #define R2057_TX0_IQCAL_GAIN_BW 0x170 #define R2057_TX0_LOFT_FINE_I 0x171 #define R2057_TX0_LOFT_FINE_Q 0x172 @@ -362,6 +369,8 @@ #define R2057_TX0_TXRXCOUPLE_2G_PWRUP 0x17e #define R2057_TX0_TXRXCOUPLE_5G_ATTEN 0x17f #define R2057_TX0_TXRXCOUPLE_5G_PWRUP 0x180 + +/* TX core 1 */ #define R2057_TX1_IQCAL_GAIN_BW 0x190 #define R2057_TX1_LOFT_FINE_I 0x191 #define R2057_TX1_LOFT_FINE_Q 0x192 @@ -379,6 +388,7 @@ #define R2057_TX1_TXRXCOUPLE_2G_PWRUP 0x19e #define R2057_TX1_TXRXCOUPLE_5G_ATTEN 0x19f #define R2057_TX1_TXRXCOUPLE_5G_PWRUP 0x1a0 + #define R2057_AFE_VCM_CAL_MASTER_CORE0 0x1a1 #define R2057_AFE_SET_VCM_I_CORE0 0x1a2 #define R2057_AFE_SET_VCM_Q_CORE0 0x1a3 -- cgit v1.2.3 From 162bee1a3e5714abd9a429d85c64830bacaca682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 8 Jul 2014 15:11:08 +0200 Subject: b43: N-PHY: init and channel switching of radio 0x2057 rev 9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 47 ++++++++- drivers/net/wireless/b43/radio_2057.c | 188 ++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 44349f5b99c6..479cda88ca5e 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -746,10 +746,55 @@ static void b43_radio_2057_setup(struct b43_wldev *dev, b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C2, 0x8); } break; + case 9: /* e.g. PHY rev 16 */ + b43_radio_write(dev, R2057_LOGEN_PTAT_RESETS, 0x20); + b43_radio_write(dev, R2057_VCOBUF_IDACS, 0x18); + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { + b43_radio_write(dev, R2057_LOGEN_PTAT_RESETS, 0x38); + b43_radio_write(dev, R2057_VCOBUF_IDACS, 0x0f); + + if (b43_is_40mhz(dev)) { + /* TODO */ + } else { + b43_radio_write(dev, + R2057_PAD_BIAS_FILTER_BWS_CORE0, + 0x3c); + b43_radio_write(dev, + R2057_PAD_BIAS_FILTER_BWS_CORE1, + 0x3c); + } + } + break; /* TODO */ } - /* TODO */ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + u16 txmix2g_tune_boost_pu = 0; + u16 pad2g_tune_pus = 0; + + if (b43_nphy_ipa(dev)) { + switch (phy->radio_rev) { + case 9: + txmix2g_tune_boost_pu = 0x0041; + /* TODO */ + break; + } + /* TODO */ + } + + if (txmix2g_tune_boost_pu) + b43_radio_write(dev, R2057_TXMIX2G_TUNE_BOOST_PU_CORE0, + txmix2g_tune_boost_pu); + if (pad2g_tune_pus) + b43_radio_write(dev, R2057_PAD2G_TUNE_PUS_CORE0, + pad2g_tune_pus); + if (txmix2g_tune_boost_pu) + b43_radio_write(dev, R2057_TXMIX2G_TUNE_BOOST_PU_CORE1, + txmix2g_tune_boost_pu); + if (pad2g_tune_pus) + b43_radio_write(dev, R2057_PAD2G_TUNE_PUS_CORE1, + pad2g_tune_pus); + } usleep_range(50, 100); diff --git a/drivers/net/wireless/b43/radio_2057.c b/drivers/net/wireless/b43/radio_2057.c index df3574545819..941cf3db5a64 100644 --- a/drivers/net/wireless/b43/radio_2057.c +++ b/drivers/net/wireless/b43/radio_2057.c @@ -105,6 +105,18 @@ static u16 r2057_rev8_init[][2] = { }; */ +/* Extracted from MMIO dump of 6.30.223.141 */ +static u16 r2057_rev9_init[][2] = { + { 0x27, 0x1f }, { 0x28, 0x0a }, { 0x29, 0x2f }, { 0x42, 0x1f }, + { 0x48, 0x3f }, { 0x5c, 0x41 }, { 0x63, 0x14 }, { 0x64, 0x12 }, + { 0x66, 0xff }, { 0x74, 0xa3 }, { 0x7b, 0x14 }, { 0x7c, 0x14 }, + { 0x7d, 0xee }, { 0x86, 0xc0 }, { 0xc4, 0x10 }, { 0xc9, 0x01 }, + { 0xe1, 0x41 }, { 0xe8, 0x14 }, { 0xe9, 0x12 }, { 0xeb, 0xff }, + { 0xf5, 0x0a }, { 0xf8, 0x09 }, { 0xf9, 0xa3 }, { 0x100, 0x14 }, + { 0x101, 0x10 }, { 0x102, 0xee }, { 0x10b, 0xc0 }, { 0x149, 0x10 }, + { 0x14e, 0x01 }, { 0x1b7, 0x05 }, { 0x1c2, 0xa0 }, +}; + #define RADIOREGS7(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \ r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \ r20, r21, r22, r23, r24, r25, r26, r27) \ @@ -145,6 +157,170 @@ static u16 r2057_rev8_init[][2] = { .phy_regs.phy_bw5 = r4, \ .phy_regs.phy_bw6 = r5 +/* Extracted from MMIO dump of 6.30.223.141 */ +static const struct b43_nphy_chantabent_rev7 b43_nphy_chantab_phy_rev16_radio_rev9[] = { + { + .freq = 2412, + RADIOREGS7(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, + 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x41, 0x63, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00, + 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { + .freq = 2417, + RADIOREGS7(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, + 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x41, 0x63, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00, + 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { + .freq = 2422, + RADIOREGS7(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, + 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x41, 0x63, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00, + 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { + .freq = 2427, + RADIOREGS7(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, + 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x41, 0x63, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00, + 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { + .freq = 2432, + RADIOREGS7(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, + 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x41, 0x63, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00, + 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { + .freq = 2437, + RADIOREGS7(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, + 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x41, 0x63, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00, + 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { + .freq = 2442, + RADIOREGS7(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, + 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x41, 0x63, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00, + 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { + .freq = 2447, + RADIOREGS7(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, + 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x41, 0x63, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00, + 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { + .freq = 2452, + RADIOREGS7(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, + 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x41, 0x63, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00, + 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { + .freq = 2457, + RADIOREGS7(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, + 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x41, 0x63, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00, + 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { + .freq = 2462, + RADIOREGS7(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, + 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x41, 0x63, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x41, 0x63, 0x00, + 0x00, 0x00, 0xf0, 0x00), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, + { + .freq = 5180, + RADIOREGS7(0xbe, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x06, + 0x02, 0x0e, 0x00, 0x0e, 0x00, 0x9e, 0x00, 0x00, + 0x9f, 0x2f, 0xa3, 0x00, 0xfc, 0x00, 0x00, 0x4f, + 0x3a, 0x83, 0x00, 0xfc), + PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb), + }, + { + .freq = 5200, + RADIOREGS7(0xc5, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x08, + 0x02, 0x0e, 0x00, 0x0e, 0x00, 0x9e, 0x00, 0x00, + 0x7f, 0x2f, 0x83, 0x00, 0xf8, 0x00, 0x00, 0x4c, + 0x4a, 0x83, 0x00, 0xf8), + PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9), + }, + { + .freq = 5220, + RADIOREGS7(0xcc, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0a, + 0x02, 0x0e, 0x00, 0x0e, 0x00, 0x9e, 0x00, 0x00, + 0x6d, 0x3d, 0x83, 0x00, 0xf8, 0x00, 0x00, 0x2d, + 0x2a, 0x73, 0x00, 0xf8), + PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7), + }, + { + .freq = 5240, + RADIOREGS7(0xd2, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0c, + 0x02, 0x0d, 0x00, 0x0d, 0x00, 0x8d, 0x00, 0x00, + 0x4d, 0x1c, 0x73, 0x00, 0xf8, 0x00, 0x00, 0x4d, + 0x2b, 0x73, 0x00, 0xf8), + PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5), + }, + { + .freq = 5745, + RADIOREGS7(0x7b, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x7d, + 0x04, 0x08, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, + 0x08, 0x03, 0x03, 0x00, 0x30, 0x00, 0x00, 0x06, + 0x02, 0x03, 0x00, 0x30), + PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9), + }, + { + .freq = 5765, + RADIOREGS7(0x81, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x81, + 0x04, 0x08, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, + 0x06, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x02, 0x03, 0x00, 0x00), + PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8), + }, + { + .freq = 5785, + RADIOREGS7(0x88, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x85, + 0x04, 0x08, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, + 0x08, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x21, 0x03, 0x00, 0x00), + PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6), + }, + { + .freq = 5805, + RADIOREGS7(0x8f, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x89, + 0x04, 0x07, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, + 0x06, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x03, 0x00, 0x00), + PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4), + }, + { + .freq = 5825, + RADIOREGS7(0x95, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x8d, + 0x04, 0x07, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, + 0x05, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x03, 0x00, 0x00), + PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3), + }, +}; + void r2057_upload_inittabs(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -171,6 +347,12 @@ void r2057_upload_inittabs(struct b43_wldev *dev) size = ARRAY_SIZE(r2057_rev5a_init); } break; + case 16: + if (phy->radio_rev == 9) { + table = r2057_rev9_init[0]; + size = ARRAY_SIZE(r2057_rev9_init); + } + break; } B43_WARN_ON(!table); @@ -195,6 +377,12 @@ void r2057_get_chantabent_rev7(struct b43_wldev *dev, u16 freq, /* TODO */ switch (phy->rev) { + case 16: + if (phy->radio_rev == 9) { + e_r7 = b43_nphy_chantab_phy_rev16_radio_rev9; + len = ARRAY_SIZE(b43_nphy_chantab_phy_rev16_radio_rev9); + } + break; default: break; } -- cgit v1.2.3 From 785e7dbb75d2b3109daad37a261b9b66ece393c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 8 Jul 2014 15:11:09 +0200 Subject: b43: N-PHY: implement channel switching of radio 0x2057 rev 5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/radio_2057.c | 129 ++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/drivers/net/wireless/b43/radio_2057.c b/drivers/net/wireless/b43/radio_2057.c index 941cf3db5a64..ca22faa41d28 100644 --- a/drivers/net/wireless/b43/radio_2057.c +++ b/drivers/net/wireless/b43/radio_2057.c @@ -149,6 +149,27 @@ static u16 r2057_rev9_init[][2] = { .radio_lna2g_tune_core1 = r26, \ .radio_lna5g_tune_core1 = r27 +#define RADIOREGS7_2G(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \ + r10, r11, r12, r13, r14, r15, r16, r17) \ + .radio_vcocal_countval0 = r00, \ + .radio_vcocal_countval1 = r01, \ + .radio_rfpll_refmaster_sparextalsize = r02, \ + .radio_rfpll_loopfilter_r1 = r03, \ + .radio_rfpll_loopfilter_c2 = r04, \ + .radio_rfpll_loopfilter_c1 = r05, \ + .radio_cp_kpd_idac = r06, \ + .radio_rfpll_mmd0 = r07, \ + .radio_rfpll_mmd1 = r08, \ + .radio_vcobuf_tune = r09, \ + .radio_logen_mx2g_tune = r10, \ + .radio_logen_indbuf2g_tune = r11, \ + .radio_lna2g_tune_core0 = r12, \ + .radio_txmix2g_tune_boost_pu_core0 = r13, \ + .radio_pad2g_tune_pus_core0 = r14, \ + .radio_lna2g_tune_core1 = r15, \ + .radio_txmix2g_tune_boost_pu_core1 = r16, \ + .radio_pad2g_tune_pus_core1 = r17 + #define PHYREGS(r0, r1, r2, r3, r4, r5) \ .phy_regs.phy_bw1a = r0, \ .phy_regs.phy_bw2 = r1, \ @@ -157,6 +178,108 @@ static u16 r2057_rev9_init[][2] = { .phy_regs.phy_bw5 = r4, \ .phy_regs.phy_bw6 = r5 +/* Copied from brcmsmac (5.75.11): chan_info_nphyrev8_2057_rev5 */ +static const struct b43_nphy_chantabent_rev7_2g b43_nphy_chantab_phy_rev8_radio_rev5[] = { + { + .freq = 2412, + RADIOREGS7_2G(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, + 0x09, 0x0d, 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, + 0x03, 0xff), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { + .freq = 2417, + RADIOREGS7_2G(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, + 0x09, 0x0d, 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, + 0x03, 0xff), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { + .freq = 2422, + RADIOREGS7_2G(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, + 0x09, 0x0d, 0x08, 0x0e, 0x61, 0x03, 0xef, 0x61, + 0x03, 0xef), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { + .freq = 2427, + RADIOREGS7_2G(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, + 0x09, 0x0c, 0x08, 0x0e, 0x61, 0x03, 0xdf, 0x61, + 0x03, 0xdf), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { + .freq = 2432, + RADIOREGS7_2G(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, + 0x09, 0x0c, 0x07, 0x0d, 0x61, 0x03, 0xcf, 0x61, + 0x03, 0xcf), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { + .freq = 2437, + RADIOREGS7_2G(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, + 0x09, 0x0c, 0x07, 0x0d, 0x61, 0x03, 0xbf, 0x61, + 0x03, 0xbf), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { + .freq = 2442, + RADIOREGS7_2G(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, + 0x09, 0x0b, 0x07, 0x0d, 0x61, 0x03, 0xaf, 0x61, + 0x03, 0xaf), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { + .freq = 2447, + RADIOREGS7_2G(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, + 0x09, 0x0b, 0x07, 0x0d, 0x61, 0x03, 0x9f, 0x61, + 0x03, 0x9f), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { + .freq = 2452, + RADIOREGS7_2G(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, + 0x09, 0x0b, 0x07, 0x0d, 0x61, 0x03, 0x8f, 0x61, + 0x03, 0x8f), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { + .freq = 2457, + RADIOREGS7_2G(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, + 0x09, 0x0b, 0x07, 0x0c, 0x61, 0x03, 0x7f, 0x61, + 0x03, 0x7f), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { + .freq = 2462, + RADIOREGS7_2G(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, + 0x09, 0x0b, 0x07, 0x0c, 0x61, 0x03, 0x6f, 0x61, + 0x03, 0x6f), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, + { + .freq = 2467, + RADIOREGS7_2G(0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, + 0x09, 0x0b, 0x06, 0x0c, 0x61, 0x03, 0x5f, 0x61, + 0x03, 0x5f), + PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b), + }, + { + .freq = 2472, + RADIOREGS7_2G(0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, + 0x09, 0x0a, 0x06, 0x0b, 0x61, 0x03, 0x4f, 0x61, + 0x03, 0x4f), + PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429), + }, + { + .freq = 2484, + RADIOREGS7_2G(0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, + 0x09, 0x0a, 0x06, 0x0b, 0x61, 0x03, 0x3f, 0x61, + 0x03, 0x3f), + PHYREGS(0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424), + } +}; + /* Extracted from MMIO dump of 6.30.223.141 */ static const struct b43_nphy_chantabent_rev7 b43_nphy_chantab_phy_rev16_radio_rev9[] = { { @@ -377,6 +500,12 @@ void r2057_get_chantabent_rev7(struct b43_wldev *dev, u16 freq, /* TODO */ switch (phy->rev) { + case 8: + if (phy->radio_rev == 5) { + e_r7_2g = b43_nphy_chantab_phy_rev8_radio_rev5; + len = ARRAY_SIZE(b43_nphy_chantab_phy_rev8_radio_rev5); + } + break; case 16: if (phy->radio_rev == 9) { e_r7 = b43_nphy_chantab_phy_rev16_radio_rev9; -- cgit v1.2.3 From 3695b9324ee9bb801d7e0e76fa991683997758d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 8 Jul 2014 15:11:10 +0200 Subject: b43: enable radio 0x2057 rev 9 (AKA BCM43228) support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for N-PHY rev 8 with 0x2057 rev 5 is almost ready, but we still need to figure out how to handle rev 9 first. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 8dd69a3ae7ac..ad335307a3d4 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -210,6 +210,9 @@ static struct ieee80211_channel b43_2ghz_chantable[] = { CHAN2G(13, 2472, 0), CHAN2G(14, 2484, 0), }; + +/* No support for the last 3 channels (12, 13, 14) */ +#define b43_2ghz_chantable_limited_size 11 #undef CHAN2G #define CHAN4G(_channel, _flags) { \ @@ -335,6 +338,14 @@ static struct ieee80211_supported_band b43_band_2GHz = { .n_bitrates = b43_g_ratetable_size, }; +static struct ieee80211_supported_band b43_band_2ghz_limited = { + .band = IEEE80211_BAND_2GHZ, + .channels = b43_2ghz_chantable, + .n_channels = b43_2ghz_chantable_limited_size, + .bitrates = b43_g_ratetable, + .n_bitrates = b43_g_ratetable_size, +}; + static void b43_wireless_core_exit(struct b43_wldev *dev); static int b43_wireless_core_init(struct b43_wldev *dev); static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev); @@ -4459,7 +4470,10 @@ static int b43_phy_versioning(struct b43_wldev *dev) unsupported = 1; break; case B43_PHYTYPE_N: - if (radio_ver != 0x2055 && radio_ver != 0x2056) + if (radio_ver != 0x2055 && radio_ver != 0x2056 && + radio_ver != 0x2057) + unsupported = 1; + if (radio_ver == 0x2057 && !(radio_rev == 9)) unsupported = 1; break; case B43_PHYTYPE_LP: @@ -5095,9 +5109,15 @@ static int b43_setup_bands(struct b43_wldev *dev, bool have_2ghz_phy, bool have_5ghz_phy) { struct ieee80211_hw *hw = dev->wl->hw; + struct b43_phy *phy = &dev->phy; + bool limited_2g; + + /* We don't support all 2 GHz channels on some devices */ + limited_2g = phy->radio_ver == 0x2057 && phy->radio_rev == 9; if (have_2ghz_phy) - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz; + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = limited_2g ? + &b43_band_2ghz_limited : &b43_band_2GHz; if (dev->phy.type == B43_PHYTYPE_N) { if (have_5ghz_phy) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_nphy; -- cgit v1.2.3 From 72fcd3d16c16cd47a897cd72cd9a231aab01ac5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 8 Jul 2014 21:00:19 +0200 Subject: b43: don't warn about no 5 GHz support on 2.4 GHz devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This could be a bit confusing to see warning about lacking support for 5 GHz band if your device supports 2.4 GHz only. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ad335307a3d4..3dcd3aa38608 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -5268,14 +5268,16 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) b43_supported_bands(dev, &have_2ghz_phy, &have_5ghz_phy); /* We don't support 5 GHz on some PHYs yet */ - switch (dev->phy.type) { - case B43_PHYTYPE_A: - case B43_PHYTYPE_G: - case B43_PHYTYPE_N: - case B43_PHYTYPE_LP: - case B43_PHYTYPE_HT: - b43warn(wl, "5 GHz band is unsupported on this PHY\n"); - have_5ghz_phy = false; + if (have_5ghz_phy) { + switch (dev->phy.type) { + case B43_PHYTYPE_A: + case B43_PHYTYPE_G: + case B43_PHYTYPE_N: + case B43_PHYTYPE_LP: + case B43_PHYTYPE_HT: + b43warn(wl, "5 GHz band is unsupported on this PHY\n"); + have_5ghz_phy = false; + } } if (!have_2ghz_phy && !have_5ghz_phy) { -- cgit v1.2.3 From 50d26aa338fb290f0488e8f87c1c080d2de26e21 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:26 +0300 Subject: wlcore: save seq num only between recoveries We want seq num (freed_pkts) to be initialized on each new connection, but keep persistent between recoveries/suspends. Save the freed_pkts in the private block of the sta struct (we already do a similar thing for AP's stations). However, keep the old wlvif->total_freed_pkts in order to avoid too intrusive change. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/cmd.c | 5 +- drivers/net/wireless/ti/wlcore/main.c | 77 +++++++++++++++++++++++-------- drivers/net/wireless/ti/wlcore/wlcore_i.h | 17 ++++--- 3 files changed, 68 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index e269c0a57017..d298ead88c70 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -372,9 +372,8 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) wl1271_tx_reset_link_queues(wl, *hlid); wl->links[*hlid].wlvif = NULL; - if (wlvif->bss_type == BSS_TYPE_STA_BSS || - (wlvif->bss_type == BSS_TYPE_AP_BSS && - *hlid == wlvif->ap.bcast_hlid)) { + if (wlvif->bss_type == BSS_TYPE_AP_BSS && + *hlid == wlvif->ap.bcast_hlid) { /* * save the total freed packets in the wlvif, in case this is * recovery or suspend diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 48f83868f9cb..2996cefe4aed 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -898,6 +898,41 @@ out: wlcore_set_partition(wl, &old_part); } +static void wlcore_save_freed_pkts(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 hlid, struct ieee80211_sta *sta) +{ + struct wl1271_station *wl_sta; + + wl_sta = (void *)sta->drv_priv; + wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts; + + /* + * increment the initial seq number on recovery to account for + * transmitted packets that we haven't yet got in the FW status + */ + if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) + wl_sta->total_freed_pkts += + WL1271_TX_SQN_POST_RECOVERY_PADDING; +} + +static void wlcore_save_freed_pkts_addr(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + u8 hlid, const u8 *addr) +{ + struct ieee80211_sta *sta; + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + + if (WARN_ON(hlid == WL12XX_INVALID_LINK_ID || + is_zero_ether_addr(addr))) + return; + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, addr); + if (sta) + wlcore_save_freed_pkts(wl, wlvif, hlid, sta); + rcu_read_unlock(); +} + static void wlcore_print_recovery(struct wl1271 *wl) { u32 pc = 0; @@ -961,6 +996,13 @@ static void wl1271_recovery_work(struct work_struct *work) wlvif = list_first_entry(&wl->wlvif_list, struct wl12xx_vif, list); vif = wl12xx_wlvif_to_vif(wlvif); + + if (wlvif->bss_type == BSS_TYPE_STA_BSS && + test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { + wlcore_save_freed_pkts_addr(wl, wlvif, wlvif->sta.hlid, + vif->bss_conf.bssid); + } + __wl1271_op_remove_interface(wl, vif, false); } @@ -4703,10 +4745,6 @@ static int wl1271_allocate_sta(struct wl1271 *wl, void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) { - struct wl1271_station *wl_sta; - struct ieee80211_sta *sta; - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - if (!test_bit(hlid, wlvif->ap.sta_hlid_map)) return; @@ -4718,21 +4756,7 @@ void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) * save the last used PN in the private part of iee80211_sta, * in case of recovery/suspend */ - rcu_read_lock(); - sta = ieee80211_find_sta(vif, wl->links[hlid].addr); - if (sta) { - wl_sta = (void *)sta->drv_priv; - wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts; - - /* - * increment the initial seq number on recovery to account for - * transmitted packets that we haven't yet got in the FW status - */ - if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) - wl_sta->total_freed_pkts += - WL1271_TX_SQN_POST_RECOVERY_PADDING; - } - rcu_read_unlock(); + wlcore_save_freed_pkts_addr(wl, wlvif, hlid, wl->links[hlid].addr); wl12xx_free_link(wl, wlvif, &hlid); wl->active_sta_count--; @@ -4915,6 +4939,21 @@ static int wl12xx_update_sta_state(struct wl1271 *wl, clear_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags); } + /* save seq number on disassoc (suspend) */ + if (is_sta && + old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTH) { + wlcore_save_freed_pkts(wl, wlvif, wlvif->sta.hlid, sta); + wlvif->total_freed_pkts = 0; + } + + /* restore seq number on assoc (resume) */ + if (is_sta && + old_state == IEEE80211_STA_AUTH && + new_state == IEEE80211_STA_ASSOC) { + wlvif->total_freed_pkts = wl_sta->total_freed_pkts; + } + /* clear ROCs on failure or authorization */ if (is_sta && (new_state == IEEE80211_STA_AUTHORIZED || diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index c2c34a84ff3d..986da43ecfdd 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -324,6 +324,7 @@ struct wl1271_station { * total freed FW packets on the link to the STA - used for tracking the * AES/TKIP PN across recoveries. Re-initialized each time from the * wl1271_station structure. + * Used in both AP and STA mode. */ u64 total_freed_pkts; }; @@ -459,6 +460,13 @@ struct wl12xx_vif { /* work for canceling ROC after pending auth reply */ struct delayed_work pending_auth_complete_work; + /* + * total freed FW packets on the link. + * For STA this holds the PN of the link to the AP. + * For AP this holds the PN of the broadcast link. + */ + u64 total_freed_pkts; + /* * This struct must be last! * data that has to be saved acrossed reconfigs (e.g. recovery) @@ -466,15 +474,6 @@ struct wl12xx_vif { */ struct { u8 persistent[0]; - - /* - * total freed FW packets on the link - used for - * storing the AES/TKIP PN during recovery, as this - * structure is not zeroed out. - * For STA this holds the PN of the link to the AP. - * For AP this holds the PN of the broadcast link. - */ - u64 total_freed_pkts; }; }; -- cgit v1.2.3 From 30a003588898924964dfa537670f35aac7cd9629 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:27 +0300 Subject: wlcore: user smaller sqn padding for GEM On recovery, we increase the current seq num by WL1271_TX_SQN_POST_RECOVERY_PADDING in order to compensate for packets we might have missed during recovery. It seems that some GEM APs have issues when the gap is too big, so use a smaller padding in this case. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/cmd.c | 7 +++++-- drivers/net/wireless/ti/wlcore/main.c | 7 +++++-- drivers/net/wireless/ti/wlcore/wlcore_i.h | 3 +++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index d298ead88c70..05604ee31224 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -374,6 +374,7 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) if (wlvif->bss_type == BSS_TYPE_AP_BSS && *hlid == wlvif->ap.bcast_hlid) { + u32 sqn_padding = WL1271_TX_SQN_POST_RECOVERY_PADDING; /* * save the total freed packets in the wlvif, in case this is * recovery or suspend @@ -384,9 +385,11 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) * increment the initial seq number on recovery to account for * transmitted packets that we haven't yet got in the FW status */ + if (wlvif->encryption_type == KEY_GEM) + sqn_padding = WL1271_TX_SQN_POST_RECOVERY_PADDING_GEM; + if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) - wlvif->total_freed_pkts += - WL1271_TX_SQN_POST_RECOVERY_PADDING; + wlvif->total_freed_pkts += sqn_padding; } wl->links[*hlid].total_freed_pkts = 0; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 2996cefe4aed..1ab6dbdb47f3 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -902,6 +902,7 @@ static void wlcore_save_freed_pkts(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid, struct ieee80211_sta *sta) { struct wl1271_station *wl_sta; + u32 sqn_recovery_padding = WL1271_TX_SQN_POST_RECOVERY_PADDING; wl_sta = (void *)sta->drv_priv; wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts; @@ -910,9 +911,11 @@ static void wlcore_save_freed_pkts(struct wl1271 *wl, struct wl12xx_vif *wlvif, * increment the initial seq number on recovery to account for * transmitted packets that we haven't yet got in the FW status */ + if (wlvif->encryption_type == KEY_GEM) + sqn_recovery_padding = WL1271_TX_SQN_POST_RECOVERY_PADDING_GEM; + if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) - wl_sta->total_freed_pkts += - WL1271_TX_SQN_POST_RECOVERY_PADDING; + wl_sta->total_freed_pkts += sqn_recovery_padding; } static void wlcore_save_freed_pkts_addr(struct wl1271 *wl, diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 986da43ecfdd..0e52556044d9 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -45,6 +45,9 @@ #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) #define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff +/* Use smaller padding for GEM, as some APs have issues when it's too big */ +#define WL1271_TX_SQN_POST_RECOVERY_PADDING_GEM 0x20 + #define WL1271_CIPHER_SUITE_GEM 0x00147201 -- cgit v1.2.3 From 601d6c4e701133ae23dd1b9507bf9d3a4172e586 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:28 +0300 Subject: wl18xx: fix last tx rate calculation The last tx rate calculation didn't take into account the different indices of 11a and 11g rates tables. Add the required alignment (count only from the first 11a rate in case of 11a) Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl18xx/tx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ti/wl18xx/tx.c b/drivers/net/wireless/ti/wl18xx/tx.c index be1ebd55ac88..3406ffb53325 100644 --- a/drivers/net/wireless/ti/wl18xx/tx.c +++ b/drivers/net/wireless/ti/wl18xx/tx.c @@ -30,7 +30,7 @@ static void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif, - struct ieee80211_tx_rate *rate) + u8 band, struct ieee80211_tx_rate *rate) { u8 fw_rate = wl->fw_status->counters.tx_last_rate; @@ -43,6 +43,8 @@ void wl18xx_get_last_tx_rate(struct wl1271 *wl, struct ieee80211_vif *vif, if (fw_rate <= CONF_HW_RATE_INDEX_54MBPS) { rate->idx = fw_rate; + if (band == IEEE80211_BAND_5GHZ) + rate->idx -= CONF_HW_RATE_INDEX_6MBPS; rate->flags = 0; } else { rate->flags = IEEE80211_TX_RC_MCS; @@ -102,7 +104,8 @@ static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte) * first pass info->control.vif while it's valid, and then fill out * the info->status structures */ - wl18xx_get_last_tx_rate(wl, info->control.vif, &info->status.rates[0]); + wl18xx_get_last_tx_rate(wl, info->control.vif, + info->band, &info->status.rates[0]); info->status.rates[0].count = 1; /* no data about retries */ info->status.ack_signal = -1; -- cgit v1.2.3 From 71a301bb461da1e42e6d2764d99c683289c96f33 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:29 +0300 Subject: wlcore: use correct LAA bit The LAA bit is second bit of the MSB, not of the third byte. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 1ab6dbdb47f3..4c16262afa16 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5661,7 +5661,7 @@ static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic) memcpy(&wl->addresses[idx], &wl->addresses[0], sizeof(wl->addresses[0])); /* LAA bit */ - wl->addresses[idx].addr[2] |= BIT(1); + wl->addresses[idx].addr[0] |= BIT(1); } wl->hw->wiphy->n_addresses = WLCORE_NUM_MAC_ADDRESSES; -- cgit v1.2.3 From 936c50dd0605d7d81772f53700ef42f45525ffad Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:30 +0300 Subject: wlcore: add smart config definitions Add definitions for the smart config commands. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl18xx/cmd.h | 14 ++++++++++++++ drivers/net/wireless/ti/wlcore/cmd.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h index 6687d10899ac..03b746bf84f7 100644 --- a/drivers/net/wireless/ti/wl18xx/cmd.h +++ b/drivers/net/wireless/ti/wl18xx/cmd.h @@ -45,6 +45,20 @@ struct wl18xx_cmd_channel_switch { u8 padding[2]; } __packed; +struct wl18xx_cmd_smart_config_start { + struct wl1271_cmd_header header; + + __le32 group_id_bitmask; +} __packed; + +struct wl18xx_cmd_smart_config_set_group_key { + struct wl1271_cmd_header header; + + __le32 group_id; + + u8 key[16]; +} __packed; + int wl18xx_cmd_channel_switch(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct ieee80211_channel_switch *ch_switch); diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index 6788d7356ca5..ca6a28b03f8f 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -170,6 +170,9 @@ enum wl1271_commands { /* start of 18xx specific commands */ CMD_DFS_CHANNEL_CONFIG = 60, + CMD_SMART_CONFIG_START = 61, + CMD_SMART_CONFIG_STOP = 62, + CMD_SMART_CONFIG_SET_GROUP_KEY = 63, MAX_COMMAND_ID = 0xFFFF, }; -- cgit v1.2.3 From ccb1df948085abcac0a91154e9cabeb563b65833 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:31 +0300 Subject: wlcore/wl18xx: add smart config commands These commands configures the fw to set key, enter smart config mode, and exit it. Add relevant hw ops as well. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl18xx/cmd.c | 89 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ti/wl18xx/cmd.h | 5 +- drivers/net/wireless/ti/wl18xx/main.c | 3 ++ drivers/net/wireless/ti/wlcore/hw_ops.h | 27 ++++++++++ drivers/net/wireless/ti/wlcore/wlcore.h | 4 ++ 5 files changed, 127 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c index 7649c75cd68d..44f0b205b065 100644 --- a/drivers/net/wireless/ti/wl18xx/cmd.c +++ b/drivers/net/wireless/ti/wl18xx/cmd.c @@ -78,3 +78,92 @@ out_free: out: return ret; } + +int wl18xx_cmd_smart_config_start(struct wl1271 *wl, u32 group_bitmap) +{ + struct wl18xx_cmd_smart_config_start *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd smart config start group_bitmap=0x%x", + group_bitmap); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->group_id_bitmask = cpu_to_le32(group_bitmap); + + ret = wl1271_cmd_send(wl, CMD_SMART_CONFIG_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send smart config start command"); + goto out_free; + } + +out_free: + kfree(cmd); +out: + return ret; +} + +int wl18xx_cmd_smart_config_stop(struct wl1271 *wl) +{ + struct wl1271_cmd_header *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd smart config stop"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_send(wl, CMD_SMART_CONFIG_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send smart config stop command"); + goto out_free; + } + +out_free: + kfree(cmd); +out: + return ret; +} + +int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id, + u8 key_len, u8 *key) +{ + struct wl18xx_cmd_smart_config_set_group_key *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd smart config set group key id=0x%x", + group_id); + + if (key_len != sizeof(cmd->key)) { + wl1271_error("invalid group key size: %d", key_len); + return -E2BIG; + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->group_id = cpu_to_le32(group_id); + memcpy(cmd->key, key, key_len); + + ret = wl1271_cmd_send(wl, CMD_SMART_CONFIG_SET_GROUP_KEY, cmd, + sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send smart config set group key cmd"); + goto out_free; + } + +out_free: + kfree(cmd); +out: + return ret; +} diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h index 03b746bf84f7..92499e2dfa83 100644 --- a/drivers/net/wireless/ti/wl18xx/cmd.h +++ b/drivers/net/wireless/ti/wl18xx/cmd.h @@ -62,5 +62,8 @@ struct wl18xx_cmd_smart_config_set_group_key { int wl18xx_cmd_channel_switch(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct ieee80211_channel_switch *ch_switch); - +int wl18xx_cmd_smart_config_start(struct wl1271 *wl, u32 group_bitmap); +int wl18xx_cmd_smart_config_stop(struct wl1271 *wl); +int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id, + u8 key_len, u8 *key); #endif diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index de5b4fa5d166..2727ca38807c 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1687,6 +1687,9 @@ static struct wlcore_ops wl18xx_ops = { .convert_hwaddr = wl18xx_convert_hwaddr, .lnk_high_prio = wl18xx_lnk_high_prio, .lnk_low_prio = wl18xx_lnk_low_prio, + .smart_config_start = wl18xx_cmd_smart_config_start, + .smart_config_stop = wl18xx_cmd_smart_config_stop, + .smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key, }; /* HT cap appropriate for wide channels in 2Ghz */ diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h index 1555ff970050..aa9f82c72296 100644 --- a/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/drivers/net/wireless/ti/wlcore/hw_ops.h @@ -260,4 +260,31 @@ wlcore_hw_lnk_low_prio(struct wl1271 *wl, u8 hlid, return wl->ops->lnk_low_prio(wl, hlid, lnk); } +static inline int +wlcore_smart_config_start(struct wl1271 *wl, u32 group_bitmap) +{ + if (!wl->ops->smart_config_start) + return -EINVAL; + + return wl->ops->smart_config_start(wl, group_bitmap); +} + +static inline int +wlcore_smart_config_stop(struct wl1271 *wl) +{ + if (!wl->ops->smart_config_stop) + return -EINVAL; + + return wl->ops->smart_config_stop(wl); +} + +static inline int +wlcore_smart_config_set_group_key(struct wl1271 *wl, u16 group_id, + u8 key_len, u8 *key) +{ + if (!wl->ops->smart_config_set_group_key) + return -EINVAL; + + return wl->ops->smart_config_set_group_key(wl, group_id, key_len, key); +} #endif diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 71320509b56d..13459c4f74d0 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -117,6 +117,10 @@ struct wlcore_ops { struct wl1271_link *lnk); bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid, struct wl1271_link *lnk); + int (*smart_config_start)(struct wl1271 *wl, u32 group_bitmap); + int (*smart_config_stop)(struct wl1271 *wl); + int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id, + u8 key_len, u8 *key); }; enum wlcore_partitions { -- cgit v1.2.3 From 80ff8063e87c352072c6d96fb2d87becaf591966 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:32 +0300 Subject: wlcore: handle smart config vendor commands userspace can ask to perform various smart config actions via custom vendor commands. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/Makefile | 2 +- drivers/net/wireless/ti/wlcore/vendor_cmd.c | 184 ++++++++++++++++++++++++++++ drivers/net/wireless/ti/wlcore/vendor_cmd.h | 36 ++++++ 3 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ti/wlcore/vendor_cmd.c create mode 100644 drivers/net/wireless/ti/wlcore/vendor_cmd.h diff --git a/drivers/net/wireless/ti/wlcore/Makefile b/drivers/net/wireless/ti/wlcore/Makefile index 4f23931d7bd5..0a69c1373643 100644 --- a/drivers/net/wireless/ti/wlcore/Makefile +++ b/drivers/net/wireless/ti/wlcore/Makefile @@ -1,5 +1,5 @@ wlcore-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ - boot.o init.o debugfs.o scan.o sysfs.o + boot.o init.o debugfs.o scan.o sysfs.o vendor_cmd.o wlcore_spi-objs = spi.o wlcore_sdio-objs = sdio.o diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c new file mode 100644 index 000000000000..98852b2ceb4d --- /dev/null +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c @@ -0,0 +1,184 @@ +/* + * This file is part of wlcore + * + * Copyright (C) 2014 Texas Instruments. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include + +#include "wlcore.h" +#include "debug.h" +#include "ps.h" +#include "hw_ops.h" +#include "vendor_cmd.h" + +static const +struct nla_policy wlcore_vendor_attr_policy[NUM_WLCORE_VENDOR_ATTR] = { + [WLCORE_VENDOR_ATTR_FREQ] = { .type = NLA_U32 }, + [WLCORE_VENDOR_ATTR_GROUP_ID] = { .type = NLA_U32 }, + [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_U32, + .len = WLAN_MAX_KEY_LEN }, +}; + +static int +wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct wl1271 *wl = hw->priv; + struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR]; + int ret; + + wl1271_debug(DEBUG_CMD, "vendor cmd smart config start"); + + if (!data) + return -EINVAL; + + ret = nla_parse(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len, + wlcore_vendor_attr_policy); + if (ret) + return ret; + + if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID]) + return -EINVAL; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) { + ret = -EINVAL; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wlcore_smart_config_start(wl, + nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID])); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + + return 0; +} + +static int +wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct wl1271 *wl = hw->priv; + int ret; + + wl1271_debug(DEBUG_CMD, "testmode cmd smart config stop"); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) { + ret = -EINVAL; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wlcore_smart_config_stop(wl); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int +wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct wl1271 *wl = hw->priv; + struct nlattr *tb[NUM_WLCORE_VENDOR_ATTR]; + int ret; + + wl1271_debug(DEBUG_CMD, "testmode cmd smart config set group key"); + + if (!data) + return -EINVAL; + + ret = nla_parse(tb, MAX_WLCORE_VENDOR_ATTR, data, data_len, + wlcore_vendor_attr_policy); + if (ret) + return ret; + + if (!tb[WLCORE_VENDOR_ATTR_GROUP_ID] || + !tb[WLCORE_VENDOR_ATTR_GROUP_KEY]) + return -EINVAL; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) { + ret = -EINVAL; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wlcore_smart_config_set_group_key(wl, + nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]), + nla_len(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]), + nla_data(tb[WLCORE_VENDOR_ATTR_GROUP_KEY])); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static const struct wiphy_vendor_command wlcore_vendor_commands[] = { + { + .info = { + .vendor_id = TI_OUI, + .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_START, + }, + .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlcore_vendor_cmd_smart_config_start, + }, + { + .info = { + .vendor_id = TI_OUI, + .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_STOP, + }, + .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlcore_vendor_cmd_smart_config_stop, + }, + { + .info = { + .vendor_id = TI_OUI, + .subcmd = WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY, + }, + .flags = WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlcore_vendor_cmd_smart_config_set_group_key, + }, +}; + +void wlcore_set_vendor_commands(struct wiphy *wiphy) +{ + wiphy->vendor_commands = wlcore_vendor_commands; + wiphy->n_vendor_commands = ARRAY_SIZE(wlcore_vendor_commands); +} diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.h b/drivers/net/wireless/ti/wlcore/vendor_cmd.h new file mode 100644 index 000000000000..7e8e92fad16c --- /dev/null +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.h @@ -0,0 +1,36 @@ +/* + * This file is part of wlcore + * + * Copyright (C) 2014 Texas Instruments. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef __WLCORE_VENDOR_H__ +#define __WLCORE_VENDOR_H__ + +#define TI_OUI 0x080028 + +enum wlcore_vendor_commands { + WLCORE_VENDOR_CMD_SMART_CONFIG_START, + WLCORE_VENDOR_CMD_SMART_CONFIG_STOP, + WLCORE_VENDOR_CMD_SMART_CONFIG_SET_GROUP_KEY, + + NUM_WLCORE_VENDOR_CMD, + MAX_WLCORE_VENDOR_CMD = NUM_WLCORE_VENDOR_CMD - 1 +}; + +enum wlcore_vendor_attributes { + WLCORE_VENDOR_ATTR_FREQ, + WLCORE_VENDOR_ATTR_PSK, + WLCORE_VENDOR_ATTR_SSID, + WLCORE_VENDOR_ATTR_GROUP_ID, + WLCORE_VENDOR_ATTR_GROUP_KEY, + + NUM_WLCORE_VENDOR_ATTR, + MAX_WLCORE_VENDOR_ATTR = NUM_WLCORE_VENDOR_ATTR - 1 +}; + +#endif /* __WLCORE_VENDOR_H__ */ -- cgit v1.2.3 From e93e15fb47e53bd5dc256e2c3e40785b39ff8ff7 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:33 +0300 Subject: wlcore/wl18xx: handle smart config events add defintions and handling for smart config events (SMART_CONFIG_SYNC_EVENT_ID and SMART_CONFIG_DECODE_EVENT_ID) parse the relevant info and send it to userspace as vendor event. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl18xx/event.c | 65 +++++++++++++++++++++++++++++ drivers/net/wireless/ti/wl18xx/event.h | 2 + drivers/net/wireless/ti/wl18xx/main.c | 5 ++- drivers/net/wireless/ti/wlcore/vendor_cmd.c | 13 ++++++ drivers/net/wireless/ti/wlcore/vendor_cmd.h | 9 ++++ 5 files changed, 93 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c index c9199d7804c6..eb1848e08424 100644 --- a/drivers/net/wireless/ti/wl18xx/event.c +++ b/drivers/net/wireless/ti/wl18xx/event.c @@ -19,10 +19,12 @@ * */ +#include #include "event.h" #include "scan.h" #include "../wlcore/cmd.h" #include "../wlcore/debug.h" +#include "../wlcore/vendor_cmd.h" int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, bool *timeout) @@ -45,6 +47,58 @@ int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout); } +static int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel, + u8 sync_band) +{ + struct sk_buff *skb; + enum ieee80211_band band; + int freq; + + if (sync_band == WLCORE_BAND_5GHZ) + band = IEEE80211_BAND_5GHZ; + else + band = IEEE80211_BAND_2GHZ; + + freq = ieee80211_channel_to_frequency(sync_channel, band); + + wl1271_debug(DEBUG_EVENT, + "SMART_CONFIG_SYNC_EVENT_ID, freq: %d (chan: %d band %d)", + freq, sync_channel, sync_band); + skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, 20, + WLCORE_VENDOR_EVENT_SC_SYNC, + GFP_KERNEL); + + if (nla_put_u32(skb, WLCORE_VENDOR_ATTR_FREQ, freq)) { + kfree_skb(skb); + return -EMSGSIZE; + } + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; +} + +static int wlcore_smart_config_decode_event(struct wl1271 *wl, + u8 ssid_len, u8 *ssid, + u8 pwd_len, u8 *pwd) +{ + struct sk_buff *skb; + + wl1271_debug(DEBUG_EVENT, "SMART_CONFIG_DECODE_EVENT_ID"); + wl1271_dump_ascii(DEBUG_EVENT, "SSID:", ssid, ssid_len); + + skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, + ssid_len + pwd_len + 20, + WLCORE_VENDOR_EVENT_SC_DECODE, + GFP_KERNEL); + + if (nla_put(skb, WLCORE_VENDOR_ATTR_SSID, ssid_len, ssid) || + nla_put(skb, WLCORE_VENDOR_ATTR_PSK, pwd_len, pwd)) { + kfree_skb(skb); + return -EMSGSIZE; + } + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; +} + int wl18xx_process_mailbox_events(struct wl1271 *wl) { struct wl18xx_event_mailbox *mbox = wl->mbox; @@ -107,5 +161,16 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl) if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID) wlcore_event_roc_complete(wl); + if (vector & SMART_CONFIG_SYNC_EVENT_ID) + wlcore_smart_config_sync_event(wl, mbox->sc_sync_channel, + mbox->sc_sync_band); + + if (vector & SMART_CONFIG_DECODE_EVENT_ID) + wlcore_smart_config_decode_event(wl, + mbox->sc_ssid_len, + mbox->sc_ssid, + mbox->sc_pwd_len, + mbox->sc_pwd); + return 0; } diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h index a76e98eb8372..0680312d4943 100644 --- a/drivers/net/wireless/ti/wl18xx/event.h +++ b/drivers/net/wireless/ti/wl18xx/event.h @@ -38,6 +38,8 @@ enum { REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(18), DFS_CHANNELS_CONFIG_COMPLETE_EVENT = BIT(19), PERIODIC_SCAN_REPORT_EVENT_ID = BIT(20), + SMART_CONFIG_SYNC_EVENT_ID = BIT(22), + SMART_CONFIG_DECODE_EVENT_ID = BIT(23), }; struct wl18xx_event_mailbox { diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 2727ca38807c..4422ecf0e726 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -992,7 +992,10 @@ static int wl18xx_boot(struct wl1271 *wl) REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | INACTIVE_STA_EVENT_ID | CHANNEL_SWITCH_COMPLETE_EVENT_ID | - DFS_CHANNELS_CONFIG_COMPLETE_EVENT; + DFS_CHANNELS_CONFIG_COMPLETE_EVENT | + SMART_CONFIG_SYNC_EVENT_ID | + SMART_CONFIG_DECODE_EVENT_ID; +; wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID; diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c index 98852b2ceb4d..ad86a48dcfcb 100644 --- a/drivers/net/wireless/ti/wlcore/vendor_cmd.c +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c @@ -177,8 +177,21 @@ static const struct wiphy_vendor_command wlcore_vendor_commands[] = { }, }; +static const struct nl80211_vendor_cmd_info wlcore_vendor_events[] = { + { + .vendor_id = TI_OUI, + .subcmd = WLCORE_VENDOR_EVENT_SC_SYNC, + }, + { + .vendor_id = TI_OUI, + .subcmd = WLCORE_VENDOR_EVENT_SC_DECODE, + }, +}; + void wlcore_set_vendor_commands(struct wiphy *wiphy) { wiphy->vendor_commands = wlcore_vendor_commands; wiphy->n_vendor_commands = ARRAY_SIZE(wlcore_vendor_commands); + wiphy->vendor_events = wlcore_vendor_events; + wiphy->n_vendor_events = ARRAY_SIZE(wlcore_vendor_events); } diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.h b/drivers/net/wireless/ti/wlcore/vendor_cmd.h index 7e8e92fad16c..6e0c15e30f03 100644 --- a/drivers/net/wireless/ti/wlcore/vendor_cmd.h +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.h @@ -11,6 +11,10 @@ #ifndef __WLCORE_VENDOR_H__ #define __WLCORE_VENDOR_H__ +#ifdef __KERNEL__ +void wlcore_set_vendor_commands(struct wiphy *wiphy); +#endif + #define TI_OUI 0x080028 enum wlcore_vendor_commands { @@ -33,4 +37,9 @@ enum wlcore_vendor_attributes { MAX_WLCORE_VENDOR_ATTR = NUM_WLCORE_VENDOR_ATTR - 1 }; +enum wlcore_vendor_events { + WLCORE_VENDOR_EVENT_SC_SYNC, + WLCORE_VENDOR_EVENT_SC_DECODE, +}; + #endif /* __WLCORE_VENDOR_H__ */ -- cgit v1.2.3 From fbddf587cbd1b75557267b674c8b42a677437c69 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:34 +0300 Subject: wlcore: increase max roc duration to 30 seconds we don't have any actual limitation in the driver, so increase it arbitrarily to 30 seconds. The long ROC is needed for the smart config.flow. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 4c16262afa16..01b4d9e9af69 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5806,7 +5806,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - sizeof(struct ieee80211_header); - wl->hw->wiphy->max_remain_on_channel_duration = 5000; + wl->hw->wiphy->max_remain_on_channel_duration = 30000; wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | -- cgit v1.2.3 From d8c5a48d2751086de9ed0ae9ff97ab094e2d534d Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:35 +0300 Subject: wlcore: register vendor commands All the smart config code is in place now, so register the relevant vendor commands. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 01b4d9e9af69..d92f578dd95c 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -37,6 +37,7 @@ #include "init.h" #include "debugfs.h" #include "testmode.h" +#include "vendor_cmd.h" #include "scan.h" #include "hw_ops.h" #include "sysfs.h" @@ -5875,6 +5876,9 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->iface_combinations = wl->iface_combinations; wl->hw->wiphy->n_iface_combinations = wl->n_iface_combinations; + /* register vendor commands */ + wlcore_set_vendor_commands(wl->hw->wiphy); + SET_IEEE80211_DEV(wl->hw, wl->dev); wl->hw->sta_data_size = sizeof(struct wl1271_station); -- cgit v1.2.3 From e65628691f04f1a9ce57d8036c9b119c43031187 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Fri, 11 Jul 2014 03:01:36 +0300 Subject: wlcore: don't switch channels on disconnected STA vifs Sending the FW a channel switch command on a disconnected vif may result in a beacon loss event. Avoid this corner case. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index d92f578dd95c..ec211413ffe6 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5192,6 +5192,10 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, if (unlikely(wl->state == WLCORE_STATE_OFF)) { wl12xx_for_each_wlvif_sta(wl, wlvif) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + continue; + ieee80211_chswitch_done(vif, false); } goto out; @@ -5207,6 +5211,9 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, wl12xx_for_each_wlvif_sta(wl, wlvif) { unsigned long delay_usec; + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + continue; + ret = wl->ops->channel_switch(wl, wlvif, ch_switch); if (ret) goto out_sleep; -- cgit v1.2.3 From 1631020226ee6a95d1d9ff64562c5da1113ff77f Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Fri, 11 Jul 2014 03:01:37 +0300 Subject: wl18xx: change the number of WLAN addrs per chip Each 18xx chip contains only 2 real MAC addresses usable for WLAN, forcing us to use the LAA bit approach to obtain a third MAC address. Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl18xx/wl18xx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h index eb7cfe817010..6a2b88030c1d 100644 --- a/drivers/net/wireless/ti/wl18xx/wl18xx.h +++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h @@ -38,7 +38,7 @@ #define WL18XX_NUM_TX_DESCRIPTORS 32 #define WL18XX_NUM_RX_DESCRIPTORS 32 -#define WL18XX_NUM_MAC_ADDRESSES 3 +#define WL18XX_NUM_MAC_ADDRESSES 2 #define WL18XX_RX_BA_MAX_SESSIONS 13 -- cgit v1.2.3 From 9bccb8ae054fda9ab51e3291eeee545ecc1f1854 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:38 +0300 Subject: wl18xx: make sure fw_status->priv exists before deref In some corner cases with specific timings, we might try dequeueing tx before we got information about the link status (e.g. due to recovery during tx). Instead of NULL dereference, assume all the links in this case have low priorities. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl18xx/main.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 4422ecf0e726..edc3e4d8966d 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1609,9 +1609,14 @@ static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid, u8 thold; struct wl18xx_fw_status_priv *status_priv = (struct wl18xx_fw_status_priv *)wl->fw_status->priv; - u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap); + u32 suspend_bitmap; + + /* if we don't have the link map yet, assume they all low prio */ + if (!status_priv) + return false; /* suspended links are never high priority */ + suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap); if (test_bit(hlid, (unsigned long *)&suspend_bitmap)) return false; @@ -1631,8 +1636,13 @@ static bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid, u8 thold; struct wl18xx_fw_status_priv *status_priv = (struct wl18xx_fw_status_priv *)wl->fw_status->priv; - u32 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap); + u32 suspend_bitmap; + + /* if we don't have the link map yet, assume they all low prio */ + if (!status_priv) + return true; + suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap); if (test_bit(hlid, (unsigned long *)&suspend_bitmap)) thold = status_priv->tx_suspend_threshold; else if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) && -- cgit v1.2.3 From 5e74b3aa6ffd80128e3df605bf27d8a6a3c04997 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 11 Jul 2014 03:01:39 +0300 Subject: wlcore/wl18xx/wl12xx: convert bitmaps to unsigned longs The *_bit operations expect unsigned longs. Instead of casting the pointers, simply define various bitmaps as unsigned long (instead of u32). Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl12xx/main.c | 2 +- drivers/net/wireless/ti/wl18xx/main.c | 16 ++++++++-------- drivers/net/wireless/ti/wlcore/debugfs.c | 2 +- drivers/net/wireless/ti/wlcore/main.c | 8 ++++---- drivers/net/wireless/ti/wlcore/tx.c | 2 +- drivers/net/wireless/ti/wlcore/wlcore.h | 4 ++-- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index d50dfac91631..0bccf123831e 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -1668,7 +1668,7 @@ static bool wl12xx_lnk_high_prio(struct wl1271 *wl, u8 hlid, { u8 thold; - if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map)) + if (test_bit(hlid, &wl->fw_fast_lnk_map)) thold = wl->conf.tx.fast_link_thold; else thold = wl->conf.tx.slow_link_thold; diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index edc3e4d8966d..7af1936719eb 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1609,7 +1609,7 @@ static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid, u8 thold; struct wl18xx_fw_status_priv *status_priv = (struct wl18xx_fw_status_priv *)wl->fw_status->priv; - u32 suspend_bitmap; + unsigned long suspend_bitmap; /* if we don't have the link map yet, assume they all low prio */ if (!status_priv) @@ -1617,12 +1617,12 @@ static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid, /* suspended links are never high priority */ suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap); - if (test_bit(hlid, (unsigned long *)&suspend_bitmap)) + if (test_bit(hlid, &suspend_bitmap)) return false; /* the priority thresholds are taken from FW */ - if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) && - !test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map)) + if (test_bit(hlid, &wl->fw_fast_lnk_map) && + !test_bit(hlid, &wl->ap_fw_ps_map)) thold = status_priv->tx_fast_link_prio_threshold; else thold = status_priv->tx_slow_link_prio_threshold; @@ -1636,17 +1636,17 @@ static bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid, u8 thold; struct wl18xx_fw_status_priv *status_priv = (struct wl18xx_fw_status_priv *)wl->fw_status->priv; - u32 suspend_bitmap; + unsigned long suspend_bitmap; /* if we don't have the link map yet, assume they all low prio */ if (!status_priv) return true; suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap); - if (test_bit(hlid, (unsigned long *)&suspend_bitmap)) + if (test_bit(hlid, &suspend_bitmap)) thold = status_priv->tx_suspend_threshold; - else if (test_bit(hlid, (unsigned long *)&wl->fw_fast_lnk_map) && - !test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map)) + else if (test_bit(hlid, &wl->fw_fast_lnk_map) && + !test_bit(hlid, &wl->ap_fw_ps_map)) thold = status_priv->tx_fast_stop_threshold; else thold = status_priv->tx_slow_stop_threshold; diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index 89893c717025..0be21f62fcb0 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c @@ -496,7 +496,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_INT(sg_enabled); DRIVER_STATE_PRINT_INT(enable_11a); DRIVER_STATE_PRINT_INT(noise); - DRIVER_STATE_PRINT_HEX(ap_fw_ps_map); + DRIVER_STATE_PRINT_LHEX(ap_fw_ps_map); DRIVER_STATE_PRINT_LHEX(ap_ps_map); DRIVER_STATE_PRINT_HEX(quirks); DRIVER_STATE_PRINT_HEX(irq); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index ec211413ffe6..575c8f6d4009 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -333,7 +333,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, { bool fw_ps; - fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + fw_ps = test_bit(hlid, &wl->ap_fw_ps_map); /* * Wake up from high level PS if the STA is asleep with too little @@ -360,13 +360,13 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct wl_fw_status *status) { - u32 cur_fw_ps_map; + unsigned long cur_fw_ps_map; u8 hlid; cur_fw_ps_map = status->link_ps_bitmap; if (wl->ap_fw_ps_map != cur_fw_ps_map) { wl1271_debug(DEBUG_PSM, - "link ps prev 0x%x cur 0x%x changed 0x%x", + "link ps prev 0x%lx cur 0x%lx changed 0x%lx", wl->ap_fw_ps_map, cur_fw_ps_map, wl->ap_fw_ps_map ^ cur_fw_ps_map); @@ -4754,7 +4754,7 @@ void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) clear_bit(hlid, wlvif->ap.sta_hlid_map); __clear_bit(hlid, &wl->ap_ps_map); - __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + __clear_bit(hlid, &wl->ap_fw_ps_map); /* * save the last used PN in the private part of iee80211_sta, diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index 40b43115f835..f0ac36139bcc 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -126,7 +126,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, if (WARN_ON(!test_bit(hlid, wlvif->links_map))) return; - fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + fw_ps = test_bit(hlid, &wl->ap_fw_ps_map); tx_pkts = wl->links[hlid].allocated_pkts; /* diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 13459c4f74d0..df78cf12ef15 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -388,10 +388,10 @@ struct wl1271 { int active_link_count; /* Fast/slow links bitmap according to FW */ - u32 fw_fast_lnk_map; + unsigned long fw_fast_lnk_map; /* AP-mode - a bitmap of links currently in PS mode according to FW */ - u32 ap_fw_ps_map; + unsigned long ap_fw_ps_map; /* AP-mode - a bitmap of links currently in PS mode in mac80211 */ unsigned long ap_ps_map; -- cgit v1.2.3 From 6a06e554daef86c4e8d290284927b081fedb249e Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Fri, 11 Jul 2014 21:46:57 +0200 Subject: wireless: rt2x00: add new rt2800usb devices 0x0b05 0x17e8 RT5372 USB 2.0 bgn 2x2 ASUS USB-N14 0x0411 0x0253 RT5572 USB 2.0 abgn 2x2 BUFFALO WLP-U2-300D 0x0df6 0x0078 RT???? Sitecom N300 Cc: Ivo van Doorn Cc: Helmut Schaa Cc: John W. Linville Cc: users@rt2x00.serialmonkey.com Cc: linux-wireless@vger.kernel.org Signed-off-by: Xose Vazquez Perez Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 832006b5aab1..573897b8e878 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1284,6 +1284,8 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Arcadyan */ { USB_DEVICE(0x043e, 0x7a12) }, { USB_DEVICE(0x043e, 0x7a32) }, + /* ASUS */ + { USB_DEVICE(0x0b05, 0x17e8) }, /* Azurewave */ { USB_DEVICE(0x13d3, 0x3329) }, { USB_DEVICE(0x13d3, 0x3365) }, @@ -1320,6 +1322,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x057c, 0x8501) }, /* Buffalo */ { USB_DEVICE(0x0411, 0x0241) }, + { USB_DEVICE(0x0411, 0x0253) }, /* D-Link */ { USB_DEVICE(0x2001, 0x3c1a) }, { USB_DEVICE(0x2001, 0x3c21) }, @@ -1410,6 +1413,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0df6, 0x0053) }, { USB_DEVICE(0x0df6, 0x0069) }, { USB_DEVICE(0x0df6, 0x006f) }, + { USB_DEVICE(0x0df6, 0x0078) }, /* SMC */ { USB_DEVICE(0x083a, 0xa512) }, { USB_DEVICE(0x083a, 0xc522) }, -- cgit v1.2.3 From 2d702830e004f17e62980869e72f79775140201a Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 11 Jul 2014 20:53:13 -0700 Subject: mwifiex: access rx_reorder_tbl_ptr only while holding lock This patch fixes a bug in which rx_reorder_tbl_ptr is accessed without holding spinlock at few places. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n_rxreorder.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index b22bae3d1205..06a2c215ef5e 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -249,13 +249,22 @@ void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta) * buffered in Rx reordering table. */ static int -mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr) +mwifiex_11n_find_last_seq_num(struct reorder_tmr_cnxt *ctx) { + struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr = ctx->ptr; + struct mwifiex_private *priv = ctx->priv; + unsigned long flags; int i; - for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) - if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + for (i = rx_reorder_tbl_ptr->win_size - 1; i >= 0; --i) { + if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) { + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, + flags); return i; + } + } + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); return -1; } @@ -274,7 +283,7 @@ mwifiex_flush_data(unsigned long context) (struct reorder_tmr_cnxt *) context; int start_win, seq_num; - seq_num = mwifiex_11n_find_last_seq_num(ctx->ptr); + seq_num = mwifiex_11n_find_last_seq_num(ctx); if (seq_num < 0) return; @@ -729,9 +738,9 @@ void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv) mwifiex_del_rx_reorder_entry(priv, del_tbl_ptr); spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); } + INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); - INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); mwifiex_reset_11n_rx_seq_num(priv); } @@ -749,10 +758,14 @@ void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags) priv = adapter->priv[i]; if (!priv) continue; - if (list_empty(&priv->rx_reorder_tbl_ptr)) - continue; spin_lock_irqsave(&priv->rx_reorder_tbl_lock, lock_flags); + if (list_empty(&priv->rx_reorder_tbl_ptr)) { + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, + lock_flags); + continue; + } + list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list) tbl->flags = flags; spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, lock_flags); -- cgit v1.2.3 From d5343f06902bf6635734d1e72aa2100dd63a6f4b Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 11 Jul 2014 20:53:14 -0700 Subject: mwifiex: fix corner case system hang issue Sometimes pending internal scan commands are delayed to give preference to Tx traffic. 'scan_processing' flag has been checked at the beginning of delay timer routine to know if in the meantime scan operation has been cancelled. There is a corner case where pending scan commands are emptied after scan_processing flag check is passed. In this case wrong pointer returned by list_first_entry() is passed to list_del() which causes system hang. This patch fixes the issue by adding list_empty() check. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/main.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 3e5194fb0b0f..dfa37eadc4db 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -33,6 +33,7 @@ static void scan_delay_timer_fn(unsigned long data) struct mwifiex_private *priv = (struct mwifiex_private *)data; struct mwifiex_adapter *adapter = priv->adapter; struct cmd_ctrl_node *cmd_node, *tmp_node; + spinlock_t *scan_q_lock = &adapter->scan_pending_q_lock; unsigned long flags; if (adapter->surprise_removed) @@ -44,13 +45,13 @@ static void scan_delay_timer_fn(unsigned long data) * Abort scan operation by cancelling all pending scan * commands */ - spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + spin_lock_irqsave(scan_q_lock, flags); list_for_each_entry_safe(cmd_node, tmp_node, &adapter->scan_pending_q, list) { list_del(&cmd_node->list); mwifiex_insert_cmd_to_free_q(adapter, cmd_node); } - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + spin_unlock_irqrestore(scan_q_lock, flags); spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); adapter->scan_processing = false; @@ -79,12 +80,17 @@ static void scan_delay_timer_fn(unsigned long data) */ adapter->scan_delay_cnt = 0; adapter->empty_tx_q_cnt = 0; - spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + spin_lock_irqsave(scan_q_lock, flags); + + if (list_empty(&adapter->scan_pending_q)) { + spin_unlock_irqrestore(scan_q_lock, flags); + goto done; + } + cmd_node = list_first_entry(&adapter->scan_pending_q, struct cmd_ctrl_node, list); list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, - flags); + spin_unlock_irqrestore(scan_q_lock, flags); mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); -- cgit v1.2.3 From 2a317ad806655dbb376a97a336c6dc30cb849275 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 11 Jul 2014 20:54:32 -0700 Subject: mwifiex: fix a cut-n-paste error in adhoc-start The 'else if' branch never gets the chance as its condition matches 'if' branch's. Reported-by: David Binderman Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/join.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index fc135649b85f..0b977ea1cddb 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -949,7 +949,7 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, chan_tlv->chan_scan_param[0].radio_type |= (IEEE80211_HT_PARAM_CHA_SEC_ABOVE << 4); else if (adapter->sec_chan_offset == - IEEE80211_HT_PARAM_CHA_SEC_ABOVE) + IEEE80211_HT_PARAM_CHA_SEC_BELOW) chan_tlv->chan_scan_param[0].radio_type |= (IEEE80211_HT_PARAM_CHA_SEC_BELOW << 4); } -- cgit v1.2.3 From 30fa51c8889bfad475a6c7ec46a203092da5c162 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 11 Jul 2014 20:57:13 -0700 Subject: mwifiex: define TDLS idle timeout macro with units The unit of this timeout is in seconds. Reported-by: Paul Stewart Signed-off-by: Bing Zhao Signed-off-by: Avinash Patil Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/fw.h | 2 +- drivers/net/wireless/mwifiex/sta_cmd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 5561573452bb..49da2d53d294 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -713,7 +713,7 @@ struct mwifiex_ie_types_vendor_param_set { u8 ie[MWIFIEX_MAX_VSIE_LEN]; }; -#define MWIFIEX_TDLS_IDLE_TIMEOUT 60 +#define MWIFIEX_TDLS_IDLE_TIMEOUT_IN_SEC 60 struct mwifiex_ie_types_tdls_idle_timeout { struct mwifiex_ie_types_header header; diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 0f077aaadab6..733de92a4c61 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1647,7 +1647,7 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, timeout = (void *)(pos + config_len); timeout->header.type = cpu_to_le16(TLV_TYPE_TDLS_IDLE_TIMEOUT); timeout->header.len = cpu_to_le16(sizeof(timeout->value)); - timeout->value = cpu_to_le16(MWIFIEX_TDLS_IDLE_TIMEOUT); + timeout->value = cpu_to_le16(MWIFIEX_TDLS_IDLE_TIMEOUT_IN_SEC); config_len += sizeof(struct mwifiex_ie_types_tdls_idle_timeout); break; -- cgit v1.2.3 From ea4eb7fb0c6c5bb56fcbf2181f2d43cdfa95265a Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 11 Jul 2014 20:57:14 -0700 Subject: mwifiex: declare sta_ptr in smaller scope sta_ptr is used only in an 'if' branch in this function. Move it to the smaller scope where it is used. Reported-by: Paul Stewart Signed-off-by: Bing Zhao Signed-off-by: Avinash Patil Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 9d6d8d9f01e3..62f5dbe602d3 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -541,7 +541,6 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid, int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) { struct host_cmd_ds_11n_addba_req add_ba_req; - struct mwifiex_sta_node *sta_ptr; u32 tx_win_size = priv->add_ba_param.tx_win_size; static u8 dialog_tok; int ret; @@ -553,6 +552,8 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && priv->adapter->is_hw_11ac_capable && memcmp(priv->cfg_bssid, peer_mac, ETH_ALEN)) { + struct mwifiex_sta_node *sta_ptr; + sta_ptr = mwifiex_get_sta_entry(priv, peer_mac); if (!sta_ptr) { dev_warn(priv->adapter->dev, -- cgit v1.2.3 From b0535570869f0f4c66f41811d9d941f2e5866b47 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 11 Jul 2014 20:57:15 -0700 Subject: mwifiex: correct a typo in mwifiex_ret_tdls_oper This patch fixes this typo. Reported-by: Paul Stewart Signed-off-by: Bing Zhao Signed-off-by: Avinash Patil Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 822357b7b0bb..08b78baeb846 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -908,7 +908,7 @@ static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv, break; default: dev_err(priv->adapter->dev, - "Unknown TDLS command action respnse %d", action); + "Unknown TDLS command action response %d", action); return -1; } -- cgit v1.2.3 From 5779ae6a5559252adabc5b5e807381dc7a16f1ff Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Sat, 12 Jul 2014 08:49:34 +0200 Subject: brcmfmac: Cleanup used device IDs. This patch cleans up used broadcom IDs, device IDs for all the bus layers and uses consistent naming for all IDs. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 23 +++++---- drivers/net/wireless/brcm80211/brcmfmac/chip.c | 28 +++++----- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 32 ++++++------ drivers/net/wireless/brcm80211/brcmfmac/usb.c | 49 +++++++++--------- .../net/wireless/brcm80211/include/brcm_hw_ids.h | 60 +++++++++++++++------- 5 files changed, 107 insertions(+), 85 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index a16e644e7c08..f467cafe3e8f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -979,18 +978,20 @@ out: return ret; } +#define BRCMF_SDIO_DEVICE(dev_id) \ + {SDIO_DEVICE(BRCM_SDIO_VENDOR_ID_BROADCOM, dev_id)} + /* devices we support, null terminated */ static const struct sdio_device_id brcmf_sdmmc_ids[] = { - {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43143)}, - {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43241)}, - {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)}, - {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)}, - {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)}, - {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43362)}, - {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, - SDIO_DEVICE_ID_BROADCOM_4335_4339)}, - {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4354)}, - { /* end: all zeroes */ }, + BRCMF_SDIO_DEVICE(BRCM_SDIO_43143_DEVICE_ID), + BRCMF_SDIO_DEVICE(BRCM_SDIO_43241_DEVICE_ID), + BRCMF_SDIO_DEVICE(BRCM_SDIO_4329_DEVICE_ID), + BRCMF_SDIO_DEVICE(BRCM_SDIO_4330_DEVICE_ID), + BRCMF_SDIO_DEVICE(BRCM_SDIO_4334_DEVICE_ID), + BRCMF_SDIO_DEVICE(BRCM_SDIO_43362_DEVICE_ID), + BRCMF_SDIO_DEVICE(BRCM_SDIO_4335_4339_DEVICE_ID), + BRCMF_SDIO_DEVICE(BRCM_SDIO_4354_DEVICE_ID), + { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index c7c9f15c0fe0..96800db0536b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -482,30 +482,30 @@ static inline int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci) { switch (ci->pub.chip) { - case BCM4329_CHIP_ID: + case BRCM_CC_4329_CHIP_ID: ci->pub.ramsize = BCM4329_RAMSIZE; break; - case BCM43143_CHIP_ID: + case BRCM_CC_43143_CHIP_ID: ci->pub.ramsize = BCM43143_RAMSIZE; break; - case BCM43241_CHIP_ID: + case BRCM_CC_43241_CHIP_ID: ci->pub.ramsize = 0x90000; break; - case BCM4330_CHIP_ID: + case BRCM_CC_4330_CHIP_ID: ci->pub.ramsize = 0x48000; break; - case BCM4334_CHIP_ID: + case BRCM_CC_4334_CHIP_ID: ci->pub.ramsize = 0x80000; break; - case BCM4335_CHIP_ID: + case BRCM_CC_4335_CHIP_ID: ci->pub.ramsize = 0xc0000; ci->pub.rambase = 0x180000; break; - case BCM43362_CHIP_ID: + case BRCM_CC_43362_CHIP_ID: ci->pub.ramsize = 0x3c000; break; - case BCM4339_CHIP_ID: - case BCM4354_CHIP_ID: + case BRCM_CC_4339_CHIP_ID: + case BRCM_CC_4354_CHIP_ID: ci->pub.ramsize = 0xc0000; ci->pub.rambase = 0x180000; break; @@ -682,7 +682,7 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) ci->pub.chiprev); if (socitype == SOCI_SB) { - if (ci->pub.chip != BCM4329_CHIP_ID) { + if (ci->pub.chip != BRCM_CC_4329_CHIP_ID) { brcmf_err("SB chip is not supported\n"); return -ENODEV; } @@ -1008,13 +1008,13 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) chip = container_of(pub, struct brcmf_chip_priv, pub); switch (pub->chip) { - case BCM4354_CHIP_ID: + case BRCM_CC_4354_CHIP_ID: /* explicitly check SR engine enable bit */ pmu_cc3_mask = BIT(2); /* fall-through */ - case BCM43241_CHIP_ID: - case BCM4335_CHIP_ID: - case BCM4339_CHIP_ID: + case BRCM_CC_43241_CHIP_ID: + case BRCM_CC_4335_CHIP_ID: + case BRCM_CC_4339_CHIP_ID: /* read PMU chipcontrol register 3 */ addr = CORE_CC_REG(base, chipcontrol_addr); chip->ops->write32(chip->ctx, addr, 3); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 8fa0dbbbda72..bf9bc2d89230 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -620,16 +620,16 @@ enum brcmf_firmware_type { name ## _FIRMWARE_NAME, name ## _NVRAM_NAME static const struct brcmf_firmware_names brcmf_fwname_data[] = { - { BCM43143_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43143) }, - { BCM43241_CHIP_ID, 0x0000001F, BRCMF_FIRMWARE_NVRAM(BCM43241B0) }, - { BCM43241_CHIP_ID, 0xFFFFFFE0, BRCMF_FIRMWARE_NVRAM(BCM43241B4) }, - { BCM4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) }, - { BCM4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) }, - { BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) }, - { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }, - { BCM43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) }, - { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }, - { BCM4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) } + { BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43143) }, + { BRCM_CC_43241_CHIP_ID, 0x0000001F, BRCMF_FIRMWARE_NVRAM(BCM43241B0) }, + { BRCM_CC_43241_CHIP_ID, 0xFFFFFFE0, BRCMF_FIRMWARE_NVRAM(BCM43241B4) }, + { BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) }, + { BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) }, + { BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) }, + { BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }, + { BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) }, + { BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }, + { BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) } }; static const char *brcmf_sdio_get_fwname(struct brcmf_chip *ci, @@ -3598,17 +3598,17 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, return; switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) { - case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): + case SDIOD_DRVSTR_KEY(BRCM_CC_4330_CHIP_ID, 12): str_tab = sdiod_drvstr_tab1_1v8; str_mask = 0x00003800; str_shift = 11; break; - case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): + case SDIOD_DRVSTR_KEY(BRCM_CC_4334_CHIP_ID, 17): str_tab = sdiod_drvstr_tab6_1v8; str_mask = 0x00001800; str_shift = 11; break; - case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): + case SDIOD_DRVSTR_KEY(BRCM_CC_43143_CHIP_ID, 17): /* note: 43143 does not support tristate */ i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1; if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) { @@ -3619,7 +3619,7 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n", ci->name, drivestrength); break; - case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): + case SDIOD_DRVSTR_KEY(BRCM_CC_43362_CHIP_ID, 13): str_tab = sdiod_drive_strength_tab5_1v8; str_mask = 0x00003800; str_shift = 11; @@ -3720,12 +3720,12 @@ static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr) u32 val, rev; val = brcmf_sdiod_regrl(sdiodev, addr, NULL); - if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 && + if (sdiodev->func[0]->device == BRCM_SDIO_4335_4339_DEVICE_ID && addr == CORE_CC_REG(SI_ENUM_BASE, chipid)) { rev = (val & CID_REV_MASK) >> CID_REV_SHIFT; if (rev >= 2) { val &= ~CID_ID_MASK; - val |= BCM4339_CHIP_ID; + val |= BRCM_CC_4339_CHIP_ID; } } return val; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index b732a99e402c..dc135915470d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -913,16 +914,16 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo) static bool brcmf_usb_chip_support(int chipid, int chiprev) { switch(chipid) { - case 43143: + case BRCM_CC_43143_CHIP_ID: return true; - case 43235: - case 43236: - case 43238: + case BRCM_CC_43235_CHIP_ID: + case BRCM_CC_43236_CHIP_ID: + case BRCM_CC_43238_CHIP_ID: return (chiprev == 3); - case 43242: + case BRCM_CC_43242_CHIP_ID: return true; - case 43566: - case 43569: + case BRCM_CC_43566_CHIP_ID: + case BRCM_CC_43569_CHIP_ID: return true; default: break; @@ -1016,16 +1017,16 @@ static int check_file(const u8 *headers) static const char *brcmf_usb_get_fwname(struct brcmf_usbdev_info *devinfo) { switch (devinfo->bus_pub.devid) { - case 43143: + case BRCM_CC_43143_CHIP_ID: return BRCMF_USB_43143_FW_NAME; - case 43235: - case 43236: - case 43238: + case BRCM_CC_43235_CHIP_ID: + case BRCM_CC_43236_CHIP_ID: + case BRCM_CC_43238_CHIP_ID: return BRCMF_USB_43236_FW_NAME; - case 43242: + case BRCM_CC_43242_CHIP_ID: return BRCMF_USB_43242_FW_NAME; - case 43566: - case 43569: + case BRCM_CC_43566_CHIP_ID: + case BRCM_CC_43569_CHIP_ID: return BRCMF_USB_43569_FW_NAME; default: return NULL; @@ -1366,21 +1367,17 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf) brcmf_usb_probe_phase2); } -#define BRCMF_USB_VENDOR_ID_BROADCOM 0x0a5c -#define BRCMF_USB_DEVICE_ID_43143 0xbd1e -#define BRCMF_USB_DEVICE_ID_43236 0xbd17 -#define BRCMF_USB_DEVICE_ID_43242 0xbd1f -#define BRCMF_USB_DEVICE_ID_43569 0xbd27 -#define BRCMF_USB_DEVICE_ID_BCMFW 0x0bdc +#define BRCMF_USB_DEVICE(dev_id) \ + { USB_DEVICE(BRCM_USB_VENDOR_ID_BROADCOM, dev_id) } static struct usb_device_id brcmf_usb_devid_table[] = { - { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43143) }, - { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43236) }, - { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43242) }, - { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43569) }, + BRCMF_USB_DEVICE(BRCM_USB_43143_DEVICE_ID), + BRCMF_USB_DEVICE(BRCM_USB_43236_DEVICE_ID), + BRCMF_USB_DEVICE(BRCM_USB_43242_DEVICE_ID), + BRCMF_USB_DEVICE(BRCM_USB_43569_DEVICE_ID), /* special entry for device with firmware loaded and running */ - { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) }, - { } + BRCMF_USB_DEVICE(BRCM_USB_BCMFW_DEVICE_ID), + { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table); diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index d816270db3be..64d1a7ba040c 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -17,32 +17,56 @@ #ifndef _BRCM_HW_IDS_H_ #define _BRCM_HW_IDS_H_ -#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ +#include +#include + +#define BRCM_USB_VENDOR_ID_BROADCOM 0x0a5c +#define BRCM_PCIE_VENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM +#define BRCM_SDIO_VENDOR_ID_BROADCOM SDIO_VENDOR_ID_BROADCOM + +/* Chipcommon Core Chip IDs */ +#define BRCM_CC_43143_CHIP_ID 43143 +#define BRCM_CC_43235_CHIP_ID 43235 +#define BRCM_CC_43236_CHIP_ID 43236 +#define BRCM_CC_43238_CHIP_ID 43238 +#define BRCM_CC_43241_CHIP_ID 0x4324 +#define BRCM_CC_43242_CHIP_ID 43242 +#define BRCM_CC_4329_CHIP_ID 0x4329 +#define BRCM_CC_4330_CHIP_ID 0x4330 +#define BRCM_CC_4334_CHIP_ID 0x4334 +#define BRCM_CC_43362_CHIP_ID 43362 +#define BRCM_CC_4335_CHIP_ID 0x4335 +#define BRCM_CC_4339_CHIP_ID 0x4339 +#define BRCM_CC_4354_CHIP_ID 0x4354 +#define BRCM_CC_43566_CHIP_ID 43566 +#define BRCM_CC_43569_CHIP_ID 43569 + +/* SDIO Device IDs */ +#define BRCM_SDIO_43143_DEVICE_ID BRCM_CC_43143_CHIP_ID +#define BRCM_SDIO_43241_DEVICE_ID BRCM_CC_43241_CHIP_ID +#define BRCM_SDIO_4329_DEVICE_ID BRCM_CC_4329_CHIP_ID +#define BRCM_SDIO_4330_DEVICE_ID BRCM_CC_4330_CHIP_ID +#define BRCM_SDIO_4334_DEVICE_ID BRCM_CC_4334_CHIP_ID +#define BRCM_SDIO_43362_DEVICE_ID BRCM_CC_43362_CHIP_ID +#define BRCM_SDIO_4335_4339_DEVICE_ID BRCM_CC_4335_CHIP_ID +#define BRCM_SDIO_4354_DEVICE_ID BRCM_CC_4354_CHIP_ID +/* USB Device IDs */ +#define BRCM_USB_43143_DEVICE_ID 0xbd1e +#define BRCM_USB_43236_DEVICE_ID 0xbd17 +#define BRCM_USB_43242_DEVICE_ID 0xbd1f +#define BRCM_USB_43569_DEVICE_ID 0xbd27 +#define BRCM_USB_BCMFW_DEVICE_ID 0x0bdc + +/* brcmsmac IDs */ +#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ #define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */ #define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db */ - #define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */ - #define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */ #define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */ -/* Chipcommon Core Chip IDs */ #define BCM4313_CHIP_ID 0x4313 -#define BCM43143_CHIP_ID 43143 #define BCM43224_CHIP_ID 43224 -#define BCM43225_CHIP_ID 43225 -#define BCM43235_CHIP_ID 43235 -#define BCM43236_CHIP_ID 43236 -#define BCM43238_CHIP_ID 43238 -#define BCM43241_CHIP_ID 0x4324 -#define BCM4329_CHIP_ID 0x4329 -#define BCM4330_CHIP_ID 0x4330 -#define BCM4331_CHIP_ID 0x4331 -#define BCM4334_CHIP_ID 0x4334 -#define BCM4335_CHIP_ID 0x4335 -#define BCM43362_CHIP_ID 43362 -#define BCM4339_CHIP_ID 0x4339 -#define BCM4354_CHIP_ID 0x4354 #endif /* _BRCM_HW_IDS_H_ */ -- cgit v1.2.3 From 1b1e4e9e3abca01b7be6400db879ca8c475a2c96 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 12 Jul 2014 08:49:35 +0200 Subject: brcmfmac: make use of seq_file API for debugfs entries The use of seq_file simplifies the debugfs code. Simpler is better. Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c | 249 ++++++++++----------- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 122 ++++------ 2 files changed, 170 insertions(+), 201 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c index 03fe8aca4d32..e1ac932a3154 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c @@ -41,28 +41,27 @@ void brcmf_debugfs_exit(void) root_folder = NULL; } -static -ssize_t brcmf_debugfs_chipinfo_read(struct file *f, char __user *data, - size_t count, loff_t *ppos) +static int brcmf_debugfs_chipinfo_read(struct seq_file *seq, void *data) { - struct brcmf_pub *drvr = f->private_data; + struct brcmf_pub *drvr = seq->private; struct brcmf_bus *bus = drvr->bus_if; - char buf[40]; - int res; - /* only allow read from start */ - if (*ppos > 0) - return 0; + seq_printf(seq, "chip: %x(%u) rev %u\n", + bus->chip, bus->chip, bus->chiprev); + return 0; +} - res = scnprintf(buf, sizeof(buf), "chip: %x(%u) rev %u\n", - bus->chip, bus->chip, bus->chiprev); - return simple_read_from_buffer(data, count, ppos, buf, res); +static int brcmf_debugfs_chipinfo_open(struct inode *inode, struct file *f) +{ + return single_open(f, brcmf_debugfs_chipinfo_read, inode->i_private); } static const struct file_operations brcmf_debugfs_chipinfo_ops = { .owner = THIS_MODULE, - .open = simple_open, - .read = brcmf_debugfs_chipinfo_read + .open = brcmf_debugfs_chipinfo_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek }; static int brcmf_debugfs_create_chipinfo(struct brcmf_pub *drvr) @@ -98,55 +97,54 @@ struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr) return drvr->dbgfs_dir; } -static -ssize_t brcmf_debugfs_sdio_counter_read(struct file *f, char __user *data, - size_t count, loff_t *ppos) +static int brcmf_debugfs_sdio_count_read(struct seq_file *seq, void *data) { - struct brcmf_sdio_count *sdcnt = f->private_data; - char buf[750]; - int res; - - /* only allow read from start */ - if (*ppos > 0) - return 0; - - res = scnprintf(buf, sizeof(buf), - "intrcount: %u\nlastintrs: %u\n" - "pollcnt: %u\nregfails: %u\n" - "tx_sderrs: %u\nfcqueued: %u\n" - "rxrtx: %u\nrx_toolong: %u\n" - "rxc_errors: %u\nrx_hdrfail: %u\n" - "rx_badhdr: %u\nrx_badseq: %u\n" - "fc_rcvd: %u\nfc_xoff: %u\n" - "fc_xon: %u\nrxglomfail: %u\n" - "rxglomframes: %u\nrxglompkts: %u\n" - "f2rxhdrs: %u\nf2rxdata: %u\n" - "f2txdata: %u\nf1regdata: %u\n" - "tickcnt: %u\ntx_ctlerrs: %lu\n" - "tx_ctlpkts: %lu\nrx_ctlerrs: %lu\n" - "rx_ctlpkts: %lu\nrx_readahead: %lu\n", - sdcnt->intrcount, sdcnt->lastintrs, - sdcnt->pollcnt, sdcnt->regfails, - sdcnt->tx_sderrs, sdcnt->fcqueued, - sdcnt->rxrtx, sdcnt->rx_toolong, - sdcnt->rxc_errors, sdcnt->rx_hdrfail, - sdcnt->rx_badhdr, sdcnt->rx_badseq, - sdcnt->fc_rcvd, sdcnt->fc_xoff, - sdcnt->fc_xon, sdcnt->rxglomfail, - sdcnt->rxglomframes, sdcnt->rxglompkts, - sdcnt->f2rxhdrs, sdcnt->f2rxdata, - sdcnt->f2txdata, sdcnt->f1regdata, - sdcnt->tickcnt, sdcnt->tx_ctlerrs, - sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs, - sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt); - - return simple_read_from_buffer(data, count, ppos, buf, res); + struct brcmf_sdio_count *sdcnt = seq->private; + + seq_printf(seq, + "intrcount: %u\nlastintrs: %u\n" + "pollcnt: %u\nregfails: %u\n" + "tx_sderrs: %u\nfcqueued: %u\n" + "rxrtx: %u\nrx_toolong: %u\n" + "rxc_errors: %u\nrx_hdrfail: %u\n" + "rx_badhdr: %u\nrx_badseq: %u\n" + "fc_rcvd: %u\nfc_xoff: %u\n" + "fc_xon: %u\nrxglomfail: %u\n" + "rxglomframes: %u\nrxglompkts: %u\n" + "f2rxhdrs: %u\nf2rxdata: %u\n" + "f2txdata: %u\nf1regdata: %u\n" + "tickcnt: %u\ntx_ctlerrs: %lu\n" + "tx_ctlpkts: %lu\nrx_ctlerrs: %lu\n" + "rx_ctlpkts: %lu\nrx_readahead: %lu\n", + sdcnt->intrcount, sdcnt->lastintrs, + sdcnt->pollcnt, sdcnt->regfails, + sdcnt->tx_sderrs, sdcnt->fcqueued, + sdcnt->rxrtx, sdcnt->rx_toolong, + sdcnt->rxc_errors, sdcnt->rx_hdrfail, + sdcnt->rx_badhdr, sdcnt->rx_badseq, + sdcnt->fc_rcvd, sdcnt->fc_xoff, + sdcnt->fc_xon, sdcnt->rxglomfail, + sdcnt->rxglomframes, sdcnt->rxglompkts, + sdcnt->f2rxhdrs, sdcnt->f2rxdata, + sdcnt->f2txdata, sdcnt->f1regdata, + sdcnt->tickcnt, sdcnt->tx_ctlerrs, + sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs, + sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt); + + return 0; +} + +static int brcmf_debugfs_sdio_count_open(struct inode *inode, struct file *f) +{ + return single_open(f, brcmf_debugfs_sdio_count_read, inode->i_private); } static const struct file_operations brcmf_debugfs_sdio_counter_ops = { .owner = THIS_MODULE, - .open = simple_open, - .read = brcmf_debugfs_sdio_counter_read + .open = brcmf_debugfs_sdio_count_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek }; void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr, @@ -159,79 +157,78 @@ void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr, sdcnt, &brcmf_debugfs_sdio_counter_ops); } -static -ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data, - size_t count, loff_t *ppos) +static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data) +{ + struct brcmf_fws_stats *fwstats = seq->private; + + seq_printf(seq, + "header_pulls: %u\n" + "header_only_pkt: %u\n" + "tlv_parse_failed: %u\n" + "tlv_invalid_type: %u\n" + "mac_update_fails: %u\n" + "ps_update_fails: %u\n" + "if_update_fails: %u\n" + "pkt2bus: %u\n" + "generic_error: %u\n" + "rollback_success: %u\n" + "rollback_failed: %u\n" + "delayq_full: %u\n" + "supprq_full: %u\n" + "txs_indicate: %u\n" + "txs_discard: %u\n" + "txs_suppr_core: %u\n" + "txs_suppr_ps: %u\n" + "txs_tossed: %u\n" + "txs_host_tossed: %u\n" + "bus_flow_block: %u\n" + "fws_flow_block: %u\n" + "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n" + "requested_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n", + fwstats->header_pulls, + fwstats->header_only_pkt, + fwstats->tlv_parse_failed, + fwstats->tlv_invalid_type, + fwstats->mac_update_failed, + fwstats->mac_ps_update_failed, + fwstats->if_update_failed, + fwstats->pkt2bus, + fwstats->generic_error, + fwstats->rollback_success, + fwstats->rollback_failed, + fwstats->delayq_full_error, + fwstats->supprq_full_error, + fwstats->txs_indicate, + fwstats->txs_discard, + fwstats->txs_supp_core, + fwstats->txs_supp_ps, + fwstats->txs_tossed, + fwstats->txs_host_tossed, + fwstats->bus_flow_block, + fwstats->fws_flow_block, + fwstats->send_pkts[0], fwstats->send_pkts[1], + fwstats->send_pkts[2], fwstats->send_pkts[3], + fwstats->send_pkts[4], + fwstats->requested_sent[0], + fwstats->requested_sent[1], + fwstats->requested_sent[2], + fwstats->requested_sent[3], + fwstats->requested_sent[4]); + + return 0; +} + +static int brcmf_debugfs_fws_stats_open(struct inode *inode, struct file *f) { - struct brcmf_fws_stats *fwstats = f->private_data; - char buf[650]; - int res; - - /* only allow read from start */ - if (*ppos > 0) - return 0; - - res = scnprintf(buf, sizeof(buf), - "header_pulls: %u\n" - "header_only_pkt: %u\n" - "tlv_parse_failed: %u\n" - "tlv_invalid_type: %u\n" - "mac_update_fails: %u\n" - "ps_update_fails: %u\n" - "if_update_fails: %u\n" - "pkt2bus: %u\n" - "generic_error: %u\n" - "rollback_success: %u\n" - "rollback_failed: %u\n" - "delayq_full: %u\n" - "supprq_full: %u\n" - "txs_indicate: %u\n" - "txs_discard: %u\n" - "txs_suppr_core: %u\n" - "txs_suppr_ps: %u\n" - "txs_tossed: %u\n" - "txs_host_tossed: %u\n" - "bus_flow_block: %u\n" - "fws_flow_block: %u\n" - "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n" - "requested_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n", - fwstats->header_pulls, - fwstats->header_only_pkt, - fwstats->tlv_parse_failed, - fwstats->tlv_invalid_type, - fwstats->mac_update_failed, - fwstats->mac_ps_update_failed, - fwstats->if_update_failed, - fwstats->pkt2bus, - fwstats->generic_error, - fwstats->rollback_success, - fwstats->rollback_failed, - fwstats->delayq_full_error, - fwstats->supprq_full_error, - fwstats->txs_indicate, - fwstats->txs_discard, - fwstats->txs_supp_core, - fwstats->txs_supp_ps, - fwstats->txs_tossed, - fwstats->txs_host_tossed, - fwstats->bus_flow_block, - fwstats->fws_flow_block, - fwstats->send_pkts[0], fwstats->send_pkts[1], - fwstats->send_pkts[2], fwstats->send_pkts[3], - fwstats->send_pkts[4], - fwstats->requested_sent[0], - fwstats->requested_sent[1], - fwstats->requested_sent[2], - fwstats->requested_sent[3], - fwstats->requested_sent[4]); - - return simple_read_from_buffer(data, count, ppos, buf, res); + return single_open(f, brcmf_debugfs_fws_stats_read, inode->i_private); } static const struct file_operations brcmf_debugfs_fws_stats_ops = { .owner = THIS_MODULE, - .open = simple_open, - .read = brcmf_debugfs_fws_stats_read + .open = brcmf_debugfs_fws_stats_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek }; void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index bf9bc2d89230..0c98a7942a0f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2898,16 +2898,13 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) } #ifdef DEBUG -static int brcmf_sdio_dump_console(struct brcmf_sdio *bus, - struct sdpcm_shared *sh, char __user *data, - size_t count) +static int brcmf_sdio_dump_console(struct seq_file *seq, struct brcmf_sdio *bus, + struct sdpcm_shared *sh) { u32 addr, console_ptr, console_size, console_index; char *conbuf = NULL; __le32 sh_val; int rv; - loff_t pos = 0; - int nbytes = 0; /* obtain console information from device memory */ addr = sh->console_addr + offsetof(struct rte_console, log_le); @@ -2945,33 +2942,24 @@ static int brcmf_sdio_dump_console(struct brcmf_sdio *bus, if (rv < 0) goto done; - rv = simple_read_from_buffer(data, count, &pos, - conbuf + console_index, - console_size - console_index); + rv = seq_write(seq, conbuf + console_index, + console_size - console_index); if (rv < 0) goto done; - nbytes = rv; - if (console_index > 0) { - pos = 0; - rv = simple_read_from_buffer(data+nbytes, count, &pos, - conbuf, console_index - 1); - if (rv < 0) - goto done; - rv += nbytes; - } + if (console_index > 0) + rv = seq_write(seq, conbuf, console_index - 1); + done: vfree(conbuf); return rv; } -static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh, - char __user *data, size_t count) +static int brcmf_sdio_trap_info(struct seq_file *seq, struct brcmf_sdio *bus, + struct sdpcm_shared *sh) { - int error, res; - char buf[350]; + int error; struct brcmf_trap_info tr; - loff_t pos = 0; if ((sh->flags & SDPCM_SHARED_TRAP) == 0) { brcmf_dbg(INFO, "no trap in firmware\n"); @@ -2983,34 +2971,30 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh, if (error < 0) return error; - res = scnprintf(buf, sizeof(buf), - "dongle trap info: type 0x%x @ epc 0x%08x\n" - " cpsr 0x%08x spsr 0x%08x sp 0x%08x\n" - " lr 0x%08x pc 0x%08x offset 0x%x\n" - " r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n" - " r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n", - le32_to_cpu(tr.type), le32_to_cpu(tr.epc), - le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr), - le32_to_cpu(tr.r13), le32_to_cpu(tr.r14), - le32_to_cpu(tr.pc), sh->trap_addr, - le32_to_cpu(tr.r0), le32_to_cpu(tr.r1), - le32_to_cpu(tr.r2), le32_to_cpu(tr.r3), - le32_to_cpu(tr.r4), le32_to_cpu(tr.r5), - le32_to_cpu(tr.r6), le32_to_cpu(tr.r7)); - - return simple_read_from_buffer(data, count, &pos, buf, res); + seq_printf(seq, + "dongle trap info: type 0x%x @ epc 0x%08x\n" + " cpsr 0x%08x spsr 0x%08x sp 0x%08x\n" + " lr 0x%08x pc 0x%08x offset 0x%x\n" + " r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n" + " r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n", + le32_to_cpu(tr.type), le32_to_cpu(tr.epc), + le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr), + le32_to_cpu(tr.r13), le32_to_cpu(tr.r14), + le32_to_cpu(tr.pc), sh->trap_addr, + le32_to_cpu(tr.r0), le32_to_cpu(tr.r1), + le32_to_cpu(tr.r2), le32_to_cpu(tr.r3), + le32_to_cpu(tr.r4), le32_to_cpu(tr.r5), + le32_to_cpu(tr.r6), le32_to_cpu(tr.r7)); + + return 0; } -static int brcmf_sdio_assert_info(struct brcmf_sdio *bus, - struct sdpcm_shared *sh, char __user *data, - size_t count) +static int brcmf_sdio_assert_info(struct seq_file *seq, struct brcmf_sdio *bus, + struct sdpcm_shared *sh) { int error = 0; - char buf[200]; char file[80] = "?"; char expr[80] = ""; - int res; - loff_t pos = 0; if ((sh->flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { brcmf_dbg(INFO, "firmware not built with -assert\n"); @@ -3035,10 +3019,9 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus, } sdio_release_host(bus->sdiodev->func[1]); - res = scnprintf(buf, sizeof(buf), - "dongle assert: %s:%d: assert(%s)\n", - file, sh->assert_line, expr); - return simple_read_from_buffer(data, count, &pos, buf, res); + seq_printf(seq, "dongle assert: %s:%d: assert(%s)\n", + file, sh->assert_line, expr); + return 0; } static int brcmf_sdio_checkdied(struct brcmf_sdio *bus) @@ -3062,58 +3045,47 @@ static int brcmf_sdio_checkdied(struct brcmf_sdio *bus) return 0; } -static int brcmf_sdio_died_dump(struct brcmf_sdio *bus, char __user *data, - size_t count, loff_t *ppos) +static int brcmf_sdio_died_dump(struct seq_file *seq, struct brcmf_sdio *bus) { int error = 0; struct sdpcm_shared sh; - int nbytes = 0; - loff_t pos = *ppos; - - if (pos != 0) - return 0; error = brcmf_sdio_readshared(bus, &sh); if (error < 0) goto done; - error = brcmf_sdio_assert_info(bus, &sh, data, count); + error = brcmf_sdio_assert_info(seq, bus, &sh); if (error < 0) goto done; - nbytes = error; - error = brcmf_sdio_trap_info(bus, &sh, data+nbytes, count); + error = brcmf_sdio_trap_info(seq, bus, &sh); if (error < 0) goto done; - nbytes += error; - error = brcmf_sdio_dump_console(bus, &sh, data+nbytes, count); - if (error < 0) - goto done; - nbytes += error; + error = brcmf_sdio_dump_console(seq, bus, &sh); - error = nbytes; - *ppos += nbytes; done: return error; } -static ssize_t brcmf_sdio_forensic_read(struct file *f, char __user *data, - size_t count, loff_t *ppos) +static int brcmf_sdio_forensic_read(struct seq_file *seq, void *data) { - struct brcmf_sdio *bus = f->private_data; - int res; + struct brcmf_sdio *bus = seq->private; - res = brcmf_sdio_died_dump(bus, data, count, ppos); - if (res > 0) - *ppos += res; - return (ssize_t)res; + return brcmf_sdio_died_dump(seq, bus); +} + +static int brcmf_sdio_forensic_open(struct inode *inode, struct file *f) +{ + return single_open(f, brcmf_sdio_forensic_read, inode->i_private); } static const struct file_operations brcmf_sdio_forensic_ops = { .owner = THIS_MODULE, - .open = simple_open, - .read = brcmf_sdio_forensic_read + .open = brcmf_sdio_forensic_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek }; static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus) -- cgit v1.2.3 From 82d957e09d4f0ff8091ca67e39b51ec6bdc672b1 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 12 Jul 2014 08:49:36 +0200 Subject: brcmfmac: rework debugfs functions in the driver Reworked the debugfs functions in the driver making it easier for other driver parts to add a debugfs entry and keeping the information they want to expose in debugfs private, ie. not in a header. This is accomplished by providing the function brcmf_debugfs_add_entry() in which the caller provides a read function in which they provide the content. The debugfs function will take care of creating the debugfs entry and cleaning up upon removal. Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c | 179 ++++----------------- drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h | 74 +-------- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 89 ++++++++-- drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 100 +++++++++++- 4 files changed, 207 insertions(+), 235 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c index e1ac932a3154..be9f4f829192 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c @@ -43,37 +43,13 @@ void brcmf_debugfs_exit(void) static int brcmf_debugfs_chipinfo_read(struct seq_file *seq, void *data) { - struct brcmf_pub *drvr = seq->private; - struct brcmf_bus *bus = drvr->bus_if; + struct brcmf_bus *bus = dev_get_drvdata(seq->private); seq_printf(seq, "chip: %x(%u) rev %u\n", bus->chip, bus->chip, bus->chiprev); return 0; } -static int brcmf_debugfs_chipinfo_open(struct inode *inode, struct file *f) -{ - return single_open(f, brcmf_debugfs_chipinfo_read, inode->i_private); -} - -static const struct file_operations brcmf_debugfs_chipinfo_ops = { - .owner = THIS_MODULE, - .open = brcmf_debugfs_chipinfo_open, - .release = single_release, - .read = seq_read, - .llseek = seq_lseek -}; - -static int brcmf_debugfs_create_chipinfo(struct brcmf_pub *drvr) -{ - struct dentry *dentry = drvr->dbgfs_dir; - - if (!IS_ERR_OR_NULL(dentry)) - debugfs_create_file("chipinfo", S_IRUGO, dentry, drvr, - &brcmf_debugfs_chipinfo_ops); - return 0; -} - int brcmf_debugfs_attach(struct brcmf_pub *drvr) { struct device *dev = drvr->bus_if->dev; @@ -82,7 +58,8 @@ int brcmf_debugfs_attach(struct brcmf_pub *drvr) return -ENODEV; drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder); - brcmf_debugfs_create_chipinfo(drvr); + brcmf_debugfs_add_entry(drvr, "chipinfo", brcmf_debugfs_chipinfo_read); + return PTR_ERR_OR_ZERO(drvr->dbgfs_dir); } @@ -97,146 +74,44 @@ struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr) return drvr->dbgfs_dir; } -static int brcmf_debugfs_sdio_count_read(struct seq_file *seq, void *data) -{ - struct brcmf_sdio_count *sdcnt = seq->private; - - seq_printf(seq, - "intrcount: %u\nlastintrs: %u\n" - "pollcnt: %u\nregfails: %u\n" - "tx_sderrs: %u\nfcqueued: %u\n" - "rxrtx: %u\nrx_toolong: %u\n" - "rxc_errors: %u\nrx_hdrfail: %u\n" - "rx_badhdr: %u\nrx_badseq: %u\n" - "fc_rcvd: %u\nfc_xoff: %u\n" - "fc_xon: %u\nrxglomfail: %u\n" - "rxglomframes: %u\nrxglompkts: %u\n" - "f2rxhdrs: %u\nf2rxdata: %u\n" - "f2txdata: %u\nf1regdata: %u\n" - "tickcnt: %u\ntx_ctlerrs: %lu\n" - "tx_ctlpkts: %lu\nrx_ctlerrs: %lu\n" - "rx_ctlpkts: %lu\nrx_readahead: %lu\n", - sdcnt->intrcount, sdcnt->lastintrs, - sdcnt->pollcnt, sdcnt->regfails, - sdcnt->tx_sderrs, sdcnt->fcqueued, - sdcnt->rxrtx, sdcnt->rx_toolong, - sdcnt->rxc_errors, sdcnt->rx_hdrfail, - sdcnt->rx_badhdr, sdcnt->rx_badseq, - sdcnt->fc_rcvd, sdcnt->fc_xoff, - sdcnt->fc_xon, sdcnt->rxglomfail, - sdcnt->rxglomframes, sdcnt->rxglompkts, - sdcnt->f2rxhdrs, sdcnt->f2rxdata, - sdcnt->f2txdata, sdcnt->f1regdata, - sdcnt->tickcnt, sdcnt->tx_ctlerrs, - sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs, - sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt); - - return 0; -} +struct brcmf_debugfs_entry { + int (*read)(struct seq_file *seq, void *data); + struct brcmf_pub *drvr; +}; -static int brcmf_debugfs_sdio_count_open(struct inode *inode, struct file *f) +static int brcmf_debugfs_entry_open(struct inode *inode, struct file *f) { - return single_open(f, brcmf_debugfs_sdio_count_read, inode->i_private); + struct brcmf_debugfs_entry *entry = inode->i_private; + + return single_open(f, entry->read, entry->drvr->bus_if->dev); } -static const struct file_operations brcmf_debugfs_sdio_counter_ops = { +static const struct file_operations brcmf_debugfs_def_ops = { .owner = THIS_MODULE, - .open = brcmf_debugfs_sdio_count_open, + .open = brcmf_debugfs_entry_open, .release = single_release, .read = seq_read, .llseek = seq_lseek }; -void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr, - struct brcmf_sdio_count *sdcnt) +int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, + int (*read_fn)(struct seq_file *seq, void *data)) { - struct dentry *dentry = drvr->dbgfs_dir; + struct dentry *dentry = drvr->dbgfs_dir; + struct brcmf_debugfs_entry *entry; - if (!IS_ERR_OR_NULL(dentry)) - debugfs_create_file("counters", S_IRUGO, dentry, - sdcnt, &brcmf_debugfs_sdio_counter_ops); -} + if (IS_ERR_OR_NULL(dentry)) + return -ENOENT; -static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data) -{ - struct brcmf_fws_stats *fwstats = seq->private; - - seq_printf(seq, - "header_pulls: %u\n" - "header_only_pkt: %u\n" - "tlv_parse_failed: %u\n" - "tlv_invalid_type: %u\n" - "mac_update_fails: %u\n" - "ps_update_fails: %u\n" - "if_update_fails: %u\n" - "pkt2bus: %u\n" - "generic_error: %u\n" - "rollback_success: %u\n" - "rollback_failed: %u\n" - "delayq_full: %u\n" - "supprq_full: %u\n" - "txs_indicate: %u\n" - "txs_discard: %u\n" - "txs_suppr_core: %u\n" - "txs_suppr_ps: %u\n" - "txs_tossed: %u\n" - "txs_host_tossed: %u\n" - "bus_flow_block: %u\n" - "fws_flow_block: %u\n" - "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n" - "requested_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n", - fwstats->header_pulls, - fwstats->header_only_pkt, - fwstats->tlv_parse_failed, - fwstats->tlv_invalid_type, - fwstats->mac_update_failed, - fwstats->mac_ps_update_failed, - fwstats->if_update_failed, - fwstats->pkt2bus, - fwstats->generic_error, - fwstats->rollback_success, - fwstats->rollback_failed, - fwstats->delayq_full_error, - fwstats->supprq_full_error, - fwstats->txs_indicate, - fwstats->txs_discard, - fwstats->txs_supp_core, - fwstats->txs_supp_ps, - fwstats->txs_tossed, - fwstats->txs_host_tossed, - fwstats->bus_flow_block, - fwstats->fws_flow_block, - fwstats->send_pkts[0], fwstats->send_pkts[1], - fwstats->send_pkts[2], fwstats->send_pkts[3], - fwstats->send_pkts[4], - fwstats->requested_sent[0], - fwstats->requested_sent[1], - fwstats->requested_sent[2], - fwstats->requested_sent[3], - fwstats->requested_sent[4]); + entry = devm_kzalloc(drvr->bus_if->dev, sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; - return 0; -} + entry->read = read_fn; + entry->drvr = drvr; -static int brcmf_debugfs_fws_stats_open(struct inode *inode, struct file *f) -{ - return single_open(f, brcmf_debugfs_fws_stats_read, inode->i_private); -} - -static const struct file_operations brcmf_debugfs_fws_stats_ops = { - .owner = THIS_MODULE, - .open = brcmf_debugfs_fws_stats_open, - .release = single_release, - .read = seq_read, - .llseek = seq_lseek -}; - -void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr, - struct brcmf_fws_stats *stats) -{ - struct dentry *dentry = drvr->dbgfs_dir; + dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry, + &brcmf_debugfs_def_ops); - if (!IS_ERR_OR_NULL(dentry)) - debugfs_create_file("fws_stats", S_IRUGO, dentry, - stats, &brcmf_debugfs_fws_stats_ops); + return PTR_ERR_OR_ZERO(dentry); } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index ef52ed7abc69..6eade7c60c63 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h @@ -100,68 +100,6 @@ do { \ extern int brcmf_msg_level; -/* - * hold counter variables used in brcmfmac sdio driver. - */ -struct brcmf_sdio_count { - uint intrcount; /* Count of device interrupt callbacks */ - uint lastintrs; /* Count as of last watchdog timer */ - uint pollcnt; /* Count of active polls */ - uint regfails; /* Count of R_REG failures */ - uint tx_sderrs; /* Count of tx attempts with sd errors */ - uint fcqueued; /* Tx packets that got queued */ - uint rxrtx; /* Count of rtx requests (NAK to dongle) */ - uint rx_toolong; /* Receive frames too long to receive */ - uint rxc_errors; /* SDIO errors when reading control frames */ - uint rx_hdrfail; /* SDIO errors on header reads */ - uint rx_badhdr; /* Bad received headers (roosync?) */ - uint rx_badseq; /* Mismatched rx sequence number */ - uint fc_rcvd; /* Number of flow-control events received */ - uint fc_xoff; /* Number which turned on flow-control */ - uint fc_xon; /* Number which turned off flow-control */ - uint rxglomfail; /* Failed deglom attempts */ - uint rxglomframes; /* Number of glom frames (superframes) */ - uint rxglompkts; /* Number of packets from glom frames */ - uint f2rxhdrs; /* Number of header reads */ - uint f2rxdata; /* Number of frame data reads */ - uint f2txdata; /* Number of f2 frame writes */ - uint f1regdata; /* Number of f1 register accesses */ - uint tickcnt; /* Number of watchdog been schedule */ - ulong tx_ctlerrs; /* Err of sending ctrl frames */ - ulong tx_ctlpkts; /* Ctrl frames sent to dongle */ - ulong rx_ctlerrs; /* Err of processing rx ctrl frames */ - ulong rx_ctlpkts; /* Ctrl frames processed from dongle */ - ulong rx_readahead_cnt; /* packets where header read-ahead was used */ -}; - -struct brcmf_fws_stats { - u32 tlv_parse_failed; - u32 tlv_invalid_type; - u32 header_only_pkt; - u32 header_pulls; - u32 pkt2bus; - u32 send_pkts[5]; - u32 requested_sent[5]; - u32 generic_error; - u32 mac_update_failed; - u32 mac_ps_update_failed; - u32 if_update_failed; - u32 packet_request_failed; - u32 credit_request_failed; - u32 rollback_success; - u32 rollback_failed; - u32 delayq_full_error; - u32 supprq_full_error; - u32 txs_indicate; - u32 txs_discard; - u32 txs_supp_core; - u32 txs_supp_ps; - u32 txs_tossed; - u32 txs_host_tossed; - u32 bus_flow_block; - u32 fws_flow_block; -}; - struct brcmf_pub; #ifdef DEBUG void brcmf_debugfs_init(void); @@ -169,10 +107,8 @@ void brcmf_debugfs_exit(void); int brcmf_debugfs_attach(struct brcmf_pub *drvr); void brcmf_debugfs_detach(struct brcmf_pub *drvr); struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr); -void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr, - struct brcmf_sdio_count *sdcnt); -void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr, - struct brcmf_fws_stats *stats); +int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, + int (*read_fn)(struct seq_file *seq, void *data)); #else static inline void brcmf_debugfs_init(void) { @@ -187,9 +123,11 @@ static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr) static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr) { } -static inline void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr, - struct brcmf_fws_stats *stats) +static inline +int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, + int (*read_fn)(struct seq_file *seq, void *data)) { + return 0; } #endif diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 0c98a7942a0f..c0486329331b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -391,6 +391,40 @@ struct brcmf_sdio_hdrinfo { u16 tail_pad; }; +/* + * hold counter variables + */ +struct brcmf_sdio_count { + uint intrcount; /* Count of device interrupt callbacks */ + uint lastintrs; /* Count as of last watchdog timer */ + uint pollcnt; /* Count of active polls */ + uint regfails; /* Count of R_REG failures */ + uint tx_sderrs; /* Count of tx attempts with sd errors */ + uint fcqueued; /* Tx packets that got queued */ + uint rxrtx; /* Count of rtx requests (NAK to dongle) */ + uint rx_toolong; /* Receive frames too long to receive */ + uint rxc_errors; /* SDIO errors when reading control frames */ + uint rx_hdrfail; /* SDIO errors on header reads */ + uint rx_badhdr; /* Bad received headers (roosync?) */ + uint rx_badseq; /* Mismatched rx sequence number */ + uint fc_rcvd; /* Number of flow-control events received */ + uint fc_xoff; /* Number which turned on flow-control */ + uint fc_xon; /* Number which turned off flow-control */ + uint rxglomfail; /* Failed deglom attempts */ + uint rxglomframes; /* Number of glom frames (superframes) */ + uint rxglompkts; /* Number of packets from glom frames */ + uint f2rxhdrs; /* Number of header reads */ + uint f2rxdata; /* Number of frame data reads */ + uint f2txdata; /* Number of f2 frame writes */ + uint f1regdata; /* Number of f1 register accesses */ + uint tickcnt; /* Number of watchdog been schedule */ + ulong tx_ctlerrs; /* Err of sending ctrl frames */ + ulong tx_ctlpkts; /* Ctrl frames sent to dongle */ + ulong rx_ctlerrs; /* Err of processing rx ctrl frames */ + ulong rx_ctlpkts; /* Ctrl frames processed from dongle */ + ulong rx_readahead_cnt; /* packets where header read-ahead was used */ +}; + /* misc chip info needed by some of the routines */ /* Private data for SDIO bus interaction */ struct brcmf_sdio { @@ -3070,23 +3104,50 @@ done: static int brcmf_sdio_forensic_read(struct seq_file *seq, void *data) { - struct brcmf_sdio *bus = seq->private; + struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); + struct brcmf_sdio *bus = bus_if->bus_priv.sdio->bus; return brcmf_sdio_died_dump(seq, bus); } -static int brcmf_sdio_forensic_open(struct inode *inode, struct file *f) +static int brcmf_debugfs_sdio_count_read(struct seq_file *seq, void *data) { - return single_open(f, brcmf_sdio_forensic_read, inode->i_private); -} + struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + struct brcmf_sdio_count *sdcnt = &sdiodev->bus->sdcnt; -static const struct file_operations brcmf_sdio_forensic_ops = { - .owner = THIS_MODULE, - .open = brcmf_sdio_forensic_open, - .release = single_release, - .read = seq_read, - .llseek = seq_lseek -}; + seq_printf(seq, + "intrcount: %u\nlastintrs: %u\n" + "pollcnt: %u\nregfails: %u\n" + "tx_sderrs: %u\nfcqueued: %u\n" + "rxrtx: %u\nrx_toolong: %u\n" + "rxc_errors: %u\nrx_hdrfail: %u\n" + "rx_badhdr: %u\nrx_badseq: %u\n" + "fc_rcvd: %u\nfc_xoff: %u\n" + "fc_xon: %u\nrxglomfail: %u\n" + "rxglomframes: %u\nrxglompkts: %u\n" + "f2rxhdrs: %u\nf2rxdata: %u\n" + "f2txdata: %u\nf1regdata: %u\n" + "tickcnt: %u\ntx_ctlerrs: %lu\n" + "tx_ctlpkts: %lu\nrx_ctlerrs: %lu\n" + "rx_ctlpkts: %lu\nrx_readahead: %lu\n", + sdcnt->intrcount, sdcnt->lastintrs, + sdcnt->pollcnt, sdcnt->regfails, + sdcnt->tx_sderrs, sdcnt->fcqueued, + sdcnt->rxrtx, sdcnt->rx_toolong, + sdcnt->rxc_errors, sdcnt->rx_hdrfail, + sdcnt->rx_badhdr, sdcnt->rx_badseq, + sdcnt->fc_rcvd, sdcnt->fc_xoff, + sdcnt->fc_xon, sdcnt->rxglomfail, + sdcnt->rxglomframes, sdcnt->rxglompkts, + sdcnt->f2rxhdrs, sdcnt->f2rxdata, + sdcnt->f2txdata, sdcnt->f1regdata, + sdcnt->tickcnt, sdcnt->tx_ctlerrs, + sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs, + sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt); + + return 0; +} static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus) { @@ -3096,9 +3157,9 @@ static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus) if (IS_ERR_OR_NULL(dentry)) return; - debugfs_create_file("forensics", S_IRUGO, dentry, bus, - &brcmf_sdio_forensic_ops); - brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt); + brcmf_debugfs_add_entry(drvr, "forensics", brcmf_sdio_forensic_read); + brcmf_debugfs_add_entry(drvr, "counters", + brcmf_debugfs_sdio_count_read); debugfs_create_u32("console_interval", 0644, dentry, &bus->console_interval); } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 699908de314a..d42f7d04b65f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -454,6 +454,34 @@ struct brcmf_fws_macdesc_table { struct brcmf_fws_mac_descriptor other; }; +struct brcmf_fws_stats { + u32 tlv_parse_failed; + u32 tlv_invalid_type; + u32 header_only_pkt; + u32 header_pulls; + u32 pkt2bus; + u32 send_pkts[5]; + u32 requested_sent[5]; + u32 generic_error; + u32 mac_update_failed; + u32 mac_ps_update_failed; + u32 if_update_failed; + u32 packet_request_failed; + u32 credit_request_failed; + u32 rollback_success; + u32 rollback_failed; + u32 delayq_full_error; + u32 supprq_full_error; + u32 txs_indicate; + u32 txs_discard; + u32 txs_supp_core; + u32 txs_supp_ps; + u32 txs_tossed; + u32 txs_host_tossed; + u32 bus_flow_block; + u32 fws_flow_block; +}; + struct brcmf_fws_info { struct brcmf_pub *drvr; spinlock_t spinlock; @@ -2017,6 +2045,75 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker) brcmf_fws_unlock(fws); } +#ifdef DEBUG +static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); + struct brcmf_fws_stats *fwstats = &bus_if->drvr->fws->stats; + + seq_printf(seq, + "header_pulls: %u\n" + "header_only_pkt: %u\n" + "tlv_parse_failed: %u\n" + "tlv_invalid_type: %u\n" + "mac_update_fails: %u\n" + "ps_update_fails: %u\n" + "if_update_fails: %u\n" + "pkt2bus: %u\n" + "generic_error: %u\n" + "rollback_success: %u\n" + "rollback_failed: %u\n" + "delayq_full: %u\n" + "supprq_full: %u\n" + "txs_indicate: %u\n" + "txs_discard: %u\n" + "txs_suppr_core: %u\n" + "txs_suppr_ps: %u\n" + "txs_tossed: %u\n" + "txs_host_tossed: %u\n" + "bus_flow_block: %u\n" + "fws_flow_block: %u\n" + "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n" + "requested_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n", + fwstats->header_pulls, + fwstats->header_only_pkt, + fwstats->tlv_parse_failed, + fwstats->tlv_invalid_type, + fwstats->mac_update_failed, + fwstats->mac_ps_update_failed, + fwstats->if_update_failed, + fwstats->pkt2bus, + fwstats->generic_error, + fwstats->rollback_success, + fwstats->rollback_failed, + fwstats->delayq_full_error, + fwstats->supprq_full_error, + fwstats->txs_indicate, + fwstats->txs_discard, + fwstats->txs_supp_core, + fwstats->txs_supp_ps, + fwstats->txs_tossed, + fwstats->txs_host_tossed, + fwstats->bus_flow_block, + fwstats->fws_flow_block, + fwstats->send_pkts[0], fwstats->send_pkts[1], + fwstats->send_pkts[2], fwstats->send_pkts[3], + fwstats->send_pkts[4], + fwstats->requested_sent[0], + fwstats->requested_sent[1], + fwstats->requested_sent[2], + fwstats->requested_sent[3], + fwstats->requested_sent[4]); + + return 0; +} +#else +static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data) +{ + return 0; +} +#endif + int brcmf_fws_init(struct brcmf_pub *drvr) { struct brcmf_fws_info *fws; @@ -2107,7 +2204,8 @@ int brcmf_fws_init(struct brcmf_pub *drvr) BRCMF_FWS_PSQ_LEN); /* create debugfs file for statistics */ - brcmf_debugfs_create_fws_stats(drvr, &fws->stats); + brcmf_debugfs_add_entry(drvr, "fws_stats", + brcmf_debugfs_fws_stats_read); brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n", fws->fw_signals ? "enabled" : "disabled", tlv); -- cgit v1.2.3 From c1b20532ef395f23c2d24bc9c7f772a45e0420c7 Mon Sep 17 00:00:00 2001 From: Daniel Kim Date: Sat, 12 Jul 2014 08:49:37 +0200 Subject: brcmfmac: Make firmware path a module parameter This patch makes firmware path a module parameter so that firmware and nvram files can be loaded from the specified path. Signed-off-by: Daniel Kim Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 47 +++++++++++++--------- drivers/net/wireless/brcm80211/brcmfmac/firmware.c | 5 +++ drivers/net/wireless/brcm80211/brcmfmac/firmware.h | 5 +++ .../net/wireless/brcm80211/brcmfmac/sdio_host.h | 4 ++ 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index c0486329331b..67d91d5cc13d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -666,28 +666,34 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = { { BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) } }; -static const char *brcmf_sdio_get_fwname(struct brcmf_chip *ci, - enum brcmf_firmware_type type) +static int brcmf_sdio_get_fwnames(struct brcmf_chip *ci, + struct brcmf_sdio_dev *sdiodev) { int i; for (i = 0; i < ARRAY_SIZE(brcmf_fwname_data); i++) { if (brcmf_fwname_data[i].chipid == ci->chip && - brcmf_fwname_data[i].revmsk & BIT(ci->chiprev)) { - switch (type) { - case BRCMF_FIRMWARE_BIN: - return brcmf_fwname_data[i].bin; - case BRCMF_FIRMWARE_NVRAM: - return brcmf_fwname_data[i].nv; - default: - brcmf_err("invalid firmware type (%d)\n", type); - return NULL; - } - } + brcmf_fwname_data[i].revmsk & BIT(ci->chiprev)) + break; } - brcmf_err("Unknown chipid %d [%d]\n", - ci->chip, ci->chiprev); - return NULL; + + if (i == ARRAY_SIZE(brcmf_fwname_data)) { + brcmf_err("Unknown chipid %d [%d]\n", ci->chip, ci->chiprev); + return -ENODEV; + } + + /* check if firmware path is provided by module parameter */ + if (brcmf_firmware_path[0] != '\0') { + if (brcmf_firmware_path[strlen(brcmf_firmware_path) - 1] != '/') + strcat(brcmf_firmware_path, "/"); + + strcpy(sdiodev->fw_name, brcmf_firmware_path); + strcpy(sdiodev->nvram_name, brcmf_firmware_path); + } + strcat(sdiodev->fw_name, brcmf_fwname_data[i].bin); + strcat(sdiodev->nvram_name, brcmf_fwname_data[i].nv); + + return 0; } static void pkt_align(struct sk_buff *p, int len, int align) @@ -4160,11 +4166,12 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) brcmf_sdio_debugfs_create(bus); brcmf_dbg(INFO, "completed!!\n"); + ret = brcmf_sdio_get_fwnames(bus->ci, sdiodev); + if (ret) + goto fail; + ret = brcmf_fw_get_firmwares(sdiodev->dev, BRCMF_FW_REQUEST_NVRAM, - brcmf_sdio_get_fwname(bus->ci, - BRCMF_FIRMWARE_BIN), - brcmf_sdio_get_fwname(bus->ci, - BRCMF_FIRMWARE_NVRAM), + sdiodev->fw_name, sdiodev->nvram_name, brcmf_sdio_firmware_callback); if (ret != 0) { brcmf_err("async firmware request failed: %d\n", ret); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c index 7b7d237c1ddb..8ea9f283d2b8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c @@ -18,10 +18,15 @@ #include #include #include +#include #include "dhd_dbg.h" #include "firmware.h" +char brcmf_firmware_path[BRCMF_FW_PATH_LEN]; +module_param_string(firmware_path, brcmf_firmware_path, + BRCMF_FW_PATH_LEN, 0440); + enum nvram_parser_state { IDLE, KEY, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/brcm80211/brcmfmac/firmware.h index 6431bfd7afff..4d3482356b77 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.h @@ -21,6 +21,11 @@ #define BRCMF_FW_REQ_FLAGS 0x00F0 #define BRCMF_FW_REQ_NV_OPTIONAL 0x0010 +#define BRCMF_FW_PATH_LEN 256 +#define BRCMF_FW_NAME_LEN 32 + +extern char brcmf_firmware_path[]; + void brcmf_fw_nvram_free(void *nvram); /* * Request firmware(s) asynchronously. When the asynchronous request diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h index 3deab7959a0d..6c5e585ccda9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h @@ -18,6 +18,8 @@ #define _BRCM_SDH_H_ #include +#include +#include "firmware.h" #define SDIO_FUNC_0 0 #define SDIO_FUNC_1 1 @@ -182,6 +184,8 @@ struct brcmf_sdio_dev { uint max_segment_size; uint txglomsz; struct sg_table sgtable; + char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN]; + char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN]; }; /* sdio core registers */ -- cgit v1.2.3 From ccfd1e810bb7f053e74bc796b84c8e1de37c21fa Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 12 Jul 2014 08:49:38 +0200 Subject: brcmfmac: move attach and detach functions in wl_cfg80211.c Preparing for another patch move the functions in separate commit. Reviewed-by: Hante Meuleman Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 215 ++++++++++----------- 1 file changed, 107 insertions(+), 108 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 9682cf213ec4..dd487e93141f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4967,114 +4967,6 @@ static int brcmf_enable_bw40_2g(struct brcmf_if *ifp) return err; } -struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, - struct device *busdev) -{ - struct net_device *ndev = drvr->iflist[0]->ndev; - struct brcmf_cfg80211_info *cfg; - struct wiphy *wiphy; - struct brcmf_cfg80211_vif *vif; - struct brcmf_if *ifp; - s32 err = 0; - s32 io_type; - - if (!ndev) { - brcmf_err("ndev is invalid\n"); - return NULL; - } - - ifp = netdev_priv(ndev); - wiphy = brcmf_setup_wiphy(busdev); - if (IS_ERR(wiphy)) - return NULL; - - cfg = wiphy_priv(wiphy); - cfg->wiphy = wiphy; - cfg->pub = drvr; - init_vif_event(&cfg->vif_event); - INIT_LIST_HEAD(&cfg->vif_list); - - vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false); - if (IS_ERR(vif)) { - wiphy_free(wiphy); - return NULL; - } - - vif->ifp = ifp; - vif->wdev.netdev = ndev; - ndev->ieee80211_ptr = &vif->wdev; - SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy)); - - err = wl_init_priv(cfg); - if (err) { - brcmf_err("Failed to init iwm_priv (%d)\n", err); - goto cfg80211_attach_out; - } - ifp->vif = vif; - - err = brcmf_p2p_attach(cfg); - if (err) { - brcmf_err("P2P initilisation failed (%d)\n", err); - goto cfg80211_p2p_attach_out; - } - err = brcmf_btcoex_attach(cfg); - if (err) { - brcmf_err("BT-coex initialisation failed (%d)\n", err); - brcmf_p2p_detach(&cfg->p2p); - goto cfg80211_p2p_attach_out; - } - - /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(), - * setup 40MHz in 2GHz band and enable OBSS scanning. - */ - if (wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap & - IEEE80211_HT_CAP_SUP_WIDTH_20_40) { - err = brcmf_enable_bw40_2g(ifp); - if (!err) - err = brcmf_fil_iovar_int_set(ifp, "obss_coex", - BRCMF_OBSS_COEX_AUTO); - } - /* clear for now and rely on update later */ - wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.ht_supported = false; - wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap = 0; - - err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); - if (err) { - brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err); - wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS; - } - - err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, - &io_type); - if (err) { - brcmf_err("Failed to get D11 version (%d)\n", err); - goto cfg80211_p2p_attach_out; - } - cfg->d11inf.io_type = (u8)io_type; - brcmu_d11_attach(&cfg->d11inf); - - return cfg; - -cfg80211_p2p_attach_out: - wl_deinit_priv(cfg); - -cfg80211_attach_out: - brcmf_free_vif(vif); - return NULL; -} - -void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) -{ - if (!cfg) - return; - - WARN_ON(!list_empty(&cfg->vif_list)); - wiphy_unregister(cfg->wiphy); - brcmf_btcoex_detach(cfg); - wl_deinit_priv(cfg); - wiphy_free(cfg->wiphy); -} - static s32 brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout) { @@ -5658,3 +5550,110 @@ int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, vif_event_equals(event, action), timeout); } +struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, + struct device *busdev) +{ + struct net_device *ndev = drvr->iflist[0]->ndev; + struct brcmf_cfg80211_info *cfg; + struct wiphy *wiphy; + struct brcmf_cfg80211_vif *vif; + struct brcmf_if *ifp; + s32 err = 0; + s32 io_type; + + if (!ndev) { + brcmf_err("ndev is invalid\n"); + return NULL; + } + + ifp = netdev_priv(ndev); + wiphy = brcmf_setup_wiphy(busdev); + if (IS_ERR(wiphy)) + return NULL; + + cfg = wiphy_priv(wiphy); + cfg->wiphy = wiphy; + cfg->pub = drvr; + init_vif_event(&cfg->vif_event); + INIT_LIST_HEAD(&cfg->vif_list); + + vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false); + if (IS_ERR(vif)) { + wiphy_free(wiphy); + return NULL; + } + + vif->ifp = ifp; + vif->wdev.netdev = ndev; + ndev->ieee80211_ptr = &vif->wdev; + SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy)); + + err = wl_init_priv(cfg); + if (err) { + brcmf_err("Failed to init iwm_priv (%d)\n", err); + goto cfg80211_attach_out; + } + ifp->vif = vif; + + err = brcmf_p2p_attach(cfg); + if (err) { + brcmf_err("P2P initilisation failed (%d)\n", err); + goto cfg80211_p2p_attach_out; + } + err = brcmf_btcoex_attach(cfg); + if (err) { + brcmf_err("BT-coex initialisation failed (%d)\n", err); + brcmf_p2p_detach(&cfg->p2p); + goto cfg80211_p2p_attach_out; + } + + /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(), + * setup 40MHz in 2GHz band and enable OBSS scanning. + */ + if (wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40) { + err = brcmf_enable_bw40_2g(ifp); + if (!err) + err = brcmf_fil_iovar_int_set(ifp, "obss_coex", + BRCMF_OBSS_COEX_AUTO); + } + /* clear for now and rely on update later */ + wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.ht_supported = false; + wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap = 0; + + err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); + if (err) { + brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err); + wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS; + } + + err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, + &io_type); + if (err) { + brcmf_err("Failed to get D11 version (%d)\n", err); + goto cfg80211_p2p_attach_out; + } + cfg->d11inf.io_type = (u8)io_type; + brcmu_d11_attach(&cfg->d11inf); + + return cfg; + +cfg80211_p2p_attach_out: + wl_deinit_priv(cfg); + +cfg80211_attach_out: + brcmf_free_vif(vif); + return NULL; +} + +void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) +{ + if (!cfg) + return; + + WARN_ON(!list_empty(&cfg->vif_list)); + wiphy_unregister(cfg->wiphy); + brcmf_btcoex_detach(cfg); + wl_deinit_priv(cfg); + wiphy_free(cfg->wiphy); +} -- cgit v1.2.3 From c08437b4b5c89677a81b543644b2d0a99484d947 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 12 Jul 2014 08:49:39 +0200 Subject: brcmfmac: introduce feature and quirk handling Introducing a new source module that will be responsible for identifying features and quirks related to the device being handled. Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/Makefile | 1 + drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 5 +- .../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 13 +- drivers/net/wireless/brcm80211/brcmfmac/feature.c | 136 +++++++++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/feature.h | 86 +++++++++++++ .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 30 +++-- 6 files changed, 244 insertions(+), 27 deletions(-) create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/feature.c create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/feature.h diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 4cffb2ee3673..de0cff3df389 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -34,6 +34,7 @@ brcmfmac-objs += \ dhd_common.o \ dhd_linux.o \ firmware.o \ + feature.o \ btcoex.o \ vendor.o brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index a8998eb60d22..7da6441bcfa8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -103,6 +103,10 @@ struct brcmf_pub { struct brcmf_ampdu_rx_reorder *reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS]; + + u32 feat_flags; + u32 chip_quirks; + #ifdef DEBUG struct dentry *dbgfs_dir; #endif @@ -175,7 +179,6 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx); void brcmf_txflowblock_if(struct brcmf_if *ifp, enum brcmf_netif_stop_reason reason, bool state); -u32 brcmf_get_chip_info(struct brcmf_if *ifp); void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx, bool success); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 09dd8c13d844..bf448081d6fb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -30,6 +30,7 @@ #include "wl_cfg80211.h" #include "fwil.h" #include "fwsignal.h" +#include "feature.h" #include "proto.h" MODULE_AUTHOR("Broadcom Corporation"); @@ -936,6 +937,8 @@ int brcmf_bus_start(struct device *dev) if (ret < 0) goto fail; + brcmf_feat_attach(drvr); + ret = brcmf_fws_init(drvr); if (ret < 0) goto fail; @@ -1073,16 +1076,6 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev) return !err; } -/* - * return chip id and rev of the device encoded in u32. - */ -u32 brcmf_get_chip_info(struct brcmf_if *ifp) -{ - struct brcmf_bus *bus = ifp->drvr->bus_if; - - return bus->chip << 4 | bus->chiprev; -} - static void brcmf_driver_register(struct work_struct *work) { #ifdef CONFIG_BRCMFMAC_SDIO diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/brcm80211/brcmfmac/feature.c new file mode 100644 index 000000000000..50877e3c5d2f --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include "dhd.h" +#include "dhd_bus.h" +#include "dhd_dbg.h" +#include "fwil.h" +#include "feature.h" + +/* + * firmware error code received if iovar is unsupported. + */ +#define EBRCMF_FEAT_UNSUPPORTED 23 + +/* + * expand feature list to array of feature strings. + */ +#define BRCMF_FEAT_DEF(_f) \ + #_f, +static const char *brcmf_feat_names[] = { + BRCMF_FEAT_LIST +}; +#undef BRCMF_FEAT_DEF + +#ifdef DEBUG +/* + * expand quirk list to array of quirk strings. + */ +#define BRCMF_QUIRK_DEF(_q) \ + #_q, +static const char * const brcmf_quirk_names[] = { + BRCMF_QUIRK_LIST +}; +#undef BRCMF_QUIRK_DEF + +/** + * brcmf_feat_debugfs_read() - expose feature info to debugfs. + * + * @seq: sequence for debugfs entry. + * @data: raw data pointer. + */ +static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); + u32 feats = bus_if->drvr->feat_flags; + u32 quirks = bus_if->drvr->chip_quirks; + int id; + + seq_printf(seq, "Features: %08x\n", feats); + for (id = 0; id < BRCMF_FEAT_LAST; id++) + if (feats & BIT(id)) + seq_printf(seq, "\t%s\n", brcmf_feat_names[id]); + seq_printf(seq, "\nQuirks: %08x\n", quirks); + for (id = 0; id < BRCMF_FEAT_QUIRK_LAST; id++) + if (quirks & BIT(id)) + seq_printf(seq, "\t%s\n", brcmf_quirk_names[id]); + return 0; +} +#else +static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data) +{ + return 0; +} +#endif /* DEBUG */ + +/** + * brcmf_feat_iovar_int_get() - determine feature through iovar query. + * + * @ifp: interface to query. + * @id: feature id. + * @name: iovar name. + */ +static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, + enum brcmf_feat_id id, char *name) +{ + u32 data; + int err; + + err = brcmf_fil_iovar_int_get(ifp, name, &data); + if (err == 0) { + brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]); + ifp->drvr->feat_flags |= BIT(id); + } else { + brcmf_dbg(TRACE, "%s feature check failed: %d\n", + brcmf_feat_names[id], err); + } +} + +void brcmf_feat_attach(struct brcmf_pub *drvr) +{ + struct brcmf_if *ifp = drvr->iflist[0]; + + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan"); + + /* set chip related quirks */ + switch (drvr->bus_if->chip) { + case BRCM_CC_43236_CHIP_ID: + drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_AUTO_AUTH); + break; + case BRCM_CC_4329_CHIP_ID: + drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_NEED_MPC); + break; + default: + /* no quirks */ + break; + } + + brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read); +} + +bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id) +{ + return (ifp->drvr->feat_flags & BIT(id)); +} + +bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp, + enum brcmf_feat_quirk quirk) +{ + return (ifp->drvr->chip_quirks & BIT(quirk)); +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/brcm80211/brcmfmac/feature.h new file mode 100644 index 000000000000..961d175f8afb --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _BRCMF_FEATURE_H +#define _BRCMF_FEATURE_H + +/* + * Features: + * + * MCHAN: multi-channel for concurrent P2P. + */ +#define BRCMF_FEAT_LIST \ + BRCMF_FEAT_DEF(MCHAN) +/* + * Quirks: + * + * AUTO_AUTH: workaround needed for automatic authentication type. + * NEED_MPC: driver needs to disable MPC during scanning operation. + */ +#define BRCMF_QUIRK_LIST \ + BRCMF_QUIRK_DEF(AUTO_AUTH) \ + BRCMF_QUIRK_DEF(NEED_MPC) + +#define BRCMF_FEAT_DEF(_f) \ + BRCMF_FEAT_ ## _f, +/* + * expand feature list to enumeration. + */ +enum brcmf_feat_id { + BRCMF_FEAT_LIST + BRCMF_FEAT_LAST +}; +#undef BRCMF_FEAT_DEF + +#define BRCMF_QUIRK_DEF(_q) \ + BRCMF_FEAT_QUIRK_ ## _q, +/* + * expand quirk list to enumeration. + */ +enum brcmf_feat_quirk { + BRCMF_QUIRK_LIST + BRCMF_FEAT_QUIRK_LAST +}; +#undef BRCMF_QUIRK_DEF + +/** + * brcmf_feat_attach() - determine features and quirks. + * + * @drvr: driver instance. + */ +void brcmf_feat_attach(struct brcmf_pub *drvr); + +/** + * brcmf_feat_is_enabled() - query feature. + * + * @ifp: interface instance. + * @id: feature id to check. + * + * Return: true is feature is enabled; otherwise false. + */ +bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id); + +/** + * brcmf_feat_is_quirk_enabled() - query chip quirk. + * + * @ifp: interface instance. + * @quirk: quirk id to check. + * + * Return: true is quirk is enabled; otherwise false. + */ +bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp, + enum brcmf_feat_quirk quirk); + +#endif /* _BRCMF_FEATURE_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index dd487e93141f..e3c1c71c5d2e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -33,6 +33,7 @@ #include "p2p.h" #include "btcoex.h" #include "wl_cfg80211.h" +#include "feature.h" #include "fwil.h" #include "vendor.h" @@ -592,7 +593,7 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc) { - if ((brcmf_get_chip_info(ifp) >> 4) == 0x4329) + if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC)) brcmf_set_mpc(ifp, mpc); } @@ -1619,17 +1620,10 @@ static enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp, enum nl80211_auth_type type) { - u32 ci; - if (type == NL80211_AUTHTYPE_AUTOMATIC) { - /* shift to ignore chip revision */ - ci = brcmf_get_chip_info(ifp) >> 4; - switch (ci) { - case 43236: - brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n"); - return NL80211_AUTHTYPE_OPEN_SYSTEM; - default: - break; - } + if (type == NL80211_AUTHTYPE_AUTOMATIC && + brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) { + brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n"); + type = NL80211_AUTHTYPE_OPEN_SYSTEM; } return type; } @@ -4310,10 +4304,10 @@ static const struct ieee80211_iface_limit brcmf_iface_limits[] = { .types = BIT(NL80211_IFTYPE_P2P_DEVICE) } }; -static const struct ieee80211_iface_combination brcmf_iface_combos[] = { +static struct ieee80211_iface_combination brcmf_iface_combos[] = { { .max_interfaces = BRCMF_IFACE_MAX_CNT, - .num_different_channels = 2, + .num_different_channels = 1, .n_limits = ARRAY_SIZE(brcmf_iface_limits), .limits = brcmf_iface_limits } @@ -4348,7 +4342,8 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { } }; -static struct wiphy *brcmf_setup_wiphy(struct device *phydev) +static +struct wiphy *brcmf_setup_wiphy(struct brcmf_if *ifp, struct device *phydev) { struct wiphy *wiphy; s32 err = 0; @@ -4368,6 +4363,9 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_DEVICE); + /* need VSDB firmware feature for concurrent channels */ + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) + brcmf_iface_combos[0].num_different_channels = 2; wiphy->iface_combinations = brcmf_iface_combos; wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; @@ -5567,7 +5565,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, } ifp = netdev_priv(ndev); - wiphy = brcmf_setup_wiphy(busdev); + wiphy = brcmf_setup_wiphy(ifp, busdev); if (IS_ERR(wiphy)) return NULL; -- cgit v1.2.3 From aa70b4fa43dfe5dc3df2161d814ccaa7897d73c9 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 12 Jul 2014 08:49:40 +0200 Subject: brcmfmac: moving some functions around Just reordering the functions in preparation of subsequent changes. Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 288 ++++++++++----------- 1 file changed, 144 insertions(+), 144 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index e3c1c71c5d2e..d0b48dd4f154 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4278,126 +4278,6 @@ static struct cfg80211_ops wl_cfg80211_ops = { .tdls_oper = brcmf_cfg80211_tdls_oper, }; -static void brcmf_wiphy_pno_params(struct wiphy *wiphy) -{ - /* scheduled scan settings */ - wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; - wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; - wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; - wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; -} - -static const struct ieee80211_iface_limit brcmf_iface_limits[] = { - { - .max = 2, - .types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP) - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO) - }, - { - .max = 1, - .types = BIT(NL80211_IFTYPE_P2P_DEVICE) - } -}; -static struct ieee80211_iface_combination brcmf_iface_combos[] = { - { - .max_interfaces = BRCMF_IFACE_MAX_CNT, - .num_different_channels = 1, - .n_limits = ARRAY_SIZE(brcmf_iface_limits), - .limits = brcmf_iface_limits - } -}; - -static const struct ieee80211_txrx_stypes -brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { - [NL80211_IFTYPE_STATION] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) - }, - [NL80211_IFTYPE_P2P_CLIENT] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) - }, - [NL80211_IFTYPE_P2P_GO] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | - BIT(IEEE80211_STYPE_DISASSOC >> 4) | - BIT(IEEE80211_STYPE_AUTH >> 4) | - BIT(IEEE80211_STYPE_DEAUTH >> 4) | - BIT(IEEE80211_STYPE_ACTION >> 4) - }, - [NL80211_IFTYPE_P2P_DEVICE] = { - .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | - BIT(IEEE80211_STYPE_PROBE_REQ >> 4) - } -}; - -static -struct wiphy *brcmf_setup_wiphy(struct brcmf_if *ifp, struct device *phydev) -{ - struct wiphy *wiphy; - s32 err = 0; - - wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info)); - if (!wiphy) { - brcmf_err("Could not allocate wiphy device\n"); - return ERR_PTR(-ENOMEM); - } - set_wiphy_dev(wiphy, phydev); - wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; - wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; - wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_P2P_DEVICE); - /* need VSDB firmware feature for concurrent channels */ - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) - brcmf_iface_combos[0].num_different_channels = 2; - wiphy->iface_combinations = brcmf_iface_combos; - wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); - wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; - wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - wiphy->cipher_suites = __wl_cipher_suites; - wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); - wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT | - WIPHY_FLAG_OFFCHAN_TX | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | - WIPHY_FLAG_SUPPORTS_TDLS; - if (!brcmf_roamoff) - wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; - wiphy->mgmt_stypes = brcmf_txrx_stypes; - wiphy->max_remain_on_channel_duration = 5000; - brcmf_wiphy_pno_params(wiphy); - brcmf_dbg(INFO, "Registering custom regulatory\n"); - wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; - wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); - - /* vendor commands/events support */ - wiphy->vendor_commands = brcmf_vendor_cmds; - wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1; - - err = wiphy_register(wiphy); - if (err < 0) { - brcmf_err("Could not register wiphy device (%d)\n", err); - wiphy_free(wiphy); - return ERR_PTR(err); - } - return wiphy; -} - struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, enum nl80211_iftype type, bool pm_block) @@ -4941,30 +4821,6 @@ static void init_vif_event(struct brcmf_cfg80211_vif_event *event) mutex_init(&event->vif_event_lock); } -static int brcmf_enable_bw40_2g(struct brcmf_if *ifp) -{ - struct brcmf_fil_bwcap_le band_bwcap; - u32 val; - int err; - - /* verify support for bw_cap command */ - val = WLC_BAND_5G; - err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val); - - if (!err) { - /* only set 2G bandwidth using bw_cap command */ - band_bwcap.band = cpu_to_le32(WLC_BAND_2G); - band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ); - err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap, - sizeof(band_bwcap)); - } else { - brcmf_dbg(INFO, "fallback to mimo_bw_cap\n"); - val = WLC_N_BW_40ALL; - err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val); - } - return err; -} - static s32 brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout) { @@ -5194,6 +5050,30 @@ exit: return err; } +static int brcmf_enable_bw40_2g(struct brcmf_if *ifp) +{ + struct brcmf_fil_bwcap_le band_bwcap; + u32 val; + int err; + + /* verify support for bw_cap command */ + val = WLC_BAND_5G; + err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val); + + if (!err) { + /* only set 2G bandwidth using bw_cap command */ + band_bwcap.band = cpu_to_le32(WLC_BAND_2G); + band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ); + err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap, + sizeof(band_bwcap)); + } else { + brcmf_dbg(INFO, "fallback to mimo_bw_cap\n"); + val = WLC_N_BW_40ALL; + err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val); + } + return err; +} + static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[]) { u32 band, mimo_bwcap; @@ -5377,6 +5257,126 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) return err; } +static const struct ieee80211_iface_limit brcmf_iface_limits[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE) + } +}; +static struct ieee80211_iface_combination brcmf_iface_combos[] = { + { + .max_interfaces = BRCMF_IFACE_MAX_CNT, + .num_different_channels = 1, + .n_limits = ARRAY_SIZE(brcmf_iface_limits), + .limits = brcmf_iface_limits + } +}; + +static const struct ieee80211_txrx_stypes +brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_GO] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_DEVICE] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + } +}; + +static void brcmf_wiphy_pno_params(struct wiphy *wiphy) +{ + /* scheduled scan settings */ + wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; + wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; + wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; + wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; +} + +static struct wiphy *brcmf_setup_wiphy(struct brcmf_if *ifp, + struct device *phydev) +{ + struct wiphy *wiphy; + s32 err = 0; + + wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info)); + if (!wiphy) { + brcmf_err("Could not allocate wiphy device\n"); + return ERR_PTR(-ENOMEM); + } + set_wiphy_dev(wiphy, phydev); + wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; + wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; + wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_DEVICE); + /* need VSDB firmware feature for concurrent channels */ + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) + brcmf_iface_combos[0].num_different_channels = 2; + wiphy->iface_combinations = brcmf_iface_combos; + wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); + wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->cipher_suites = __wl_cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); + wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT | + WIPHY_FLAG_OFFCHAN_TX | + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_SUPPORTS_TDLS; + if (!brcmf_roamoff) + wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + wiphy->mgmt_stypes = brcmf_txrx_stypes; + wiphy->max_remain_on_channel_duration = 5000; + brcmf_wiphy_pno_params(wiphy); + brcmf_dbg(INFO, "Registering custom regulatory\n"); + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; + wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); + + /* vendor commands/events support */ + wiphy->vendor_commands = brcmf_vendor_cmds; + wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1; + + err = wiphy_register(wiphy); + if (err < 0) { + brcmf_err("Could not register wiphy device (%d)\n", err); + wiphy_free(wiphy); + return ERR_PTR(err); + } + return wiphy; +} + static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg) { -- cgit v1.2.3 From b48d891676f756d48b4d0ee131e4a7a5d43ca417 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 12 Jul 2014 08:49:41 +0200 Subject: brcmfmac: rework wiphy structure setup Instead of waiting for IFF_UP of the primary net device to determine the band and channel information of the wiphy structure, this is now done during driver initialization in brcmf_cfg80211_attach(). The channel information is obtained from the device and the 2G band is updated when 40MHz bandwidth is enabled for that band. Before this change the band and channel objects were common between multiple brcmfmac devices in the system, which make that information rather unreliable. That is also fixed with this reworked implementation. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 566 +++++++++++---------- 1 file changed, 298 insertions(+), 268 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index d0b48dd4f154..d3bb4e0f4480 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -103,24 +103,6 @@ static bool check_vif_up(struct brcmf_cfg80211_vif *vif) return true; } -#define CHAN2G(_channel, _freq, _flags) { \ - .band = IEEE80211_BAND_2GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_channel), \ - .flags = (_flags), \ - .max_antenna_gain = 0, \ - .max_power = 30, \ -} - -#define CHAN5G(_channel, _flags) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = 5000 + (5 * (_channel)), \ - .hw_value = (_channel), \ - .flags = (_flags), \ - .max_antenna_gain = 0, \ - .max_power = 30, \ -} - #define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) #define RATETAB_ENT(_rateid, _flags) \ { \ @@ -149,58 +131,17 @@ static struct ieee80211_rate __wl_rates[] = { #define wl_g_rates (__wl_rates + 0) #define wl_g_rates_size 12 -static struct ieee80211_channel __wl_2ghz_channels[] = { - CHAN2G(1, 2412, 0), - CHAN2G(2, 2417, 0), - CHAN2G(3, 2422, 0), - CHAN2G(4, 2427, 0), - CHAN2G(5, 2432, 0), - CHAN2G(6, 2437, 0), - CHAN2G(7, 2442, 0), - CHAN2G(8, 2447, 0), - CHAN2G(9, 2452, 0), - CHAN2G(10, 2457, 0), - CHAN2G(11, 2462, 0), - CHAN2G(12, 2467, 0), - CHAN2G(13, 2472, 0), - CHAN2G(14, 2484, 0), -}; - -static struct ieee80211_channel __wl_5ghz_a_channels[] = { - CHAN5G(34, 0), CHAN5G(36, 0), - CHAN5G(38, 0), CHAN5G(40, 0), - CHAN5G(42, 0), CHAN5G(44, 0), - CHAN5G(46, 0), CHAN5G(48, 0), - CHAN5G(52, 0), CHAN5G(56, 0), - CHAN5G(60, 0), CHAN5G(64, 0), - CHAN5G(100, 0), CHAN5G(104, 0), - CHAN5G(108, 0), CHAN5G(112, 0), - CHAN5G(116, 0), CHAN5G(120, 0), - CHAN5G(124, 0), CHAN5G(128, 0), - CHAN5G(132, 0), CHAN5G(136, 0), - CHAN5G(140, 0), CHAN5G(149, 0), - CHAN5G(153, 0), CHAN5G(157, 0), - CHAN5G(161, 0), CHAN5G(165, 0), - CHAN5G(184, 0), CHAN5G(188, 0), - CHAN5G(192, 0), CHAN5G(196, 0), - CHAN5G(200, 0), CHAN5G(204, 0), - CHAN5G(208, 0), CHAN5G(212, 0), - CHAN5G(216, 0), -}; - -static struct ieee80211_supported_band __wl_band_2ghz = { +/* Band templates duplicated per wiphy. The channel info + * is filled in after querying the device. + */ +static const struct ieee80211_supported_band __wl_band_2ghz = { .band = IEEE80211_BAND_2GHZ, - .channels = __wl_2ghz_channels, - .n_channels = ARRAY_SIZE(__wl_2ghz_channels), .bitrates = wl_g_rates, .n_bitrates = wl_g_rates_size, - .ht_cap = {IEEE80211_HT_CAP_SUP_WIDTH_20_40, true}, }; -static struct ieee80211_supported_band __wl_band_5ghz_a = { +static const struct ieee80211_supported_band __wl_band_5ghz_a = { .band = IEEE80211_BAND_5GHZ, - .channels = __wl_5ghz_a_channels, - .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), .bitrates = wl_a_rates, .n_bitrates = wl_a_rates_size, }; @@ -4913,25 +4854,77 @@ dongle_scantime_out: return err; } +/* Filter the list of channels received from firmware counting only + * the 20MHz channels. The wiphy band data only needs those which get + * flagged to indicate if they can take part in higher bandwidth. + */ +static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg, + struct brcmf_chanspec_list *chlist, + u32 chcnt[]) +{ + u32 total = le32_to_cpu(chlist->count); + struct brcmu_chan ch; + int i; + + for (i = 0; i <= total; i++) { + ch.chspec = (u16)le32_to_cpu(chlist->element[i]); + cfg->d11inf.decchspec(&ch); + + /* Firmware gives a ordered list. We skip non-20MHz + * channels is 2G. For 5G we can abort upon reaching + * a non-20MHz channel in the list. + */ + if (ch.bw != BRCMU_CHAN_BW_20) { + if (ch.band == BRCMU_CHAN_BAND_5G) + break; + else + continue; + } + + if (ch.band == BRCMU_CHAN_BAND_2G) + chcnt[0] += 1; + else if (ch.band == BRCMU_CHAN_BAND_5G) + chcnt[1] += 1; + } +} + +static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel, + struct brcmu_chan *ch) +{ + u32 ht40_flag; -static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, - u32 bw_cap[]) + ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40; + if (ch->sb == BRCMU_CHAN_SB_U) { + if (ht40_flag == IEEE80211_CHAN_NO_HT40) + channel->flags &= ~IEEE80211_CHAN_NO_HT40; + channel->flags |= IEEE80211_CHAN_NO_HT40PLUS; + } else { + /* It should be one of + * IEEE80211_CHAN_NO_HT40 or + * IEEE80211_CHAN_NO_HT40PLUS + */ + channel->flags &= ~IEEE80211_CHAN_NO_HT40; + if (ht40_flag == IEEE80211_CHAN_NO_HT40) + channel->flags |= IEEE80211_CHAN_NO_HT40MINUS; + } +} + +static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg, + u32 bw_cap[]) { struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); - struct ieee80211_channel *band_chan_arr; + struct ieee80211_supported_band *band; + struct ieee80211_channel *channel; + struct wiphy *wiphy; struct brcmf_chanspec_list *list; struct brcmu_chan ch; - s32 err; + int err; u8 *pbuf; u32 i, j; u32 total; - enum ieee80211_band band; - u32 channel; - u32 *n_cnt; + u32 chaninfo; + u32 chcnt[2] = { 0, 0 }; u32 index; - u32 ht40_flag; - bool update; - u32 array_size; pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL); @@ -4944,11 +4937,45 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, BRCMF_DCMD_MEDLEN); if (err) { brcmf_err("get chanspecs error (%d)\n", err); - goto exit; + goto fail_pbuf; } - __wl_band_2ghz.n_channels = 0; - __wl_band_5ghz_a.n_channels = 0; + brcmf_count_20mhz_channels(cfg, list, chcnt); + wiphy = cfg_to_wiphy(cfg); + if (chcnt[0]) { + band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz), + GFP_KERNEL); + if (band == NULL) { + err = -ENOMEM; + goto fail_pbuf; + } + band->channels = kcalloc(chcnt[0], sizeof(*channel), + GFP_KERNEL); + if (band->channels == NULL) { + kfree(band); + err = -ENOMEM; + goto fail_pbuf; + } + band->n_channels = 0; + wiphy->bands[IEEE80211_BAND_2GHZ] = band; + } + if (chcnt[1]) { + band = kmemdup(&__wl_band_5ghz_a, sizeof(__wl_band_5ghz_a), + GFP_KERNEL); + if (band == NULL) { + err = -ENOMEM; + goto fail_band2g; + } + band->channels = kcalloc(chcnt[1], sizeof(*channel), + GFP_KERNEL); + if (band->channels == NULL) { + kfree(band); + err = -ENOMEM; + goto fail_band2g; + } + band->n_channels = 0; + wiphy->bands[IEEE80211_BAND_5GHZ] = band; + } total = le32_to_cpu(list->count); for (i = 0; i < total; i++) { @@ -4956,105 +4983,88 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, cfg->d11inf.decchspec(&ch); if (ch.band == BRCMU_CHAN_BAND_2G) { - band_chan_arr = __wl_2ghz_channels; - array_size = ARRAY_SIZE(__wl_2ghz_channels); - n_cnt = &__wl_band_2ghz.n_channels; - band = IEEE80211_BAND_2GHZ; + band = wiphy->bands[IEEE80211_BAND_2GHZ]; } else if (ch.band == BRCMU_CHAN_BAND_5G) { - band_chan_arr = __wl_5ghz_a_channels; - array_size = ARRAY_SIZE(__wl_5ghz_a_channels); - n_cnt = &__wl_band_5ghz_a.n_channels; - band = IEEE80211_BAND_5GHZ; + band = wiphy->bands[IEEE80211_BAND_5GHZ]; } else { brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec); continue; } - if (!(bw_cap[band] & WLC_BW_40MHZ_BIT) && + if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) && ch.bw == BRCMU_CHAN_BW_40) continue; - if (!(bw_cap[band] & WLC_BW_80MHZ_BIT) && + if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) && ch.bw == BRCMU_CHAN_BW_80) continue; - update = false; - for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { - if (band_chan_arr[j].hw_value == ch.chnum) { - update = true; + + channel = band->channels; + index = band->n_channels; + for (j = 0; j < band->n_channels; j++) { + if (channel[j].hw_value == ch.chnum) { + index = j; break; } } - if (update) - index = j; - else - index = *n_cnt; - if (index < array_size) { - band_chan_arr[index].center_freq = - ieee80211_channel_to_frequency(ch.chnum, band); - band_chan_arr[index].hw_value = ch.chnum; - - /* assuming the chanspecs order is HT20, - * HT40 upper, HT40 lower, and VHT80. + channel[index].center_freq = + ieee80211_channel_to_frequency(ch.chnum, band->band); + channel[index].hw_value = ch.chnum; + + /* assuming the chanspecs order is HT20, + * HT40 upper, HT40 lower, and VHT80. + */ + if (ch.bw == BRCMU_CHAN_BW_80) { + channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ; + } else if (ch.bw == BRCMU_CHAN_BW_40) { + brcmf_update_bw40_channel_flag(&channel[index], &ch); + } else { + /* disable other bandwidths for now as mentioned + * order assure they are enabled for subsequent + * chanspecs. */ - if (ch.bw == BRCMU_CHAN_BW_80) { - band_chan_arr[index].flags &= - ~IEEE80211_CHAN_NO_80MHZ; - } else if (ch.bw == BRCMU_CHAN_BW_40) { - ht40_flag = band_chan_arr[index].flags & - IEEE80211_CHAN_NO_HT40; - if (ch.sb == BRCMU_CHAN_SB_U) { - if (ht40_flag == IEEE80211_CHAN_NO_HT40) - band_chan_arr[index].flags &= - ~IEEE80211_CHAN_NO_HT40; - band_chan_arr[index].flags |= - IEEE80211_CHAN_NO_HT40PLUS; - } else { - /* It should be one of - * IEEE80211_CHAN_NO_HT40 or - * IEEE80211_CHAN_NO_HT40PLUS - */ - band_chan_arr[index].flags &= - ~IEEE80211_CHAN_NO_HT40; - if (ht40_flag == IEEE80211_CHAN_NO_HT40) - band_chan_arr[index].flags |= - IEEE80211_CHAN_NO_HT40MINUS; - } - } else { - /* disable other bandwidths for now as mentioned - * order assure they are enabled for subsequent - * chanspecs. - */ - band_chan_arr[index].flags = - IEEE80211_CHAN_NO_HT40 | - IEEE80211_CHAN_NO_80MHZ; - ch.bw = BRCMU_CHAN_BW_20; - cfg->d11inf.encchspec(&ch); - channel = ch.chspec; - err = brcmf_fil_bsscfg_int_get(ifp, - "per_chan_info", - &channel); - if (!err) { - if (channel & WL_CHAN_RADAR) - band_chan_arr[index].flags |= - (IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IR); - if (channel & WL_CHAN_PASSIVE) - band_chan_arr[index].flags |= - IEEE80211_CHAN_NO_IR; - } + channel[index].flags = IEEE80211_CHAN_NO_HT40 | + IEEE80211_CHAN_NO_80MHZ; + ch.bw = BRCMU_CHAN_BW_20; + cfg->d11inf.encchspec(&ch); + chaninfo = ch.chspec; + err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info", + &chaninfo); + if (!err) { + if (chaninfo & WL_CHAN_RADAR) + channel[index].flags |= + (IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR); + if (chaninfo & WL_CHAN_PASSIVE) + channel[index].flags |= + IEEE80211_CHAN_NO_IR; } - if (!update) - (*n_cnt)++; } + if (index == band->n_channels) + band->n_channels++; } -exit: + kfree(pbuf); + return 0; + +fail_band2g: + kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels); + kfree(wiphy->bands[IEEE80211_BAND_2GHZ]); + wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; +fail_pbuf: kfree(pbuf); return err; } -static int brcmf_enable_bw40_2g(struct brcmf_if *ifp) +static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg) { + struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + struct ieee80211_supported_band *band; struct brcmf_fil_bwcap_le band_bwcap; + struct brcmf_chanspec_list *list; + u8 *pbuf; u32 val; int err; + struct brcmu_chan ch; + u32 num_chan; + int i, j; /* verify support for bw_cap command */ val = WLC_BAND_5G; @@ -5071,6 +5081,50 @@ static int brcmf_enable_bw40_2g(struct brcmf_if *ifp) val = WLC_N_BW_40ALL; err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val); } + + if (!err) { + /* update channel info in 2G band */ + pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL); + + if (pbuf == NULL) + return -ENOMEM; + + ch.band = BRCMU_CHAN_BAND_2G; + ch.bw = BRCMU_CHAN_BW_40; + ch.chnum = 0; + cfg->d11inf.encchspec(&ch); + + /* pass encoded chanspec in query */ + *(__le16 *)pbuf = cpu_to_le16(ch.chspec); + + err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf, + BRCMF_DCMD_MEDLEN); + if (err) { + brcmf_err("get chanspecs error (%d)\n", err); + kfree(pbuf); + return err; + } + + band = cfg_to_wiphy(cfg)->bands[IEEE80211_BAND_2GHZ]; + list = (struct brcmf_chanspec_list *)pbuf; + num_chan = le32_to_cpu(list->count); + for (i = 0; i < num_chan; i++) { + ch.chspec = (u16)le32_to_cpu(list->element[i]); + cfg->d11inf.decchspec(&ch); + if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G)) + continue; + if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40)) + continue; + for (j = 0; j < band->n_channels; j++) { + if (band->channels[j].hw_value == ch.chnum) + break; + } + if (WARN_ON(j == band->n_channels)) + continue; + + brcmf_update_bw40_channel_flag(&band->channels[j], &ch); + } + } return err; } @@ -5164,44 +5218,19 @@ static void brcmf_update_vht_cap(struct ieee80211_supported_band *band, band->vht_cap.vht_mcs.tx_mcs_map = mcs_map; } -static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) +static int brcmf_setup_wiphybands(struct wiphy *wiphy) { + struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); - struct wiphy *wiphy; - s32 phy_list; - u32 band_list[3]; u32 nmode = 0; u32 vhtmode = 0; - u32 bw_cap[2] = { 0, 0 }; + u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT }; u32 rxchain; u32 nchain; - s8 phy; - s32 err; - u32 nband; + int err; s32 i; - struct ieee80211_supported_band *bands[2] = { NULL, NULL }; struct ieee80211_supported_band *band; - err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST, - &phy_list, sizeof(phy_list)); - if (err) { - brcmf_err("BRCMF_C_GET_PHYLIST error (%d)\n", err); - return err; - } - - phy = ((char *)&phy_list)[0]; - brcmf_dbg(INFO, "BRCMF_C_GET_PHYLIST reported: %c phy\n", phy); - - - err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST, - &band_list, sizeof(band_list)); - if (err) { - brcmf_err("BRCMF_C_GET_BANDLIST error (%d)\n", err); - return err; - } - brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n", - band_list[0], band_list[1], band_list[2]); - (void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode); err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode); if (err) { @@ -5223,38 +5252,25 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) } brcmf_dbg(INFO, "nchain=%d\n", nchain); - err = brcmf_construct_reginfo(cfg, bw_cap); + err = brcmf_construct_chaninfo(cfg, bw_cap); if (err) { - brcmf_err("brcmf_construct_reginfo failed (%d)\n", err); + brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err); return err; } - nband = band_list[0]; - - for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) { - band = NULL; - if ((band_list[i] == WLC_BAND_5G) && - (__wl_band_5ghz_a.n_channels > 0)) - band = &__wl_band_5ghz_a; - else if ((band_list[i] == WLC_BAND_2G) && - (__wl_band_2ghz.n_channels > 0)) - band = &__wl_band_2ghz; - else + wiphy = cfg_to_wiphy(cfg); + for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) { + band = wiphy->bands[i]; + if (band == NULL) continue; if (nmode) brcmf_update_ht_cap(band, bw_cap, nchain); if (vhtmode) brcmf_update_vht_cap(band, bw_cap, nchain); - bands[band->band] = band; } - wiphy = cfg_to_wiphy(cfg); - wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ]; - wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ]; - wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); - - return err; + return 0; } static const struct ieee80211_iface_limit brcmf_iface_limits[] = { @@ -5321,18 +5337,9 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy) wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; } -static struct wiphy *brcmf_setup_wiphy(struct brcmf_if *ifp, - struct device *phydev) +static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) { - struct wiphy *wiphy; - s32 err = 0; - - wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info)); - if (!wiphy) { - brcmf_err("Could not allocate wiphy device\n"); - return ERR_PTR(-ENOMEM); - } - set_wiphy_dev(wiphy, phydev); + struct ieee80211_iface_combination ifc_combo; wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; @@ -5343,11 +5350,13 @@ static struct wiphy *brcmf_setup_wiphy(struct brcmf_if *ifp, BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_DEVICE); /* need VSDB firmware feature for concurrent channels */ + ifc_combo = brcmf_iface_combos[0]; if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) - brcmf_iface_combos[0].num_different_channels = 2; - wiphy->iface_combinations = brcmf_iface_combos; + ifc_combo.num_different_channels = 2; + wiphy->iface_combinations = kmemdup(&ifc_combo, + sizeof(ifc_combo), + GFP_KERNEL); wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); - wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->cipher_suites = __wl_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); @@ -5360,27 +5369,12 @@ static struct wiphy *brcmf_setup_wiphy(struct brcmf_if *ifp, wiphy->mgmt_stypes = brcmf_txrx_stypes; wiphy->max_remain_on_channel_duration = 5000; brcmf_wiphy_pno_params(wiphy); - brcmf_dbg(INFO, "Registering custom regulatory\n"); - wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; - wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); /* vendor commands/events support */ wiphy->vendor_commands = brcmf_vendor_cmds; wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1; - err = wiphy_register(wiphy); - if (err < 0) { - brcmf_err("Could not register wiphy device (%d)\n", err); - wiphy_free(wiphy); - return ERR_PTR(err); - } - return wiphy; -} - - -static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg) -{ - return brcmf_update_wiphybands(cfg); + return brcmf_setup_wiphybands(wiphy); } static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) @@ -5418,9 +5412,6 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) NULL, NULL); if (err) goto default_conf_out; - err = brcmf_dongle_probecap(cfg); - if (err) - goto default_conf_out; brcmf_configure_arp_offload(ifp, true); @@ -5548,6 +5539,20 @@ int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, vif_event_equals(event, action), timeout); } +static void brcmf_free_wiphy(struct wiphy *wiphy) +{ + kfree(wiphy->iface_combinations); + if (wiphy->bands[IEEE80211_BAND_2GHZ]) { + kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels); + kfree(wiphy->bands[IEEE80211_BAND_2GHZ]); + } + if (wiphy->bands[IEEE80211_BAND_5GHZ]) { + kfree(wiphy->bands[IEEE80211_BAND_5GHZ]->channels); + kfree(wiphy->bands[IEEE80211_BAND_5GHZ]); + } + wiphy_free(wiphy); +} + struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, struct device *busdev) { @@ -5558,6 +5563,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, struct brcmf_if *ifp; s32 err = 0; s32 io_type; + u16 *cap = NULL; if (!ndev) { brcmf_err("ndev is invalid\n"); @@ -5565,9 +5571,12 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, } ifp = netdev_priv(ndev); - wiphy = brcmf_setup_wiphy(ifp, busdev); - if (IS_ERR(wiphy)) + wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info)); + if (!wiphy) { + brcmf_err("Could not allocate wiphy device\n"); return NULL; + } + set_wiphy_dev(wiphy, busdev); cfg = wiphy_priv(wiphy); cfg->wiphy = wiphy; @@ -5576,10 +5585,8 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, INIT_LIST_HEAD(&cfg->vif_list); vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false); - if (IS_ERR(vif)) { - wiphy_free(wiphy); - return NULL; - } + if (IS_ERR(vif)) + goto wiphy_out; vif->ifp = ifp; vif->wdev.netdev = ndev; @@ -5589,58 +5596,81 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, err = wl_init_priv(cfg); if (err) { brcmf_err("Failed to init iwm_priv (%d)\n", err); - goto cfg80211_attach_out; + brcmf_free_vif(vif); + goto wiphy_out; } ifp->vif = vif; - err = brcmf_p2p_attach(cfg); + /* determine d11 io type before wiphy setup */ + err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type); if (err) { - brcmf_err("P2P initilisation failed (%d)\n", err); - goto cfg80211_p2p_attach_out; + brcmf_err("Failed to get D11 version (%d)\n", err); + goto priv_out; } - err = brcmf_btcoex_attach(cfg); - if (err) { - brcmf_err("BT-coex initialisation failed (%d)\n", err); - brcmf_p2p_detach(&cfg->p2p); - goto cfg80211_p2p_attach_out; + cfg->d11inf.io_type = (u8)io_type; + brcmu_d11_attach(&cfg->d11inf); + + err = brcmf_setup_wiphy(wiphy, ifp); + if (err < 0) + goto priv_out; + + brcmf_dbg(INFO, "Registering custom regulatory\n"); + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; + wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); + + /* firmware defaults to 40MHz disabled in 2G band. We signal + * cfg80211 here that we do and have it decide we can enable + * it. But first check if device does support 2G operation. + */ + if (wiphy->bands[IEEE80211_BAND_2GHZ]) { + cap = &wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap; + *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } + err = wiphy_register(wiphy); + if (err < 0) { + brcmf_err("Could not register wiphy device (%d)\n", err); + goto priv_out; } /* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(), * setup 40MHz in 2GHz band and enable OBSS scanning. */ - if (wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap & - IEEE80211_HT_CAP_SUP_WIDTH_20_40) { - err = brcmf_enable_bw40_2g(ifp); + if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) { + err = brcmf_enable_bw40_2g(cfg); if (!err) err = brcmf_fil_iovar_int_set(ifp, "obss_coex", BRCMF_OBSS_COEX_AUTO); + else + *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; } - /* clear for now and rely on update later */ - wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.ht_supported = false; - wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap = 0; - err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); + err = brcmf_p2p_attach(cfg); if (err) { - brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err); - wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS; + brcmf_err("P2P initilisation failed (%d)\n", err); + goto wiphy_unreg_out; + } + err = brcmf_btcoex_attach(cfg); + if (err) { + brcmf_err("BT-coex initialisation failed (%d)\n", err); + brcmf_p2p_detach(&cfg->p2p); + goto wiphy_unreg_out; } - err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, - &io_type); + err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); if (err) { - brcmf_err("Failed to get D11 version (%d)\n", err); - goto cfg80211_p2p_attach_out; + brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err); + wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS; } - cfg->d11inf.io_type = (u8)io_type; - brcmu_d11_attach(&cfg->d11inf); return cfg; -cfg80211_p2p_attach_out: +wiphy_unreg_out: + wiphy_unregister(cfg->wiphy); +priv_out: wl_deinit_priv(cfg); - -cfg80211_attach_out: brcmf_free_vif(vif); +wiphy_out: + brcmf_free_wiphy(wiphy); return NULL; } @@ -5653,5 +5683,5 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) wiphy_unregister(cfg->wiphy); brcmf_btcoex_detach(cfg); wl_deinit_priv(cfg); - wiphy_free(cfg->wiphy); + brcmf_free_wiphy(cfg->wiphy); } -- cgit v1.2.3 From c3da74bbbb8b230ad8bb84ca324c4e07607c9a7f Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sat, 12 Jul 2014 08:49:42 +0200 Subject: brcmfmac: add brcmf_p2p_detach() call in brcmf_cfg80211_detach() The function brcmf_p2p_detach() was only called in error flow of the brcmf_cfg80211_attach() routine, but it also needs to be called upon brcmf_cfg80211_detach(). Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index d3bb4e0f4480..48078a321716 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -5682,6 +5682,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) WARN_ON(!list_empty(&cfg->vif_list)); wiphy_unregister(cfg->wiphy); brcmf_btcoex_detach(cfg); + brcmf_p2p_detach(&cfg->p2p); wl_deinit_priv(cfg); brcmf_free_wiphy(cfg->wiphy); } -- cgit v1.2.3 From c9ff78b4ff6aee37155bf8bc1df3d6156a46656d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 12 Jul 2014 12:34:46 +0200 Subject: b43: N-PHY: add missing TX gain table for radio 0x2057 rev 5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/tables_nphy.c | 58 +++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 3a5cd902ff1f..b39a8dd375e9 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2692,6 +2692,42 @@ static const u32 b43_ntab_tx_gain_ipa_rev6_2g[] = { 0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025, }; +/* Copied from brcmsmac (5.75.11): nphy_tpc_txgain_ipa_2g_2057rev5 */ +static const u32 b43_ntab_tx_gain_ipa_2057_rev5_2g[] = { + 0x30ff0031, 0x30e70031, 0x30e7002e, 0x30cf002e, + 0x30bf002e, 0x30af002e, 0x309f002f, 0x307f0033, + 0x307f0031, 0x307f002e, 0x3077002e, 0x306f002e, + 0x3067002e, 0x305f002f, 0x30570030, 0x3057002d, + 0x304f002e, 0x30470031, 0x3047002e, 0x3047002c, + 0x30470029, 0x303f002c, 0x303f0029, 0x3037002d, + 0x3037002a, 0x30370028, 0x302f002c, 0x302f002a, + 0x302f0028, 0x302f0026, 0x3027002c, 0x30270029, + 0x30270027, 0x30270025, 0x30270023, 0x301f002c, + 0x301f002a, 0x301f0028, 0x301f0025, 0x301f0024, + 0x301f0022, 0x301f001f, 0x3017002d, 0x3017002b, + 0x30170028, 0x30170026, 0x30170024, 0x30170022, + 0x30170020, 0x3017001e, 0x3017001d, 0x3017001b, + 0x3017001a, 0x30170018, 0x30170017, 0x30170015, + 0x300f002c, 0x300f0029, 0x300f0027, 0x300f0024, + 0x300f0022, 0x300f0021, 0x300f001f, 0x300f001d, + 0x300f001b, 0x300f001a, 0x300f0018, 0x300f0017, + 0x300f0016, 0x300f0015, 0x300f0115, 0x300f0215, + 0x300f0315, 0x300f0415, 0x300f0515, 0x300f0615, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, +}; + /* Extracted from MMIO dump of 6.30.223.141 */ static const u32 b43_ntab_tx_gain_ipa_2057_rev9_2g[] = { 0x60ff0031, 0x60e7002c, 0x60cf002a, 0x60c70029, @@ -3550,6 +3586,11 @@ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) case 16: if (phy->radio_rev == 9) return b43_ntab_tx_gain_ipa_2057_rev9_2g; + break; + case 8: + if (phy->radio_rev == 5) + return b43_ntab_tx_gain_ipa_2057_rev5_2g; + break; case 6: if (dev->dev->chip_id == BCMA_CHIP_ID_BCM47162) return b43_ntab_tx_gain_ipa_rev5_2g; @@ -3559,23 +3600,24 @@ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) case 4: case 3: return b43_ntab_tx_gain_ipa_rev3_2g; - default: - b43err(dev->wl, - "No 2GHz IPA gain table available for this device\n"); - return NULL; } + + b43err(dev->wl, + "No 2GHz IPA gain table available for this device\n"); + return NULL; } else { switch (phy->rev) { case 16: if (phy->radio_rev == 9) return b43_ntab_tx_gain_ipa_2057_rev9_5g; + break; case 3 ... 6: return b43_ntab_tx_gain_ipa_rev3_5g; - default: - b43err(dev->wl, - "No 5GHz IPA gain table available for this device\n"); - return NULL; } + + b43err(dev->wl, + "No 5GHz IPA gain table available for this device\n"); + return NULL; } } -- cgit v1.2.3 From b3bbf842670def767ec8ebdd424f09358afeb5c6 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Sat, 12 Jul 2014 14:57:38 +0200 Subject: wireless: zd1211rw: new url for fw, remove experimental Cc: Daniel Drake Cc: Ulrich Kunitz Cc: John W. Linville Cc: linux-wireless@vger.kernel.org Signed-off-by: Xose Vazquez Perez Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig index 96c8e1de0879..95920581860a 100644 --- a/drivers/net/wireless/zd1211rw/Kconfig +++ b/drivers/net/wireless/zd1211rw/Kconfig @@ -3,11 +3,11 @@ config ZD1211RW depends on USB && MAC80211 select FW_LOADER ---help--- - This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless + This is a driver for the ZyDAS ZD1211/ZD1211B wireless chip, present in many USB-wireless adapters. Device firmware is required alongside this driver. You can download - the firmware distribution from http://zd1211.ath.cx/get-firmware + the firmware distribution from http://sf.net/projects/zd1211/files/ config ZD1211RW_DEBUG bool "ZyDAS ZD1211 debugging" -- cgit v1.2.3 From 67d392c0e900bbf885ee08b8942c3204a2cab697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 12 Jul 2014 16:42:09 +0200 Subject: ssb: make code for antenna gain extraction more generic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/ssb/pci.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index a8dc95ebf2d6..fc0bb4923ac3 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -326,13 +326,13 @@ err_ctlreg: return err; } -static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in, - u16 mask, u16 shift) +static s8 sprom_extract_antgain(u8 sprom_revision, const u16 *in, u16 offset, + u16 mask, u16 shift) { u16 v; u8 gain; - v = in[SPOFF(SSB_SPROM1_AGAIN)]; + v = in[SPOFF(offset)]; gain = (v & mask) >> shift; if (gain == 0xFF) gain = 2; /* If unset use 2dBm */ @@ -416,12 +416,14 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0); /* Extract the antenna gain values. */ - out->antenna_gain.a0 = r123_extract_antgain(out->revision, in, - SSB_SPROM1_AGAIN_BG, - SSB_SPROM1_AGAIN_BG_SHIFT); - out->antenna_gain.a1 = r123_extract_antgain(out->revision, in, - SSB_SPROM1_AGAIN_A, - SSB_SPROM1_AGAIN_A_SHIFT); + out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in, + SSB_SPROM1_AGAIN, + SSB_SPROM1_AGAIN_BG, + SSB_SPROM1_AGAIN_BG_SHIFT); + out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in, + SSB_SPROM1_AGAIN, + SSB_SPROM1_AGAIN_A, + SSB_SPROM1_AGAIN_A_SHIFT); if (out->revision >= 2) sprom_extract_r23(out, in); } -- cgit v1.2.3 From 6daf43216fd5171f0f44504226efeb5563538f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 12 Jul 2014 16:42:10 +0200 Subject: ssb: extract antenna gains from SPROMs revs 4+ properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They are encoded the same way as in older SPROMs. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/ssb/pci.c | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index fc0bb4923ac3..6318364be590 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -526,14 +526,22 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) } /* Extract the antenna gain values. */ - SPEX(antenna_gain.a0, SSB_SPROM4_AGAIN01, - SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT); - SPEX(antenna_gain.a1, SSB_SPROM4_AGAIN01, - SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT); - SPEX(antenna_gain.a2, SSB_SPROM4_AGAIN23, - SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT); - SPEX(antenna_gain.a3, SSB_SPROM4_AGAIN23, - SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT); + out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in, + SSB_SPROM4_AGAIN01, + SSB_SPROM4_AGAIN0, + SSB_SPROM4_AGAIN0_SHIFT); + out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in, + SSB_SPROM4_AGAIN01, + SSB_SPROM4_AGAIN1, + SSB_SPROM4_AGAIN1_SHIFT); + out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in, + SSB_SPROM4_AGAIN23, + SSB_SPROM4_AGAIN2, + SSB_SPROM4_AGAIN2_SHIFT); + out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in, + SSB_SPROM4_AGAIN23, + SSB_SPROM4_AGAIN3, + SSB_SPROM4_AGAIN3_SHIFT); sprom_extract_r458(out, in); @@ -623,14 +631,22 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0); /* Extract the antenna gain values. */ - SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01, - SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT); - SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01, - SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT); - SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23, - SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT); - SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23, - SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT); + out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in, + SSB_SPROM8_AGAIN01, + SSB_SPROM8_AGAIN0, + SSB_SPROM8_AGAIN0_SHIFT); + out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in, + SSB_SPROM8_AGAIN01, + SSB_SPROM8_AGAIN1, + SSB_SPROM8_AGAIN1_SHIFT); + out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in, + SSB_SPROM8_AGAIN23, + SSB_SPROM8_AGAIN2, + SSB_SPROM8_AGAIN2_SHIFT); + out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in, + SSB_SPROM8_AGAIN23, + SSB_SPROM8_AGAIN3, + SSB_SPROM8_AGAIN3_SHIFT); /* Extract cores power info info */ for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { -- cgit v1.2.3 From c634099d685b46de368c0888da3667eb14b9034a Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 14 Jul 2014 10:34:47 -0300 Subject: net: mvpp2: Fix a typo in the license The proper string for this license is "GPL v2", instead of "GPLv2". This commit fixes that. Reported-by: Arnd Bergmann Signed-off-by: Ezequiel Garcia Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 9463ede32e6a..f4de2a9316ff 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -6390,4 +6390,4 @@ module_platform_driver(mvpp2_driver); MODULE_DESCRIPTION("Marvell PPv2 Ethernet Driver - www.marvell.com"); MODULE_AUTHOR("Marcin Wojtas "); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 685343fc3ba61a1f6eef361b786601123db16c28 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 14 Jul 2014 16:37:22 +0200 Subject: net: add name_assign_type netdev attribute Based on a patch by David Herrmann. The name_assign_type attribute gives hints where the interface name of a given net-device comes from. These values are currently defined: NET_NAME_ENUM: The ifname is provided by the kernel with an enumerated suffix, typically based on order of discovery. Names may be reused and unpredictable. NET_NAME_PREDICTABLE: The ifname has been assigned by the kernel in a predictable way that is guaranteed to avoid reuse and always be the same for a given device. Examples include statically created devices like the loopback device and names deduced from hardware properties (including being given explicitly by the firmware). Names depending on the order of discovery, or in any other way on the existence of other devices, must not be marked as PREDICTABLE. NET_NAME_USER: The ifname was provided by user-space during net-device setup. NET_NAME_RENAMED: The net-device has been renamed from userspace. Once this type is set, it cannot change again. NET_NAME_UNKNOWN: This is an internal placeholder to indicate that we yet haven't yet categorized the name. It will not be exposed to userspace, rather -EINVAL is returned. The aim of these patches is to improve user-space renaming of interfaces. As a general rule, userspace must rename interfaces to guarantee that names stay the same every time a given piece of hardware appears (at boot, or when attaching it). However, there are several situations where userspace should not perform the renaming, and that depends on both the policy of the local admin, but crucially also on the nature of the current interface name. If an interface was created in repsonse to a userspace request, and userspace already provided a name, we most probably want to leave that name alone. The main instance of this is wifi-P2P devices created over nl80211, which currently have a long-standing bug where they are getting renamed by udev. We label such names NET_NAME_USER. If an interface, unbeknown to us, has already been renamed from userspace, we most probably want to leave also that alone. This will typically happen when third-party plugins (for instance to udev, but the interface is generic so could be from anywhere) renames the interface without informing udev about it. A typical situation is when you switch root from an installer or an initrd to the real system and the new instance of udev does not know what happened before the switch. These types of problems have caused repeated issues in the past. To solve this, once an interface has been renamed, its name is labelled NET_NAME_RENAMED. In many cases, the kernel is actually able to name interfaces in such a way that there is no need for userspace to rename them. This is the case when the enumeration order of devices, or in fact any other (non-parent) device on the system, can not influence the name of the interface. Examples include statically created devices, or any naming schemes based on hardware properties of the interface. In this case the admin may prefer to use the kernel-provided names, and to make that possible we label such names NET_NAME_PREDICTABLE. We want the kernel to have tho possibilty of performing predictable interface naming itself (and exposing to userspace that it has), as the information necessary for a proper naming scheme for a certain class of devices may not be exposed to userspace. The case where renaming is almost certainly desired, is when the kernel has given the interface a name using global device enumeration based on order of discovery (ethX, wlanY, etc). These naming schemes are labelled NET_NAME_ENUM. Lastly, a fallback is left as NET_NAME_UNKNOWN, to indicate that a driver has not yet been ported. This is mostly useful as a transitionary measure, allowing us to label the various naming schemes bit by bit. v8: minor documentation fixes v9: move comment to the right commit Signed-off-by: Tom Gundersen Reviewed-by: David Herrmann Reviewed-by: Kay Sievers Signed-off-by: David S. Miller --- Documentation/ABI/testing/sysfs-class-net | 11 +++++++++++ include/linux/netdevice.h | 2 ++ include/uapi/linux/netdevice.h | 6 ++++++ net/core/net-sysfs.c | 20 ++++++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-net b/Documentation/ABI/testing/sysfs-class-net index 416c5d59f52e..d322b0581194 100644 --- a/Documentation/ABI/testing/sysfs-class-net +++ b/Documentation/ABI/testing/sysfs-class-net @@ -1,3 +1,14 @@ +What: /sys/class/net//name_assign_type +Date: July 2014 +KernelVersion: 3.17 +Contact: netdev@vger.kernel.org +Description: + Indicates the name assignment type. Possible values are: + 1: enumerated by the kernel, possibly in an unpredictable way + 2: predictably named by the kernel + 3: named by userspace + 4: renamed + What: /sys/class/net//addr_assign_type Date: July 2010 KernelVersion: 3.2 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 3a320db96180..9be34732142f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1381,6 +1381,8 @@ struct net_device { struct kset *queues_kset; #endif + unsigned char name_assign_type; + bool uc_promisc; unsigned int promiscuity; unsigned int allmulti; diff --git a/include/uapi/linux/netdevice.h b/include/uapi/linux/netdevice.h index fdfbd1c17065..55818543342d 100644 --- a/include/uapi/linux/netdevice.h +++ b/include/uapi/linux/netdevice.h @@ -37,6 +37,12 @@ #define INIT_NETDEV_GROUP 0 +/* interface name assignment types (sysfs name_assign_type attribute) */ +#define NET_NAME_UNKNOWN 0 /* unknown origin (not exposed to userspace) */ +#define NET_NAME_ENUM 1 /* enumerated by kernel */ +#define NET_NAME_PREDICTABLE 2 /* predictably named by the kernel */ +#define NET_NAME_USER 3 /* provided by user-space */ +#define NET_NAME_RENAMED 4 /* renamed by user-space */ /* Media selection options. */ enum { diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 1cac29ebb05b..7752f2ad49a5 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -112,6 +112,25 @@ NETDEVICE_SHOW_RO(ifindex, fmt_dec); NETDEVICE_SHOW_RO(type, fmt_dec); NETDEVICE_SHOW_RO(link_mode, fmt_dec); +static ssize_t format_name_assign_type(const struct net_device *net, char *buf) +{ + return sprintf(buf, fmt_dec, net->name_assign_type); +} + +static ssize_t name_assign_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net = to_net_dev(dev); + ssize_t ret = -EINVAL; + + if (net->name_assign_type != NET_NAME_UNKNOWN) + ret = netdev_show(dev, attr, buf, format_name_assign_type); + + return ret; +} +static DEVICE_ATTR_RO(name_assign_type); + /* use same locking rules as GIFHWADDR ioctl's */ static ssize_t address_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -387,6 +406,7 @@ static struct attribute *net_class_attrs[] = { &dev_attr_dev_port.attr, &dev_attr_iflink.attr, &dev_attr_ifindex.attr, + &dev_attr_name_assign_type.attr, &dev_attr_addr_assign_type.attr, &dev_attr_addr_len.attr, &dev_attr_link_mode.attr, -- cgit v1.2.3 From 238fa3623a5709d29673ed78ff8e714d040fbb89 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 14 Jul 2014 16:37:23 +0200 Subject: net: set name assign type for renamed devices Based on a patch from David Herrmann. This is the only place devices can be renamed. v9: restore revers-christmas-tree order of local variables Signed-off-by: Tom Gundersen Reviewed-by: David Herrmann Signed-off-by: David S. Miller --- net/core/dev.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index 6e2a2cd82321..38793fb84a35 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1082,6 +1082,7 @@ static int dev_get_valid_name(struct net *net, */ int dev_change_name(struct net_device *dev, const char *newname) { + unsigned char old_assign_type; char oldname[IFNAMSIZ]; int err = 0; int ret; @@ -1109,10 +1110,14 @@ int dev_change_name(struct net_device *dev, const char *newname) return err; } + old_assign_type = dev->name_assign_type; + dev->name_assign_type = NET_NAME_RENAMED; + rollback: ret = device_rename(&dev->dev, dev->name); if (ret) { memcpy(dev->name, oldname, IFNAMSIZ); + dev->name_assign_type = old_assign_type; write_seqcount_end(&devnet_rename_seq); return ret; } @@ -1141,6 +1146,8 @@ rollback: write_seqcount_begin(&devnet_rename_seq); memcpy(dev->name, oldname, IFNAMSIZ); memcpy(oldname, newname, IFNAMSIZ); + dev->name_assign_type = old_assign_type; + old_assign_type = NET_NAME_RENAMED; goto rollback; } else { pr_err("%s: name change rollback failed: %d\n", -- cgit v1.2.3 From c835a677331495cf137a7f8a023463afd9f032f8 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 14 Jul 2014 16:37:24 +0200 Subject: net: set name_assign_type in alloc_netdev() Extend alloc_netdev{,_mq{,s}}() to take name_assign_type as argument, and convert all users to pass NET_NAME_UNKNOWN. Coccinelle patch: @@ expression sizeof_priv, name, setup, txqs, rxqs, count; @@ ( -alloc_netdev_mqs(sizeof_priv, name, setup, txqs, rxqs) +alloc_netdev_mqs(sizeof_priv, name, NET_NAME_UNKNOWN, setup, txqs, rxqs) | -alloc_netdev_mq(sizeof_priv, name, setup, count) +alloc_netdev_mq(sizeof_priv, name, NET_NAME_UNKNOWN, setup, count) | -alloc_netdev(sizeof_priv, name, setup) +alloc_netdev(sizeof_priv, name, NET_NAME_UNKNOWN, setup) ) v9: move comments here from the wrong commit Signed-off-by: Tom Gundersen Reviewed-by: David Herrmann Signed-off-by: David S. Miller --- drivers/firewire/net.c | 3 ++- drivers/hsi/clients/ssi_protocol.c | 2 +- drivers/infiniband/hw/amso1100/c2_provider.c | 2 +- drivers/infiniband/ulp/ipoib/ipoib_main.c | 4 ++-- drivers/isdn/i4l/isdn_net.c | 3 ++- drivers/media/dvb-core/dvb_net.c | 3 ++- drivers/misc/sgi-xp/xpnet.c | 3 ++- drivers/net/arcnet/arcnet.c | 3 ++- drivers/net/bonding/bond_main.c | 2 +- drivers/net/caif/caif_serial.c | 3 ++- drivers/net/caif/caif_spi.c | 4 ++-- drivers/net/caif/caif_virtio.c | 2 +- drivers/net/can/dev.c | 2 +- drivers/net/can/slcan.c | 2 +- drivers/net/dummy.c | 2 +- drivers/net/eql.c | 3 ++- drivers/net/ethernet/8390/lib8390.c | 2 +- drivers/net/ethernet/tile/tilegx.c | 4 ++-- drivers/net/ethernet/tile/tilepro.c | 3 ++- drivers/net/hamradio/6pack.c | 3 ++- drivers/net/hamradio/baycom_epp.c | 2 +- drivers/net/hamradio/bpqether.c | 4 ++-- drivers/net/hamradio/dmascc.c | 4 ++-- drivers/net/hamradio/hdlcdrv.c | 2 +- drivers/net/hamradio/mkiss.c | 3 ++- drivers/net/hamradio/scc.c | 2 +- drivers/net/hamradio/yam.c | 2 +- drivers/net/ieee802154/fakehard.c | 3 ++- drivers/net/ifb.c | 4 ++-- drivers/net/loopback.c | 2 +- drivers/net/ppp/ppp_generic.c | 3 ++- drivers/net/slip/slip.c | 2 +- drivers/net/tun.c | 3 ++- drivers/net/usb/cdc-phonet.c | 2 +- drivers/net/usb/hso.c | 3 ++- drivers/net/wan/dlci.c | 4 ++-- drivers/net/wan/hdlc.c | 3 ++- drivers/net/wan/hdlc_fr.c | 5 +++-- drivers/net/wan/lapbether.c | 4 ++-- drivers/net/wan/sbni.c | 7 ++++--- drivers/net/wan/sdla.c | 3 ++- drivers/net/wan/x25_asy.c | 4 ++-- drivers/net/wimax/i2400m/usb.c | 2 +- drivers/net/wireless/airo.c | 5 +++-- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- drivers/net/wireless/ath/wil6210/netdev.c | 2 +- drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | 3 ++- drivers/net/wireless/libertas/main.c | 2 +- drivers/net/wireless/libertas/mesh.c | 2 +- drivers/net/wireless/mac80211_hwsim.c | 3 ++- drivers/net/wireless/mwifiex/cfg80211.c | 3 ++- drivers/net/xen-netback/interface.c | 4 ++-- drivers/s390/net/claw.c | 2 +- drivers/s390/net/ctcm_main.c | 6 ++++-- drivers/s390/net/netiucv.c | 2 +- drivers/s390/net/qeth_l2_main.c | 6 ++++-- drivers/s390/net/qeth_l3_main.c | 3 ++- drivers/staging/cxt1e1/linux.c | 3 ++- drivers/staging/gdm724x/gdm_lte.c | 2 +- drivers/staging/gdm72xx/gdm_wimax.c | 3 ++- drivers/staging/vt6655/wpactl.c | 3 ++- drivers/staging/wlan-ng/p80211netdev.c | 2 +- drivers/tty/n_gsm.c | 5 ++--- drivers/usb/gadget/f_phonet.c | 3 ++- include/linux/netdevice.h | 10 ++++++---- net/802/fc.c | 2 +- net/802/fddi.c | 3 ++- net/802/hippi.c | 3 ++- net/8021q/vlan.c | 3 ++- net/appletalk/dev.c | 3 ++- net/atm/br2684.c | 4 ++-- net/atm/clip.c | 3 ++- net/batman-adv/soft-interface.c | 2 +- net/bluetooth/6lowpan.c | 2 +- net/bluetooth/bnep/core.c | 5 +++-- net/bridge/br_if.c | 2 +- net/core/dev.c | 13 ++++++++----- net/core/rtnetlink.c | 4 ++-- net/dsa/slave.c | 4 ++-- net/ethernet/eth.c | 3 ++- net/ipv4/ip_tunnel.c | 2 +- net/ipv4/ipmr.c | 2 +- net/ipv6/ip6_gre.c | 6 ++++-- net/ipv6/ip6_tunnel.c | 5 +++-- net/ipv6/ip6_vti.c | 4 ++-- net/ipv6/ip6mr.c | 2 +- net/ipv6/sit.c | 4 +++- net/irda/irda_device.c | 3 ++- net/irda/irlan/irlan_eth.c | 2 +- net/l2tp/l2tp_eth.c | 3 ++- net/mac80211/iface.c | 6 +++--- net/mac802154/ieee802154_dev.c | 6 ++++-- net/netrom/af_netrom.c | 2 +- net/openvswitch/vport-internal_dev.c | 3 ++- net/phonet/pep-gprs.c | 2 +- net/rose/af_rose.c | 2 +- net/sched/sch_teql.c | 4 ++-- 97 files changed, 185 insertions(+), 133 deletions(-) diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index c3986452194d..2c68da1ceeee 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -1460,7 +1460,8 @@ static int fwnet_probe(struct fw_unit *unit, goto have_dev; } - net = alloc_netdev(sizeof(*dev), "firewire%d", fwnet_init_dev); + net = alloc_netdev(sizeof(*dev), "firewire%d", NET_NAME_UNKNOWN, + fwnet_init_dev); if (net == NULL) { mutex_unlock(&fwnet_device_mutex); return -ENOMEM; diff --git a/drivers/hsi/clients/ssi_protocol.c b/drivers/hsi/clients/ssi_protocol.c index ce4be3738d46..737fa2e0e782 100644 --- a/drivers/hsi/clients/ssi_protocol.c +++ b/drivers/hsi/clients/ssi_protocol.c @@ -1115,7 +1115,7 @@ static int ssi_protocol_probe(struct device *dev) goto out; } - ssi->netdev = alloc_netdev(0, ifname, ssip_pn_setup); + ssi->netdev = alloc_netdev(0, ifname, NET_NAME_UNKNOWN, ssip_pn_setup); if (!ssi->netdev) { dev_err(dev, "No memory for netdev\n"); err = -ENOMEM; diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index 8af33cf1fc4e..2d5cbf4363e4 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c @@ -734,7 +734,7 @@ static struct net_device *c2_pseudo_netdev_init(struct c2_dev *c2dev) /* change ethxxx to iwxxx */ strcpy(name, "iw"); strcat(name, &c2dev->netdev->name[3]); - netdev = alloc_netdev(0, name, setup); + netdev = alloc_netdev(0, name, NET_NAME_UNKNOWN, setup); if (!netdev) { printk(KERN_ERR PFX "%s - etherdev alloc failed", __func__); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 5786a78ff8bc..4e675f4fecc9 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1394,8 +1394,8 @@ struct ipoib_dev_priv *ipoib_intf_alloc(const char *name) { struct net_device *dev; - dev = alloc_netdev((int) sizeof (struct ipoib_dev_priv), name, - ipoib_setup); + dev = alloc_netdev((int)sizeof(struct ipoib_dev_priv), name, + NET_NAME_UNKNOWN, ipoib_setup); if (!dev) return NULL; diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index d9aebbc510cc..c2ed6246a389 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -2588,7 +2588,8 @@ isdn_net_new(char *name, struct net_device *master) printk(KERN_WARNING "isdn_net: Could not allocate net-device\n"); return NULL; } - netdev->dev = alloc_netdev(sizeof(isdn_net_local), name, _isdn_setup); + netdev->dev = alloc_netdev(sizeof(isdn_net_local), name, + NET_NAME_UNKNOWN, _isdn_setup); if (!netdev->dev) { printk(KERN_WARNING "isdn_net: Could not allocate network device\n"); kfree(netdev); diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 8a86b3025637..059e6117f22b 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -1276,7 +1276,8 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) if ((if_num = get_if(dvbnet)) < 0) return -EINVAL; - net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", dvb_net_setup); + net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", + NET_NAME_UNKNOWN, dvb_net_setup); if (!net) return -ENOMEM; diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 3fac67a5204c..557f9782c53c 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -544,7 +544,8 @@ xpnet_init(void) * use ether_setup() to init the majority of our device * structure and then override the necessary pieces. */ - xpnet_device = alloc_netdev(0, XPNET_DEVICE_NAME, ether_setup); + xpnet_device = alloc_netdev(0, XPNET_DEVICE_NAME, NET_NAME_UNKNOWN, + ether_setup); if (xpnet_device == NULL) { kfree(xpnet_broadcast_partitions); return -ENOMEM; diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index a956053608f9..3b790de6c976 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -346,7 +346,8 @@ struct net_device *alloc_arcdev(const char *name) struct net_device *dev; dev = alloc_netdev(sizeof(struct arcnet_local), - name && *name ? name : "arc%d", arcdev_setup); + name && *name ? name : "arc%d", NET_NAME_UNKNOWN, + arcdev_setup); if(dev) { struct arcnet_local *lp = netdev_priv(dev); spin_lock_init(&lp->lock); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 09dc3ef771a7..46dcb7b6216f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4420,7 +4420,7 @@ int bond_create(struct net *net, const char *name) rtnl_lock(); bond_dev = alloc_netdev_mq(sizeof(struct bonding), - name ? name : "bond%d", + name ? name : "bond%d", NET_NAME_UNKNOWN, bond_setup, tx_queues); if (!bond_dev) { pr_err("%s: eek! can't alloc netdev!\n", name); diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index fc73865bb83a..27bbc56de15f 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -349,7 +349,8 @@ static int ldisc_open(struct tty_struct *tty) result = snprintf(name, sizeof(name), "cf%s", tty->name); if (result >= IFNAMSIZ) return -EINVAL; - dev = alloc_netdev(sizeof(*ser), name, caifdev_setup); + dev = alloc_netdev(sizeof(*ser), name, NET_NAME_UNKNOWN, + caifdev_setup); if (!dev) return -ENOMEM; diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index ff54c0eb2052..72ea9ff9bb9c 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -730,8 +730,8 @@ int cfspi_spi_probe(struct platform_device *pdev) int res; dev = (struct cfspi_dev *)pdev->dev.platform_data; - ndev = alloc_netdev(sizeof(struct cfspi), - "cfspi%d", cfspi_setup); + ndev = alloc_netdev(sizeof(struct cfspi), "cfspi%d", + NET_NAME_UNKNOWN, cfspi_setup); if (!dev) return -ENODEV; diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c index 985608634f8c..a5fefb9059c5 100644 --- a/drivers/net/caif/caif_virtio.c +++ b/drivers/net/caif/caif_virtio.c @@ -661,7 +661,7 @@ static int cfv_probe(struct virtio_device *vdev) int err = -EINVAL; netdev = alloc_netdev(sizeof(struct cfv_info), cfv_netdev_name, - cfv_netdev_setup); + NET_NAME_UNKNOWN, cfv_netdev_setup); if (!netdev) return -ENOMEM; diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index e318e87e2bfc..9f91fcba43f8 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -565,7 +565,7 @@ struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max) else size = sizeof_priv; - dev = alloc_netdev(size, "can%d", can_setup); + dev = alloc_netdev(size, "can%d", NET_NAME_UNKNOWN, can_setup); if (!dev) return NULL; diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index ea4d4f1a6411..acb5b92ace92 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -529,7 +529,7 @@ static struct slcan *slc_alloc(dev_t line) return NULL; sprintf(name, "slcan%d", i); - dev = alloc_netdev(sizeof(*sl), name, slc_setup); + dev = alloc_netdev(sizeof(*sl), name, NET_NAME_UNKNOWN, slc_setup); if (!dev) return NULL; diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 0932ffbf381b..ff435fbd1ad0 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -164,7 +164,7 @@ static int __init dummy_init_one(void) struct net_device *dev_dummy; int err; - dev_dummy = alloc_netdev(0, "dummy%d", dummy_setup); + dev_dummy = alloc_netdev(0, "dummy%d", NET_NAME_UNKNOWN, dummy_setup); if (!dev_dummy) return -ENOMEM; diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 7a79b6046879..957e5c0cede3 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -585,7 +585,8 @@ static int __init eql_init_module(void) pr_info("%s\n", version); - dev_eql = alloc_netdev(sizeof(equalizer_t), "eql", eql_setup); + dev_eql = alloc_netdev(sizeof(equalizer_t), "eql", NET_NAME_UNKNOWN, + eql_setup); if (!dev_eql) return -ENOMEM; diff --git a/drivers/net/ethernet/8390/lib8390.c b/drivers/net/ethernet/8390/lib8390.c index 599311f0e05c..b96e8852b2d1 100644 --- a/drivers/net/ethernet/8390/lib8390.c +++ b/drivers/net/ethernet/8390/lib8390.c @@ -986,7 +986,7 @@ static void ethdev_setup(struct net_device *dev) static struct net_device *____alloc_ei_netdev(int size) { return alloc_netdev(sizeof(struct ei_device) + size, "eth%d", - ethdev_setup); + NET_NAME_UNKNOWN, ethdev_setup); } diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 4c70360967c2..69557a26f749 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -2201,8 +2201,8 @@ static void tile_net_dev_init(const char *name, const uint8_t *mac) /* Allocate the device structure. Normally, "name" is a * template, instantiated by register_netdev(), but not for us. */ - dev = alloc_netdev_mqs(sizeof(*priv), name, tile_net_setup, - NR_CPUS, 1); + dev = alloc_netdev_mqs(sizeof(*priv), name, NET_NAME_UNKNOWN, + tile_net_setup, NR_CPUS, 1); if (!dev) { pr_err("alloc_netdev_mqs(%s) failed\n", name); return; diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c index e5a5c5d4ce0c..88c712126692 100644 --- a/drivers/net/ethernet/tile/tilepro.c +++ b/drivers/net/ethernet/tile/tilepro.c @@ -2292,7 +2292,8 @@ static struct net_device *tile_net_dev_init(const char *name) * tile_net_setup(), and saves "name". Normally, "name" is a * template, instantiated by register_netdev(), but not for us. */ - dev = alloc_netdev(sizeof(*priv), name, tile_net_setup); + dev = alloc_netdev(sizeof(*priv), name, NET_NAME_UNKNOWN, + tile_net_setup); if (!dev) { pr_err("alloc_netdev(%s) failed\n", name); return NULL; diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 66e2b19ef709..c3c4051a089d 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -596,7 +596,8 @@ static int sixpack_open(struct tty_struct *tty) if (tty->ops->write == NULL) return -EOPNOTSUPP; - dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup); + dev = alloc_netdev(sizeof(struct sixpack), "sp%d", NET_NAME_UNKNOWN, + sp_setup); if (!dev) { err = -ENOMEM; goto out; diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 484f77ec2ce1..a98c153f371e 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -1206,7 +1206,7 @@ static int __init init_baycomepp(void) struct net_device *dev; dev = alloc_netdev(sizeof(struct baycom_state), "bce%d", - baycom_epp_dev_setup); + NET_NAME_UNKNOWN, baycom_epp_dev_setup); if (!dev) { printk(KERN_WARNING "bce%d : out of memory\n", i); diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index d50b23cf9ea9..c2894e43840e 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -501,8 +501,8 @@ static int bpq_new_device(struct net_device *edev) struct net_device *ndev; struct bpqdev *bpq; - ndev = alloc_netdev(sizeof(struct bpqdev), "bpq%d", - bpq_setup); + ndev = alloc_netdev(sizeof(struct bpqdev), "bpq%d", NET_NAME_UNKNOWN, + bpq_setup); if (!ndev) return -ENOMEM; diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 6636022a1027..0fad408f24aa 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -466,7 +466,7 @@ static int __init setup_adapter(int card_base, int type, int n) if (!info) goto out; - info->dev[0] = alloc_netdev(0, "", dev_setup); + info->dev[0] = alloc_netdev(0, "", NET_NAME_UNKNOWN, dev_setup); if (!info->dev[0]) { printk(KERN_ERR "dmascc: " "could not allocate memory for %s at %#3x\n", @@ -474,7 +474,7 @@ static int __init setup_adapter(int card_base, int type, int n) goto out1; } - info->dev[1] = alloc_netdev(0, "", dev_setup); + info->dev[1] = alloc_netdev(0, "", NET_NAME_UNKNOWN, dev_setup); if (!info->dev[1]) { printk(KERN_ERR "dmascc: " "could not allocate memory for %s at %#3x\n", diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index 5d78c1d08abd..c67a27245072 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -699,7 +699,7 @@ struct net_device *hdlcdrv_register(const struct hdlcdrv_ops *ops, if (privsize < sizeof(struct hdlcdrv_state)) privsize = sizeof(struct hdlcdrv_state); - dev = alloc_netdev(privsize, ifname, hdlcdrv_setup); + dev = alloc_netdev(privsize, ifname, NET_NAME_UNKNOWN, hdlcdrv_setup); if (!dev) return ERR_PTR(-ENOMEM); diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 8a6c720a4cc9..f990bb1c3e02 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -734,7 +734,8 @@ static int mkiss_open(struct tty_struct *tty) if (tty->ops->write == NULL) return -EOPNOTSUPP; - dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup); + dev = alloc_netdev(sizeof(struct mkiss), "ax%d", NET_NAME_UNKNOWN, + ax_setup); if (!dev) { err = -ENOMEM; goto out; diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 4bc6ee8e7987..57be9e0e98a6 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1515,7 +1515,7 @@ static int scc_net_alloc(const char *name, struct scc_channel *scc) int err; struct net_device *dev; - dev = alloc_netdev(0, name, scc_net_setup); + dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, scc_net_setup); if (!dev) return -ENOMEM; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 81901659cc9e..717433cfb81d 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -1147,7 +1147,7 @@ static int __init yam_init_driver(void) sprintf(name, "yam%d", i); dev = alloc_netdev(sizeof(struct yam_port), name, - yam_setup); + NET_NAME_UNKNOWN, yam_setup); if (!dev) { pr_err("yam: cannot allocate net device\n"); err = -ENOMEM; diff --git a/drivers/net/ieee802154/fakehard.c b/drivers/net/ieee802154/fakehard.c index 78f18be3bbf2..9ce854f43917 100644 --- a/drivers/net/ieee802154/fakehard.c +++ b/drivers/net/ieee802154/fakehard.c @@ -343,7 +343,8 @@ static int ieee802154fake_probe(struct platform_device *pdev) if (!phy) return -ENOMEM; - dev = alloc_netdev(sizeof(struct fakehard_priv), "hardwpan%d", ieee802154_fake_setup); + dev = alloc_netdev(sizeof(struct fakehard_priv), "hardwpan%d", + NET_NAME_UNKNOWN, ieee802154_fake_setup); if (!dev) { wpan_phy_free(phy); return -ENOMEM; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 46a7790be004..d2d4a3d2237f 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -269,8 +269,8 @@ static int __init ifb_init_one(int index) struct ifb_private *dp; int err; - dev_ifb = alloc_netdev(sizeof(struct ifb_private), - "ifb%d", ifb_setup); + dev_ifb = alloc_netdev(sizeof(struct ifb_private), "ifb%d", + NET_NAME_UNKNOWN, ifb_setup); if (!dev_ifb) return -ENOMEM; diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index bb96409f8c05..8f2262540561 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -195,7 +195,7 @@ static __net_init int loopback_net_init(struct net *net) int err; err = -ENOMEM; - dev = alloc_netdev(0, "lo", loopback_setup); + dev = alloc_netdev(0, "lo", NET_NAME_UNKNOWN, loopback_setup); if (!dev) goto out; diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 91d6c1272fcf..5c002b1ef169 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -2665,7 +2665,8 @@ ppp_create_interface(struct net *net, int unit, int *retp) int ret = -ENOMEM; int i; - dev = alloc_netdev(sizeof(struct ppp), "", ppp_setup); + dev = alloc_netdev(sizeof(struct ppp), "", NET_NAME_UNKNOWN, + ppp_setup); if (!dev) goto out1; diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index 87526443841f..05387b1e2e95 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -749,7 +749,7 @@ static struct slip *sl_alloc(dev_t line) return NULL; sprintf(name, "sl%d", i); - dev = alloc_netdev(sizeof(*sl), name, sl_setup); + dev = alloc_netdev(sizeof(*sl), name, NET_NAME_UNKNOWN, sl_setup); if (!dev) return NULL; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 98bad1fb1bfb..acaaf6784179 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1633,7 +1633,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) name = ifr->ifr_name; dev = alloc_netdev_mqs(sizeof(struct tun_struct), name, - tun_setup, queues, queues); + NET_NAME_UNKNOWN, tun_setup, queues, + queues); if (!dev) return -ENOMEM; diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 6358d420e185..2ec1500d0077 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -387,7 +387,7 @@ static int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *i return -EINVAL; dev = alloc_netdev(sizeof(*pnd) + sizeof(pnd->urbs[0]) * rxq_size, - ifname, usbpn_setup); + ifname, NET_NAME_UNKNOWN, usbpn_setup); if (!dev) return -ENOMEM; diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index a3a05869309d..50b36b299946 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2520,7 +2520,8 @@ static struct hso_device *hso_create_net_device(struct usb_interface *interface, /* allocate our network device, then we can put in our private data */ /* call hso_net_init to do the basic initialization */ - net = alloc_netdev(sizeof(struct hso_net), "hso%d", hso_net_init); + net = alloc_netdev(sizeof(struct hso_net), "hso%d", NET_NAME_UNKNOWN, + hso_net_init); if (!net) { dev_err(&interface->dev, "Unable to create ethernet device\n"); goto exit; diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 19f7cb2cdef3..a463613a0719 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -327,8 +327,8 @@ static int dlci_add(struct dlci_add *dlci) goto err1; /* create device name */ - master = alloc_netdev( sizeof(struct dlci_local), "dlci%d", - dlci_setup); + master = alloc_netdev(sizeof(struct dlci_local), "dlci%d", + NET_NAME_UNKNOWN, dlci_setup); if (!master) { err = -ENOMEM; goto err1; diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index 9c33ca918e19..51f6cee8aab2 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -256,7 +256,8 @@ static void hdlc_setup(struct net_device *dev) struct net_device *alloc_hdlcdev(void *priv) { struct net_device *dev; - dev = alloc_netdev(sizeof(struct hdlc_device), "hdlc%d", hdlc_setup); + dev = alloc_netdev(sizeof(struct hdlc_device), "hdlc%d", + NET_NAME_UNKNOWN, hdlc_setup); if (dev) dev_to_hdlc(dev)->priv = priv; return dev; diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 7c6cb4f31798..7cc64eac0fa3 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -1075,10 +1075,11 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) used = pvc_is_used(pvc); if (type == ARPHRD_ETHER) { - dev = alloc_netdev(0, "pvceth%d", ether_setup); + dev = alloc_netdev(0, "pvceth%d", NET_NAME_UNKNOWN, + ether_setup); dev->priv_flags &= ~IFF_TX_SKB_SHARING; } else - dev = alloc_netdev(0, "pvc%d", pvc_setup); + dev = alloc_netdev(0, "pvc%d", NET_NAME_UNKNOWN, pvc_setup); if (!dev) { netdev_warn(frad, "Memory squeeze on fr_pvc()\n"); diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index a33a46fa88dd..2f5eda8a7227 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -325,8 +325,8 @@ static int lapbeth_new_device(struct net_device *dev) ASSERT_RTNL(); - ndev = alloc_netdev(sizeof(*lapbeth), "lapb%d", - lapbeth_setup); + ndev = alloc_netdev(sizeof(*lapbeth), "lapb%d", NET_NAME_UNKNOWN, + lapbeth_setup); if (!ndev) goto out; diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 1b89ecf0959e..758c4ba1e97c 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -227,7 +227,8 @@ int __init sbni_probe(int unit) struct net_device *dev; int err; - dev = alloc_netdev(sizeof(struct net_local), "sbni", sbni_devsetup); + dev = alloc_netdev(sizeof(struct net_local), "sbni", + NET_NAME_UNKNOWN, sbni_devsetup); if (!dev) return -ENOMEM; @@ -1477,8 +1478,8 @@ int __init init_module( void ) int err; while( num < SBNI_MAX_NUM_CARDS ) { - dev = alloc_netdev(sizeof(struct net_local), - "sbni%d", sbni_devsetup); + dev = alloc_netdev(sizeof(struct net_local), "sbni%d", + NET_NAME_UNKNOWN, sbni_devsetup); if( !dev) break; diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index cdd45fb8a1f6..421ac5f85699 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -1631,7 +1631,8 @@ static int __init init_sdla(void) printk("%s.\n", version); - sdla = alloc_netdev(sizeof(struct frad_local), "sdla0", setup_sdla); + sdla = alloc_netdev(sizeof(struct frad_local), "sdla0", + NET_NAME_UNKNOWN, setup_sdla); if (!sdla) return -ENOMEM; diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 5895f1978691..df6c07357556 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -81,8 +81,8 @@ static struct x25_asy *x25_asy_alloc(void) char name[IFNAMSIZ]; sprintf(name, "x25asy%d", i); - dev = alloc_netdev(sizeof(struct x25_asy), - name, x25_asy_setup); + dev = alloc_netdev(sizeof(struct x25_asy), name, + NET_NAME_UNKNOWN, x25_asy_setup); if (!dev) return NULL; diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index cd15a93d9084..e7f5910a6519 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -472,7 +472,7 @@ int i2400mu_probe(struct usb_interface *iface, /* Allocate instance [calls i2400m_netdev_setup() on it]. */ result = -ENOMEM; - net_dev = alloc_netdev(sizeof(*i2400mu), "wmx%d", + net_dev = alloc_netdev(sizeof(*i2400mu), "wmx%d", NET_NAME_UNKNOWN, i2400mu_netdev_setup); if (net_dev == NULL) { dev_err(dev, "no memory for network device instance\n"); diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 64747d457bb3..29d88739454b 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2685,7 +2685,8 @@ static struct net_device *init_wifidev(struct airo_info *ai, struct net_device *ethdev) { int err; - struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup); + struct net_device *dev = alloc_netdev(0, "wifi%d", NET_NAME_UNKNOWN, + wifi_setup); if (!dev) return NULL; dev->ml_priv = ethdev->ml_priv; @@ -2785,7 +2786,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, CapabilityRid cap_rid; /* Create the network device object. */ - dev = alloc_netdev(sizeof(*ai), "", ether_setup); + dev = alloc_netdev(sizeof(*ai), "", NET_NAME_UNKNOWN, ether_setup); if (!dev) { airo_print_err("", "Couldn't alloc_etherdev"); return NULL; diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 0e26f4a34fda..1c4ce8e3eebe 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3636,7 +3636,7 @@ struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, struct net_device *ndev; struct ath6kl_vif *vif; - ndev = alloc_netdev(sizeof(*vif), name, ether_setup); + ndev = alloc_netdev(sizeof(*vif), name, NET_NAME_UNKNOWN, ether_setup); if (!ndev) return NULL; diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 106b6dcb773a..7afce6e8c507 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -132,7 +132,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); - ndev = alloc_netdev(0, "wlan%d", ether_setup); + ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, ether_setup); if (!ndev) { dev_err(dev, "alloc_netdev_mqs failed\n"); rc = -ENOMEM; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 09dd8c13d844..2699441d4f41 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -808,7 +808,8 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, } else { brcmf_dbg(INFO, "allocate netdev interface\n"); /* Allocate netdev, including space for private structure */ - ndev = alloc_netdev(sizeof(*ifp), name, ether_setup); + ndev = alloc_netdev(sizeof(*ifp), name, NET_NAME_UNKNOWN, + ether_setup); if (!ndev) return ERR_PTR(-ENOMEM); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 0c02f0483d1f..569b64ecc607 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -981,7 +981,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) goto err_wdev; } - dev = alloc_netdev(0, "wlan%d", ether_setup); + dev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, ether_setup); if (!dev) { dev_err(dmdev, "no memory for network device instance\n"); goto err_adapter; diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 6fef746345bc..01a67f62696f 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -1000,7 +1000,7 @@ static int lbs_add_mesh(struct lbs_private *priv) goto done; } - mesh_dev = alloc_netdev(0, "msh%d", ether_setup); + mesh_dev = alloc_netdev(0, "msh%d", NET_NAME_UNKNOWN, ether_setup); if (!mesh_dev) { lbs_deb_mesh("init mshX device failed\n"); ret = -ENOMEM; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index eba51460a5de..5ea65fce0b83 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2676,7 +2676,8 @@ static int __init init_mac80211_hwsim(void) goto out_free_radios; } - hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup); + hwsim_mon = alloc_netdev(0, "hwsim%d", NET_NAME_UNKNOWN, + hwsim_mon_setup); if (hwsim_mon == NULL) { err = -ENOMEM; goto out_free_radios; diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 6af135fa99f7..ca87f923c61e 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2232,7 +2232,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, } dev = alloc_netdev_mqs(sizeof(struct mwifiex_private *), name, - ether_setup, IEEE80211_NUM_ACS, 1); + NET_NAME_UNKNOWN, ether_setup, + IEEE80211_NUM_ACS, 1); if (!dev) { wiphy_err(wiphy, "no memory available for netdevice\n"); priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index ef75b45e5085..bd59d9dbf27b 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -418,8 +418,8 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, * When the guest selects the desired number, it will be updated * via netif_set_real_num_*_queues(). */ - dev = alloc_netdev_mq(sizeof(struct xenvif), name, ether_setup, - xenvif_max_queues); + dev = alloc_netdev_mq(sizeof(struct xenvif), name, NET_NAME_UNKNOWN, + ether_setup, xenvif_max_queues); if (dev == NULL) { pr_warn("Could not allocate netdev for %s\n", name); return ERR_PTR(-ENOMEM); diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index d837c3c5330f..fbc6701bef30 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -2915,7 +2915,7 @@ claw_new_device(struct ccwgroup_device *cgdev) "failed with error code %d\n", ret); goto out; } - dev = alloc_netdev(0,"claw%d",claw_init_netdevice); + dev = alloc_netdev(0, "claw%d", NET_NAME_UNKNOWN, claw_init_netdevice); if (!dev) { dev_warn(&cgdev->dev, "Activating the CLAW device failed\n"); diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 03b6ad035577..e056dd4fe44d 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -1137,9 +1137,11 @@ static struct net_device *ctcm_init_netdevice(struct ctcm_priv *priv) return NULL; if (IS_MPC(priv)) - dev = alloc_netdev(0, MPC_DEVICE_GENE, ctcm_dev_setup); + dev = alloc_netdev(0, MPC_DEVICE_GENE, NET_NAME_UNKNOWN, + ctcm_dev_setup); else - dev = alloc_netdev(0, CTC_DEVICE_GENE, ctcm_dev_setup); + dev = alloc_netdev(0, CTC_DEVICE_GENE, NET_NAME_UNKNOWN, + ctcm_dev_setup); if (!dev) { CTCM_DBF_TEXT_(ERROR, CTC_DBF_CRIT, diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index ce16d1bdb20a..0a87809c8af7 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -2015,7 +2015,7 @@ static struct net_device *netiucv_init_netdevice(char *username, char *userdata) struct net_device *dev; dev = alloc_netdev(sizeof(struct netiucv_priv), "iucv%d", - netiucv_setup_netdevice); + NET_NAME_UNKNOWN, netiucv_setup_netdevice); if (!dev) return NULL; rtnl_lock(); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 5ef5b4f45758..c2679bfe7f66 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -952,10 +952,12 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) { switch (card->info.type) { case QETH_CARD_TYPE_IQD: - card->dev = alloc_netdev(0, "hsi%d", ether_setup); + card->dev = alloc_netdev(0, "hsi%d", NET_NAME_UNKNOWN, + ether_setup); break; case QETH_CARD_TYPE_OSN: - card->dev = alloc_netdev(0, "osn%d", ether_setup); + card->dev = alloc_netdev(0, "osn%d", NET_NAME_UNKNOWN, + ether_setup); card->dev->flags |= IFF_NOARP; break; default: diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 14e0b5810e8c..f8427a2c4840 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3287,7 +3287,8 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) } } } else if (card->info.type == QETH_CARD_TYPE_IQD) { - card->dev = alloc_netdev(0, "hsi%d", ether_setup); + card->dev = alloc_netdev(0, "hsi%d", NET_NAME_UNKNOWN, + ether_setup); if (!card->dev) return -ENODEV; card->dev->flags |= IFF_NOARP; diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c index 09f3d5ca75ac..85d776bbfb15 100644 --- a/drivers/staging/cxt1e1/linux.c +++ b/drivers/staging/cxt1e1/linux.c @@ -917,7 +917,8 @@ c4_add_dev(hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, struct net_device *ndev; ci_t *ci; - ndev = alloc_netdev(sizeof(ci_t), SBE_IFACETMPL, c4_setup); + ndev = alloc_netdev(sizeof(ci_t), SBE_IFACETMPL, NET_NAME_UNKNOWN, + c4_setup); if (!ndev) { pr_warning("%s: no memory for struct net_device !\n", hi->devname); diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c index 64c55b99fda4..c2268527422f 100644 --- a/drivers/staging/gdm724x/gdm_lte.c +++ b/drivers/staging/gdm724x/gdm_lte.c @@ -885,7 +885,7 @@ int register_lte_device(struct phy_dev *phy_dev, /* Allocate netdev */ net = alloc_netdev(sizeof(struct nic), pdn_dev_name, - ether_setup); + NET_NAME_UNKNOWN, ether_setup); if (net == NULL) { pr_err("alloc_netdev failed\n"); ret = -ENOMEM; diff --git a/drivers/staging/gdm72xx/gdm_wimax.c b/drivers/staging/gdm72xx/gdm_wimax.c index e5e511585122..a9a6fc51024b 100644 --- a/drivers/staging/gdm72xx/gdm_wimax.c +++ b/drivers/staging/gdm72xx/gdm_wimax.c @@ -886,7 +886,8 @@ int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev) struct net_device *dev; int ret; - dev = alloc_netdev(sizeof(*nic), "wm%d", ether_setup); + dev = alloc_netdev(sizeof(*nic), "wm%d", NET_NAME_UNKNOWN, + ether_setup); if (dev == NULL) { pr_err("alloc_etherdev failed\n"); diff --git a/drivers/staging/vt6655/wpactl.c b/drivers/staging/vt6655/wpactl.c index 8392d4d1d5ed..0814bfd68b2e 100644 --- a/drivers/staging/vt6655/wpactl.c +++ b/drivers/staging/vt6655/wpactl.c @@ -89,7 +89,8 @@ static int wpa_init_wpadev(PSDevice pDevice) struct net_device *dev = pDevice->dev; int ret = 0; - pDevice->wpadev = alloc_netdev(sizeof(PSDevice), "vntwpa", wpadev_setup); + pDevice->wpadev = alloc_netdev(sizeof(PSDevice), "vntwpa", + NET_NAME_UNKNOWN, wpadev_setup); if (pDevice->wpadev == NULL) return -ENOMEM; diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index 00b186c59725..6c78f917e24a 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -769,7 +769,7 @@ int wlan_setup(wlandevice_t *wlandev, struct device *physdev) /* Allocate and initialize the struct device */ netdev = alloc_netdev(sizeof(struct wireless_dev), "wlan%d", - ether_setup); + NET_NAME_UNKNOWN, ether_setup); if (netdev == NULL) { dev_err(physdev, "Failed to alloc netdev.\n"); wlan_free_wiphy(wiphy); diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 2ebe47b78a3e..cde3ab97900f 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2789,9 +2789,8 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) netname = "gsm%d"; if (nc->if_name[0] != '\0') netname = nc->if_name; - net = alloc_netdev(sizeof(struct gsm_mux_net), - netname, - gsm_mux_net_init); + net = alloc_netdev(sizeof(struct gsm_mux_net), netname, + NET_NAME_UNKNOWN, gsm_mux_net_init); if (!net) { pr_err("alloc_netdev failed"); return -ENOMEM; diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index f2b781773eed..b9cfc1571d71 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -721,7 +721,8 @@ struct net_device *gphonet_setup_default(void) struct phonet_port *port; /* Create net device */ - dev = alloc_netdev(sizeof(*port), "upnlink%d", pn_net_setup); + dev = alloc_netdev(sizeof(*port), "upnlink%d", NET_NAME_UNKNOWN, + pn_net_setup); if (!dev) return ERR_PTR(-ENOMEM); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9be34732142f..15ed750458ad 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2991,13 +2991,15 @@ void ether_setup(struct net_device *dev); /* Support for loadable net-drivers */ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, + unsigned char name_assign_type, void (*setup)(struct net_device *), unsigned int txqs, unsigned int rxqs); -#define alloc_netdev(sizeof_priv, name, setup) \ - alloc_netdev_mqs(sizeof_priv, name, setup, 1, 1) +#define alloc_netdev(sizeof_priv, name, name_assign_type, setup) \ + alloc_netdev_mqs(sizeof_priv, name, name_assign_type, setup, 1, 1) -#define alloc_netdev_mq(sizeof_priv, name, setup, count) \ - alloc_netdev_mqs(sizeof_priv, name, setup, count, count) +#define alloc_netdev_mq(sizeof_priv, name, name_assign_type, setup, count) \ + alloc_netdev_mqs(sizeof_priv, name, name_assign_type, setup, count, \ + count) int register_netdev(struct net_device *dev); void unregister_netdev(struct net_device *dev); diff --git a/net/802/fc.c b/net/802/fc.c index 05eea6b98bb8..7c174b6750cd 100644 --- a/net/802/fc.c +++ b/net/802/fc.c @@ -126,6 +126,6 @@ static void fc_setup(struct net_device *dev) */ struct net_device *alloc_fcdev(int sizeof_priv) { - return alloc_netdev(sizeof_priv, "fc%d", fc_setup); + return alloc_netdev(sizeof_priv, "fc%d", NET_NAME_UNKNOWN, fc_setup); } EXPORT_SYMBOL(alloc_fcdev); diff --git a/net/802/fddi.c b/net/802/fddi.c index 9cda40661e0d..59e7346f1193 100644 --- a/net/802/fddi.c +++ b/net/802/fddi.c @@ -207,7 +207,8 @@ static void fddi_setup(struct net_device *dev) */ struct net_device *alloc_fddidev(int sizeof_priv) { - return alloc_netdev(sizeof_priv, "fddi%d", fddi_setup); + return alloc_netdev(sizeof_priv, "fddi%d", NET_NAME_UNKNOWN, + fddi_setup); } EXPORT_SYMBOL(alloc_fddidev); diff --git a/net/802/hippi.c b/net/802/hippi.c index 5ff2a718ddca..2e03f8259dd5 100644 --- a/net/802/hippi.c +++ b/net/802/hippi.c @@ -228,7 +228,8 @@ static void hippi_setup(struct net_device *dev) struct net_device *alloc_hippi_dev(int sizeof_priv) { - return alloc_netdev(sizeof_priv, "hip%d", hippi_setup); + return alloc_netdev(sizeof_priv, "hip%d", NET_NAME_UNKNOWN, + hippi_setup); } EXPORT_SYMBOL(alloc_hippi_dev); diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 44ebd5c2cd4a..cba9c212a730 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -250,7 +250,8 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) snprintf(name, IFNAMSIZ, "vlan%.4i", vlan_id); } - new_dev = alloc_netdev(sizeof(struct vlan_dev_priv), name, vlan_setup); + new_dev = alloc_netdev(sizeof(struct vlan_dev_priv), name, + NET_NAME_UNKNOWN, vlan_setup); if (new_dev == NULL) return -ENOBUFS; diff --git a/net/appletalk/dev.c b/net/appletalk/dev.c index 6c8016f61866..e4158b8b926d 100644 --- a/net/appletalk/dev.c +++ b/net/appletalk/dev.c @@ -39,6 +39,7 @@ static void ltalk_setup(struct net_device *dev) struct net_device *alloc_ltalkdev(int sizeof_priv) { - return alloc_netdev(sizeof_priv, "lt%d", ltalk_setup); + return alloc_netdev(sizeof_priv, "lt%d", NET_NAME_UNKNOWN, + ltalk_setup); } EXPORT_SYMBOL(alloc_ltalkdev); diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 403e71fa88fe..cc78538d163b 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -682,8 +682,8 @@ static int br2684_create(void __user *arg) netdev = alloc_netdev(sizeof(struct br2684_dev), ni.ifname[0] ? ni.ifname : "nas%d", - (payload == p_routed) ? - br2684_setup_routed : br2684_setup); + NET_NAME_UNKNOWN, + (payload == p_routed) ? br2684_setup_routed : br2684_setup); if (!netdev) return -ENOMEM; diff --git a/net/atm/clip.c b/net/atm/clip.c index ba291ce4bdff..46339040fef0 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -520,7 +520,8 @@ static int clip_create(int number) if (PRIV(dev)->number >= number) number = PRIV(dev)->number + 1; } - dev = alloc_netdev(sizeof(struct clip_priv), "", clip_setup); + dev = alloc_netdev(sizeof(struct clip_priv), "", NET_NAME_UNKNOWN, + clip_setup); if (!dev) return -ENOMEM; clip_priv = PRIV(dev); diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index e7ee65dc20bf..d551e6302cf3 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -895,7 +895,7 @@ struct net_device *batadv_softif_create(const char *name) int ret; soft_iface = alloc_netdev(sizeof(struct batadv_priv), name, - batadv_softif_init_early); + NET_NAME_UNKNOWN, batadv_softif_init_early); if (!soft_iface) return NULL; diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 5a7f81df603c..206b65ccd5b8 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -712,7 +712,7 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev) unsigned long flags; netdev = alloc_netdev(sizeof(struct lowpan_dev), IFACE_NAME_TEMPLATE, - netdev_setup); + NET_NAME_UNKNOWN, netdev_setup); if (!netdev) return -ENOMEM; diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index a841d3e776c5..85bcc21e84d2 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -538,8 +538,9 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) /* session struct allocated as private part of net_device */ dev = alloc_netdev(sizeof(struct bnep_session), - (*req->device) ? req->device : "bnep%d", - bnep_net_setup); + (*req->device) ? req->device : "bnep%d", + NET_NAME_UNKNOWN, + bnep_net_setup); if (!dev) return -ENOMEM; diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 3eca3fdf8fe1..078d336a1f37 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -344,7 +344,7 @@ int br_add_bridge(struct net *net, const char *name) struct net_device *dev; int res; - dev = alloc_netdev(sizeof(struct net_bridge), name, + dev = alloc_netdev(sizeof(struct net_bridge), name, NET_NAME_UNKNOWN, br_dev_setup); if (!dev) diff --git a/net/core/dev.c b/net/core/dev.c index 38793fb84a35..2c98f10ee62a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6441,17 +6441,19 @@ void netdev_freemem(struct net_device *dev) /** * alloc_netdev_mqs - allocate network device - * @sizeof_priv: size of private data to allocate space for - * @name: device name format string - * @setup: callback to initialize device - * @txqs: the number of TX subqueues to allocate - * @rxqs: the number of RX subqueues to allocate + * @sizeof_priv: size of private data to allocate space for + * @name: device name format string + * @name_assign_type: origin of device name + * @setup: callback to initialize device + * @txqs: the number of TX subqueues to allocate + * @rxqs: the number of RX subqueues to allocate * * Allocates a struct net_device with private data area for driver use * and performs basic initialization. Also allocates subqueue structs * for each queue on the device. */ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, + unsigned char name_assign_type, void (*setup)(struct net_device *), unsigned int txqs, unsigned int rxqs) { @@ -6530,6 +6532,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, #endif strcpy(dev->name, name); + dev->name_assign_type = name_assign_type; dev->group = INIT_NETDEV_GROUP; if (!dev->ethtool_ops) dev->ethtool_ops = &default_ethtool_ops; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 1f8a59e02c48..599864322de8 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1828,8 +1828,8 @@ struct net_device *rtnl_create_link(struct net *net, num_rx_queues = ops->get_num_rx_queues(); err = -ENOMEM; - dev = alloc_netdev_mqs(ops->priv_size, ifname, ops->setup, - num_tx_queues, num_rx_queues); + dev = alloc_netdev_mqs(ops->priv_size, ifname, NET_NAME_UNKNOWN, + ops->setup, num_tx_queues, num_rx_queues); if (!dev) goto err; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 64c5af0a10dd..45a1e34c89e0 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -340,8 +340,8 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent, struct dsa_slave_priv *p; int ret; - slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), - name, ether_setup); + slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), name, + NET_NAME_UNKNOWN, ether_setup); if (slave_dev == NULL) return slave_dev; diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 5dc638cad2e1..f405e0592407 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -390,7 +390,8 @@ EXPORT_SYMBOL(ether_setup); struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs, unsigned int rxqs) { - return alloc_netdev_mqs(sizeof_priv, "eth%d", ether_setup, txqs, rxqs); + return alloc_netdev_mqs(sizeof_priv, "eth%d", NET_NAME_UNKNOWN, + ether_setup, txqs, rxqs); } EXPORT_SYMBOL(alloc_etherdev_mqs); diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 54b6731dab55..0157a7af20a8 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -301,7 +301,7 @@ static struct net_device *__ip_tunnel_create(struct net *net, } ASSERT_RTNL(); - dev = alloc_netdev(ops->priv_size, name, ops->setup); + dev = alloc_netdev(ops->priv_size, name, NET_NAME_UNKNOWN, ops->setup); if (!dev) { err = -ENOMEM; goto failed; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 65bcaa789043..c8034587859d 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -500,7 +500,7 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt) else sprintf(name, "pimreg%u", mrt->id); - dev = alloc_netdev(0, name, reg_vif_setup); + dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup); if (dev == NULL) return NULL; diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 365b2b6f3942..5f19dfbc4c6a 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -322,7 +322,8 @@ static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net, else strcpy(name, "ip6gre%d"); - dev = alloc_netdev(sizeof(*t), name, ip6gre_tunnel_setup); + dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, + ip6gre_tunnel_setup); if (!dev) return NULL; @@ -1326,7 +1327,8 @@ static int __net_init ip6gre_init_net(struct net *net) int err; ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6gre0", - ip6gre_tunnel_setup); + NET_NAME_UNKNOWN, + ip6gre_tunnel_setup); if (!ign->fb_tunnel_dev) { err = -ENOMEM; goto err_alloc_dev; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 51a1eb185ea7..f9de5a695072 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -315,7 +315,8 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p) else sprintf(name, "ip6tnl%%d"); - dev = alloc_netdev(sizeof (*t), name, ip6_tnl_dev_setup); + dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, + ip6_tnl_dev_setup); if (dev == NULL) goto failed; @@ -1773,7 +1774,7 @@ static int __net_init ip6_tnl_init_net(struct net *net) err = -ENOMEM; ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0", - ip6_tnl_dev_setup); + NET_NAME_UNKNOWN, ip6_tnl_dev_setup); if (!ip6n->fb_tnl_dev) goto err_alloc_dev; diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 9aaa6bb229e4..17ee4fc32dfe 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -204,7 +204,7 @@ static struct ip6_tnl *vti6_tnl_create(struct net *net, struct __ip6_tnl_parm *p else sprintf(name, "ip6_vti%%d"); - dev = alloc_netdev(sizeof(*t), name, vti6_dev_setup); + dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, vti6_dev_setup); if (dev == NULL) goto failed; @@ -1020,7 +1020,7 @@ static int __net_init vti6_init_net(struct net *net) err = -ENOMEM; ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6_vti0", - vti6_dev_setup); + NET_NAME_UNKNOWN, vti6_dev_setup); if (!ip6n->fb_tnl_dev) goto err_alloc_dev; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 8250474ab7dc..f9a3fd320d1d 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -744,7 +744,7 @@ static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt) else sprintf(name, "pim6reg%u", mrt->id); - dev = alloc_netdev(0, name, reg_vif_setup); + dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup); if (dev == NULL) return NULL; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 4f408176dc64..2e9ba035fb5f 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -250,7 +250,8 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, else strcpy(name, "sit%d"); - dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup); + dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, + ipip6_tunnel_setup); if (dev == NULL) return NULL; @@ -1729,6 +1730,7 @@ static int __net_init sit_init_net(struct net *net) sitn->tunnels[3] = sitn->tunnels_r_l; sitn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0", + NET_NAME_UNKNOWN, ipip6_tunnel_setup); if (!sitn->fb_tunnel_dev) { err = -ENOMEM; diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c index 365b895da84b..9e0d909390fd 100644 --- a/net/irda/irda_device.c +++ b/net/irda/irda_device.c @@ -293,7 +293,8 @@ static void irda_device_setup(struct net_device *dev) */ struct net_device *alloc_irdadev(int sizeof_priv) { - return alloc_netdev(sizeof_priv, "irda%d", irda_device_setup); + return alloc_netdev(sizeof_priv, "irda%d", NET_NAME_UNKNOWN, + irda_device_setup); } EXPORT_SYMBOL(alloc_irdadev); diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index ffcec225b5d9..dc13f1a45f2f 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -96,7 +96,7 @@ static void irlan_eth_setup(struct net_device *dev) */ struct net_device *alloc_irlandev(const char *name) { - return alloc_netdev(sizeof(struct irlan_cb), name, + return alloc_netdev(sizeof(struct irlan_cb), name, NET_NAME_UNKNOWN, irlan_eth_setup); } diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index 76125c57ee6d..edb78e69efe4 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c @@ -246,7 +246,8 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p goto out; } - dev = alloc_netdev(sizeof(*priv), name, l2tp_eth_dev_setup); + dev = alloc_netdev(sizeof(*priv), name, NET_NAME_UNKNOWN, + l2tp_eth_dev_setup); if (!dev) { rc = -ENOMEM; goto out_del_session; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bbf51b2f0651..4edfc7c1524f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1624,9 +1624,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, if (local->hw.queues >= IEEE80211_NUM_ACS) txqs = IEEE80211_NUM_ACS; - ndev = alloc_netdev_mqs(sizeof(*sdata) + - local->hw.vif_data_size, - name, ieee80211_if_setup, txqs, 1); + ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size, + name, NET_NAME_UNKNOWN, + ieee80211_if_setup, txqs, 1); if (!ndev) return -ENOMEM; dev_net_set(ndev, wiphy_net(local->hw.wiphy)); diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c index 9b54370f5e87..b36b2b996578 100644 --- a/net/mac802154/ieee802154_dev.c +++ b/net/mac802154/ieee802154_dev.c @@ -167,11 +167,13 @@ mac802154_add_iface(struct wpan_phy *phy, const char *name, int type) switch (type) { case IEEE802154_DEV_MONITOR: dev = alloc_netdev(sizeof(struct mac802154_sub_if_data), - name, mac802154_monitor_setup); + name, NET_NAME_UNKNOWN, + mac802154_monitor_setup); break; case IEEE802154_DEV_WPAN: dev = alloc_netdev(sizeof(struct mac802154_sub_if_data), - name, mac802154_wpan_setup); + name, NET_NAME_UNKNOWN, + mac802154_wpan_setup); break; default: dev = NULL; diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index ede50d197e10..71cf1bffea06 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -1418,7 +1418,7 @@ static int __init nr_proto_init(void) struct net_device *dev; sprintf(name, "nr%d", i); - dev = alloc_netdev(0, name, nr_setup); + dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, nr_setup); if (!dev) { printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n"); goto fail; diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index 295471a66c78..bd658555afdf 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -165,7 +165,8 @@ static struct vport *internal_dev_create(const struct vport_parms *parms) netdev_vport = netdev_vport_priv(vport); netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev), - parms->name, do_setup); + parms->name, NET_NAME_UNKNOWN, + do_setup); if (!netdev_vport->dev) { err = -ENOMEM; goto error_free_vport; diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c index 66dc65e7c6a1..e9a83a637185 100644 --- a/net/phonet/pep-gprs.c +++ b/net/phonet/pep-gprs.c @@ -267,7 +267,7 @@ int gprs_attach(struct sock *sk) return -EINVAL; /* need packet boundaries */ /* Create net device */ - dev = alloc_netdev(sizeof(*gp), ifname, gprs_setup); + dev = alloc_netdev(sizeof(*gp), ifname, NET_NAME_UNKNOWN, gprs_setup); if (!dev) return -ENOMEM; gp = netdev_priv(dev); diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 8451c8cdc9de..a85c1a086ae4 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1538,7 +1538,7 @@ static int __init rose_proto_init(void) char name[IFNAMSIZ]; sprintf(name, "rose%d", i); - dev = alloc_netdev(0, name, rose_setup); + dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, rose_setup); if (!dev) { printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate memory\n"); rc = -ENOMEM; diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 474167162947..bd33793b527e 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -485,8 +485,8 @@ static int __init teql_init(void) struct net_device *dev; struct teql_master *master; - dev = alloc_netdev(sizeof(struct teql_master), - "teql%d", teql_master_setup); + dev = alloc_netdev(sizeof(struct teql_master), "teql%d", + NET_NAME_UNKNOWN, teql_master_setup); if (!dev) { err = -ENOMEM; break; -- cgit v1.2.3 From 5517750f058edd111bcabe5e116056cc63b1f39c Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 14 Jul 2014 16:37:25 +0200 Subject: net: rtnetlink - make create_link take name_assign_type This passes down NET_NAME_USER (or NET_NAME_ENUM) to alloc_netdev(), for any device created over rtnetlink. v9: restore reverse-christmas-tree order of local variables Signed-off-by: Tom Gundersen Signed-off-by: David S. Miller --- drivers/net/veth.c | 11 ++++++++--- include/net/rtnetlink.h | 1 + net/core/rtnetlink.c | 12 ++++++++---- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 9b945e60530e..8ad596573d17 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -335,6 +335,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, struct veth_priv *priv; char ifname[IFNAMSIZ]; struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; + unsigned char name_assign_type; struct ifinfomsg *ifmp; struct net *net; @@ -362,16 +363,20 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, tbp = tb; } - if (tbp[IFLA_IFNAME]) + if (tbp[IFLA_IFNAME]) { nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ); - else + name_assign_type = NET_NAME_USER; + } else { snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); + name_assign_type = NET_NAME_ENUM; + } net = rtnl_link_get_net(src_net, tbp); if (IS_ERR(net)) return PTR_ERR(net); - peer = rtnl_create_link(net, ifname, &veth_link_ops, tbp); + peer = rtnl_create_link(net, ifname, name_assign_type, + &veth_link_ops, tbp); if (IS_ERR(peer)) { put_net(net); return PTR_ERR(peer); diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 72240e5ac2c4..e21b9f9653c0 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -136,6 +136,7 @@ void rtnl_af_unregister(struct rtnl_af_ops *ops); struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]); struct net_device *rtnl_create_link(struct net *net, char *ifname, + unsigned char name_assign_type, const struct rtnl_link_ops *ops, struct nlattr *tb[]); int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 599864322de8..e9918020dbc9 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1810,7 +1810,8 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) EXPORT_SYMBOL(rtnl_configure_link); struct net_device *rtnl_create_link(struct net *net, - char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[]) + char *ifname, unsigned char name_assign_type, + const struct rtnl_link_ops *ops, struct nlattr *tb[]) { int err; struct net_device *dev; @@ -1828,7 +1829,7 @@ struct net_device *rtnl_create_link(struct net *net, num_rx_queues = ops->get_num_rx_queues(); err = -ENOMEM; - dev = alloc_netdev_mqs(ops->priv_size, ifname, NET_NAME_UNKNOWN, + dev = alloc_netdev_mqs(ops->priv_size, ifname, name_assign_type, ops->setup, num_tx_queues, num_rx_queues); if (!dev) goto err; @@ -1894,6 +1895,7 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh) char ifname[IFNAMSIZ]; struct nlattr *tb[IFLA_MAX+1]; struct nlattr *linkinfo[IFLA_INFO_MAX+1]; + unsigned char name_assign_type = NET_NAME_USER; int err; #ifdef CONFIG_MODULES @@ -2046,14 +2048,16 @@ replay: if (!ops->setup) return -EOPNOTSUPP; - if (!ifname[0]) + if (!ifname[0]) { snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); + name_assign_type = NET_NAME_ENUM; + } dest_net = rtnl_link_get_net(net, tb); if (IS_ERR(dest_net)) return PTR_ERR(dest_net); - dev = rtnl_create_link(dest_net, ifname, ops, tb); + dev = rtnl_create_link(dest_net, ifname, name_assign_type, ops, tb); if (IS_ERR(dev)) { err = PTR_ERR(dev); goto out; -- cgit v1.2.3 From 5ee2c941b5969eb1b5592f9731b3ee76a784641f Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Mon, 14 Jul 2014 16:58:32 +0200 Subject: tcp: Remove unnecessary arg from tcp_enter_cwr and tcp_init_cwnd_reduction Since Yuchung's 9b44190dc11 (tcp: refactor F-RTO), tcp_enter_cwr is always called with set_ssthresh = 1. Thus, we can remove this argument from tcp_enter_cwr. Further, as we remove this one, tcp_init_cwnd_reduction is then always called with set_ssthresh = true, and so we can get rid of this argument as well. Cc: Yuchung Cheng Signed-off-by: Christoph Paasch Acked-by: Yuchung Cheng Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- net/ipv4/tcp_input.c | 15 +++++++-------- net/ipv4/tcp_output.c | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index c9a75dbba0c7..0aeb2eb749dc 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -928,7 +928,7 @@ static inline __u32 tcp_current_ssthresh(const struct sock *sk) /* Use define here intentionally to get WARN_ON location shown at the caller */ #define tcp_verify_left_out(tp) WARN_ON(tcp_left_out(tp) > tp->packets_out) -void tcp_enter_cwr(struct sock *sk, const int set_ssthresh); +void tcp_enter_cwr(struct sock *sk); __u32 tcp_init_cwnd(const struct tcp_sock *tp, const struct dst_entry *dst); /* The maximum number of MSS of available cwnd for which TSO defers diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index bb684967f7a7..2e16afba182c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2475,7 +2475,7 @@ static bool tcp_try_undo_loss(struct sock *sk, bool frto_undo) * losses and/or application stalls), do not perform any further cwnd * reductions, but instead slow start up to ssthresh. */ -static void tcp_init_cwnd_reduction(struct sock *sk, const bool set_ssthresh) +static void tcp_init_cwnd_reduction(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); @@ -2485,8 +2485,7 @@ static void tcp_init_cwnd_reduction(struct sock *sk, const bool set_ssthresh) tp->prior_cwnd = tp->snd_cwnd; tp->prr_delivered = 0; tp->prr_out = 0; - if (set_ssthresh) - tp->snd_ssthresh = inet_csk(sk)->icsk_ca_ops->ssthresh(sk); + tp->snd_ssthresh = inet_csk(sk)->icsk_ca_ops->ssthresh(sk); TCP_ECN_queue_cwr(tp); } @@ -2528,14 +2527,14 @@ static inline void tcp_end_cwnd_reduction(struct sock *sk) } /* Enter CWR state. Disable cwnd undo since congestion is proven with ECN */ -void tcp_enter_cwr(struct sock *sk, const int set_ssthresh) +void tcp_enter_cwr(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); tp->prior_ssthresh = 0; if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) { tp->undo_marker = 0; - tcp_init_cwnd_reduction(sk, set_ssthresh); + tcp_init_cwnd_reduction(sk); tcp_set_ca_state(sk, TCP_CA_CWR); } } @@ -2564,7 +2563,7 @@ static void tcp_try_to_open(struct sock *sk, int flag, const int prior_unsacked) tp->retrans_stamp = 0; if (flag & FLAG_ECE) - tcp_enter_cwr(sk, 1); + tcp_enter_cwr(sk); if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) { tcp_try_keep_open(sk); @@ -2670,7 +2669,7 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack) if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) { if (!ece_ack) tp->prior_ssthresh = tcp_current_ssthresh(sk); - tcp_init_cwnd_reduction(sk, true); + tcp_init_cwnd_reduction(sk); } tcp_set_ca_state(sk, TCP_CA_Recovery); } @@ -3346,7 +3345,7 @@ static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag) tp->tlp_high_seq = 0; /* Don't reduce cwnd if DSACK arrives for TLP retrans. */ if (!(flag & FLAG_DSACKING_ACK)) { - tcp_init_cwnd_reduction(sk, true); + tcp_init_cwnd_reduction(sk); tcp_set_ca_state(sk, TCP_CA_CWR); tcp_end_cwnd_reduction(sk); tcp_try_keep_open(sk); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index bcee13c4627c..306dd5dead7d 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -979,7 +979,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, if (likely(err <= 0)) return err; - tcp_enter_cwr(sk, 1); + tcp_enter_cwr(sk); return net_xmit_eval(err); } -- cgit v1.2.3 From 04e10e2164fcfa05e14eff3c2757a5097f11d258 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 14 Jul 2014 21:34:51 +0530 Subject: iw_cxgb4: Detect Ing. Padding Boundary at run-time Updates iw_cxgb4 to determine the Ingress Padding Boundary from cxgb4_lld_info, and take subsequent actions. Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/cq.c | 4 ++-- drivers/infiniband/hw/cxgb4/device.c | 21 +++++++++++++++++++++ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 12 ++++++++++++ drivers/infiniband/hw/cxgb4/provider.c | 4 ++-- drivers/infiniband/hw/cxgb4/qp.c | 10 ++++++---- drivers/infiniband/hw/cxgb4/t4.h | 8 -------- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 ++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 2 ++ 8 files changed, 47 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index c04292c950f1..f04a838b65c7 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -895,7 +895,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries, /* * Make actual HW queue 2x to avoid cdix_inc overflows. */ - hwentries = min(entries * 2, T4_MAX_IQ_SIZE); + hwentries = min(entries * 2, rhp->rdev.hw_queue.t4_max_iq_size); /* * Make HW queue at least 64 entries so GTS updates aren't too @@ -912,7 +912,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries, if (ucontext) { memsize = roundup(memsize, PAGE_SIZE); hwentries = memsize / sizeof *chp->cq.queue; - while (hwentries > T4_MAX_IQ_SIZE) { + while (hwentries > rhp->rdev.hw_queue.t4_max_iq_size) { memsize -= PAGE_SIZE; hwentries = memsize / sizeof *chp->cq.queue; } diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index dd93aadc996e..88291ef82941 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -768,6 +768,27 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) } devp->rdev.lldi = *infop; + /* init various hw-queue params based on lld info */ + PDBG("%s: Ing. padding boundary is %d, egrsstatuspagesize = %d\n", + __func__, devp->rdev.lldi.sge_ingpadboundary, + devp->rdev.lldi.sge_egrstatuspagesize); + + devp->rdev.hw_queue.t4_eq_status_entries = + devp->rdev.lldi.sge_ingpadboundary > 64 ? 2 : 1; + devp->rdev.hw_queue.t4_max_eq_size = + 65520 - devp->rdev.hw_queue.t4_eq_status_entries; + devp->rdev.hw_queue.t4_max_iq_size = 65520 - 1; + devp->rdev.hw_queue.t4_max_rq_size = + 8192 - devp->rdev.hw_queue.t4_eq_status_entries; + devp->rdev.hw_queue.t4_max_sq_size = + devp->rdev.hw_queue.t4_max_eq_size - 1; + devp->rdev.hw_queue.t4_max_qp_depth = + devp->rdev.hw_queue.t4_max_rq_size - 1; + devp->rdev.hw_queue.t4_max_cq_depth = + devp->rdev.hw_queue.t4_max_iq_size - 1; + devp->rdev.hw_queue.t4_stat_len = + devp->rdev.lldi.sge_egrstatuspagesize; + /* * For T5 devices, we map all of BAR2 with WC. * For T4 devices with onchip qp mem, we map only that part diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 125bc5d1e175..9b9754c69ea0 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -139,6 +139,17 @@ struct c4iw_stats { u64 pas_ofld_conn_fails; }; +struct c4iw_hw_queue { + int t4_eq_status_entries; + int t4_max_eq_size; + int t4_max_iq_size; + int t4_max_rq_size; + int t4_max_sq_size; + int t4_max_qp_depth; + int t4_max_cq_depth; + int t4_stat_len; +}; + struct c4iw_rdev { struct c4iw_resource resource; unsigned long qpshift; @@ -156,6 +167,7 @@ struct c4iw_rdev { unsigned long oc_mw_pa; void __iomem *oc_mw_kva; struct c4iw_stats stats; + struct c4iw_hw_queue hw_queue; struct t4_dev_status_page *status_page; }; diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index b1d305338de6..1d41b92caaf5 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -319,13 +319,13 @@ static int c4iw_query_device(struct ib_device *ibdev, props->vendor_part_id = (u32)dev->rdev.lldi.pdev->device; props->max_mr_size = T4_MAX_MR_SIZE; props->max_qp = T4_MAX_NUM_QP; - props->max_qp_wr = T4_MAX_QP_DEPTH; + props->max_qp_wr = dev->rdev.hw_queue.t4_max_qp_depth; props->max_sge = T4_MAX_RECV_SGE; props->max_sge_rd = 1; props->max_qp_rd_atom = c4iw_max_read_depth; props->max_qp_init_rd_atom = c4iw_max_read_depth; props->max_cq = T4_MAX_NUM_CQ; - props->max_cqe = T4_MAX_CQ_DEPTH; + props->max_cqe = dev->rdev.hw_queue.t4_max_cq_depth; props->max_mr = c4iw_num_stags(&dev->rdev); props->max_pd = T4_MAX_NUM_PD; props->local_ca_ack_delay = 0; diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 086f62f5dc9e..6f74e0e9a022 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -258,7 +258,8 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, /* * eqsize is the number of 64B entries plus the status page size. */ - eqsize = wq->sq.size * T4_SQ_NUM_SLOTS + T4_EQ_STATUS_ENTRIES; + eqsize = wq->sq.size * T4_SQ_NUM_SLOTS + + rdev->hw_queue.t4_eq_status_entries; res->u.sqrq.fetchszm_to_iqid = cpu_to_be32( V_FW_RI_RES_WR_HOSTFCMODE(0) | /* no host cidx updates */ @@ -283,7 +284,8 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, /* * eqsize is the number of 64B entries plus the status page size. */ - eqsize = wq->rq.size * T4_RQ_NUM_SLOTS + T4_EQ_STATUS_ENTRIES; + eqsize = wq->rq.size * T4_RQ_NUM_SLOTS + + rdev->hw_queue.t4_eq_status_entries; res->u.sqrq.fetchszm_to_iqid = cpu_to_be32( V_FW_RI_RES_WR_HOSTFCMODE(0) | /* no host cidx updates */ V_FW_RI_RES_WR_CPRIO(0) | /* don't keep in chip cache */ @@ -1570,11 +1572,11 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, return ERR_PTR(-EINVAL); rqsize = roundup(attrs->cap.max_recv_wr + 1, 16); - if (rqsize > T4_MAX_RQ_SIZE) + if (rqsize > rhp->rdev.hw_queue.t4_max_rq_size) return ERR_PTR(-E2BIG); sqsize = roundup(attrs->cap.max_send_wr + 1, 16); - if (sqsize > T4_MAX_SQ_SIZE) + if (sqsize > rhp->rdev.hw_queue.t4_max_sq_size) return ERR_PTR(-E2BIG); ucontext = pd->uobject ? to_c4iw_ucontext(pd->uobject->context) : NULL; diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index 68b0a6bf4eb0..e64fa8b2be06 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -39,19 +39,11 @@ #define T4_MAX_NUM_QP 65536 #define T4_MAX_NUM_CQ 65536 #define T4_MAX_NUM_PD 65536 -#define T4_EQ_STATUS_ENTRIES (L1_CACHE_BYTES > 64 ? 2 : 1) -#define T4_MAX_EQ_SIZE (65520 - T4_EQ_STATUS_ENTRIES) -#define T4_MAX_IQ_SIZE (65520 - 1) -#define T4_MAX_RQ_SIZE (8192 - T4_EQ_STATUS_ENTRIES) -#define T4_MAX_SQ_SIZE (T4_MAX_EQ_SIZE - 1) -#define T4_MAX_QP_DEPTH (T4_MAX_RQ_SIZE - 1) -#define T4_MAX_CQ_DEPTH (T4_MAX_IQ_SIZE - 1) #define T4_MAX_NUM_STAG (1<<15) #define T4_MAX_MR_SIZE (~0ULL) #define T4_PAGESIZE_MASK 0xffff000 /* 4KB-128MB */ #define T4_STAG_UNSET 0xffffffff #define T4_FW_MAJ 0 -#define T4_EQ_STATUS_ENTRIES (L1_CACHE_BYTES > 64 ? 2 : 1) #define A_PCIE_MA_SYNC 0x30b4 struct t4_status_page { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 2b438bd68c73..a7ce996630ed 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4109,6 +4109,8 @@ static void uld_attach(struct adapter *adap, unsigned int uld) lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL); lli.fw_vers = adap->params.fw_vers; lli.dbfifo_int_thresh = dbfifo_int_thresh; + lli.sge_ingpadboundary = adap->sge.fl_align; + lli.sge_egrstatuspagesize = adap->sge.stat_len; lli.sge_pktshift = adap->sge.pktshift; lli.enable_fw_ofld_conn = adap->flags & FW_OFLD_CONN; lli.ulptx_memwrite_dsgl = adap->params.ulptx_memwrite_dsgl; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index 8f60851b75ad..962458f5d5b3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -251,6 +251,8 @@ struct cxgb4_lld_info { void __iomem *gts_reg; /* address of GTS register */ void __iomem *db_reg; /* address of kernel doorbell */ int dbfifo_int_thresh; /* doorbell fifo int threshold */ + unsigned int sge_ingpadboundary; /* SGE ingress padding boundary */ + unsigned int sge_egrstatuspagesize; /* SGE egress status page size */ unsigned int sge_pktshift; /* Padding between CPL and */ /* packet data */ unsigned int pf; /* Physical Function we're using */ -- cgit v1.2.3 From 4c2c5763227a14ce111d6f35df708459d2443cc3 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 14 Jul 2014 21:34:52 +0530 Subject: cxgb4/iw_cxgb4: use firmware ord/ird resource limits Advertise a larger max read queue depth for qps, and gather the resource limits from fw and use them to avoid exhaustinq all the resources. Design: cxgb4: Obtain the max_ordird_qp and max_ird_adapter device params from FW at init time and pass them up to the ULDs when they attach. If these parameters are not available, due to older firmware, then hard-code the values based on the known values for older firmware. iw_cxgb4: Fix the c4iw_query_device() to report these correct values based on adapter parameters. ibv_query_device() will always return: max_qp_rd_atom = max_qp_init_rd_atom = min(module_max, max_ordird_qp) max_res_rd_atom = max_ird_adapter Bump up the per qp max module option to 32, allowing it to be increased by the user up to the device max of max_ordird_qp. 32 seems to be sufficient to maximize throughput for streaming read benchmarks. Fail connection setup if the negotiated IRD exhausts the available adapter ird resources. So the driver will track the amount of ird resource in use and not send an RI_WR/INIT to FW that would reduce the available ird resources below zero. Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/cm.c | 80 ++++++++++++++++++------- drivers/infiniband/hw/cxgb4/device.c | 2 + drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 9 ++- drivers/infiniband/hw/cxgb4/provider.c | 6 +- drivers/infiniband/hw/cxgb4/qp.c | 54 ++++++++++++++--- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 3 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 18 ++++++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 2 + drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 2 + 9 files changed, 142 insertions(+), 34 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index d62a0f9dd11a..df5bd3df08a2 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -79,9 +79,10 @@ static int dack_mode = 1; module_param(dack_mode, int, 0644); MODULE_PARM_DESC(dack_mode, "Delayed ack mode (default=1)"); -int c4iw_max_read_depth = 8; +uint c4iw_max_read_depth = 32; module_param(c4iw_max_read_depth, int, 0644); -MODULE_PARM_DESC(c4iw_max_read_depth, "Per-connection max ORD/IRD (default=8)"); +MODULE_PARM_DESC(c4iw_max_read_depth, + "Per-connection max ORD/IRD (default=32)"); static int enable_tcp_timestamps; module_param(enable_tcp_timestamps, int, 0644); @@ -813,6 +814,8 @@ static void send_mpa_req(struct c4iw_ep *ep, struct sk_buff *skb, if (mpa_rev_to_use == 2) { mpa->private_data_size = htons(ntohs(mpa->private_data_size) + sizeof (struct mpa_v2_conn_params)); + PDBG("%s initiator ird %u ord %u\n", __func__, ep->ird, + ep->ord); mpa_v2_params.ird = htons((u16)ep->ird); mpa_v2_params.ord = htons((u16)ep->ord); @@ -1182,8 +1185,8 @@ static int connect_request_upcall(struct c4iw_ep *ep) sizeof(struct mpa_v2_conn_params); } else { /* this means MPA_v1 is used. Send max supported */ - event.ord = c4iw_max_read_depth; - event.ird = c4iw_max_read_depth; + event.ord = cur_max_read_depth(ep->com.dev); + event.ird = cur_max_read_depth(ep->com.dev); event.private_data_len = ep->plen; event.private_data = ep->mpa_pkt + sizeof(struct mpa_message); } @@ -1247,6 +1250,8 @@ static int update_rx_credits(struct c4iw_ep *ep, u32 credits) return credits; } +#define RELAXED_IRD_NEGOTIATION 1 + static int process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb) { struct mpa_message *mpa; @@ -1358,17 +1363,33 @@ static int process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb) MPA_V2_IRD_ORD_MASK; resp_ord = ntohs(mpa_v2_params->ord) & MPA_V2_IRD_ORD_MASK; + PDBG("%s responder ird %u ord %u ep ird %u ord %u\n", + __func__, resp_ird, resp_ord, ep->ird, ep->ord); /* * This is a double-check. Ideally, below checks are * not required since ird/ord stuff has been taken * care of in c4iw_accept_cr */ - if ((ep->ird < resp_ord) || (ep->ord > resp_ird)) { + if (ep->ird < resp_ord) { + if (RELAXED_IRD_NEGOTIATION && resp_ord <= + ep->com.dev->rdev.lldi.max_ordird_qp) + ep->ird = resp_ord; + else + insuff_ird = 1; + } else if (ep->ird > resp_ord) { + ep->ird = resp_ord; + } + if (ep->ord > resp_ird) { + if (RELAXED_IRD_NEGOTIATION) + ep->ord = resp_ird; + else + insuff_ird = 1; + } + if (insuff_ird) { err = -ENOMEM; ep->ird = resp_ord; ep->ord = resp_ird; - insuff_ird = 1; } if (ntohs(mpa_v2_params->ird) & @@ -1571,6 +1592,8 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) MPA_V2_IRD_ORD_MASK; ep->ord = ntohs(mpa_v2_params->ord) & MPA_V2_IRD_ORD_MASK; + PDBG("%s initiator ird %u ord %u\n", __func__, ep->ird, + ep->ord); if (ntohs(mpa_v2_params->ird) & MPA_V2_PEER2PEER_MODEL) if (peer2peer) { if (ntohs(mpa_v2_params->ord) & @@ -2724,8 +2747,8 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) BUG_ON(!qp); set_bit(ULP_ACCEPT, &ep->com.history); - if ((conn_param->ord > c4iw_max_read_depth) || - (conn_param->ird > c4iw_max_read_depth)) { + if ((conn_param->ord > cur_max_read_depth(ep->com.dev)) || + (conn_param->ird > cur_max_read_depth(ep->com.dev))) { abort_connection(ep, NULL, GFP_KERNEL); err = -EINVAL; goto err; @@ -2733,31 +2756,41 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) { if (conn_param->ord > ep->ird) { - ep->ird = conn_param->ird; - ep->ord = conn_param->ord; - send_mpa_reject(ep, conn_param->private_data, - conn_param->private_data_len); - abort_connection(ep, NULL, GFP_KERNEL); - err = -ENOMEM; - goto err; + if (RELAXED_IRD_NEGOTIATION) { + ep->ord = ep->ird; + } else { + ep->ird = conn_param->ird; + ep->ord = conn_param->ord; + send_mpa_reject(ep, conn_param->private_data, + conn_param->private_data_len); + abort_connection(ep, NULL, GFP_KERNEL); + err = -ENOMEM; + goto err; + } } - if (conn_param->ird > ep->ord) { - if (!ep->ord) - conn_param->ird = 1; - else { + if (conn_param->ird < ep->ord) { + if (RELAXED_IRD_NEGOTIATION && + ep->ord <= h->rdev.lldi.max_ordird_qp) { + conn_param->ird = ep->ord; + } else { abort_connection(ep, NULL, GFP_KERNEL); err = -ENOMEM; goto err; } } - } ep->ird = conn_param->ird; ep->ord = conn_param->ord; - if (ep->mpa_attr.version != 2) + if (ep->mpa_attr.version == 1) { if (peer2peer && ep->ird == 0) ep->ird = 1; + } else { + if (peer2peer && + (ep->mpa_attr.p2p_type != FW_RI_INIT_P2PTYPE_DISABLED) && + (p2p_type == FW_RI_INIT_P2PTYPE_READ_REQ) && ep->ord == 0) + ep->ird = 1; + } PDBG("%s %d ird %d ord %d\n", __func__, __LINE__, ep->ird, ep->ord); @@ -2796,6 +2829,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) return 0; err1: ep->com.cm_id = NULL; + abort_connection(ep, NULL, GFP_KERNEL); cm_id->rem_ref(cm_id); err: mutex_unlock(&ep->com.mutex); @@ -2879,8 +2913,8 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) int iptype; int iwpm_err = 0; - if ((conn_param->ord > c4iw_max_read_depth) || - (conn_param->ird > c4iw_max_read_depth)) { + if ((conn_param->ord > cur_max_read_depth(dev)) || + (conn_param->ird > cur_max_read_depth(dev))) { err = -EINVAL; goto out; } diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index 88291ef82941..e76358efcaa1 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -348,6 +348,7 @@ static int stats_show(struct seq_file *seq, void *v) dev->rdev.stats.act_ofld_conn_fails); seq_printf(seq, "PAS_OFLD_CONN_FAILS: %10llu\n", dev->rdev.stats.pas_ofld_conn_fails); + seq_printf(seq, "AVAILABLE IRD: %10u\n", dev->avail_ird); return 0; } @@ -839,6 +840,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) mutex_init(&devp->rdev.stats.lock); mutex_init(&devp->db_mutex); INIT_LIST_HEAD(&devp->db_fc_list); + devp->avail_ird = devp->rdev.lldi.max_ird_adapter; if (c4iw_debugfs_root) { devp->debugfs_root = debugfs_create_dir( diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 9b9754c69ea0..75541cb833c6 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -249,6 +249,7 @@ struct c4iw_dev { struct idr atid_idr; struct idr stid_idr; struct list_head db_fc_list; + u32 avail_ird; }; static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev) @@ -330,6 +331,13 @@ static inline void remove_handle_nolock(struct c4iw_dev *rhp, _remove_handle(rhp, idr, id, 0); } +extern uint c4iw_max_read_depth; + +static inline int cur_max_read_depth(struct c4iw_dev *dev) +{ + return min(dev->rdev.lldi.max_ordird_qp, c4iw_max_read_depth); +} + struct c4iw_pd { struct ib_pd ibpd; u32 pdid; @@ -1003,7 +1011,6 @@ void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe); extern struct cxgb4_client t4c_client; extern c4iw_handler_func c4iw_handlers[NUM_CPL_CMDS]; -extern int c4iw_max_read_depth; extern int db_fc_threshold; extern int db_coalescing_threshold; extern int use_dsgl; diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 1d41b92caaf5..67c4a6908021 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -322,8 +322,10 @@ static int c4iw_query_device(struct ib_device *ibdev, props->max_qp_wr = dev->rdev.hw_queue.t4_max_qp_depth; props->max_sge = T4_MAX_RECV_SGE; props->max_sge_rd = 1; - props->max_qp_rd_atom = c4iw_max_read_depth; - props->max_qp_init_rd_atom = c4iw_max_read_depth; + props->max_res_rd_atom = dev->rdev.lldi.max_ird_adapter; + props->max_qp_rd_atom = min(dev->rdev.lldi.max_ordird_qp, + c4iw_max_read_depth); + props->max_qp_init_rd_atom = props->max_qp_rd_atom; props->max_cq = T4_MAX_NUM_CQ; props->max_cqe = dev->rdev.hw_queue.t4_max_cq_depth; props->max_mr = c4iw_num_stags(&dev->rdev); diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 6f74e0e9a022..0de3cf64eb5e 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -58,6 +58,31 @@ static int max_fr_immd = T4_MAX_FR_IMMD; module_param(max_fr_immd, int, 0644); MODULE_PARM_DESC(max_fr_immd, "fastreg threshold for using DSGL instead of immedate"); +static int alloc_ird(struct c4iw_dev *dev, u32 ird) +{ + int ret = 0; + + spin_lock_irq(&dev->lock); + if (ird <= dev->avail_ird) + dev->avail_ird -= ird; + else + ret = -ENOMEM; + spin_unlock_irq(&dev->lock); + + if (ret) + dev_warn(&dev->rdev.lldi.pdev->dev, + "device IRD resources exhausted\n"); + + return ret; +} + +static void free_ird(struct c4iw_dev *dev, int ird) +{ + spin_lock_irq(&dev->lock); + dev->avail_ird += ird; + spin_unlock_irq(&dev->lock); +} + static void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state) { unsigned long flag; @@ -1204,12 +1229,20 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp) int ret; struct sk_buff *skb; - PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid, - qhp->ep->hwtid); + PDBG("%s qhp %p qid 0x%x tid %u ird %u ord %u\n", __func__, qhp, + qhp->wq.sq.qid, qhp->ep->hwtid, qhp->ep->ird, qhp->ep->ord); skb = alloc_skb(sizeof *wqe, GFP_KERNEL); - if (!skb) - return -ENOMEM; + if (!skb) { + ret = -ENOMEM; + goto out; + } + ret = alloc_ird(rhp, qhp->attr.max_ird); + if (ret) { + qhp->attr.max_ird = 0; + kfree_skb(skb); + goto out; + } set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx); wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe)); @@ -1260,10 +1293,14 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp) ret = c4iw_ofld_send(&rhp->rdev, skb); if (ret) - goto out; + goto err1; ret = c4iw_wait_for_reply(&rhp->rdev, &qhp->ep->com.wr_wait, qhp->ep->hwtid, qhp->wq.sq.qid, __func__); + if (!ret) + goto out; +err1: + free_ird(rhp, qhp->attr.max_ird); out: PDBG("%s ret %d\n", __func__, ret); return ret; @@ -1308,7 +1345,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, newattr.max_ord = attrs->max_ord; } if (mask & C4IW_QP_ATTR_MAX_IRD) { - if (attrs->max_ird > c4iw_max_read_depth) { + if (attrs->max_ird > cur_max_read_depth(rhp)) { ret = -EINVAL; goto out; } @@ -1531,6 +1568,7 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp) if (!list_empty(&qhp->db_fc_entry)) list_del_init(&qhp->db_fc_entry); spin_unlock_irq(&rhp->lock); + free_ird(rhp, qhp->attr.max_ird); ucontext = ib_qp->uobject ? to_c4iw_ucontext(ib_qp->uobject->context) : NULL; @@ -1621,8 +1659,8 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, qhp->attr.enable_rdma_read = 1; qhp->attr.enable_rdma_write = 1; qhp->attr.enable_bind = 1; - qhp->attr.max_ord = 1; - qhp->attr.max_ird = 1; + qhp->attr.max_ord = 0; + qhp->attr.max_ird = 0; qhp->sq_sig_all = attrs->sq_sig_type == IB_SIGNAL_ALL_WR; spin_lock_init(&qhp->lock); mutex_init(&qhp->mutex); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index f338a7fcebf7..46156210df34 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -310,6 +310,9 @@ struct adapter_params { unsigned int ofldq_wr_cred; bool ulptx_memwrite_dsgl; /* use of T5 DSGL allowed */ + + unsigned int max_ordird_qp; /* Max read depth per RDMA QP */ + unsigned int max_ird_adapter; /* Max read depth per adapter */ }; #include "t4fw_api.h" diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index a7ce996630ed..767cbbaa3d1e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4113,6 +4113,8 @@ static void uld_attach(struct adapter *adap, unsigned int uld) lli.sge_egrstatuspagesize = adap->sge.stat_len; lli.sge_pktshift = adap->sge.pktshift; lli.enable_fw_ofld_conn = adap->flags & FW_OFLD_CONN; + lli.max_ordird_qp = adap->params.max_ordird_qp; + lli.max_ird_adapter = adap->params.max_ird_adapter; lli.ulptx_memwrite_dsgl = adap->params.ulptx_memwrite_dsgl; handle = ulds[uld].add(&lli); @@ -5877,6 +5879,22 @@ static int adap_init0(struct adapter *adap) adap->vres.cq.size = val[3] - val[2] + 1; adap->vres.ocq.start = val[4]; adap->vres.ocq.size = val[5] - val[4] + 1; + + params[0] = FW_PARAM_DEV(MAXORDIRD_QP); + params[1] = FW_PARAM_DEV(MAXIRD_ADAPTER); + ret = t4_query_params(adap, 0, 0, 0, 2, params, val); + if (ret < 0) { + adap->params.max_ordird_qp = 8; + adap->params.max_ird_adapter = 32 * adap->tids.ntids; + ret = 0; + } else { + adap->params.max_ordird_qp = val[0]; + adap->params.max_ird_adapter = val[1]; + } + dev_info(adap->pdev_dev, + "max_ordird_qp %d max_ird_adapter %d\n", + adap->params.max_ordird_qp, + adap->params.max_ird_adapter); } if (caps_cmd.iscsicaps) { params[0] = FW_PARAM_PFVF(ISCSI_START); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index 962458f5d5b3..df1d9446768a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -258,6 +258,8 @@ struct cxgb4_lld_info { unsigned int pf; /* Physical Function we're using */ bool enable_fw_ofld_conn; /* Enable connection through fw */ /* WR */ + unsigned int max_ordird_qp; /* Max ORD/IRD depth per RDMA QP */ + unsigned int max_ird_adapter; /* Max IRD memory per adapter */ bool ulptx_memwrite_dsgl; /* use of T5 DSGL allowed */ }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 4a6ae4db7397..ff709e3b3e7e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -934,6 +934,8 @@ enum fw_params_param_dev { FW_PARAMS_PARAM_DEV_FWREV = 0x0B, FW_PARAMS_PARAM_DEV_TPREV = 0x0C, FW_PARAMS_PARAM_DEV_CF = 0x0D, + FW_PARAMS_PARAM_DEV_MAXORDIRD_QP = 0x13, /* max supported QP IRD/ORD */ + FW_PARAMS_PARAM_DEV_MAXIRD_ADAPTER = 0x14, /* max supported adap IRD */ FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17, }; -- cgit v1.2.3 From 031cf4769bc4504d046074274d1ecd70d89d20b8 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 14 Jul 2014 21:34:53 +0530 Subject: cxgb4/iw_cxgb4: display TPTE on errors With ingress WRITE or READ RESPONSE errors, HW provides the offending stag from the packet. This patch adds logic to log the parsed TPTE in this case. cxgb4 now exports a function to read a TPTE entry from adapter memory. Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/device.c | 28 +++++++++-- drivers/infiniband/hw/cxgb4/ev.c | 55 +++++++++++++++++++-- drivers/infiniband/hw/cxgb4/t4.h | 4 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 66 +++++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 1 + 5 files changed, 143 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index e76358efcaa1..8386678f1159 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -241,12 +241,32 @@ static int dump_stag(int id, void *p, void *data) struct c4iw_debugfs_data *stagd = data; int space; int cc; + struct fw_ri_tpte tpte; + int ret; space = stagd->bufsize - stagd->pos - 1; if (space == 0) return 1; - cc = snprintf(stagd->buf + stagd->pos, space, "0x%x\n", id<<8); + ret = cxgb4_read_tpte(stagd->devp->rdev.lldi.ports[0], (u32)id<<8, + (__be32 *)&tpte); + if (ret) { + dev_err(&stagd->devp->rdev.lldi.pdev->dev, + "%s cxgb4_read_tpte err %d\n", __func__, ret); + return ret; + } + cc = snprintf(stagd->buf + stagd->pos, space, + "stag: idx 0x%x valid %d key 0x%x state %d pdid %d " + "perm 0x%x ps %d len 0x%llx va 0x%llx\n", + (u32)id<<8, + G_FW_RI_TPTE_VALID(ntohl(tpte.valid_to_pdid)), + G_FW_RI_TPTE_STAGKEY(ntohl(tpte.valid_to_pdid)), + G_FW_RI_TPTE_STAGSTATE(ntohl(tpte.valid_to_pdid)), + G_FW_RI_TPTE_PDID(ntohl(tpte.valid_to_pdid)), + G_FW_RI_TPTE_PERM(ntohl(tpte.locread_to_qpid)), + G_FW_RI_TPTE_PS(ntohl(tpte.locread_to_qpid)), + ((u64)ntohl(tpte.len_hi) << 32) | ntohl(tpte.len_lo), + ((u64)ntohl(tpte.va_hi) << 32) | ntohl(tpte.va_lo_fbo)); if (cc < space) stagd->pos += cc; return 0; @@ -259,7 +279,7 @@ static int stag_release(struct inode *inode, struct file *file) printk(KERN_INFO "%s null stagd?\n", __func__); return 0; } - kfree(stagd->buf); + vfree(stagd->buf); kfree(stagd); return 0; } @@ -282,8 +302,8 @@ static int stag_open(struct inode *inode, struct file *file) idr_for_each(&stagd->devp->mmidr, count_idrs, &count); spin_unlock_irq(&stagd->devp->lock); - stagd->bufsize = count * sizeof("0x12345678\n"); - stagd->buf = kmalloc(stagd->bufsize, GFP_KERNEL); + stagd->bufsize = count * 256; + stagd->buf = vmalloc(stagd->bufsize); if (!stagd->buf) { ret = -ENOMEM; goto err1; diff --git a/drivers/infiniband/hw/cxgb4/ev.c b/drivers/infiniband/hw/cxgb4/ev.c index d61d0a18f784..fbe6051af254 100644 --- a/drivers/infiniband/hw/cxgb4/ev.c +++ b/drivers/infiniband/hw/cxgb4/ev.c @@ -35,6 +35,55 @@ #include "iw_cxgb4.h" +static void print_tpte(struct c4iw_dev *dev, u32 stag) +{ + int ret; + struct fw_ri_tpte tpte; + + ret = cxgb4_read_tpte(dev->rdev.lldi.ports[0], stag, + (__be32 *)&tpte); + if (ret) { + dev_err(&dev->rdev.lldi.pdev->dev, + "%s cxgb4_read_tpte err %d\n", __func__, ret); + return; + } + PDBG("stag idx 0x%x valid %d key 0x%x state %d pdid %d " + "perm 0x%x ps %d len 0x%llx va 0x%llx\n", + stag & 0xffffff00, + G_FW_RI_TPTE_VALID(ntohl(tpte.valid_to_pdid)), + G_FW_RI_TPTE_STAGKEY(ntohl(tpte.valid_to_pdid)), + G_FW_RI_TPTE_STAGSTATE(ntohl(tpte.valid_to_pdid)), + G_FW_RI_TPTE_PDID(ntohl(tpte.valid_to_pdid)), + G_FW_RI_TPTE_PERM(ntohl(tpte.locread_to_qpid)), + G_FW_RI_TPTE_PS(ntohl(tpte.locread_to_qpid)), + ((u64)ntohl(tpte.len_hi) << 32) | ntohl(tpte.len_lo), + ((u64)ntohl(tpte.va_hi) << 32) | ntohl(tpte.va_lo_fbo)); +} + +static void dump_err_cqe(struct c4iw_dev *dev, struct t4_cqe *err_cqe) +{ + __be64 *p = (void *)err_cqe; + + dev_err(&dev->rdev.lldi.pdev->dev, + "AE qpid %d opcode %d status 0x%x " + "type %d len 0x%x wrid.hi 0x%x wrid.lo 0x%x\n", + CQE_QPID(err_cqe), CQE_OPCODE(err_cqe), + CQE_STATUS(err_cqe), CQE_TYPE(err_cqe), ntohl(err_cqe->len), + CQE_WRID_HI(err_cqe), CQE_WRID_LOW(err_cqe)); + + PDBG("%016llx %016llx %016llx %016llx\n", + be64_to_cpu(p[0]), be64_to_cpu(p[1]), be64_to_cpu(p[2]), + be64_to_cpu(p[3])); + + /* + * Ingress WRITE and READ_RESP errors provide + * the offending stag, so parse and log it. + */ + if (RQ_TYPE(err_cqe) && (CQE_OPCODE(err_cqe) == FW_RI_RDMA_WRITE || + CQE_OPCODE(err_cqe) == FW_RI_READ_RESP)) + print_tpte(dev, CQE_WRID_STAG(err_cqe)); +} + static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp, struct c4iw_qp *qhp, struct t4_cqe *err_cqe, @@ -44,11 +93,7 @@ static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp, struct c4iw_qp_attributes attrs; unsigned long flag; - printk(KERN_ERR MOD "AE qpid 0x%x opcode %d status 0x%x " - "type %d wrid.hi 0x%x wrid.lo 0x%x\n", - CQE_QPID(err_cqe), CQE_OPCODE(err_cqe), - CQE_STATUS(err_cqe), CQE_TYPE(err_cqe), - CQE_WRID_HI(err_cqe), CQE_WRID_LOW(err_cqe)); + dump_err_cqe(dev, err_cqe); if (qhp->attr.state == C4IW_QP_STATE_RTS) { attrs.next_state = C4IW_QP_STATE_TERMINATE; diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index e64fa8b2be06..dd45186d1c55 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -236,8 +236,8 @@ struct t4_cqe { #define CQE_WRID_SQ_IDX(x) ((x)->u.scqe.cidx) /* generic accessor macros */ -#define CQE_WRID_HI(x) ((x)->u.gen.wrid_hi) -#define CQE_WRID_LOW(x) ((x)->u.gen.wrid_low) +#define CQE_WRID_HI(x) (be32_to_cpu((x)->u.gen.wrid_hi)) +#define CQE_WRID_LOW(x) (be32_to_cpu((x)->u.gen.wrid_low)) /* macros for flit 3 of the cqe */ #define S_CQE_GENBIT 63 diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 767cbbaa3d1e..ba7d13de5e83 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -3832,6 +3832,72 @@ void cxgb4_enable_db_coalescing(struct net_device *dev) } EXPORT_SYMBOL(cxgb4_enable_db_coalescing); +int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte) +{ + struct adapter *adap; + u32 offset, memtype, memaddr; + u32 edc0_size, edc1_size, mc0_size, mc1_size; + u32 edc0_end, edc1_end, mc0_end, mc1_end; + int ret; + + adap = netdev2adap(dev); + + offset = ((stag >> 8) * 32) + adap->vres.stag.start; + + /* Figure out where the offset lands in the Memory Type/Address scheme. + * This code assumes that the memory is laid out starting at offset 0 + * with no breaks as: EDC0, EDC1, MC0, MC1. All cards have both EDC0 + * and EDC1. Some cards will have neither MC0 nor MC1, most cards have + * MC0, and some have both MC0 and MC1. + */ + edc0_size = EDRAM_SIZE_GET(t4_read_reg(adap, MA_EDRAM0_BAR)) << 20; + edc1_size = EDRAM_SIZE_GET(t4_read_reg(adap, MA_EDRAM1_BAR)) << 20; + mc0_size = EXT_MEM_SIZE_GET(t4_read_reg(adap, MA_EXT_MEMORY_BAR)) << 20; + + edc0_end = edc0_size; + edc1_end = edc0_end + edc1_size; + mc0_end = edc1_end + mc0_size; + + if (offset < edc0_end) { + memtype = MEM_EDC0; + memaddr = offset; + } else if (offset < edc1_end) { + memtype = MEM_EDC1; + memaddr = offset - edc0_end; + } else { + if (offset < mc0_end) { + memtype = MEM_MC0; + memaddr = offset - edc1_end; + } else if (is_t4(adap->params.chip)) { + /* T4 only has a single memory channel */ + goto err; + } else { + mc1_size = EXT_MEM_SIZE_GET( + t4_read_reg(adap, + MA_EXT_MEMORY1_BAR)) << 20; + mc1_end = mc0_end + mc1_size; + if (offset < mc1_end) { + memtype = MEM_MC1; + memaddr = offset - mc0_end; + } else { + /* offset beyond the end of any memory */ + goto err; + } + } + } + + spin_lock(&adap->win0_lock); + ret = t4_memory_rw(adap, 0, memtype, memaddr, 32, tpte, T4_MEMORY_READ); + spin_unlock(&adap->win0_lock); + return ret; + +err: + dev_err(adap->pdev_dev, "stag %#x, offset %#x out of range\n", + stag, offset); + return -EINVAL; +} +EXPORT_SYMBOL(cxgb4_read_tpte); + static struct pci_driver cxgb4_driver; static void check_neigh_update(struct neighbour *neigh) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index df1d9446768a..c7170d68bf63 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -296,5 +296,6 @@ int cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx, u16 size); int cxgb4_flush_eq_cache(struct net_device *dev); void cxgb4_disable_db_coalescing(struct net_device *dev); void cxgb4_enable_db_coalescing(struct net_device *dev); +int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte); #endif /* !__CXGB4_OFLD_H */ -- cgit v1.2.3 From 7730b4c7e32c0ab4d7db746a9c3a84cf715161fa Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 14 Jul 2014 21:34:54 +0530 Subject: cxgb4/iw_cxgb4: work request logging feature This commit enhances the iwarp driver to optionally keep a log of rdma work request timining data for kernel mode QPs. If iw_cxgb4 module option c4iw_wr_log is set to non-zero, each work request is tracked and timing data maintained in a rolling log that is 4096 entries deep by default. Module option c4iw_wr_log_size_order allows specifing a log2 size to use instead of the default order of 12 (4096 entries). Both module options are read-only and must be passed in at module load time to set them. IE: modprobe iw_cxgb4 c4iw_wr_log=1 c4iw_wr_log_size_order=10 The timing data is viewable via the iw_cxgb4 debugfs file "wr_log". Writing anything to this file will clear all the timing data. Data tracked includes: - The host time when the work request was posted, just before ringing the doorbell. The host time when the completion was polled by the application. This is also the time the log entry is created. The delta of these two times is the amount of time took processing the work request. - The qid of the EQ used to post the work request. - The work request opcode. - The cqe wr_id field. For sq completions requests this is the swsqe index. For recv completions this is the MSN of the ingress SEND. This value can be used to match log entries from this log with firmware flowc event entries. - The sge timestamp value just before ringing the doorbell when posting, the sge timestamp value just after polling the completion, and CQE.timestamp field from the completion itself. With these three timestamps we can track the latency from post to poll, and the amount of time the completion resided in the CQ before being reaped by the application. With debug firmware, the sge timestamp is also logged by firmware in its flowc history so that we can compute the latency from posting the work request until the firmware sees it. Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/cq.c | 4 + drivers/infiniband/hw/cxgb4/device.c | 137 ++++++++++++++++++++++++ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 17 +++ drivers/infiniband/hw/cxgb4/qp.c | 12 +++ drivers/infiniband/hw/cxgb4/t4.h | 4 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 14 +++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 2 + drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 6 ++ 8 files changed, 196 insertions(+) diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index f04a838b65c7..de9bcf2e6d30 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -633,11 +633,15 @@ proc_cqe: wq->sq.cidx = (uint16_t)idx; PDBG("%s completing sq idx %u\n", __func__, wq->sq.cidx); *cookie = wq->sq.sw_sq[wq->sq.cidx].wr_id; + if (c4iw_wr_log) + c4iw_log_wr_stats(wq, hw_cqe); t4_sq_consume(wq); } else { PDBG("%s completing rq idx %u\n", __func__, wq->rq.cidx); *cookie = wq->rq.sw_rq[wq->rq.cidx].wr_id; BUG_ON(t4_rq_empty(wq)); + if (c4iw_wr_log) + c4iw_log_wr_stats(wq, hw_cqe); t4_rq_consume(wq); goto skip_cqe; } diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index 8386678f1159..df1f1b52c7ec 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -55,6 +55,15 @@ module_param(allow_db_coalescing_on_t5, int, 0644); MODULE_PARM_DESC(allow_db_coalescing_on_t5, "Allow DB Coalescing on T5 (default = 0)"); +int c4iw_wr_log = 0; +module_param(c4iw_wr_log, int, 0444); +MODULE_PARM_DESC(c4iw_wr_log, "Enables logging of work request timing data."); + +int c4iw_wr_log_size_order = 12; +module_param(c4iw_wr_log_size_order, int, 0444); +MODULE_PARM_DESC(c4iw_wr_log_size_order, + "Number of entries (log2) in the work request timing log."); + struct uld_ctx { struct list_head entry; struct cxgb4_lld_info lldi; @@ -103,6 +112,117 @@ static ssize_t debugfs_read(struct file *file, char __user *buf, size_t count, return simple_read_from_buffer(buf, count, ppos, d->buf, d->pos); } +void c4iw_log_wr_stats(struct t4_wq *wq, struct t4_cqe *cqe) +{ + struct wr_log_entry le; + int idx; + + if (!wq->rdev->wr_log) + return; + + idx = (atomic_inc_return(&wq->rdev->wr_log_idx) - 1) & + (wq->rdev->wr_log_size - 1); + le.poll_sge_ts = cxgb4_read_sge_timestamp(wq->rdev->lldi.ports[0]); + getnstimeofday(&le.poll_host_ts); + le.valid = 1; + le.cqe_sge_ts = CQE_TS(cqe); + if (SQ_TYPE(cqe)) { + le.qid = wq->sq.qid; + le.opcode = CQE_OPCODE(cqe); + le.post_host_ts = wq->sq.sw_sq[wq->sq.cidx].host_ts; + le.post_sge_ts = wq->sq.sw_sq[wq->sq.cidx].sge_ts; + le.wr_id = CQE_WRID_SQ_IDX(cqe); + } else { + le.qid = wq->rq.qid; + le.opcode = FW_RI_RECEIVE; + le.post_host_ts = wq->rq.sw_rq[wq->rq.cidx].host_ts; + le.post_sge_ts = wq->rq.sw_rq[wq->rq.cidx].sge_ts; + le.wr_id = CQE_WRID_MSN(cqe); + } + wq->rdev->wr_log[idx] = le; +} + +static int wr_log_show(struct seq_file *seq, void *v) +{ + struct c4iw_dev *dev = seq->private; + struct timespec prev_ts = {0, 0}; + struct wr_log_entry *lep; + int prev_ts_set = 0; + int idx, end; + +#define ts2ns(ts) ((ts) * dev->rdev.lldi.cclk_ps / 1000) + + idx = atomic_read(&dev->rdev.wr_log_idx) & + (dev->rdev.wr_log_size - 1); + end = idx - 1; + if (end < 0) + end = dev->rdev.wr_log_size - 1; + lep = &dev->rdev.wr_log[idx]; + while (idx != end) { + if (lep->valid) { + if (!prev_ts_set) { + prev_ts_set = 1; + prev_ts = lep->poll_host_ts; + } + seq_printf(seq, "%04u: sec %lu nsec %lu qid %u opcode " + "%u %s 0x%x host_wr_delta sec %lu nsec %lu " + "post_sge_ts 0x%llx cqe_sge_ts 0x%llx " + "poll_sge_ts 0x%llx post_poll_delta_ns %llu " + "cqe_poll_delta_ns %llu\n", + idx, + timespec_sub(lep->poll_host_ts, + prev_ts).tv_sec, + timespec_sub(lep->poll_host_ts, + prev_ts).tv_nsec, + lep->qid, lep->opcode, + lep->opcode == FW_RI_RECEIVE ? + "msn" : "wrid", + lep->wr_id, + timespec_sub(lep->poll_host_ts, + lep->post_host_ts).tv_sec, + timespec_sub(lep->poll_host_ts, + lep->post_host_ts).tv_nsec, + lep->post_sge_ts, lep->cqe_sge_ts, + lep->poll_sge_ts, + ts2ns(lep->poll_sge_ts - lep->post_sge_ts), + ts2ns(lep->poll_sge_ts - lep->cqe_sge_ts)); + prev_ts = lep->poll_host_ts; + } + idx++; + if (idx > (dev->rdev.wr_log_size - 1)) + idx = 0; + lep = &dev->rdev.wr_log[idx]; + } +#undef ts2ns + return 0; +} + +static int wr_log_open(struct inode *inode, struct file *file) +{ + return single_open(file, wr_log_show, inode->i_private); +} + +static ssize_t wr_log_clear(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + struct c4iw_dev *dev = ((struct seq_file *)file->private_data)->private; + int i; + + if (dev->rdev.wr_log) + for (i = 0; i < dev->rdev.wr_log_size; i++) + dev->rdev.wr_log[i].valid = 0; + return count; +} + +static const struct file_operations wr_log_debugfs_fops = { + .owner = THIS_MODULE, + .open = wr_log_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, + .write = wr_log_clear, +}; + static int dump_qp(int id, void *p, void *data) { struct c4iw_qp *qp = p; @@ -604,6 +724,12 @@ static int setup_debugfs(struct c4iw_dev *devp) if (de && de->d_inode) de->d_inode->i_size = 4096; + if (c4iw_wr_log) { + de = debugfs_create_file("wr_log", S_IWUSR, devp->debugfs_root, + (void *)devp, &wr_log_debugfs_fops); + if (de && de->d_inode) + de->d_inode->i_size = 4096; + } return 0; } @@ -717,6 +843,16 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev) pr_err(MOD "error allocating status page\n"); goto err4; } + if (c4iw_wr_log) { + rdev->wr_log = kzalloc((1 << c4iw_wr_log_size_order) * + sizeof(*rdev->wr_log), GFP_KERNEL); + if (rdev->wr_log) { + rdev->wr_log_size = 1 << c4iw_wr_log_size_order; + atomic_set(&rdev->wr_log_idx, 0); + } else { + pr_err(MOD "error allocating wr_log. Logging disabled\n"); + } + } return 0; err4: c4iw_rqtpool_destroy(rdev); @@ -730,6 +866,7 @@ err1: static void c4iw_rdev_close(struct c4iw_rdev *rdev) { + kfree(rdev->wr_log); free_page((unsigned long)rdev->status_page); c4iw_pblpool_destroy(rdev); c4iw_rqtpool_destroy(rdev); diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 75541cb833c6..69f047cdba6a 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -150,6 +150,18 @@ struct c4iw_hw_queue { int t4_stat_len; }; +struct wr_log_entry { + struct timespec post_host_ts; + struct timespec poll_host_ts; + u64 post_sge_ts; + u64 cqe_sge_ts; + u64 poll_sge_ts; + u16 qid; + u16 wr_id; + u8 opcode; + u8 valid; +}; + struct c4iw_rdev { struct c4iw_resource resource; unsigned long qpshift; @@ -169,6 +181,9 @@ struct c4iw_rdev { struct c4iw_stats stats; struct c4iw_hw_queue hw_queue; struct t4_dev_status_page *status_page; + atomic_t wr_log_idx; + struct wr_log_entry *wr_log; + int wr_log_size; }; static inline int c4iw_fatal_error(struct c4iw_rdev *rdev) @@ -1011,6 +1026,8 @@ void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe); extern struct cxgb4_client t4c_client; extern c4iw_handler_func c4iw_handlers[NUM_CPL_CMDS]; +extern void c4iw_log_wr_stats(struct t4_wq *wq, struct t4_cqe *cqe); +extern int c4iw_wr_log; extern int db_fc_threshold; extern int db_coalescing_threshold; extern int use_dsgl; diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 0de3cf64eb5e..fd66bd9a9db0 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -823,6 +823,11 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, qhp->sq_sig_all; swsqe->flushed = 0; swsqe->wr_id = wr->wr_id; + if (c4iw_wr_log) { + swsqe->sge_ts = cxgb4_read_sge_timestamp( + qhp->rhp->rdev.lldi.ports[0]); + getnstimeofday(&swsqe->host_ts); + } init_wr_hdr(wqe, qhp->wq.sq.pidx, fw_opcode, fw_flags, len16); @@ -886,6 +891,13 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, } qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].wr_id = wr->wr_id; + if (c4iw_wr_log) { + qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].sge_ts = + cxgb4_read_sge_timestamp( + qhp->rhp->rdev.lldi.ports[0]); + getnstimeofday( + &qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].host_ts); + } wqe->recv.opcode = FW_RI_RECV_WR; wqe->recv.r1 = 0; diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index dd45186d1c55..c9f7034e6647 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -269,6 +269,8 @@ struct t4_swsqe { int signaled; u16 idx; int flushed; + struct timespec host_ts; + u64 sge_ts; }; static inline pgprot_t t4_pgprot_wc(pgprot_t prot) @@ -306,6 +308,8 @@ struct t4_sq { struct t4_swrqe { u64 wr_id; + struct timespec host_ts; + u64 sge_ts; }; struct t4_rq { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index ba7d13de5e83..9c7e4f0a7683 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -3898,6 +3898,19 @@ err: } EXPORT_SYMBOL(cxgb4_read_tpte); +u64 cxgb4_read_sge_timestamp(struct net_device *dev) +{ + u32 hi, lo; + struct adapter *adap; + + adap = netdev2adap(dev); + lo = t4_read_reg(adap, SGE_TIMESTAMP_LO); + hi = GET_TSVAL(t4_read_reg(adap, SGE_TIMESTAMP_HI)); + + return ((u64)hi << 32) | (u64)lo; +} +EXPORT_SYMBOL(cxgb4_read_sge_timestamp); + static struct pci_driver cxgb4_driver; static void check_neigh_update(struct neighbour *neigh) @@ -4161,6 +4174,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld) lli.wr_cred = adap->params.ofldq_wr_cred; lli.adapter_type = adap->params.chip; lli.iscsi_iolen = MAXRXDATA_GET(t4_read_reg(adap, TP_PARA_REG2)); + lli.cclk_ps = 1000000000 / adap->params.vpd.cclk; lli.udb_density = 1 << QUEUESPERPAGEPF0_GET( t4_read_reg(adap, SGE_EGRESS_QUEUES_PER_PAGE_PF) >> (adap->fn * 4)); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index c7170d68bf63..79a84de1d204 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -243,6 +243,7 @@ struct cxgb4_lld_info { unsigned char fw_api_ver; /* FW API version */ unsigned int fw_vers; /* FW version */ unsigned int iscsi_iolen; /* iSCSI max I/O length */ + unsigned int cclk_ps; /* Core clock period in psec */ unsigned short udb_density; /* # of user DB/page */ unsigned short ucq_density; /* # of user CQs/page */ unsigned short filt_mode; /* filter optional components */ @@ -297,5 +298,6 @@ int cxgb4_flush_eq_cache(struct net_device *dev); void cxgb4_disable_db_coalescing(struct net_device *dev); void cxgb4_enable_db_coalescing(struct net_device *dev); int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte); +u64 cxgb4_read_sge_timestamp(struct net_device *dev); #endif /* !__CXGB4_OFLD_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index ae7776471ceb..3b244abbf907 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -251,6 +251,12 @@ #define V_NOCOALESCE(x) ((x) << S_NOCOALESCE) #define F_NOCOALESCE V_NOCOALESCE(1U) +#define SGE_TIMESTAMP_LO 0x1098 +#define SGE_TIMESTAMP_HI 0x109c +#define S_TSVAL 0 +#define M_TSVAL 0xfffffffU +#define GET_TSVAL(x) (((x) >> S_TSVAL) & M_TSVAL) + #define SGE_TIMER_VALUE_0_AND_1 0x10b8 #define TIMERVALUE0_MASK 0xffff0000U #define TIMERVALUE0_SHIFT 16 -- cgit v1.2.3 From fe8c0f4ac2878bbdbebcbf8a6c7f62c48661111f Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:30:51 +0200 Subject: packet: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/packet/af_packet.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index b85c67ccb797..614ca91f785a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3071,10 +3071,8 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i, break; case PACKET_MR_PROMISC: return dev_set_promiscuity(dev, what); - break; case PACKET_MR_ALLMULTI: return dev_set_allmulti(dev, what); - break; case PACKET_MR_UNICAST: if (i->alen != dev->addr_len) return -EINVAL; -- cgit v1.2.3 From 7ceaa583becacb985ad5803bac0970b8f8cc0d74 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:30:52 +0200 Subject: tipc: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/tipc/socket.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 8c5600cfcc3e..de01622672b2 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2028,7 +2028,6 @@ int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) return 0; } return -EADDRNOTAVAIL; - break; default: return -ENOIOCTLCMD; } -- cgit v1.2.3 From d8282ea05ad119247122de23db7d48ad6098cfa2 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:30:53 +0200 Subject: 9P: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/9p/client.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/9p/client.c b/net/9p/client.c index 0004cbaac4a4..e86a9bea1d16 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -959,7 +959,6 @@ static int p9_client_version(struct p9_client *c) break; default: return -EINVAL; - break; } if (IS_ERR(req)) -- cgit v1.2.3 From 089b03227a503ba2c5a8174900e531764e54db0f Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:30:54 +0200 Subject: af_iucv: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/iucv/af_iucv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 7a95fa4a3de1..d79f5fb695b8 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1103,7 +1103,6 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, default: err = -EINVAL; goto out; - break; } } -- cgit v1.2.3 From 0947611d161c41efd4102b18e7ae768723b18eab Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:30:55 +0200 Subject: netlabel: remove unnecessary break after goto Signed-off-by: Fabian Frederick Acked-by: Paul Moore Signed-off-by: David S. Miller --- net/netlabel/netlabel_kapi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 3045a964f39c..fe9415e5f91d 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -170,7 +170,6 @@ int netlbl_cfg_unlbl_map_add(const char *domain, #endif /* IPv6 */ default: goto cfg_unlbl_map_add_failure; - break; } entry->def.addrsel = addrmap; -- cgit v1.2.3 From aee944ddf893e14a148af0f4e857c11887660053 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:30:56 +0200 Subject: pktgen: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/core/pktgen.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 5b05e364b8ae..8b849ddfef2e 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -804,7 +804,6 @@ static int strn_len(const char __user * user_buffer, unsigned int maxlen) case '\t': case ' ': goto done_str; - break; default: break; } -- cgit v1.2.3 From 4d3520cb529e520554906573e4be0efaa38050fe Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:30:57 +0200 Subject: drop_monitor: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/core/drop_monitor.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index e70301eb7a4a..50f9a9db5792 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -289,10 +289,8 @@ static int net_dm_cmd_trace(struct sk_buff *skb, switch (info->genlhdr->cmd) { case NET_DM_CMD_START: return set_all_monitor_traces(TRACE_ON); - break; case NET_DM_CMD_STOP: return set_all_monitor_traces(TRACE_OFF); - break; } return -ENOTSUPP; -- cgit v1.2.3 From be45dff2900af5a68c07a37144f340fcec2293d8 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:30:58 +0200 Subject: mac80211: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/mac80211/mesh_hwmp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 94758b9c9ed4..214e63b84e5c 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -157,7 +157,6 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, default: kfree_skb(skb); return -ENOTSUPP; - break; } *pos++ = ie_len; *pos++ = flags; -- cgit v1.2.3 From 4ecf1dc7ad031ede37a0eac259b57eebfe375bfa Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:30:59 +0200 Subject: af_key: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/key/af_key.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/key/af_key.c b/net/key/af_key.c index ba2a2f95911c..1847ec4e3930 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -405,7 +405,6 @@ static int verify_address_len(const void *p) * XXX When it can, remove this -EINVAL. -DaveM */ return -EINVAL; - break; } return 0; @@ -536,7 +535,6 @@ pfkey_satype2proto(uint8_t satype) return IPPROTO_ESP; case SADB_X_SATYPE_IPCOMP: return IPPROTO_COMP; - break; default: return 0; } @@ -553,7 +551,6 @@ pfkey_proto2satype(uint16_t proto) return SADB_SATYPE_ESP; case IPPROTO_COMP: return SADB_X_SATYPE_IPCOMP; - break; default: return 0; } -- cgit v1.2.3 From d518825eab84409341d9e90375138ef6d9355b8b Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:36:33 +0200 Subject: netfilter: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/ipv6/netfilter/ip6t_ipv6header.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c index 54bd9790603f..8b147440fbdc 100644 --- a/net/ipv6/netfilter/ip6t_ipv6header.c +++ b/net/ipv6/netfilter/ip6t_ipv6header.c @@ -94,7 +94,6 @@ ipv6header_mt6(const struct sk_buff *skb, struct xt_action_param *par) break; default: return false; - break; } nexthdr = hp->nexthdr; -- cgit v1.2.3 From 66635dc121e1ceb15a4481c221d0721ce1699523 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:36:34 +0200 Subject: ipv6: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/ipv6/ipv6_sockglue.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index b50b9e54cf53..0c289982796d 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -1162,7 +1162,6 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, return -EFAULT; return 0; - break; } case IPV6_TRANSPARENT: -- cgit v1.2.3 From 6c4c170105f0113999c41a0e848ba4dca40a5725 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:36:35 +0200 Subject: NFC: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/nfc/digital_dep.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index 171cb9949ab5..37deb173c956 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c @@ -457,12 +457,10 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, pr_err("Received a ACK/NACK PDU\n"); rc = -EINVAL; goto exit; - break; case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: pr_err("Received a SUPERVISOR PDU\n"); rc = -EINVAL; goto exit; - break; } skb_pull(resp, size); -- cgit v1.2.3 From 1f7a316f9ba5ea743c95b5fcc472fa3caf8fec98 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:36:36 +0200 Subject: caif: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/caif/cfctrl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c index 0f455227da83..f5afda1abc76 100644 --- a/net/caif/cfctrl.c +++ b/net/caif/cfctrl.c @@ -547,7 +547,6 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) default: pr_err("Unrecognized Control Frame\n"); goto error; - break; } ret = 0; error: -- cgit v1.2.3 From f301f22f36a031f767de1002735adf639230e1de Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:36:37 +0200 Subject: irda: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/irda/af_irda.c | 1 - net/irda/irlan/irlan_common.c | 1 - 2 files changed, 2 deletions(-) diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 54747c25c86c..92fafd485deb 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -674,7 +674,6 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name) self->daddr = DEV_ADDR_ANY; kfree(discoveries); return -EHOSTUNREACH; - break; } } /* Cleanup our copy of the discovery log */ diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index 7ac4d1becbfc..1bc49edf2296 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c @@ -1024,7 +1024,6 @@ static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, default: IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __func__ ); return 0; - break; } /* Insert at end of sk-buffer */ -- cgit v1.2.3 From 84dbee1869668284fb5e1008c8ee0710d9c23709 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:36:38 +0200 Subject: ieee802154: remove unnecessary break after goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/ieee802154/6lowpan_iphc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ieee802154/6lowpan_iphc.c b/net/ieee802154/6lowpan_iphc.c index 511ddeee7353..a1b7117a9600 100644 --- a/net/ieee802154/6lowpan_iphc.c +++ b/net/ieee802154/6lowpan_iphc.c @@ -297,7 +297,6 @@ uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) default: pr_debug("ERROR: unknown UDP format\n"); goto err; - break; } pr_debug("uncompressed UDP ports: src = %d, dst = %d\n", -- cgit v1.2.3 From 138ce9102468ef3ad42214b2878004522f357a2a Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 14 Jul 2014 18:36:39 +0200 Subject: net: sctp: remove unnecessary break after return/goto Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- net/sctp/outqueue.c | 1 - net/sctp/sm_statefuns.c | 4 ---- 2 files changed, 5 deletions(-) diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 9c77947c0597..d31435e559b2 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -1025,7 +1025,6 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) sctp_outq_head_data(q, chunk); goto sctp_flush_out; - break; case SCTP_XMIT_OK: /* The sender is in the SHUTDOWN-PENDING state, diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 5170a1ff95a1..d3f1ea460c50 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -4182,7 +4182,6 @@ sctp_disposition_t sctp_sf_unk_chunk(struct net *net, case SCTP_CID_ACTION_DISCARD: /* Discard the packet. */ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); - break; case SCTP_CID_ACTION_DISCARD_ERR: /* Generate an ERROR chunk as response. */ hdr = unk_chunk->chunk_hdr; @@ -4198,11 +4197,9 @@ sctp_disposition_t sctp_sf_unk_chunk(struct net *net, /* Discard the packet. */ sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); return SCTP_DISPOSITION_CONSUME; - break; case SCTP_CID_ACTION_SKIP: /* Skip the chunk. */ return SCTP_DISPOSITION_DISCARD; - break; case SCTP_CID_ACTION_SKIP_ERR: /* Generate an ERROR chunk as response. */ hdr = unk_chunk->chunk_hdr; @@ -4216,7 +4213,6 @@ sctp_disposition_t sctp_sf_unk_chunk(struct net *net, } /* Skip the chunk. */ return SCTP_DISPOSITION_CONSUME; - break; default: break; } -- cgit v1.2.3 From 3e7077067e80cdded012b7db19b7aae33ceb01e9 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Mon, 14 Jul 2014 14:05:46 -0500 Subject: phy: Expand phy speed/duplex settings array Expand the phy speed/duplex settings array to support more than just baseT features. This change adds entries to support the following additional speed/duplex/media types: SUPPORTED_10000baseKR_Full SUPPORTED_10000baseKX4_Full SUPPORTED_2500baseX_Full SUPPORTED_1000baseKX_Full Additionally, it changes the 10GbE baseT entry from using the hardcoded value 10000 to the SPEED_10000 define. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index f7c61812ea4a..e56e269a6eb3 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -138,10 +138,30 @@ struct phy_setting { /* A mapping of all SUPPORTED settings to speed/duplex */ static const struct phy_setting settings[] = { { - .speed = 10000, + .speed = SPEED_10000, + .duplex = DUPLEX_FULL, + .setting = SUPPORTED_10000baseKR_Full, + }, + { + .speed = SPEED_10000, + .duplex = DUPLEX_FULL, + .setting = SUPPORTED_10000baseKX4_Full, + }, + { + .speed = SPEED_10000, .duplex = DUPLEX_FULL, .setting = SUPPORTED_10000baseT_Full, }, + { + .speed = SPEED_2500, + .duplex = DUPLEX_FULL, + .setting = SUPPORTED_2500baseX_Full, + }, + { + .speed = SPEED_1000, + .duplex = DUPLEX_FULL, + .setting = SUPPORTED_1000baseKX_Full, + }, { .speed = SPEED_1000, .duplex = DUPLEX_FULL, -- cgit v1.2.3 From 6964e97051146c2dcac99065e0c0367cf76c829a Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Mon, 14 Jul 2014 14:05:52 -0500 Subject: amd-xgbe: Remove the adjustments needed for fixed speed With the addition of entries in the phy speed/duplex settings array to support KR and KX mode, the work-around to add/remove baseT settings to run at a fixed speed is no longer needed. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 10 ---------- drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 4 ---- 2 files changed, 14 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index 8909f2b51af1..f7405261f23e 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -331,16 +331,6 @@ static int xgbe_set_settings(struct net_device *netdev, (cmd->duplex != DUPLEX_FULL))) goto unlock; - if (cmd->autoneg == AUTONEG_ENABLE) { - /* Clear settings needed to force speeds */ - phydev->supported &= ~SUPPORTED_1000baseT_Full; - phydev->supported &= ~SUPPORTED_10000baseT_Full; - } else { - /* Add settings needed to force speed */ - phydev->supported |= SUPPORTED_1000baseT_Full; - phydev->supported |= SUPPORTED_10000baseT_Full; - } - cmd->advertising &= phydev->supported; if ((cmd->autoneg == AUTONEG_ENABLE) && !cmd->advertising) goto unlock; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index ea7a5d6750ea..225f22d5fe0a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -375,10 +375,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) phydev->autoneg = pdata->default_autoneg; if (phydev->autoneg == AUTONEG_DISABLE) { - /* Add settings needed to force speed */ - phydev->supported |= SUPPORTED_1000baseT_Full; - phydev->supported |= SUPPORTED_10000baseT_Full; - phydev->speed = pdata->default_speed; phydev->duplex = DUPLEX_FULL; -- cgit v1.2.3 From 11878b40ed5c5bc20d6a115bae156a5b90b0fb3e Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 14 Jul 2014 17:55:06 -0400 Subject: net-timestamp: SOCK_RAW and PING timestamping Add SO_TIMESTAMPING to sockets of type PF_INET[6]/SOCK_RAW: Add the necessary sock_tx_timestamp calls to the datapath for RAW sockets (ping sockets already had these calls). Fix the IP output path to pass the timestamp flags on the first fragment also for these sockets. The existing code relies on transhdrlen != 0 to indicate a first fragment. For these sockets, that assumption does not hold. This fixes http://bugzilla.kernel.org/show_bug.cgi?id=77221 Tested SOCK_RAW on IPv4 and IPv6, not PING. Signed-off-by: Willem de Bruijn Acked-by: Richard Cochran Signed-off-by: David S. Miller --- net/ipv4/ip_output.c | 7 +++---- net/ipv4/raw.c | 4 ++++ net/ipv6/ip6_output.c | 13 ++++--------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 8d3b6b0e9857..b16556836d66 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -962,10 +962,6 @@ alloc_new_skb: sk->sk_allocation); if (unlikely(skb == NULL)) err = -ENOBUFS; - else - /* only the initial fragment is - time stamped */ - cork->tx_flags = 0; } if (skb == NULL) goto error; @@ -976,7 +972,10 @@ alloc_new_skb: skb->ip_summed = csummode; skb->csum = 0; skb_reserve(skb, hh_len); + + /* only the initial fragment is time stamped */ skb_shinfo(skb)->tx_flags = cork->tx_flags; + cork->tx_flags = 0; /* * Find where to start putting bytes. diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 2c65160565e1..2054d7136c62 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -365,6 +365,8 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, skb->ip_summed = CHECKSUM_NONE; + sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags); + skb->transport_header = skb->network_header; err = -EFAULT; if (memcpy_fromiovecend((void *)iph, from, 0, length)) @@ -606,6 +608,8 @@ back_from_confirm: &rt, msg->msg_flags); else { + sock_tx_timestamp(sk, &ipc.tx_flags); + if (!ipc.addr) ipc.addr = fl4.daddr; lock_sock(sk); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9b395c639a07..759456f0c207 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1271,7 +1271,7 @@ emsgsize: } /* For UDP, check if TX timestamp is enabled */ - if (sk->sk_type == SOCK_DGRAM) + if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) sock_tx_timestamp(sk, &tx_flags); /* @@ -1380,12 +1380,6 @@ alloc_new_skb: sk->sk_allocation); if (unlikely(skb == NULL)) err = -ENOBUFS; - else { - /* Only the initial fragment - * is time stamped. - */ - tx_flags = 0; - } } if (skb == NULL) goto error; @@ -1399,8 +1393,9 @@ alloc_new_skb: skb_reserve(skb, hh_len + sizeof(struct frag_hdr) + dst_exthdrlen); - if (sk->sk_type == SOCK_DGRAM) - skb_shinfo(skb)->tx_flags = tx_flags; + /* Only the initial fragment is time stamped */ + skb_shinfo(skb)->tx_flags = tx_flags; + tx_flags = 0; /* * Find where to start putting bytes -- cgit v1.2.3 From 26c4fdb0528ae7c4be9fbc8a8210f3b410e6b5aa Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 14 Jul 2014 17:55:30 -0400 Subject: net-timestamp: document deprecated syststamp The SO_TIMESTAMPING API defines option SOF_TIMESTAMPING_SYS_HW. This feature is deprecated. It should not be implemented by new device drivers. Existing drivers do not implement it, either -- with one exception. Driver developers are encouraged to expose the NIC hw clock as a PTP HW clock source, instead, and synchronize system time to the HW source. The control flag cannot be removed due to being part of the ABI, nor can the structure scm_timestamping that is returned. Due to the one legacy driver, the internal datapath and structure are not removed. This patch only clearly marks the interface as deprecated. Device drivers should always return a syststamp value of zero. Signed-off-by: Willem de Bruijn ---- We can consider adding a WARN_ON_ONCE in__sock_recv_timestamp if non-zero syststamp is encountered Acked-by: Richard Cochran Signed-off-by: David S. Miller --- Documentation/networking/timestamping.txt | 10 ++++++++-- include/linux/skbuff.h | 6 ++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index bc3554124903..8b4ad809df27 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt @@ -40,7 +40,7 @@ the set bits correspond to data that is available, then the control message will not be generated: SOF_TIMESTAMPING_SOFTWARE: report systime if available -SOF_TIMESTAMPING_SYS_HARDWARE: report hwtimetrans if available +SOF_TIMESTAMPING_SYS_HARDWARE: report hwtimetrans if available (deprecated) SOF_TIMESTAMPING_RAW_HARDWARE: report hwtimeraw if available It is worth noting that timestamps may be collected for reasons other @@ -94,7 +94,13 @@ not perfect; as a consequence, sorting packets received via different NICs by their hwtimetrans may differ from the order in which they were received. hwtimetrans may be non-monotonic even for the same NIC. Filled in if SOF_TIMESTAMPING_SYS_HARDWARE is set. Requires support -by the network device and will be empty without that support. +by the network device and will be empty without that support. This +field is DEPRECATED. Only one driver computes this value. New device +drivers must leave this zero. Instead, they can expose the hardware +clock device on the NIC directly as a HW PTP clock source, to allow +time conversion in userspace and optionally synchronize system time +with a userspace PTP stack such as linuxptp. For the PTP clock API, +see Documentation/ptp/ptp.txt. SIOCSHWTSTAMP, SIOCGHWTSTAMP: diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 890fb3307dd6..369430340ed9 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -211,7 +211,7 @@ static inline void skb_frag_size_sub(skb_frag_t *frag, int delta) * struct skb_shared_hwtstamps - hardware time stamps * @hwtstamp: hardware time stamp transformed into duration * since arbitrary point in time - * @syststamp: hwtstamp transformed to system time base + * @syststamp: hwtstamp transformed to system time base (deprecated) * * Software time stamps generated by ktime_get_real() are stored in * skb->tstamp. The relation between the different kinds of time @@ -222,7 +222,9 @@ static inline void skb_frag_size_sub(skb_frag_t *frag, int delta) * syststamp/tstamp/"syststamp from other device" comparison is * limited by the accuracy of the transformation into system time * base. This depends on the device driver and its underlying - * hardware. + * hardware. The syststamp implementation is deprecated in favor + * of hwtstamps and hw PTP clock sources exposed directly to + * userspace. * * hwtstamps can only be compared against other hwtstamps from * the same device. -- cgit v1.2.3 From e965f8049460569bab12fe7bb5381bb2279712e2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 15 Jul 2014 06:56:53 -0700 Subject: bonding: get rid of bond_option_active_slave_get() Only keep bond_option_active_slave_get_rcu() helper. bond_fill_info() uses a new bond_option_active_slave_get_ifindex() helper. Signed-off-by: Eric Dumazet Acked-by: Veaceslav Falico Reviewed-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 21 ++++++++++++++++----- drivers/net/bonding/bond_options.c | 5 ----- drivers/net/bonding/bonding.h | 1 - 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 5ab3c1847e67..4d97e23eb497 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -398,20 +398,31 @@ static size_t bond_get_size(const struct net_device *bond_dev) 0; } +static int bond_option_active_slave_get_ifindex(struct bonding *bond) +{ + const struct net_device *slave; + int ifindex; + + rcu_read_lock(); + slave = bond_option_active_slave_get_rcu(bond); + ifindex = slave ? slave->ifindex : 0; + rcu_read_unlock(); + return ifindex; +} + static int bond_fill_info(struct sk_buff *skb, const struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); - struct net_device *slave_dev = bond_option_active_slave_get(bond); - struct nlattr *targets; unsigned int packets_per_slave; - int i, targets_added; + int ifindex, i, targets_added; + struct nlattr *targets; if (nla_put_u8(skb, IFLA_BOND_MODE, BOND_MODE(bond))) goto nla_put_failure; - if (slave_dev && - nla_put_u32(skb, IFLA_BOND_ACTIVE_SLAVE, slave_dev->ifindex)) + ifindex = bond_option_active_slave_get_ifindex(bond); + if (ifindex && nla_put_u32(skb, IFLA_BOND_ACTIVE_SLAVE, ifindex)) goto nla_put_failure; if (nla_put_u32(skb, IFLA_BOND_MIIMON, bond->params.miimon)) diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 540e0167bf24..b26271fd7b09 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -704,11 +704,6 @@ struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond) return __bond_option_active_slave_get(bond, slave); } -struct net_device *bond_option_active_slave_get(struct bonding *bond) -{ - return __bond_option_active_slave_get(bond, bond->curr_active_slave); -} - static int bond_option_active_slave_set(struct bonding *bond, const struct bond_opt_value *newval) { diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 0b4d9cde0b05..713e2a99c661 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -514,7 +514,6 @@ unsigned int bond_get_num_tx_queues(void); int bond_netlink_init(void); void bond_netlink_fini(void); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); -struct net_device *bond_option_active_slave_get(struct bonding *bond); const char *bond_slave_link_status(s8 link); bool bond_verify_device_path(struct net_device *start_dev, struct net_device *end_dev, -- cgit v1.2.3 From c2646b593eb127adc50e108649e4d34144e14c6c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 15 Jul 2014 06:56:54 -0700 Subject: bonding: use rcu_access_pointer() in bonding_show_mii_status() curr_active_slave is rcu protected, and bonding_show_mii_status() only wants to check if pointer is NULL or not. Signed-off-by: Eric Dumazet Acked-by: Veaceslav Falico Reviewed-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_sysfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index daed52f68ce1..98db8edd9c75 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -492,8 +492,9 @@ static ssize_t bonding_show_mii_status(struct device *d, char *buf) { struct bonding *bond = to_bond(d); + bool active = !!rcu_access_pointer(bond->curr_active_slave); - return sprintf(buf, "%s\n", bond->curr_active_slave ? "up" : "down"); + return sprintf(buf, "%s\n", active ? "up" : "down"); } static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); -- cgit v1.2.3 From 4740d6382790077f22c606d03804f5d9f15b90d7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 15 Jul 2014 06:56:55 -0700 Subject: bonding: add proper __rcu annotation for curr_active_slave RCU was added to bonding in linux-3.12 but lacked proper sparse annotations. Using __rcu annotation actually helps to spot all accesses to bond->curr_active_slave are correctly protected, with LOCKDEP support. Signed-off-by: Eric Dumazet Acked-by: Veaceslav Falico Reviewed-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.c | 47 +++++++++++++++++++-------------- drivers/net/bonding/bond_main.c | 53 +++++++++++++++++++++----------------- drivers/net/bonding/bond_options.c | 2 +- drivers/net/bonding/bonding.h | 6 ++++- 4 files changed, 63 insertions(+), 45 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 76c0dade233f..de5bd03925b4 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -448,11 +448,13 @@ static struct slave *__rlb_next_rx_slave(struct bonding *bond) */ static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) { - if (!bond->curr_active_slave) + struct slave *curr_active = bond_deref_active_protected(bond); + + if (!curr_active) return; if (!bond->alb_info.primary_is_promisc) { - if (!dev_set_promiscuity(bond->curr_active_slave->dev, 1)) + if (!dev_set_promiscuity(curr_active->dev, 1)) bond->alb_info.primary_is_promisc = 1; else bond->alb_info.primary_is_promisc = 0; @@ -460,7 +462,7 @@ static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) bond->alb_info.rlb_promisc_timeout_counter = 0; - alb_send_learning_packets(bond->curr_active_slave, addr, true); + alb_send_learning_packets(curr_active, addr, true); } /* slave being removed should not be active at this point @@ -509,7 +511,7 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave) write_lock_bh(&bond->curr_slave_lock); - if (slave != bond->curr_active_slave) + if (slave != bond_deref_active_protected(bond)) rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr); write_unlock_bh(&bond->curr_slave_lock); @@ -684,7 +686,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon * move the old client to primary (curr_active_slave) so * that the new client can be assigned to this entry. */ - if (bond->curr_active_slave && + if (curr_active_slave && client_info->slave != curr_active_slave) { client_info->slave = curr_active_slave; rlb_update_client(client_info); @@ -1221,7 +1223,7 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla */ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) { - struct slave *has_bond_addr = bond->curr_active_slave; + struct slave *has_bond_addr = rcu_access_pointer(bond->curr_active_slave); struct slave *tmp_slave1, *free_mac_slave = NULL; struct list_head *iter; @@ -1575,7 +1577,7 @@ void bond_alb_monitor(struct work_struct *work) * use mac of the slave device. * In RLB mode, we always use strict matches. */ - strict_match = (slave != bond->curr_active_slave || + strict_match = (slave != rcu_access_pointer(bond->curr_active_slave) || bond_info->rlb_enabled); alb_send_learning_packets(slave, slave->dev->dev_addr, strict_match); @@ -1593,7 +1595,7 @@ void bond_alb_monitor(struct work_struct *work) bond_for_each_slave_rcu(bond, slave, iter) { tlb_clear_slave(bond, slave, 1); - if (slave == bond->curr_active_slave) { + if (slave == rcu_access_pointer(bond->curr_active_slave)) { SLAVE_TLB_INFO(slave).load = bond_info->unbalanced_load / BOND_TLB_REBALANCE_INTERVAL; @@ -1625,7 +1627,8 @@ void bond_alb_monitor(struct work_struct *work) * because a slave was disabled then * it can now leave promiscuous mode. */ - dev_set_promiscuity(bond->curr_active_slave->dev, -1); + dev_set_promiscuity(rtnl_dereference(bond->curr_active_slave)->dev, + -1); bond_info->primary_is_promisc = 0; rtnl_unlock(); @@ -1742,17 +1745,21 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave __acquires(&bond->curr_slave_lock) { struct slave *swap_slave; + struct slave *curr_active; - if (bond->curr_active_slave == new_slave) + curr_active = rcu_dereference_protected(bond->curr_active_slave, + !new_slave || + lockdep_is_held(&bond->curr_slave_lock)); + if (curr_active == new_slave) return; - if (bond->curr_active_slave && bond->alb_info.primary_is_promisc) { - dev_set_promiscuity(bond->curr_active_slave->dev, -1); + if (curr_active && bond->alb_info.primary_is_promisc) { + dev_set_promiscuity(curr_active->dev, -1); bond->alb_info.primary_is_promisc = 0; bond->alb_info.rlb_promisc_timeout_counter = 0; } - swap_slave = bond->curr_active_slave; + swap_slave = curr_active; rcu_assign_pointer(bond->curr_active_slave, new_slave); if (!new_slave || !bond_has_slaves(bond)) @@ -1818,6 +1825,7 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) { struct bonding *bond = netdev_priv(bond_dev); struct sockaddr *sa = addr; + struct slave *curr_active; struct slave *swap_slave; int res; @@ -1834,23 +1842,24 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) * Otherwise we'll need to pass the new address to it and handle * duplications. */ - if (!bond->curr_active_slave) + curr_active = rtnl_dereference(bond->curr_active_slave); + if (!curr_active) return 0; swap_slave = bond_slave_has_mac(bond, bond_dev->dev_addr); if (swap_slave) { - alb_swap_mac_addr(swap_slave, bond->curr_active_slave); - alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave); + alb_swap_mac_addr(swap_slave, curr_active); + alb_fasten_mac_swap(bond, swap_slave, curr_active); } else { - alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr); + alb_set_slave_mac_addr(curr_active, bond_dev->dev_addr); read_lock(&bond->lock); - alb_send_learning_packets(bond->curr_active_slave, + alb_send_learning_packets(curr_active, bond_dev->dev_addr, false); if (bond->alb_info.rlb_enabled) { /* inform clients mac address has changed */ - rlb_req_update_slave_clients(bond, bond->curr_active_slave); + rlb_req_update_slave_clients(bond, curr_active); } read_unlock(&bond->lock); } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 46dcb7b6216f..27ce838d45d6 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -498,11 +498,11 @@ static int bond_set_promiscuity(struct bonding *bond, int inc) int err = 0; if (bond_uses_primary(bond)) { + struct slave *curr_active = bond_deref_active_protected(bond); + /* write lock already acquired */ - if (bond->curr_active_slave) { - err = dev_set_promiscuity(bond->curr_active_slave->dev, - inc); - } + if (curr_active) + err = dev_set_promiscuity(curr_active->dev, inc); } else { struct slave *slave; @@ -524,11 +524,11 @@ static int bond_set_allmulti(struct bonding *bond, int inc) int err = 0; if (bond_uses_primary(bond)) { + struct slave *curr_active = bond_deref_active_protected(bond); + /* write lock already acquired */ - if (bond->curr_active_slave) { - err = dev_set_allmulti(bond->curr_active_slave->dev, - inc); - } + if (curr_active) + err = dev_set_allmulti(curr_active->dev, inc); } else { struct slave *slave; @@ -713,7 +713,7 @@ out: static bool bond_should_change_active(struct bonding *bond) { struct slave *prim = bond->primary_slave; - struct slave *curr = bond->curr_active_slave; + struct slave *curr = bond_deref_active_protected(bond); if (!prim || !curr || curr->link != BOND_LINK_UP) return true; @@ -792,7 +792,11 @@ static bool bond_should_notify_peers(struct bonding *bond) */ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) { - struct slave *old_active = bond->curr_active_slave; + struct slave *old_active; + + old_active = rcu_dereference_protected(bond->curr_active_slave, + !new_active || + lockdep_is_held(&bond->curr_slave_lock)); if (old_active == new_active) return; @@ -900,7 +904,7 @@ void bond_select_active_slave(struct bonding *bond) int rv; best_slave = bond_find_best_slave(bond); - if (best_slave != bond->curr_active_slave) { + if (best_slave != bond_deref_active_protected(bond)) { bond_change_active_slave(bond, best_slave); rv = bond_set_carrier(bond); if (!rv) @@ -1531,7 +1535,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * anyway (it holds no special properties of the bond device), * so we can change it without calling change_active_interface() */ - if (!bond->curr_active_slave && new_slave->link == BOND_LINK_UP) + if (!rcu_access_pointer(bond->curr_active_slave) && + new_slave->link == BOND_LINK_UP) rcu_assign_pointer(bond->curr_active_slave, new_slave); break; @@ -1602,7 +1607,7 @@ err_detach: vlan_vids_del_by_dev(slave_dev, bond_dev); if (bond->primary_slave == new_slave) bond->primary_slave = NULL; - if (bond->curr_active_slave == new_slave) { + if (rcu_access_pointer(bond->curr_active_slave) == new_slave) { block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); bond_change_active_slave(bond, NULL); @@ -1704,7 +1709,7 @@ static int __bond_release_one(struct net_device *bond_dev, bond_is_active_slave(slave) ? "active" : "backup", slave_dev->name); - oldcurrent = bond->curr_active_slave; + oldcurrent = rcu_access_pointer(bond->curr_active_slave); bond->current_arp_slave = NULL; @@ -1878,7 +1883,7 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in /*-------------------------------- Monitoring -------------------------------*/ - +/* called with rcu_read_lock() */ static int bond_miimon_inspect(struct bonding *bond) { int link_state, commit = 0; @@ -1886,7 +1891,7 @@ static int bond_miimon_inspect(struct bonding *bond) struct slave *slave; bool ignore_updelay; - ignore_updelay = !bond->curr_active_slave ? true : false; + ignore_updelay = !rcu_dereference(bond->curr_active_slave); bond_for_each_slave_rcu(bond, slave, iter) { slave->new_link = BOND_LINK_NOCHANGE; @@ -2046,7 +2051,7 @@ static void bond_miimon_commit(struct bonding *bond) bond_alb_handle_link_change(bond, slave, BOND_LINK_DOWN); - if (slave == bond->curr_active_slave) + if (slave == rcu_access_pointer(bond->curr_active_slave)) goto do_failover; continue; @@ -2416,7 +2421,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) rcu_read_lock(); - oldcurrent = ACCESS_ONCE(bond->curr_active_slave); + oldcurrent = rcu_dereference(bond->curr_active_slave); /* see if any of the previous devices are up now (i.e. they have * xmt and rcv traffic). the curr_active_slave does not come into * the picture unless it is null. also, slave->last_link_up is not @@ -2607,8 +2612,8 @@ static void bond_ab_arp_commit(struct bonding *bond) case BOND_LINK_UP: trans_start = dev_trans_start(slave->dev); - if (bond->curr_active_slave != slave || - (!bond->curr_active_slave && + if (rtnl_dereference(bond->curr_active_slave) != slave || + (!rtnl_dereference(bond->curr_active_slave) && bond_time_in_interval(bond, trans_start, 1))) { slave->link = BOND_LINK_UP; if (bond->current_arp_slave) { @@ -2621,7 +2626,7 @@ static void bond_ab_arp_commit(struct bonding *bond) pr_info("%s: link status definitely up for interface %s\n", bond->dev->name, slave->dev->name); - if (!bond->curr_active_slave || + if (!rtnl_dereference(bond->curr_active_slave) || (slave == bond->primary_slave)) goto do_failover; @@ -2640,7 +2645,7 @@ static void bond_ab_arp_commit(struct bonding *bond) pr_info("%s: link status definitely down for interface %s, disabling it\n", bond->dev->name, slave->dev->name); - if (slave == bond->curr_active_slave) { + if (slave == rtnl_dereference(bond->curr_active_slave)) { bond->current_arp_slave = NULL; goto do_failover; } @@ -3097,8 +3102,8 @@ static int bond_open(struct net_device *bond_dev) if (bond_has_slaves(bond)) { read_lock(&bond->curr_slave_lock); bond_for_each_slave(bond, slave, iter) { - if (bond_uses_primary(bond) - && (slave != bond->curr_active_slave)) { + if (bond_uses_primary(bond) && + slave != rcu_access_pointer(bond->curr_active_slave)) { bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW); } else { diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index b26271fd7b09..f908e65e86c1 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -743,7 +743,7 @@ static int bond_option_active_slave_set(struct bonding *bond, RCU_INIT_POINTER(bond->curr_active_slave, NULL); bond_select_active_slave(bond); } else { - struct slave *old_active = bond->curr_active_slave; + struct slave *old_active = bond_deref_active_protected(bond); struct slave *new_active = bond_slave_get_rtnl(slave_dev); BUG_ON(!new_active); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 713e2a99c661..d03d2ae4d3af 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -194,7 +194,7 @@ struct slave { */ struct bonding { struct net_device *dev; /* first - useful for panic debug */ - struct slave *curr_active_slave; + struct slave __rcu *curr_active_slave; struct slave *current_arp_slave; struct slave *primary_slave; bool force_primary; @@ -232,6 +232,10 @@ struct bonding { #define bond_slave_get_rtnl(dev) \ ((struct slave *) rtnl_dereference(dev->rx_handler_data)) +#define bond_deref_active_protected(bond) \ + rcu_dereference_protected(bond->curr_active_slave, \ + lockdep_is_held(&bond->curr_slave_lock)) + struct bond_vlan_tag { __be16 vlan_proto; unsigned short vlan_id; -- cgit v1.2.3 From 8574171833b24fda5101e1aa892a38c0d91d083e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 15 Jul 2014 06:56:56 -0700 Subject: bonding: add proper __rcu annotation for current_arp_slave Using __rcu annotation actually helps to spot all accesses to bond->current_arp_slave are correctly protected, with LOCKDEP support. Signed-off-by: Eric Dumazet Reviewed-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 15 +++++++++------ drivers/net/bonding/bonding.h | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 27ce838d45d6..6d3b8db882a1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1711,7 +1711,7 @@ static int __bond_release_one(struct net_device *bond_dev, oldcurrent = rcu_access_pointer(bond->curr_active_slave); - bond->current_arp_slave = NULL; + RCU_INIT_POINTER(bond->current_arp_slave, NULL); if (!all && (!bond->params.fail_over_mac || BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP)) { @@ -2569,7 +2569,7 @@ static int bond_ab_arp_inspect(struct bonding *bond) * before being taken out */ if (!bond_is_active_slave(slave) && - !bond->current_arp_slave && + !rcu_access_pointer(bond->current_arp_slave) && !bond_time_in_interval(bond, last_rx, 3)) { slave->new_link = BOND_LINK_DOWN; commit++; @@ -2615,12 +2615,15 @@ static void bond_ab_arp_commit(struct bonding *bond) if (rtnl_dereference(bond->curr_active_slave) != slave || (!rtnl_dereference(bond->curr_active_slave) && bond_time_in_interval(bond, trans_start, 1))) { + struct slave *current_arp_slave; + + current_arp_slave = rtnl_dereference(bond->current_arp_slave); slave->link = BOND_LINK_UP; - if (bond->current_arp_slave) { + if (current_arp_slave) { bond_set_slave_inactive_flags( - bond->current_arp_slave, + current_arp_slave, BOND_SLAVE_NOTIFY_NOW); - bond->current_arp_slave = NULL; + RCU_INIT_POINTER(bond->current_arp_slave, NULL); } pr_info("%s: link status definitely up for interface %s\n", @@ -2646,7 +2649,7 @@ static void bond_ab_arp_commit(struct bonding *bond) bond->dev->name, slave->dev->name); if (slave == rtnl_dereference(bond->curr_active_slave)) { - bond->current_arp_slave = NULL; + RCU_INIT_POINTER(bond->current_arp_slave, NULL); goto do_failover; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index d03d2ae4d3af..b2e548e9d738 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -195,7 +195,7 @@ struct slave { struct bonding { struct net_device *dev; /* first - useful for panic debug */ struct slave __rcu *curr_active_slave; - struct slave *current_arp_slave; + struct slave __rcu *current_arp_slave; struct slave *primary_slave; bool force_primary; s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ -- cgit v1.2.3 From b734427a4fbe4e129c6536a726e93c0d801e5cd0 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 20 Jun 2014 22:35:42 +0200 Subject: ipvs: remove null test before kfree Fix checkpatch warning: WARNING: kfree(NULL) is safe this check is probably not required Signed-off-by: Fabian Frederick Signed-off-by: Simon Horman --- net/netfilter/ipvs/ip_vs_sync.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index db801263ee9f..eadffb29dec0 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -886,8 +886,7 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param, cp = ip_vs_conn_new(param, daddr, dport, flags, dest, fwmark); rcu_read_unlock(); if (!cp) { - if (param->pe_data) - kfree(param->pe_data); + kfree(param->pe_data); IP_VS_DBG(2, "BACKUP, add new conn. failed\n"); return; } -- cgit v1.2.3 From 16ea4c6b9dde2ff44b2bd8bb459daa283cf3a46e Mon Sep 17 00:00:00 2001 From: Yannick Brosseau Date: Thu, 26 Jun 2014 19:10:26 -0700 Subject: ipvs: Remove dead debug code This code section cannot compile as it refer to non existing variable It also pre-date git history. Signed-off-by: Yannick Brosseau Signed-off-by: Simon Horman --- net/netfilter/ipvs/ip_vs_ctl.c | 86 ------------------------------------------ 1 file changed, 86 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index c42e83d2751c..335fdb80beb6 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1806,92 +1806,6 @@ static struct ctl_table vs_vars[] = { .mode = 0644, .proc_handler = proc_dointvec, }, -#endif -#if 0 - { - .procname = "timeout_established", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_ESTABLISHED], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "timeout_synsent", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_SYN_SENT], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "timeout_synrecv", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_SYN_RECV], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "timeout_finwait", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_FIN_WAIT], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "timeout_timewait", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_TIME_WAIT], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "timeout_close", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "timeout_closewait", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE_WAIT], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "timeout_lastack", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_LAST_ACK], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "timeout_listen", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_LISTEN], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "timeout_synack", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_SYNACK], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "timeout_udp", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_UDP], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "timeout_icmp", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_ICMP], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, #endif { } }; -- cgit v1.2.3 From d762d038497c9df51c19fcbe69b094b3bf8e5568 Mon Sep 17 00:00:00 2001 From: Christoph Schulz Date: Tue, 15 Jul 2014 11:51:03 +0200 Subject: net: ppp: reset nextseq counter when enabling SC_MULTILINK If using a demand-dialled PPP unit for a PPP multilink master, the pppd daemon needs to reset the sequence counter between two connections. This allows the daemon to reuse the PPP unit instead of destroying and recreating it. As there is no API to reset the counter, this patch resets the counter whenever the SC_MULTILINK flag is set. Signed-off-by: Christoph Schulz Signed-off-by: David S. Miller --- drivers/net/ppp/ppp_generic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 5c002b1ef169..c38ee903bd59 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -661,6 +661,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; ppp_lock(ppp); cflags = ppp->flags & ~val; + if (!(ppp->flags & SC_MULTILINK) && (val & SC_MULTILINK)) + ppp->nextseq = 0; ppp->flags = val & SC_FLAG_BITS; ppp_unlock(ppp); if (cflags & SC_CCP_OPEN) -- cgit v1.2.3 From e4d112e4f9502083fd27f9ac1a4cd690e3f01421 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Tue, 15 Jul 2014 11:58:12 +0100 Subject: sfc: add extra RX drop counters for nodesc_trunc and noskb_drop Added a counter rx_noskb_drop for failure to allocate an skb. Summed the per-channel rx_nodesc_trunc counters earlier so that they can be included in rx_dropped. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 14 +++++++++++--- drivers/net/ethernet/sfc/efx.c | 11 +++++++++++ drivers/net/ethernet/sfc/efx.h | 3 +++ drivers/net/ethernet/sfc/ethtool.c | 1 - drivers/net/ethernet/sfc/falcon.c | 9 ++++++++- drivers/net/ethernet/sfc/net_driver.h | 2 ++ drivers/net/ethernet/sfc/nic.h | 13 ++++++++++--- drivers/net/ethernet/sfc/rx.c | 4 +++- drivers/net/ethernet/sfc/siena.c | 9 ++++++++- 9 files changed, 56 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index b5ed30a39144..002d4cdc319f 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -755,6 +755,8 @@ static int efx_ef10_reset(struct efx_nic *efx, enum reset_type reset_type) { NULL, 64, 8 * MC_CMD_MAC_ ## mcdi_name } #define EF10_OTHER_STAT(ext_name) \ [EF10_STAT_ ## ext_name] = { #ext_name, 0, 0 } +#define GENERIC_SW_STAT(ext_name) \ + [GENERIC_STAT_ ## ext_name] = { #ext_name, 0, 0 } static const struct efx_hw_stat_desc efx_ef10_stat_desc[EF10_STAT_COUNT] = { EF10_DMA_STAT(tx_bytes, TX_BYTES), @@ -798,6 +800,8 @@ static const struct efx_hw_stat_desc efx_ef10_stat_desc[EF10_STAT_COUNT] = { EF10_DMA_STAT(rx_align_error, RX_ALIGN_ERROR_PKTS), EF10_DMA_STAT(rx_length_error, RX_LENGTH_ERROR_PKTS), EF10_DMA_STAT(rx_nodesc_drops, RX_NODESC_DROPS), + GENERIC_SW_STAT(rx_nodesc_trunc), + GENERIC_SW_STAT(rx_noskb_drops), EF10_DMA_STAT(rx_pm_trunc_bb_overflow, PM_TRUNC_BB_OVERFLOW), EF10_DMA_STAT(rx_pm_discard_bb_overflow, PM_DISCARD_BB_OVERFLOW), EF10_DMA_STAT(rx_pm_trunc_vfifo_full, PM_TRUNC_VFIFO_FULL), @@ -841,7 +845,9 @@ static const struct efx_hw_stat_desc efx_ef10_stat_desc[EF10_STAT_COUNT] = { (1ULL << EF10_STAT_rx_gtjumbo) | \ (1ULL << EF10_STAT_rx_bad_gtjumbo) | \ (1ULL << EF10_STAT_rx_overflow) | \ - (1ULL << EF10_STAT_rx_nodesc_drops)) + (1ULL << EF10_STAT_rx_nodesc_drops) | \ + (1ULL << GENERIC_STAT_rx_nodesc_trunc) | \ + (1ULL << GENERIC_STAT_rx_noskb_drops)) /* These statistics are only provided by the 10G MAC. For a 10G/40G * switchable port we do not expose these because they might not @@ -951,7 +957,7 @@ static int efx_ef10_try_update_nic_stats(struct efx_nic *efx) stats[EF10_STAT_rx_bytes_minus_good_bytes]; efx_update_diff_stat(&stats[EF10_STAT_rx_bad_bytes], stats[EF10_STAT_rx_bytes_minus_good_bytes]); - + efx_update_sw_stats(efx, stats); return 0; } @@ -990,7 +996,9 @@ static size_t efx_ef10_update_stats(struct efx_nic *efx, u64 *full_stats, core_stats->tx_packets = stats[EF10_STAT_tx_packets]; core_stats->rx_bytes = stats[EF10_STAT_rx_bytes]; core_stats->tx_bytes = stats[EF10_STAT_tx_bytes]; - core_stats->rx_dropped = stats[EF10_STAT_rx_nodesc_drops]; + core_stats->rx_dropped = stats[EF10_STAT_rx_nodesc_drops] + + stats[GENERIC_STAT_rx_nodesc_trunc] + + stats[GENERIC_STAT_rx_noskb_drops]; core_stats->multicast = stats[EF10_STAT_rx_multicast]; core_stats->rx_length_errors = stats[EF10_STAT_rx_gtjumbo] + diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 2d8622430012..4b80c0be6e57 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -2724,6 +2724,17 @@ static void efx_fini_struct(struct efx_nic *efx) } } +void efx_update_sw_stats(struct efx_nic *efx, u64 *stats) +{ + u64 n_rx_nodesc_trunc = 0; + struct efx_channel *channel; + + efx_for_each_channel(channel, efx) + n_rx_nodesc_trunc += channel->n_rx_nodesc_trunc; + stats[GENERIC_STAT_rx_nodesc_trunc] = n_rx_nodesc_trunc; + stats[GENERIC_STAT_rx_noskb_drops] = atomic_read(&efx->n_rx_noskb_drops); +} + /************************************************************************** * * PCI interface diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 99032581336f..b41601e052d6 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -199,6 +199,9 @@ void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, int efx_port_dummy_op_int(struct efx_nic *efx); void efx_port_dummy_op_void(struct efx_nic *efx); +/* Update the generic software stats in the passed stats array */ +void efx_update_sw_stats(struct efx_nic *efx, u64 *stats); + /* MTD */ #ifdef CONFIG_SFC_MTD int efx_mtd_add(struct efx_nic *efx, struct efx_mtd_partition *parts, diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 74739c4b9997..03fe4e715024 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -77,7 +77,6 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = { EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc), - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_nodesc_trunc), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_events), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_packets), }; diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index fae25a418647..157037546d30 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -142,6 +142,8 @@ hw_name ## _ ## offset } #define FALCON_OTHER_STAT(ext_name) \ [FALCON_STAT_ ## ext_name] = { #ext_name, 0, 0 } +#define GENERIC_SW_STAT(ext_name) \ + [GENERIC_STAT_ ## ext_name] = { #ext_name, 0, 0 } static const struct efx_hw_stat_desc falcon_stat_desc[FALCON_STAT_COUNT] = { FALCON_DMA_STAT(tx_bytes, XgTxOctets), @@ -191,6 +193,8 @@ static const struct efx_hw_stat_desc falcon_stat_desc[FALCON_STAT_COUNT] = { FALCON_DMA_STAT(rx_length_error, XgRxLengthError), FALCON_DMA_STAT(rx_internal_error, XgRxInternalMACError), FALCON_OTHER_STAT(rx_nodesc_drop_cnt), + GENERIC_SW_STAT(rx_nodesc_trunc), + GENERIC_SW_STAT(rx_noskb_drops), }; static const unsigned long falcon_stat_mask[] = { [0 ... BITS_TO_LONGS(FALCON_STAT_COUNT) - 1] = ~0UL, @@ -2574,6 +2578,7 @@ static size_t falcon_update_nic_stats(struct efx_nic *efx, u64 *full_stats, stats[FALCON_STAT_rx_bytes] - stats[FALCON_STAT_rx_good_bytes] - stats[FALCON_STAT_rx_control] * 64); + efx_update_sw_stats(efx, stats); } if (full_stats) @@ -2584,7 +2589,9 @@ static size_t falcon_update_nic_stats(struct efx_nic *efx, u64 *full_stats, core_stats->tx_packets = stats[FALCON_STAT_tx_packets]; core_stats->rx_bytes = stats[FALCON_STAT_rx_bytes]; core_stats->tx_bytes = stats[FALCON_STAT_tx_bytes]; - core_stats->rx_dropped = stats[FALCON_STAT_rx_nodesc_drop_cnt]; + core_stats->rx_dropped = stats[FALCON_STAT_rx_nodesc_drop_cnt] + + stats[GENERIC_STAT_rx_nodesc_trunc] + + stats[GENERIC_STAT_rx_noskb_drops]; core_stats->multicast = stats[FALCON_STAT_rx_multicast]; core_stats->rx_length_errors = stats[FALCON_STAT_rx_gtjumbo] + diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 5bdae8ed7c57..8a02d45ed667 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -777,6 +777,7 @@ struct vfdi_status; * interrupt has occurred. * @stats_lock: Statistics update lock. Must be held when calling * efx_nic_type::{update,start,stop}_stats. + * @n_rx_noskb_drops: Count of RX packets dropped due to failure to allocate an skb * * This is stored in the private area of the &struct net_device. */ @@ -930,6 +931,7 @@ struct efx_nic { spinlock_t biu_lock; int last_irq_cpu; spinlock_t stats_lock; + atomic_t n_rx_noskb_drops; }; static inline int efx_dev_registered(struct efx_nic *efx) diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index d3ad8ed8d901..60f85149fc4c 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -135,6 +135,13 @@ enum { /* Size and alignment of buffer table entries (same) */ #define EFX_BUF_SIZE EFX_PAGE_SIZE +/* NIC-generic software stats */ +enum { + GENERIC_STAT_rx_noskb_drops, + GENERIC_STAT_rx_nodesc_trunc, + GENERIC_STAT_COUNT +}; + /** * struct falcon_board_type - board operations and type information * @id: Board type id, as found in NVRAM @@ -205,7 +212,7 @@ static inline bool falcon_spi_present(const struct falcon_spi_device *spi) } enum { - FALCON_STAT_tx_bytes, + FALCON_STAT_tx_bytes = GENERIC_STAT_COUNT, FALCON_STAT_tx_packets, FALCON_STAT_tx_pause, FALCON_STAT_tx_control, @@ -290,7 +297,7 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx) } enum { - SIENA_STAT_tx_bytes, + SIENA_STAT_tx_bytes = GENERIC_STAT_COUNT, SIENA_STAT_tx_good_bytes, SIENA_STAT_tx_bad_bytes, SIENA_STAT_tx_packets, @@ -361,7 +368,7 @@ struct siena_nic_data { }; enum { - EF10_STAT_tx_bytes, + EF10_STAT_tx_bytes = GENERIC_STAT_COUNT, EF10_STAT_tx_packets, EF10_STAT_tx_pause, EF10_STAT_tx_control, diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index 48588ddf81b0..bf537a2a901f 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -480,8 +480,10 @@ static struct sk_buff *efx_rx_mk_skb(struct efx_channel *channel, skb = netdev_alloc_skb(efx->net_dev, efx->rx_ip_align + efx->rx_prefix_size + hdr_len); - if (unlikely(skb == NULL)) + if (unlikely(skb == NULL)) { + atomic_inc(&efx->n_rx_noskb_drops); return NULL; + } EFX_BUG_ON_PARANOID(rx_buf->len < hdr_len); diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 50ffefed492c..ae696855f21a 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -424,6 +424,8 @@ static void siena_remove_nic(struct efx_nic *efx) { #ext_name, 64, 8 * MC_CMD_MAC_ ## mcdi_name } #define SIENA_OTHER_STAT(ext_name) \ [SIENA_STAT_ ## ext_name] = { #ext_name, 0, 0 } +#define GENERIC_SW_STAT(ext_name) \ + [GENERIC_STAT_ ## ext_name] = { #ext_name, 0, 0 } static const struct efx_hw_stat_desc siena_stat_desc[SIENA_STAT_COUNT] = { SIENA_DMA_STAT(tx_bytes, TX_BYTES), @@ -483,6 +485,8 @@ static const struct efx_hw_stat_desc siena_stat_desc[SIENA_STAT_COUNT] = { SIENA_DMA_STAT(rx_length_error, RX_LENGTH_ERROR_PKTS), SIENA_DMA_STAT(rx_internal_error, RX_INTERNAL_ERROR_PKTS), SIENA_DMA_STAT(rx_nodesc_drop_cnt, RX_NODESC_DROPS), + GENERIC_SW_STAT(rx_nodesc_trunc), + GENERIC_SW_STAT(rx_noskb_drops), }; static const unsigned long siena_stat_mask[] = { [0 ... BITS_TO_LONGS(SIENA_STAT_COUNT) - 1] = ~0UL, @@ -528,6 +532,7 @@ static int siena_try_update_nic_stats(struct efx_nic *efx) efx_update_diff_stat(&stats[SIENA_STAT_rx_good_bytes], stats[SIENA_STAT_rx_bytes] - stats[SIENA_STAT_rx_bad_bytes]); + efx_update_sw_stats(efx, stats); return 0; } @@ -554,7 +559,9 @@ static size_t siena_update_nic_stats(struct efx_nic *efx, u64 *full_stats, core_stats->tx_packets = stats[SIENA_STAT_tx_packets]; core_stats->rx_bytes = stats[SIENA_STAT_rx_bytes]; core_stats->tx_bytes = stats[SIENA_STAT_tx_bytes]; - core_stats->rx_dropped = stats[SIENA_STAT_rx_nodesc_drop_cnt]; + core_stats->rx_dropped = stats[SIENA_STAT_rx_nodesc_drop_cnt] + + stats[GENERIC_STAT_rx_nodesc_trunc] + + stats[GENERIC_STAT_rx_noskb_drops]; core_stats->multicast = stats[SIENA_STAT_rx_multicast]; core_stats->collisions = stats[SIENA_STAT_tx_collision]; core_stats->rx_length_errors = -- cgit v1.2.3 From f54424412b6b2f64cae4d7c39d981ca14ce0052c Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 13:26:01 +0200 Subject: bonding: permit enslaving interfaces without set_mac support Currently we exit if the slave isn't the first slave, doesn't support mac address setting and fail_over_mac isn't FOM_ACTIVE. It's wrong because we only require ndo_set_mac_address in case bonding is in active-backup mode and FOM isn't FOM_ACTIVE. To fix this - only exit with an error if we're in a/b mode and have fail_over_mac != FOM_ACTIVE. Also, maintain current behaviour on the first slave (forcibly change fom to FOM_ACTIVE) to not break anyone's configuration. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6d3b8db882a1..d643807a8e6a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1302,19 +1302,20 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } if (slave_ops->ndo_set_mac_address == NULL) { - if (!bond_has_slaves(bond)) { - pr_warn("%s: Warning: The first slave device specified does not support setting the MAC address\n", - bond_dev->name); - if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) { + pr_warn("%s: Warning: The slave device specified does not support setting the MAC address\n", + bond_dev->name); + if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP && + bond->params.fail_over_mac != BOND_FOM_ACTIVE) { + if (!bond_has_slaves(bond)) { bond->params.fail_over_mac = BOND_FOM_ACTIVE; pr_warn("%s: Setting fail_over_mac to active for active-backup mode\n", bond_dev->name); + } else { + pr_err("%s: Error: The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active\n", + bond_dev->name); + res = -EOPNOTSUPP; + goto err_undo_flags; } - } else if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) { - pr_err("%s: Error: The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active\n", - bond_dev->name); - res = -EOPNOTSUPP; - goto err_undo_flags; } } -- cgit v1.2.3 From ff11d8b27dcd85e7b96ac2570116d5061130bd5e Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 15 Jul 2014 16:08:57 +0200 Subject: bonding: fix bond_option_mode_set warning During the conversion to "static" functions this one got left out, only its prototype was converted, thus resulting in: drivers/net/bonding//bond_options.c:674:5: warning: symbol 'bond_option_mode_set' was not declared. Should it be static? Fix it by making it static and also break the line in two as it was too long. CC: Stephen Hemminger CC: Jay Vosburgh CC: Veaceslav Falico CC: Andy Gospodarek CC: David S. Miller Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_options.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index f908e65e86c1..cf720ce1b69e 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -671,7 +671,8 @@ const struct bond_option *bond_opt_get(unsigned int option) return &bond_opts[option]; } -int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newval) +static int bond_option_mode_set(struct bonding *bond, + const struct bond_opt_value *newval) { if (!bond_mode_uses_arp(newval->value) && bond->params.arp_interval) { pr_info("%s: %s mode is incompatible with arp monitoring, start mii monitoring\n", -- cgit v1.2.3 From a84bc2a9013fb123deeca7283480955d021503fb Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Tue, 15 Jul 2014 20:26:53 +0530 Subject: drivers: net: cpsw: disable coalesce when rx_coalesce_usecs is zero instead of return error on zero rx_coalesce_usecs, disable coalesce Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index b988d16cd34e..ae6379af5b4d 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -884,14 +884,16 @@ static int cpsw_set_coalesce(struct net_device *ndev, u32 addnl_dvdr = 1; u32 coal_intvl = 0; - if (!coal->rx_coalesce_usecs) - return -EINVAL; - coal_intvl = coal->rx_coalesce_usecs; int_ctrl = readl(&priv->wr_regs->int_control); prescale = priv->bus_freq_mhz * 4; + if (!coal->rx_coalesce_usecs) { + int_ctrl &= ~(CPSW_INTPRESCALE_MASK | CPSW_INTPACEEN); + goto update_return; + } + if (coal_intvl < CPSW_CMINTMIN_INTVL) coal_intvl = CPSW_CMINTMIN_INTVL; @@ -919,6 +921,8 @@ static int cpsw_set_coalesce(struct net_device *ndev, int_ctrl |= CPSW_INTPACEEN; int_ctrl &= (~CPSW_INTPRESCALE_MASK); int_ctrl |= (prescale & CPSW_INTPRESCALE_MASK); + +update_return: writel(int_ctrl, &priv->wr_regs->int_control); cpsw_notice(priv, timer, "Set coalesce to %d usecs.\n", coal_intvl); -- cgit v1.2.3 From 76444f5052edf6683a735c3bc307e11c121654c5 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 19:35:58 +0200 Subject: bonding: convert bond_main.c to use netdev_printk instead of pr_ Converted only the parts where we've had a valid net_device, skipping the init/deinit and options verification. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 342 +++++++++++++++++++--------------------- 1 file changed, 162 insertions(+), 180 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d643807a8e6a..3b96867e99de 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -629,8 +629,8 @@ static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active, static void bond_set_dev_addr(struct net_device *bond_dev, struct net_device *slave_dev) { - pr_debug("bond_dev=%p slave_dev=%p slave_dev->addr_len=%d\n", - bond_dev, slave_dev, slave_dev->addr_len); + netdev_dbg(bond_dev, "bond_dev=%p slave_dev=%p slave_dev->addr_len=%d\n", + bond_dev, slave_dev, slave_dev->addr_len); memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len); bond_dev->addr_assign_type = NET_ADDR_STOLEN; call_netdevice_notifiers(NETDEV_CHANGEADDR, bond_dev); @@ -684,8 +684,8 @@ static void bond_do_fail_over_mac(struct bonding *bond, rv = dev_set_mac_address(new_active->dev, &saddr); if (rv) { - pr_err("%s: Error %d setting MAC of slave %s\n", - bond->dev->name, -rv, new_active->dev->name); + netdev_err(bond->dev, "Error %d setting MAC of slave %s\n", + -rv, new_active->dev->name); goto out; } @@ -697,14 +697,14 @@ static void bond_do_fail_over_mac(struct bonding *bond, rv = dev_set_mac_address(old_active->dev, &saddr); if (rv) - pr_err("%s: Error %d setting MAC of slave %s\n", - bond->dev->name, -rv, new_active->dev->name); + netdev_err(bond->dev, "Error %d setting MAC of slave %s\n", + -rv, new_active->dev->name); out: write_lock_bh(&bond->curr_slave_lock); break; default: - pr_err("%s: bond_do_fail_over_mac impossible: bad policy %d\n", - bond->dev->name, bond->params.fail_over_mac); + netdev_err(bond->dev, "bond_do_fail_over_mac impossible: bad policy %d\n", + bond->params.fail_over_mac); break; } @@ -765,8 +765,8 @@ static bool bond_should_notify_peers(struct bonding *bond) slave = rcu_dereference(bond->curr_active_slave); rcu_read_unlock(); - pr_debug("bond_should_notify_peers: bond %s slave %s\n", - bond->dev->name, slave ? slave->dev->name : "NULL"); + netdev_dbg(bond->dev, "bond_should_notify_peers: slave %s\n", + slave ? slave->dev->name : "NULL"); if (!slave || !bond->send_peer_notif || test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) @@ -806,9 +806,9 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) if (new_active->link == BOND_LINK_BACK) { if (bond_uses_primary(bond)) { - pr_info("%s: making interface %s the new active one %d ms earlier\n", - bond->dev->name, new_active->dev->name, - (bond->params.updelay - new_active->delay) * bond->params.miimon); + netdev_info(bond->dev, "making interface %s the new active one %d ms earlier\n", + new_active->dev->name, + (bond->params.updelay - new_active->delay) * bond->params.miimon); } new_active->delay = 0; @@ -821,8 +821,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); } else { if (bond_uses_primary(bond)) { - pr_info("%s: making interface %s the new active one\n", - bond->dev->name, new_active->dev->name); + netdev_info(bond->dev, "making interface %s the new active one\n", + new_active->dev->name); } } } @@ -911,11 +911,9 @@ void bond_select_active_slave(struct bonding *bond) return; if (netif_carrier_ok(bond->dev)) { - pr_info("%s: first active interface up!\n", - bond->dev->name); + netdev_info(bond->dev, "first active interface up!\n"); } else { - pr_info("%s: now running without any active interface!\n", - bond->dev->name); + netdev_info(bond->dev, "now running without any active interface!\n"); } } } @@ -1212,36 +1210,38 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (!bond->params.use_carrier && slave_dev->ethtool_ops->get_link == NULL && slave_ops->ndo_do_ioctl == NULL) { - pr_warn("%s: Warning: no link monitoring support for %s\n", - bond_dev->name, slave_dev->name); + netdev_warn(bond_dev, "no link monitoring support for %s\n", + slave_dev->name); } /* already enslaved */ if (slave_dev->flags & IFF_SLAVE) { - pr_debug("Error: Device was already enslaved\n"); + netdev_dbg(bond_dev, "Error: Device was already enslaved\n"); return -EBUSY; } if (bond_dev == slave_dev) { - pr_err("%s: cannot enslave bond to itself.\n", bond_dev->name); + netdev_err(bond_dev, "cannot enslave bond to itself.\n"); return -EPERM; } /* vlan challenged mutual exclusion */ /* no need to lock since we're protected by rtnl_lock */ if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) { - pr_debug("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); + netdev_dbg(bond_dev, "%s is NETIF_F_VLAN_CHALLENGED\n", + slave_dev->name); if (vlan_uses_dev(bond_dev)) { - pr_err("%s: Error: cannot enslave VLAN challenged slave %s on VLAN enabled bond %s\n", - bond_dev->name, slave_dev->name, bond_dev->name); + netdev_err(bond_dev, "Error: cannot enslave VLAN challenged slave %s on VLAN enabled bond %s\n", + slave_dev->name, bond_dev->name); return -EPERM; } else { - pr_warn("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n", - bond_dev->name, slave_dev->name, - slave_dev->name, bond_dev->name); + netdev_warn(bond_dev, "enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n", + slave_dev->name, slave_dev->name, + bond_dev->name); } } else { - pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); + netdev_dbg(bond_dev, "%s is !NETIF_F_VLAN_CHALLENGED\n", + slave_dev->name); } /* @@ -1251,8 +1251,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * enslaving it; the old ifenslave will not. */ if ((slave_dev->flags & IFF_UP)) { - pr_err("%s is up - this may be due to an out of date ifenslave\n", - slave_dev->name); + netdev_err(bond_dev, "%s is up - this may be due to an out of date ifenslave\n", + slave_dev->name); res = -EPERM; goto err_undo_flags; } @@ -1266,16 +1266,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) */ if (!bond_has_slaves(bond)) { if (bond_dev->type != slave_dev->type) { - pr_debug("%s: change device type from %d to %d\n", - bond_dev->name, - bond_dev->type, slave_dev->type); + netdev_dbg(bond_dev, "change device type from %d to %d\n", + bond_dev->type, slave_dev->type); res = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, bond_dev); res = notifier_to_errno(res); if (res) { - pr_err("%s: refused to change device type\n", - bond_dev->name); + netdev_err(bond_dev, "refused to change device type\n"); res = -EBUSY; goto err_undo_flags; } @@ -1295,24 +1293,21 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_dev); } } else if (bond_dev->type != slave_dev->type) { - pr_err("%s ether type (%d) is different from other slaves (%d), can not enslave it\n", - slave_dev->name, slave_dev->type, bond_dev->type); + netdev_err(bond_dev, "%s ether type (%d) is different from other slaves (%d), can not enslave it\n", + slave_dev->name, slave_dev->type, bond_dev->type); res = -EINVAL; goto err_undo_flags; } if (slave_ops->ndo_set_mac_address == NULL) { - pr_warn("%s: Warning: The slave device specified does not support setting the MAC address\n", - bond_dev->name); + netdev_warn(bond_dev, "The slave device specified does not support setting the MAC address\n"); if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP && bond->params.fail_over_mac != BOND_FOM_ACTIVE) { if (!bond_has_slaves(bond)) { bond->params.fail_over_mac = BOND_FOM_ACTIVE; - pr_warn("%s: Setting fail_over_mac to active for active-backup mode\n", - bond_dev->name); + netdev_warn(bond_dev, "Setting fail_over_mac to active for active-backup mode\n"); } else { - pr_err("%s: Error: The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active\n", - bond_dev->name); + netdev_err(bond_dev, "The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active\n"); res = -EOPNOTSUPP; goto err_undo_flags; } @@ -1345,7 +1340,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) new_slave->original_mtu = slave_dev->mtu; res = dev_set_mtu(slave_dev, bond->dev->mtu); if (res) { - pr_debug("Error %d calling dev_set_mtu\n", res); + netdev_dbg(bond_dev, "Error %d calling dev_set_mtu\n", res); goto err_free; } @@ -1366,7 +1361,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) addr.sa_family = slave_dev->type; res = dev_set_mac_address(slave_dev, &addr); if (res) { - pr_debug("Error %d calling set_mac_address\n", res); + netdev_dbg(bond_dev, "Error %d calling set_mac_address\n", res); goto err_restore_mtu; } } @@ -1374,7 +1369,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* open the slave since the application closed it */ res = dev_open(slave_dev); if (res) { - pr_debug("Opening slave %s failed\n", slave_dev->name); + netdev_dbg(bond_dev, "Opening slave %s failed\n", slave_dev->name); goto err_restore_mac; } @@ -1424,8 +1419,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) res = vlan_vids_add_by_dev(slave_dev, bond_dev); if (res) { - pr_err("%s: Error: Couldn't add bond vlan ids to %s\n", - bond_dev->name, slave_dev->name); + netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n", + slave_dev->name); goto err_close; } @@ -1454,12 +1449,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * supported); thus, we don't need to change * the messages for netif_carrier. */ - pr_warn("%s: Warning: MII and ETHTOOL support not available for interface %s, and arp_interval/arp_ip_target module parameters not specified, thus bonding will not detect link failures! see bonding.txt for details\n", - bond_dev->name, slave_dev->name); + netdev_warn(bond_dev, "MII and ETHTOOL support not available for interface %s, and arp_interval/arp_ip_target module parameters not specified, thus bonding will not detect link failures! see bonding.txt for details\n", + slave_dev->name); } else if (link_reporting == -1) { /* unable get link status using mii/ethtool */ - pr_warn("%s: Warning: can't get link status from interface %s; the network driver associated with this interface does not support MII or ETHTOOL link status reporting, thus miimon has no effect on this interface\n", - bond_dev->name, slave_dev->name); + netdev_warn(bond_dev, "can't get link status from interface %s; the network driver associated with this interface does not support MII or ETHTOOL link status reporting, thus miimon has no effect on this interface\n", + slave_dev->name); } } @@ -1484,9 +1479,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (new_slave->link != BOND_LINK_DOWN) new_slave->last_link_up = jiffies; - pr_debug("Initial state of slave_dev is BOND_LINK_%s\n", - new_slave->link == BOND_LINK_DOWN ? "DOWN" : - (new_slave->link == BOND_LINK_UP ? "UP" : "BACK")); + netdev_dbg(bond_dev, "Initial state of slave_dev is BOND_LINK_%s\n", + new_slave->link == BOND_LINK_DOWN ? "DOWN" : + (new_slave->link == BOND_LINK_UP ? "UP" : "BACK")); if (bond_uses_primary(bond) && bond->params.primary[0]) { /* if there is a primary slave, remember it */ @@ -1527,7 +1522,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW); break; default: - pr_debug("This slave is always active in trunk mode\n"); + netdev_dbg(bond_dev, "This slave is always active in trunk mode\n"); /* always active in trunk mode */ bond_set_active_slave(new_slave); @@ -1547,8 +1542,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) slave_dev->npinfo = bond->dev->npinfo; if (slave_dev->npinfo) { if (slave_enable_netpoll(new_slave)) { - pr_info("Error, %s: master_dev is using netpoll, but new slave device does not support netpoll\n", - bond_dev->name); + netdev_info(bond_dev, "master_dev is using netpoll, but new slave device does not support netpoll\n"); res = -EBUSY; goto err_detach; } @@ -1558,19 +1552,19 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) res = netdev_rx_handler_register(slave_dev, bond_handle_frame, new_slave); if (res) { - pr_debug("Error %d calling netdev_rx_handler_register\n", res); + netdev_dbg(bond_dev, "Error %d calling netdev_rx_handler_register\n", res); goto err_detach; } res = bond_master_upper_dev_link(bond_dev, slave_dev, new_slave); if (res) { - pr_debug("Error %d calling bond_master_upper_dev_link\n", res); + netdev_dbg(bond_dev, "Error %d calling bond_master_upper_dev_link\n", res); goto err_unregister; } res = bond_sysfs_slave_add(new_slave); if (res) { - pr_debug("Error %d calling bond_sysfs_slave_add\n", res); + netdev_dbg(bond_dev, "Error %d calling bond_sysfs_slave_add\n", res); goto err_upper_unlink; } @@ -1586,10 +1580,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) unblock_netpoll_tx(); } - pr_info("%s: Enslaving %s as %s interface with %s link\n", - bond_dev->name, slave_dev->name, - bond_is_active_slave(new_slave) ? "an active" : "a backup", - new_slave->link != BOND_LINK_DOWN ? "an up" : "a down"); + netdev_info(bond_dev, "Enslaving %s as %s interface with %s link\n", + slave_dev->name, + bond_is_active_slave(new_slave) ? "an active" : "a backup", + new_slave->link != BOND_LINK_DOWN ? "an up" : "a down"); /* enslave is successful */ return 0; @@ -1674,8 +1668,8 @@ static int __bond_release_one(struct net_device *bond_dev, /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || !netdev_has_upper_dev(slave_dev, bond_dev)) { - pr_err("%s: Error: cannot release %s\n", - bond_dev->name, slave_dev->name); + netdev_err(bond_dev, "cannot release %s\n", + slave_dev->name); return -EINVAL; } @@ -1684,8 +1678,8 @@ static int __bond_release_one(struct net_device *bond_dev, slave = bond_get_slave_by_dev(bond, slave_dev); if (!slave) { /* not a slave of this bond */ - pr_info("%s: %s not enslaved\n", - bond_dev->name, slave_dev->name); + netdev_info(bond_dev, "%s not enslaved\n", + slave_dev->name); unblock_netpoll_tx(); return -EINVAL; } @@ -1705,10 +1699,9 @@ static int __bond_release_one(struct net_device *bond_dev, write_unlock_bh(&bond->lock); - pr_info("%s: Releasing %s interface %s\n", - bond_dev->name, - bond_is_active_slave(slave) ? "active" : "backup", - slave_dev->name); + netdev_info(bond_dev, "Releasing %s interface %s\n", + bond_is_active_slave(slave) ? "active" : "backup", + slave_dev->name); oldcurrent = rcu_access_pointer(bond->curr_active_slave); @@ -1718,10 +1711,9 @@ static int __bond_release_one(struct net_device *bond_dev, BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP)) { if (ether_addr_equal_64bits(bond_dev->dev_addr, slave->perm_hwaddr) && bond_has_slaves(bond)) - pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s - set the HWaddr of %s to a different address to avoid conflicts\n", - bond_dev->name, slave_dev->name, - slave->perm_hwaddr, - bond_dev->name, slave_dev->name); + netdev_warn(bond_dev, "the permanent HWaddr of %s - %pM - is still in use by %s - set the HWaddr of %s to a different address to avoid conflicts\n", + slave_dev->name, slave->perm_hwaddr, + bond_dev->name, slave_dev->name); } if (bond->primary_slave == slave) @@ -1774,8 +1766,8 @@ static int __bond_release_one(struct net_device *bond_dev, bond_compute_features(bond); if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) && (old_features & NETIF_F_VLAN_CHALLENGED)) - pr_info("%s: last VLAN challenged slave %s left bond %s - VLAN blocking is removed\n", - bond_dev->name, slave_dev->name, bond_dev->name); + netdev_info(bond_dev, "last VLAN challenged slave %s left bond %s - VLAN blocking is removed\n", + slave_dev->name, bond_dev->name); /* must do this from outside any spinlocks */ vlan_vids_del_by_dev(slave_dev, bond_dev); @@ -1842,8 +1834,8 @@ static int bond_release_and_destroy(struct net_device *bond_dev, ret = bond_release(bond_dev, slave_dev); if (ret == 0 && !bond_has_slaves(bond)) { bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; - pr_info("%s: Destroying bond %s\n", - bond_dev->name, bond_dev->name); + netdev_info(bond_dev, "Destroying bond %s\n", + bond_dev->name); unregister_netdevice(bond_dev); } return ret; @@ -1907,14 +1899,13 @@ static int bond_miimon_inspect(struct bonding *bond) slave->link = BOND_LINK_FAIL; slave->delay = bond->params.downdelay; if (slave->delay) { - pr_info("%s: link status down for %sinterface %s, disabling it in %d ms\n", - bond->dev->name, - (BOND_MODE(bond) == - BOND_MODE_ACTIVEBACKUP) ? - (bond_is_active_slave(slave) ? - "active " : "backup ") : "", - slave->dev->name, - bond->params.downdelay * bond->params.miimon); + netdev_info(bond->dev, "link status down for %sinterface %s, disabling it in %d ms\n", + (BOND_MODE(bond) == + BOND_MODE_ACTIVEBACKUP) ? + (bond_is_active_slave(slave) ? + "active " : "backup ") : "", + slave->dev->name, + bond->params.downdelay * bond->params.miimon); } /*FALLTHRU*/ case BOND_LINK_FAIL: @@ -1924,11 +1915,10 @@ static int bond_miimon_inspect(struct bonding *bond) */ slave->link = BOND_LINK_UP; slave->last_link_up = jiffies; - pr_info("%s: link status up again after %d ms for interface %s\n", - bond->dev->name, - (bond->params.downdelay - slave->delay) * - bond->params.miimon, - slave->dev->name); + netdev_info(bond->dev, "link status up again after %d ms for interface %s\n", + (bond->params.downdelay - slave->delay) * + bond->params.miimon, + slave->dev->name); continue; } @@ -1949,21 +1939,20 @@ static int bond_miimon_inspect(struct bonding *bond) slave->delay = bond->params.updelay; if (slave->delay) { - pr_info("%s: link status up for interface %s, enabling it in %d ms\n", - bond->dev->name, slave->dev->name, - ignore_updelay ? 0 : - bond->params.updelay * - bond->params.miimon); + netdev_info(bond->dev, "link status up for interface %s, enabling it in %d ms\n", + slave->dev->name, + ignore_updelay ? 0 : + bond->params.updelay * + bond->params.miimon); } /*FALLTHRU*/ case BOND_LINK_BACK: if (!link_state) { slave->link = BOND_LINK_DOWN; - pr_info("%s: link status down again after %d ms for interface %s\n", - bond->dev->name, - (bond->params.updelay - slave->delay) * - bond->params.miimon, - slave->dev->name); + netdev_info(bond->dev, "link status down again after %d ms for interface %s\n", + (bond->params.updelay - slave->delay) * + bond->params.miimon, + slave->dev->name); continue; } @@ -2011,10 +2000,10 @@ static void bond_miimon_commit(struct bonding *bond) bond_set_backup_slave(slave); } - pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex\n", - bond->dev->name, slave->dev->name, - slave->speed == SPEED_UNKNOWN ? 0 : slave->speed, - slave->duplex ? "full" : "half"); + netdev_info(bond->dev, "link status definitely up for interface %s, %u Mbps %s duplex\n", + slave->dev->name, + slave->speed == SPEED_UNKNOWN ? 0 : slave->speed, + slave->duplex ? "full" : "half"); /* notify ad that the link status has changed */ if (BOND_MODE(bond) == BOND_MODE_8023AD) @@ -2041,8 +2030,8 @@ static void bond_miimon_commit(struct bonding *bond) bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW); - pr_info("%s: link status definitely down for interface %s, disabling it\n", - bond->dev->name, slave->dev->name); + netdev_info(bond->dev, "link status definitely down for interface %s, disabling it\n", + slave->dev->name); if (BOND_MODE(bond) == BOND_MODE_8023AD) bond_3ad_handle_link_change(slave, @@ -2058,9 +2047,8 @@ static void bond_miimon_commit(struct bonding *bond) continue; default: - pr_err("%s: invalid new link %d on slave %s\n", - bond->dev->name, slave->new_link, - slave->dev->name); + netdev_err(bond->dev, "invalid new link %d on slave %s\n", + slave->new_link, slave->dev->name); slave->new_link = BOND_LINK_NOCHANGE; continue; @@ -2163,8 +2151,8 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, struct sk_buff *skb; int i; - pr_debug("arp %d on slave %s: dst %pI4 src %pI4\n", - arp_op, slave_dev->name, &dest_ip, &src_ip); + netdev_dbg(slave_dev, "arp %d on slave %s: dst %pI4 src %pI4\n", + arp_op, slave_dev->name, &dest_ip, &src_ip); skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip, NULL, slave_dev->dev_addr, NULL); @@ -2179,8 +2167,8 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, if (!tags[i].vlan_id) continue; - pr_debug("inner tag: proto %X vid %X\n", - ntohs(tags[i].vlan_proto), tags[i].vlan_id); + netdev_dbg(slave_dev, "inner tag: proto %X vid %X\n", + ntohs(tags[i].vlan_proto), tags[i].vlan_id); skb = __vlan_put_tag(skb, tags[i].vlan_proto, tags[i].vlan_id); if (!skb) { @@ -2190,8 +2178,8 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, } /* Set the outer tag */ if (tags[0].vlan_id) { - pr_debug("outer tag: proto %X vid %X\n", - ntohs(tags[0].vlan_proto), tags[0].vlan_id); + netdev_dbg(slave_dev, "outer tag: proto %X vid %X\n", + ntohs(tags[0].vlan_proto), tags[0].vlan_id); skb = vlan_put_tag(skb, tags[0].vlan_proto, tags[0].vlan_id); if (!skb) { net_err_ratelimited("failed to insert outer VLAN tag\n"); @@ -2245,7 +2233,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) bool ret; for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) { - pr_debug("basa: target %pI4\n", &targets[i]); + netdev_dbg(bond->dev, "basa: target %pI4\n", &targets[i]); memset(tags, 0, sizeof(tags)); /* Find out through which dev should the packet go */ @@ -2276,9 +2264,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) goto found; /* Not our device - skip */ - pr_debug("%s: no path to arp_ip_target %pI4 via rt.dev %s\n", - bond->dev->name, &targets[i], - rt->dst.dev ? rt->dst.dev->name : "NULL"); + netdev_dbg(bond->dev, "no path to arp_ip_target %pI4 via rt.dev %s\n", + &targets[i], rt->dst.dev ? rt->dst.dev->name : "NULL"); ip_rt_put(rt); continue; @@ -2296,13 +2283,15 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 int i; if (!sip || !bond_has_this_ip(bond, tip)) { - pr_debug("bva: sip %pI4 tip %pI4 not found\n", &sip, &tip); + netdev_dbg(bond->dev, "bva: sip %pI4 tip %pI4 not found\n", + &sip, &tip); return; } i = bond_get_targets_ip(bond->params.arp_targets, sip); if (i == -1) { - pr_debug("bva: sip %pI4 not found in targets\n", &sip); + netdev_dbg(bond->dev, "bva: sip %pI4 not found in targets\n", + &sip); return; } slave->last_rx = jiffies; @@ -2329,8 +2318,8 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, alen = arp_hdr_len(bond->dev); - pr_debug("bond_arp_rcv: bond %s skb->dev %s\n", - bond->dev->name, skb->dev->name); + netdev_dbg(bond->dev, "bond_arp_rcv: skb->dev %s\n", + skb->dev->name); if (alen > skb_headlen(skb)) { arp = kmalloc(alen, GFP_ATOMIC); @@ -2354,10 +2343,10 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, arp_ptr += 4 + bond->dev->addr_len; memcpy(&tip, arp_ptr, 4); - pr_debug("bond_arp_rcv: %s %s/%d av %d sv %d sip %pI4 tip %pI4\n", - bond->dev->name, slave->dev->name, bond_slave_state(slave), - bond->params.arp_validate, slave_do_arp_validate(bond, slave), - &sip, &tip); + netdev_dbg(bond->dev, "bond_arp_rcv: %s/%d av %d sv %d sip %pI4 tip %pI4\n", + slave->dev->name, bond_slave_state(slave), + bond->params.arp_validate, slave_do_arp_validate(bond, slave), + &sip, &tip); curr_active_slave = rcu_dereference(bond->curr_active_slave); @@ -2447,14 +2436,12 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) * is closed. */ if (!oldcurrent) { - pr_info("%s: link status definitely up for interface %s\n", - bond->dev->name, - slave->dev->name); + netdev_info(bond->dev, "link status definitely up for interface %s\n", + slave->dev->name); do_failover = 1; } else { - pr_info("%s: interface %s is now up\n", - bond->dev->name, - slave->dev->name); + netdev_info(bond->dev, "interface %s is now up\n", + slave->dev->name); } } } else { @@ -2473,8 +2460,8 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) if (slave->link_failure_count < UINT_MAX) slave->link_failure_count++; - pr_info("%s: interface %s is now down\n", - bond->dev->name, slave->dev->name); + netdev_info(bond->dev, "interface %s is now down\n", + slave->dev->name); if (slave == oldcurrent) do_failover = 1; @@ -2627,8 +2614,8 @@ static void bond_ab_arp_commit(struct bonding *bond) RCU_INIT_POINTER(bond->current_arp_slave, NULL); } - pr_info("%s: link status definitely up for interface %s\n", - bond->dev->name, slave->dev->name); + netdev_info(bond->dev, "link status definitely up for interface %s\n", + slave->dev->name); if (!rtnl_dereference(bond->curr_active_slave) || (slave == bond->primary_slave)) @@ -2646,8 +2633,8 @@ static void bond_ab_arp_commit(struct bonding *bond) bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW); - pr_info("%s: link status definitely down for interface %s, disabling it\n", - bond->dev->name, slave->dev->name); + netdev_info(bond->dev, "link status definitely down for interface %s, disabling it\n", + slave->dev->name); if (slave == rtnl_dereference(bond->curr_active_slave)) { RCU_INIT_POINTER(bond->current_arp_slave, NULL); @@ -2657,9 +2644,8 @@ static void bond_ab_arp_commit(struct bonding *bond) continue; default: - pr_err("%s: impossible: new_link %d on slave %s\n", - bond->dev->name, slave->new_link, - slave->dev->name); + netdev_err(bond->dev, "impossible: new_link %d on slave %s\n", + slave->new_link, slave->dev->name); continue; } @@ -2690,9 +2676,9 @@ static bool bond_ab_arp_probe(struct bonding *bond) bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER; if (curr_arp_slave && curr_active_slave) - pr_info("PROBE: c_arp %s && cas %s BAD\n", - curr_arp_slave->dev->name, - curr_active_slave->dev->name); + netdev_info(bond->dev, "PROBE: c_arp %s && cas %s BAD\n", + curr_arp_slave->dev->name, + curr_active_slave->dev->name); if (curr_active_slave) { bond_arp_send_all(bond, curr_active_slave); @@ -2733,8 +2719,8 @@ static bool bond_ab_arp_probe(struct bonding *bond) bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_LATER); - pr_info("%s: backup interface %s is now down\n", - bond->dev->name, slave->dev->name); + netdev_info(bond->dev, "backup interface %s is now down\n", + slave->dev->name); } if (slave == curr_arp_slave) found = true; @@ -2930,9 +2916,8 @@ static int bond_slave_netdev_event(unsigned long event, break; } - pr_info("%s: Primary slave changed to %s, reselecting active slave\n", - bond->dev->name, - bond->primary_slave ? slave_dev->name : "none"); + netdev_info(bond->dev, "Primary slave changed to %s, reselecting active slave\n", + bond->primary_slave ? slave_dev->name : "none"); block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); @@ -2967,19 +2952,18 @@ static int bond_netdev_event(struct notifier_block *this, { struct net_device *event_dev = netdev_notifier_info_to_dev(ptr); - pr_debug("event_dev: %s, event: %lx\n", - event_dev ? event_dev->name : "None", event); + netdev_dbg(event_dev, "event: %lx\n", event); if (!(event_dev->priv_flags & IFF_BONDING)) return NOTIFY_DONE; if (event_dev->flags & IFF_MASTER) { - pr_debug("IFF_MASTER\n"); + netdev_dbg(event_dev, "IFF_MASTER\n"); return bond_master_netdev_event(event, event_dev); } if (event_dev->flags & IFF_SLAVE) { - pr_debug("IFF_SLAVE\n"); + netdev_dbg(event_dev, "IFF_SLAVE\n"); return bond_slave_netdev_event(event, event_dev); } @@ -3221,7 +3205,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd struct net *net; int res = 0; - pr_debug("bond_ioctl: master=%s, cmd=%d\n", bond_dev->name, cmd); + netdev_dbg(bond_dev, "bond_ioctl: cmd=%d\n", cmd); switch (cmd) { case SIOCGMIIPHY: @@ -3291,12 +3275,12 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd slave_dev = __dev_get_by_name(net, ifr->ifr_slave); - pr_debug("slave_dev=%p:\n", slave_dev); + netdev_dbg(bond_dev, "slave_dev=%p:\n", slave_dev); if (!slave_dev) return -ENODEV; - pr_debug("slave_dev->name=%s:\n", slave_dev->name); + netdev_dbg(bond_dev, "slave_dev->name=%s:\n", slave_dev->name); switch (cmd) { case BOND_ENSLAVE_OLD: case SIOCBONDENSLAVE: @@ -3423,8 +3407,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) struct list_head *iter; int res = 0; - pr_debug("bond=%p, name=%s, new_mtu=%d\n", - bond, bond_dev ? bond_dev->name : "None", new_mtu); + netdev_dbg(bond_dev, "bond=%p, new_mtu=%d\n", bond, new_mtu); /* Can't hold bond->lock with bh disabled here since * some base drivers panic. On the other hand we can't @@ -3442,8 +3425,8 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) */ bond_for_each_slave(bond, slave, iter) { - pr_debug("s %p c_m %p\n", - slave, slave->dev->netdev_ops->ndo_change_mtu); + netdev_dbg(bond_dev, "s %p c_m %p\n", + slave, slave->dev->netdev_ops->ndo_change_mtu); res = dev_set_mtu(slave->dev, new_mtu); @@ -3456,7 +3439,8 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) * means changing their mtu from timer context, which * is probably not a good idea. */ - pr_debug("err %d %s\n", res, slave->dev->name); + netdev_dbg(bond_dev, "err %d %s\n", res, + slave->dev->name); goto unwind; } } @@ -3475,8 +3459,8 @@ unwind: tmp_res = dev_set_mtu(rollback_slave->dev, bond_dev->mtu); if (tmp_res) { - pr_debug("unwind err %d dev %s\n", - tmp_res, rollback_slave->dev->name); + netdev_dbg(bond_dev, "unwind err %d dev %s\n", + tmp_res, rollback_slave->dev->name); } } @@ -3502,8 +3486,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) return bond_alb_set_mac_address(bond_dev, addr); - pr_debug("bond=%p, name=%s\n", - bond, bond_dev ? bond_dev->name : "None"); + netdev_dbg(bond_dev, "bond=%p\n", bond); /* If fail_over_mac is enabled, do nothing and return success. * Returning an error causes ifenslave to fail. @@ -3531,7 +3514,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) */ bond_for_each_slave(bond, slave, iter) { - pr_debug("slave %p %s\n", slave, slave->dev->name); + netdev_dbg(bond_dev, "slave %p %s\n", slave, slave->dev->name); res = dev_set_mac_address(slave->dev, addr); if (res) { /* TODO: consider downing the slave @@ -3540,7 +3523,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) * breakage anyway until ARP finish * updating, so... */ - pr_debug("err %d %s\n", res, slave->dev->name); + netdev_dbg(bond_dev, "err %d %s\n", res, slave->dev->name); goto unwind; } } @@ -3562,8 +3545,8 @@ unwind: tmp_res = dev_set_mac_address(rollback_slave->dev, &tmp_sa); if (tmp_res) { - pr_debug("unwind err %d dev %s\n", - tmp_res, rollback_slave->dev->name); + netdev_dbg(bond_dev, "unwind err %d dev %s\n", + tmp_res, rollback_slave->dev->name); } } @@ -3810,8 +3793,7 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev return bond_tlb_xmit(skb, dev); default: /* Should never happen, mode already checked */ - pr_err("%s: Error: Unknown bonding mode %d\n", - dev->name, BOND_MODE(bond)); + netdev_err(dev, "Unknown bonding mode %d\n", BOND_MODE(bond)); WARN_ON_ONCE(1); dev_kfree_skb_any(skb); return NETDEV_TX_OK; @@ -3991,7 +3973,7 @@ static void bond_uninit(struct net_device *bond_dev) /* Release the bonded slaves */ bond_for_each_slave(bond, slave, iter) __bond_release_one(bond_dev, slave->dev, true); - pr_info("%s: Released all slaves\n", bond_dev->name); + netdev_info(bond_dev, "Released all slaves\n"); list_del(&bond->bond_list); @@ -4380,7 +4362,7 @@ static int bond_init(struct net_device *bond_dev) struct bond_net *bn = net_generic(dev_net(bond_dev), bond_net_id); struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - pr_debug("Begin bond_init for %s\n", bond_dev->name); + netdev_dbg(bond_dev, "Begin bond_init\n"); /* * Initialize locks that may be required during -- cgit v1.2.3 From f338532327bf1f93ff30764dbd2251c1e2fa765b Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 19:35:59 +0200 Subject: bonding: remove pr_fmt from bond_main.c To maintain the same message structure as netdev_* functions print. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 3b96867e99de..041036e31aa3 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -31,8 +31,6 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include -- cgit v1.2.3 From d4471f5e23a75c9a94d339b5a83f89b21e7c852a Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 19:36:00 +0200 Subject: bonding: convert bond_3ad.c to use netdev_printk instead of pr_ Several functions left out cause we might not have at that time a valid bond/slave/port. Also, converted severa pr_ratelimited into net_ratelimited. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 183 ++++++++++++++++++++--------------------- 1 file changed, 88 insertions(+), 95 deletions(-) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 0dfeaf5da3f2..159c451324ce 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -301,8 +301,8 @@ static u16 __get_link_speed(struct port *port) } } - pr_debug("Port %d Received link speed %d update from adapter\n", - port->actor_port_number, speed); + netdev_dbg(slave->bond->dev, "Port %d Received link speed %d update from adapter\n", + port->actor_port_number, speed); return speed; } @@ -329,14 +329,14 @@ static u8 __get_duplex(struct port *port) switch (slave->duplex) { case DUPLEX_FULL: retval = 0x1; - pr_debug("Port %d Received status full duplex update from adapter\n", - port->actor_port_number); + netdev_dbg(slave->bond->dev, "Port %d Received status full duplex update from adapter\n", + port->actor_port_number); break; case DUPLEX_HALF: default: retval = 0x0; - pr_debug("Port %d Received status NOT full duplex update from adapter\n", - port->actor_port_number); + netdev_dbg(slave->bond->dev, "Port %d Received status NOT full duplex update from adapter\n", + port->actor_port_number); break; } } @@ -1079,9 +1079,8 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) /* detect loopback situation */ if (MAC_ADDRESS_EQUAL(&(lacpdu->actor_system), &(port->actor_system))) { - pr_err("%s: An illegal loopback occurred on adapter (%s)\n" + netdev_err(port->slave->bond->dev, "An illegal loopback occurred on adapter (%s)\n" "Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n", - port->slave->bond->dev->name, port->slave->dev->name); return; } @@ -1269,9 +1268,9 @@ static void ad_port_selection_logic(struct port *port) port->next_port_in_aggregator = NULL; port->actor_port_aggregator_identifier = 0; - pr_debug("Port %d left LAG %d\n", - port->actor_port_number, - temp_aggregator->aggregator_identifier); + netdev_dbg(bond->dev, "Port %d left LAG %d\n", + port->actor_port_number, + temp_aggregator->aggregator_identifier); /* if the aggregator is empty, clear its * parameters, and set it ready to be attached */ @@ -1284,11 +1283,11 @@ static void ad_port_selection_logic(struct port *port) /* meaning: the port was related to an aggregator * but was not on the aggregator port list */ - pr_warn_ratelimited("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n", - port->slave->bond->dev->name, - port->actor_port_number, - port->slave->dev->name, - port->aggregator->aggregator_identifier); + net_warn_ratelimited("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n", + port->slave->bond->dev->name, + port->actor_port_number, + port->slave->dev->name, + port->aggregator->aggregator_identifier); } } /* search on all aggregators for a suitable aggregator for this port */ @@ -1318,9 +1317,9 @@ static void ad_port_selection_logic(struct port *port) port->next_port_in_aggregator = aggregator->lag_ports; port->aggregator->num_of_ports++; aggregator->lag_ports = port; - pr_debug("Port %d joined LAG %d(existing LAG)\n", - port->actor_port_number, - port->aggregator->aggregator_identifier); + netdev_dbg(bond->dev, "Port %d joined LAG %d(existing LAG)\n", + port->actor_port_number, + port->aggregator->aggregator_identifier); /* mark this port as selected */ port->sm_vars |= AD_PORT_SELECTED; @@ -1363,12 +1362,11 @@ static void ad_port_selection_logic(struct port *port) /* mark this port as selected */ port->sm_vars |= AD_PORT_SELECTED; - pr_debug("Port %d joined LAG %d(new LAG)\n", - port->actor_port_number, - port->aggregator->aggregator_identifier); + netdev_dbg(bond->dev, "Port %d joined LAG %d(new LAG)\n", + port->actor_port_number, + port->aggregator->aggregator_identifier); } else { - pr_err("%s: Port %d (on %s) did not find a suitable aggregator\n", - port->slave->bond->dev->name, + netdev_err(bond->dev, "Port %d (on %s) did not find a suitable aggregator\n", port->actor_port_number, port->slave->dev->name); } } @@ -1445,9 +1443,9 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best, break; default: - pr_warn_ratelimited("%s: Impossible agg select mode %d\n", - curr->slave->bond->dev->name, - __get_agg_selection_mode(curr->lag_ports)); + net_warn_ratelimited("%s: Impossible agg select mode %d\n", + curr->slave->bond->dev->name, + __get_agg_selection_mode(curr->lag_ports)); break; } @@ -1539,40 +1537,40 @@ static void ad_agg_selection_logic(struct aggregator *agg) /* if there is new best aggregator, activate it */ if (best) { - pr_debug("best Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", - best->aggregator_identifier, best->num_of_ports, - best->actor_oper_aggregator_key, - best->partner_oper_aggregator_key, - best->is_individual, best->is_active); - pr_debug("best ports %p slave %p %s\n", - best->lag_ports, best->slave, - best->slave ? best->slave->dev->name : "NULL"); + netdev_dbg(bond->dev, "best Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", + best->aggregator_identifier, best->num_of_ports, + best->actor_oper_aggregator_key, + best->partner_oper_aggregator_key, + best->is_individual, best->is_active); + netdev_dbg(bond->dev, "best ports %p slave %p %s\n", + best->lag_ports, best->slave, + best->slave ? best->slave->dev->name : "NULL"); bond_for_each_slave_rcu(bond, slave, iter) { agg = &(SLAVE_AD_INFO(slave)->aggregator); - pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", - agg->aggregator_identifier, agg->num_of_ports, - agg->actor_oper_aggregator_key, - agg->partner_oper_aggregator_key, - agg->is_individual, agg->is_active); + netdev_dbg(bond->dev, "Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", + agg->aggregator_identifier, agg->num_of_ports, + agg->actor_oper_aggregator_key, + agg->partner_oper_aggregator_key, + agg->is_individual, agg->is_active); } /* check if any partner replys */ if (best->is_individual) { - pr_warn_ratelimited("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n", - best->slave ? - best->slave->bond->dev->name : "NULL"); + net_warn_ratelimited("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n", + best->slave ? + best->slave->bond->dev->name : "NULL"); } best->is_active = 1; - pr_debug("LAG %d chosen as the active LAG\n", - best->aggregator_identifier); - pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", - best->aggregator_identifier, best->num_of_ports, - best->actor_oper_aggregator_key, - best->partner_oper_aggregator_key, - best->is_individual, best->is_active); + netdev_dbg(bond->dev, "LAG %d chosen as the active LAG\n", + best->aggregator_identifier); + netdev_dbg(bond->dev, "Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", + best->aggregator_identifier, best->num_of_ports, + best->actor_oper_aggregator_key, + best->partner_oper_aggregator_key, + best->is_individual, best->is_active); /* disable the ports that were related to the former * active_aggregator @@ -1908,13 +1906,13 @@ void bond_3ad_unbind_slave(struct slave *slave) /* if slave is null, the whole port is not initialized */ if (!port->slave) { - pr_warn("Warning: %s: Trying to unbind an uninitialized port on %s\n", - slave->bond->dev->name, slave->dev->name); + netdev_warn(bond->dev, "Trying to unbind an uninitialized port on %s\n", + slave->dev->name); return; } - pr_debug("Unbinding Link Aggregation Group %d\n", - aggregator->aggregator_identifier); + netdev_dbg(bond->dev, "Unbinding Link Aggregation Group %d\n", + aggregator->aggregator_identifier); /* Tell the partner that this port is not suitable for aggregation */ port->actor_oper_port_state &= ~AD_STATE_AGGREGATION; @@ -1949,14 +1947,13 @@ void bond_3ad_unbind_slave(struct slave *slave) * new aggregator */ if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) { - pr_debug("Some port(s) related to LAG %d - replacing with LAG %d\n", - aggregator->aggregator_identifier, - new_aggregator->aggregator_identifier); + netdev_dbg(bond->dev, "Some port(s) related to LAG %d - replacing with LAG %d\n", + aggregator->aggregator_identifier, + new_aggregator->aggregator_identifier); if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) { - pr_info("%s: Removing an active aggregator\n", - aggregator->slave->bond->dev->name); + netdev_info(bond->dev, "Removing an active aggregator\n"); select_new_active_agg = 1; } @@ -1986,8 +1983,7 @@ void bond_3ad_unbind_slave(struct slave *slave) if (select_new_active_agg) ad_agg_selection_logic(__get_first_agg(port)); } else { - pr_warn("%s: Warning: unbinding aggregator, and could not find a new aggregator for its ports\n", - slave->bond->dev->name); + netdev_warn(bond->dev, "unbinding aggregator, and could not find a new aggregator for its ports\n"); } } else { /* in case that the only port related to this @@ -1996,8 +1992,7 @@ void bond_3ad_unbind_slave(struct slave *slave) select_new_active_agg = aggregator->is_active; ad_clear_agg(aggregator); if (select_new_active_agg) { - pr_info("%s: Removing an active aggregator\n", - slave->bond->dev->name); + netdev_info(bond->dev, "Removing an active aggregator\n"); /* select new active aggregator */ temp_aggregator = __get_first_agg(port); if (temp_aggregator) @@ -2006,7 +2001,7 @@ void bond_3ad_unbind_slave(struct slave *slave) } } - pr_debug("Unbinding port %d\n", port->actor_port_number); + netdev_dbg(bond->dev, "Unbinding port %d\n", port->actor_port_number); /* find the aggregator that this port is connected to */ bond_for_each_slave(bond, slave_iter, iter) { @@ -2029,8 +2024,7 @@ void bond_3ad_unbind_slave(struct slave *slave) select_new_active_agg = temp_aggregator->is_active; ad_clear_agg(temp_aggregator); if (select_new_active_agg) { - pr_info("%s: Removing an active aggregator\n", - slave->bond->dev->name); + netdev_info(bond->dev, "Removing an active aggregator\n"); /* select new active aggregator */ ad_agg_selection_logic(__get_first_agg(port)); } @@ -2081,8 +2075,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work) /* select the active aggregator for the bond */ if (port) { if (!port->slave) { - pr_warn_ratelimited("%s: Warning: bond's first port is uninitialized\n", - bond->dev->name); + net_warn_ratelimited("%s: Warning: bond's first port is uninitialized\n", + bond->dev->name); goto re_arm; } @@ -2096,7 +2090,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work) bond_for_each_slave_rcu(bond, slave, iter) { port = &(SLAVE_AD_INFO(slave)->port); if (!port->slave) { - pr_warn_ratelimited("%s: Warning: Found an uninitialized port\n", + net_warn_ratelimited("%s: Warning: Found an uninitialized port\n", bond->dev->name); goto re_arm; } @@ -2158,16 +2152,16 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, port = &(SLAVE_AD_INFO(slave)->port); if (!port->slave) { - pr_warn_ratelimited("%s: Warning: port of slave %s is uninitialized\n", - slave->dev->name, slave->bond->dev->name); + net_warn_ratelimited("%s: Warning: port of slave %s is uninitialized\n", + slave->dev->name, slave->bond->dev->name); return ret; } switch (lacpdu->subtype) { case AD_TYPE_LACPDU: ret = RX_HANDLER_CONSUMED; - pr_debug("Received LACPDU on port %d\n", - port->actor_port_number); + netdev_dbg(slave->bond->dev, "Received LACPDU on port %d\n", + port->actor_port_number); /* Protect against concurrent state machines */ __get_state_machine_lock(port); ad_rx_machine(lacpdu, port); @@ -2182,20 +2176,20 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, switch (((struct bond_marker *)lacpdu)->tlv_type) { case AD_MARKER_INFORMATION_SUBTYPE: - pr_debug("Received Marker Information on port %d\n", - port->actor_port_number); + netdev_dbg(slave->bond->dev, "Received Marker Information on port %d\n", + port->actor_port_number); ad_marker_info_received((struct bond_marker *)lacpdu, port); break; case AD_MARKER_RESPONSE_SUBTYPE: - pr_debug("Received Marker Response on port %d\n", - port->actor_port_number); + netdev_dbg(slave->bond->dev, "Received Marker Response on port %d\n", + port->actor_port_number); ad_marker_response_received((struct bond_marker *)lacpdu, port); break; default: - pr_debug("Received an unknown Marker subtype on slot %d\n", - port->actor_port_number); + netdev_dbg(slave->bond->dev, "Received an unknown Marker subtype on slot %d\n", + port->actor_port_number); } } } @@ -2216,8 +2210,8 @@ void bond_3ad_adapter_speed_changed(struct slave *slave) /* if slave is null, the whole port is not initialized */ if (!port->slave) { - pr_warn("Warning: %s: speed changed for uninitialized port on %s\n", - slave->bond->dev->name, slave->dev->name); + netdev_warn(slave->bond->dev, "speed changed for uninitialized port on %s\n", + slave->dev->name); return; } @@ -2226,7 +2220,7 @@ void bond_3ad_adapter_speed_changed(struct slave *slave) port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS; port->actor_oper_port_key = port->actor_admin_port_key |= (__get_link_speed(port) << 1); - pr_debug("Port %d changed speed\n", port->actor_port_number); + netdev_dbg(slave->bond->dev, "Port %d changed speed\n", port->actor_port_number); /* there is no need to reselect a new aggregator, just signal the * state machines to reinitialize */ @@ -2249,8 +2243,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) /* if slave is null, the whole port is not initialized */ if (!port->slave) { - pr_warn("%s: Warning: duplex changed for uninitialized port on %s\n", - slave->bond->dev->name, slave->dev->name); + netdev_warn(slave->bond->dev, "duplex changed for uninitialized port on %s\n", + slave->dev->name); return; } @@ -2259,7 +2253,7 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; port->actor_oper_port_key = port->actor_admin_port_key |= __get_duplex(port); - pr_debug("Port %d changed duplex\n", port->actor_port_number); + netdev_dbg(slave->bond->dev, "Port %d changed duplex\n", port->actor_port_number); /* there is no need to reselect a new aggregator, just signal the * state machines to reinitialize */ @@ -2283,8 +2277,8 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) /* if slave is null, the whole port is not initialized */ if (!port->slave) { - pr_warn("Warning: %s: link status changed for uninitialized port on %s\n", - slave->bond->dev->name, slave->dev->name); + netdev_warn(slave->bond->dev, "link status changed for uninitialized port on %s\n", + slave->dev->name); return; } @@ -2311,9 +2305,9 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) port->actor_oper_port_key = (port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS); } - pr_debug("Port %d changed link status to %s\n", - port->actor_port_number, - link == BOND_LINK_UP ? "UP" : "DOWN"); + netdev_dbg(slave->bond->dev, "Port %d changed link status to %s\n", + port->actor_port_number, + link == BOND_LINK_UP ? "UP" : "DOWN"); /* there is no need to reselect a new aggregator, just signal the * state machines to reinitialize */ @@ -2427,8 +2421,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) int agg_id; if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { - pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n", - dev->name); + netdev_dbg(dev, "__bond_3ad_get_active_agg_info failed\n"); goto err_free; } @@ -2436,7 +2429,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) agg_id = ad_info.aggregator_id; if (slaves_in_agg == 0) { - pr_debug("%s: Error: active aggregator is empty\n", dev->name); + netdev_dbg(dev, "active aggregator is empty\n"); goto err_free; } @@ -2462,8 +2455,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) } if (slave_agg_no >= 0) { - pr_err("%s: Error: Couldn't find a slave to tx on for aggregator ID %d\n", - dev->name, agg_id); + netdev_err(dev, "Couldn't find a slave to tx on for aggregator ID %d\n", + agg_id); goto err_free; } -- cgit v1.2.3 From dbfddcfdd0aa5a67923838b5899d5fa994a672eb Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 19:36:01 +0200 Subject: bonding: remove pr_fmt from bond_3ad.c To maintain the same message structure as netdev_* functions print. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 159c451324ce..ee2c73a9de39 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -20,8 +20,6 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include -- cgit v1.2.3 From 0a111a03f474dfd04e119ea095c3cff4192fccd1 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 19:36:02 +0200 Subject: bonding: convert bond_alb.c to use netdev_printk instead of pr_ CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index de5bd03925b4..194a45bd1ef7 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -369,7 +369,7 @@ static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond, if (arp->op_code == htons(ARPOP_REPLY)) { /* update rx hash table for this ARP */ rlb_update_entry_from_arp(bond, arp); - pr_debug("Server received an ARP Reply from client\n"); + netdev_dbg(bond->dev, "Server received an ARP Reply from client\n"); } out: return RX_HANDLER_ANOTHER; @@ -535,8 +535,8 @@ static void rlb_update_client(struct rlb_client_info *client_info) client_info->slave->dev->dev_addr, client_info->mac_dst); if (!skb) { - pr_err("%s: Error: failed to create an ARP packet\n", - client_info->slave->bond->dev->name); + netdev_err(client_info->slave->bond->dev, + "failed to create an ARP packet\n"); continue; } @@ -545,8 +545,8 @@ static void rlb_update_client(struct rlb_client_info *client_info) if (client_info->vlan_id) { skb = vlan_put_tag(skb, htons(ETH_P_8021Q), client_info->vlan_id); if (!skb) { - pr_err("%s: Error: failed to insert VLAN tag\n", - client_info->slave->bond->dev->name); + netdev_err(client_info->slave->bond->dev, + "failed to insert VLAN tag\n"); continue; } } @@ -630,8 +630,7 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip) client_info = &(bond_info->rx_hashtbl[hash_index]); if (!client_info->slave) { - pr_err("%s: Error: found a client with no channel in the client's hash table\n", - bond->dev->name); + netdev_err(bond->dev, "found a client with no channel in the client's hash table\n"); continue; } /*update all clients using this src_ip, that are not assigned @@ -767,7 +766,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) tx_slave = rlb_choose_channel(skb, bond); if (tx_slave) ether_addr_copy(arp->mac_src, tx_slave->dev->dev_addr); - pr_debug("Server sent ARP Reply packet\n"); + netdev_dbg(bond->dev, "Server sent ARP Reply packet\n"); } else if (arp->op_code == htons(ARPOP_REQUEST)) { /* Create an entry in the rx_hashtbl for this client as a * place holder. @@ -787,7 +786,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) * updated with their assigned mac. */ rlb_req_update_subnet_clients(bond, arp->ip_src); - pr_debug("Server sent ARP Request packet\n"); + netdev_dbg(bond->dev, "Server sent ARP Request packet\n"); } return tx_slave; @@ -1026,8 +1025,7 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[], if (vid) { skb = vlan_put_tag(skb, vlan_proto, vid); if (!skb) { - pr_err("%s: Error: failed to insert VLAN tag\n", - slave->bond->dev->name); + netdev_err(slave->bond->dev, "failed to insert VLAN tag\n"); return; } } @@ -1093,9 +1091,8 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[]) memcpy(s_addr.sa_data, addr, dev->addr_len); s_addr.sa_family = dev->type; if (dev_set_mac_address(dev, &s_addr)) { - pr_err("%s: Error: dev_set_mac_address of dev %s failed!\n" - "ALB mode requires that the base driver support setting the hw address also when the network device's interface is open\n", - slave->bond->dev->name, dev->name); + netdev_err(slave->bond->dev, "dev_set_mac_address of dev %s failed! ALB mode requires that the base driver support setting the hw address also when the network device's interface is open\n", + dev->name); return -EOPNOTSUPP; } return 0; @@ -1269,13 +1266,12 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav if (free_mac_slave) { alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr); - pr_warn("%s: Warning: the hw address of slave %s is in use by the bond; giving it the hw address of %s\n", - bond->dev->name, slave->dev->name, - free_mac_slave->dev->name); + netdev_warn(bond->dev, "the hw address of slave %s is in use by the bond; giving it the hw address of %s\n", + slave->dev->name, free_mac_slave->dev->name); } else if (has_bond_addr) { - pr_err("%s: Error: the hw address of slave %s is in use by the bond; couldn't find a slave with a free hw address to give it (this should not have happened)\n", - bond->dev->name, slave->dev->name); + netdev_err(bond->dev, "the hw address of slave %s is in use by the bond; couldn't find a slave with a free hw address to give it (this should not have happened)\n", + slave->dev->name); return -EFAULT; } -- cgit v1.2.3 From abaf98ef8078a48157027ec3168c4f4c8c13f48a Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 19:36:03 +0200 Subject: bonding: remove pr_fmt from bond_alb.c To maintain the same message structure as netdev_* functions print. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 194a45bd1ef7..f16442fa97ff 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -19,8 +19,6 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include -- cgit v1.2.3 From 9ef1cf16cfc789eb631eb38d46d5dbfb36832546 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 19:36:04 +0200 Subject: bonding: convert bond_debugfs.c to use netdev_printk instead of pr_ One occurance left intact as it's unrelated to net_device. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_debugfs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c index 658e761c4568..280971b227ea 100644 --- a/drivers/net/bonding/bond_debugfs.c +++ b/drivers/net/bonding/bond_debugfs.c @@ -69,8 +69,7 @@ void bond_debug_register(struct bonding *bond) debugfs_create_dir(bond->dev->name, bonding_debug_root); if (!bond->debug_dir) { - pr_warn("%s: Warning: failed to register to debugfs\n", - bond->dev->name); + netdev_warn(bond->dev, "failed to register to debugfs\n"); return; } @@ -98,8 +97,7 @@ void bond_debug_reregister(struct bonding *bond) if (d) { bond->debug_dir = d; } else { - pr_warn("%s: Warning: failed to reregister, so just unregister old one\n", - bond->dev->name); + netdev_warn(bond->dev, "failed to reregister, so just unregister old one\n"); bond_debug_unregister(bond); } } -- cgit v1.2.3 From a5f24542ab61f4dc3d07fb4ae7d8903c3040449a Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 19:36:05 +0200 Subject: bonding: convert bond_netlink.c to use netdev_printk instead of pr_ CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 4d97e23eb497..6b58f8af88cc 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -181,8 +181,7 @@ static int bond_changelink(struct net_device *bond_dev, int arp_interval = nla_get_u32(data[IFLA_BOND_ARP_INTERVAL]); if (arp_interval && miimon) { - pr_err("%s: ARP monitoring cannot be used with MII monitoring\n", - bond->dev->name); + netdev_err(bond->dev, "ARP monitoring cannot be used with MII monitoring\n"); return -EINVAL; } @@ -207,8 +206,7 @@ static int bond_changelink(struct net_device *bond_dev, i++; } if (i == 0 && bond->params.arp_interval) - pr_warn("%s: Removing last arp target with arp_interval on\n", - bond->dev->name); + netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n"); if (err) return err; } @@ -216,8 +214,7 @@ static int bond_changelink(struct net_device *bond_dev, int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]); if (arp_validate && miimon) { - pr_err("%s: ARP validating cannot be used with MII monitoring\n", - bond->dev->name); + netdev_err(bond->dev, "ARP validating cannot be used with MII monitoring\n"); return -EINVAL; } -- cgit v1.2.3 From 6a9fc6f14a3c183a1a9df6d4a5e6ecb11beafb82 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 19:36:06 +0200 Subject: bonding: bonding: remove pr_fmt from bond_netlink.c To maintain the same message structure as netdev_* functions print. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 6b58f8af88cc..d163e112f04c 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -9,8 +9,6 @@ * (at your option) any later version. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include -- cgit v1.2.3 From c735ee6c4376663f1a7a281c837d839037792748 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 19:36:07 +0200 Subject: bonding: convert bond_procfs.c to use netdev_printk instead of pr_ CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_procfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index b215b479bb3a..de62c0385dfb 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -252,8 +252,8 @@ void bond_create_proc_entry(struct bonding *bond) S_IRUGO, bn->proc_dir, &bond_info_fops, bond); if (bond->proc_entry == NULL) - pr_warn("Warning: Cannot create /proc/net/%s/%s\n", - DRV_NAME, bond_dev->name); + netdev_warn(bond_dev, "Cannot create /proc/net/%s/%s\n", + DRV_NAME, bond_dev->name); else memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ); } -- cgit v1.2.3 From 2de390bace7c533c88359404911ff6e080de4004 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 19:36:08 +0200 Subject: bonding: convert bond_options.c to use netdev_printk instead of pr_ CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_options.c | 216 +++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 115 deletions(-) diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index cf720ce1b69e..1e28de28dddd 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -544,9 +544,8 @@ static void bond_opt_dep_print(struct bonding *bond, params = &bond->params; modeval = bond_opt_get_val(BOND_OPT_MODE, params->mode); if (test_bit(params->mode, &opt->unsuppmodes)) - pr_err("%s: option %s: mode dependency failed, not supported in mode %s(%llu)\n", - bond->dev->name, opt->name, - modeval->string, modeval->value); + netdev_err(bond->dev, "option %s: mode dependency failed, not supported in mode %s(%llu)\n", + opt->name, modeval->string, modeval->value); } static void bond_opt_error_interpret(struct bonding *bond, @@ -564,31 +563,30 @@ static void bond_opt_error_interpret(struct bonding *bond, p = strchr(val->string, '\n'); if (p) *p = '\0'; - pr_err("%s: option %s: invalid value (%s)\n", - bond->dev->name, opt->name, val->string); + netdev_err(bond->dev, "option %s: invalid value (%s)\n", + opt->name, val->string); } else { - pr_err("%s: option %s: invalid value (%llu)\n", - bond->dev->name, opt->name, val->value); + netdev_err(bond->dev, "option %s: invalid value (%llu)\n", + opt->name, val->value); } } minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN); maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX); if (!maxval) break; - pr_err("%s: option %s: allowed values %llu - %llu\n", - bond->dev->name, opt->name, minval ? minval->value : 0, - maxval->value); + netdev_err(bond->dev, "option %s: allowed values %llu - %llu\n", + opt->name, minval ? minval->value : 0, maxval->value); break; case -EACCES: bond_opt_dep_print(bond, opt); break; case -ENOTEMPTY: - pr_err("%s: option %s: unable to set because the bond device has slaves\n", - bond->dev->name, opt->name); + netdev_err(bond->dev, "option %s: unable to set because the bond device has slaves\n", + opt->name); break; case -EBUSY: - pr_err("%s: option %s: unable to set because the bond device is up\n", - bond->dev->name, opt->name); + netdev_err(bond->dev, "option %s: unable to set because the bond device is up\n", + opt->name); break; default: break; @@ -675,14 +673,14 @@ static int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newval) { if (!bond_mode_uses_arp(newval->value) && bond->params.arp_interval) { - pr_info("%s: %s mode is incompatible with arp monitoring, start mii monitoring\n", - bond->dev->name, newval->string); + netdev_info(bond->dev, "%s mode is incompatible with arp monitoring, start mii monitoring\n", + newval->string); /* disable arp monitoring */ bond->params.arp_interval = 0; /* set miimon to default value */ bond->params.miimon = BOND_DEFAULT_MIIMON; - pr_info("%s: Setting MII monitoring interval to %d\n", - bond->dev->name, bond->params.miimon); + netdev_info(bond->dev, "Setting MII monitoring interval to %d\n", + bond->params.miimon); } /* don't cache arp_validate between modes */ @@ -723,14 +721,14 @@ static int bond_option_active_slave_set(struct bonding *bond, if (slave_dev) { if (!netif_is_bond_slave(slave_dev)) { - pr_err("Device %s is not bonding slave\n", - slave_dev->name); + netdev_err(bond->dev, "Device %s is not bonding slave\n", + slave_dev->name); return -EINVAL; } if (bond->dev != netdev_master_upper_dev_get(slave_dev)) { - pr_err("%s: Device %s is not our slave\n", - bond->dev->name, slave_dev->name); + netdev_err(bond->dev, "Device %s is not our slave\n", + slave_dev->name); return -EINVAL; } } @@ -740,7 +738,7 @@ static int bond_option_active_slave_set(struct bonding *bond, /* check to see if we are clearing active */ if (!slave_dev) { - pr_info("%s: Clearing current active slave\n", bond->dev->name); + netdev_info(bond->dev, "Clearing current active slave\n"); RCU_INIT_POINTER(bond->curr_active_slave, NULL); bond_select_active_slave(bond); } else { @@ -751,18 +749,18 @@ static int bond_option_active_slave_set(struct bonding *bond, if (new_active == old_active) { /* do nothing */ - pr_info("%s: %s is already the current active slave\n", - bond->dev->name, new_active->dev->name); + netdev_info(bond->dev, "%s is already the current active slave\n", + new_active->dev->name); } else { if (old_active && (new_active->link == BOND_LINK_UP) && bond_slave_is_up(new_active)) { - pr_info("%s: Setting %s as active slave\n", - bond->dev->name, new_active->dev->name); + netdev_info(bond->dev, "Setting %s as active slave\n", + new_active->dev->name); bond_change_active_slave(bond, new_active); } else { - pr_err("%s: Could not set %s as active slave; either %s is down or the link is down\n", - bond->dev->name, new_active->dev->name, - new_active->dev->name); + netdev_err(bond->dev, "Could not set %s as active slave; either %s is down or the link is down\n", + new_active->dev->name, + new_active->dev->name); ret = -EINVAL; } } @@ -781,20 +779,17 @@ static int bond_option_active_slave_set(struct bonding *bond, static int bond_option_miimon_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting MII monitoring interval to %llu\n", - bond->dev->name, newval->value); + netdev_info(bond->dev, "Setting MII monitoring interval to %llu\n", + newval->value); bond->params.miimon = newval->value; if (bond->params.updelay) - pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value\n", - bond->dev->name, + netdev_info(bond->dev, "Note: Updating updelay (to %d) since it is a multiple of the miimon value\n", bond->params.updelay * bond->params.miimon); if (bond->params.downdelay) - pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n", - bond->dev->name, - bond->params.downdelay * bond->params.miimon); + netdev_info(bond->dev, "Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n", + bond->params.downdelay * bond->params.miimon); if (newval->value && bond->params.arp_interval) { - pr_info("%s: MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n", - bond->dev->name); + netdev_info(bond->dev, "MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n"); bond->params.arp_interval = 0; if (bond->params.arp_validate) bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; @@ -826,20 +821,18 @@ static int bond_option_updelay_set(struct bonding *bond, int value = newval->value; if (!bond->params.miimon) { - pr_err("%s: Unable to set up delay as MII monitoring is disabled\n", - bond->dev->name); + netdev_err(bond->dev, "Unable to set up delay as MII monitoring is disabled\n"); return -EPERM; } if ((value % bond->params.miimon) != 0) { - pr_warn("%s: Warning: up delay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n", - bond->dev->name, value, - bond->params.miimon, - (value / bond->params.miimon) * - bond->params.miimon); + netdev_warn(bond->dev, "up delay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n", + value, bond->params.miimon, + (value / bond->params.miimon) * + bond->params.miimon); } bond->params.updelay = value / bond->params.miimon; - pr_info("%s: Setting up delay to %d\n", - bond->dev->name, bond->params.updelay * bond->params.miimon); + netdev_info(bond->dev, "Setting up delay to %d\n", + bond->params.updelay * bond->params.miimon); return 0; } @@ -850,20 +843,18 @@ static int bond_option_downdelay_set(struct bonding *bond, int value = newval->value; if (!bond->params.miimon) { - pr_err("%s: Unable to set down delay as MII monitoring is disabled\n", - bond->dev->name); + netdev_err(bond->dev, "Unable to set down delay as MII monitoring is disabled\n"); return -EPERM; } if ((value % bond->params.miimon) != 0) { - pr_warn("%s: Warning: down delay (%d) is not a multiple of miimon (%d), delay rounded to %d ms\n", - bond->dev->name, value, - bond->params.miimon, - (value / bond->params.miimon) * - bond->params.miimon); + netdev_warn(bond->dev, "down delay (%d) is not a multiple of miimon (%d), delay rounded to %d ms\n", + value, bond->params.miimon, + (value / bond->params.miimon) * + bond->params.miimon); } bond->params.downdelay = value / bond->params.miimon; - pr_info("%s: Setting down delay to %d\n", - bond->dev->name, bond->params.downdelay * bond->params.miimon); + netdev_info(bond->dev, "Setting down delay to %d\n", + bond->params.downdelay * bond->params.miimon); return 0; } @@ -871,8 +862,8 @@ static int bond_option_downdelay_set(struct bonding *bond, static int bond_option_use_carrier_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting use_carrier to %llu\n", - bond->dev->name, newval->value); + netdev_info(bond->dev, "Setting use_carrier to %llu\n", + newval->value); bond->params.use_carrier = newval->value; return 0; @@ -885,18 +876,16 @@ static int bond_option_use_carrier_set(struct bonding *bond, static int bond_option_arp_interval_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting ARP monitoring interval to %llu\n", - bond->dev->name, newval->value); + netdev_info(bond->dev, "Setting ARP monitoring interval to %llu\n", + newval->value); bond->params.arp_interval = newval->value; if (newval->value) { if (bond->params.miimon) { - pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring\n", - bond->dev->name, bond->dev->name); + netdev_info(bond->dev, "ARP monitoring cannot be used with MII monitoring. Disabling MII monitoring\n"); bond->params.miimon = 0; } if (!bond->params.arp_targets[0]) - pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified\n", - bond->dev->name); + netdev_info(bond->dev, "ARP monitoring has been set up, but no ARP targets have been specified\n"); } if (bond->dev->flags & IFF_UP) { /* If the interface is up, we may need to fire off @@ -940,24 +929,24 @@ static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target) int ind; if (!bond_is_ip_target_ok(target)) { - pr_err("%s: invalid ARP target %pI4 specified for addition\n", - bond->dev->name, &target); + netdev_err(bond->dev, "invalid ARP target %pI4 specified for addition\n", + &target); return -EINVAL; } if (bond_get_targets_ip(targets, target) != -1) { /* dup */ - pr_err("%s: ARP target %pI4 is already present\n", - bond->dev->name, &target); + netdev_err(bond->dev, "ARP target %pI4 is already present\n", + &target); return -EINVAL; } ind = bond_get_targets_ip(targets, 0); /* first free slot */ if (ind == -1) { - pr_err("%s: ARP target table is full!\n", bond->dev->name); + netdev_err(bond->dev, "ARP target table is full!\n"); return -EINVAL; } - pr_info("%s: Adding ARP target %pI4\n", bond->dev->name, &target); + netdev_info(bond->dev, "Adding ARP target %pI4\n", &target); _bond_options_arp_ip_target_set(bond, ind, target, jiffies); @@ -985,23 +974,22 @@ static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target) int ind, i; if (!bond_is_ip_target_ok(target)) { - pr_err("%s: invalid ARP target %pI4 specified for removal\n", - bond->dev->name, &target); + netdev_err(bond->dev, "invalid ARP target %pI4 specified for removal\n", + &target); return -EINVAL; } ind = bond_get_targets_ip(targets, target); if (ind == -1) { - pr_err("%s: unable to remove nonexistent ARP target %pI4\n", - bond->dev->name, &target); + netdev_err(bond->dev, "unable to remove nonexistent ARP target %pI4\n", + &target); return -EINVAL; } if (ind == 0 && !targets[1] && bond->params.arp_interval) - pr_warn("%s: Removing last arp target with arp_interval on\n", - bond->dev->name); + netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n"); - pr_info("%s: Removing ARP target %pI4\n", bond->dev->name, &target); + netdev_info(bond->dev, "Removing ARP target %pI4\n", &target); /* not to race with bond_arp_rcv */ write_lock_bh(&bond->lock); @@ -1040,8 +1028,8 @@ static int bond_option_arp_ip_targets_set(struct bonding *bond, if (newval->string) { if (!in4_pton(newval->string+1, -1, (u8 *)&target, -1, NULL)) { - pr_err("%s: invalid ARP target %pI4 specified\n", - bond->dev->name, &target); + netdev_err(bond->dev, "invalid ARP target %pI4 specified\n", + &target); return ret; } if (newval->string[0] == '+') @@ -1049,8 +1037,7 @@ static int bond_option_arp_ip_targets_set(struct bonding *bond, else if (newval->string[0] == '-') ret = bond_option_arp_ip_target_rem(bond, target); else - pr_err("no command found in arp_ip_targets file for bond %s - use + or -\n", - bond->dev->name); + netdev_err(bond->dev, "no command found in arp_ip_targets file - use + or -\n"); } else { target = newval->value; ret = bond_option_arp_ip_target_add(bond, target); @@ -1062,8 +1049,8 @@ static int bond_option_arp_ip_targets_set(struct bonding *bond, static int bond_option_arp_validate_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting arp_validate to %s (%llu)\n", - bond->dev->name, newval->string, newval->value); + netdev_info(bond->dev, "Setting arp_validate to %s (%llu)\n", + newval->string, newval->value); if (bond->dev->flags & IFF_UP) { if (!newval->value) @@ -1079,8 +1066,8 @@ static int bond_option_arp_validate_set(struct bonding *bond, static int bond_option_arp_all_targets_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting arp_all_targets to %s (%llu)\n", - bond->dev->name, newval->string, newval->value); + netdev_info(bond->dev, "Setting arp_all_targets to %s (%llu)\n", + newval->string, newval->value); bond->params.arp_all_targets = newval->value; return 0; @@ -1102,7 +1089,7 @@ static int bond_option_primary_set(struct bonding *bond, *p = '\0'; /* check to see if we are clearing primary */ if (!strlen(primary)) { - pr_info("%s: Setting primary slave to None\n", bond->dev->name); + netdev_info(bond->dev, "Setting primary slave to None\n"); bond->primary_slave = NULL; memset(bond->params.primary, 0, sizeof(bond->params.primary)); bond_select_active_slave(bond); @@ -1111,8 +1098,8 @@ static int bond_option_primary_set(struct bonding *bond, bond_for_each_slave(bond, slave, iter) { if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) { - pr_info("%s: Setting %s as primary slave\n", - bond->dev->name, slave->dev->name); + netdev_info(bond->dev, "Setting %s as primary slave\n", + slave->dev->name); bond->primary_slave = slave; strcpy(bond->params.primary, slave->dev->name); bond_select_active_slave(bond); @@ -1121,15 +1108,15 @@ static int bond_option_primary_set(struct bonding *bond, } if (bond->primary_slave) { - pr_info("%s: Setting primary slave to None\n", bond->dev->name); + netdev_info(bond->dev, "Setting primary slave to None\n"); bond->primary_slave = NULL; bond_select_active_slave(bond); } strncpy(bond->params.primary, primary, IFNAMSIZ); bond->params.primary[IFNAMSIZ - 1] = 0; - pr_info("%s: Recording %s as primary, but it has not been enslaved to %s yet\n", - bond->dev->name, primary, bond->dev->name); + netdev_info(bond->dev, "Recording %s as primary, but it has not been enslaved to %s yet\n", + primary, bond->dev->name); out: write_unlock_bh(&bond->curr_slave_lock); @@ -1142,8 +1129,8 @@ out: static int bond_option_primary_reselect_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting primary_reselect to %s (%llu)\n", - bond->dev->name, newval->string, newval->value); + netdev_info(bond->dev, "Setting primary_reselect to %s (%llu)\n", + newval->string, newval->value); bond->params.primary_reselect = newval->value; block_netpoll_tx(); @@ -1158,8 +1145,8 @@ static int bond_option_primary_reselect_set(struct bonding *bond, static int bond_option_fail_over_mac_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting fail_over_mac to %s (%llu)\n", - bond->dev->name, newval->string, newval->value); + netdev_info(bond->dev, "Setting fail_over_mac to %s (%llu)\n", + newval->string, newval->value); bond->params.fail_over_mac = newval->value; return 0; @@ -1168,8 +1155,8 @@ static int bond_option_fail_over_mac_set(struct bonding *bond, static int bond_option_xmit_hash_policy_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting xmit hash policy to %s (%llu)\n", - bond->dev->name, newval->string, newval->value); + netdev_info(bond->dev, "Setting xmit hash policy to %s (%llu)\n", + newval->string, newval->value); bond->params.xmit_policy = newval->value; return 0; @@ -1178,8 +1165,8 @@ static int bond_option_xmit_hash_policy_set(struct bonding *bond, static int bond_option_resend_igmp_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting resend_igmp to %llu\n", - bond->dev->name, newval->value); + netdev_info(bond->dev, "Setting resend_igmp to %llu\n", + newval->value); bond->params.resend_igmp = newval->value; return 0; @@ -1217,8 +1204,8 @@ static int bond_option_all_slaves_active_set(struct bonding *bond, static int bond_option_min_links_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting min links value to %llu\n", - bond->dev->name, newval->value); + netdev_info(bond->dev, "Setting min links value to %llu\n", + newval->value); bond->params.min_links = newval->value; return 0; @@ -1253,8 +1240,8 @@ static int bond_option_pps_set(struct bonding *bond, static int bond_option_lacp_rate_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting LACP rate to %s (%llu)\n", - bond->dev->name, newval->string, newval->value); + netdev_info(bond->dev, "Setting LACP rate to %s (%llu)\n", + newval->string, newval->value); bond->params.lacp_fast = newval->value; bond_3ad_update_lacp_rate(bond); @@ -1264,8 +1251,8 @@ static int bond_option_lacp_rate_set(struct bonding *bond, static int bond_option_ad_select_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting ad_select to %s (%llu)\n", - bond->dev->name, newval->string, newval->value); + netdev_info(bond->dev, "Setting ad_select to %s (%llu)\n", + newval->string, newval->value); bond->params.ad_select = newval->value; return 0; @@ -1326,7 +1313,7 @@ out: return ret; err_no_cmd: - pr_info("invalid input for queue_id set for %s\n", bond->dev->name); + netdev_info(bond->dev, "invalid input for queue_id set\n"); ret = -EPERM; goto out; @@ -1348,20 +1335,20 @@ static int bond_option_slaves_set(struct bonding *bond, dev = __dev_get_by_name(dev_net(bond->dev), ifname); if (!dev) { - pr_info("%s: interface %s does not exist!\n", - bond->dev->name, ifname); + netdev_info(bond->dev, "interface %s does not exist!\n", + ifname); ret = -ENODEV; goto out; } switch (command[0]) { case '+': - pr_info("%s: Adding slave %s\n", bond->dev->name, dev->name); + netdev_info(bond->dev, "Adding slave %s\n", dev->name); ret = bond_enslave(bond->dev, dev); break; case '-': - pr_info("%s: Removing slave %s\n", bond->dev->name, dev->name); + netdev_info(bond->dev, "Removing slave %s\n", dev->name); ret = bond_release(bond->dev, dev); break; @@ -1373,8 +1360,7 @@ out: return ret; err_no_cmd: - pr_err("no command found in slaves file for bond %s - use +ifname or -ifname\n", - bond->dev->name); + netdev_err(bond->dev, "no command found in slaves file - use +ifname or -ifname\n"); ret = -EPERM; goto out; } @@ -1382,8 +1368,8 @@ err_no_cmd: static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, const struct bond_opt_value *newval) { - pr_info("%s: Setting dynamic-lb to %s (%llu)\n", - bond->dev->name, newval->string, newval->value); + netdev_info(bond->dev, "Setting dynamic-lb to %s (%llu)\n", + newval->string, newval->value); bond->params.tlb_dynamic_lb = newval->value; return 0; -- cgit v1.2.3 From cb25235860c8b6552a8f9cca3291e9d46efb7925 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 15 Jul 2014 19:36:09 +0200 Subject: bonding: remove pr_fmt from bond_options.c To maintain the same message structure as netdev_* functions print. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_options.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 1e28de28dddd..dc73463c2c23 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -9,8 +9,6 @@ * (at your option) any later version. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include -- cgit v1.2.3 From ba165a90b59812ab1d9cd2943fd104cfc25c601e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 11:42:26 +0300 Subject: Bluetooth: Add proper defines for HCI connection role All HCI commands and events, including LE ones, use 0x00 for master role and 0x01 for slave role. It makes therefore sense to add generic defines for these instead of the current LE_CONN_ROLE_MASTER. Having clean defines will also make it possible to provide simpler internal APIs. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 6 +++--- net/bluetooth/hci_event.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 2fee852816ee..f0a3d8890760 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -401,6 +401,9 @@ enum { /* The core spec defines 127 as the "not available" value */ #define HCI_TX_POWER_INVALID 127 +#define HCI_ROLE_MASTER 0x00 +#define HCI_ROLE_SLAVE 0x01 + /* Extended Inquiry Response field types */ #define EIR_FLAGS 0x01 /* flags */ #define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ @@ -1713,9 +1716,6 @@ struct hci_ev_sync_train_complete { #define HCI_EV_SLAVE_PAGE_RESP_TIMEOUT 0x54 -/* Low energy meta events */ -#define LE_CONN_ROLE_MASTER 0x00 - #define HCI_EV_LE_CONN_COMPLETE 0x01 struct hci_ev_le_conn_complete { __u8 status; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 68d335e193bf..13f83c48face 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4116,7 +4116,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->dst_type = ev->bdaddr_type; - if (ev->role == LE_CONN_ROLE_MASTER) { + if (ev->role == HCI_ROLE_MASTER) { conn->out = true; set_bit(HCI_CONN_MASTER, &conn->flags); } -- cgit v1.2.3 From 40bef302f6323d1ee6fb3dc0e62edb0f446d0339 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 11:42:27 +0300 Subject: Bluetooth: Convert HCI_CONN_MASTER flag to a conn->role variable Having a dedicated u8 role variable in the hci_conn struct greatly simplifies tracking of the role, since this is the native way that it's represented on the HCI level. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_conn.c | 13 ++++++------- net/bluetooth/hci_event.c | 27 +++++++++------------------ net/bluetooth/l2cap_core.c | 4 ++-- net/bluetooth/smp.c | 12 ++++++------ 5 files changed, 24 insertions(+), 34 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b52c2ef3f56d..e335c5fd8824 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -371,6 +371,7 @@ struct hci_conn { __u16 state; __u8 mode; __u8 type; + __u8 role; bool out; __u8 attempt; __u8 dev_class[3]; @@ -540,7 +541,6 @@ enum { HCI_CONN_POWER_SAVE, HCI_CONN_REMOTE_OOB, HCI_CONN_FLUSH_KEY, - HCI_CONN_MASTER, HCI_CONN_ENCRYPT, HCI_CONN_AUTH, HCI_CONN_SECURE, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 490ee8846d9e..6c1c5048984c 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -66,8 +66,7 @@ static void hci_acl_create_connection(struct hci_conn *conn) conn->state = BT_CONNECT; conn->out = true; - - set_bit(HCI_CONN_MASTER, &conn->flags); + conn->role = HCI_ROLE_MASTER; conn->attempt++; @@ -335,7 +334,7 @@ static void hci_conn_timeout(struct work_struct *work) * event handling and hci_clock_offset_evt function. */ if (conn->type == ACL_LINK && - test_bit(HCI_CONN_MASTER, &conn->flags)) { + conn->role == HCI_ROLE_MASTER) { struct hci_dev *hdev = conn->hdev; struct hci_cp_read_clock_offset cp; @@ -786,8 +785,8 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, goto create_conn; } - conn->out = true; - set_bit(HCI_CONN_MASTER, &conn->flags); + conn->out = true; + conn->role = HCI_ROLE_MASTER; params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); if (params) { @@ -1076,7 +1075,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) { BT_DBG("hcon %p", conn); - if (!role && test_bit(HCI_CONN_MASTER, &conn->flags)) + if (role == conn->role) return 1; if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) { @@ -1151,7 +1150,7 @@ static u32 get_link_mode(struct hci_conn *conn) { u32 link_mode = 0; - if (test_bit(HCI_CONN_MASTER, &conn->flags)) + if (conn->role == HCI_ROLE_MASTER) link_mode |= HCI_LM_MASTER; if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 13f83c48face..3b1d2dadedc8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -101,12 +101,8 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle)); - if (conn) { - if (rp->role) - clear_bit(HCI_CONN_MASTER, &conn->flags); - else - set_bit(HCI_CONN_MASTER, &conn->flags); - } + if (conn) + conn->role = rp->role; hci_dev_unlock(hdev); } @@ -1420,8 +1416,8 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) if (!conn) { conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); if (conn) { - conn->out = true; - set_bit(HCI_CONN_MASTER, &conn->flags); + conn->out = true; + conn->role = HCI_ROLE_MASTER; } else BT_ERR("No memory for new connection"); } @@ -2924,12 +2920,8 @@ static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn) { - if (!ev->status) { - if (ev->role) - clear_bit(HCI_CONN_MASTER, &conn->flags); - else - set_bit(HCI_CONN_MASTER, &conn->flags); - } + if (!ev->status) + conn->role = ev->role; clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags); @@ -4116,10 +4108,9 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->dst_type = ev->bdaddr_type; - if (ev->role == HCI_ROLE_MASTER) { + conn->role = ev->role; + if (conn->role == HCI_ROLE_MASTER) conn->out = true; - set_bit(HCI_CONN_MASTER, &conn->flags); - } /* If we didn't have a hci_conn object previously * but we're in master role this must be something @@ -4527,7 +4518,7 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, return send_conn_param_neg_reply(hdev, handle, HCI_ERROR_INVALID_LL_PARAMS); - if (test_bit(HCI_CONN_MASTER, &hcon->flags)) { + if (hcon->role == HCI_ROLE_MASTER) { struct hci_conn_params *params; u8 store_hint; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8538cb07b0c0..ea68d3219b7e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1487,7 +1487,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) * been configured for this connection. If not, then trigger * the connection update procedure. */ - if (!test_bit(HCI_CONN_MASTER, &hcon->flags) && + if (hcon->role == HCI_ROLE_SLAVE && (hcon->le_conn_interval < hcon->le_conn_min_interval || hcon->le_conn_interval > hcon->le_conn_max_interval)) { struct l2cap_conn_param_update_req req; @@ -5227,7 +5227,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, u16 min, max, latency, to_multiplier; int err; - if (!test_bit(HCI_CONN_MASTER, &hcon->flags)) + if (hcon->role != HCI_ROLE_MASTER) return -EINVAL; if (cmd_len != sizeof(struct l2cap_conn_param_update_req)) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 8339d6b0f2b8..78eeb8b5970a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -445,7 +445,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, * Confirms and the slave Enters the passkey. */ if (method == OVERLAP) { - if (test_bit(HCI_CONN_MASTER, &hcon->flags)) + if (hcon->role == HCI_ROLE_MASTER) method = CFM_PASSKEY; else method = REQ_PASSKEY; @@ -686,7 +686,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*req)) return SMP_INVALID_PARAMS; - if (test_bit(HCI_CONN_MASTER, &conn->hcon->flags)) + if (conn->hcon->role != HCI_ROLE_SLAVE) return SMP_CMD_NOTSUPP; if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) @@ -755,7 +755,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rsp)) return SMP_INVALID_PARAMS; - if (!test_bit(HCI_CONN_MASTER, &conn->hcon->flags)) + if (conn->hcon->role != HCI_ROLE_MASTER) return SMP_CMD_NOTSUPP; skb_pull(skb, sizeof(*rsp)); @@ -903,7 +903,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rp)) return SMP_INVALID_PARAMS; - if (!test_bit(HCI_CONN_MASTER, &conn->hcon->flags)) + if (hcon->role != HCI_ROLE_MASTER) return SMP_CMD_NOTSUPP; sec_level = authreq_to_seclevel(rp->auth_req); @@ -961,7 +961,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) if (sec_level > hcon->pending_sec_level) hcon->pending_sec_level = sec_level; - if (test_bit(HCI_CONN_MASTER, &hcon->flags)) + if (hcon->role == HCI_ROLE_MASTER) if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) return 0; @@ -981,7 +981,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) hcon->pending_sec_level > BT_SECURITY_MEDIUM) authreq |= SMP_AUTH_MITM; - if (test_bit(HCI_CONN_MASTER, &hcon->flags)) { + if (hcon->role == HCI_ROLE_MASTER) { struct smp_cmd_pairing cp; build_pairing_cmd(conn, &cp, NULL, authreq); -- cgit v1.2.3 From e804d25d4a07c0ff9e5e1c58ea5ee67232aa9af8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 11:42:28 +0300 Subject: Bluetooth: Use explicit role instead of a bool in function parameters To make the code more understandable it makes sense to use the new HCI defines for connection role instead of a "bool master" parameter. This makes it immediately clear when looking at the function calls what the last parameter is describing. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 6 +++--- net/bluetooth/hci_conn.c | 7 ++++--- net/bluetooth/hci_core.c | 19 +++++++++++-------- net/bluetooth/hci_event.c | 5 ++--- net/bluetooth/l2cap_core.c | 9 ++++++--- net/bluetooth/mgmt.c | 4 ++-- net/bluetooth/smp.c | 4 ++-- 7 files changed, 30 insertions(+), 24 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e335c5fd8824..abe5083becd3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -707,7 +707,7 @@ struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle); struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u16 conn_timeout, - bool master); + u8 role); struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, u8 sec_level, u8 auth_type); struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, @@ -881,12 +881,12 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len, bool *persistent); struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, - bool master); + u8 role); struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, u8 authenticated, u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type, bool master); + u8 addr_type, u8 role); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type); void hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 6c1c5048984c..6edd55340157 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -697,7 +697,7 @@ static void hci_req_directed_advertising(struct hci_request *req, struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u16 conn_timeout, - bool master) + u8 role) { struct hci_conn_params *params; struct hci_conn *conn; @@ -769,8 +769,10 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, &enable); } + conn->role = role; + /* If requested to connect as slave use directed advertising */ - if (!master) { + if (conn->role == HCI_ROLE_SLAVE) { /* If we're active scanning most controllers are unable * to initiate advertising. Simply reject the attempt. */ @@ -786,7 +788,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, } conn->out = true; - conn->role = HCI_ROLE_MASTER; params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); if (params) { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 172041e2b15a..f575abdf2b4e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3121,13 +3121,16 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, return false; } -static bool ltk_type_master(u8 type) +static u8 ltk_role(u8 type) { - return (type == SMP_LTK); + if (type == SMP_LTK) + return HCI_ROLE_MASTER; + + return HCI_ROLE_SLAVE; } struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, - bool master) + u8 role) { struct smp_ltk *k; @@ -3135,7 +3138,7 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, if (k->ediv != ediv || k->rand != rand) continue; - if (ltk_type_master(k->type) != master) + if (ltk_role(k->type) != role) continue; return k; @@ -3145,14 +3148,14 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, } struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type, bool master) + u8 addr_type, u8 role) { struct smp_ltk *k; list_for_each_entry(k, &hdev->long_term_keys, list) if (addr_type == k->bdaddr_type && bacmp(bdaddr, &k->bdaddr) == 0 && - ltk_type_master(k->type) == master) + ltk_role(k->type) == role) return k; return NULL; @@ -3247,9 +3250,9 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand) { struct smp_ltk *key, *old_key; - bool master = ltk_type_master(type); + u8 role = ltk_role(type); - old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, master); + old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, role); if (old_key) key = old_key; else { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3b1d2dadedc8..5f7fd410fb3b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4263,9 +4263,8 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, return; connect: - /* Request connection in master = true role */ conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, - HCI_LE_AUTOCONN_TIMEOUT, true); + HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER); if (!IS_ERR(conn)) return; @@ -4443,7 +4442,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) if (conn == NULL) goto not_found; - ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->out); + ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->role); if (ltk == NULL) goto not_found; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ea68d3219b7e..d0f36336b6ce 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7128,7 +7128,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, chan->dcid = cid; if (bdaddr_type_is_le(dst_type)) { - bool master; + u8 role; /* Convert from L2CAP channel address type to HCI address type */ @@ -7137,10 +7137,13 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, else dst_type = ADDR_LE_DEV_RANDOM; - master = !test_bit(HCI_ADVERTISING, &hdev->dev_flags); + if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) + role = HCI_ROLE_SLAVE; + else + role = HCI_ROLE_MASTER; hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level, - HCI_LE_CONN_TIMEOUT, master); + HCI_LE_CONN_TIMEOUT, role); } else { u8 auth_type = l2cap_get_auth_type(chan); hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7703b72653ff..b981bfb87f86 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3154,9 +3154,9 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, */ hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type); - /* Request a connection with master = true role */ conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type, - sec_level, HCI_LE_CONN_TIMEOUT, true); + sec_level, HCI_LE_CONN_TIMEOUT, + HCI_ROLE_MASTER); } if (IS_ERR(conn)) { diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 78eeb8b5970a..70b726518d7b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -849,7 +849,7 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) struct hci_conn *hcon = conn->hcon; key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, - hcon->out); + hcon->role); if (!key) return false; @@ -881,7 +881,7 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) */ if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) && hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, - hcon->out)) + hcon->role)) return false; if (hcon->sec_level >= sec_level) -- cgit v1.2.3 From a5c4e309b9f23b9de5475029b2cb1641ec293137 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 11:56:07 +0300 Subject: Bluetooth: Add a role parameter to hci_conn_add() We need to be able to track slave vs master LE connections in hci_conn_hash, and to be able to do that we need to know the role of the connection by the time hci_conn_add_has() is called. This means in practice the hci_conn_add() call that creates the hci_conn_object. This patch adds a new role parameter to hci_conn_add() function to give the object its initial role value, and updates the callers to pass the appropriate role to it. Since the function now takes care of initializing both conn->role and conn->out values we can remove some other unnecessary assignments. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 ++- net/bluetooth/amp.c | 4 ++-- net/bluetooth/hci_conn.c | 17 +++++++++-------- net/bluetooth/hci_event.c | 17 ++++++----------- 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index abe5083becd3..3de000fbecdc 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -695,7 +695,8 @@ void hci_disconnect(struct hci_conn *conn, __u8 reason); bool hci_setup_sync(struct hci_conn *conn, __u16 handle); void hci_sco_setup(struct hci_conn *conn, __u8 status); -struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, + u8 role); int hci_conn_del(struct hci_conn *conn); void hci_conn_hash_flush(struct hci_dev *hdev); void hci_conn_check_pending(struct hci_dev *hdev); diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index bb39509b3f06..e60603a8969f 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -113,8 +113,9 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, { bdaddr_t *dst = &mgr->l2cap_conn->hcon->dst; struct hci_conn *hcon; + u8 role = out ? HCI_ROLE_MASTER : HCI_ROLE_SLAVE; - hcon = hci_conn_add(hdev, AMP_LINK, dst); + hcon = hci_conn_add(hdev, AMP_LINK, dst, role); if (!hcon) return NULL; @@ -125,7 +126,6 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, hcon->handle = __next_handle(mgr); hcon->remote_id = remote_id; hcon->amp_mgr = amp_mgr_get(mgr); - hcon->out = out; return hcon; } diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 6edd55340157..ad5f0b819e90 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -421,7 +421,8 @@ static void le_conn_timeout(struct work_struct *work) hci_le_create_connection_cancel(conn); } -struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, + u8 role) { struct hci_conn *conn; @@ -435,6 +436,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) bacpy(&conn->src, &hdev->bdaddr); conn->hdev = hdev; conn->type = type; + conn->role = role; conn->mode = HCI_CM_ACTIVE; conn->state = BT_OPEN; conn->auth_type = HCI_AT_GENERAL_BONDING; @@ -447,6 +449,9 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) set_bit(HCI_CONN_POWER_SAVE, &conn->flags); conn->disc_timeout = HCI_DISCONN_TIMEOUT; + if (conn->role == HCI_ROLE_MASTER) + conn->out = true; + switch (type) { case ACL_LINK: conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; @@ -746,7 +751,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, dst_type = ADDR_LE_DEV_RANDOM; } - conn = hci_conn_add(hdev, LE_LINK, dst); + conn = hci_conn_add(hdev, LE_LINK, dst, role); if (!conn) return ERR_PTR(-ENOMEM); @@ -769,8 +774,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, &enable); } - conn->role = role; - /* If requested to connect as slave use directed advertising */ if (conn->role == HCI_ROLE_SLAVE) { /* If we're active scanning most controllers are unable @@ -787,8 +790,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, goto create_conn; } - conn->out = true; - params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); if (params) { conn->le_conn_min_interval = params->conn_min_interval; @@ -837,7 +838,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); if (!acl) { - acl = hci_conn_add(hdev, ACL_LINK, dst); + acl = hci_conn_add(hdev, ACL_LINK, dst, HCI_ROLE_MASTER); if (!acl) return ERR_PTR(-ENOMEM); } @@ -866,7 +867,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, sco = hci_conn_hash_lookup_ba(hdev, type, dst); if (!sco) { - sco = hci_conn_add(hdev, type, dst); + sco = hci_conn_add(hdev, type, dst, HCI_ROLE_MASTER); if (!sco) { hci_conn_drop(acl); return ERR_PTR(-ENOMEM); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5f7fd410fb3b..c68b93e11686 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1414,11 +1414,9 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) } } else { if (!conn) { - conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); - if (conn) { - conn->out = true; - conn->role = HCI_ROLE_MASTER; - } else + conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr, + HCI_ROLE_MASTER); + if (!conn) BT_ERR("No memory for new connection"); } } @@ -2156,7 +2154,8 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); if (!conn) { - conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr); + conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr, + HCI_ROLE_SLAVE); if (!conn) { BT_ERR("No memory for new connection"); hci_dev_unlock(hdev); @@ -4100,7 +4099,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); if (!conn) { - conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr); + conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr, ev->role); if (!conn) { BT_ERR("No memory for new connection"); goto unlock; @@ -4108,10 +4107,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->dst_type = ev->bdaddr_type; - conn->role = ev->role; - if (conn->role == HCI_ROLE_MASTER) - conn->out = true; - /* If we didn't have a hci_conn object previously * but we're in master role this must be something * initiated using a white list. Since white list based -- cgit v1.2.3 From f8218dc6605a7b2af843f9ff5d66229a4a0b1c45 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 11:56:08 +0300 Subject: Bluetooth: Track number of LE slave connections Most (probably all) controllers can only deal with a single slave LE connection at a time. This patch adds a counter for such connections so that the number can be quickly looked up without iterating the connections list. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3de000fbecdc..73e16ecfd6b9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -83,6 +83,7 @@ struct hci_conn_hash { unsigned int amp_num; unsigned int sco_num; unsigned int le_num; + unsigned int le_num_slave; }; struct bdaddr_list { @@ -575,6 +576,8 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) break; case LE_LINK: h->le_num++; + if (c->role == HCI_ROLE_SLAVE) + h->le_num_slave++; break; case SCO_LINK: case ESCO_LINK: @@ -599,6 +602,8 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) break; case LE_LINK: h->le_num--; + if (c->role == HCI_ROLE_SLAVE) + h->le_num_slave--; break; case SCO_LINK: case ESCO_LINK: -- cgit v1.2.3 From f99353cf9c061bc1700b6a49ee98cae93e28207b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 11:56:09 +0300 Subject: Bluetooth: Fix trying to initiate connections when acting as LE slave When we have at least one LE slave connection most (probably all) controllers will refuse to initiate any new connections. To avoid unnecessary failures simply check for this situation up-front and skip the connection attempt. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c68b93e11686..e54db7f0590b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4246,6 +4246,12 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, if (hci_bdaddr_list_lookup(&hdev->blacklist, addr, addr_type)) return; + /* Most controller will fail if we try to create new connections + * while we have an existing one in slave role. + */ + if (hdev->conn_hash.le_num_slave > 0) + return; + /* If we're connectable, always connect any ADV_DIRECT_IND event */ if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && adv_type == LE_ADV_DIRECT_IND) -- cgit v1.2.3 From 46c4c941a417265e4b8afb3c52f31cabcbf4deb1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 16:19:21 +0300 Subject: Bluetooth: Fix always checking the blacklist for incoming connections We should check the blacklist no matter what, meaning also when we're not connectable. This patch fixes the respective logic in the function making the decision whether to accept a connection or not. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e54db7f0590b..cae860b02d67 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2129,18 +2129,17 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) return; } - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) { - if (hci_bdaddr_list_lookup(&hdev->blacklist, &ev->bdaddr, - BDADDR_BREDR)) { - hci_reject_conn(hdev, &ev->bdaddr); - return; - } - } else { - if (!hci_bdaddr_list_lookup(&hdev->whitelist, &ev->bdaddr, - BDADDR_BREDR)) { - hci_reject_conn(hdev, &ev->bdaddr); - return; - } + if (hci_bdaddr_list_lookup(&hdev->blacklist, &ev->bdaddr, + BDADDR_BREDR)) { + hci_reject_conn(hdev, &ev->bdaddr); + return; + } + + if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && + !hci_bdaddr_list_lookup(&hdev->whitelist, &ev->bdaddr, + BDADDR_BREDR)) { + hci_reject_conn(hdev, &ev->bdaddr); + return; } /* Connection accepted */ -- cgit v1.2.3 From f95f59fe5d2b05a0333214eeba78690081ee5f70 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Mon, 14 Jul 2014 20:53:34 -0700 Subject: mwifiex: remove redundant TDLS setup action frame check and avoid leaks The unwanted frame types are already handled in 'default' case of the switch/case below. The str_ptr is allocated but it can be leaked if the length check fails in the REQUEST/RESP cases. Fix it by allocating sta_ptr after the length checks. Reported-by: Paul Stewart Signed-off-by: Bing Zhao Signed-off-by: Avinash Patil Signed-off-by: Paul Stewart Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/tdls.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index a414161c6064..4c5fd953893d 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -781,6 +781,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, struct mwifiex_sta_node *sta_ptr; u8 *peer, *pos, *end; u8 i, action, basic; + __le16 cap = 0; int ie_len = 0; if (len < (sizeof(struct ethhdr) + 3)) @@ -792,18 +793,9 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, peer = buf + ETH_ALEN; action = *(buf + sizeof(struct ethhdr) + 2); - - /* just handle TDLS setup request/response/confirm */ - if (action > WLAN_TDLS_SETUP_CONFIRM) - return; - dev_dbg(priv->adapter->dev, "rx:tdls action: peer=%pM, action=%d\n", peer, action); - sta_ptr = mwifiex_add_sta_entry(priv, peer); - if (!sta_ptr) - return; - switch (action) { case WLAN_TDLS_SETUP_REQUEST: if (len < (sizeof(struct ethhdr) + TDLS_REQ_FIX_LEN)) @@ -811,7 +803,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, pos = buf + sizeof(struct ethhdr) + 4; /* payload 1+ category 1 + action 1 + dialog 1 */ - sta_ptr->tdls_cap.capab = cpu_to_le16(*(u16 *)pos); + cap = cpu_to_le16(*(u16 *)pos); ie_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN; pos += 2; break; @@ -821,7 +813,7 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, return; /* payload 1+ category 1 + action 1 + dialog 1 + status code 2*/ pos = buf + sizeof(struct ethhdr) + 6; - sta_ptr->tdls_cap.capab = cpu_to_le16(*(u16 *)pos); + cap = cpu_to_le16(*(u16 *)pos); ie_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN; pos += 2; break; @@ -833,10 +825,16 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, ie_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN; break; default: - dev_warn(priv->adapter->dev, "Unknown TDLS frame type.\n"); + dev_dbg(priv->adapter->dev, "Unknown TDLS frame type.\n"); return; } + sta_ptr = mwifiex_add_sta_entry(priv, peer); + if (!sta_ptr) + return; + + sta_ptr->tdls_cap.capab = cap; + for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) { if (pos + 2 + pos[1] > end) break; -- cgit v1.2.3 From 1f224ad2f760288dcc58b26546892a6b200b2af2 Mon Sep 17 00:00:00 2001 From: Neerav Parikh Date: Wed, 12 Feb 2014 01:45:31 +0000 Subject: i40e: Add ndo_get_phys_port_id() callback support This patch adds a new API to get the port mac address from firmware. It also adds support to the ndo_get_phys_port_id() callback to provide port specific unique id to the netdev layer. If the adapter has a valid per-port mac address then that would be used for this purpose and is expected to be unique on a per-port basis. The information can be viewed by reading the phys_port_id attribute in sysfs for each netdev or via IF netlink interface. Change-ID: I341fa6fff9c112f1f6d987189309e730e0b50e8b Signed-off-by: Neerav Parikh Acked-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_common.c | 25 ++++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_main.c | 20 +++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_prototype.h | 4 ++-- drivers/net/ethernet/intel/i40e/i40e_type.h | 1 + 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 0fbb32a8ad42..f7bf69fa15c7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -279,6 +279,7 @@ struct i40e_pf { #ifdef CONFIG_I40E_VXLAN #define I40E_FLAG_VXLAN_FILTER_SYNC (u64)(1 << 27) #endif +#define I40E_FLAG_PORT_ID_VALID (u64)(1 << 28) #define I40E_FLAG_DCB_CAPABLE (u64)(1 << 29) /* tracks features that get auto disabled by errors */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index bf808d4cb7b8..51087b5c7d91 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -654,6 +654,31 @@ i40e_status i40e_get_mac_addr(struct i40e_hw *hw, u8 *mac_addr) return status; } +/** + * i40e_get_port_mac_addr - get Port MAC address + * @hw: pointer to the HW structure + * @mac_addr: pointer to Port MAC address + * + * Reads the adapter's Port MAC address + **/ +i40e_status i40e_get_port_mac_addr(struct i40e_hw *hw, u8 *mac_addr) +{ + struct i40e_aqc_mac_address_read_data addrs; + i40e_status status; + u16 flags = 0; + + status = i40e_aq_mac_address_read(hw, &flags, &addrs, NULL); + if (status) + return status; + + if (flags & I40E_AQC_PORT_ADDR_VALID) + memcpy(mac_addr, &addrs.port_mac, sizeof(addrs.port_mac)); + else + status = I40E_ERR_INVALID_MAC_ADDR; + + return status; +} + /** * i40e_pre_tx_queue_cfg - pre tx queue configure * @hw: pointer to the HW structure diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 2899f783ee1d..1f72eeca00ce 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7018,6 +7018,22 @@ static void i40e_del_vxlan_port(struct net_device *netdev, } #endif +static int i40e_get_phys_port_id(struct net_device *netdev, + struct netdev_phys_port_id *ppid) +{ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + struct i40e_hw *hw = &pf->hw; + + if (!(pf->flags & I40E_FLAG_PORT_ID_VALID)) + return -EOPNOTSUPP; + + ppid->id_len = min_t(int, sizeof(hw->mac.port_addr), sizeof(ppid->id)); + memcpy(ppid->id, hw->mac.port_addr, ppid->id_len); + + return 0; +} + #ifdef HAVE_FDB_OPS #ifdef USE_CONST_DEV_UC_CHAR static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], @@ -7137,6 +7153,7 @@ static const struct net_device_ops i40e_netdev_ops = { .ndo_add_vxlan_port = i40e_add_vxlan_port, .ndo_del_vxlan_port = i40e_del_vxlan_port, #endif + .ndo_get_phys_port_id = i40e_get_phys_port_id, #ifdef HAVE_FDB_OPS .ndo_fdb_add = i40e_ndo_fdb_add, #ifndef USE_DEFAULT_FDB_DEL_DUMP @@ -8686,6 +8703,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } dev_info(&pdev->dev, "MAC address: %pM\n", hw->mac.addr); ether_addr_copy(hw->mac.perm_addr, hw->mac.addr); + i40e_get_port_mac_addr(hw, hw->mac.port_addr); + if (is_valid_ether_addr(hw->mac.port_addr)) + pf->flags |= I40E_FLAG_PORT_ID_VALID; pci_set_drvdata(pdev, pf); pci_save_state(pdev); diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index b6849fb47db7..9383f08ff4e3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -230,8 +230,8 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw); void i40e_clear_hw(struct i40e_hw *hw); void i40e_clear_pxe_mode(struct i40e_hw *hw); bool i40e_get_link_status(struct i40e_hw *hw); -i40e_status i40e_get_mac_addr(struct i40e_hw *hw, - u8 *mac_addr); +i40e_status i40e_get_mac_addr(struct i40e_hw *hw, u8 *mac_addr); +i40e_status i40e_get_port_mac_addr(struct i40e_hw *hw, u8 *mac_addr); i40e_status i40e_validate_mac_addr(u8 *mac_addr); void i40e_pre_tx_queue_cfg(struct i40e_hw *hw, u32 queue, bool enable); /* prototype for functions used for NVM access */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 380eb53a83b3..1fcf2205ffe6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -246,6 +246,7 @@ struct i40e_mac_info { u8 addr[ETH_ALEN]; u8 perm_addr[ETH_ALEN]; u8 san_addr[ETH_ALEN]; + u8 port_addr[ETH_ALEN]; u16 max_fcoeq; }; -- cgit v1.2.3 From 259afec7c34bbaa0236edd7e6ad811c4dce2fb1b Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 15 Mar 2014 14:55:37 +0000 Subject: i40e: never generate both software and hardware timestamps skb_tx_timestamp() does not report software time stamp if SKBTX_IN_PROGRESS is set. According to timestamping.txt software time stamps are a fallback and should not be generated if hardware time stamp is provided. Move call to skb_tx_timestamp() after setting SKBTX_IN_PROGRESS. Signed-off-by: Jakub Kicinski Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 2c686e2dfe1d..f65d361aeb35 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2285,13 +2285,13 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, else if (tso) tx_flags |= I40E_TX_FLAGS_TSO; - skb_tx_timestamp(skb); - tsyn = i40e_tsyn(tx_ring, skb, tx_flags, &cd_type_cmd_tso_mss); if (tsyn) tx_flags |= I40E_TX_FLAGS_TSYN; + skb_tx_timestamp(skb); + /* always enable CRC insertion offload */ td_cmd |= I40E_TX_DESC_CMD_ICRC; -- cgit v1.2.3 From 9ce34f023d6025af89087472f0327e0a81073167 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 15 Mar 2014 14:55:42 +0000 Subject: i40e: fix race conditions on queuing skb for HW time stamp i40e has a single set of TX time stamping resources per NIC. Use a simple bit lock to avoid race conditions and leaking skbs when multiple TX rings try to claim time stamping. Signed-off-by: Jakub Kicinski Tested-By: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_ptp.c | 2 ++ drivers/net/ethernet/intel/i40e/i40e_txrx.c | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index f7bf69fa15c7..29cd81ae29f4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -134,6 +134,7 @@ enum i40e_state_t { __I40E_EMP_RESET_REQUESTED, __I40E_FILTER_OVERFLOW_PROMISC, __I40E_SUSPENDED, + __I40E_PTP_TX_IN_PROGRESS, __I40E_BAD_EEPROM, __I40E_DOWN_REQUESTED, }; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index c364781c8160..582704a642ae 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -314,6 +314,7 @@ void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf) skb_tstamp_tx(pf->ptp_tx_skb, &shhwtstamps); dev_kfree_skb_any(pf->ptp_tx_skb); pf->ptp_tx_skb = NULL; + clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, &pf->state); } /** @@ -677,6 +678,7 @@ void i40e_ptp_stop(struct i40e_pf *pf) if (pf->ptp_tx_skb) { dev_kfree_skb_any(pf->ptp_tx_skb); pf->ptp_tx_skb = NULL; + clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, &pf->state); } if (pf->ptp_clock) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index f65d361aeb35..79489a8e9ac3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1856,7 +1856,8 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb, * we are not already transmitting a packet to be timestamped */ pf = i40e_netdev_to_pf(tx_ring->netdev); - if (pf->ptp_tx && !pf->ptp_tx_skb) { + if (pf->ptp_tx && + !test_and_set_bit_lock(__I40E_PTP_TX_IN_PROGRESS, &pf->state)) { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; pf->ptp_tx_skb = skb_get(skb); } else { -- cgit v1.2.3 From ec9a7db7f0438bc8ad69bc436cb3b3ed16642af9 Mon Sep 17 00:00:00 2001 From: Paul M Stillwell Jr Date: Wed, 9 Jul 2014 07:46:10 +0000 Subject: i40e/i40evf: Clean up code 1. Remove some break statements that will never get touched. 2. Remove an extra space. 3. Remove a comment for a parameter that doesn't exist 4. Move the assignment of a variable up to get rid of an else case. Change-ID: I308a4b5ec070b1f0601f13b041ba4375aaad4b06 Signed-off-by: Paul M Stillwell Jr Tested-by: Jim Young Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 2 +- drivers/net/ethernet/intel/i40e/i40e_common.c | 1 - drivers/net/ethernet/intel/i40e/i40e_main.c | 3 +-- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 1 - drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 2 +- 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 2708bcdddd41..0e551f281d59 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -863,7 +863,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, /* ugh! delay while spin_lock */ udelay(delay_len); total_delay += delay_len; - } while (total_delay < hw->aq.asq_cmd_timeout); + } while (total_delay < hw->aq.asq_cmd_timeout); } /* if ready, copy the desc back to temp */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 51087b5c7d91..c65f4e8e6cee 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -554,7 +554,6 @@ i40e_status i40e_init_shared_code(struct i40e_hw *hw) break; default: return I40E_ERR_DEVICE_NOT_SUPPORTED; - break; } hw->phy.get_link_info = true; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 1f72eeca00ce..c34e39009a8f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6773,13 +6773,12 @@ static int i40e_sw_init(struct i40e_pf *pf) * maximum might end up larger than the available queues */ pf->rss_size_max = 0x1 << pf->hw.func_caps.rss_table_entry_width; + pf->rss_size = 1; pf->rss_size_max = min_t(int, pf->rss_size_max, pf->hw.func_caps.num_tx_qp); if (pf->hw.func_caps.rss) { pf->flags |= I40E_FLAG_RSS_ENABLED; pf->rss_size = min_t(int, pf->rss_size_max, num_online_cpus()); - } else { - pf->rss_size = 1; } /* MFP mode enabled */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 79489a8e9ac3..989866af26e5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -303,7 +303,6 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, * a specific flow spec * @vsi: pointer to the targeted VSI * @fd_data: the flow director data required for the FDir descriptor - * @raw_packet: the pre-allocated packet buffer for FDir * @add: true adds a filter, false removes it * * Always returns -EOPNOTSUPP diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index cc4b6db10b04..8330744b02f1 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -817,7 +817,7 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, /* ugh! delay while spin_lock */ udelay(delay_len); total_delay += delay_len; - } while (total_delay < hw->aq.asq_cmd_timeout); + } while (total_delay < hw->aq.asq_cmd_timeout); } /* if ready, copy the desc back to temp */ -- cgit v1.2.3 From 302b46449e2918a30b3f98a54653972d2ad0f072 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 9 Jul 2014 07:46:11 +0000 Subject: i40e: (ptp) warn when PF_ID does not match in PRTTSYN_CTL0 Display a verbose warning message when the incorrect PF attempts to control timestamping for a port to which it was not assigned. This shouldn't display except in the case of multiple PFs per port. The primary intent of this message is to help debugging the reason why the SIOCSHWTSTAMP ioctl has failed, and to help narrow the cause of the issue. Change-ID: Ic98798e0c844d98389d4c20e7160ba256f2bc7e8 Signed-off-by: Jacob Keller Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 582704a642ae..bb7fe98b3a6c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -447,8 +447,12 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, /* Confirm that 1588 is supported on this PF. */ pf_id = (rd32(hw, I40E_PRTTSYN_CTL0) & I40E_PRTTSYN_CTL0_PF_ID_MASK) >> I40E_PRTTSYN_CTL0_PF_ID_SHIFT; - if (hw->pf_id != pf_id) - return -EINVAL; + if (hw->pf_id != pf_id) { + dev_err(&pf->pdev->dev, + "PF %d attempted to control timestamp mode on port %d, which is owned by PF %d\n", + hw->pf_id, hw->port, pf_id); + return -EPERM; + } switch (config->tx_type) { case HWTSTAMP_TX_OFF: -- cgit v1.2.3 From 63b949382c5f263746b1c177f6ff84de2201ae9d Mon Sep 17 00:00:00 2001 From: Geir Ola Vaagland Date: Sat, 12 Jul 2014 20:30:36 +0200 Subject: net: sctp: implement rfc6458, 5.3.4. SCTP_SNDINFO cmsg support This patch implements section 5.3.4. of RFC6458, that is, support for 'SCTP Send Information Structure' (SCTP_SNDINFO) which can be placed into ancillary data cmsghdr structure for sendmsg() calls. The sctp_sndinfo structure is defined as per RFC as below ... struct sctp_sndinfo { uint16_t snd_sid; uint16_t snd_flags; uint32_t snd_ppid; uint32_t snd_context; sctp_assoc_t snd_assoc_id; }; ... and supplied under cmsg_level IPPROTO_SCTP, cmsg_type SCTP_SNDINFO, while cmsg_data[] contains struct sctp_sndinfo. An sctp_sndinfo item always corresponds to the data in msg_iov. Joint work with Daniel Borkmann. Signed-off-by: Geir Ola Vaagland Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 3 +- include/uapi/linux/sctp.h | 22 +++++++++++-- net/sctp/socket.c | 77 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 79 insertions(+), 23 deletions(-) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index f38588bf3462..7af9a0f5d8ce 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1919,7 +1919,8 @@ struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc); /* A convenience structure to parse out SCTP specific CMSGs. */ typedef struct sctp_cmsgs { struct sctp_initmsg *init; - struct sctp_sndrcvinfo *info; + struct sctp_sndrcvinfo *srinfo; + struct sctp_sndinfo *sinfo; } sctp_cmsgs_t; /* Structure for tracking memory objects */ diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h index 266022a2be4a..a387761f7e02 100644 --- a/include/uapi/linux/sctp.h +++ b/include/uapi/linux/sctp.h @@ -154,6 +154,22 @@ struct sctp_sndrcvinfo { sctp_assoc_t sinfo_assoc_id; }; +/* 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO) + * + * This cmsghdr structure specifies SCTP options for sendmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ------------------- + * IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo + */ +struct sctp_sndinfo { + __u16 snd_sid; + __u16 snd_flags; + __u32 snd_ppid; + __u32 snd_context; + sctp_assoc_t snd_assoc_id; +}; + /* * sinfo_flags: 16 bits (unsigned integer) * @@ -177,10 +193,12 @@ typedef union { /* These are cmsg_types. */ typedef enum sctp_cmsg_type { - SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */ + SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */ #define SCTP_INIT SCTP_INIT - SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */ + SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */ #define SCTP_SNDRCV SCTP_SNDRCV + SCTP_SNDINFO, /* 5.3.4 SCTP Send Information Structure */ +#define SCTP_SNDINFO SCTP_SNDINFO } sctp_cmsg_t; /* diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 429899689408..d61729e99856 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1602,12 +1602,13 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, struct sctp_initmsg *sinit; sctp_assoc_t associd = 0; sctp_cmsgs_t cmsgs = { NULL }; - int err; sctp_scope_t scope; - long timeo; - __u16 sinfo_flags = 0; + bool fill_sinfo_ttl = false; struct sctp_datamsg *datamsg; int msg_flags = msg->msg_flags; + __u16 sinfo_flags = 0; + long timeo; + int err; err = 0; sp = sctp_sk(sk); @@ -1648,10 +1649,21 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, msg_name = msg->msg_name; } - sinfo = cmsgs.info; sinit = cmsgs.init; + if (cmsgs.sinfo != NULL) { + memset(&default_sinfo, 0, sizeof(default_sinfo)); + default_sinfo.sinfo_stream = cmsgs.sinfo->snd_sid; + default_sinfo.sinfo_flags = cmsgs.sinfo->snd_flags; + default_sinfo.sinfo_ppid = cmsgs.sinfo->snd_ppid; + default_sinfo.sinfo_context = cmsgs.sinfo->snd_context; + default_sinfo.sinfo_assoc_id = cmsgs.sinfo->snd_assoc_id; - /* Did the user specify SNDRCVINFO? */ + sinfo = &default_sinfo; + fill_sinfo_ttl = true; + } else { + sinfo = cmsgs.srinfo; + } + /* Did the user specify SNDINFO/SNDRCVINFO? */ if (sinfo) { sinfo_flags = sinfo->sinfo_flags; associd = sinfo->sinfo_assoc_id; @@ -1858,8 +1870,8 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, pr_debug("%s: we have a valid association\n", __func__); if (!sinfo) { - /* If the user didn't specify SNDRCVINFO, make up one with - * some defaults. + /* If the user didn't specify SNDINFO/SNDRCVINFO, make up + * one with some defaults. */ memset(&default_sinfo, 0, sizeof(default_sinfo)); default_sinfo.sinfo_stream = asoc->default_stream; @@ -1868,7 +1880,13 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, default_sinfo.sinfo_context = asoc->default_context; default_sinfo.sinfo_timetolive = asoc->default_timetolive; default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc); + sinfo = &default_sinfo; + } else if (fill_sinfo_ttl) { + /* In case SNDINFO was specified, we still need to fill + * it with a default ttl from the assoc here. + */ + sinfo->sinfo_timetolive = asoc->default_timetolive; } /* API 7.1.7, the sndbuf size per association bounds the @@ -6390,8 +6408,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) struct cmsghdr *cmsg; struct msghdr *my_msg = (struct msghdr *)msg; - for (cmsg = CMSG_FIRSTHDR(msg); - cmsg != NULL; + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(my_msg, cmsg)) { if (!CMSG_OK(my_msg, cmsg)) return -EINVAL; @@ -6404,7 +6421,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) switch (cmsg->cmsg_type) { case SCTP_INIT: /* SCTP Socket API Extension - * 5.2.1 SCTP Initiation Structure (SCTP_INIT) + * 5.3.1 SCTP Initiation Structure (SCTP_INIT) * * This cmsghdr structure provides information for * initializing new SCTP associations with sendmsg(). @@ -6416,15 +6433,15 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) * ------------ ------------ ---------------------- * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg */ - if (cmsg->cmsg_len != - CMSG_LEN(sizeof(struct sctp_initmsg))) + if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_initmsg))) return -EINVAL; - cmsgs->init = (struct sctp_initmsg *)CMSG_DATA(cmsg); + + cmsgs->init = CMSG_DATA(cmsg); break; case SCTP_SNDRCV: /* SCTP Socket API Extension - * 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV) + * 5.3.2 SCTP Header Information Structure(SCTP_SNDRCV) * * This cmsghdr structure specifies SCTP options for * sendmsg() and describes SCTP header information @@ -6434,24 +6451,44 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) * ------------ ------------ ---------------------- * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo */ - if (cmsg->cmsg_len != - CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) + if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) return -EINVAL; - cmsgs->info = - (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + cmsgs->srinfo = CMSG_DATA(cmsg); - /* Minimally, validate the sinfo_flags. */ - if (cmsgs->info->sinfo_flags & + if (cmsgs->srinfo->sinfo_flags & ~(SCTP_UNORDERED | SCTP_ADDR_OVER | SCTP_ABORT | SCTP_EOF)) return -EINVAL; break; + case SCTP_SNDINFO: + /* SCTP Socket API Extension + * 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO) + * + * This cmsghdr structure specifies SCTP options for + * sendmsg(). This structure and SCTP_RCVINFO replaces + * SCTP_SNDRCV which has been deprecated. + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ --------------------- + * IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo + */ + if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndinfo))) + return -EINVAL; + + cmsgs->sinfo = CMSG_DATA(cmsg); + + if (cmsgs->sinfo->snd_flags & + ~(SCTP_UNORDERED | SCTP_ADDR_OVER | + SCTP_ABORT | SCTP_EOF)) + return -EINVAL; + break; default: return -EINVAL; } } + return 0; } -- cgit v1.2.3 From 0d3a421d284812d07970b4ccee74d4fa38737e4d Mon Sep 17 00:00:00 2001 From: Geir Ola Vaagland Date: Sat, 12 Jul 2014 20:30:37 +0200 Subject: net: sctp: implement rfc6458, 5.3.5. SCTP_RCVINFO cmsg support This patch implements section 5.3.5. of RFC6458, that is, support for 'SCTP Receive Information Structure' (SCTP_RCVINFO) which is placed into ancillary data cmsghdr structure for each recvmsg() call. This option can be enabled/disabled via setsockopt(2) on SOL_SCTP level by setting an int value with 1/0 for SCTP_RECVRCVINFO in user space applications as per RFC6458, section 8.1.29. The sctp_rcvinfo structure is defined as per RFC as below ... struct sctp_rcvinfo { uint16_t rcv_sid; uint16_t rcv_ssn; uint16_t rcv_flags; <-- 2 bytes hole --> uint32_t rcv_ppid; uint32_t rcv_tsn; uint32_t rcv_cumtsn; uint32_t rcv_context; sctp_assoc_t rcv_assoc_id; }; ... and provided under cmsg_level IPPROTO_SCTP, cmsg_type SCTP_RCVINFO, while cmsg_data[] contains struct sctp_rcvinfo. An sctp_rcvinfo item always corresponds to the data in msg_iov. Joint work with Daniel Borkmann. Signed-off-by: Geir Ola Vaagland Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 3 +++ include/net/sctp/ulpevent.h | 5 ++++- include/uapi/linux/sctp.h | 32 ++++++++++++++++++++++------- net/sctp/socket.c | 49 ++++++++++++++++++++++++++++++++++++++++++++- net/sctp/ulpevent.c | 25 +++++++++++++++++++++++ 5 files changed, 105 insertions(+), 9 deletions(-) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 7af9a0f5d8ce..11d5df015370 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -207,7 +207,9 @@ struct sctp_sock { struct sctp_paddrparams paddrparam; struct sctp_event_subscribe subscribe; struct sctp_assocparams assocparams; + int user_frag; + __u32 autoclose; __u8 nodelay; __u8 disable_fragments; @@ -215,6 +217,7 @@ struct sctp_sock { __u8 frag_interleave; __u32 adaptation_ind; __u32 pd_point; + __u8 recvrcvinfo; atomic_t pd_mode; /* Receive to here while partial delivery is in effect. */ diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index daacb32b55b5..e8095f973e94 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -129,7 +129,10 @@ struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event( const struct sctp_association *asoc, gfp_t gfp); void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, - struct msghdr *); + struct msghdr *); +void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event, + struct msghdr *); + __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event); /* Is this event type enabled? */ diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h index a387761f7e02..29b81bbfc53d 100644 --- a/include/uapi/linux/sctp.h +++ b/include/uapi/linux/sctp.h @@ -95,6 +95,7 @@ typedef __s32 sctp_assoc_t; #define SCTP_GET_ASSOC_ID_LIST 29 /* Read only */ #define SCTP_AUTO_ASCONF 30 #define SCTP_PEER_ADDR_THLDS 31 +#define SCTP_RECVRCVINFO 32 /* Internal Socket Options. Some of the sctp library functions are * implemented using these socket options. @@ -110,8 +111,7 @@ typedef __s32 sctp_assoc_t; #define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */ #define SCTP_GET_ASSOC_STATS 112 /* Read only */ -/* - * 5.2.1 SCTP Initiation Structure (SCTP_INIT) +/* 5.3.1 SCTP Initiation Structure (SCTP_INIT) * * This cmsghdr structure provides information for initializing new * SCTP associations with sendmsg(). The SCTP_INITMSG socket option @@ -121,7 +121,6 @@ typedef __s32 sctp_assoc_t; * cmsg_level cmsg_type cmsg_data[] * ------------ ------------ ---------------------- * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg - * */ struct sctp_initmsg { __u16 sinit_num_ostreams; @@ -130,8 +129,7 @@ struct sctp_initmsg { __u16 sinit_max_init_timeo; }; -/* - * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) +/* 5.3.2 SCTP Header Information Structure (SCTP_SNDRCV) * * This cmsghdr structure specifies SCTP options for sendmsg() and * describes SCTP header information about a received message through @@ -140,7 +138,6 @@ struct sctp_initmsg { * cmsg_level cmsg_type cmsg_data[] * ------------ ------------ ---------------------- * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo - * */ struct sctp_sndrcvinfo { __u16 sinfo_stream; @@ -170,13 +167,32 @@ struct sctp_sndinfo { sctp_assoc_t snd_assoc_id; }; +/* 5.3.5 SCTP Receive Information Structure (SCTP_RCVINFO) + * + * This cmsghdr structure describes SCTP receive information + * about a received message through recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ------------------- + * IPPROTO_SCTP SCTP_RCVINFO struct sctp_rcvinfo + */ +struct sctp_rcvinfo { + __u16 rcv_sid; + __u16 rcv_ssn; + __u16 rcv_flags; + __u32 rcv_ppid; + __u32 rcv_tsn; + __u32 rcv_cumtsn; + __u32 rcv_context; + sctp_assoc_t rcv_assoc_id; +}; + /* * sinfo_flags: 16 bits (unsigned integer) * * This field may contain any of the following flags and is composed of * a bitwise OR of these values. */ - enum sctp_sinfo_flags { SCTP_UNORDERED = 1, /* Send/receive message unordered. */ SCTP_ADDR_OVER = 2, /* Override the primary destination. */ @@ -199,6 +215,8 @@ typedef enum sctp_cmsg_type { #define SCTP_SNDRCV SCTP_SNDRCV SCTP_SNDINFO, /* 5.3.4 SCTP Send Information Structure */ #define SCTP_SNDINFO SCTP_SNDINFO + SCTP_RCVINFO, /* 5.3.5 SCTP Receive Information Structure */ +#define SCTP_RCVINFO SCTP_RCVINFO } sctp_cmsg_t; /* diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d61729e99856..9c193887c5cd 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2112,9 +2112,13 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, sp->pf->skb_msgname(skb, msg->msg_name, addr_len); } + /* Check if we allow SCTP_RCVINFO. */ + if (sp->recvrcvinfo) + sctp_ulpevent_read_rcvinfo(event, msg); /* Check if we allow SCTP_SNDRCVINFO. */ if (sp->subscribe.sctp_data_io_event) sctp_ulpevent_read_sndrcvinfo(event, msg); + #if 0 /* FIXME: we should be calling IP/IPv6 layers. */ if (sk->sk_protinfo.af_inet.cmsg_flags) @@ -3541,7 +3545,6 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, return 0; } - /* * SCTP_PEER_ADDR_THLDS * @@ -3592,6 +3595,22 @@ static int sctp_setsockopt_paddr_thresholds(struct sock *sk, return 0; } +static int sctp_setsockopt_recvrcvinfo(struct sock *sk, + char __user *optval, + unsigned int optlen) +{ + int val; + + if (optlen < sizeof(int)) + return -EINVAL; + if (get_user(val, (int __user *) optval)) + return -EFAULT; + + sctp_sk(sk)->recvrcvinfo = (val == 0) ? 0 : 1; + + return 0; +} + /* API 6.2 setsockopt(), getsockopt() * * Applications use setsockopt() and getsockopt() to set or retrieve @@ -3743,6 +3762,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, case SCTP_PEER_ADDR_THLDS: retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen); break; + case SCTP_RECVRCVINFO: + retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; @@ -3989,6 +4011,8 @@ static int sctp_init_sock(struct sock *sk) /* Enable Nagle algorithm by default. */ sp->nodelay = 0; + sp->recvrcvinfo = 0; + /* Enable by default. */ sp->v4mapped = 1; @@ -5770,6 +5794,26 @@ static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, return 0; } +static int sctp_getsockopt_recvrcvinfo(struct sock *sk, int len, + char __user *optval, + int __user *optlen) +{ + int val = 0; + + if (len < sizeof(int)) + return -EINVAL; + + len = sizeof(int); + if (sctp_sk(sk)->recvrcvinfo) + val = 1; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} + static int sctp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -5913,6 +5957,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_GET_ASSOC_STATS: retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); break; + case SCTP_RECVRCVINFO: + retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index b6842fdb53d4..b31f365f18ab 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -886,6 +886,31 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, sizeof(sinfo), &sinfo); } +/* RFC6458, Section 5.3.5 SCTP Receive Information Structure + * (SCTP_SNDRCV) + */ +void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event, + struct msghdr *msghdr) +{ + struct sctp_rcvinfo rinfo; + + if (sctp_ulpevent_is_notification(event)) + return; + + memset(&rinfo, 0, sizeof(struct sctp_rcvinfo)); + rinfo.rcv_sid = event->stream; + rinfo.rcv_ssn = event->ssn; + rinfo.rcv_ppid = event->ppid; + rinfo.rcv_flags = event->flags; + rinfo.rcv_tsn = event->tsn; + rinfo.rcv_cumtsn = event->cumtsn; + rinfo.rcv_assoc_id = sctp_assoc2id(event->asoc); + rinfo.rcv_context = event->asoc->default_rcv_context; + + put_cmsg(msghdr, IPPROTO_SCTP, SCTP_RCVINFO, + sizeof(rinfo), &rinfo); +} + /* Do accounting for bytes received and hold a reference to the association * for each skb. */ -- cgit v1.2.3 From 2347c80ff127b94ddaa675e2b78ab4cef46dc905 Mon Sep 17 00:00:00 2001 From: Geir Ola Vaagland Date: Sat, 12 Jul 2014 20:30:38 +0200 Subject: net: sctp: implement rfc6458, 5.3.6. SCTP_NXTINFO cmsg support This patch implements section 5.3.6. of RFC6458, that is, support for 'SCTP Next Receive Information Structure' (SCTP_NXTINFO) which is placed into ancillary data cmsghdr structure for each recvmsg() call, if this information is already available when delivering the current message. This option can be enabled/disabled via setsockopt(2) on SOL_SCTP level by setting an int value with 1/0 for SCTP_RECVNXTINFO in user space applications as per RFC6458, section 8.1.30. The sctp_nxtinfo structure is defined as per RFC as below ... struct sctp_nxtinfo { uint16_t nxt_sid; uint16_t nxt_flags; uint32_t nxt_ppid; uint32_t nxt_length; sctp_assoc_t nxt_assoc_id; }; ... and provided under cmsg_level IPPROTO_SCTP, cmsg_type SCTP_NXTINFO, while cmsg_data[] contains struct sctp_nxtinfo. Joint work with Daniel Borkmann. Signed-off-by: Geir Ola Vaagland Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/net/sctp/sctp.h | 1 + include/net/sctp/structs.h | 1 + include/net/sctp/ulpevent.h | 9 ++------ include/uapi/linux/sctp.h | 47 +++++++++++++++++++++++++++++----------- net/sctp/socket.c | 52 +++++++++++++++++++++++++++++++++++++++++---- net/sctp/ulpevent.c | 38 +++++++++++++++++++++++++++++++++ 6 files changed, 125 insertions(+), 23 deletions(-) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index c2035c96a2ee..90c1cccd164d 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -109,6 +109,7 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk, struct sctp_association *asoc); extern struct percpu_counter sctp_sockets_allocated; int sctp_asconf_mgmt(struct sctp_sock *, struct sctp_sockaddr_entry *); +struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *); /* * sctp/primitive.c diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 11d5df015370..7741d1b66967 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -218,6 +218,7 @@ struct sctp_sock { __u32 adaptation_ind; __u32 pd_point; __u8 recvrcvinfo; + __u8 recvnxtinfo; atomic_t pd_mode; /* Receive to here while partial delivery is in effect. */ diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index e8095f973e94..cccdcfd14973 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -132,6 +132,8 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, struct msghdr *); void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event, struct msghdr *); +void sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event, + struct msghdr *, struct sock *sk); __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event); @@ -158,10 +160,3 @@ static inline int sctp_ulpevent_is_enabled(const struct sctp_ulpevent *event, } #endif /* __sctp_ulpevent_h__ */ - - - - - - - diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h index 29b81bbfc53d..222f82ffeca4 100644 --- a/include/uapi/linux/sctp.h +++ b/include/uapi/linux/sctp.h @@ -96,6 +96,7 @@ typedef __s32 sctp_assoc_t; #define SCTP_AUTO_ASCONF 30 #define SCTP_PEER_ADDR_THLDS 31 #define SCTP_RECVRCVINFO 32 +#define SCTP_RECVNXTINFO 33 /* Internal Socket Options. Some of the sctp library functions are * implemented using these socket options. @@ -111,6 +112,13 @@ typedef __s32 sctp_assoc_t; #define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */ #define SCTP_GET_ASSOC_STATS 112 /* Read only */ +/* These are bit fields for msghdr->msg_flags. See section 5.1. */ +/* On user space Linux, these live in as an enum. */ +enum sctp_msg_flags { + MSG_NOTIFICATION = 0x8000, +#define MSG_NOTIFICATION MSG_NOTIFICATION +}; + /* 5.3.1 SCTP Initiation Structure (SCTP_INIT) * * This cmsghdr structure provides information for initializing new @@ -187,6 +195,25 @@ struct sctp_rcvinfo { sctp_assoc_t rcv_assoc_id; }; +/* 5.3.6 SCTP Next Receive Information Structure (SCTP_NXTINFO) + * + * This cmsghdr structure describes SCTP receive information + * of the next message that will be delivered through recvmsg() + * if this information is already available when delivering + * the current message. + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ------------------- + * IPPROTO_SCTP SCTP_NXTINFO struct sctp_nxtinfo + */ +struct sctp_nxtinfo { + __u16 nxt_sid; + __u16 nxt_flags; + __u32 nxt_ppid; + __u32 nxt_length; + sctp_assoc_t nxt_assoc_id; +}; + /* * sinfo_flags: 16 bits (unsigned integer) * @@ -194,11 +221,12 @@ struct sctp_rcvinfo { * a bitwise OR of these values. */ enum sctp_sinfo_flags { - SCTP_UNORDERED = 1, /* Send/receive message unordered. */ - SCTP_ADDR_OVER = 2, /* Override the primary destination. */ - SCTP_ABORT=4, /* Send an ABORT message to the peer. */ - SCTP_SACK_IMMEDIATELY = 8, /* SACK should be sent without delay */ - SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */ + SCTP_UNORDERED = (1 << 0), /* Send/receive message unordered. */ + SCTP_ADDR_OVER = (1 << 1), /* Override the primary destination. */ + SCTP_ABORT = (1 << 2), /* Send an ABORT message to the peer. */ + SCTP_SACK_IMMEDIATELY = (1 << 3), /* SACK should be sent without delay. */ + SCTP_NOTIFICATION = MSG_NOTIFICATION, /* Next message is not user msg but notification. */ + SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. */ }; typedef union { @@ -217,6 +245,8 @@ typedef enum sctp_cmsg_type { #define SCTP_SNDINFO SCTP_SNDINFO SCTP_RCVINFO, /* 5.3.5 SCTP Receive Information Structure */ #define SCTP_RCVINFO SCTP_RCVINFO + SCTP_NXTINFO, /* 5.3.6 SCTP Next Receive Information Structure */ +#define SCTP_NXTINFO SCTP_NXTINFO } sctp_cmsg_t; /* @@ -844,13 +874,6 @@ struct sctp_assoc_stats { __u64 sas_ictrlchunks; /* Control chunks received */ }; -/* These are bit fields for msghdr->msg_flags. See section 5.1. */ -/* On user space Linux, these live in as an enum. */ -enum sctp_msg_flags { - MSG_NOTIFICATION = 0x8000, -#define MSG_NOTIFICATION MSG_NOTIFICATION -}; - /* * 8.1 sctp_bindx() * diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9c193887c5cd..9bca87ee5152 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2060,8 +2060,6 @@ static int sctp_skb_pull(struct sk_buff *skb, int len) * flags - flags sent or received with the user message, see Section * 5 for complete description of the flags. */ -static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *); - static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int noblock, int flags, int *addr_len) @@ -2112,6 +2110,9 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, sp->pf->skb_msgname(skb, msg->msg_name, addr_len); } + /* Check if we allow SCTP_NXTINFO. */ + if (sp->recvnxtinfo) + sctp_ulpevent_read_nxtinfo(event, msg, sk); /* Check if we allow SCTP_RCVINFO. */ if (sp->recvrcvinfo) sctp_ulpevent_read_rcvinfo(event, msg); @@ -3611,6 +3612,22 @@ static int sctp_setsockopt_recvrcvinfo(struct sock *sk, return 0; } +static int sctp_setsockopt_recvnxtinfo(struct sock *sk, + char __user *optval, + unsigned int optlen) +{ + int val; + + if (optlen < sizeof(int)) + return -EINVAL; + if (get_user(val, (int __user *) optval)) + return -EFAULT; + + sctp_sk(sk)->recvnxtinfo = (val == 0) ? 0 : 1; + + return 0; +} + /* API 6.2 setsockopt(), getsockopt() * * Applications use setsockopt() and getsockopt() to set or retrieve @@ -3765,6 +3782,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, case SCTP_RECVRCVINFO: retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen); break; + case SCTP_RECVNXTINFO: + retval = sctp_setsockopt_recvnxtinfo(sk, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; @@ -4012,6 +4032,7 @@ static int sctp_init_sock(struct sock *sk) sp->nodelay = 0; sp->recvrcvinfo = 0; + sp->recvnxtinfo = 0; /* Enable by default. */ sp->v4mapped = 1; @@ -5814,6 +5835,26 @@ static int sctp_getsockopt_recvrcvinfo(struct sock *sk, int len, return 0; } +static int sctp_getsockopt_recvnxtinfo(struct sock *sk, int len, + char __user *optval, + int __user *optlen) +{ + int val = 0; + + if (len < sizeof(int)) + return -EINVAL; + + len = sizeof(int); + if (sctp_sk(sk)->recvnxtinfo) + val = 1; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} + static int sctp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -5960,6 +6001,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_RECVRCVINFO: retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen); break; + case SCTP_RECVNXTINFO: + retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; @@ -6602,8 +6646,8 @@ out: * Note: This is pretty much the same routine as in core/datagram.c * with a few changes to make lksctp work. */ -static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, - int noblock, int *err) +struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, + int noblock, int *err) { int error; struct sk_buff *skb; diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index b31f365f18ab..e049298ecfa0 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -911,6 +911,44 @@ void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event, sizeof(rinfo), &rinfo); } +/* RFC6458, Section 5.3.6. SCTP Next Receive Information Structure + * (SCTP_NXTINFO) + */ +static void __sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event, + struct msghdr *msghdr, + const struct sk_buff *skb) +{ + struct sctp_nxtinfo nxtinfo; + + memset(&nxtinfo, 0, sizeof(nxtinfo)); + nxtinfo.nxt_sid = event->stream; + nxtinfo.nxt_ppid = event->ppid; + nxtinfo.nxt_flags = event->flags; + if (sctp_ulpevent_is_notification(event)) + nxtinfo.nxt_flags |= SCTP_NOTIFICATION; + nxtinfo.nxt_length = skb->len; + nxtinfo.nxt_assoc_id = sctp_assoc2id(event->asoc); + + put_cmsg(msghdr, IPPROTO_SCTP, SCTP_NXTINFO, + sizeof(nxtinfo), &nxtinfo); +} + +void sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event, + struct msghdr *msghdr, + struct sock *sk) +{ + struct sk_buff *skb; + int err; + + skb = sctp_skb_recv_datagram(sk, MSG_PEEK, 1, &err); + if (skb != NULL) { + __sctp_ulpevent_read_nxtinfo(sctp_skb2event(skb), + msghdr, skb); + /* Just release refcount here. */ + kfree_skb(skb); + } +} + /* Do accounting for bytes received and hold a reference to the association * for each skb. */ -- cgit v1.2.3 From 6b3fd5f3a2bbc8464a8e0bf134a183b8fa026439 Mon Sep 17 00:00:00 2001 From: Geir Ola Vaagland Date: Sat, 12 Jul 2014 20:30:39 +0200 Subject: net: sctp: implement rfc6458, 8.1.31. SCTP_DEFAULT_SNDINFO support This patch implements section 8.1.31. of RFC6458, which adds support for setting/retrieving SCTP_DEFAULT_SNDINFO: Applications that wish to use the sendto() system call may wish to specify a default set of parameters that would normally be supplied through the inclusion of ancillary data. This socket option allows such an application to set the default sctp_sndinfo structure. The application that wishes to use this socket option simply passes the sctp_sndinfo structure (defined in Section 5.3.4) to this call. The input parameters accepted by this call include snd_sid, snd_flags, snd_ppid, and snd_context. The snd_flags parameter is composed of a bitwise OR of SCTP_UNORDERED, SCTP_EOF, and SCTP_SENDALL. The snd_assoc_id field specifies the association to which to apply the parameters. For a one-to-many style socket, any of the predefined constants are also allowed in this field. The field is ignored for one-to-one style sockets. Joint work with Daniel Borkmann. Signed-off-by: Geir Ola Vaagland Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/uapi/linux/sctp.h | 1 + net/sctp/socket.c | 107 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 99 insertions(+), 9 deletions(-) diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h index 222f82ffeca4..ce70fe6b45df 100644 --- a/include/uapi/linux/sctp.h +++ b/include/uapi/linux/sctp.h @@ -97,6 +97,7 @@ typedef __s32 sctp_assoc_t; #define SCTP_PEER_ADDR_THLDS 31 #define SCTP_RECVRCVINFO 32 #define SCTP_RECVNXTINFO 33 +#define SCTP_DEFAULT_SNDINFO 34 /* Internal Socket Options. Some of the sctp library functions are * implemented using these socket options. diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9bca87ee5152..d95a50c013c9 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2770,19 +2770,22 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, char __user *optval, unsigned int optlen) { - struct sctp_sndrcvinfo info; - struct sctp_association *asoc; struct sctp_sock *sp = sctp_sk(sk); + struct sctp_association *asoc; + struct sctp_sndrcvinfo info; - if (optlen != sizeof(struct sctp_sndrcvinfo)) + if (optlen != sizeof(info)) return -EINVAL; if (copy_from_user(&info, optval, optlen)) return -EFAULT; + if (info.sinfo_flags & + ~(SCTP_UNORDERED | SCTP_ADDR_OVER | + SCTP_ABORT | SCTP_EOF)) + return -EINVAL; asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) return -EINVAL; - if (asoc) { asoc->default_stream = info.sinfo_stream; asoc->default_flags = info.sinfo_flags; @@ -2800,6 +2803,44 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, return 0; } +/* RFC6458, Section 8.1.31. Set/get Default Send Parameters + * (SCTP_DEFAULT_SNDINFO) + */ +static int sctp_setsockopt_default_sndinfo(struct sock *sk, + char __user *optval, + unsigned int optlen) +{ + struct sctp_sock *sp = sctp_sk(sk); + struct sctp_association *asoc; + struct sctp_sndinfo info; + + if (optlen != sizeof(info)) + return -EINVAL; + if (copy_from_user(&info, optval, optlen)) + return -EFAULT; + if (info.snd_flags & + ~(SCTP_UNORDERED | SCTP_ADDR_OVER | + SCTP_ABORT | SCTP_EOF)) + return -EINVAL; + + asoc = sctp_id2assoc(sk, info.snd_assoc_id); + if (!asoc && info.snd_assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + if (asoc) { + asoc->default_stream = info.snd_sid; + asoc->default_flags = info.snd_flags; + asoc->default_ppid = info.snd_ppid; + asoc->default_context = info.snd_context; + } else { + sp->default_stream = info.snd_sid; + sp->default_flags = info.snd_flags; + sp->default_ppid = info.snd_ppid; + sp->default_context = info.snd_context; + } + + return 0; +} + /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) * * Requests that the local SCTP stack use the enclosed peer address as @@ -3725,6 +3766,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, retval = sctp_setsockopt_default_send_param(sk, optval, optlen); break; + case SCTP_DEFAULT_SNDINFO: + retval = sctp_setsockopt_default_sndinfo(sk, optval, optlen); + break; case SCTP_PRIMARY_ADDR: retval = sctp_setsockopt_primary_addr(sk, optval, optlen); break; @@ -5027,14 +5071,14 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, int len, char __user *optval, int __user *optlen) { - struct sctp_sndrcvinfo info; - struct sctp_association *asoc; struct sctp_sock *sp = sctp_sk(sk); + struct sctp_association *asoc; + struct sctp_sndrcvinfo info; - if (len < sizeof(struct sctp_sndrcvinfo)) + if (len < sizeof(info)) return -EINVAL; - len = sizeof(struct sctp_sndrcvinfo); + len = sizeof(info); if (copy_from_user(&info, optval, len)) return -EFAULT; @@ -5042,7 +5086,6 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) return -EINVAL; - if (asoc) { info.sinfo_stream = asoc->default_stream; info.sinfo_flags = asoc->default_flags; @@ -5065,6 +5108,48 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, return 0; } +/* RFC6458, Section 8.1.31. Set/get Default Send Parameters + * (SCTP_DEFAULT_SNDINFO) + */ +static int sctp_getsockopt_default_sndinfo(struct sock *sk, int len, + char __user *optval, + int __user *optlen) +{ + struct sctp_sock *sp = sctp_sk(sk); + struct sctp_association *asoc; + struct sctp_sndinfo info; + + if (len < sizeof(info)) + return -EINVAL; + + len = sizeof(info); + + if (copy_from_user(&info, optval, len)) + return -EFAULT; + + asoc = sctp_id2assoc(sk, info.snd_assoc_id); + if (!asoc && info.snd_assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + if (asoc) { + info.snd_sid = asoc->default_stream; + info.snd_flags = asoc->default_flags; + info.snd_ppid = asoc->default_ppid; + info.snd_context = asoc->default_context; + } else { + info.snd_sid = sp->default_stream; + info.snd_flags = sp->default_flags; + info.snd_ppid = sp->default_ppid; + info.snd_context = sp->default_context; + } + + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &info, len)) + return -EFAULT; + + return 0; +} + /* * * 7.1.5 SCTP_NODELAY @@ -5924,6 +6009,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_default_send_param(sk, len, optval, optlen); break; + case SCTP_DEFAULT_SNDINFO: + retval = sctp_getsockopt_default_sndinfo(sk, len, + optval, optlen); + break; case SCTP_PRIMARY_ADDR: retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); break; -- cgit v1.2.3 From bbbea41d5e53335fd81e89c728f71b14386f336e Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 12 Jul 2014 20:30:40 +0200 Subject: net: sctp: deprecate rfc6458, 5.3.2. SCTP_SNDRCV support With support of SCTP_SNDINFO/SCTP_RCVINFO as described in RFC6458, 5.3.4/5.3.5, we can now deprecate SCTP_SNDRCV. The RFC already declares it as deprecated: This structure mixes the send and receive path. SCTP_SNDINFO (described in Section 5.3.4) and SCTP_RCVINFO (described in Section 5.3.5) split this information. These structures should be used, when possible, since SCTP_SNDRCV is deprecated. So whenever a user tries to subscribe to sctp_data_io_event via setsockopt(2) which triggers inclusion of SCTP_SNDRCV cmsg_type, issue a warning in the log. Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/sctp/socket.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d95a50c013c9..743308f40544 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2205,8 +2205,13 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval, if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) return -EFAULT; - /* - * At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT, + if (sctp_sk(sk)->subscribe.sctp_data_io_event) + pr_warn_ratelimited(DEPRECATED "%s (pid %d) " + "Requested SCTP_SNDRCVINFO event.\n" + "Use SCTP_RCVINFO through SCTP_RECVRCVINFO option instead.\n", + current->comm, task_pid_nr(current)); + + /* At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT, * if there is no data to be sent or retransmit, the stack will * immediately send up this notification. */ -- cgit v1.2.3 From a9f559c37b582c9eb12f82ac9bb77476cfda6309 Mon Sep 17 00:00:00 2001 From: Christoph Schulz Date: Wed, 16 Jul 2014 23:41:26 +0200 Subject: net: ppp: access ppp->nextseq only if CONFIG_PPP_MULTILINK is defined Commit d762d038497c9df51c19fcbe69b094b3bf8e5568 resets the counter holding the next sequence number for multilink PPP fragments to zero whenever the SC_MULTILINK flag is set. However, this counter only exists if CONFIG_PPP_MULTILINK is defined. Consequently, the new code has to be enclosed within #ifdef CONFIG_PPP_MULTILINK ... #endif. Signed-off-by: Christoph Schulz Signed-off-by: David S. Miller --- drivers/net/ppp/ppp_generic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 3ed16a89b5d8..2031ce4051dc 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -655,8 +655,10 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; ppp_lock(ppp); cflags = ppp->flags & ~val; +#ifdef CONFIG_PPP_MULTILINK if (!(ppp->flags & SC_MULTILINK) && (val & SC_MULTILINK)) ppp->nextseq = 0; +#endif ppp->flags = val & SC_FLAG_BITS; ppp_unlock(ppp); if (cflags & SC_CCP_OPEN) -- cgit v1.2.3 From 76f084bc10004b3050b2cff9cfac29148f1f6088 Mon Sep 17 00:00:00 2001 From: Alex Gartrell Date: Wed, 16 Jul 2014 15:57:34 -0700 Subject: ipvs: Maintain all DSCP and ECN bits for ipv6 tun forwarding Previously, only the four high bits of the tclass were maintained in the ipv6 case. This matches the behavior of ipv4, though whether or not we should reflect ECN bits may be up for debate. Signed-off-by: Alex Gartrell Acked-by: Julian Anastasov Signed-off-by: Simon Horman --- net/netfilter/ipvs/ip_vs_xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 73ba1cc7a88d..6f70bdd3a90a 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -967,8 +967,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, iph->nexthdr = IPPROTO_IPV6; iph->payload_len = old_iph->payload_len; be16_add_cpu(&iph->payload_len, sizeof(*old_iph)); - iph->priority = old_iph->priority; memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl)); + ipv6_change_dsfield(iph, 0, ipv6_get_dsfield(old_iph)); iph->daddr = cp->daddr.in6; iph->saddr = saddr; iph->hop_limit = old_iph->hop_limit; -- cgit v1.2.3 From dbdf6d24ad37d63938f29a2d134a1a9f6e9e673c Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 16 Jul 2014 20:40:58 -0400 Subject: tipc: make name table distributor use new send function In a previous commit series ("tipc: new unicast transmission code") we introduced a new message sending function, tipc_link_xmit2(), and moved the unicast data users over to use that function. We now let the internal name table distributor do the same. The interaction between the name distributor and the node/link layer also becomes significantly simpler, so we can eliminate the function tipc_link_names_xmit(). Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/link.c | 41 --------------------------- net/tipc/link.h | 1 - net/tipc/name_distr.c | 76 +++++++++++++++++++++++++++++---------------------- net/tipc/name_distr.h | 2 +- net/tipc/node.c | 13 ++------- 5 files changed, 48 insertions(+), 85 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index a235b245f682..367b0f5886f8 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1032,47 +1032,6 @@ static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf) kfree_skb(buf); } -/* - * tipc_link_names_xmit - send name table entries to new neighbor - * - * Send routine for bulk delivery of name table messages when contact - * with a new neighbor occurs. No link congestion checking is performed - * because name table messages *must* be delivered. The messages must be - * small enough not to require fragmentation. - * Called without any locks held. - */ -void tipc_link_names_xmit(struct list_head *message_list, u32 dest) -{ - struct tipc_node *n_ptr; - struct tipc_link *l_ptr; - struct sk_buff *buf; - struct sk_buff *temp_buf; - - if (list_empty(message_list)) - return; - - n_ptr = tipc_node_find(dest); - if (n_ptr) { - tipc_node_lock(n_ptr); - l_ptr = n_ptr->active_links[0]; - if (l_ptr) { - /* convert circular list to linear list */ - ((struct sk_buff *)message_list->prev)->next = NULL; - link_add_chain_to_outqueue(l_ptr, - (struct sk_buff *)message_list->next, 0); - tipc_link_push_queue(l_ptr); - INIT_LIST_HEAD(message_list); - } - tipc_node_unlock(n_ptr); - } - - /* discard the messages if they couldn't be sent */ - list_for_each_safe(buf, temp_buf, ((struct sk_buff *)message_list)) { - list_del((struct list_head *)buf); - kfree_skb(buf); - } -} - /* * tipc_link_push_packet: Push one unsent packet to the media */ diff --git a/net/tipc/link.h b/net/tipc/link.h index 227ff8120897..04a59c58d385 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -228,7 +228,6 @@ void tipc_link_reset(struct tipc_link *l_ptr); void tipc_link_reset_list(unsigned int bearer_id); int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector); int tipc_link_xmit2(struct sk_buff *buf, u32 dest, u32 selector); -void tipc_link_names_xmit(struct list_head *message_list, u32 dest); int __tipc_link_xmit(struct tipc_link *l_ptr, struct sk_buff *buf); int __tipc_link_xmit2(struct tipc_link *link, struct sk_buff *buf); int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf); diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 8ce730984aa1..d16f9475fa76 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -101,24 +101,22 @@ static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest) void named_cluster_distribute(struct sk_buff *buf) { - struct sk_buff *buf_copy; - struct tipc_node *n_ptr; - struct tipc_link *l_ptr; + struct sk_buff *obuf; + struct tipc_node *node; + u32 dnode; rcu_read_lock(); - list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) { - tipc_node_lock(n_ptr); - l_ptr = n_ptr->active_links[n_ptr->addr & 1]; - if (l_ptr) { - buf_copy = skb_copy(buf, GFP_ATOMIC); - if (!buf_copy) { - tipc_node_unlock(n_ptr); - break; - } - msg_set_destnode(buf_msg(buf_copy), n_ptr->addr); - __tipc_link_xmit(l_ptr, buf_copy); - } - tipc_node_unlock(n_ptr); + list_for_each_entry_rcu(node, &tipc_node_list, list) { + dnode = node->addr; + if (in_own_node(dnode)) + continue; + if (!tipc_node_active_links(node)) + continue; + obuf = skb_copy(buf, GFP_ATOMIC); + if (!obuf) + break; + msg_set_destnode(buf_msg(obuf), dnode); + tipc_link_xmit2(obuf, dnode, dnode); } rcu_read_unlock(); @@ -175,34 +173,44 @@ struct sk_buff *tipc_named_withdraw(struct publication *publ) return buf; } -/* +/** * named_distribute - prepare name info for bulk distribution to another node + * @msg_list: list of messages (buffers) to be returned from this function + * @dnode: node to be updated + * @pls: linked list of publication items to be packed into buffer chain */ -static void named_distribute(struct list_head *message_list, u32 node, - struct publ_list *pls, u32 max_item_buf) +static void named_distribute(struct list_head *msg_list, u32 dnode, + struct publ_list *pls) { struct publication *publ; struct sk_buff *buf = NULL; struct distr_item *item = NULL; - u32 left = 0; - u32 rest = pls->size * ITEM_SIZE; + uint dsz = pls->size * ITEM_SIZE; + uint msg_dsz = (tipc_node_get_mtu(dnode, 0) / ITEM_SIZE) * ITEM_SIZE; + uint rem = dsz; + uint msg_rem = 0; list_for_each_entry(publ, &pls->list, local_list) { + /* Prepare next buffer: */ if (!buf) { - left = (rest <= max_item_buf) ? rest : max_item_buf; - rest -= left; - buf = named_prepare_buf(PUBLICATION, left, node); + msg_rem = min_t(uint, rem, msg_dsz); + rem -= msg_rem; + buf = named_prepare_buf(PUBLICATION, msg_rem, dnode); if (!buf) { pr_warn("Bulk publication failure\n"); return; } item = (struct distr_item *)msg_data(buf_msg(buf)); } + + /* Pack publication into message: */ publ_to_item(item, publ); item++; - left -= ITEM_SIZE; - if (!left) { - list_add_tail((struct list_head *)buf, message_list); + msg_rem -= ITEM_SIZE; + + /* Append full buffer to list: */ + if (!msg_rem) { + list_add_tail((struct list_head *)buf, msg_list); buf = NULL; } } @@ -211,16 +219,20 @@ static void named_distribute(struct list_head *message_list, u32 node, /** * tipc_named_node_up - tell specified node about all publications by this node */ -void tipc_named_node_up(u32 max_item_buf, u32 node) +void tipc_named_node_up(u32 dnode) { - LIST_HEAD(message_list); + LIST_HEAD(msg_list); + struct sk_buff *buf_chain; read_lock_bh(&tipc_nametbl_lock); - named_distribute(&message_list, node, &publ_cluster, max_item_buf); - named_distribute(&message_list, node, &publ_zone, max_item_buf); + named_distribute(&msg_list, dnode, &publ_cluster); + named_distribute(&msg_list, dnode, &publ_zone); read_unlock_bh(&tipc_nametbl_lock); - tipc_link_names_xmit(&message_list, node); + /* Convert circular list to linear list and send: */ + buf_chain = (struct sk_buff *)msg_list.next; + ((struct sk_buff *)msg_list.prev)->next = NULL; + tipc_link_xmit2(buf_chain, dnode, dnode); } /** diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h index b2eed4ec1526..8afe32b7fc9a 100644 --- a/net/tipc/name_distr.h +++ b/net/tipc/name_distr.h @@ -70,7 +70,7 @@ struct distr_item { struct sk_buff *tipc_named_publish(struct publication *publ); struct sk_buff *tipc_named_withdraw(struct publication *publ); void named_cluster_distribute(struct sk_buff *buf); -void tipc_named_node_up(u32 max_item_buf, u32 node); +void tipc_named_node_up(u32 dnode); void tipc_named_rcv(struct sk_buff *buf); void tipc_named_reinit(void); diff --git a/net/tipc/node.c b/net/tipc/node.c index d959343043fd..f7069299943f 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -474,8 +474,6 @@ int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len) void tipc_node_unlock(struct tipc_node *node) { LIST_HEAD(nsub_list); - struct tipc_link *link; - int pkt_sz = 0; u32 addr = 0; if (likely(!node->action_flags)) { @@ -488,18 +486,13 @@ void tipc_node_unlock(struct tipc_node *node) node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN; } if (node->action_flags & TIPC_NOTIFY_NODE_UP) { - link = node->active_links[0]; node->action_flags &= ~TIPC_NOTIFY_NODE_UP; - if (link) { - pkt_sz = ((link->max_pkt - INT_H_SIZE) / ITEM_SIZE) * - ITEM_SIZE; - addr = node->addr; - } + addr = node->addr; } spin_unlock_bh(&node->lock); if (!list_empty(&nsub_list)) tipc_nodesub_notify(&nsub_list); - if (pkt_sz) - tipc_named_node_up(pkt_sz, addr); + if (addr) + tipc_named_node_up(addr); } -- cgit v1.2.3 From 25b660c7e202d533e4985380b24729fd12de2b5e Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 16 Jul 2014 20:40:59 -0400 Subject: tipc: let internal link users call the new link send function We convert the link internal users (changeover protocol, broadcast synchronization) to use the new packet send function. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/link.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 367b0f5886f8..d1255ba51216 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -999,7 +999,7 @@ int tipc_link_xmit2(struct sk_buff *buf, u32 dnode, u32 selector) * * Called with node locked */ -static void tipc_link_sync_xmit(struct tipc_link *l) +static void tipc_link_sync_xmit(struct tipc_link *link) { struct sk_buff *buf; struct tipc_msg *msg; @@ -1009,10 +1009,9 @@ static void tipc_link_sync_xmit(struct tipc_link *l) return; msg = buf_msg(buf); - tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, l->addr); - msg_set_last_bcast(msg, l->owner->bclink.acked); - link_add_chain_to_outqueue(l, buf, 0); - tipc_link_push_queue(l); + tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, link->addr); + msg_set_last_bcast(msg, link->owner->bclink.acked); + __tipc_link_xmit2(link, buf); } /* @@ -1859,7 +1858,7 @@ static void tipc_link_tunnel_xmit(struct tipc_link *l_ptr, } skb_copy_to_linear_data(buf, tunnel_hdr, INT_H_SIZE); skb_copy_to_linear_data_offset(buf, INT_H_SIZE, msg, length); - __tipc_link_xmit(tunnel, buf); + __tipc_link_xmit2(tunnel, buf); } @@ -1892,7 +1891,7 @@ void tipc_link_failover_send_queue(struct tipc_link *l_ptr) if (buf) { skb_copy_to_linear_data(buf, &tunnel_hdr, INT_H_SIZE); msg_set_size(&tunnel_hdr, INT_H_SIZE); - __tipc_link_xmit(tunnel, buf); + __tipc_link_xmit2(tunnel, buf); } else { pr_warn("%sunable to send changeover msg\n", link_co_err); @@ -1965,7 +1964,7 @@ void tipc_link_dup_queue_xmit(struct tipc_link *l_ptr, skb_copy_to_linear_data(outbuf, &tunnel_hdr, INT_H_SIZE); skb_copy_to_linear_data_offset(outbuf, INT_H_SIZE, iter->data, length); - __tipc_link_xmit(tunnel, outbuf); + __tipc_link_xmit2(tunnel, outbuf); if (!tipc_link_is_up(l_ptr)) return; iter = iter->next; -- cgit v1.2.3 From 078bec826f7b73cf2a2397680537bcb7e075b492 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 16 Jul 2014 20:41:00 -0400 Subject: tipc: add new functions for multicast and broadcast distribution We add a new broadcast link transmit function in bclink.c and a new receive function in socket.c. The purpose is to move the branching between external and internal destination down to the link layer, just as we have done with unicast in earlier commits. We also make use of the new link-independent fragmentation support that was introduced in an earlier commit series. This gives a shorter and simpler code path, and makes it possible to obtain copy-free buffer delivery to all node local destination sockets. The new transmission code is added in parallel with the existing one, and will be used by the socket multicast send function in the next commit in this series. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/bcast.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- net/tipc/bcast.h | 4 +++- net/tipc/msg.c | 35 +++++++++++++++++++++++++++++++++++ net/tipc/msg.h | 2 ++ net/tipc/socket.c | 40 ++++++++++++++++++++++++++++++++++++++++ net/tipc/socket.h | 2 ++ 6 files changed, 136 insertions(+), 2 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 55c6c9d3e1ce..ac947251dd37 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -1,7 +1,7 @@ /* * net/tipc/bcast.c: TIPC broadcast code * - * Copyright (c) 2004-2006, Ericsson AB + * Copyright (c) 2004-2006, 2014, Ericsson AB * Copyright (c) 2004, Intel Corporation. * Copyright (c) 2005, 2010-2011, Wind River Systems * All rights reserved. @@ -38,6 +38,8 @@ #include "core.h" #include "link.h" #include "port.h" +#include "socket.h" +#include "msg.h" #include "bcast.h" #include "name_distr.h" @@ -138,6 +140,11 @@ static void tipc_bclink_unlock(void) tipc_link_reset_all(node); } +uint tipc_bclink_get_mtu(void) +{ + return MAX_PKT_DEFAULT_MCAST; +} + void tipc_bclink_set_flags(unsigned int flags) { bclink->flags |= flags; @@ -408,6 +415,52 @@ exit: return res; } +/* tipc_bclink_xmit2 - broadcast buffer chain to all nodes in cluster + * and to identified node local sockets + * @buf: chain of buffers containing message + * Consumes the buffer chain, except when returning -ELINKCONG + * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE + */ +int tipc_bclink_xmit2(struct sk_buff *buf) +{ + int rc = 0; + int bc = 0; + struct sk_buff *clbuf; + + /* Prepare clone of message for local node */ + clbuf = tipc_msg_reassemble(buf); + if (unlikely(!clbuf)) { + kfree_skb_list(buf); + return -EHOSTUNREACH; + } + + /* Broadcast to all other nodes */ + if (likely(bclink)) { + tipc_bclink_lock(); + if (likely(bclink->bcast_nodes.count)) { + rc = __tipc_link_xmit(bcl, buf); + if (likely(!rc)) { + bclink_set_last_sent(); + bcl->stats.queue_sz_counts++; + bcl->stats.accu_queue_sz += bcl->out_queue_size; + } + bc = 1; + } + tipc_bclink_unlock(); + } + + if (unlikely(!bc)) + kfree_skb_list(buf); + + /* Deliver message clone */ + if (likely(!rc)) + tipc_sk_mcast_rcv(clbuf); + else + kfree_skb(clbuf); + + return rc; +} + /** * bclink_accept_pkt - accept an incoming, in-sequence broadcast packet * diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index 00330c45df3e..d90645f408aa 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -1,7 +1,7 @@ /* * net/tipc/bcast.h: Include file for TIPC broadcast code * - * Copyright (c) 2003-2006, Ericsson AB + * Copyright (c) 2003-2006, 2014, Ericsson AB * Copyright (c) 2005, 2010-2011, Wind River Systems * All rights reserved. * @@ -98,5 +98,7 @@ int tipc_bclink_stats(char *stats_buf, const u32 buf_size); int tipc_bclink_reset_stats(void); int tipc_bclink_set_queue_limits(u32 limit); void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action); +uint tipc_bclink_get_mtu(void); +int tipc_bclink_xmit2(struct sk_buff *buf); #endif diff --git a/net/tipc/msg.c b/net/tipc/msg.c index ce6d929d66d2..9682296f5e7c 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -417,3 +417,38 @@ int tipc_msg_eval(struct sk_buff *buf, u32 *dnode) msg_set_destport(msg, dport); return TIPC_OK; } + +/* tipc_msg_reassemble() - clone a buffer chain of fragments and + * reassemble the clones into one message + */ +struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain) +{ + struct sk_buff *buf = chain; + struct sk_buff *frag = buf; + struct sk_buff *head = NULL; + int hdr_sz; + + /* Copy header if single buffer */ + if (!buf->next) { + hdr_sz = skb_headroom(buf) + msg_hdr_sz(buf_msg(buf)); + return __pskb_copy(buf, hdr_sz, GFP_ATOMIC); + } + + /* Clone all fragments and reassemble */ + while (buf) { + frag = skb_clone(buf, GFP_ATOMIC); + if (!frag) + goto error; + frag->next = NULL; + if (tipc_buf_append(&head, &frag)) + break; + if (!head) + goto error; + buf = buf->next; + } + return frag; +error: + pr_warn("Failed do clone local mcast rcv buffer\n"); + kfree_skb(head); + return NULL; +} diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 7d574346e75e..a15d59601bf9 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -744,4 +744,6 @@ bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode); int tipc_msg_build2(struct tipc_msg *mhdr, struct iovec const *iov, int offset, int dsz, int mtu , struct sk_buff **chain); +struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain); + #endif diff --git a/net/tipc/socket.c b/net/tipc/socket.c index de01622672b2..8d30995682b1 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -534,6 +534,46 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, return mask; } +/* tipc_sk_mcast_rcv - Deliver multicast message to all destination sockets + */ +void tipc_sk_mcast_rcv(struct sk_buff *buf) +{ + struct tipc_msg *msg = buf_msg(buf); + struct tipc_port_list dports = {0, NULL, }; + struct tipc_port_list *item; + struct sk_buff *b; + uint i, last, dst = 0; + u32 scope = TIPC_CLUSTER_SCOPE; + + if (in_own_node(msg_orignode(msg))) + scope = TIPC_NODE_SCOPE; + + /* Create destination port list: */ + tipc_nametbl_mc_translate(msg_nametype(msg), + msg_namelower(msg), + msg_nameupper(msg), + scope, + &dports); + last = dports.count; + if (!last) { + kfree_skb(buf); + return; + } + + for (item = &dports; item; item = item->next) { + for (i = 0; i < PLSIZE && ++dst <= last; i++) { + b = (dst != last) ? skb_clone(buf, GFP_ATOMIC) : buf; + if (!b) { + pr_warn("Failed do clone mcast rcv buffer\n"); + continue; + } + msg_set_destport(msg, item->ports[i]); + tipc_sk_rcv(b); + } + } + tipc_port_list_free(&dports); +} + /** * tipc_sk_proto_rcv - receive a connection mng protocol message * @tsk: receiving socket diff --git a/net/tipc/socket.h b/net/tipc/socket.h index 2cdede9eda1b..43b75b3ceced 100644 --- a/net/tipc/socket.h +++ b/net/tipc/socket.h @@ -85,4 +85,6 @@ static inline int tipc_sk_conn_cong(struct tipc_sock *tsk) int tipc_sk_rcv(struct sk_buff *buf); +void tipc_sk_mcast_rcv(struct sk_buff *buf); + #endif -- cgit v1.2.3 From 0abd8ff21f19adddc465538354e9baaca63df073 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 16 Jul 2014 20:41:01 -0400 Subject: tipc: start using the new multicast functions In this commit, we convert the socket multicast send function to directly call the new multicast/broadcast function (tipc_bclink_xmit2()) introduced in the previous commit. We do this instead of letting the call go via the now obsolete tipc_port_mcast_xmit(), hence saving a call level and some code complexity. We also remove the initial destination lookup at the message sending side, and replace that with an unconditional lookup at the receiving side, including on the sending node itself. This makes the destination lookup and message transfer more uniform than before. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/bcast.c | 7 ++--- net/tipc/socket.c | 90 ++++++++++++++++++++++++++++++++----------------------- 2 files changed, 56 insertions(+), 41 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index ac947251dd37..4a1c9afc9d74 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -496,7 +496,7 @@ void tipc_bclink_rcv(struct sk_buff *buf) struct tipc_node *node; u32 next_in; u32 seqno; - int deferred; + int deferred = 0; /* Screen out unwanted broadcast messages */ @@ -547,7 +547,7 @@ receive: tipc_bclink_unlock(); tipc_node_unlock(node); if (likely(msg_mcast(msg))) - tipc_port_mcast_rcv(buf, NULL); + tipc_sk_mcast_rcv(buf); else kfree_skb(buf); } else if (msg_user(msg) == MSG_BUNDLER) { @@ -626,8 +626,7 @@ receive: node->bclink.deferred_size += deferred; bclink_update_last_sent(node, seqno); buf = NULL; - } else - deferred = 0; + } tipc_bclink_lock(); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 8d30995682b1..b28eea50c7fc 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -53,6 +53,7 @@ static void tipc_data_ready(struct sock *sk); static void tipc_write_space(struct sock *sk); static int tipc_release(struct socket *sock); static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags); +static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p); static const struct proto_ops packet_ops; static const struct proto_ops stream_ops; @@ -534,6 +535,58 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, return mask; } +/** + * tipc_sendmcast - send multicast message + * @sock: socket structure + * @seq: destination address + * @iov: message data to send + * @dsz: total length of message data + * @timeo: timeout to wait for wakeup + * + * Called from function tipc_sendmsg(), which has done all sanity checks + * Returns the number of bytes sent on success, or errno + */ +static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq, + struct iovec *iov, size_t dsz, long timeo) +{ + struct sock *sk = sock->sk; + struct tipc_msg *mhdr = &tipc_sk(sk)->port.phdr; + struct sk_buff *buf; + uint mtu; + int rc; + + msg_set_type(mhdr, TIPC_MCAST_MSG); + msg_set_lookup_scope(mhdr, TIPC_CLUSTER_SCOPE); + msg_set_destport(mhdr, 0); + msg_set_destnode(mhdr, 0); + msg_set_nametype(mhdr, seq->type); + msg_set_namelower(mhdr, seq->lower); + msg_set_nameupper(mhdr, seq->upper); + msg_set_hdr_sz(mhdr, MCAST_H_SIZE); + +new_mtu: + mtu = tipc_bclink_get_mtu(); + rc = tipc_msg_build2(mhdr, iov, 0, dsz, mtu, &buf); + if (unlikely(rc < 0)) + return rc; + + do { + rc = tipc_bclink_xmit(buf); + if (likely(rc >= 0)) { + rc = dsz; + break; + } + if (rc == -EMSGSIZE) + goto new_mtu; + if (rc != -ELINKCONG) + break; + rc = tipc_wait_for_sndmsg(sock, &timeo); + if (rc) + kfree_skb_list(buf); + } while (!rc); + return rc; +} + /* tipc_sk_mcast_rcv - Deliver multicast message to all destination sockets */ void tipc_sk_mcast_rcv(struct sk_buff *buf) @@ -669,43 +722,6 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) return 0; } -/** - * tipc_sendmcast - send multicast message - * @sock: socket structure - * @seq: destination address - * @iov: message data to send - * @dsz: total length of message data - * @timeo: timeout to wait for wakeup - * - * Called from function tipc_sendmsg(), which has done all sanity checks - * Returns the number of bytes sent on success, or errno - */ -static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq, - struct iovec *iov, size_t dsz, long timeo) -{ - struct sock *sk = sock->sk; - struct tipc_sock *tsk = tipc_sk(sk); - int rc; - - do { - if (sock->state != SS_READY) { - rc = -EOPNOTSUPP; - break; - } - rc = tipc_port_mcast_xmit(&tsk->port, seq, iov, dsz); - if (likely(rc >= 0)) { - if (sock->state != SS_READY) - sock->state = SS_CONNECTING; - break; - } - if (rc != -ELINKCONG) - break; - rc = tipc_wait_for_sndmsg(sock, &timeo); - } while (!rc); - - return rc; -} - /** * tipc_sendmsg - send message in connectionless manner * @iocb: if NULL, indicates that socket lock is already held -- cgit v1.2.3 From c4116e10579c5bbbfc3cd2ad0324ee0d8691e531 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 16 Jul 2014 20:41:02 -0400 Subject: tipc: remove unreferenced functions We can now remove a number of functions which have become obsolete and unreferenced through this commit series. There are no functional changes in this commit. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/bcast.c | 26 ------ net/tipc/bcast.h | 1 - net/tipc/link.c | 247 ------------------------------------------------------- net/tipc/link.h | 6 -- net/tipc/msg.c | 35 -------- net/tipc/msg.h | 3 - net/tipc/port.c | 112 ------------------------- net/tipc/port.h | 10 --- 8 files changed, 440 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 4a1c9afc9d74..2f3256da6f88 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -389,32 +389,6 @@ static void bclink_peek_nack(struct tipc_msg *msg) tipc_node_unlock(n_ptr); } -/* - * tipc_bclink_xmit - broadcast a packet to all nodes in cluster - */ -int tipc_bclink_xmit(struct sk_buff *buf) -{ - int res; - - tipc_bclink_lock(); - - if (!bclink->bcast_nodes.count) { - res = msg_data_sz(buf_msg(buf)); - kfree_skb(buf); - goto exit; - } - - res = __tipc_link_xmit(bcl, buf); - if (likely(res >= 0)) { - bclink_set_last_sent(); - bcl->stats.queue_sz_counts++; - bcl->stats.accu_queue_sz += bcl->out_queue_size; - } -exit: - tipc_bclink_unlock(); - return res; -} - /* tipc_bclink_xmit2 - broadcast buffer chain to all nodes in cluster * and to identified node local sockets * @buf: chain of buffers containing message diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index d90645f408aa..af6b6579f5c7 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -89,7 +89,6 @@ void tipc_bclink_add_node(u32 addr); void tipc_bclink_remove_node(u32 addr); struct tipc_node *tipc_bclink_retransmit_to(void); void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked); -int tipc_bclink_xmit(struct sk_buff *buf); void tipc_bclink_rcv(struct sk_buff *buf); u32 tipc_bclink_get_last_sent(void); u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr); diff --git a/net/tipc/link.c b/net/tipc/link.c index d1255ba51216..28730ddf4b78 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -85,7 +85,6 @@ static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); static void link_state_event(struct tipc_link *l_ptr, u32 event); static void link_reset_statistics(struct tipc_link *l_ptr); static void link_print(struct tipc_link *l_ptr, const char *str); -static int tipc_link_frag_xmit(struct tipc_link *l_ptr, struct sk_buff *buf); static void tipc_link_sync_xmit(struct tipc_link *l); static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf); static int tipc_link_input(struct tipc_link *l, struct sk_buff *buf); @@ -679,180 +678,6 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) } } -/* - * link_bundle_buf(): Append contents of a buffer to - * the tail of an existing one. - */ -static int link_bundle_buf(struct tipc_link *l_ptr, struct sk_buff *bundler, - struct sk_buff *buf) -{ - struct tipc_msg *bundler_msg = buf_msg(bundler); - struct tipc_msg *msg = buf_msg(buf); - u32 size = msg_size(msg); - u32 bundle_size = msg_size(bundler_msg); - u32 to_pos = align(bundle_size); - u32 pad = to_pos - bundle_size; - - if (msg_user(bundler_msg) != MSG_BUNDLER) - return 0; - if (msg_type(bundler_msg) != OPEN_MSG) - return 0; - if (skb_tailroom(bundler) < (pad + size)) - return 0; - if (l_ptr->max_pkt < (to_pos + size)) - return 0; - - skb_put(bundler, pad + size); - skb_copy_to_linear_data_offset(bundler, to_pos, buf->data, size); - msg_set_size(bundler_msg, to_pos + size); - msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1); - kfree_skb(buf); - l_ptr->stats.sent_bundled++; - return 1; -} - -static void link_add_to_outqueue(struct tipc_link *l_ptr, - struct sk_buff *buf, - struct tipc_msg *msg) -{ - u32 ack = mod(l_ptr->next_in_no - 1); - u32 seqno = mod(l_ptr->next_out_no++); - - msg_set_word(msg, 2, ((ack << 16) | seqno)); - msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); - buf->next = NULL; - if (l_ptr->first_out) { - l_ptr->last_out->next = buf; - l_ptr->last_out = buf; - } else - l_ptr->first_out = l_ptr->last_out = buf; - - l_ptr->out_queue_size++; - if (l_ptr->out_queue_size > l_ptr->stats.max_queue_sz) - l_ptr->stats.max_queue_sz = l_ptr->out_queue_size; -} - -static void link_add_chain_to_outqueue(struct tipc_link *l_ptr, - struct sk_buff *buf_chain, - u32 long_msgno) -{ - struct sk_buff *buf; - struct tipc_msg *msg; - - if (!l_ptr->next_out) - l_ptr->next_out = buf_chain; - while (buf_chain) { - buf = buf_chain; - buf_chain = buf_chain->next; - - msg = buf_msg(buf); - msg_set_long_msgno(msg, long_msgno); - link_add_to_outqueue(l_ptr, buf, msg); - } -} - -/* - * tipc_link_xmit() is the 'full path' for messages, called from - * inside TIPC when the 'fast path' in tipc_send_xmit - * has failed, and from link_send() - */ -int __tipc_link_xmit(struct tipc_link *l_ptr, struct sk_buff *buf) -{ - struct tipc_msg *msg = buf_msg(buf); - u32 size = msg_size(msg); - u32 dsz = msg_data_sz(msg); - u32 queue_size = l_ptr->out_queue_size; - u32 imp = tipc_msg_tot_importance(msg); - u32 queue_limit = l_ptr->queue_limit[imp]; - u32 max_packet = l_ptr->max_pkt; - - /* Match msg importance against queue limits: */ - if (unlikely(queue_size >= queue_limit)) { - if (imp <= TIPC_CRITICAL_IMPORTANCE) { - link_schedule_port(l_ptr, msg_origport(msg), size); - kfree_skb(buf); - return -ELINKCONG; - } - kfree_skb(buf); - if (imp > CONN_MANAGER) { - pr_warn("%s<%s>, send queue full", link_rst_msg, - l_ptr->name); - tipc_link_reset(l_ptr); - } - return dsz; - } - - /* Fragmentation needed ? */ - if (size > max_packet) - return tipc_link_frag_xmit(l_ptr, buf); - - /* Packet can be queued or sent. */ - if (likely(!link_congested(l_ptr))) { - link_add_to_outqueue(l_ptr, buf, msg); - - tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr); - l_ptr->unacked_window = 0; - return dsz; - } - /* Congestion: can message be bundled ? */ - if ((msg_user(msg) != CHANGEOVER_PROTOCOL) && - (msg_user(msg) != MSG_FRAGMENTER)) { - - /* Try adding message to an existing bundle */ - if (l_ptr->next_out && - link_bundle_buf(l_ptr, l_ptr->last_out, buf)) - return dsz; - - /* Try creating a new bundle */ - if (size <= max_packet * 2 / 3) { - struct sk_buff *bundler = tipc_buf_acquire(max_packet); - struct tipc_msg bundler_hdr; - - if (bundler) { - tipc_msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG, - INT_H_SIZE, l_ptr->addr); - skb_copy_to_linear_data(bundler, &bundler_hdr, - INT_H_SIZE); - skb_trim(bundler, INT_H_SIZE); - link_bundle_buf(l_ptr, bundler, buf); - buf = bundler; - msg = buf_msg(buf); - l_ptr->stats.sent_bundles++; - } - } - } - if (!l_ptr->next_out) - l_ptr->next_out = buf; - link_add_to_outqueue(l_ptr, buf, msg); - return dsz; -} - -/* - * tipc_link_xmit(): same as __tipc_link_xmit(), but the link to use - * has not been selected yet, and the the owner node is not locked - * Called by TIPC internal users, e.g. the name distributor - */ -int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector) -{ - struct tipc_link *l_ptr; - struct tipc_node *n_ptr; - int res = -ELINKCONG; - - n_ptr = tipc_node_find(dest); - if (n_ptr) { - tipc_node_lock(n_ptr); - l_ptr = n_ptr->active_links[selector & 1]; - if (l_ptr) - res = __tipc_link_xmit(l_ptr, buf); - else - kfree_skb(buf); - tipc_node_unlock(n_ptr); - } else { - kfree_skb(buf); - } - return res; -} - /* tipc_link_cong: determine return value and how to treat the * sent buffer during link congestion. * - For plain, errorless user data messages we keep the buffer and @@ -2123,78 +1948,6 @@ void tipc_link_bundle_rcv(struct sk_buff *buf) kfree_skb(buf); } -/* - * Fragmentation/defragmentation: - */ - -/* - * tipc_link_frag_xmit: Entry for buffers needing fragmentation. - * The buffer is complete, inclusive total message length. - * Returns user data length. - */ -static int tipc_link_frag_xmit(struct tipc_link *l_ptr, struct sk_buff *buf) -{ - struct sk_buff *buf_chain = NULL; - struct sk_buff *buf_chain_tail = (struct sk_buff *)&buf_chain; - struct tipc_msg *inmsg = buf_msg(buf); - struct tipc_msg fragm_hdr; - u32 insize = msg_size(inmsg); - u32 dsz = msg_data_sz(inmsg); - unchar *crs = buf->data; - u32 rest = insize; - u32 pack_sz = l_ptr->max_pkt; - u32 fragm_sz = pack_sz - INT_H_SIZE; - u32 fragm_no = 0; - u32 destaddr; - - if (msg_short(inmsg)) - destaddr = l_ptr->addr; - else - destaddr = msg_destnode(inmsg); - - /* Prepare reusable fragment header: */ - tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, - INT_H_SIZE, destaddr); - - /* Chop up message: */ - while (rest > 0) { - struct sk_buff *fragm; - - if (rest <= fragm_sz) { - fragm_sz = rest; - msg_set_type(&fragm_hdr, LAST_FRAGMENT); - } - fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); - if (fragm == NULL) { - kfree_skb(buf); - kfree_skb_list(buf_chain); - return -ENOMEM; - } - msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); - fragm_no++; - msg_set_fragm_no(&fragm_hdr, fragm_no); - skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE); - skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs, - fragm_sz); - buf_chain_tail->next = fragm; - buf_chain_tail = fragm; - - rest -= fragm_sz; - crs += fragm_sz; - msg_set_type(&fragm_hdr, FRAGMENT); - } - kfree_skb(buf); - - /* Append chain of fragments to send queue & send them */ - l_ptr->long_msg_seq_no++; - link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no); - l_ptr->stats.sent_fragments += fragm_no; - l_ptr->stats.sent_fragmented++; - tipc_link_push_queue(l_ptr); - - return dsz; -} - static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) { if ((tolerance < TIPC_MIN_LINK_TOL) || (tolerance > TIPC_MAX_LINK_TOL)) diff --git a/net/tipc/link.h b/net/tipc/link.h index 04a59c58d385..f0ebeb677a8b 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -226,15 +226,9 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, void tipc_link_reset_all(struct tipc_node *node); void tipc_link_reset(struct tipc_link *l_ptr); void tipc_link_reset_list(unsigned int bearer_id); -int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector); int tipc_link_xmit2(struct sk_buff *buf, u32 dest, u32 selector); -int __tipc_link_xmit(struct tipc_link *l_ptr, struct sk_buff *buf); int __tipc_link_xmit2(struct tipc_link *link, struct sk_buff *buf); -int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf); u32 tipc_link_get_max_pkt(u32 dest, u32 selector); -int tipc_link_iovec_xmit_fast(struct tipc_port *sender, - struct iovec const *msg_sect, - unsigned int len, u32 destnode); void tipc_link_bundle_rcv(struct sk_buff *buf); void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob, u32 gap, u32 tolerance, u32 priority, u32 acked_mtu); diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 9682296f5e7c..e3102ea494d4 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -60,41 +60,6 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, msg_set_destnode(m, destnode); } -/** - * tipc_msg_build - create message using specified header and data - * - * Note: Caller must not hold any locks in case copy_from_user() is interrupted! - * - * Returns message data size or errno - */ -int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, - unsigned int len, int max_size, struct sk_buff **buf) -{ - int dsz, sz, hsz; - unsigned char *to; - - dsz = len; - hsz = msg_hdr_sz(hdr); - sz = hsz + dsz; - msg_set_size(hdr, sz); - if (unlikely(sz > max_size)) { - *buf = NULL; - return dsz; - } - - *buf = tipc_buf_acquire(sz); - if (!(*buf)) - return -ENOMEM; - skb_copy_to_linear_data(*buf, hdr, hsz); - to = (*buf)->data + hsz; - if (len && memcpy_fromiovecend(to, msg_sect, 0, dsz)) { - kfree_skb(*buf); - *buf = NULL; - return -EFAULT; - } - return dsz; -} - /* tipc_buf_append(): Append a buffer to the fragment list of another buffer * @*headbuf: in: NULL for first frag, otherwise value returned from prev call * out: set when successful non-complete reassembly, otherwise NULL diff --git a/net/tipc/msg.h b/net/tipc/msg.h index a15d59601bf9..868fe22e3452 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -732,9 +732,6 @@ int tipc_msg_eval(struct sk_buff *buf, u32 *dnode); void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, u32 destnode); -int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, - unsigned int len, int max_size, struct sk_buff **buf); - int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf); bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu); diff --git a/net/tipc/port.c b/net/tipc/port.c index 0d09dcb6da18..835dca1fd7ad 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -74,118 +74,6 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg) (!peernode && (orignode == tipc_own_addr)); } -/** - * tipc_port_mcast_xmit - send a multicast message to local and remote - * destinations - */ -int tipc_port_mcast_xmit(struct tipc_port *oport, - struct tipc_name_seq const *seq, - struct iovec const *msg_sect, - unsigned int len) -{ - struct tipc_msg *hdr; - struct sk_buff *buf; - struct sk_buff *ibuf = NULL; - struct tipc_port_list dports = {0, NULL, }; - int ext_targets; - int res; - - /* Create multicast message */ - hdr = &oport->phdr; - msg_set_type(hdr, TIPC_MCAST_MSG); - msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE); - msg_set_destport(hdr, 0); - msg_set_destnode(hdr, 0); - msg_set_nametype(hdr, seq->type); - msg_set_namelower(hdr, seq->lower); - msg_set_nameupper(hdr, seq->upper); - msg_set_hdr_sz(hdr, MCAST_H_SIZE); - res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf); - if (unlikely(!buf)) - return res; - - /* Figure out where to send multicast message */ - ext_targets = tipc_nametbl_mc_translate(seq->type, seq->lower, seq->upper, - TIPC_NODE_SCOPE, &dports); - - /* Send message to destinations (duplicate it only if necessary) */ - if (ext_targets) { - if (dports.count != 0) { - ibuf = skb_copy(buf, GFP_ATOMIC); - if (ibuf == NULL) { - tipc_port_list_free(&dports); - kfree_skb(buf); - return -ENOMEM; - } - } - res = tipc_bclink_xmit(buf); - if ((res < 0) && (dports.count != 0)) - kfree_skb(ibuf); - } else { - ibuf = buf; - } - - if (res >= 0) { - if (ibuf) - tipc_port_mcast_rcv(ibuf, &dports); - } else { - tipc_port_list_free(&dports); - } - return res; -} - -/** - * tipc_port_mcast_rcv - deliver multicast message to all destination ports - * - * If there is no port list, perform a lookup to create one - */ -void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp) -{ - struct tipc_msg *msg; - struct tipc_port_list dports = {0, NULL, }; - struct tipc_port_list *item = dp; - int cnt = 0; - - msg = buf_msg(buf); - - /* Create destination port list, if one wasn't supplied */ - if (dp == NULL) { - tipc_nametbl_mc_translate(msg_nametype(msg), - msg_namelower(msg), - msg_nameupper(msg), - TIPC_CLUSTER_SCOPE, - &dports); - item = dp = &dports; - } - - /* Deliver a copy of message to each destination port */ - if (dp->count != 0) { - msg_set_destnode(msg, tipc_own_addr); - if (dp->count == 1) { - msg_set_destport(msg, dp->ports[0]); - tipc_sk_rcv(buf); - tipc_port_list_free(dp); - return; - } - for (; cnt < dp->count; cnt++) { - int index = cnt % PLSIZE; - struct sk_buff *b = skb_clone(buf, GFP_ATOMIC); - - if (b == NULL) { - pr_warn("Unable to deliver multicast message(s)\n"); - goto exit; - } - if ((index == 0) && (cnt != 0)) - item = item->next; - msg_set_destport(buf_msg(b), item->ports[index]); - tipc_sk_rcv(b); - } - } -exit: - kfree_skb(buf); - tipc_port_list_free(dp); -} - /* tipc_port_init - intiate TIPC port and lock it * * Returns obtained reference if initialization is successful, zero otherwise diff --git a/net/tipc/port.h b/net/tipc/port.h index 0e47052daa29..3f93454592b6 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -120,17 +120,7 @@ int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr, struct tipc_portid const *peer); int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg); -/* - * TIPC messaging routines - */ - -int tipc_port_mcast_xmit(struct tipc_port *port, - struct tipc_name_seq const *seq, - struct iovec const *msg, - unsigned int len); - struct sk_buff *tipc_port_get_ports(void); -void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp); void tipc_port_reinit(void); /** -- cgit v1.2.3 From 9fbfb8b120bd4fe89cd70d6c8841e6e1cfab2609 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 16 Jul 2014 20:41:03 -0400 Subject: tipc: rename temporarily named functions After the previous commit, we can now give the functions with temporary names, such as tipc_link_xmit2(), tipc_msg_build2() etc., their proper names. There are no functional changes in this commit. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/bcast.c | 6 +++--- net/tipc/bcast.h | 2 +- net/tipc/link.c | 18 +++++++++--------- net/tipc/link.h | 4 ++-- net/tipc/msg.c | 6 +++--- net/tipc/msg.h | 4 ++-- net/tipc/name_distr.c | 4 ++-- net/tipc/port.c | 10 +++++----- net/tipc/socket.c | 20 ++++++++++---------- 9 files changed, 37 insertions(+), 37 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 2f3256da6f88..d890d480ae3b 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -389,13 +389,13 @@ static void bclink_peek_nack(struct tipc_msg *msg) tipc_node_unlock(n_ptr); } -/* tipc_bclink_xmit2 - broadcast buffer chain to all nodes in cluster - * and to identified node local sockets +/* tipc_bclink_xmit - broadcast buffer chain to all nodes in cluster + * and to identified node local sockets * @buf: chain of buffers containing message * Consumes the buffer chain, except when returning -ELINKCONG * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE */ -int tipc_bclink_xmit2(struct sk_buff *buf) +int tipc_bclink_xmit(struct sk_buff *buf) { int rc = 0; int bc = 0; diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index af6b6579f5c7..4875d9536aee 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -98,6 +98,6 @@ int tipc_bclink_reset_stats(void); int tipc_bclink_set_queue_limits(u32 limit); void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action); uint tipc_bclink_get_mtu(void); -int tipc_bclink_xmit2(struct sk_buff *buf); +int tipc_bclink_xmit(struct sk_buff *buf); #endif diff --git a/net/tipc/link.c b/net/tipc/link.c index 28730ddf4b78..fb1485dc6736 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -706,7 +706,7 @@ static int tipc_link_cong(struct tipc_link *link, struct sk_buff *buf) } /** - * __tipc_link_xmit2(): same as tipc_link_xmit2, but destlink is known & locked + * __tipc_link_xmit(): same as tipc_link_xmit, but destlink is known & locked * @link: link to use * @buf: chain of buffers containing message * Consumes the buffer chain, except when returning -ELINKCONG @@ -715,7 +715,7 @@ static int tipc_link_cong(struct tipc_link *link, struct sk_buff *buf) * Only the socket functions tipc_send_stream() and tipc_send_packet() need * to act on the return value, since they may need to do more send attempts. */ -int __tipc_link_xmit2(struct tipc_link *link, struct sk_buff *buf) +int __tipc_link_xmit(struct tipc_link *link, struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); uint psz = msg_size(msg); @@ -783,7 +783,7 @@ int __tipc_link_xmit2(struct tipc_link *link, struct sk_buff *buf) } /** - * tipc_link_xmit2() is the general link level function for message sending + * tipc_link_xmit() is the general link level function for message sending * @buf: chain of buffers containing message * @dsz: amount of user data to be sent * @dnode: address of destination node @@ -791,7 +791,7 @@ int __tipc_link_xmit2(struct tipc_link *link, struct sk_buff *buf) * Consumes the buffer chain, except when returning -ELINKCONG * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE */ -int tipc_link_xmit2(struct sk_buff *buf, u32 dnode, u32 selector) +int tipc_link_xmit(struct sk_buff *buf, u32 dnode, u32 selector) { struct tipc_link *link = NULL; struct tipc_node *node; @@ -802,7 +802,7 @@ int tipc_link_xmit2(struct sk_buff *buf, u32 dnode, u32 selector) tipc_node_lock(node); link = node->active_links[selector & 1]; if (link) - rc = __tipc_link_xmit2(link, buf); + rc = __tipc_link_xmit(link, buf); tipc_node_unlock(node); } @@ -836,7 +836,7 @@ static void tipc_link_sync_xmit(struct tipc_link *link) msg = buf_msg(buf); tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, link->addr); msg_set_last_bcast(msg, link->owner->bclink.acked); - __tipc_link_xmit2(link, buf); + __tipc_link_xmit(link, buf); } /* @@ -1683,7 +1683,7 @@ static void tipc_link_tunnel_xmit(struct tipc_link *l_ptr, } skb_copy_to_linear_data(buf, tunnel_hdr, INT_H_SIZE); skb_copy_to_linear_data_offset(buf, INT_H_SIZE, msg, length); - __tipc_link_xmit2(tunnel, buf); + __tipc_link_xmit(tunnel, buf); } @@ -1716,7 +1716,7 @@ void tipc_link_failover_send_queue(struct tipc_link *l_ptr) if (buf) { skb_copy_to_linear_data(buf, &tunnel_hdr, INT_H_SIZE); msg_set_size(&tunnel_hdr, INT_H_SIZE); - __tipc_link_xmit2(tunnel, buf); + __tipc_link_xmit(tunnel, buf); } else { pr_warn("%sunable to send changeover msg\n", link_co_err); @@ -1789,7 +1789,7 @@ void tipc_link_dup_queue_xmit(struct tipc_link *l_ptr, skb_copy_to_linear_data(outbuf, &tunnel_hdr, INT_H_SIZE); skb_copy_to_linear_data_offset(outbuf, INT_H_SIZE, iter->data, length); - __tipc_link_xmit2(tunnel, outbuf); + __tipc_link_xmit(tunnel, outbuf); if (!tipc_link_is_up(l_ptr)) return; iter = iter->next; diff --git a/net/tipc/link.h b/net/tipc/link.h index f0ebeb677a8b..782983ccd323 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -226,8 +226,8 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, void tipc_link_reset_all(struct tipc_node *node); void tipc_link_reset(struct tipc_link *l_ptr); void tipc_link_reset_list(unsigned int bearer_id); -int tipc_link_xmit2(struct sk_buff *buf, u32 dest, u32 selector); -int __tipc_link_xmit2(struct tipc_link *link, struct sk_buff *buf); +int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector); +int __tipc_link_xmit(struct tipc_link *link, struct sk_buff *buf); u32 tipc_link_get_max_pkt(u32 dest, u32 selector); void tipc_link_bundle_rcv(struct sk_buff *buf); void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob, diff --git a/net/tipc/msg.c b/net/tipc/msg.c index e3102ea494d4..b6f45d029933 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -120,7 +120,7 @@ out_free: /** - * tipc_msg_build2 - create buffer chain containing specified header and data + * tipc_msg_build - create buffer chain containing specified header and data * @mhdr: Message header, to be prepended to data * @iov: User data * @offset: Posision in iov to start copying from @@ -129,8 +129,8 @@ out_free: * @chain: Buffer or chain of buffers to be returned to caller * Returns message data size or errno: -ENOMEM, -EFAULT */ -int tipc_msg_build2(struct tipc_msg *mhdr, struct iovec const *iov, - int offset, int dsz, int pktmax , struct sk_buff **chain) +int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, + int offset, int dsz, int pktmax , struct sk_buff **chain) { int mhsz = msg_hdr_sz(mhdr); int msz = mhsz + dsz; diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 868fe22e3452..462fa194a6af 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -738,8 +738,8 @@ bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu); bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode); -int tipc_msg_build2(struct tipc_msg *mhdr, struct iovec const *iov, - int offset, int dsz, int mtu , struct sk_buff **chain); +int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, + int offset, int dsz, int mtu , struct sk_buff **chain); struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain); diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index d16f9475fa76..dcc15bcd5692 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -116,7 +116,7 @@ void named_cluster_distribute(struct sk_buff *buf) if (!obuf) break; msg_set_destnode(buf_msg(obuf), dnode); - tipc_link_xmit2(obuf, dnode, dnode); + tipc_link_xmit(obuf, dnode, dnode); } rcu_read_unlock(); @@ -232,7 +232,7 @@ void tipc_named_node_up(u32 dnode) /* Convert circular list to linear list and send: */ buf_chain = (struct sk_buff *)msg_list.next; ((struct sk_buff *)msg_list.prev)->next = NULL; - tipc_link_xmit2(buf_chain, dnode, dnode); + tipc_link_xmit(buf_chain, dnode, dnode); } /** diff --git a/net/tipc/port.c b/net/tipc/port.c index 835dca1fd7ad..7e096a5e7701 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -130,7 +130,7 @@ void tipc_port_destroy(struct tipc_port *p_ptr) tipc_nodesub_unsubscribe(&p_ptr->subscription); msg = buf_msg(buf); peer = msg_destnode(msg); - tipc_link_xmit2(buf, peer, msg_link_selector(msg)); + tipc_link_xmit(buf, peer, msg_link_selector(msg)); } spin_lock_bh(&tipc_port_list_lock); list_del(&p_ptr->port_list); @@ -187,7 +187,7 @@ static void port_timeout(unsigned long ref) } tipc_port_unlock(p_ptr); msg = buf_msg(buf); - tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg)); + tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); } @@ -202,7 +202,7 @@ static void port_handle_node_down(unsigned long ref) buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE); tipc_port_unlock(p_ptr); msg = buf_msg(buf); - tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg)); + tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); } @@ -347,7 +347,7 @@ void tipc_acknowledge(u32 ref, u32 ack) if (!buf) return; msg = buf_msg(buf); - tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg)); + tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); } int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, @@ -509,6 +509,6 @@ int tipc_port_shutdown(u32 ref) buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN); tipc_port_unlock(p_ptr); msg = buf_msg(buf); - tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg)); + tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); return tipc_port_disconnect(ref); } diff --git a/net/tipc/socket.c b/net/tipc/socket.c index b28eea50c7fc..5ad42f6137d8 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -131,7 +131,7 @@ static void reject_rx_queue(struct sock *sk) while ((buf = __skb_dequeue(&sk->sk_receive_queue))) { if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT)) - tipc_link_xmit2(buf, dnode, 0); + tipc_link_xmit(buf, dnode, 0); } } @@ -341,7 +341,7 @@ static int tipc_release(struct socket *sock) tipc_port_disconnect(port->ref); } if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT)) - tipc_link_xmit2(buf, dnode, 0); + tipc_link_xmit(buf, dnode, 0); } } @@ -566,7 +566,7 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq, new_mtu: mtu = tipc_bclink_get_mtu(); - rc = tipc_msg_build2(mhdr, iov, 0, dsz, mtu, &buf); + rc = tipc_msg_build(mhdr, iov, 0, dsz, mtu, &buf); if (unlikely(rc < 0)) return rc; @@ -821,12 +821,12 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, new_mtu: mtu = tipc_node_get_mtu(dnode, tsk->port.ref); - rc = tipc_msg_build2(mhdr, iov, 0, dsz, mtu, &buf); + rc = tipc_msg_build(mhdr, iov, 0, dsz, mtu, &buf); if (rc < 0) goto exit; do { - rc = tipc_link_xmit2(buf, dnode, tsk->port.ref); + rc = tipc_link_xmit(buf, dnode, tsk->port.ref); if (likely(rc >= 0)) { if (sock->state != SS_READY) sock->state = SS_CONNECTING; @@ -934,12 +934,12 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, next: mtu = port->max_pkt; send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE); - rc = tipc_msg_build2(mhdr, m->msg_iov, sent, send, mtu, &buf); + rc = tipc_msg_build(mhdr, m->msg_iov, sent, send, mtu, &buf); if (unlikely(rc < 0)) goto exit; do { if (likely(!tipc_sk_conn_cong(tsk))) { - rc = tipc_link_xmit2(buf, dnode, ref); + rc = tipc_link_xmit(buf, dnode, ref); if (likely(!rc)) { tsk->sent_unacked++; sent += send; @@ -1571,7 +1571,7 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf) if ((rc < 0) && !tipc_msg_reverse(buf, &onode, -rc)) return 0; - tipc_link_xmit2(buf, onode, 0); + tipc_link_xmit(buf, onode, 0); return 0; } @@ -1623,7 +1623,7 @@ exit: if ((rc < 0) && !tipc_msg_reverse(buf, &dnode, -rc)) return -EHOSTUNREACH; - tipc_link_xmit2(buf, dnode, 0); + tipc_link_xmit(buf, dnode, 0); return (rc < 0) ? -EHOSTUNREACH : 0; } @@ -1910,7 +1910,7 @@ restart: } tipc_port_disconnect(port->ref); if (tipc_msg_reverse(buf, &peer, TIPC_CONN_SHUTDOWN)) - tipc_link_xmit2(buf, peer, 0); + tipc_link_xmit(buf, peer, 0); } else { tipc_port_shutdown(port->ref); } -- cgit v1.2.3 From 6f92ee54b316c116e125a6bb268abe308e4c14e6 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 16 Jul 2014 20:41:04 -0400 Subject: tipc: ensure sequential message delivery across dual bearers When we run broadcast packets over dual bearers/interfaces, the current transmission code is flipping bearers between each sent packet, with the purpose of leveraging the double bandwidth available. The receiving bclink is resequencing the packets if needed, so all messages are delivered upwards from the broadcast link in the correct order, even if they may arrive in concurrent interrupts. However, at the moment of delivery upwards to the socket, we release all spinlocks (bclink_lock, node_lock), so it is still possible that arriving messages bypass each other before they reach the socket queue. We fix this by applying the same technique we are using for unicast traffic. We use a link selector (i.e., the last bit of sending port number) to ensure that messages from the same sender socket always are sent over the same bearer. This guarantees sequential delivery between socket pairs, which is sufficient to satisfy the protocol spec, as well as all known user requirements. Signed-off-by: Jon Maloy Reviewed-by: Erik Hugne Reviewed-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/bcast.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index d890d480ae3b..dd13bfa09333 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -637,6 +637,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, struct tipc_media_addr *unused2) { int bp_index; + struct tipc_msg *msg = buf_msg(buf); /* Prepare broadcast link message for reliable transmission, * if first time trying to send it; @@ -644,10 +645,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, * since they are sent in an unreliable manner and don't need it */ if (likely(!msg_non_seq(buf_msg(buf)))) { - struct tipc_msg *msg; - bcbuf_set_acks(buf, bclink->bcast_nodes.count); - msg = buf_msg(buf); msg_set_non_seq(msg, 1); msg_set_mc_netid(msg, tipc_net_id); bcl->stats.sent_info++; @@ -664,12 +662,14 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) { struct tipc_bearer *p = bcbearer->bpairs[bp_index].primary; struct tipc_bearer *s = bcbearer->bpairs[bp_index].secondary; - struct tipc_bearer *b = p; + struct tipc_bearer *bp[2] = {p, s}; + struct tipc_bearer *b = bp[msg_link_selector(msg)]; struct sk_buff *tbuf; if (!p) break; /* No more bearers to try */ - + if (!b) + b = p; tipc_nmap_diff(&bcbearer->remains, &b->nodes, &bcbearer->remains_new); if (bcbearer->remains_new.count == bcbearer->remains.count) @@ -686,13 +686,6 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, tipc_bearer_send(b->identity, tbuf, &b->bcast_addr); kfree_skb(tbuf); /* Bearer keeps a clone */ } - - /* Swap bearers for next packet */ - if (s) { - bcbearer->bpairs[bp_index].primary = s; - bcbearer->bpairs[bp_index].secondary = p; - } - if (bcbearer->remains_new.count == 0) break; /* All targets reached */ -- cgit v1.2.3 From a40e0a664bce465a3b8ad1d792153cef8ded9f7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Tue, 15 Jul 2014 23:55:35 +0200 Subject: net: remove open-coded skb_cow_head. Signed-off-by: Francois Romieu Signed-off-by: David S. Miller --- net/core/dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 138ab897de7d..239722af098d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2421,8 +2421,8 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb, skb_warn_bad_offload(skb); - if (skb_header_cloned(skb) && - (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) + err = skb_cow_head(skb, 0); + if (err < 0) return ERR_PTR(err); } -- cgit v1.2.3 From c8a89c4a1d58230192cf7243520bf7f9899239f4 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 15 Jul 2014 15:15:20 -0700 Subject: rtnetlink: Drop unnecessary return value from ndo_dflt_fdb_del This change cleans up ndo_dflt_fdb_del to drop the ENOTSUPP return value since that isn't actually returned anywhere in the code. As a result we are able to drop a few lines by just defaulting this to -EINVAL. Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e9918020dbc9..8d39071f32d7 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2392,22 +2392,20 @@ int ndo_dflt_fdb_del(struct ndmsg *ndm, struct net_device *dev, const unsigned char *addr) { - int err = -EOPNOTSUPP; + int err = -EINVAL; /* If aging addresses are supported device will need to * implement its own handler for this. */ if (!(ndm->ndm_state & NUD_PERMANENT)) { pr_info("%s: FDB only supports static addresses\n", dev->name); - return -EINVAL; + return err; } if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) err = dev_uc_del(dev, addr); else if (is_multicast_ether_addr(addr)) err = dev_mc_del(dev, addr); - else - err = -EINVAL; return err; } -- cgit v1.2.3 From 498044bb2ba39a6fb12c26298c697d5cd9b7378e Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 16 Jul 2014 10:59:47 +0530 Subject: netlink: remove bool varible This patch removes the bool variable 'pass'. If the swith case exist return true or return false. Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 837ff9a57503..1b38f7fe12f1 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -170,7 +170,6 @@ EXPORT_SYMBOL_GPL(netlink_remove_tap); static bool netlink_filter_tap(const struct sk_buff *skb) { struct sock *sk = skb->sk; - bool pass = false; /* We take the more conservative approach and * whitelist socket protocols that may pass. @@ -184,11 +183,10 @@ static bool netlink_filter_tap(const struct sk_buff *skb) case NETLINK_FIB_LOOKUP: case NETLINK_NETFILTER: case NETLINK_GENERIC: - pass = true; - break; + return true; } - return pass; + return false; } static int __netlink_deliver_tap_skb(struct sk_buff *skb, -- cgit v1.2.3 From 0d7869acb2f30b64e4fb782b5df309e2287c2e1f Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Wed, 16 Jul 2014 11:57:47 +0300 Subject: net/mlx4_core: Fix leakage of SW multicast entries When removing multicast address in B0 steering mode there is a bug in cases where there is a single QP registered for the address, and this QP is also promiscuous. In such cases the entry wouldn't be deleted from the SW structure representing all Ethernet MCG entries, but would be removed in HW. This way when driver goes to remove it from SW and HW structures the HW deletion fails. Moreover the same index could later be used for registering different address, which can be Infiniband. Signed-off-by: Yevgeny Petrilin Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/mcg.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index 4c36def8e10f..14a407193478 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -363,8 +363,20 @@ static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, ret = true; list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { if (entry->index == index) { - if (list_empty(&entry->duplicates)) { + if (list_empty(&entry->duplicates) || + members_count == 1) { + struct mlx4_promisc_qp *pqp, *tmp_pqp; + /* If there is only 1 entry in duplicates then + * this is the QP we want to delete, going over + * the list and deleting the entry. + */ list_del(&entry->list); + list_for_each_entry_safe(pqp, tmp_pqp, + &entry->duplicates, + list) { + list_del(&pqp->list); + kfree(pqp); + } kfree(entry); } else { /* This entry contains duplicates so it shouldn't be removed */ -- cgit v1.2.3 From aab2bb0e290bc4f99992cb2198c40eb645647548 Mon Sep 17 00:00:00 2001 From: Dotan Barak Date: Wed, 16 Jul 2014 11:57:48 +0300 Subject: net/mlx4_core: Make sure that negative array index isn't used To make sure that the array index isn't used in the code with negative value, we stop using the for loop integer iterator outside of it. >From now on use members count to swap the last QP with removed one. Fix also the second occurrence of this flow in mlx4_qp_detach_common(). In mlx4_qp_detach_common() use members_count instead of loop iterator outside of the for loop. Signed-off-by: Dotan Barak Reviewed-by: Yevgeny Petrilin Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/mcg.c | 38 ++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index 14a407193478..04a8636a0b7e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -513,7 +513,7 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port, u32 members_count; bool found; bool back_to_list = false; - int loc, i; + int i; int err; if (port < 1 || port > dev->caps.num_ports) @@ -565,18 +565,30 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port, list_del(&dqp->list); kfree(dqp); } else { + int loc = -1; err = mlx4_READ_ENTRY(dev, entry->index, mailbox); if (err) goto out_mailbox; members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - for (loc = -1, i = 0; i < members_count; ++i) - if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) + for (i = 0; i < members_count; ++i) + if ((be32_to_cpu(mgm->qp[i]) & + MGM_QPN_MASK) == qpn) { loc = i; + break; + } + + if (loc < 0) { + mlx4_err(dev, "QP %06x wasn't found in entry %d\n", + qpn, entry->index); + err = -EINVAL; + goto out_mailbox; + } + /* copy the last QP in this MGM over removed QP */ + mgm->qp[loc] = mgm->qp[members_count - 1]; + mgm->qp[members_count - 1] = 0; mgm->members_count = cpu_to_be32(--members_count | (MLX4_PROT_ETH << 30)); - mgm->qp[loc] = mgm->qp[i - 1]; - mgm->qp[i - 1] = 0; err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); if (err) @@ -1074,7 +1086,7 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], struct mlx4_mgm *mgm; u32 members_count; int prev, index; - int i, loc; + int i, loc = -1; int err; u8 port = gid[5]; bool removed_entry = false; @@ -1103,9 +1115,11 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], goto out; members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - for (loc = -1, i = 0; i < members_count; ++i) - if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) + for (i = 0; i < members_count; ++i) + if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { loc = i; + break; + } if (loc == -1) { mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn); @@ -1113,15 +1127,15 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], goto out; } - + /* copy the last QP in this MGM over removed QP */ + mgm->qp[loc] = mgm->qp[members_count - 1]; + mgm->qp[members_count - 1] = 0; mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30); - mgm->qp[loc] = mgm->qp[i - 1]; - mgm->qp[i - 1] = 0; if (prot == MLX4_PROT_ETH) removed_entry = can_remove_steering_entry(dev, port, steer, index, qp->qpn); - if (i != 1 && (prot != MLX4_PROT_ETH || !removed_entry)) { + if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) { err = mlx4_WRITE_ENTRY(dev, index, mailbox); goto out; } -- cgit v1.2.3 From 75908376038c44ea154e4c2782ee367e679c81b1 Mon Sep 17 00:00:00 2001 From: Alexander Guller Date: Wed, 16 Jul 2014 11:57:49 +0300 Subject: net/mlx4_core: Make sure the max number of QPs per MCG isn't exceeded In B0 steering mode when adding QPs to the default MCG entry need to check that maximal number of QPs per MCG entry was not exceeded. Signed-off-by: Alexander Guller Reviewed-by: Aviad Yehezkel Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/mcg.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index 04a8636a0b7e..39ab85a56c9a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -477,8 +477,14 @@ static int add_promisc_qp(struct mlx4_dev *dev, u8 port, /* now need to add all the promisc qps to default entry */ memset(mgm, 0, sizeof *mgm); members_count = 0; - list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) + list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) { + if (members_count == dev->caps.num_qp_per_mgm) { + /* entry is full */ + err = -ENOMEM; + goto out_list; + } mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); + } mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); -- cgit v1.2.3 From 816e59846bb683e8d5c91e35df5f8fabac20494f Mon Sep 17 00:00:00 2001 From: Eugenia Emantayev Date: Wed, 16 Jul 2014 11:57:50 +0300 Subject: net/mlx4_core: In SR-IOV mode host should add promisc QP to default entry only In current situation host is adding the promiscuous QP to all steering entries and the default entry as well. In this case when having PV and SR-IOV on the same setup bridge will receive all traffic that is targeted to the other VMs. This is bad. Solution: In SR-IOV mode host can add promiscuous QP to default entry only. The above problem and fix are relevant for B0 steering mode only. Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/mcg.c | 169 ++++++++++++++++++------------- 1 file changed, 99 insertions(+), 70 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index 39ab85a56c9a..9d92bc22b9e5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -433,43 +433,58 @@ static int add_promisc_qp(struct mlx4_dev *dev, u8 port, } mgm = mailbox->buf; - /* the promisc qp needs to be added for each one of the steering - * entries, if it already exists, needs to be added as a duplicate - * for this entry */ - list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { - err = mlx4_READ_ENTRY(dev, entry->index, mailbox); - if (err) - goto out_mailbox; + if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { + /* The promisc QP needs to be added for each one of the steering + * entries. If it already exists, needs to be added as + * a duplicate for this entry. + */ + list_for_each_entry(entry, + &s_steer->steer_entries[steer], + list) { + err = mlx4_READ_ENTRY(dev, entry->index, mailbox); + if (err) + goto out_mailbox; - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - prot = be32_to_cpu(mgm->members_count) >> 30; - found = false; - for (i = 0; i < members_count; i++) { - if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { - /* Entry already exists, add to duplicates */ - dqp = kmalloc(sizeof *dqp, GFP_KERNEL); - if (!dqp) { + members_count = be32_to_cpu(mgm->members_count) & + 0xffffff; + prot = be32_to_cpu(mgm->members_count) >> 30; + found = false; + for (i = 0; i < members_count; i++) { + if ((be32_to_cpu(mgm->qp[i]) & + MGM_QPN_MASK) == qpn) { + /* Entry already exists. + * Add to duplicates. + */ + dqp = kmalloc(sizeof(*dqp), GFP_KERNEL); + if (!dqp) { + err = -ENOMEM; + goto out_mailbox; + } + dqp->qpn = qpn; + list_add_tail(&dqp->list, + &entry->duplicates); + found = true; + } + } + if (!found) { + /* Need to add the qpn to mgm */ + if (members_count == + dev->caps.num_qp_per_mgm) { + /* entry is full */ err = -ENOMEM; goto out_mailbox; } - dqp->qpn = qpn; - list_add_tail(&dqp->list, &entry->duplicates); - found = true; + mgm->qp[members_count++] = + cpu_to_be32(qpn & MGM_QPN_MASK); + mgm->members_count = + cpu_to_be32(members_count | + (prot << 30)); + err = mlx4_WRITE_ENTRY(dev, entry->index, + mailbox); + if (err) + goto out_mailbox; } } - if (!found) { - /* Need to add the qpn to mgm */ - if (members_count == dev->caps.num_qp_per_mgm) { - /* entry is full */ - err = -ENOMEM; - goto out_mailbox; - } - mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK); - mgm->members_count = cpu_to_be32(members_count | (prot << 30)); - err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); - if (err) - goto out_mailbox; - } } /* add the new qpn to list of promisc qps */ @@ -556,51 +571,65 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port, if (err) goto out_mailbox; - /* remove the qp from all the steering entries*/ - list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { - found = false; - list_for_each_entry(dqp, &entry->duplicates, list) { - if (dqp->qpn == qpn) { - found = true; - break; + if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { + /* remove the qp from all the steering entries*/ + list_for_each_entry(entry, + &s_steer->steer_entries[steer], + list) { + found = false; + list_for_each_entry(dqp, &entry->duplicates, list) { + if (dqp->qpn == qpn) { + found = true; + break; + } } - } - if (found) { - /* a duplicate, no need to change the mgm, - * only update the duplicates list */ - list_del(&dqp->list); - kfree(dqp); - } else { - int loc = -1; - err = mlx4_READ_ENTRY(dev, entry->index, mailbox); - if (err) + if (found) { + /* A duplicate, no need to change the MGM, + * only update the duplicates list + */ + list_del(&dqp->list); + kfree(dqp); + } else { + int loc = -1; + + err = mlx4_READ_ENTRY(dev, + entry->index, + mailbox); + if (err) + goto out_mailbox; + members_count = + be32_to_cpu(mgm->members_count) & + 0xffffff; + for (i = 0; i < members_count; ++i) + if ((be32_to_cpu(mgm->qp[i]) & + MGM_QPN_MASK) == qpn) { + loc = i; + break; + } + + if (loc < 0) { + mlx4_err(dev, "QP %06x wasn't found in entry %d\n", + qpn, entry->index); + err = -EINVAL; goto out_mailbox; - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - for (i = 0; i < members_count; ++i) - if ((be32_to_cpu(mgm->qp[i]) & - MGM_QPN_MASK) == qpn) { - loc = i; - break; } - if (loc < 0) { - mlx4_err(dev, "QP %06x wasn't found in entry %d\n", - qpn, entry->index); - err = -EINVAL; - goto out_mailbox; + /* copy the last QP in this MGM + * over removed QP + */ + mgm->qp[loc] = mgm->qp[members_count - 1]; + mgm->qp[members_count - 1] = 0; + mgm->members_count = + cpu_to_be32(--members_count | + (MLX4_PROT_ETH << 30)); + + err = mlx4_WRITE_ENTRY(dev, + entry->index, + mailbox); + if (err) + goto out_mailbox; } - - /* copy the last QP in this MGM over removed QP */ - mgm->qp[loc] = mgm->qp[members_count - 1]; - mgm->qp[members_count - 1] = 0; - mgm->members_count = cpu_to_be32(--members_count | - (MLX4_PROT_ETH << 30)); - - err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); - if (err) - goto out_mailbox; } - } out_mailbox: -- cgit v1.2.3 From 1645a54082ec8bf3fc0147c6d1ced273549ac1a2 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Wed, 16 Jul 2014 11:57:51 +0300 Subject: net/mlx4_core: Remove MCG in case it is attached to promiscuous QPs only In B0 steering mode if promiscuous QP asks to be detached from MCG entry, and it is the only one in this entry then the entry will never be deleted. This is a wrong behavior since we don't want to keep those entries after the promiscuous QP becomes non-promiscuous. Therefore remove steering entry containing only promiscuous QP. Signed-off-by: Saeed Mahameed Signed-off-by: Eugenia Emantayev Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/mcg.c | 88 ++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index 9d92bc22b9e5..d80e7a6fac74 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -270,7 +270,7 @@ static int existing_steering_entry(struct mlx4_dev *dev, u8 port, * we need to add it as a duplicate to this entry * for future references */ list_for_each_entry(dqp, &entry->duplicates, list) { - if (qpn == pqp->qpn) + if (qpn == dqp->qpn) return 0; /* qp is already duplicated */ } @@ -324,24 +324,22 @@ static bool check_duplicate_entry(struct mlx4_dev *dev, u8 port, return true; } -/* I a steering entry contains only promisc QPs, it can be removed. */ -static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, - enum mlx4_steer_type steer, - unsigned int index, u32 tqpn) +/* Returns true if all the QPs != tqpn contained in this entry + * are Promisc QPs. Returns false otherwise. + */ +static bool promisc_steering_entry(struct mlx4_dev *dev, u8 port, + enum mlx4_steer_type steer, + unsigned int index, u32 tqpn, + u32 *members_count) { - struct mlx4_steer *s_steer; struct mlx4_cmd_mailbox *mailbox; struct mlx4_mgm *mgm; - struct mlx4_steer_index *entry = NULL, *tmp_entry; - u32 qpn; - u32 members_count; + u32 m_count; bool ret = false; int i; if (port < 1 || port > dev->caps.num_ports) - return NULL; - - s_steer = &mlx4_priv(dev)->steer[port - 1]; + return false; mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) @@ -350,15 +348,43 @@ static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, if (mlx4_READ_ENTRY(dev, index, mailbox)) goto out; - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; - for (i = 0; i < members_count; i++) { - qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; + m_count = be32_to_cpu(mgm->members_count) & 0xffffff; + if (members_count) + *members_count = m_count; + + for (i = 0; i < m_count; i++) { + u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) { /* the qp is not promisc, the entry can't be removed */ goto out; } } - /* All the qps currently registered for this entry are promiscuous, + ret = true; +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return ret; +} + +/* IF a steering entry contains only promisc QPs, it can be removed. */ +static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, + enum mlx4_steer_type steer, + unsigned int index, u32 tqpn) +{ + struct mlx4_steer *s_steer; + struct mlx4_steer_index *entry = NULL, *tmp_entry; + u32 members_count; + bool ret = false; + + if (port < 1 || port > dev->caps.num_ports) + return NULL; + + s_steer = &mlx4_priv(dev)->steer[port - 1]; + + if (!promisc_steering_entry(dev, port, steer, index, + tqpn, &members_count)) + goto out; + + /* All the qps currently registered for this entry are promiscuous, * Checking for duplicates */ ret = true; list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { @@ -387,7 +413,6 @@ static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, } out: - mlx4_free_cmd_mailbox(dev, mailbox); return ret; } @@ -528,7 +553,7 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port, struct mlx4_steer *s_steer; struct mlx4_cmd_mailbox *mailbox; struct mlx4_mgm *mgm; - struct mlx4_steer_index *entry; + struct mlx4_steer_index *entry, *tmp_entry; struct mlx4_promisc_qp *pqp; struct mlx4_promisc_qp *dqp; u32 members_count; @@ -572,10 +597,10 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port, goto out_mailbox; if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) { - /* remove the qp from all the steering entries*/ - list_for_each_entry(entry, - &s_steer->steer_entries[steer], - list) { + /* Remove the QP from all the steering entries */ + list_for_each_entry_safe(entry, tmp_entry, + &s_steer->steer_entries[steer], + list) { found = false; list_for_each_entry(dqp, &entry->duplicates, list) { if (dqp->qpn == qpn) { @@ -600,6 +625,14 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port, members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + if (!members_count) { + mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0. deleting entry...\n", + qpn, entry->index); + list_del(&entry->list); + kfree(entry); + continue; + } + for (i = 0; i < members_count; ++i) if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { @@ -614,7 +647,7 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port, goto out_mailbox; } - /* copy the last QP in this MGM + /* Copy the last QP in this MGM * over removed QP */ mgm->qp[loc] = mgm->qp[members_count - 1]; @@ -1144,10 +1177,13 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], goto out; } - /* if this pq is also a promisc qp, it shouldn't be removed */ + /* If this QP is also a promisc QP, it shouldn't be removed only if + * at least one none promisc QP is also attached to this MCG + */ if (prot == MLX4_PROT_ETH && - check_duplicate_entry(dev, port, steer, index, qp->qpn)) - goto out; + check_duplicate_entry(dev, port, steer, index, qp->qpn) && + !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL)) + goto out; members_count = be32_to_cpu(mgm->members_count) & 0xffffff; for (i = 0; i < members_count; ++i) -- cgit v1.2.3 From 5cf3d46192fccf68b4a4759e4d7346e41c669a76 Mon Sep 17 00:00:00 2001 From: David Held Date: Tue, 15 Jul 2014 23:28:31 -0400 Subject: udp: Simplify __udp*_lib_mcast_deliver. Switch to using sk_nulls_for_each which shortens the code and makes it easier to update. Signed-off-by: David Held Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/udp.c | 48 ++++++++++---------------------- net/ipv6/udp.c | 88 +++++++++++++++++++++++----------------------------------- 2 files changed, 49 insertions(+), 87 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 668af516f094..bbcc33737ef1 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -594,26 +594,6 @@ static inline bool __udp_is_mcast_sock(struct net *net, struct sock *sk, return true; } -static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk, - __be16 loc_port, __be32 loc_addr, - __be16 rmt_port, __be32 rmt_addr, - int dif) -{ - struct hlist_nulls_node *node; - unsigned short hnum = ntohs(loc_port); - - sk_nulls_for_each_from(sk, node) { - if (__udp_is_mcast_sock(net, sk, - loc_port, loc_addr, - rmt_port, rmt_addr, - dif, hnum)) - goto found; - } - sk = NULL; -found: - return sk; -} - /* * This routine is called by the ICMP module when it gets some * sort of error condition. If err < 0 then the socket should @@ -1667,23 +1647,23 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, struct udp_table *udptable) { struct sock *sk, *stack[256 / sizeof(struct sock *)]; - struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest)); - int dif; + struct hlist_nulls_node *node; + unsigned short hnum = ntohs(uh->dest); + struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum); + int dif = skb->dev->ifindex; unsigned int i, count = 0; spin_lock(&hslot->lock); - sk = sk_nulls_head(&hslot->head); - dif = skb->dev->ifindex; - sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); - while (sk) { - stack[count++] = sk; - sk = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest, - daddr, uh->source, saddr, dif); - if (unlikely(count == ARRAY_SIZE(stack))) { - if (!sk) - break; - flush_stack(stack, count, skb, ~0); - count = 0; + sk_nulls_for_each(sk, node, &hslot->head) { + if (__udp_is_mcast_sock(net, sk, + uh->dest, daddr, + uh->source, saddr, + dif, hnum)) { + if (unlikely(count == ARRAY_SIZE(stack))) { + flush_stack(stack, count, skb, ~0); + count = 0; + } + stack[count++] = sk; } } /* diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index b4481df3d5fa..7d3bd80085be 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -702,43 +702,26 @@ drop: return -1; } -static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, - __be16 loc_port, const struct in6_addr *loc_addr, - __be16 rmt_port, const struct in6_addr *rmt_addr, - int dif) +static bool __udp_v6_is_mcast_sock(struct net *net, struct sock *sk, + __be16 loc_port, const struct in6_addr *loc_addr, + __be16 rmt_port, const struct in6_addr *rmt_addr, + int dif, unsigned short hnum) { - struct hlist_nulls_node *node; - unsigned short num = ntohs(loc_port); - - sk_nulls_for_each_from(sk, node) { - struct inet_sock *inet = inet_sk(sk); - - if (!net_eq(sock_net(sk), net)) - continue; - - if (udp_sk(sk)->udp_port_hash == num && - sk->sk_family == PF_INET6) { - if (inet->inet_dport) { - if (inet->inet_dport != rmt_port) - continue; - } - if (!ipv6_addr_any(&sk->sk_v6_daddr) && - !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) - continue; - - if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) - continue; + struct inet_sock *inet = inet_sk(sk); - if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { - if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr)) - continue; - } - if (!inet6_mc_check(sk, loc_addr, rmt_addr)) - continue; - return sk; - } - } - return NULL; + if (!net_eq(sock_net(sk), net)) + return false; + + if (udp_sk(sk)->udp_port_hash != hnum || + sk->sk_family != PF_INET6 || + (inet->inet_dport && inet->inet_dport != rmt_port) || + (!ipv6_addr_any(&sk->sk_v6_daddr) && + !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) || + (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) + return false; + if (!inet6_mc_check(sk, loc_addr, rmt_addr)) + return false; + return true; } static void flush_stack(struct sock **stack, unsigned int count, @@ -787,28 +770,27 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, { struct sock *sk, *stack[256 / sizeof(struct sock *)]; const struct udphdr *uh = udp_hdr(skb); - struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest)); - int dif; + struct hlist_nulls_node *node; + unsigned short hnum = ntohs(uh->dest); + struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum); + int dif = inet6_iif(skb); unsigned int i, count = 0; spin_lock(&hslot->lock); - sk = sk_nulls_head(&hslot->head); - dif = inet6_iif(skb); - sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); - while (sk) { - /* If zero checksum and no_check is not on for - * the socket then skip it. - */ - if (uh->check || udp_sk(sk)->no_check6_rx) + sk_nulls_for_each(sk, node, &hslot->head) { + if (__udp_v6_is_mcast_sock(net, sk, + uh->dest, daddr, + uh->source, saddr, + dif, hnum) && + /* If zero checksum and no_check is not on for + * the socket then skip it. + */ + (uh->check || udp_sk(sk)->no_check6_rx)) { + if (unlikely(count == ARRAY_SIZE(stack))) { + flush_stack(stack, count, skb, ~0); + count = 0; + } stack[count++] = sk; - - sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr, - uh->source, saddr, dif); - if (unlikely(count == ARRAY_SIZE(stack))) { - if (!sk) - break; - flush_stack(stack, count, skb, ~0); - count = 0; } } /* -- cgit v1.2.3 From 2dc41cff7545d55c6294525c811594576f8e119c Mon Sep 17 00:00:00 2001 From: David Held Date: Tue, 15 Jul 2014 23:28:32 -0400 Subject: udp: Use hash2 for long hash1 chains in __udp*_lib_mcast_deliver. Many multicast sources can have the same port which can result in a very large list when hashing by port only. Hash by address and port instead if this is the case. This makes multicast more similar to unicast. On a 24-core machine receiving from 500 multicast sockets on the same port, before this patch 80% of system CPU was used up by spin locking and only ~25% of packets were successfully delivered. With this patch, all packets are delivered and kernel overhead is ~8% system CPU on spinlocks. Signed-off-by: David Held Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 14 ++++++++++++++ net/ipv4/udp.c | 31 +++++++++++++++++++++---------- net/ipv6/udp.c | 30 ++++++++++++++++++++---------- 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 29e48a6d1ded..28f734601b50 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -660,6 +660,20 @@ static inline void sk_add_bind_node(struct sock *sk, #define sk_for_each_bound(__sk, list) \ hlist_for_each_entry(__sk, list, sk_bind_node) +/** + * sk_nulls_for_each_entry_offset - iterate over a list at a given struct offset + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @offset: offset of hlist_node within the struct. + * + */ +#define sk_nulls_for_each_entry_offset(tpos, pos, head, offset) \ + for (pos = (head)->first; \ + (!is_a_nulls(pos)) && \ + ({ tpos = (typeof(*tpos) *)((void *)pos - offset); 1;}); \ + pos = pos->next) + static inline struct user_namespace *sk_user_ns(struct sock *sk) { /* Careful only use this in a context where these parameters diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index bbcc33737ef1..f31053b90ee0 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1619,6 +1619,8 @@ static void flush_stack(struct sock **stack, unsigned int count, if (skb1 && udp_queue_rcv_skb(sk, skb1) <= 0) skb1 = NULL; + + sock_put(sk); } if (unlikely(skb1)) kfree_skb(skb1); @@ -1651,10 +1653,20 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, unsigned short hnum = ntohs(uh->dest); struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum); int dif = skb->dev->ifindex; - unsigned int i, count = 0; + unsigned int count = 0, offset = offsetof(typeof(*sk), sk_nulls_node); + unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10); + + if (use_hash2) { + hash2_any = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum) & + udp_table.mask; + hash2 = udp4_portaddr_hash(net, daddr, hnum) & udp_table.mask; +start_lookup: + hslot = &udp_table.hash2[hash2]; + offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node); + } spin_lock(&hslot->lock); - sk_nulls_for_each(sk, node, &hslot->head) { + sk_nulls_for_each_entry_offset(sk, node, &hslot->head, offset) { if (__udp_is_mcast_sock(net, sk, uh->dest, daddr, uh->source, saddr, @@ -1664,24 +1676,23 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, count = 0; } stack[count++] = sk; + sock_hold(sk); } } - /* - * before releasing chain lock, we must take a reference on sockets - */ - for (i = 0; i < count; i++) - sock_hold(stack[i]); spin_unlock(&hslot->lock); + /* Also lookup *:port if we are using hash2 and haven't done so yet. */ + if (use_hash2 && hash2 != hash2_any) { + hash2 = hash2_any; + goto start_lookup; + } + /* * do the slow work with no lock held */ if (count) { flush_stack(stack, count, skb, count - 1); - - for (i = 0; i < count; i++) - sock_put(stack[i]); } else { kfree_skb(skb); } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 7d3bd80085be..f9d8800bb72f 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -745,6 +745,7 @@ static void flush_stack(struct sock **stack, unsigned int count, if (skb1 && udpv6_queue_rcv_skb(sk, skb1) <= 0) skb1 = NULL; + sock_put(sk); } if (unlikely(skb1)) kfree_skb(skb1); @@ -774,10 +775,20 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, unsigned short hnum = ntohs(uh->dest); struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum); int dif = inet6_iif(skb); - unsigned int i, count = 0; + unsigned int count = 0, offset = offsetof(typeof(*sk), sk_nulls_node); + unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10); + + if (use_hash2) { + hash2_any = udp6_portaddr_hash(net, &in6addr_any, hnum) & + udp_table.mask; + hash2 = udp6_portaddr_hash(net, daddr, hnum) & udp_table.mask; +start_lookup: + hslot = &udp_table.hash2[hash2]; + offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node); + } spin_lock(&hslot->lock); - sk_nulls_for_each(sk, node, &hslot->head) { + sk_nulls_for_each_entry_offset(sk, node, &hslot->head, offset) { if (__udp_v6_is_mcast_sock(net, sk, uh->dest, daddr, uh->source, saddr, @@ -791,21 +802,20 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, count = 0; } stack[count++] = sk; + sock_hold(sk); } } - /* - * before releasing the lock, we must take reference on sockets - */ - for (i = 0; i < count; i++) - sock_hold(stack[i]); spin_unlock(&hslot->lock); + /* Also lookup *:port if we are using hash2 and haven't done so yet. */ + if (use_hash2 && hash2 != hash2_any) { + hash2 = hash2_any; + goto start_lookup; + } + if (count) { flush_stack(stack, count, skb, count - 1); - - for (i = 0; i < count; i++) - sock_put(stack[i]); } else { kfree_skb(skb); } -- cgit v1.2.3 From 1373a7739e886cda3ed4848293dc9c46bc5d0d6a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 16 Jul 2014 06:55:46 -0400 Subject: net: clean up some sparse endianness warnings in ipv6.h sparse is throwing warnings when building sunrpc modules due to some endianness shenanigans in ipv6.h. Specifically: CHECK net/sunrpc/addr.c include/net/ipv6.h:573:17: warning: restricted __be64 degrades to integer include/net/ipv6.h:577:34: warning: restricted __be32 degrades to integer include/net/ipv6.h:573:17: warning: restricted __be64 degrades to integer include/net/ipv6.h:577:34: warning: restricted __be32 degrades to integer Sprinkle some endianness fixups to silence them. These should all get fixed up at compile time, so I don't think this will add any extra work to be done at runtime. Signed-off-by: Jeff Layton Signed-off-by: David S. Miller --- include/net/ipv6.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index b9ac2357e7db..a25017247457 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -558,24 +558,29 @@ static inline u32 __ipv6_addr_jhash(const struct in6_addr *a, const u32 initval) static inline bool ipv6_addr_loopback(const struct in6_addr *a) { #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - const unsigned long *ul = (const unsigned long *)a; + const __be64 *be = (const __be64 *)a; - return (ul[0] | (ul[1] ^ cpu_to_be64(1))) == 0UL; + return (be[0] | (be[1] ^ cpu_to_be64(1))) == 0UL; #else return (a->s6_addr32[0] | a->s6_addr32[1] | - a->s6_addr32[2] | (a->s6_addr32[3] ^ htonl(1))) == 0; + a->s6_addr32[2] | (a->s6_addr32[3] ^ cpu_to_be32(1))) == 0; #endif } +/* + * Note that we must __force cast these to unsigned long to make sparse happy, + * since all of the endian-annotated types are fixed size regardless of arch. + */ static inline bool ipv6_addr_v4mapped(const struct in6_addr *a) { return ( #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - *(__be64 *)a | + *(unsigned long *)a | #else - (a->s6_addr32[0] | a->s6_addr32[1]) | + (__force unsigned long)(a->s6_addr32[0] | a->s6_addr32[1]) | #endif - (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0UL; + (__force unsigned long)(a->s6_addr32[2] ^ + cpu_to_be32(0x0000ffff))) == 0UL; } /* -- cgit v1.2.3 From f68c9257201ff5d443bf2e815ce01578835674e4 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 16 Jul 2014 15:13:02 +0300 Subject: net: davinci_mdio: reuse for keystone2 arch The similar MDIO HW blocks is used by keystone 2 SoCs as in Davinci SoCs: - one in Gigabit Ethernet (GbE) Switch Subsystem See http://www.ti.com/lit/ug/sprugv9d/sprugv9d.pdf - one in 10 Gigabit Ethernet Subsystem See http://www.ti.com/lit/ug/spruhj5/spruhj5.pdf Hence, reuse Davinci MDIO driver for Keystone 2 and enable TI networking for Keystone 2 devices Reviewed-by: Santosh Shilimkar Acked-by: Mugunthan V N Signed-off-by: Grygorii Strashko Reviewed-by: Lad, Prabhakar Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/davinci-mdio.txt | 8 ++++---- drivers/net/ethernet/ti/Kconfig | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/net/davinci-mdio.txt b/Documentation/devicetree/bindings/net/davinci-mdio.txt index 72efaaf764f7..0369e25aabd2 100644 --- a/Documentation/devicetree/bindings/net/davinci-mdio.txt +++ b/Documentation/devicetree/bindings/net/davinci-mdio.txt @@ -1,8 +1,8 @@ -TI SoC Davinci MDIO Controller Device Tree Bindings +TI SoC Davinci/Keystone2 MDIO Controller Device Tree Bindings --------------------------------------------------- Required properties: -- compatible : Should be "ti,davinci_mdio" +- compatible : Should be "ti,davinci_mdio" or "ti,keystone_mdio" - reg : physical base address and size of the davinci mdio registers map - bus_freq : Mdio Bus frequency @@ -19,7 +19,7 @@ file. Examples: mdio: davinci_mdio@4A101000 { - compatible = "ti,cpsw"; + compatible = "ti,davinci_mdio"; reg = <0x4A101000 0x1000>; bus_freq = <1000000>; }; @@ -27,7 +27,7 @@ Examples: (or) mdio: davinci_mdio@4A101000 { - compatible = "ti,cpsw"; + compatible = "ti,davinci_mdio"; ti,hwmods = "davinci_mdio"; bus_freq = <1000000>; }; diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index 53150c25a96b..1769700a6070 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -5,7 +5,7 @@ config NET_VENDOR_TI bool "Texas Instruments (TI) devices" default y - depends on PCI || EISA || AR7 || (ARM && (ARCH_DAVINCI || ARCH_OMAP3 || SOC_AM33XX)) + depends on PCI || EISA || AR7 || (ARM && (ARCH_DAVINCI || ARCH_OMAP3 || SOC_AM33XX || ARCH_KEYSTONE)) ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from @@ -32,7 +32,7 @@ config TI_DAVINCI_EMAC config TI_DAVINCI_MDIO tristate "TI DaVinci MDIO Support" - depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 || SOC_AM33XX ) + depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 || SOC_AM33XX || ARCH_KEYSTONE ) select PHYLIB ---help--- This driver supports TI's DaVinci MDIO module. -- cgit v1.2.3 From 0a0ea068728138641037daa5fce33cb06724285d Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 16 Jul 2014 15:13:03 +0300 Subject: net: davinci_mdio: allow to create phys from dt This patch allows to create PHYs from DT in case if they are explicitly defined. The of_mdiobus_register() is used for such purposes. For backward compatibility, call of_mdiobus_register() only in case if at least one PHY's child is defined in DT, otherwise rollback to mdiobus_register(). Reviewed-by: Santosh Shilimkar Acked-by: Mugunthan V N Signed-off-by: Grygorii Strashko Reviewed-by: Lad, Prabhakar Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_mdio.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c index 735dc53d4b01..2791f6f2db11 100644 --- a/drivers/net/ethernet/ti/davinci_mdio.c +++ b/drivers/net/ethernet/ti/davinci_mdio.c @@ -38,6 +38,7 @@ #include #include #include +#include #include /* @@ -95,6 +96,10 @@ struct davinci_mdio_data { struct mii_bus *bus; bool suspended; unsigned long access_time; /* jiffies */ + /* Indicates that driver shouldn't modify phy_mask in case + * if MDIO bus is registered from DT. + */ + bool skip_scan; }; static void __davinci_mdio_reset(struct davinci_mdio_data *data) @@ -144,6 +149,9 @@ static int davinci_mdio_reset(struct mii_bus *bus) dev_info(data->dev, "davinci mdio revision %d.%d\n", (ver >> 8) & 0xff, ver & 0xff); + if (data->skip_scan) + return 0; + /* get phy mask from the alive register */ phy_mask = __raw_readl(&data->regs->alive); if (phy_mask) { @@ -369,8 +377,17 @@ static int davinci_mdio_probe(struct platform_device *pdev) goto bail_out; } - /* register the mii bus */ - ret = mdiobus_register(data->bus); + /* register the mii bus + * Create PHYs from DT only in case if PHY child nodes are explicitly + * defined to support backward compatibility with DTs which assume that + * Davinci MDIO will always scan the bus for PHYs detection. + */ + if (dev->of_node && of_get_child_count(dev->of_node)) { + data->skip_scan = true; + ret = of_mdiobus_register(data->bus, dev->of_node); + } else { + ret = mdiobus_register(data->bus); + } if (ret) goto bail_out; -- cgit v1.2.3 From 6b794c1cd8e0e693621e846166f6a25b38bcb862 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Wed, 16 Jul 2014 11:10:36 -0700 Subject: bonding: Do not try to send packets over dead link in TLB mode. In TLB mode if tlb_dynamic_lb is NOT set, slaves from the bond group are selected based on the hash distribution. This does not exclude dead links which are part of the bond. Also if there is a temporary link event which brings down the interface, packets hashed on that interface would be dropped too. This patch fixes these issues and distributes flows across the UP links only. Also the array construction of links which are capable of sending packets happen in the control path leaving only link-selection during the data-path. One possible side effect of this is - at a link event; all flows will be shuffled to get good distribution. But impact of this should be minimum with the assumption that a member or members of the bond group are not available is a very temporary situation. Signed-off-by: Mahesh Bandewar Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.c | 55 ++++++++++++++++++++++++++++++++++++++---- drivers/net/bonding/bond_alb.h | 8 ++++++ drivers/net/bonding/bonding.h | 6 +++++ 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index f16442fa97ff..d3c6801f101e 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -200,6 +200,7 @@ static int tlb_initialize(struct bonding *bond) static void tlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct tlb_up_slave *arr; _lock_tx_hashtbl_bh(bond); @@ -207,6 +208,10 @@ static void tlb_deinitialize(struct bonding *bond) bond_info->tx_hashtbl = NULL; _unlock_tx_hashtbl_bh(bond); + + arr = rtnl_dereference(bond_info->slave_arr); + if (arr) + kfree_rcu(arr, rcu); } static long long compute_gap(struct slave *slave) @@ -1402,9 +1407,39 @@ out: return NETDEV_TX_OK; } +static int bond_tlb_update_slave_arr(struct bonding *bond, + struct slave *skipslave) +{ + struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct slave *tx_slave; + struct list_head *iter; + struct tlb_up_slave *new_arr, *old_arr; + + new_arr = kzalloc(offsetof(struct tlb_up_slave, arr[bond->slave_cnt]), + GFP_ATOMIC); + if (!new_arr) + return -ENOMEM; + + bond_for_each_slave(bond, tx_slave, iter) { + if (!bond_slave_can_tx(tx_slave)) + continue; + if (skipslave == tx_slave) + continue; + new_arr->arr[new_arr->count++] = tx_slave; + } + + old_arr = rtnl_dereference(bond_info->slave_arr); + rcu_assign_pointer(bond_info->slave_arr, new_arr); + if (old_arr) + kfree_rcu(old_arr, rcu); + + return 0; +} + int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); + struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct ethhdr *eth_data; struct slave *tx_slave = NULL; u32 hash_index; @@ -1425,12 +1460,12 @@ int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev) hash_index & 0xFF, skb->len); } else { - struct list_head *iter; - int idx = hash_index % bond->slave_cnt; + struct tlb_up_slave *slaves; - bond_for_each_slave_rcu(bond, tx_slave, iter) - if (--idx < 0) - break; + slaves = rcu_dereference(bond_info->slave_arr); + if (slaves && slaves->count) + tx_slave = slaves->arr[hash_index % + slaves->count]; } break; } @@ -1695,6 +1730,11 @@ void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) bond->alb_info.rx_slave = NULL; rlb_clear_slave(bond, slave); } + + if (bond_is_nondyn_tlb(bond)) + if (bond_tlb_update_slave_arr(bond, slave)) + pr_err("Failed to build slave-array for TLB mode.\n"); + } /* Caller must hold bond lock for read */ @@ -1718,6 +1758,11 @@ void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char */ } } + + if (bond_is_nondyn_tlb(bond)) { + if (bond_tlb_update_slave_arr(bond, NULL)) + pr_err("Failed to build slave-array for TLB mode.\n"); + } } /** diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 5fc76c01636c..aaeac61d03cf 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -139,12 +139,20 @@ struct tlb_slave_info { */ }; +struct tlb_up_slave { + unsigned int count; + struct rcu_head rcu; + struct slave *arr[0]; +}; + struct alb_bond_info { struct tlb_client_info *tx_hashtbl; /* Dynamically allocated */ spinlock_t tx_hashtbl_lock; u32 unbalanced_load; int tx_rebalance_counter; int lp_counter; + /* -------- non-dynamic tlb mode only ---------*/ + struct tlb_up_slave __rcu *slave_arr; /* Up slaves */ /* -------- rlb parameters -------- */ int rlb_enabled; struct rlb_client_info *rx_hashtbl; /* Receive hash table */ diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index b2e548e9d738..a85ca51eabf5 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -269,6 +269,12 @@ static inline bool bond_is_lb(const struct bonding *bond) BOND_MODE(bond) == BOND_MODE_ALB; } +static inline bool bond_is_nondyn_tlb(const struct bonding *bond) +{ + return (BOND_MODE(bond) == BOND_MODE_TLB) && + (bond->params.tlb_dynamic_lb == 0); +} + static inline bool bond_mode_uses_arp(int mode) { return mode != BOND_MODE_8023AD && mode != BOND_MODE_TLB && -- cgit v1.2.3 From 48e48a70c08a8a68f8697f8b30cb83775bda8001 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 16 Jul 2014 11:25:52 -0700 Subject: openvswitch: make generic netlink group const Generic netlink tables can be const. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/openvswitch/datapath.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 493b5141a618..20f59b62721a 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -66,16 +66,16 @@ static struct genl_family dp_packet_genl_family; static struct genl_family dp_flow_genl_family; static struct genl_family dp_datapath_genl_family; -static struct genl_multicast_group ovs_dp_flow_multicast_group = { - .name = OVS_FLOW_MCGROUP +static const struct genl_multicast_group ovs_dp_flow_multicast_group = { + .name = OVS_FLOW_MCGROUP, }; -static struct genl_multicast_group ovs_dp_datapath_multicast_group = { - .name = OVS_DATAPATH_MCGROUP +static const struct genl_multicast_group ovs_dp_datapath_multicast_group = { + .name = OVS_DATAPATH_MCGROUP, }; -struct genl_multicast_group ovs_dp_vport_multicast_group = { - .name = OVS_VPORT_MCGROUP +static const struct genl_multicast_group ovs_dp_vport_multicast_group = { + .name = OVS_VPORT_MCGROUP, }; /* Check if need to build a reply message. @@ -1189,7 +1189,7 @@ static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = { [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, }; -static struct genl_ops dp_flow_genl_ops[] = { +static const struct genl_ops dp_flow_genl_ops[] = { { .cmd = OVS_FLOW_CMD_NEW, .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ .policy = flow_policy, @@ -1577,7 +1577,7 @@ static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = { [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 }, }; -static struct genl_ops dp_datapath_genl_ops[] = { +static const struct genl_ops dp_datapath_genl_ops[] = { { .cmd = OVS_DP_CMD_NEW, .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ .policy = datapath_policy, @@ -1944,7 +1944,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, }; -static struct genl_ops dp_vport_genl_ops[] = { +static const struct genl_ops dp_vport_genl_ops[] = { { .cmd = OVS_VPORT_CMD_NEW, .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ .policy = vport_policy, -- cgit v1.2.3 From 9f743d7499bc2c4dc8c35af33bdb2a29bea663b9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 17 Jul 2014 11:56:33 +0300 Subject: Bluetooth: Fix using uninitialized variable when pairing Commit 6c53823ae0e10e723131055e1e65dd6a328a228e reshuffled the way the authentication requirement gets set in the hci_io_capa_request_evt() function, but at the same time it failed to update an if-statement where cp.authentication is used before it has been initialized. The correct value the code should be looking for in this if-statement is conn->auth_type. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org # 3.16 --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index cae860b02d67..1ac526022ad9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3658,7 +3658,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) * except for the no-bonding case. */ if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && - cp.authentication != HCI_AT_NO_BONDING) + conn->auth_type != HCI_AT_NO_BONDING) conn->auth_type |= 0x01; cp.authentication = conn->auth_type; -- cgit v1.2.3 From 02f3e25457915728624b976b0382601b5605ad64 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 15:09:13 +0300 Subject: Bluetooth: Don't bother user space without IO capabilities If user space has a NoInputNoOutput IO capability it makes no sense to bother it with confirmation requests. This patch updates both SSP and SMP to check for the local IO capability before sending a user confirmation request to user space. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 4 +++- net/bluetooth/smp.c | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1ac526022ad9..1bd4de7e74fc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3752,9 +3752,11 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, /* If we're not the initiators request authorization to * proceed from user space (mgmt_user_confirm with * confirm_hint set to 1). The exception is if neither - * side had MITM in which case we do auto-accept. + * side had MITM or if the local IO capability is + * NoInputNoOutput, in which case we do auto-accept */ if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && + conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && (loc_mitm || rem_mitm)) { BT_DBG("Confirming auto-accept as acceptor"); confirm_hint = 1; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 70b726518d7b..74a0308e39f3 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -431,6 +431,10 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR, &smp->flags)) method = JUST_WORKS; + /* Don't bother user space with no IO capabilities */ + if (method == JUST_CFM && hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT) + method = JUST_WORKS; + /* If Just Works, Continue with Zero TK */ if (method == JUST_WORKS) { set_bit(SMP_FLAG_TK_VALID, &smp->flags); -- cgit v1.2.3 From 093facf3634da1b0c2cc7ed106f1983da901bbab Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Tue, 15 Jul 2014 12:25:28 +0400 Subject: Bluetooth: never linger on process exit If the current process is exiting, lingering on socket close will make it unkillable, so we should avoid it. Reproducer: #include #include #define BTPROTO_L2CAP 0 #define BTPROTO_SCO 2 #define BTPROTO_RFCOMM 3 int main() { int fd; struct linger ling; fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); //or: fd = socket(PF_BLUETOOTH, SOCK_DGRAM, BTPROTO_L2CAP); //or: fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); ling.l_onoff = 1; ling.l_linger = 1000000000; setsockopt(fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); return 0; } Signed-off-by: Vladimir Davydov Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org --- net/bluetooth/l2cap_sock.c | 3 ++- net/bluetooth/rfcomm/sock.c | 3 ++- net/bluetooth/sco.c | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 9bb4d1b3a483..0bc67dc5dcce 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1112,7 +1112,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) l2cap_chan_close(chan, 0); lock_sock(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index c603a5eb4720..8bbbb5ec468c 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -918,7 +918,8 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how) sk->sk_shutdown = SHUTDOWN_MASK; __rfcomm_sock_close(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } release_sock(sk); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index ebf7ee6a446c..7ee9e4ab00f8 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -970,7 +970,8 @@ static int sco_sock_shutdown(struct socket *sock, int how) sco_sock_clear_timer(sk); __sco_sock_close(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } @@ -990,7 +991,8 @@ static int sco_sock_release(struct socket *sock) sco_sock_close(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) { + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) { lock_sock(sk); err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); release_sock(sk); -- cgit v1.2.3 From c1d4fa7aa86e9194724dfff9cb9359edb98d75ac Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 17 Jul 2014 15:14:50 +0300 Subject: Bluetooth: Fix resetting remote authentication requirement after pairing When a new hci_conn object is created the remote SSP authentication requirement is set to the invalid value 0xff to indicate that it is unknown. Once pairing completes however the code was leaving it as-is. In case a new pairing happens over the same connection it is important that we reset the value back to unknown so that the pairing code doesn't make false assumptions about the requirements. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1bd4de7e74fc..495d6d5c1146 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3870,6 +3870,9 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev, if (!conn) goto unlock; + /* Reset the authentication requirement to unknown */ + conn->remote_auth = 0xff; + /* To avoid duplicate auth_failed events to user space we check * the HCI_CONN_AUTH_PEND flag which will be set if we * initiated the authentication. A traditional auth_complete -- cgit v1.2.3 From e7cafc45258c852c5176cd421615846e79a3d307 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 17 Jul 2014 15:35:38 +0300 Subject: Bluetooth: Pass initiator/acceptor information to hci_conn_security() We're interested in whether an authentication request is because of a remote or local action. So far hci_conn_security() has been used both for incoming and outgoing actions (e.g. RFCOMM or L2CAP connect requests) so without some modifications it cannot know which peer is responsible for requesting authentication. This patch adds a new "bool initiator" parameter to hci_conn_security() to indicate which side is responsible for the request and updates the current users to pass this information correspondingly. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 ++- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/hci_conn.c | 3 ++- net/bluetooth/l2cap_core.c | 15 ++++++++------- net/bluetooth/l2cap_sock.c | 2 +- net/bluetooth/mgmt.c | 2 +- net/bluetooth/rfcomm/core.c | 3 ++- 7 files changed, 17 insertions(+), 13 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 73e16ecfd6b9..eb2b9c9e3480 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -720,7 +720,8 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, __u16 setting); int hci_conn_check_link_mode(struct hci_conn *conn); int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); -int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); +int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type, + bool initiator); int hci_conn_change_link_key(struct hci_conn *conn); int hci_conn_switch_role(struct hci_conn *conn, __u8 role); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 1fffd92808b0..8df15ad0d43f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -905,7 +905,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst, u8 dst_type); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); -int l2cap_chan_check_security(struct l2cap_chan *chan); +int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator); void l2cap_chan_set_defaults(struct l2cap_chan *chan); int l2cap_ertm_init(struct l2cap_chan *chan); void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index ad5f0b819e90..76c5a38e5997 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -973,7 +973,8 @@ static void hci_conn_encrypt(struct hci_conn *conn) } /* Enable security */ -int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) +int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type, + bool initiator) { BT_DBG("hcon %p", conn); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d0f36336b6ce..c8c259f21d80 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -775,7 +775,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) } /* Service level security */ -int l2cap_chan_check_security(struct l2cap_chan *chan) +int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator) { struct l2cap_conn *conn = chan->conn; __u8 auth_type; @@ -785,7 +785,8 @@ int l2cap_chan_check_security(struct l2cap_chan *chan) auth_type = l2cap_get_auth_type(chan); - return hci_conn_security(conn->hcon, chan->sec_level, auth_type); + return hci_conn_security(conn->hcon, chan->sec_level, auth_type, + initiator); } static u8 l2cap_get_ident(struct l2cap_conn *conn) @@ -1278,7 +1279,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) return; - if (l2cap_chan_check_security(chan) && + if (l2cap_chan_check_security(chan, true) && __l2cap_no_conn_pending(chan)) { l2cap_start_connection(chan); } @@ -1357,7 +1358,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } if (chan->state == BT_CONNECT) { - if (!l2cap_chan_check_security(chan) || + if (!l2cap_chan_check_security(chan, true) || !__l2cap_no_conn_pending(chan)) { l2cap_chan_unlock(chan); continue; @@ -1379,7 +1380,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); - if (l2cap_chan_check_security(chan)) { + if (l2cap_chan_check_security(chan, false)) { if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); @@ -3849,7 +3850,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, chan->ident = cmd->ident; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { - if (l2cap_chan_check_security(chan)) { + if (l2cap_chan_check_security(chan, false)) { if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; @@ -7191,7 +7192,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, if (hcon->state == BT_CONNECTED) { if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { __clear_chan_timer(chan); - if (l2cap_chan_check_security(chan)) + if (l2cap_chan_check_security(chan, true)) l2cap_state_change(chan, BT_CONNECTED); } else l2cap_do_start(chan); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 0bc67dc5dcce..3bb1cdf34f07 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -797,7 +797,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, } else if ((sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) || sk->sk_state == BT_CONNECTED) { - if (!l2cap_chan_check_security(chan)) + if (!l2cap_chan_check_security(chan, true)) set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); else sk->sk_state_change(sk); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b981bfb87f86..190668367e42 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3202,7 +3202,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, cmd->user_data = conn; if (conn->state == BT_CONNECTED && - hci_conn_security(conn, sec_level, auth_type)) + hci_conn_security(conn, sec_level, auth_type, true)) pairing_complete(cmd, 0); err = 0; diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 754b6fe4f742..a0690a84f3e9 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -227,7 +227,8 @@ static int rfcomm_check_security(struct rfcomm_dlc *d) break; } - return hci_conn_security(conn->hcon, d->sec_level, auth_type); + return hci_conn_security(conn->hcon, d->sec_level, auth_type, + d->out); } static void rfcomm_session_timeout(unsigned long arg) -- cgit v1.2.3 From 977f8fce0279e5f96dc5c5068610d60b9ae94802 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 17 Jul 2014 15:35:39 +0300 Subject: Bluetooth: Introduce a flag to track who really initiates authentication Even though our side requests authentication, the original action that caused it may be remotely triggered, such as an incoming L2CAP or RFCOMM connect request. To track this information introduce a new hci_conn flag called HCI_CONN_AUTH_INITIATOR. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_conn.c | 3 +++ net/bluetooth/hci_event.c | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index eb2b9c9e3480..996ed065b6c2 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -547,6 +547,7 @@ enum { HCI_CONN_SECURE, HCI_CONN_FIPS, HCI_CONN_STK_ENCRYPT, + HCI_CONN_AUTH_INITIATOR, }; static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 76c5a38e5997..0d76054efd26 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1027,6 +1027,9 @@ auth: if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return 0; + if (initiator) + set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); + if (!hci_conn_auth(conn, sec_level, auth_type)) return 0; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 495d6d5c1146..af2cdca03d73 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1645,6 +1645,8 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested auth_cp; + set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); + auth_cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(auth_cp), &auth_cp); @@ -2387,6 +2389,9 @@ check_auth: if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested cp; + + set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); + cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); } -- cgit v1.2.3 From 2f407f0afb443207789df3fb46456551aea11cc3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 17 Jul 2014 15:35:40 +0300 Subject: Bluetooth: Fix allowing initiating pairing when not pairable When we're not pairable we should still allow us to act as initiators for pairing, i.e. the HCI_PAIRABLE flag should only be affecting incoming pairing attempts. This patch fixes the relevant checks for the hci_io_capa_request_evt() and hci_pin_code_request_evt() functions. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index af2cdca03d73..4c41774aa556 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3118,10 +3118,11 @@ static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_conn_drop(conn); } - if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags)) + if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags) && + !test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags)) { hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); - else if (test_bit(HCI_MGMT, &hdev->dev_flags)) { + } else if (test_bit(HCI_MGMT, &hdev->dev_flags)) { u8 secure; if (conn->pending_sec_level == BT_SECURITY_HIGH) @@ -3647,7 +3648,11 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) if (!test_bit(HCI_MGMT, &hdev->dev_flags)) goto unlock; + /* Allow pairing if we're pairable, the initiators of the + * pairing or if the remote is not requesting bonding. + */ if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) || + test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags) || (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { struct hci_cp_io_capability_reply cp; -- cgit v1.2.3 From 9cc63db5e1f2f1c387f1a4c9983cf1364fe4ef95 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 16 Jul 2014 14:25:30 -0700 Subject: net_sched: cancel nest attribute on failure in tcf_exts_dump() Like other places, we need to cancel the nest attribute after we start. Fortunately the netlink message will not be sent on failure, so it's not a big problem at all. Cc: Jamal Hadi Salim Cc: "David S. Miller" Signed-off-by: Cong Wang Signed-off-by: Cong Wang Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_api.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 45527e6b52db..c28b0d327b12 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -561,13 +561,14 @@ EXPORT_SYMBOL(tcf_exts_change); int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts) { #ifdef CONFIG_NET_CLS_ACT + struct nlattr *nest; + if (exts->action && !list_empty(&exts->actions)) { /* * again for backward compatible mode - we want * to work with both old and new modes of entering * tc data even if iproute2 was newer - jhs */ - struct nlattr *nest; if (exts->type != TCA_OLD_COMPAT) { nest = nla_nest_start(skb, exts->action); if (nest == NULL) @@ -585,10 +586,14 @@ int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts) nla_nest_end(skb, nest); } } -#endif return 0; -nla_put_failure: __attribute__ ((unused)) + +nla_put_failure: + nla_nest_cancel(skb, nest); return -1; +#else + return 0; +#endif } EXPORT_SYMBOL(tcf_exts_dump); -- cgit v1.2.3 From c2659479f7865fb538493089bce3dd3d2abf90b0 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Wed, 16 Jul 2014 22:32:39 -0700 Subject: Update setapp/getapp prototypes in dcbnl_rtnl_ops to return int instead of u8 v2: fixed issue with checking return of dcbnl_rtnl_ops->getapp() Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c | 4 ++-- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 21 ++++++--------------- drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c | 6 +++--- drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c | 4 ++-- include/net/dcbnl.h | 4 ++-- net/dcb/dcbnl.c | 8 +++++++- 6 files changed, 22 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c index 51a952c51cb1..fb26bc4c42a1 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c @@ -2303,8 +2303,8 @@ static int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up) return 0; } -static u8 bnx2x_dcbnl_set_app_up(struct net_device *netdev, u8 idtype, - u16 idval, u8 up) +static int bnx2x_dcbnl_set_app_up(struct net_device *netdev, u8 idtype, + u16 idval, u8 up) { struct bnx2x *bp = netdev_priv(netdev); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index a8b1073e6373..0d3a9df5be36 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -648,26 +648,17 @@ static int __cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id, } /* Return the Application User Priority Map associated with the specified - * Application ID. Since this routine is prototyped to return "u8" we can't - * return errors ... + * Application ID. */ -static u8 cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id) +static int cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id) { - int result = __cxgb4_getapp(dev, app_idtype, app_id, 0); - - if (result < 0) - result = 0; - - return result; + return __cxgb4_getapp(dev, app_idtype, app_id, 0); } -/* Write a new Application User Priority Map for the specified Application ID. - * This routine is prototyped to return "u8" but other instantiations of the - * DCB NetLink Operations "setapp" routines return negative errnos for errors. - * We follow their lead. +/* Write a new Application User Priority Map for the specified Application ID */ -static u8 cxgb4_setapp(struct net_device *dev, u8 app_idtype, u16 app_id, - u8 app_prio) +static int cxgb4_setapp(struct net_device *dev, u8 app_idtype, u16 app_id, + u8 app_prio) { struct fw_port_cmd pcmd; struct port_info *pi = netdev2pinfo(dev); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c index 5172b6b12c09..ea1c1ab926e2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c @@ -495,10 +495,10 @@ static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state) * @id: id is either ether type or TCP/UDP port number * * Returns : on success, returns a non-zero 802.1p user priority bitmap - * otherwise returns 0 as the invalid user priority bitmap to indicate an + * otherwise returns -EINVAL as the invalid user priority bitmap to indicate an * error. */ -static u8 ixgbe_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id) +static int ixgbe_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct dcb_app app = { @@ -507,7 +507,7 @@ static u8 ixgbe_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id) }; if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) - return 0; + return -EINVAL; return dcb_getapp(netdev, &app); } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c index 561cb11ca58c..a72bcddf160a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c @@ -926,7 +926,7 @@ static int qlcnic_dcb_get_num_tcs(struct net_device *netdev, int attr, u8 *num) } } -static u8 qlcnic_dcb_get_app(struct net_device *netdev, u8 idtype, u16 id) +static int qlcnic_dcb_get_app(struct net_device *netdev, u8 idtype, u16 id) { struct qlcnic_adapter *adapter = netdev_priv(netdev); struct dcb_app app = { @@ -935,7 +935,7 @@ static u8 qlcnic_dcb_get_app(struct net_device *netdev, u8 idtype, u16 id) }; if (!test_bit(QLCNIC_DCB_STATE, &adapter->dcb->state)) - return 0; + return -EINVAL; return dcb_getapp(netdev, &app); } diff --git a/include/net/dcbnl.h b/include/net/dcbnl.h index a975edf21b22..597b88a94332 100644 --- a/include/net/dcbnl.h +++ b/include/net/dcbnl.h @@ -81,8 +81,8 @@ struct dcbnl_rtnl_ops { void (*setbcncfg)(struct net_device *, int, u32); void (*getbcnrp)(struct net_device *, int, u8 *); void (*setbcnrp)(struct net_device *, int, u8); - u8 (*setapp)(struct net_device *, u8, u16, u8); - u8 (*getapp)(struct net_device *, u8, u16); + int (*setapp)(struct net_device *, u8, u16, u8); + int (*getapp)(struct net_device *, u8, u16); u8 (*getfeatcfg)(struct net_device *, int, u8 *); u8 (*setfeatcfg)(struct net_device *, int, u8); diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index f8b98d89c285..c34af7a1d2d4 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -471,7 +471,11 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlmsghdr *nlh, id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); if (netdev->dcbnl_ops->getapp) { - up = netdev->dcbnl_ops->getapp(netdev, idtype, id); + ret = netdev->dcbnl_ops->getapp(netdev, idtype, id); + if (ret < 0) + return ret; + else + up = ret; } else { struct dcb_app app = { .selector = idtype, @@ -538,6 +542,8 @@ static int dcbnl_setapp(struct net_device *netdev, struct nlmsghdr *nlh, if (netdev->dcbnl_ops->setapp) { ret = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); + if (ret < 0) + return ret; } else { struct dcb_app app; app.selector = idtype; -- cgit v1.2.3 From ce04d63502ca7ec30ef07336a0fd6f1165fd486b Mon Sep 17 00:00:00 2001 From: Jianhua Xie Date: Thu, 17 Jul 2014 14:16:25 +0800 Subject: bonding: enhance L2 hash helper with packet type Current L2 hash helper calculates destination eth addr and source ether addr as L2 hash factors. This patch is adding packet type ID field into L2 hash factors. While one of BOND_XMIT_POLICY_LAYER2 or BOND_XMIT_POLICY_{LAYER|ENCAP}23 is applied, for the 2nd level hash, enhanced hash method can help to distribute different types of packets like IPv4/IPv6 packets to different slave devices. CC: Jay Vosburgh CC: Veaceslav Falico CC: Andy Gospodarek CC: David S. Miller CC: Pan Jiafei Acked-by: Eric Dumazet Signed-off-by: Jianhua Xie Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 1ff676caa9cd..a2c4e8d4a955 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2977,11 +2977,11 @@ static struct notifier_block bond_netdev_notifier = { /* L2 hash helper */ static inline u32 bond_eth_hash(struct sk_buff *skb) { - struct ethhdr *data = (struct ethhdr *)skb->data; - - if (skb_headlen(skb) >= offsetof(struct ethhdr, h_proto)) - return data->h_dest[5] ^ data->h_source[5]; + struct ethhdr *ep, hdr_tmp; + ep = skb_header_pointer(skb, 0, sizeof(hdr_tmp), &hdr_tmp); + if (ep) + return ep->h_dest[5] ^ ep->h_source[5] ^ ep->h_proto; return 0; } -- cgit v1.2.3 From 92abf75033d2677a684c623d60f093b130c4b38f Mon Sep 17 00:00:00 2001 From: Jianhua Xie Date: Thu, 17 Jul 2014 14:16:26 +0800 Subject: bonding: update bonding.txt for Layer2 hash factors Document the Layer 2 hash factors with packet type ID field. CC: Jay Vosburgh CC: Veaceslav Falico CC: Andy Gospodarek CC: David S. Miller CC: Pan Jiafei Signed-off-by: Jianhua Xie Signed-off-by: David S. Miller --- Documentation/networking/bonding.txt | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index 9c723ecd0025..eeb5b2e97bed 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -542,10 +542,10 @@ mode XOR policy: Transmit based on the selected transmit hash policy. The default policy is a simple [(source - MAC address XOR'd with destination MAC address) modulo - slave count]. Alternate transmit policies may be - selected via the xmit_hash_policy option, described - below. + MAC address XOR'd with destination MAC address XOR + packet type ID) modulo slave count]. Alternate transmit + policies may be selected via the xmit_hash_policy option, + described below. This mode provides load balancing and fault tolerance. @@ -801,10 +801,11 @@ xmit_hash_policy layer2 - Uses XOR of hardware MAC addresses to generate the - hash. The formula is + Uses XOR of hardware MAC addresses and packet type ID + field to generate the hash. The formula is - (source MAC XOR destination MAC) modulo slave count + hash = source MAC XOR destination MAC XOR packet type ID + slave number = hash modulo slave count This algorithm will place all traffic to a particular network peer on the same slave. @@ -819,7 +820,7 @@ xmit_hash_policy Uses XOR of hardware MAC addresses and IP addresses to generate the hash. The formula is - hash = source MAC XOR destination MAC + hash = source MAC XOR destination MAC XOR packet type ID hash = hash XOR source IP XOR destination IP hash = hash XOR (hash RSHIFT 16) hash = hash XOR (hash RSHIFT 8) @@ -2301,13 +2302,13 @@ broadcast: Like active-backup, there is not much advantage to this bandwidth. Additionally, the linux bonding 802.3ad implementation - distributes traffic by peer (using an XOR of MAC addresses), - so in a "gatewayed" configuration, all outgoing traffic will - generally use the same device. Incoming traffic may also end - up on a single device, but that is dependent upon the - balancing policy of the peer's 8023.ad implementation. In a - "local" configuration, traffic will be distributed across the - devices in the bond. + distributes traffic by peer (using an XOR of MAC addresses + and packet type ID), so in a "gatewayed" configuration, all + outgoing traffic will generally use the same device. Incoming + traffic may also end up on a single device, but that is + dependent upon the balancing policy of the peer's 8023.ad + implementation. In a "local" configuration, traffic will be + distributed across the devices in the bond. Finally, the 802.3ad mode mandates the use of the MII monitor, therefore, the ARP monitor is not available in this mode. -- cgit v1.2.3 From 3ded29ace767a626d07c14fbdf9586dc0e520636 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Thu, 17 Jul 2014 00:18:15 -0700 Subject: cxgb4/iw_cxgb4: Move common defines to cxgb4 This define is used by cxgb4i and iw_cxgb4, moving to avoid code duplication Signed-off-by: Anish Bhatt Acked-by: Steve Wise Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/t4fw_ri_api.h | 1 - drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h index 91289a051af9..5709e77faf7c 100644 --- a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h +++ b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h @@ -849,6 +849,5 @@ enum { /* TCP congestion control algorithms */ #define G_CONG_CNTRL(x) (((x) >> S_CONG_CNTRL) & M_CONG_CNTRL) #define CONG_CNTRL_VALID (1 << 18) -#define T5_OPT_2_VALID (1 << 31) #endif /* _T4FW_RI_API_H_ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index abb45809c0c8..64006327df83 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -276,6 +276,7 @@ struct cpl_pass_accept_rpl { #define WND_SCALE_EN(x) ((x) << 28) #define TSTAMPS_EN(x) ((x) << 29) #define SACK_EN(x) ((x) << 30) +#define T5_OPT_2_VALID ((1U) << 31) __be64 opt0; }; -- cgit v1.2.3 From a3e3b2857d35988819bc396c012c53898b8223e6 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Thu, 17 Jul 2014 00:18:16 -0700 Subject: cxgb4: Export symbols required by cxgb4i for ipv6 support and required defines Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 10 ++++++---- drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 4 ++++ drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 9c7e4f0a7683..8b46534b06c1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -3445,8 +3445,8 @@ static int tid_init(struct tid_info *t) return 0; } -static int cxgb4_clip_get(const struct net_device *dev, - const struct in6_addr *lip) +int cxgb4_clip_get(const struct net_device *dev, + const struct in6_addr *lip) { struct adapter *adap; struct fw_clip_cmd c; @@ -3460,9 +3460,10 @@ static int cxgb4_clip_get(const struct net_device *dev, c.ip_lo = *(__be64 *)(lip->s6_addr + 8); return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); } +EXPORT_SYMBOL(cxgb4_clip_get); -static int cxgb4_clip_release(const struct net_device *dev, - const struct in6_addr *lip) +int cxgb4_clip_release(const struct net_device *dev, + const struct in6_addr *lip) { struct adapter *adap; struct fw_clip_cmd c; @@ -3476,6 +3477,7 @@ static int cxgb4_clip_release(const struct net_device *dev, c.ip_lo = *(__be64 *)(lip->s6_addr + 8); return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); } +EXPORT_SYMBOL(cxgb4_clip_release); /** * cxgb4_create_server - create an IP server diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index 79a84de1d204..1366ba620c87 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -172,6 +172,10 @@ int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid, unsigned char port, unsigned char mask); int cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid, unsigned int queue, bool ipv6); +int cxgb4_clip_get(const struct net_device *dev, const struct in6_addr *lip); +int cxgb4_clip_release(const struct net_device *dev, + const struct in6_addr *lip); + static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue) { skb_set_queue_mapping(skb, (queue << 1) | prio); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index 64006327df83..0259feeab1b3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -270,6 +270,8 @@ struct cpl_pass_accept_rpl { #define RX_COALESCE_VALID(x) ((x) << 11) #define RX_COALESCE(x) ((x) << 12) #define PACE(x) ((x) << 16) +#define RX_FC_VALID ((1U) << 19) +#define RX_FC_DISABLE ((1U) << 20) #define TX_QUEUE(x) ((x) << 23) #define RX_CHANNEL(x) ((x) << 26) #define CCTRL_ECN(x) ((x) << 27) -- cgit v1.2.3 From fc8d0590d9142d01e4ccea3aa57c894bd6e53662 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Thu, 17 Jul 2014 00:18:17 -0700 Subject: libcxgbi: Add ipv6 api to driver Signed-off-by: Anish Bhatt Signed-off-by: Karen Xie Signed-off-by: Manoj Malviya Signed-off-by: David S. Miller --- drivers/scsi/cxgbi/libcxgbi.c | 237 ++++++++++++++++++++++++++++++++++++++---- drivers/scsi/cxgbi/libcxgbi.h | 21 +++- 2 files changed, 237 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index b44c1cff3114..d2fe507fc695 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -24,6 +24,10 @@ #include #include #include +#include +#include +#include + #include /* ip_dev_find */ #include #include @@ -193,8 +197,8 @@ struct cxgbi_device *cxgbi_device_find_by_lldev(void *lldev) } EXPORT_SYMBOL_GPL(cxgbi_device_find_by_lldev); -static struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev, - int *port) +struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev, + int *port) { struct net_device *vdev = NULL; struct cxgbi_device *cdev, *tmp; @@ -224,6 +228,40 @@ static struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev, "ndev 0x%p, %s, NO match found.\n", ndev, ndev->name); return NULL; } +EXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev); + +static struct cxgbi_device *cxgbi_device_find_by_mac(struct net_device *ndev, + int *port) +{ + struct net_device *vdev = NULL; + struct cxgbi_device *cdev, *tmp; + int i; + + if (ndev->priv_flags & IFF_802_1Q_VLAN) { + vdev = ndev; + ndev = vlan_dev_real_dev(ndev); + pr_info("vlan dev %s -> %s.\n", vdev->name, ndev->name); + } + + mutex_lock(&cdev_mutex); + list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { + for (i = 0; i < cdev->nports; i++) { + if (!memcmp(ndev->dev_addr, cdev->ports[i]->dev_addr, + MAX_ADDR_LEN)) { + cdev->hbas[i]->vdev = vdev; + mutex_unlock(&cdev_mutex); + if (port) + *port = i; + return cdev; + } + } + } + mutex_unlock(&cdev_mutex); + log_debug(1 << CXGBI_DBG_DEV, + "ndev 0x%p, %s, NO match mac found.\n", + ndev, ndev->name); + return NULL; +} void cxgbi_hbas_remove(struct cxgbi_device *cdev) { @@ -320,6 +358,7 @@ static int sock_get_port(struct cxgbi_sock *csk) struct cxgbi_ports_map *pmap = &cdev->pmap; unsigned int start; int idx; + __be16 *port; if (!pmap->max_connect) { pr_err("cdev 0x%p, p#%u %s, NO port map.\n", @@ -327,9 +366,14 @@ static int sock_get_port(struct cxgbi_sock *csk) return -EADDRNOTAVAIL; } - if (csk->saddr.sin_port) { + if (csk->csk_family == AF_INET) + port = &csk->saddr.sin_port; + else /* ipv6 */ + port = &csk->saddr6.sin6_port; + + if (*port) { pr_err("source port NON-ZERO %u.\n", - ntohs(csk->saddr.sin_port)); + ntohs(*port)); return -EADDRINUSE; } @@ -347,8 +391,7 @@ static int sock_get_port(struct cxgbi_sock *csk) idx = 0; if (!pmap->port_csk[idx]) { pmap->used++; - csk->saddr.sin_port = - htons(pmap->sport_base + idx); + *port = htons(pmap->sport_base + idx); pmap->next = idx; pmap->port_csk[idx] = csk; spin_unlock_bh(&pmap->lock); @@ -374,16 +417,22 @@ static void sock_put_port(struct cxgbi_sock *csk) { struct cxgbi_device *cdev = csk->cdev; struct cxgbi_ports_map *pmap = &cdev->pmap; + __be16 *port; - if (csk->saddr.sin_port) { - int idx = ntohs(csk->saddr.sin_port) - pmap->sport_base; + if (csk->csk_family == AF_INET) + port = &csk->saddr.sin_port; + else /* ipv6 */ + port = &csk->saddr6.sin6_port; - csk->saddr.sin_port = 0; + if (*port) { + int idx = ntohs(*port) - pmap->sport_base; + + *port = 0; if (idx < 0 || idx >= pmap->max_connect) { pr_err("cdev 0x%p, p#%u %s, port %u OOR.\n", cdev, csk->port_id, cdev->ports[csk->port_id]->name, - ntohs(csk->saddr.sin_port)); + ntohs(*port)); return; } @@ -479,17 +528,11 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) int port = 0xFFFF; int err = 0; - if (daddr->sin_family != AF_INET) { - pr_info("address family 0x%x NOT supported.\n", - daddr->sin_family); - err = -EAFNOSUPPORT; - goto err_out; - } - rt = find_route_ipv4(&fl4, 0, daddr->sin_addr.s_addr, 0, daddr->sin_port, 0); if (!rt) { pr_info("no route to ipv4 0x%x, port %u.\n", - daddr->sin_addr.s_addr, daddr->sin_port); + be32_to_cpu(daddr->sin_addr.s_addr), + be16_to_cpu(daddr->sin_port)); err = -ENETUNREACH; goto err_out; } @@ -537,9 +580,12 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) csk->port_id = port; csk->mtu = mtu; csk->dst = dst; + + csk->csk_family = AF_INET; csk->daddr.sin_addr.s_addr = daddr->sin_addr.s_addr; csk->daddr.sin_port = daddr->sin_port; csk->daddr.sin_family = daddr->sin_family; + csk->saddr.sin_family = daddr->sin_family; csk->saddr.sin_addr.s_addr = fl4.saddr; neigh_release(n); @@ -556,6 +602,121 @@ err_out: return ERR_PTR(err); } +static struct rt6_info *find_route_ipv6(const struct in6_addr *saddr, + const struct in6_addr *daddr) +{ + struct flowi6 fl; + + if (saddr) + memcpy(&fl.saddr, saddr, sizeof(struct in6_addr)); + if (daddr) + memcpy(&fl.daddr, daddr, sizeof(struct in6_addr)); + return (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl); +} + +static struct cxgbi_sock *cxgbi_check_route6(struct sockaddr *dst_addr) +{ + struct sockaddr_in6 *daddr6 = (struct sockaddr_in6 *)dst_addr; + struct dst_entry *dst; + struct net_device *ndev; + struct cxgbi_device *cdev; + struct rt6_info *rt = NULL; + struct neighbour *n; + struct in6_addr pref_saddr; + struct cxgbi_sock *csk = NULL; + unsigned int mtu = 0; + int port = 0xFFFF; + int err = 0; + + rt = find_route_ipv6(NULL, &daddr6->sin6_addr); + + if (!rt) { + pr_info("no route to ipv6 %pI6 port %u\n", + daddr6->sin6_addr.s6_addr, + be16_to_cpu(daddr6->sin6_port)); + err = -ENETUNREACH; + goto err_out; + } + + dst = &rt->dst; + + n = dst_neigh_lookup(dst, &daddr6->sin6_addr); + + if (!n) { + pr_info("%pI6, port %u, dst no neighbour.\n", + daddr6->sin6_addr.s6_addr, + be16_to_cpu(daddr6->sin6_port)); + err = -ENETUNREACH; + goto rel_rt; + } + ndev = n->dev; + + if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) { + pr_info("multi-cast route %pI6 port %u, dev %s.\n", + daddr6->sin6_addr.s6_addr, + ntohs(daddr6->sin6_port), ndev->name); + err = -ENETUNREACH; + goto rel_rt; + } + + cdev = cxgbi_device_find_by_netdev(ndev, &port); + if (!cdev) + cdev = cxgbi_device_find_by_mac(ndev, &port); + if (!cdev) { + pr_info("dst %pI6 %s, NOT cxgbi device.\n", + daddr6->sin6_addr.s6_addr, ndev->name); + err = -ENETUNREACH; + goto rel_rt; + } + log_debug(1 << CXGBI_DBG_SOCK, + "route to %pI6 :%u, ndev p#%d,%s, cdev 0x%p.\n", + daddr6->sin6_addr.s6_addr, ntohs(daddr6->sin6_port), port, + ndev->name, cdev); + + csk = cxgbi_sock_create(cdev); + if (!csk) { + err = -ENOMEM; + goto rel_rt; + } + csk->cdev = cdev; + csk->port_id = port; + csk->mtu = mtu; + csk->dst = dst; + + if (ipv6_addr_any(&rt->rt6i_prefsrc.addr)) { + struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt); + + err = ipv6_dev_get_saddr(&init_net, idev ? idev->dev : NULL, + &daddr6->sin6_addr, 0, &pref_saddr); + if (err) { + pr_info("failed to get source address to reach %pI6\n", + &daddr6->sin6_addr); + goto rel_rt; + } + } else { + pref_saddr = rt->rt6i_prefsrc.addr; + } + + csk->csk_family = AF_INET6; + csk->daddr6.sin6_addr = daddr6->sin6_addr; + csk->daddr6.sin6_port = daddr6->sin6_port; + csk->daddr6.sin6_family = daddr6->sin6_family; + csk->saddr6.sin6_addr = pref_saddr; + + neigh_release(n); + return csk; + +rel_rt: + if (n) + neigh_release(n); + + ip6_rt_put(rt); + if (csk) + cxgbi_sock_closed(csk); +err_out: + return ERR_PTR(err); +} + void cxgbi_sock_established(struct cxgbi_sock *csk, unsigned int snd_isn, unsigned int opt) { @@ -2194,6 +2355,34 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn, } EXPORT_SYMBOL_GPL(cxgbi_set_conn_param); +static inline int csk_print_port(struct cxgbi_sock *csk, char *buf) +{ + int len; + + cxgbi_sock_get(csk); + len = sprintf(buf, "%hu\n", ntohs(csk->daddr.sin_port)); + cxgbi_sock_put(csk); + + return len; +} + +static inline int csk_print_ip(struct cxgbi_sock *csk, char *buf) +{ + int len; + + cxgbi_sock_get(csk); + if (csk->csk_family == AF_INET) + len = sprintf(buf, "%pI4", + &csk->daddr.sin_addr.s_addr); + else + len = sprintf(buf, "%pI6", + &csk->daddr6.sin6_addr); + + cxgbi_sock_put(csk); + + return len; +} + int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param, char *buf) { @@ -2447,7 +2636,17 @@ struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost, } } - csk = cxgbi_check_route(dst_addr); + if (dst_addr->sa_family == AF_INET) { + csk = cxgbi_check_route(dst_addr); + } else if (dst_addr->sa_family == AF_INET6) { + csk = cxgbi_check_route6(dst_addr); + } else { + pr_info("address family 0x%x NOT supported.\n", + dst_addr->sa_family); + err = -EAFNOSUPPORT; + return (struct iscsi_endpoint *)ERR_PTR(err); + } + if (IS_ERR(csk)) return (struct iscsi_endpoint *)csk; cxgbi_sock_get(csk); diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h index 8135f04671af..8ad73d913f02 100644 --- a/drivers/scsi/cxgbi/libcxgbi.h +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -44,6 +44,15 @@ enum cxgbi_dbg_flag { pr_info(fmt, ##__VA_ARGS__); \ } while (0) +#define pr_info_ipaddr(fmt_trail, \ + addr1, addr2, args_trail...) \ +do { \ + if (!((1 << CXGBI_DBG_SOCK) & dbg_level)) \ + break; \ + pr_info("%pISpc - %pISpc, " fmt_trail, \ + addr1, addr2, args_trail); \ +} while (0) + /* max. connections per adapter */ #define CXGBI_MAX_CONN 16384 @@ -202,8 +211,15 @@ struct cxgbi_sock { spinlock_t lock; struct kref refcnt; unsigned int state; - struct sockaddr_in saddr; - struct sockaddr_in daddr; + unsigned int csk_family; + union { + struct sockaddr_in saddr; + struct sockaddr_in6 saddr6; + }; + union { + struct sockaddr_in daddr; + struct sockaddr_in6 daddr6; + }; struct dst_entry *dst; struct sk_buff_head receive_queue; struct sk_buff_head write_queue; @@ -692,6 +708,7 @@ struct cxgbi_device *cxgbi_device_register(unsigned int, unsigned int); void cxgbi_device_unregister(struct cxgbi_device *); void cxgbi_device_unregister_all(unsigned int flag); struct cxgbi_device *cxgbi_device_find_by_lldev(void *); +struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *, int *); int cxgbi_hbas_add(struct cxgbi_device *, unsigned int, unsigned int, struct scsi_host_template *, struct scsi_transport_template *); -- cgit v1.2.3 From 759a0cc5a3e1bc2cc48fa3c0b91bdcad8b8f87d6 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Thu, 17 Jul 2014 00:18:18 -0700 Subject: cxgb4i: Add ipv6 code to driver, call into libcxgbi ipv6 api Signed-off-by: Anish Bhatt Signed-off-by: Karen Xie Signed-off-by: Manoj Malviya Signed-off-by: David S. Miller --- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 353 +++++++++++++++++++++++++++++++++---- 1 file changed, 314 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index e8ee5e5fe0ef..1041574edcfc 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "t4_regs.h" #include "t4_msg.h" @@ -150,6 +151,7 @@ static struct scsi_transport_template *cxgb4i_stt; * The section below implments CPLs that related to iscsi tcp connection * open/close/abort and data send/receive. */ + #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) #define RCV_BUFSIZ_MASK 0x3FFU #define MAX_IMM_TX_PKT_LEN 128 @@ -179,6 +181,7 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, struct l2t_entry *e) { struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); + int t4 = is_t4(lldi->adapter_type); int wscale = cxgbi_sock_compute_wscale(csk->mss_idx); unsigned long long opt0; unsigned int opt2; @@ -248,6 +251,97 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, } set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); + + pr_info_ipaddr("t%d csk 0x%p,%u,0x%lx,%u, rss_qid %u.\n", + (&csk->saddr), (&csk->daddr), t4 ? 4 : 5, csk, + csk->state, csk->flags, csk->atid, csk->rss_qid); + + cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); +} + +static void send_act_open_req6(struct cxgbi_sock *csk, struct sk_buff *skb, + struct l2t_entry *e) +{ + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); + int t4 = is_t4(lldi->adapter_type); + int wscale = cxgbi_sock_compute_wscale(csk->mss_idx); + unsigned long long opt0; + unsigned int opt2; + unsigned int qid_atid = ((unsigned int)csk->atid) | + (((unsigned int)csk->rss_qid) << 14); + + opt0 = KEEP_ALIVE(1) | + WND_SCALE(wscale) | + MSS_IDX(csk->mss_idx) | + L2T_IDX(((struct l2t_entry *)csk->l2t)->idx) | + TX_CHAN(csk->tx_chan) | + SMAC_SEL(csk->smac_idx) | + ULP_MODE(ULP_MODE_ISCSI) | + RCV_BUFSIZ(cxgb4i_rcv_win >> 10); + + opt2 = RX_CHANNEL(0) | + RSS_QUEUE_VALID | + RX_FC_DISABLE | + RSS_QUEUE(csk->rss_qid); + + if (t4) { + struct cpl_act_open_req6 *req = + (struct cpl_act_open_req6 *)skb->head; + + INIT_TP_WR(req, 0); + OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6, + qid_atid)); + req->local_port = csk->saddr6.sin6_port; + req->peer_port = csk->daddr6.sin6_port; + + req->local_ip_hi = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr); + req->local_ip_lo = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr + + 8); + req->peer_ip_hi = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr); + req->peer_ip_lo = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr + + 8); + + req->opt0 = cpu_to_be64(opt0); + + opt2 |= RX_FC_VALID; + req->opt2 = cpu_to_be32(opt2); + + req->params = cpu_to_be32(cxgb4_select_ntuple( + csk->cdev->ports[csk->port_id], + csk->l2t)); + } else { + struct cpl_t5_act_open_req6 *req = + (struct cpl_t5_act_open_req6 *)skb->head; + + INIT_TP_WR(req, 0); + OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6, + qid_atid)); + req->local_port = csk->saddr6.sin6_port; + req->peer_port = csk->daddr6.sin6_port; + req->local_ip_hi = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr); + req->local_ip_lo = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr + + 8); + req->peer_ip_hi = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr); + req->peer_ip_lo = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr + + 8); + req->opt0 = cpu_to_be64(opt0); + + opt2 |= T5_OPT_2_VALID; + req->opt2 = cpu_to_be32(opt2); + + req->params = cpu_to_be64(V_FILTER_TUPLE(cxgb4_select_ntuple( + csk->cdev->ports[csk->port_id], + csk->l2t))); + } + + set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); + + pr_info("t%d csk 0x%p,%u,0x%lx,%u, [%pI6]:%u-[%pI6]:%u, rss_qid %u.\n", + t4 ? 4 : 5, csk, csk->state, csk->flags, csk->atid, + &csk->saddr6.sin6_addr, ntohs(csk->saddr.sin_port), + &csk->daddr6.sin6_addr, ntohs(csk->daddr.sin_port), + csk->rss_qid); + cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); } @@ -586,9 +680,11 @@ static void do_act_establish(struct cxgbi_device *cdev, struct sk_buff *skb) goto rel_skb; } - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx, tid %u, atid %u, rseq %u.\n", - csk, csk->state, csk->flags, tid, atid, rcv_isn); + pr_info_ipaddr("atid 0x%x, tid 0x%x, csk 0x%p,%u,0x%lx, isn %u.\n", + (&csk->saddr), (&csk->daddr), + atid, tid, csk, csk->state, csk->flags, rcv_isn); + + module_put(THIS_MODULE); cxgbi_sock_get(csk); csk->tid = tid; @@ -663,6 +759,9 @@ static void csk_act_open_retry_timer(unsigned long data) struct sk_buff *skb; struct cxgbi_sock *csk = (struct cxgbi_sock *)data; struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); + void (*send_act_open_func)(struct cxgbi_sock *, struct sk_buff *, + struct l2t_entry *); + int t4 = is_t4(lldi->adapter_type), size, size6; log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", @@ -670,20 +769,35 @@ static void csk_act_open_retry_timer(unsigned long data) cxgbi_sock_get(csk); spin_lock_bh(&csk->lock); - skb = alloc_wr(is_t4(lldi->adapter_type) ? - sizeof(struct cpl_act_open_req) : - sizeof(struct cpl_t5_act_open_req), - 0, GFP_ATOMIC); + + if (t4) { + size = sizeof(struct cpl_act_open_req); + size6 = sizeof(struct cpl_act_open_req6); + } else { + size = sizeof(struct cpl_t5_act_open_req); + size6 = sizeof(struct cpl_t5_act_open_req6); + } + + if (csk->csk_family == AF_INET) { + send_act_open_func = send_act_open_req; + skb = alloc_wr(size, 0, GFP_ATOMIC); + } else { + send_act_open_func = send_act_open_req6; + skb = alloc_wr(size6, 0, GFP_ATOMIC); + } + if (!skb) cxgbi_sock_fail_act_open(csk, -ENOMEM); else { skb->sk = (struct sock *)csk; t4_set_arp_err_handler(skb, csk, - cxgbi_sock_act_open_req_arp_failure); - send_act_open_req(csk, skb, csk->l2t); + cxgbi_sock_act_open_req_arp_failure); + send_act_open_func(csk, skb, csk->l2t); } + spin_unlock_bh(&csk->lock); cxgbi_sock_put(csk); + } static void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) @@ -703,10 +817,9 @@ static void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) goto rel_skb; } - pr_info("%pI4:%u-%pI4:%u, atid %u,%u, status %u, csk 0x%p,%u,0x%lx.\n", - &csk->saddr.sin_addr.s_addr, ntohs(csk->saddr.sin_port), - &csk->daddr.sin_addr.s_addr, ntohs(csk->daddr.sin_port), - atid, tid, status, csk, csk->state, csk->flags); + pr_info_ipaddr("tid %u/%u, status %u.\n" + "csk 0x%p,%u,0x%lx. ", (&csk->saddr), (&csk->daddr), + atid, tid, status, csk, csk->state, csk->flags); if (status == CPL_ERR_RTX_NEG_ADVICE) goto rel_skb; @@ -746,9 +859,9 @@ static void do_peer_close(struct cxgbi_device *cdev, struct sk_buff *skb) pr_err("can't find connection for tid %u.\n", tid); goto rel_skb; } - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); + pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u.\n", + (&csk->saddr), (&csk->daddr), + csk, csk->state, csk->flags, csk->tid); cxgbi_sock_rcv_peer_close(csk); rel_skb: __kfree_skb(skb); @@ -767,9 +880,9 @@ static void do_close_con_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) pr_err("can't find connection for tid %u.\n", tid); goto rel_skb; } - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); + pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u.\n", + (&csk->saddr), (&csk->daddr), + csk, csk->state, csk->flags, csk->tid); cxgbi_sock_rcv_close_conn_rpl(csk, ntohl(rpl->snd_nxt)); rel_skb: __kfree_skb(skb); @@ -808,9 +921,9 @@ static void do_abort_req_rss(struct cxgbi_device *cdev, struct sk_buff *skb) goto rel_skb; } - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx, tid %u, status 0x%x.\n", - csk, csk->state, csk->flags, csk->tid, req->status); + pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u, status %u.\n", + (&csk->saddr), (&csk->daddr), + csk, csk->state, csk->flags, csk->tid, req->status); if (req->status == CPL_ERR_RTX_NEG_ADVICE || req->status == CPL_ERR_PERSIST_NEG_ADVICE) @@ -851,10 +964,10 @@ static void do_abort_rpl_rss(struct cxgbi_device *cdev, struct sk_buff *skb) if (!csk) goto rel_skb; - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "status 0x%x, csk 0x%p, s %u, 0x%lx.\n", - rpl->status, csk, csk ? csk->state : 0, - csk ? csk->flags : 0UL); + if (csk) + pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u, status %u.\n", + (&csk->saddr), (&csk->daddr), csk, + csk->state, csk->flags, csk->tid, rpl->status); if (rpl->status == CPL_ERR_ABORT_FAILED) goto rel_skb; @@ -1163,15 +1276,29 @@ static int init_act_open(struct cxgbi_sock *csk) struct cxgbi_device *cdev = csk->cdev; struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); struct net_device *ndev = cdev->ports[csk->port_id]; - struct port_info *pi = netdev_priv(ndev); struct sk_buff *skb = NULL; - struct neighbour *n; + struct neighbour *n = NULL; + void *daddr; unsigned int step; + unsigned int size, size6; + int t4 = is_t4(lldi->adapter_type); log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", csk, csk->state, csk->flags, csk->tid); + if (csk->csk_family == AF_INET) + daddr = &csk->daddr.sin_addr.s_addr; + else + daddr = &csk->daddr6.sin6_addr; + + n = dst_neigh_lookup(csk->dst, daddr); + + if (!n) { + pr_err("%s, can't get neighbour of csk->dst.\n", ndev->name); + goto rel_resource; + } + csk->atid = cxgb4_alloc_atid(lldi->tids, csk); if (csk->atid < 0) { pr_err("%s, NO atid available.\n", ndev->name); @@ -1192,10 +1319,19 @@ static int init_act_open(struct cxgbi_sock *csk) } cxgbi_sock_get(csk); - skb = alloc_wr(is_t4(lldi->adapter_type) ? - sizeof(struct cpl_act_open_req) : - sizeof(struct cpl_t5_act_open_req), - 0, GFP_ATOMIC); + if (t4) { + size = sizeof(struct cpl_act_open_req); + size6 = sizeof(struct cpl_act_open_req6); + } else { + size = sizeof(struct cpl_t5_act_open_req); + size6 = sizeof(struct cpl_t5_act_open_req6); + } + + if (csk->csk_family == AF_INET) + skb = alloc_wr(size, 0, GFP_NOIO); + else + skb = alloc_wr(size6, 0, GFP_NOIO); + if (!skb) goto rel_resource; skb->sk = (struct sock *)csk; @@ -1211,19 +1347,27 @@ static int init_act_open(struct cxgbi_sock *csk) csk->txq_idx = cxgb4_port_idx(ndev) * step; step = lldi->nrxq / lldi->nchan; csk->rss_qid = lldi->rxq_ids[cxgb4_port_idx(ndev) * step]; - csk->wr_max_cred = csk->wr_cred = lldi->wr_cred; + csk->wr_cred = lldi->wr_cred - + DIV_ROUND_UP(sizeof(struct cpl_abort_req), 16); + csk->wr_max_cred = csk->wr_cred; csk->wr_una_cred = 0; cxgbi_sock_reset_wr_list(csk); csk->err = 0; - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,p%d,%s, %u,%u,%u, mss %u,%u, smac %u.\n", - csk, pi->port_id, ndev->name, csk->tx_chan, - csk->txq_idx, csk->rss_qid, csk->mtu, csk->mss_idx, - csk->smac_idx); + pr_info_ipaddr("csk 0x%p,%u,0x%lx,%u,%u,%u, mtu %u,%u, smac %u.\n", + (&csk->saddr), (&csk->daddr), csk, csk->state, + csk->flags, csk->tx_chan, csk->txq_idx, csk->rss_qid, + csk->mtu, csk->mss_idx, csk->smac_idx); + + /* must wait for either a act_open_rpl or act_open_establish */ + try_module_get(THIS_MODULE); cxgbi_sock_set_state(csk, CTP_ACTIVE_OPEN); - send_act_open_req(csk, skb, csk->l2t); + if (csk->csk_family == AF_INET) + send_act_open_req(csk, skb, csk->l2t); + else + send_act_open_req6(csk, skb, csk->l2t); neigh_release(n); + return 0; rel_resource: @@ -1487,6 +1631,131 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev) return 0; } +static int cxgbi_inet6addr_handler(struct notifier_block *this, + unsigned long event, void *data) +{ + struct inet6_ifaddr *ifa = data; + struct net_device *event_dev = ifa->idev->dev; + struct cxgbi_device *cdev; + int ret = NOTIFY_DONE; + + rcu_read_lock(); + + if (event_dev->priv_flags & IFF_802_1Q_VLAN) + event_dev = vlan_dev_real_dev(event_dev); + + cdev = cxgbi_device_find_by_netdev(event_dev, NULL); + if (!cdev) { + rcu_read_unlock(); + return ret; + } + switch (event) { + case NETDEV_UP: + ret = cxgb4_clip_get(event_dev, + (const struct in6_addr *) + ((ifa)->addr.s6_addr)); + if (ret < 0) { + rcu_read_unlock(); + return ret; + } + ret = NOTIFY_OK; + break; + + case NETDEV_DOWN: + cxgb4_clip_release(event_dev, + (const struct in6_addr *) + ((ifa)->addr.s6_addr)); + ret = NOTIFY_OK; + break; + + default: + break; + } + + rcu_read_unlock(); + return ret; +} + +static struct notifier_block cxgbi_inet6addr_notifier = { + .notifier_call = cxgbi_inet6addr_handler +}; + +/* Retrieve IPv6 addresses from a root device (bond, vlan) associated with + * a physical device. + * The physical device reference is needed to send the actual CLIP command. + */ +static int update_dev_clip(struct net_device *root_dev, struct net_device *dev) +{ + struct inet6_dev *idev = NULL; + struct inet6_ifaddr *ifa; + int ret = 0; + + idev = __in6_dev_get(root_dev); + if (!idev) + return ret; + + read_lock_bh(&idev->lock); + list_for_each_entry(ifa, &idev->addr_list, if_list) { + pr_info("updating the clip for addr %pI6\n", + ifa->addr.s6_addr); + ret = cxgb4_clip_get(dev, (const struct in6_addr *) + ifa->addr.s6_addr); + if (ret < 0) + break; + } + + read_unlock_bh(&idev->lock); + return ret; +} + +static int update_root_dev_clip(struct net_device *dev) +{ + struct net_device *root_dev = NULL; + int i, ret = 0; + + /* First populate the real net device's IPv6 address */ + ret = update_dev_clip(dev, dev); + if (ret) + return ret; + + /* Parse all bond and vlan devices layered on top of the physical dev */ + root_dev = netdev_master_upper_dev_get(dev); + if (root_dev) { + ret = update_dev_clip(root_dev, dev); + if (ret) + return ret; + } + + for (i = 0; i < VLAN_N_VID; i++) { + root_dev = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021Q), i); + if (!root_dev) + continue; + + ret = update_dev_clip(root_dev, dev); + if (ret) + break; + } + return ret; +} + +static void cxgbi_update_clip(struct cxgbi_device *cdev) +{ + int i; + + rcu_read_lock(); + + for (i = 0; i < cdev->nports; i++) { + struct net_device *dev = cdev->ports[i]; + int ret = 0; + + if (dev) + ret = update_root_dev_clip(dev); + if (ret < 0) + break; + } + rcu_read_unlock(); +} + static void *t4_uld_add(const struct cxgb4_lld_info *lldi) { struct cxgbi_device *cdev; @@ -1605,6 +1874,7 @@ static int t4_uld_state_change(void *handle, enum cxgb4_state state) switch (state) { case CXGB4_STATE_UP: pr_info("cdev 0x%p, UP.\n", cdev); + cxgbi_update_clip(cdev); /* re-initialize */ break; case CXGB4_STATE_START_RECOVERY: @@ -1635,11 +1905,16 @@ static int __init cxgb4i_init_module(void) if (rc < 0) return rc; cxgb4_register_uld(CXGB4_ULD_ISCSI, &cxgb4i_uld_info); + + register_inet6addr_notifier(&cxgbi_inet6addr_notifier); + return 0; } static void __exit cxgb4i_exit_module(void) { + unregister_inet6addr_notifier(&cxgbi_inet6addr_notifier); + cxgb4_unregister_uld(CXGB4_ULD_ISCSI); cxgbi_device_unregister_all(CXGBI_FLAG_DEV_T4); cxgbi_iscsi_cleanup(&cxgb4i_iscsi_transport, &cxgb4i_stt); -- cgit v1.2.3 From 14056e7930761b730e2b34ae716e151ba890f3bf Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Wed, 16 Jul 2014 18:32:01 +0200 Subject: bonding: use rtnl_deref in bond_change_rx_flags() As it's always called with RTNL held, via dev_set_allmulti/promiscuity. Also, remove the wrong comment. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a2c4e8d4a955..5e5b3b30c51c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -496,9 +496,8 @@ static int bond_set_promiscuity(struct bonding *bond, int inc) int err = 0; if (bond_uses_primary(bond)) { - struct slave *curr_active = bond_deref_active_protected(bond); + struct slave *curr_active = rtnl_dereference(bond->curr_active_slave); - /* write lock already acquired */ if (curr_active) err = dev_set_promiscuity(curr_active->dev, inc); } else { @@ -522,9 +521,8 @@ static int bond_set_allmulti(struct bonding *bond, int inc) int err = 0; if (bond_uses_primary(bond)) { - struct slave *curr_active = bond_deref_active_protected(bond); + struct slave *curr_active = rtnl_dereference(bond->curr_active_slave); - /* write lock already acquired */ if (curr_active) err = dev_set_allmulti(curr_active->dev, inc); } else { -- cgit v1.2.3 From 23fa5c2caae08f919d906b1064b9fdc352b3024e Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Thu, 17 Jul 2014 12:04:08 +0200 Subject: bonding: destroy proc directory only after all bonds are gone Currently we might arrive to bond_net_exit() with some bonds left (that were created while the module is unloading). We take care of that by destroying sysfs (the last possibility to add new bonds) and then destroying all the remaining bonds. However, we destroy the /proc/net/bonding directory before destroying those last bonds, and get a warning that we're trying to destroy a non-empty proc directory (containing /proc/net/bonding/bondX). Fix this by moving bond_destroy_proc_dir() after all the bonds are destroyed, so that we're sure that no bonds exist. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5e5b3b30c51c..14f789551616 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4448,7 +4448,6 @@ static void __net_exit bond_net_exit(struct net *net) LIST_HEAD(list); bond_destroy_sysfs(bn); - bond_destroy_proc_dir(bn); /* Kill off any bonds created after unregistering bond rtnl ops */ rtnl_lock(); @@ -4456,6 +4455,8 @@ static void __net_exit bond_net_exit(struct net *net) unregister_netdevice_queue(bond->dev, &list); unregister_netdevice_many(&list); rtnl_unlock(); + + bond_destroy_proc_dir(bn); } static struct pernet_operations bond_net_ops = { -- cgit v1.2.3 From 940a3fcddc76f82ac4e80dfa7bccb236e9bec0a1 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 17 Jul 2014 16:20:19 +0530 Subject: be2net: use -ENETDOWN error status when interface is down Updating VF's tx-rate and FW-download are not allowed when the interface is down. In such cases return -ENETDOWN to the stack. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 9bced68527a9..4388833f31d9 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1372,7 +1372,7 @@ static int be_set_vf_tx_rate(struct net_device *netdev, int vf, if (!link_status) { dev_err(dev, "TX-rate setting not allowed when link is down\n"); - status = -EPERM; + status = -ENETDOWN; goto err; } @@ -4221,7 +4221,7 @@ int be_load_fw(struct be_adapter *adapter, u8 *fw_file) if (!netif_running(adapter->netdev)) { dev_err(&adapter->pdev->dev, "Firmware load not allowed (interface is down)\n"); - return -1; + return -ENETDOWN; } status = request_firmware(&fw, fw_file, &adapter->pdev->dev); -- cgit v1.2.3 From 56ace3a0d0209ea9f1806abb9c1046fdb89e0030 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 17 Jul 2014 16:20:20 +0530 Subject: be2net: fix error status for FW-download For FW download ethtool cmd, if the user provides an FW-image incompatible with the chip, return -EINVAL instead of -1. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 4388833f31d9..1f3daee5edc3 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3956,7 +3956,7 @@ static int be_flash_skyhawk(struct be_adapter *adapter, fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); if (!fsec) { dev_err(dev, "Invalid Cookie. FW image may be corrupted\n"); - return -1; + return -EINVAL; } for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) { @@ -4187,7 +4187,7 @@ static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw) &flash_cmd, num_imgs); else { - status = -1; + status = -EINVAL; dev_err(&adapter->pdev->dev, "Can't load BE3 UFI on BE3R\n"); } @@ -4198,7 +4198,7 @@ static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw) if (ufi_type == UFI_TYPE2) status = be_flash_BEx(adapter, fw, &flash_cmd, 0); else if (ufi_type == -1) - status = -1; + status = -EINVAL; dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma); -- cgit v1.2.3 From fd45160cef0a4782cde70ec4cdeb9421ea8460b6 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 17 Jul 2014 16:20:21 +0530 Subject: be2net: return -ETIMEDOUT when a FW-cmd times out When the FW stops responding with completions, return -ETIMEDOUT error (instead of -1) to the stack. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 9904bbfd4e93..e632bd2d561c 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2224,7 +2224,7 @@ int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, if (!wait_for_completion_timeout(&adapter->et_cmd_compl, msecs_to_jiffies(60000))) - status = -1; + status = -ETIMEDOUT; else status = adapter->flash_status; @@ -2320,7 +2320,7 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, if (!wait_for_completion_timeout(&adapter->et_cmd_compl, msecs_to_jiffies(40000))) - status = -1; + status = -ETIMEDOUT; else status = adapter->flash_status; -- cgit v1.2.3 From 6b5686891c9858aea914c1d1c965d6bbc8a0521d Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 17 Jul 2014 16:20:22 +0530 Subject: be2net: return -ENOMEM for memory allocation failures Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 1f3daee5edc3..8826b778b3ab 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2931,7 +2931,7 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable) cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, GFP_KERNEL); if (cmd.va == NULL) - return -1; + return -ENOMEM; if (enable) { status = pci_write_config_dword(adapter->pdev, @@ -4586,7 +4586,7 @@ static int be_stats_init(struct be_adapter *adapter) cmd->va = dma_zalloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma, GFP_KERNEL); if (cmd->va == NULL) - return -1; + return -ENOMEM; return 0; } -- cgit v1.2.3 From 0532d4e36678d626b41528c00fefe3d6e04130b3 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 17 Jul 2014 16:20:23 +0530 Subject: be2net: fix return status of some ethtool methods ethtool expects a -ve status value to be returned when a driver method encounters an error. The driver was directly passing the error status returned by FW (a positive value) to ethtool. This patch fixes this by returning -EIO status in cases where FW returns an error. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 2 ++ drivers/net/ethernet/emulex/benet/be_ethtool.c | 12 +++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index d3d871b28cad..3e639e86e111 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -672,6 +672,8 @@ static inline void swap_dws(void *wrb, int len) #endif /* __BIG_ENDIAN */ } +#define be_cmd_status(status) (status > 0 ? -EIO : status) + static inline u8 is_tcp_pkt(struct sk_buff *skb) { u8 val = 0; diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index e2da4d20dd3d..25f516d6eb9e 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -643,7 +643,7 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) if (status) dev_warn(&adapter->pdev->dev, "Pause param set failed.\n"); - return status; + return be_cmd_status(status); } static int be_set_phys_id(struct net_device *netdev, @@ -762,7 +762,7 @@ static int be_test_ddr_dma(struct be_adapter *adapter) err: dma_free_coherent(&adapter->pdev->dev, ddrdma_cmd.size, ddrdma_cmd.va, ddrdma_cmd.dma); - return ret; + return be_cmd_status(ret); } static u64 be_loopback_test(struct be_adapter *adapter, u8 loopback_type, @@ -885,7 +885,7 @@ static int be_read_eeprom(struct net_device *netdev, dma_free_coherent(&adapter->pdev->dev, eeprom_cmd.size, eeprom_cmd.va, eeprom_cmd.dma); - return status; + return be_cmd_status(status); } static u32 be_get_msg_level(struct net_device *netdev) @@ -1042,7 +1042,7 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter, if (!status) adapter->rss_info.rss_flags = rss_flags; - return status; + return be_cmd_status(status); } static int be_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) @@ -1080,6 +1080,7 @@ static int be_set_channels(struct net_device *netdev, struct ethtool_channels *ch) { struct be_adapter *adapter = netdev_priv(netdev); + int status; if (ch->rx_count || ch->tx_count || ch->other_count || !ch->combined_count || ch->combined_count > be_max_qs(adapter)) @@ -1087,7 +1088,8 @@ static int be_set_channels(struct net_device *netdev, adapter->cfg_num_qs = ch->combined_count; - return be_update_queues(adapter); + status = be_update_queues(adapter); + return be_cmd_status(status); } static u32 be_get_rxfh_indir_size(struct net_device *netdev) -- cgit v1.2.3 From abccf23e3eebcd5b7b0ad5d2ad6d1f6d81af6b47 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 17 Jul 2014 16:20:24 +0530 Subject: be2net: fix return status of some ndo methods The netlink layer expects a -ve status value to be returned when a driver ndo method encounters an error. The driver was directly passing the error status returned by FW (a positive value) to the stack. This patch fixes this by returning -EIO status when a FW-cmd reports an error. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 43 ++++++++++++++++++----------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 8826b778b3ab..988f7658c960 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1281,13 +1281,15 @@ static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) vf + 1); } - if (status) - dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n", - mac, vf); - else - memcpy(vf_cfg->mac_addr, mac, ETH_ALEN); + if (status) { + dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed: %#x", + mac, vf, status); + return be_cmd_status(status); + } - return status; + ether_addr_copy(vf_cfg->mac_addr, mac); + + return 0; } static int be_get_vf_config(struct net_device *netdev, int vf, @@ -1336,12 +1338,16 @@ static int be_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos) vf + 1, vf_cfg->if_handle, 0); } - if (!status) - vf_cfg->vlan_tag = vlan; - else - dev_info(&adapter->pdev->dev, - "VLAN %d config on VF %d failed\n", vlan, vf); - return status; + if (status) { + dev_err(&adapter->pdev->dev, + "VLAN %d config on VF %d failed : %#x\n", vlan, + vf, status); + return be_cmd_status(status); + } + + vf_cfg->vlan_tag = vlan; + + return 0; } static int be_set_vf_tx_rate(struct net_device *netdev, int vf, @@ -1403,7 +1409,7 @@ config_qos: err: dev_err(dev, "TX-rate setting of %dMbps on VF%d failed\n", max_tx_rate, vf); - return status; + return be_cmd_status(status); } static int be_set_vf_link_state(struct net_device *netdev, int vf, int link_state) @@ -1418,10 +1424,15 @@ static int be_set_vf_link_state(struct net_device *netdev, int vf, return -EINVAL; status = be_cmd_set_logical_link_config(adapter, link_state, vf+1); - if (!status) - adapter->vf_cfg[vf].plink_tracking = link_state; + if (status) { + dev_err(&adapter->pdev->dev, + "Link state change on VF %d failed: %#x\n", vf, status); + return be_cmd_status(status); + } - return status; + adapter->vf_cfg[vf].plink_tracking = link_state; + + return 0; } static void be_aic_update(struct be_aic_obj *aic, u64 rx_pkts, u64 tx_pkts, -- cgit v1.2.3 From 6bdf8f55d27707ea3f7af0aaddf0e3bb79cf6aed Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 17 Jul 2014 16:20:25 +0530 Subject: be2net: update UE bit description strings This patch updates some description strings for BEx/Skyhawk-R UE (unrecoverable error) status register bits. The appropriate strings are logged when a UE is detected in the adapter. Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 988f7658c960..38f35e2d7a63 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -81,10 +81,10 @@ static const char * const ue_status_low_desc[] = { "P1_OB_LINK ", "HOST_GPIO ", "MBOX ", - "AXGMAC0", - "AXGMAC1", - "JTAG", - "MPU_INTPEND" + "ERX2 ", + "SPARE ", + "JTAG ", + "MPU_INTPEND " }; /* UE Status High CSR */ static const char * const ue_status_hi_desc[] = { @@ -109,16 +109,16 @@ static const char * const ue_status_hi_desc[] = { "HOST5", "HOST6", "HOST7", - "HOST8", - "HOST9", + "ECRC", + "Poison TLP", "NETC", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", + "PERIPH", + "LLTXULP", + "D2P", + "RCON", + "LDMA", + "LLTXP", + "LLTXPB", "Unknown" }; -- cgit v1.2.3 From e97e3cda5b43edf250f67cbf90b1d438ee56b2dc Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 17 Jul 2014 16:20:26 +0530 Subject: be2net: reduce arguments passed to FW-cmd routines A pointer to adapter struct is passed anyway to all of the FW-cmd routines in be_cmds.c. For routines which query data from FW, the adapter pointer is enough to return the queried fields. There is no need to separately pass pointers to individual members of the adapter structure. This patch fixes this for be_cmd_get_fw_ver() and be_cmd_get_fw_cfg() routines. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 19 ++++++++----------- drivers/net/ethernet/emulex/benet/be_cmds.h | 6 ++---- drivers/net/ethernet/emulex/benet/be_main.c | 10 +++------- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index e632bd2d561c..791094c33535 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1749,8 +1749,7 @@ err: } /* Uses synchronous mcc */ -int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver, - char *fw_on_flash) +int be_cmd_get_fw_ver(struct be_adapter *adapter) { struct be_mcc_wrb *wrb; struct be_cmd_req_get_fw_version *req; @@ -1772,9 +1771,8 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver, status = be_mcc_notify_wait(adapter); if (!status) { struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb); - strcpy(fw_ver, resp->firmware_version_string); - if (fw_on_flash) - strcpy(fw_on_flash, resp->fw_on_flash_version_string); + strcpy(adapter->fw_ver, resp->firmware_version_string); + strcpy(adapter->fw_on_flash, resp->fw_on_flash_version_string); } err: spin_unlock_bh(&adapter->mcc_lock); @@ -1997,8 +1995,7 @@ err: } /* Uses mbox */ -int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, - u32 *mode, u32 *caps, u16 *asic_rev) +int be_cmd_query_fw_cfg(struct be_adapter *adapter) { struct be_mcc_wrb *wrb; struct be_cmd_req_query_fw_cfg *req; @@ -2017,10 +2014,10 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, status = be_mbox_notify_wait(adapter); if (!status) { struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb); - *port_num = le32_to_cpu(resp->phys_port); - *mode = le32_to_cpu(resp->function_mode); - *caps = le32_to_cpu(resp->function_caps); - *asic_rev = le32_to_cpu(resp->asic_revision) & 0xFF; + adapter->port_num = le32_to_cpu(resp->phys_port); + adapter->function_mode = le32_to_cpu(resp->function_mode); + adapter->function_caps = le32_to_cpu(resp->function_caps); + adapter->asic_rev = le32_to_cpu(resp->asic_revision) & 0xFF; } mutex_unlock(&adapter->mbox_lock); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index c0f7167049b7..a9219a94d37d 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -2071,16 +2071,14 @@ int be_cmd_reset(struct be_adapter *adapter); int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd); int lancer_cmd_get_pport_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd); -int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver, - char *fw_on_flash); +int be_cmd_get_fw_ver(struct be_adapter *adapter); int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *, int num); int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, u32 num); int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status); int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc); int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc); -int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, - u32 *function_mode, u32 *function_caps, u16 *asic_rev); +int be_cmd_query_fw_cfg(struct be_adapter *adapter); int be_cmd_reset_function(struct be_adapter *adapter); int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u32 rss_hash_opts, u16 table_size, const u8 *rss_hkey); diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 38f35e2d7a63..8ffcffab62f8 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3425,10 +3425,7 @@ static int be_get_config(struct be_adapter *adapter) u16 profile_id; int status; - status = be_cmd_query_fw_cfg(adapter, &adapter->port_num, - &adapter->function_mode, - &adapter->function_caps, - &adapter->asic_rev); + status = be_cmd_query_fw_cfg(adapter); if (status) return status; @@ -3617,7 +3614,7 @@ static int be_setup(struct be_adapter *adapter) if (status) goto err; - be_cmd_get_fw_ver(adapter, adapter->fw_ver, adapter->fw_on_flash); + be_cmd_get_fw_ver(adapter); if (BE2_chip(adapter) && fw_major_num(adapter->fw_ver) < 4) { dev_err(dev, "Firmware on card is old(%s), IRQs may not work.", @@ -4247,8 +4244,7 @@ int be_load_fw(struct be_adapter *adapter, u8 *fw_file) status = be_fw_download(adapter, fw); if (!status) - be_cmd_get_fw_ver(adapter, adapter->fw_ver, - adapter->fw_on_flash); + be_cmd_get_fw_ver(adapter); fw_exit: release_firmware(fw); -- cgit v1.2.3 From b99f8036ff04d30d27ab8144b409cecdcb0bf035 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 17 Jul 2014 16:20:27 +0530 Subject: be2net: remove unused structures in be_cmds.h Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.h | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index a9219a94d37d..03e8a15c6922 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1081,11 +1081,6 @@ struct be_cmd_req_modify_eq_delay { struct be_set_eqd set_eqd[MAX_EVT_QS]; } __packed; -struct be_cmd_resp_modify_eq_delay { - struct be_cmd_resp_hdr hdr; - u32 rsvd0; -} __packed; - /******************** Get FW Config *******************/ /* The HW can come up in either of the following multi-channel modes * based on the skew/IPL. @@ -1156,11 +1151,6 @@ struct be_cmd_req_enable_disable_beacon { u8 status_duration; } __packed; -struct be_cmd_resp_enable_disable_beacon { - struct be_cmd_resp_hdr resp_hdr; - u32 rsvd0; -} __packed; - struct be_cmd_req_get_beacon_state { struct be_cmd_req_hdr hdr; u8 port_num; @@ -1326,11 +1316,6 @@ struct be_cmd_req_set_lmode { u8 loopback_state; }; -struct be_cmd_resp_set_lmode { - struct be_cmd_resp_hdr resp_hdr; - u8 rsvd0[4]; -}; - /********************** DDR DMA test *********************/ struct be_cmd_req_ddrdma_test { struct be_cmd_req_hdr hdr; @@ -1434,11 +1419,6 @@ struct be_cmd_req_set_qos { u32 rsvd[7]; }; -struct be_cmd_resp_set_qos { - struct be_cmd_resp_hdr hdr; - u32 rsvd; -}; - /*********************** Controller Attributes ***********************/ struct be_cmd_req_cntl_attribs { struct be_cmd_req_hdr hdr; @@ -1572,11 +1552,6 @@ struct be_cmd_req_set_hsw_config { u8 context[sizeof(struct amap_set_hsw_context) / 8]; } __packed; -struct be_cmd_resp_set_hsw_config { - struct be_cmd_resp_hdr hdr; - u32 rsvd; -}; - struct amap_get_hsw_req_context { u8 interface_id[16]; u8 rsvd0[14]; @@ -1966,10 +1941,6 @@ struct be_cmd_req_set_profile_config { u8 desc[2 * RESOURCE_DESC_SIZE_V1]; } __packed; -struct be_cmd_resp_set_profile_config { - struct be_cmd_resp_hdr hdr; -}; - struct be_cmd_req_get_active_profile { struct be_cmd_req_hdr hdr; u32 rsvd; -- cgit v1.2.3 From ddf1169fec57c68f9ab561ac818b02aae95943b4 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 17 Jul 2014 16:20:28 +0530 Subject: be2net: use "if (!foo)" test style Replace "if (foo == NULL)" statements with "if (!foo)" to be consistent across the driver. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 8ffcffab62f8..75c8f111d1c6 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2034,7 +2034,7 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo) */ for (;;) { rxcp = be_rx_compl_get(rxo); - if (rxcp == NULL) { + if (!rxcp) { if (lancer_chip(adapter)) break; @@ -2941,7 +2941,7 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable) cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config); cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, GFP_KERNEL); - if (cmd.va == NULL) + if (!cmd.va) return -ENOMEM; if (enable) { @@ -4133,7 +4133,7 @@ lancer_fw_exit: static int be_get_ufi_type(struct be_adapter *adapter, struct flash_file_hdr_g3 *fhdr) { - if (fhdr == NULL) + if (!fhdr) goto be_get_ufi_exit; if (skyhawk_chip(adapter) && fhdr->build[0] == '4') @@ -4475,12 +4475,12 @@ static int be_map_pci_bars(struct be_adapter *adapter) if (BEx_chip(adapter) && be_physfn(adapter)) { adapter->csr = pci_iomap(adapter->pdev, 2, 0); - if (adapter->csr == NULL) + if (!adapter->csr) return -ENOMEM; } addr = pci_iomap(adapter->pdev, db_bar(adapter), 0); - if (addr == NULL) + if (!addr) goto pci_map_err; adapter->db = addr; @@ -4543,7 +4543,7 @@ static int be_ctrl_init(struct be_adapter *adapter) rx_filter->va = dma_zalloc_coherent(&adapter->pdev->dev, rx_filter->size, &rx_filter->dma, GFP_KERNEL); - if (rx_filter->va == NULL) { + if (!rx_filter->va) { status = -ENOMEM; goto free_mbox; } @@ -4592,7 +4592,7 @@ static int be_stats_init(struct be_adapter *adapter) cmd->va = dma_zalloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma, GFP_KERNEL); - if (cmd->va == NULL) + if (!cmd->va) return -ENOMEM; return 0; } @@ -4814,7 +4814,7 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) pci_set_master(pdev); netdev = alloc_etherdev_mqs(sizeof(*adapter), MAX_TX_QS, MAX_RX_QS); - if (netdev == NULL) { + if (!netdev) { status = -ENOMEM; goto rel_reg; } -- cgit v1.2.3 From d3518e215af9545eeac1046eec84cde525bae2a5 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 17 Jul 2014 16:20:29 +0530 Subject: be2net: use be_max_vfs() macro to access max-vfs max-vfs value must be accessed via the macro be_max_vfs(adapter). The earlier patch "create optimal number of queues on SR-IOV config" by mistake, did not use this macro. This patch fixes it. fixes: bec84e6b ("be2net: create optimal number of queues on SR-IOV config") Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 75c8f111d1c6..3475bdbe7ee3 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3312,7 +3312,7 @@ static void BEx_get_resources(struct be_adapter *adapter, res->max_rx_qs = res->max_rss_qs + 1; if (be_physfn(adapter)) - res->max_evt_qs = (res->max_vfs > 0) ? + res->max_evt_qs = (be_max_vfs(adapter) > 0) ? BE3_SRIOV_MAX_EVT_QS : BE3_MAX_EVT_QS; else res->max_evt_qs = 1; -- cgit v1.2.3 From 962bcb750b47ef0c8d28cc217ec22b4e44413565 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 17 Jul 2014 16:20:30 +0530 Subject: be2net: avoid SRIOV config for BE2 chip As SRIOV is not supported on BE2 chip, avoid calling be_get/set_sriov_config() for BE2 chip. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 3475bdbe7ee3..9ee445c8096e 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3434,7 +3434,9 @@ static int be_get_config(struct be_adapter *adapter) if (!status) dev_info(&adapter->pdev->dev, "Using profile 0x%x\n", profile_id); + } + if (!BE2_chip(adapter) && be_physfn(adapter)) { status = be_get_sriov_config(adapter); if (status) return status; -- cgit v1.2.3 From f174c7ec10d99e62f7722d0608b2a881ef091d21 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 17 Jul 2014 16:20:31 +0530 Subject: be2net: use adapter->flags to track SRIOV state The driver so far used adapter->num_vfs value to check if SR-IOV is enabled or not. But, the patch bec84e6("create optimal number of queues on SR-IOV config") changed this logic. The adapter->num_vfs value is validated and set much before SR-IOV is enabled. So, we now use an explicit flag to track SR-IOV enabled state. Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 4 +++- drivers/net/ethernet/emulex/benet/be_main.c | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 3e639e86e111..25cd3c9007e5 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -372,6 +372,7 @@ enum vf_state { }; #define BE_FLAGS_LINK_STATUS_INIT 1 +#define BE_FLAGS_SRIOV_ENABLED (1 << 2) #define BE_FLAGS_WORKER_SCHEDULED (1 << 3) #define BE_FLAGS_VLAN_PROMISC (1 << 4) #define BE_FLAGS_MCAST_PROMISC (1 << 5) @@ -525,7 +526,8 @@ struct be_adapter { #define be_physfn(adapter) (!adapter->virtfn) #define be_virtfn(adapter) (adapter->virtfn) -#define sriov_enabled(adapter) (adapter->num_vfs > 0) +#define sriov_enabled(adapter) (adapter->flags & \ + BE_FLAGS_SRIOV_ENABLED) #define for_all_vfs(adapter, vf_cfg, i) \ for (i = 0, vf_cfg = &adapter->vf_cfg[i]; i < adapter->num_vfs; \ diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 9ee445c8096e..9c50814f1e95 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3049,6 +3049,7 @@ static void be_vf_clear(struct be_adapter *adapter) done: kfree(adapter->vf_cfg); adapter->num_vfs = 0; + adapter->flags &= ~BE_FLAGS_SRIOV_ENABLED; } static void be_clear_queues(struct be_adapter *adapter) @@ -3241,6 +3242,8 @@ static int be_vf_setup(struct be_adapter *adapter) goto err; } } + + adapter->flags |= BE_FLAGS_SRIOV_ENABLED; return 0; err: dev_err(dev, "VF setup failed\n"); -- cgit v1.2.3 From c346e6e51fce86714d64e395a966a1d7d91f1c48 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Thu, 17 Jul 2014 16:20:32 +0530 Subject: be2net: update driver version to 10.4 Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 25cd3c9007e5..0048ef8e5f35 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -34,7 +34,7 @@ #include "be_hw.h" #include "be_roce.h" -#define DRV_VER "10.2u" +#define DRV_VER "10.4u" #define DRV_NAME "be2net" #define BE_NAME "Emulex BladeEngine2" #define BE3_NAME "Emulex BladeEngine3" -- cgit v1.2.3 From 8ccf3800dbdeaf26bcdefa471c9c8e0da7e6ec7a Mon Sep 17 00:00:00 2001 From: Andrew Rybchenko Date: Thu, 17 Jul 2014 12:10:43 +0100 Subject: sfc: Add per-queue statistics in ethtool Implement per channel software TX and RX packet counters accessed as ethtool statistics. This allows confirmation with MAC statistics. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ethtool.c | 58 +++++++++++++++++++++++++++++++++-- drivers/net/ethernet/sfc/net_driver.h | 4 +++ drivers/net/ethernet/sfc/rx.c | 2 ++ drivers/net/ethernet/sfc/tx.c | 4 +++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 03fe4e715024..cad258a78708 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -359,6 +359,37 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, return n; } +static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings) +{ + size_t n_stats = 0; + struct efx_channel *channel; + + efx_for_each_channel(channel, efx) { + if (efx_channel_has_tx_queues(channel)) { + n_stats++; + if (strings != NULL) { + snprintf(strings, ETH_GSTRING_LEN, + "tx-%u.tx_packets", + channel->tx_queue[0].queue / + EFX_TXQ_TYPES); + + strings += ETH_GSTRING_LEN; + } + } + } + efx_for_each_channel(channel, efx) { + if (efx_channel_has_rx_queue(channel)) { + n_stats++; + if (strings != NULL) { + snprintf(strings, ETH_GSTRING_LEN, + "rx-%d.rx_packets", channel->channel); + strings += ETH_GSTRING_LEN; + } + } + } + return n_stats; +} + static int efx_ethtool_get_sset_count(struct net_device *net_dev, int string_set) { @@ -367,8 +398,9 @@ static int efx_ethtool_get_sset_count(struct net_device *net_dev, switch (string_set) { case ETH_SS_STATS: return efx->type->describe_stats(efx, NULL) + - EFX_ETHTOOL_SW_STAT_COUNT + - efx_ptp_describe_stats(efx, NULL); + EFX_ETHTOOL_SW_STAT_COUNT + + efx_describe_per_queue_stats(efx, NULL) + + efx_ptp_describe_stats(efx, NULL); case ETH_SS_TEST: return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL); default: @@ -390,6 +422,8 @@ static void efx_ethtool_get_strings(struct net_device *net_dev, strlcpy(strings + i * ETH_GSTRING_LEN, efx_sw_stat_desc[i].name, ETH_GSTRING_LEN); strings += EFX_ETHTOOL_SW_STAT_COUNT * ETH_GSTRING_LEN; + strings += (efx_describe_per_queue_stats(efx, strings) * + ETH_GSTRING_LEN); efx_ptp_describe_stats(efx, strings); break; case ETH_SS_TEST: @@ -409,6 +443,7 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, const struct efx_sw_stat_desc *stat; struct efx_channel *channel; struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; int i; spin_lock_bh(&efx->stats_lock); @@ -444,6 +479,25 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, spin_unlock_bh(&efx->stats_lock); + efx_for_each_channel(channel, efx) { + if (efx_channel_has_tx_queues(channel)) { + *data = 0; + efx_for_each_channel_tx_queue(tx_queue, channel) { + *data += tx_queue->tx_packets; + } + data++; + } + } + efx_for_each_channel(channel, efx) { + if (efx_channel_has_rx_queue(channel)) { + *data = 0; + efx_for_each_channel_rx_queue(rx_queue, channel) { + *data += rx_queue->rx_packets; + } + data++; + } + } + efx_ptp_update_stats(efx, data); } diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 8a02d45ed667..fb2e3bfeb2c2 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -249,6 +249,8 @@ struct efx_tx_queue { unsigned int tso_packets; unsigned int pushes; unsigned int pio_packets; + /* Statistics to supplement MAC stats */ + unsigned long tx_packets; /* Members shared between paths and sometimes updated */ unsigned int empty_read_count ____cacheline_aligned_in_smp; @@ -358,6 +360,8 @@ struct efx_rx_queue { unsigned int recycle_count; struct timer_list slow_fill; unsigned int slow_fill_count; + /* Statistics to supplement MAC stats */ + unsigned long rx_packets; }; enum efx_sync_events_state { diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index bf537a2a901f..a7bb63a7a521 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -530,6 +530,8 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, struct efx_channel *channel = efx_rx_queue_channel(rx_queue); struct efx_rx_buffer *rx_buf; + rx_queue->rx_packets++; + rx_buf = efx_rx_buffer(rx_queue, index); rx_buf->flags |= flags; diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index ede8dcca0ff3..283e5f87b09f 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -452,6 +452,8 @@ finish_packet: /* Pass off to hardware */ efx_nic_push_buffers(tx_queue); + tx_queue->tx_packets++; + efx_tx_maybe_stop_queue(tx_queue); return NETDEV_TX_OK; @@ -1245,6 +1247,8 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, ++tx_queue->tso_packets; + ++tx_queue->tx_packets; + return 0; } -- cgit v1.2.3 From da388973d4a15e71cada1219d625b5393c90e5ae Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 17 Jul 2014 22:31:03 +0530 Subject: iw_cxgb4: fix for 64-bit integer division Fixed error introduced in commit id 7730b4c (" cxgb4/iw_cxgb4: work request logging feature") while compiling on 32 bit architecture reported by kbuild. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index df1f1b52c7ec..03b6fa1291bf 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -150,7 +151,7 @@ static int wr_log_show(struct seq_file *seq, void *v) int prev_ts_set = 0; int idx, end; -#define ts2ns(ts) ((ts) * dev->rdev.lldi.cclk_ps / 1000) +#define ts2ns(ts) div64_ul((ts) * dev->rdev.lldi.cclk_ps, 1000) idx = atomic_read(&dev->rdev.wr_log_idx) & (dev->rdev.wr_log_size - 1); -- cgit v1.2.3 From 1d4cc30c86301543a09ff4118a36044546c7cfa1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 18 Jul 2014 09:47:26 +0200 Subject: mac80211: suppress unused variable warning without lockdep When lockdep isn't compiled, a local variable isn't used (it's only in a macro argument), annotate it to suppress the compiler warning. Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index c3fd4d275bf4..6d537f03c0ba 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -66,7 +66,7 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local) static struct ieee80211_chanctx * ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata) { - struct ieee80211_local *local = sdata->local; + struct ieee80211_local *local __maybe_unused = sdata->local; struct ieee80211_chanctx_conf *conf; conf = rcu_dereference_protected(sdata->vif.chanctx_conf, -- cgit v1.2.3 From beb19e4c079d626bf0502fbb65bd7c9891a10c2e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 18 Jul 2014 11:15:26 +0300 Subject: Bluetooth: Use EOPNOTSUPP instead of ENOTSUPP The EOPNOTSUPP and ENOTSUPP errors are very similar in meaning, but ENOTSUPP is a fairly new addition to POSIX. Not all libc versions know about the value the kernel uses for ENOTSUPP so it's better to use EOPNOTSUPP to ensure understandable error messages. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/l2cap_core.c | 2 +- net/bluetooth/l2cap_sock.c | 2 +- net/bluetooth/smp.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 0d76054efd26..1ac9f7f52acd 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -834,7 +834,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, struct hci_conn *acl; if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) - return ERR_PTR(-ENOTSUPP); + return ERR_PTR(-EOPNOTSUPP); acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); if (!acl) { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c8c259f21d80..f3fb61c9f96f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7094,7 +7094,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, break; /* fall through */ default: - err = -ENOTSUPP; + err = -EOPNOTSUPP; goto done; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 3bb1cdf34f07..1884f72083c2 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -279,7 +279,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) break; /* fall through */ default: - err = -ENOTSUPP; + err = -EOPNOTSUPP; goto done; } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 74a0308e39f3..e49c83d8b957 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1189,7 +1189,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) } if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) { - err = -ENOTSUPP; + err = -EOPNOTSUPP; reason = SMP_PAIRING_NOTSUPP; goto done; } @@ -1207,7 +1207,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) !conn->smp_chan) { BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); kfree_skb(skb); - return -ENOTSUPP; + return -EOPNOTSUPP; } switch (code) { -- cgit v1.2.3 From 6508281b0b15c469a940ffa46bb9215c9e18eaf3 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 14 Jul 2014 09:49:37 +0300 Subject: wil6210: support for "sparrow" hardware New hardware release appears; it require some changes to properly support it. Introduce struct wil_board and "board" attribute in wil6210_priv; keep hardware variant information in this structure. fill it on probe(). Used in the reset flow. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/main.c | 42 +++++++++++++++++++++++------ drivers/net/wireless/ath/wil6210/pcie_bus.c | 22 ++++++++++++--- drivers/net/wireless/ath/wil6210/wil6210.h | 10 +++++++ 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 53a689ed7c7d..3704d2a434f3 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -314,8 +314,9 @@ static void wil_target_reset(struct wil6210_priv *wil) int delay = 0; u32 hw_state; u32 rev_id; + bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW); - wil_dbg_misc(wil, "Resetting...\n"); + wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name); /* register read */ #define R(a) ioread32(wil->csr + HOSTADDR(a)) @@ -328,35 +329,59 @@ static void wil_target_reset(struct wil6210_priv *wil) wil->hw_version = R(RGF_USER_FW_REV_ID); rev_id = wil->hw_version & 0xff; + + /* Clear MAC link up */ + S(RGF_HP_CTRL, BIT(15)); /* hpal_perst_from_pad_src_n_mask */ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); /* car_perst_rst_src_n_mask */ S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7)); wmb(); /* order is important here */ + if (is_sparrow) { + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); + wmb(); /* order is important here */ + } + W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ wmb(); /* order is important here */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000B0 : 0x00000170); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00); wmb(); /* order is important here */ + if (is_sparrow) { + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); + wmb(); /* order is important here */ + } + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); wmb(); /* order is important here */ - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); - if (rev_id == 1) { - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); - } else { - W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); + if (is_sparrow) { + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); + /* reset A2 PCIE AHB */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); + + } else { + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); + if (rev_id == 1) { + /* reset A1 BOTH PCIE AHB & PCIE RGF */ + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); + } else { + W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); + } + } + + /* TODO: check order here!!! Erez code is different */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); wmb(); /* order is important here */ @@ -371,7 +396,8 @@ static void wil_target_reset(struct wil6210_priv *wil) } } while (hw_state != HW_MACHINE_BOOT_DONE); - if (rev_id == 2) + /* TODO: Erez check rev_id != 1 */ + if (!is_sparrow && (rev_id != 1)) W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 77b6272d93fb..d3fbfa28db62 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -122,10 +122,12 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct wil6210_priv *wil; struct device *dev = &pdev->dev; void __iomem *csr; + struct wil_board *board = (struct wil_board *)id->driver_data; int rc; /* check HW */ - dev_info(&pdev->dev, WIL_NAME " device found [%04x:%04x] (rev %x)\n", + dev_info(&pdev->dev, WIL_NAME + " \"%s\" device found [%04x:%04x] (rev %x)\n", board->name, (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { @@ -175,6 +177,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, wil); wil->pdev = pdev; + wil->board = board; wil6210_clear_irq(wil); /* FW should raise IRQ when ready */ @@ -225,8 +228,21 @@ static void wil_pcie_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static DEFINE_PCI_DEVICE_TABLE(wil6210_pcie_ids) = { - { PCI_DEVICE(0x1ae9, 0x0301) }, +static const struct wil_board wil_board_marlon = { + .board = WIL_BOARD_MARLON, + .name = "marlon", +}; + +static const struct wil_board wil_board_sparrow = { + .board = WIL_BOARD_SPARROW, + .name = "sparrow", +}; + +static const struct pci_device_id wil6210_pcie_ids[] = { + { PCI_DEVICE(0x1ae9, 0x0301), + .driver_data = (kernel_ulong_t)&wil_board_marlon }, + { PCI_DEVICE(0x1ae9, 0x0310), + .driver_data = (kernel_ulong_t)&wil_board_sparrow }, { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 424906635f05..09c36a7a32e0 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -24,6 +24,13 @@ #define WIL_NAME "wil6210" +struct wil_board { + int board; +#define WIL_BOARD_MARLON (1) +#define WIL_BOARD_SPARROW (2) + const char * const name; +}; + /** * extract bits [@b0:@b1] (inclusive) from the value @x * it should be @b0 <= @b1, or result is incorrect @@ -93,6 +100,7 @@ struct RGF_ICR { #define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) #define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) +#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0 (0x880c18) #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) @@ -121,6 +129,7 @@ struct RGF_ICR { #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1) #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) +#define RGF_HP_CTRL (0x88265c) #define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4) /* popular locations */ @@ -365,6 +374,7 @@ struct wil6210_priv { ulong status; u32 fw_version; u32 hw_version; + struct wil_board *board; u8 n_mids; /* number of additional MIDs as reported by FW */ int recovery_count; /* num of FW recovery attempts in a short time */ unsigned long last_fw_recovery; /* jiffies of last fw recovery */ -- cgit v1.2.3 From 6f55007d0e9d179d5893a518a9466c0abbcfa1ca Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 14 Jul 2014 09:49:38 +0300 Subject: wil6210: export FW/HW versions through debugfs Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index a868c5eebe37..7435b5a256ab 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -986,6 +986,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) &wil->secure_pcp); wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg, &wil->status); + debugfs_create_u32("fw_version", S_IRUGO, dbg, &wil->fw_version); + debugfs_create_x32("hw_version", S_IRUGO, dbg, &wil->hw_version); wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg, HOSTADDR(RGF_USER_USER_ICR)); -- cgit v1.2.3 From 76dfa4b7715679b8f90499745c071d44472c200c Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 14 Jul 2014 09:49:39 +0300 Subject: wil6210: fix double definition of 'ctx' Variable 'ctx' declarad again in the inner loop. Should use one from outer loop instead. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/txrx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index af4b93e4beb5..d3467943d39d 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1108,8 +1108,10 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) while (vring->swtail != new_swtail) { struct vring_tx_desc dd, *d = ⅆ u16 dmalen; - struct wil_ctx *ctx = &vring->ctx[vring->swtail]; - struct sk_buff *skb = ctx->skb; + struct sk_buff *skb; + + ctx = &vring->ctx[vring->swtail]; + skb = ctx->skb; _d = &vring->va[vring->swtail].tx; *d = *_d; -- cgit v1.2.3 From 359ee6275368c6fc8c6143f706e1b0075a244070 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 14 Jul 2014 09:49:40 +0300 Subject: wil6210: fix memory leak on error path in wil_write_file_rxon() If copy_from_user() fails, buffer allocated for parameters would leak Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 7435b5a256ab..b6400680850a 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -448,8 +448,10 @@ static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf, char *kbuf = kmalloc(len + 1, GFP_KERNEL); if (!kbuf) return -ENOMEM; - if (copy_from_user(kbuf, buf, len)) + if (copy_from_user(kbuf, buf, len)) { + kfree(kbuf); return -EIO; + } kbuf[len] = '\0'; rc = kstrtol(kbuf, 0, &channel); -- cgit v1.2.3 From b541d0a0266ddcb6560cf4192ce26f05ec716386 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 14 Jul 2014 09:49:41 +0300 Subject: wil6210: use same mapping table for FW addr translation and debugfs Use single data source for all information regarding the firmware memory map. With this change "ucode_xxx" regions disappears since they are in fact part of larger "upper area" region Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 49 +++++++++++++----------------- drivers/net/wireless/ath/wil6210/wil6210.h | 15 +++++---- drivers/net/wireless/ath/wil6210/wmi.c | 20 ++++++------ 3 files changed, 39 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index b6400680850a..d5b095d404e1 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -965,6 +965,26 @@ static const struct file_operations fops_sta = { }; /*----------------*/ +static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil, + struct dentry *dbg) +{ + int i; + char name[32]; + + for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { + struct debugfs_blob_wrapper *blob = &wil->blobs[i]; + const struct fw_map *map = &fw_mapping[i]; + + if (!map->name) + continue; + + blob->data = (void * __force)wil->csr + HOSTADDR(map->host); + blob->size = map->to - map->from; + snprintf(name, sizeof(name), "blob_%s", map->name); + wil_debugfs_create_ioblob(name, S_IRUGO, dbg, blob); + } +} + int wil6210_debugfs_init(struct wil6210_priv *wil) { struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, @@ -1014,34 +1034,7 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link); debugfs_create_file("info", S_IRUGO, dbg, wil, &fops_info); - wil->rgf_blob.data = (void * __force)wil->csr + 0; - wil->rgf_blob.size = 0xa000; - wil_debugfs_create_ioblob("blob_rgf", S_IRUGO, dbg, &wil->rgf_blob); - - wil->fw_code_blob.data = (void * __force)wil->csr + 0x40000; - wil->fw_code_blob.size = 0x40000; - wil_debugfs_create_ioblob("blob_fw_code", S_IRUGO, dbg, - &wil->fw_code_blob); - - wil->fw_data_blob.data = (void * __force)wil->csr + 0x80000; - wil->fw_data_blob.size = 0x8000; - wil_debugfs_create_ioblob("blob_fw_data", S_IRUGO, dbg, - &wil->fw_data_blob); - - wil->fw_peri_blob.data = (void * __force)wil->csr + 0x88000; - wil->fw_peri_blob.size = 0x18000; - wil_debugfs_create_ioblob("blob_fw_peri", S_IRUGO, dbg, - &wil->fw_peri_blob); - - wil->uc_code_blob.data = (void * __force)wil->csr + 0xa0000; - wil->uc_code_blob.size = 0x10000; - wil_debugfs_create_ioblob("blob_uc_code", S_IRUGO, dbg, - &wil->uc_code_blob); - - wil->uc_data_blob.data = (void * __force)wil->csr + 0xb0000; - wil->uc_data_blob.size = 0x4000; - wil_debugfs_create_ioblob("blob_uc_data", S_IRUGO, dbg, - &wil->uc_data_blob); + wil6210_debugfs_init_blobs(wil, dbg); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 09c36a7a32e0..02205b09fb50 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -144,6 +144,14 @@ struct RGF_ICR { #define ISR_MISC_FW_ERROR BIT_DMA_EP_MISC_ICR_FW_INT(3) /* Hardware definitions end */ +struct fw_map { + u32 from; /* linker address - from, inclusive */ + u32 to; /* linker address - to, exclusive */ + u32 host; /* PCI/Host address - BAR0 + 0x880000 */ + const char *name; /* for debugfs */ +}; +/* array size should be in sync with actual definition in the wmi.c */ +extern const struct fw_map fw_mapping[6]; /** * mk_cidxtid - construct @cidxtid field @@ -425,12 +433,7 @@ struct wil6210_priv { atomic_t isr_count_rx, isr_count_tx; /* debugfs */ struct dentry *debug; - struct debugfs_blob_wrapper fw_code_blob; - struct debugfs_blob_wrapper fw_data_blob; - struct debugfs_blob_wrapper fw_peri_blob; - struct debugfs_blob_wrapper uc_code_blob; - struct debugfs_blob_wrapper uc_data_blob; - struct debugfs_blob_wrapper rgf_blob; + struct debugfs_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)]; }; #define wil_to_wiphy(i) (i->wdev->wiphy) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index a136dab560e2..084c3de21c56 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -65,18 +65,16 @@ /** * @fw_mapping provides memory remapping table + * + * array size should be in sync with the declaration in the wil6210.h */ -static const struct { - u32 from; /* linker address - from, inclusive */ - u32 to; /* linker address - to, exclusive */ - u32 host; /* PCI/Host address - BAR0 + 0x880000 */ -} fw_mapping[] = { - {0x000000, 0x040000, 0x8c0000}, /* FW code RAM 256k */ - {0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */ - {0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */ - {0x880000, 0x88a000, 0x880000}, /* various RGF */ - {0x88b000, 0x88c000, 0x88b000}, /* Pcie_ext_rgf */ - {0x8c0000, 0x949000, 0x8c0000}, /* trivial mapping for upper area */ +const struct fw_map fw_mapping[] = { + {0x000000, 0x040000, 0x8c0000, "fw_code"}, /* FW code RAM 256k */ + {0x800000, 0x808000, 0x900000, "fw_data"}, /* FW data RAM 32k */ + {0x840000, 0x860000, 0x908000, "fw_peri"}, /* periph. data RAM 128k */ + {0x880000, 0x88a000, 0x880000, "rgf"}, /* various RGF 40k */ + {0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf 4k */ + {0x8c0000, 0x949000, 0x8c0000, "upper"}, /* upper area 548k */ /* * 920000..930000 ucode code RAM * 930000..932000 ucode data RAM -- cgit v1.2.3 From b373de72c6795e79bd66f046ced9925b08806df9 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 14 Jul 2014 09:49:42 +0300 Subject: wil6210: map RGF_USER_USAGE_1 on the debugfs Firmware sets this register with the offset of the firmware trace area within the peripheral memory region. Critical for the firmware trace to work Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/debugfs.c | 3 +++ drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index d5b095d404e1..8f66186adb8c 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1022,6 +1022,9 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) wil6210_debugfs_create_pseudo_ISR(wil, dbg); wil6210_debugfs_create_ITR_CNT(wil, dbg); + wil_debugfs_create_iomem_x32("RGF_USER_USAGE_1", S_IRUGO, dbg, + wil->csr + + HOSTADDR(RGF_USER_USAGE_1)); debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr); debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 02205b09fb50..a78aaaba59bd 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -85,6 +85,7 @@ struct RGF_ICR { } __packed; /* registers - FW addresses */ +#define RGF_USER_USAGE_1 (0x880004) #define RGF_USER_HW_MACHINE_STATE (0x8801dc) #define HW_MACHINE_BOOT_DONE (0x3fffffd) #define RGF_USER_USER_CPU_0 (0x8801e0) -- cgit v1.2.3 From 72269146afabf1656f867f715f40a7dd470499fb Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 14 Jul 2014 09:49:43 +0300 Subject: wil6210: add new register region for AGC table New register area defined in the firmware Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville --- drivers/net/wireless/ath/wil6210/wil6210.h | 2 +- drivers/net/wireless/ath/wil6210/wmi.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index a78aaaba59bd..67e9624f7111 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -152,7 +152,7 @@ struct fw_map { const char *name; /* for debugfs */ }; /* array size should be in sync with actual definition in the wmi.c */ -extern const struct fw_map fw_mapping[6]; +extern const struct fw_map fw_mapping[7]; /** * mk_cidxtid - construct @cidxtid field diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 084c3de21c56..1d1d0afdd2e1 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -73,6 +73,7 @@ const struct fw_map fw_mapping[] = { {0x800000, 0x808000, 0x900000, "fw_data"}, /* FW data RAM 32k */ {0x840000, 0x860000, 0x908000, "fw_peri"}, /* periph. data RAM 128k */ {0x880000, 0x88a000, 0x880000, "rgf"}, /* various RGF 40k */ + {0x88a000, 0x88b000, 0x88a000, "AGC_tbl"}, /* AGC table 4k */ {0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf 4k */ {0x8c0000, 0x949000, 0x8c0000, "upper"}, /* upper area 548k */ /* -- cgit v1.2.3 From 6ad59343ecd72dd3f83c4db3bcddbb0beabb4c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 15 Jul 2014 16:18:57 +0200 Subject: ssb: extract power info from SPROM revs 4 and 5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is needed to properly handle early 802.11n devices like BCM4321. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/ssb/pci.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/ssb/ssb_regs.h | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 6318364be590..0f28c08fcb3c 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -470,7 +470,15 @@ static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in) static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) { + static const u16 pwr_info_offset[] = { + SSB_SPROM4_PWR_INFO_CORE0, SSB_SPROM4_PWR_INFO_CORE1, + SSB_SPROM4_PWR_INFO_CORE2, SSB_SPROM4_PWR_INFO_CORE3 + }; u16 il0mac_offset; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != + ARRAY_SIZE(out->core_pwr_info)); if (out->revision == 4) il0mac_offset = SSB_SPROM4_IL0MAC; @@ -543,6 +551,43 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT); + /* Extract cores power info info */ + for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { + u16 o = pwr_info_offset[i]; + + SPEX(core_pwr_info[i].itssi_2g, o + SSB_SPROM4_2G_MAXP_ITSSI, + SSB_SPROM4_2G_ITSSI, SSB_SPROM4_2G_ITSSI_SHIFT); + SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SPROM4_2G_MAXP_ITSSI, + SSB_SPROM4_2G_MAXP, 0); + + SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SPROM4_2G_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SPROM4_2G_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SPROM4_2G_PA_2, ~0, 0); + SPEX(core_pwr_info[i].pa_2g[3], o + SSB_SPROM4_2G_PA_3, ~0, 0); + + SPEX(core_pwr_info[i].itssi_5g, o + SSB_SPROM4_5G_MAXP_ITSSI, + SSB_SPROM4_5G_ITSSI, SSB_SPROM4_5G_ITSSI_SHIFT); + SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SPROM4_5G_MAXP_ITSSI, + SSB_SPROM4_5G_MAXP, 0); + SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM4_5GHL_MAXP, + SSB_SPROM4_5GH_MAXP, 0); + SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM4_5GHL_MAXP, + SSB_SPROM4_5GL_MAXP, SSB_SPROM4_5GL_MAXP_SHIFT); + + SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SPROM4_5GL_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SPROM4_5GL_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SPROM4_5GL_PA_2, ~0, 0); + SPEX(core_pwr_info[i].pa_5gl[3], o + SSB_SPROM4_5GL_PA_3, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SPROM4_5G_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SPROM4_5G_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SPROM4_5G_PA_2, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[3], o + SSB_SPROM4_5G_PA_3, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SPROM4_5GH_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SPROM4_5GH_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SPROM4_5GH_PA_2, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[3], o + SSB_SPROM4_5GH_PA_3, ~0, 0); + } + sprom_extract_r458(out, in); /* TODO - get remaining rev 4 stuff needed */ diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index f9f931c89e3e..f7b9100686c3 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -345,6 +345,43 @@ #define SSB_SPROM4_TXPID5GH2_SHIFT 0 #define SSB_SPROM4_TXPID5GH3 0xFF00 #define SSB_SPROM4_TXPID5GH3_SHIFT 8 + +/* There are 4 blocks with power info sharing the same layout */ +#define SSB_SPROM4_PWR_INFO_CORE0 0x0080 +#define SSB_SPROM4_PWR_INFO_CORE1 0x00AE +#define SSB_SPROM4_PWR_INFO_CORE2 0x00DC +#define SSB_SPROM4_PWR_INFO_CORE3 0x010A + +#define SSB_SPROM4_2G_MAXP_ITSSI 0x00 /* 2 GHz ITSSI and 2 GHz Max Power */ +#define SSB_SPROM4_2G_MAXP 0x00FF +#define SSB_SPROM4_2G_ITSSI 0xFF00 +#define SSB_SPROM4_2G_ITSSI_SHIFT 8 +#define SSB_SPROM4_2G_PA_0 0x02 /* 2 GHz power amp */ +#define SSB_SPROM4_2G_PA_1 0x04 +#define SSB_SPROM4_2G_PA_2 0x06 +#define SSB_SPROM4_2G_PA_3 0x08 +#define SSB_SPROM4_5G_MAXP_ITSSI 0x0A /* 5 GHz ITSSI and 5.3 GHz Max Power */ +#define SSB_SPROM4_5G_MAXP 0x00FF +#define SSB_SPROM4_5G_ITSSI 0xFF00 +#define SSB_SPROM4_5G_ITSSI_SHIFT 8 +#define SSB_SPROM4_5GHL_MAXP 0x0C /* 5.2 GHz and 5.8 GHz Max Power */ +#define SSB_SPROM4_5GH_MAXP 0x00FF +#define SSB_SPROM4_5GL_MAXP 0xFF00 +#define SSB_SPROM4_5GL_MAXP_SHIFT 8 +#define SSB_SPROM4_5G_PA_0 0x0E /* 5.3 GHz power amp */ +#define SSB_SPROM4_5G_PA_1 0x10 +#define SSB_SPROM4_5G_PA_2 0x12 +#define SSB_SPROM4_5G_PA_3 0x14 +#define SSB_SPROM4_5GL_PA_0 0x16 /* 5.2 GHz power amp */ +#define SSB_SPROM4_5GL_PA_1 0x18 +#define SSB_SPROM4_5GL_PA_2 0x1A +#define SSB_SPROM4_5GL_PA_3 0x1C +#define SSB_SPROM4_5GH_PA_0 0x1E /* 5.8 GHz power amp */ +#define SSB_SPROM4_5GH_PA_1 0x20 +#define SSB_SPROM4_5GH_PA_2 0x22 +#define SSB_SPROM4_5GH_PA_3 0x24 + +/* TODO: Make it deprecated */ #define SSB_SPROM4_MAXP_BG 0x0080 /* Max Power BG in path 1 */ #define SSB_SPROM4_MAXP_BG_MASK 0x00FF /* Mask for Max Power BG */ #define SSB_SPROM4_ITSSI_BG 0xFF00 /* Mask for path 1 itssi_bg */ -- cgit v1.2.3 From d8aef3239e7d6a1bd550014ac766e5ec11c63ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 15 Jul 2014 16:54:47 +0200 Subject: bcma: extract antenna gains from SPROM correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like in case of SSB SPROMs they are encoded in a bit tricky way. SPROM struct already uses s8 type and it's supposed to store decoded values. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/bcma/sprom.c | 41 +++++++++++++++++++++----- drivers/net/wireless/brcm80211/brcmsmac/main.c | 37 ----------------------- 2 files changed, 33 insertions(+), 45 deletions(-) diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 72bf4540f565..a9dfb1ac138d 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -201,6 +201,23 @@ static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom, SPEX(_field[7], _offset + 14, _mask, _shift); \ } while (0) +static s8 sprom_extract_antgain(const u16 *in, u16 offset, u16 mask, u16 shift) +{ + u16 v; + u8 gain; + + v = in[SPOFF(offset)]; + gain = (v & mask) >> shift; + if (gain == 0xFF) { + gain = 8; /* If unset use 2dBm */ + } else { + /* Q5.2 Fractional part is stored in 0xC0 */ + gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2); + } + + return (s8)gain; +} + static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) { u16 v, o; @@ -381,14 +398,22 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0); /* Extract the antenna gain values. */ - SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01, - SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT); - SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01, - SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT); - SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23, - SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT); - SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23, - SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT); + bus->sprom.antenna_gain.a0 = sprom_extract_antgain(sprom, + SSB_SPROM8_AGAIN01, + SSB_SPROM8_AGAIN0, + SSB_SPROM8_AGAIN0_SHIFT); + bus->sprom.antenna_gain.a1 = sprom_extract_antgain(sprom, + SSB_SPROM8_AGAIN01, + SSB_SPROM8_AGAIN1, + SSB_SPROM8_AGAIN1_SHIFT); + bus->sprom.antenna_gain.a2 = sprom_extract_antgain(sprom, + SSB_SPROM8_AGAIN23, + SSB_SPROM8_AGAIN2, + SSB_SPROM8_AGAIN2_SHIFT); + bus->sprom.antenna_gain.a3 = sprom_extract_antgain(sprom, + SSB_SPROM8_AGAIN23, + SSB_SPROM8_AGAIN3, + SSB_SPROM8_AGAIN3_SHIFT); SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, SSB_SPROM8_LEDDC_ON_SHIFT); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index af8ba64ace39..1b474828d5b8 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -4707,41 +4707,6 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, return err; } -static void brcms_c_attach_antgain_init(struct brcms_c_info *wlc) -{ - uint unit; - unit = wlc->pub->unit; - - if ((wlc->band->antgain == -1) && (wlc->pub->sromrev == 1)) { - /* default antenna gain for srom rev 1 is 2 dBm (8 qdbm) */ - wlc->band->antgain = 8; - } else if (wlc->band->antgain == -1) { - wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in" - " srom, using 2dB\n", unit, __func__); - wlc->band->antgain = 8; - } else { - s8 gain, fract; - /* Older sroms specified gain in whole dbm only. In order - * be able to specify qdbm granularity and remain backward - * compatible the whole dbms are now encoded in only - * low 6 bits and remaining qdbms are encoded in the hi 2 bits. - * 6 bit signed number ranges from -32 - 31. - * - * Examples: - * 0x1 = 1 db, - * 0xc1 = 1.75 db (1 + 3 quarters), - * 0x3f = -1 (-1 + 0 quarters), - * 0x7f = -.75 (-1 + 1 quarters) = -3 qdbm. - * 0xbf = -.50 (-1 + 2 quarters) = -2 qdbm. - */ - gain = wlc->band->antgain & 0x3f; - gain <<= 2; /* Sign extend */ - gain >>= 2; - fract = (wlc->band->antgain & 0xc0) >> 6; - wlc->band->antgain = 4 * gain + fract; - } -} - static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc) { int aa; @@ -4780,8 +4745,6 @@ static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc) else wlc->band->antgain = sprom->antenna_gain.a0; - brcms_c_attach_antgain_init(wlc); - return true; } -- cgit v1.2.3 From d1d3799fcb1037357b54be44e796a6253484268e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 15 Jul 2014 19:44:28 +0200 Subject: bcma: add support for BCM43217 found in Tenda W322E (14e4:43a9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/bcma/driver_chipcommon_pmu.c | 1 + drivers/bcma/host_pci.c | 1 + drivers/bcma/sprom.c | 1 + include/linux/bcma/bcma.h | 1 + 4 files changed, 4 insertions(+) diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index 5081a8c439cc..bb694e2e9f32 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -603,6 +603,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid) tmp = BCMA_CC_PMU_CTL_PLL_UPD | BCMA_CC_PMU_CTL_NOILPONW; break; + case BCMA_CHIP_ID_BCM43217: case BCMA_CHIP_ID_BCM43227: case BCMA_CHIP_ID_BCM43228: case BCMA_CHIP_ID_BCM43428: diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index e333305363aa..3cf725a49dc1 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -279,6 +279,7 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, { 0, }, }; diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index a9dfb1ac138d..97bb38e9ed65 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -534,6 +534,7 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus) /* for these chips OTP is always available */ present = true; break; + case BCMA_CHIP_ID_BCM43217: case BCMA_CHIP_ID_BCM43227: case BCMA_CHIP_ID_BCM43228: case BCMA_CHIP_ID_BCM43428: diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 452286a38b2b..7cb2344741cf 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -158,6 +158,7 @@ struct bcma_host_ops { /* Chip IDs of PCIe devices */ #define BCMA_CHIP_ID_BCM4313 0x4313 #define BCMA_CHIP_ID_BCM43142 43142 +#define BCMA_CHIP_ID_BCM43217 43217 #define BCMA_CHIP_ID_BCM43224 43224 #define BCMA_PKG_ID_BCM43224_FAB_CSM 0x8 #define BCMA_PKG_ID_BCM43224_FAB_SMIC 0xa -- cgit v1.2.3 From d954cd770051cde27a9da8f2627acd5bc709ffbb Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 16 Jul 2014 20:26:05 +0200 Subject: ath9k: fix pending tx frames accounting Packets originally buffered for the regular hardware tx queues can end up being transmitted through the U-APSD queue (via PS-Poll or U-APSD). When packets are dropped due to retransmit failures, the pending frames counter is not always updated properly. Fix this by keeping track of the queue that a frame was accounted for in the ath_frame_info struct, and using that on completion to decide whether the counter should be updated. This fixes some spurious transmit queue hangs. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 ++- drivers/net/wireless/ath/ath9k/xmit.c | 25 ++++++++++++++----------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 11b5e4dd6294..7fc13a8da675 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -182,7 +182,8 @@ struct ath_atx_ac { struct ath_frame_info { struct ath_buf *bf; - int framelen; + u16 framelen; + s8 txq; enum ath9k_key_type keytype; u8 keyix; u8 rtscts_rate; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index d4927c9a6bae..36115298f64e 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -157,15 +157,14 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - int q, hw_queue; - - q = skb_get_queue_mapping(skb); - if (txq == sc->tx.uapsdq) - txq = sc->tx.txq_map[q]; + struct ath_frame_info *fi = get_frame_info(skb); + int hw_queue; + int q = fi->txq; - if (txq != sc->tx.txq_map[q]) + if (q < 0) return; + txq = sc->tx.txq_map[q]; if (WARN_ON(--txq->pending_frames < 0)) txq->pending_frames = 0; @@ -2036,6 +2035,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, an = (struct ath_node *) sta->drv_priv; memset(fi, 0, sizeof(*fi)); + fi->txq = -1; if (hw_key) fi->keyix = hw_key->hw_key_idx; else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0) @@ -2187,6 +2187,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = txctl->sta; struct ieee80211_vif *vif = info->control.vif; + struct ath_frame_info *fi = get_frame_info(skb); struct ath_vif *avp = NULL; struct ath_softc *sc = hw->priv; struct ath_txq *txq = txctl->txq; @@ -2216,11 +2217,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, hw_queue = (info->hw_queue >= sc->hw->queues - 2) ? q : info->hw_queue; ath_txq_lock(sc, txq); - if (txq == sc->tx.txq_map[q] && - ++txq->pending_frames > sc->tx.txq_max_pending[q] && - !txq->stopped) { - ieee80211_stop_queue(sc->hw, hw_queue); - txq->stopped = true; + if (txq == sc->tx.txq_map[q]) { + fi->txq = q; + if (++txq->pending_frames > sc->tx.txq_max_pending[q] && + !txq->stopped) { + ieee80211_stop_queue(sc->hw, hw_queue); + txq->stopped = true; + } } queue = ieee80211_is_data_present(hdr->frame_control); -- cgit v1.2.3 From 3ae351abf15f984c02feb9aab5394443e9efb00a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 16 Jul 2014 23:20:10 +0200 Subject: ath9k: set up tx power into the MRR Set up tx power for each MRR segment in the tx descriptor Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9002_mac.c | 6 +++++- drivers/net/wireless/ath/ath9k/ar9003_mac.c | 6 +++++- drivers/net/wireless/ath/ath9k/mac.h | 10 ++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 741b38ddcb37..59af9f9712da 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -281,7 +281,7 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen) | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) - | SM(i->txpower, AR_XmitPower) + | SM(i->txpower, AR_XmitPower0) | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | (i->flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) @@ -306,6 +306,10 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | set11nRateFlags(i->rates, 2) | set11nRateFlags(i->rates, 3) | SM(i->rtscts_rate, AR_RTSCTSRate); + + ACCESS_ONCE(ads->ds_ctl9) = SM(i->txpower, AR_XmitPower1); + ACCESS_ONCE(ads->ds_ctl10) = SM(i->txpower, AR_XmitPower2); + ACCESS_ONCE(ads->ds_ctl11) = SM(i->txpower, AR_XmitPower3); } static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 729ffbf07343..71e38e85aa99 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -101,7 +101,7 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen) | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) - | SM(i->txpower, AR_XmitPower) + | SM(i->txpower, AR_XmitPower0) | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0) @@ -151,6 +151,10 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | SM(i->rtscts_rate, AR_RTSCTSRate); ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding; + + ACCESS_ONCE(ads->ctl20) = SM(i->txpower, AR_XmitPower1); + ACCESS_ONCE(ads->ctl21) = SM(i->txpower, AR_XmitPower2); + ACCESS_ONCE(ads->ctl22) = SM(i->txpower, AR_XmitPower3); } static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index da7686757535..6c56cafa5ca4 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -346,8 +346,14 @@ struct ar5416_desc { #define AR_FrameLen 0x00000fff #define AR_VirtMoreFrag 0x00001000 #define AR_TxCtlRsvd00 0x0000e000 -#define AR_XmitPower 0x003f0000 -#define AR_XmitPower_S 16 +#define AR_XmitPower0 0x003f0000 +#define AR_XmitPower0_S 16 +#define AR_XmitPower1 0x3f000000 +#define AR_XmitPower1_S 24 +#define AR_XmitPower2 0x3f000000 +#define AR_XmitPower2_S 24 +#define AR_XmitPower3 0x3f000000 +#define AR_XmitPower3_S 24 #define AR_RTSEnable 0x00400000 #define AR_VEOL 0x00800000 #define AR_ClrDestMask 0x01000000 -- cgit v1.2.3 From 3f5572020c4829e749716f2c31b5107417d5a96d Mon Sep 17 00:00:00 2001 From: Andrey Utkin Date: Thu, 17 Jul 2014 16:56:37 +0300 Subject: ath9k: drop negativity checks for unsigned values coming from kstrtoul() Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=80471 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=80481 Reported-by: David Binderman Signed-off-by: Andrey Utkin Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 2 +- drivers/net/wireless/ath/ath9k/spectral.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index ce073e995dfe..d2279365be6f 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -202,7 +202,7 @@ static ssize_t write_file_ani(struct file *file, if (kstrtoul(buf, 0, &ani)) return -EINVAL; - if (ani < 0 || ani > 1) + if (ani > 1) return -EINVAL; common->disable_ani = !ani; diff --git a/drivers/net/wireless/ath/ath9k/spectral.c b/drivers/net/wireless/ath/ath9k/spectral.c index 99f4de95c264..5fe29b9f8fa2 100644 --- a/drivers/net/wireless/ath/ath9k/spectral.c +++ b/drivers/net/wireless/ath/ath9k/spectral.c @@ -313,7 +313,7 @@ static ssize_t write_file_spectral_short_repeat(struct file *file, if (kstrtoul(buf, 0, &val)) return -EINVAL; - if (val < 0 || val > 1) + if (val > 1) return -EINVAL; sc->spec_config.short_repeat = val; @@ -361,7 +361,7 @@ static ssize_t write_file_spectral_count(struct file *file, if (kstrtoul(buf, 0, &val)) return -EINVAL; - if (val < 0 || val > 255) + if (val > 255) return -EINVAL; sc->spec_config.count = val; @@ -409,7 +409,7 @@ static ssize_t write_file_spectral_period(struct file *file, if (kstrtoul(buf, 0, &val)) return -EINVAL; - if (val < 0 || val > 255) + if (val > 255) return -EINVAL; sc->spec_config.period = val; @@ -457,7 +457,7 @@ static ssize_t write_file_spectral_fft_period(struct file *file, if (kstrtoul(buf, 0, &val)) return -EINVAL; - if (val < 0 || val > 15) + if (val > 15) return -EINVAL; sc->spec_config.fft_period = val; -- cgit v1.2.3 From 701fa113805f5523201fafa1385829a092ff8416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 17 Jul 2014 19:31:01 +0200 Subject: b43: N-PHY: fix channel switching with 2 GHz radio 0x2057 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Values were written to wrong registers. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/radio_2057.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/b43/radio_2057.c b/drivers/net/wireless/b43/radio_2057.c index ca22faa41d28..c9c24b615cc5 100644 --- a/drivers/net/wireless/b43/radio_2057.c +++ b/drivers/net/wireless/b43/radio_2057.c @@ -163,12 +163,12 @@ static u16 r2057_rev9_init[][2] = { .radio_vcobuf_tune = r09, \ .radio_logen_mx2g_tune = r10, \ .radio_logen_indbuf2g_tune = r11, \ - .radio_lna2g_tune_core0 = r12, \ - .radio_txmix2g_tune_boost_pu_core0 = r13, \ - .radio_pad2g_tune_pus_core0 = r14, \ - .radio_lna2g_tune_core1 = r15, \ - .radio_txmix2g_tune_boost_pu_core1 = r16, \ - .radio_pad2g_tune_pus_core1 = r17 + .radio_txmix2g_tune_boost_pu_core0 = r12, \ + .radio_pad2g_tune_pus_core0 = r13, \ + .radio_lna2g_tune_core0 = r14, \ + .radio_txmix2g_tune_boost_pu_core1 = r15, \ + .radio_pad2g_tune_pus_core1 = r16, \ + .radio_lna2g_tune_core1 = r17 #define PHYREGS(r0, r1, r2, r3, r4, r5) \ .phy_regs.phy_bw1a = r0, \ -- cgit v1.2.3 From 3b7caa29272961c0205aff41316b56d4b0b588f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 17 Jul 2014 19:31:02 +0200 Subject: b43: N-PHY: add tables for radio 0x2057 rev 14 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 12 +++- drivers/net/wireless/b43/radio_2057.c | 103 ++++++++++++++++++++++++++++++++- drivers/net/wireless/b43/tables_nphy.c | 40 +++++++++++++ 3 files changed, 152 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 479cda88ca5e..3da02ff59cf1 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -765,7 +765,12 @@ static void b43_radio_2057_setup(struct b43_wldev *dev, } } break; - /* TODO */ + case 14: /* 2 GHz only */ + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_R1, 0x1b); + b43_radio_write(dev, R2057_CP_KPD_IDAC, 0x3f); + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C1, 0x1f); + b43_radio_write(dev, R2057_RFPLL_LOOPFILTER_C2, 0x1f); + break; } if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { @@ -778,8 +783,11 @@ static void b43_radio_2057_setup(struct b43_wldev *dev, txmix2g_tune_boost_pu = 0x0041; /* TODO */ break; + case 14: + txmix2g_tune_boost_pu = 0x21; + pad2g_tune_pus = 0x23; + break; } - /* TODO */ } if (txmix2g_tune_boost_pu) diff --git a/drivers/net/wireless/b43/radio_2057.c b/drivers/net/wireless/b43/radio_2057.c index c9c24b615cc5..ff1e026a61a1 100644 --- a/drivers/net/wireless/b43/radio_2057.c +++ b/drivers/net/wireless/b43/radio_2057.c @@ -117,6 +117,15 @@ static u16 r2057_rev9_init[][2] = { { 0x14e, 0x01 }, { 0x1b7, 0x05 }, { 0x1c2, 0xa0 }, }; +/* Extracted from MMIO dump of 6.30.223.248 */ +static u16 r2057_rev14_init[][2] = { + { 0x011, 0xfc }, { 0x030, 0x24 }, { 0x040, 0x1c }, { 0x082, 0x08 }, + { 0x0b4, 0x44 }, { 0x0c8, 0x01 }, { 0x0c9, 0x01 }, { 0x107, 0x08 }, + { 0x14d, 0x01 }, { 0x14e, 0x01 }, { 0x1af, 0x40 }, { 0x1b0, 0x40 }, + { 0x1cc, 0x01 }, { 0x1cf, 0x10 }, { 0x1d0, 0x0f }, { 0x1d3, 0x10 }, + { 0x1d4, 0x0f }, +}; + #define RADIOREGS7(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \ r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \ r20, r21, r22, r23, r24, r25, r26, r27) \ @@ -280,6 +289,87 @@ static const struct b43_nphy_chantabent_rev7_2g b43_nphy_chantab_phy_rev8_radio_ } }; +/* Extracted from MMIO dump of 6.30.223.248 */ +static const struct b43_nphy_chantabent_rev7_2g b43_nphy_chantab_phy_rev17_radio_rev14[] = { + { + .freq = 2412, + RADIOREGS7_2G(0x48, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x6c, + 0x09, 0x0d, 0x09, 0x03, 0x21, 0x53, 0xff, 0x21, + 0x53, 0xff), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { + .freq = 2417, + RADIOREGS7_2G(0x4b, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x71, + 0x09, 0x0d, 0x08, 0x03, 0x21, 0x53, 0xff, 0x21, + 0x53, 0xff), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { + .freq = 2422, + RADIOREGS7_2G(0x4e, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x76, + 0x09, 0x0d, 0x08, 0x03, 0x21, 0x53, 0xff, 0x21, + 0x53, 0xff), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { + .freq = 2427, + RADIOREGS7_2G(0x52, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x7b, + 0x09, 0x0c, 0x08, 0x03, 0x21, 0x53, 0xff, 0x21, + 0x53, 0xff), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { + .freq = 2432, + RADIOREGS7_2G(0x55, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x80, + 0x09, 0x0c, 0x08, 0x03, 0x21, 0x53, 0xff, 0x21, + 0x53, 0xff), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { + .freq = 2437, + RADIOREGS7_2G(0x58, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x85, + 0x09, 0x0c, 0x08, 0x03, 0x21, 0x53, 0xff, 0x21, + 0x53, 0xff), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { + .freq = 2442, + RADIOREGS7_2G(0x5c, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x8a, + 0x09, 0x0c, 0x08, 0x03, 0x21, 0x43, 0xff, 0x21, + 0x43, 0xff), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { + .freq = 2447, + RADIOREGS7_2G(0x5f, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x8f, + 0x09, 0x0c, 0x08, 0x03, 0x21, 0x43, 0xff, 0x21, + 0x43, 0xff), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { + .freq = 2452, + RADIOREGS7_2G(0x62, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x94, + 0x09, 0x0c, 0x08, 0x03, 0x21, 0x43, 0xff, 0x21, + 0x43, 0xff), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { + .freq = 2457, + RADIOREGS7_2G(0x66, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x99, + 0x09, 0x0b, 0x07, 0x03, 0x21, 0x43, 0xff, 0x21, + 0x43, 0xff), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { + .freq = 2462, + RADIOREGS7_2G(0x69, 0x16, 0x30, 0x2b, 0x1f, 0x1f, 0x30, 0x9e, + 0x09, 0x0b, 0x07, 0x03, 0x01, 0x43, 0xff, 0x01, + 0x43, 0xff), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, +}; + /* Extracted from MMIO dump of 6.30.223.141 */ static const struct b43_nphy_chantabent_rev7 b43_nphy_chantab_phy_rev16_radio_rev9[] = { { @@ -476,6 +566,12 @@ void r2057_upload_inittabs(struct b43_wldev *dev) size = ARRAY_SIZE(r2057_rev9_init); } break; + case 17: + if (phy->radio_rev == 14) { + table = r2057_rev14_init[0]; + size = ARRAY_SIZE(r2057_rev14_init); + } + break; } B43_WARN_ON(!table); @@ -498,7 +594,6 @@ void r2057_get_chantabent_rev7(struct b43_wldev *dev, u16 freq, *tabent_r7 = NULL; *tabent_r7_2g = NULL; - /* TODO */ switch (phy->rev) { case 8: if (phy->radio_rev == 5) { @@ -512,6 +607,12 @@ void r2057_get_chantabent_rev7(struct b43_wldev *dev, u16 freq, len = ARRAY_SIZE(b43_nphy_chantab_phy_rev16_radio_rev9); } break; + case 17: + if (phy->radio_rev == 14) { + e_r7_2g = b43_nphy_chantab_phy_rev17_radio_rev14; + len = ARRAY_SIZE(b43_nphy_chantab_phy_rev17_radio_rev14); + } + break; default: break; } diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index b39a8dd375e9..ab27c2de2f43 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -2764,6 +2764,42 @@ static const u32 b43_ntab_tx_gain_ipa_2057_rev9_2g[] = { 0x600f0715, 0x600f0715, 0x600f0715, 0x600f0715, }; +/* Extracted from MMIO dump of 6.30.223.248 */ +static const u32 b43_ntab_tx_gain_ipa_2057_rev14_2g[] = { + 0x50df002e, 0x50cf002d, 0x50bf002c, 0x50b7002b, + 0x50af002a, 0x50a70029, 0x509f0029, 0x50970028, + 0x508f0027, 0x50870027, 0x507f0027, 0x50770027, + 0x506f0027, 0x50670027, 0x505f0028, 0x50570029, + 0x504f002b, 0x5047002e, 0x5047002b, 0x50470029, + 0x503f002c, 0x503f0029, 0x5037002c, 0x5037002a, + 0x50370028, 0x502f002d, 0x502f002b, 0x502f0028, + 0x502f0026, 0x5027002d, 0x5027002a, 0x50270028, + 0x50270026, 0x50270024, 0x501f002e, 0x501f002b, + 0x501f0029, 0x501f0027, 0x501f0024, 0x501f0022, + 0x501f0020, 0x501f001f, 0x5017002c, 0x50170029, + 0x50170027, 0x50170024, 0x50170022, 0x50170021, + 0x5017001f, 0x5017001d, 0x5017001b, 0x5017001a, + 0x50170018, 0x50170017, 0x50170015, 0x500f002c, + 0x500f002a, 0x500f0027, 0x500f0025, 0x500f0023, + 0x500f0022, 0x500f001f, 0x500f001e, 0x500f001c, + 0x500f001a, 0x500f0019, 0x500f0018, 0x500f0016, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, + 0x500f0015, 0x500f0015, 0x500f0015, 0x500f0015, +}; + /* IPA 2 5Hz */ static const u32 b43_ntab_tx_gain_ipa_rev3_5g[] = { @@ -3583,6 +3619,10 @@ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { switch (phy->rev) { + case 17: + if (phy->radio_rev == 14) + return b43_ntab_tx_gain_ipa_2057_rev14_2g; + break; case 16: if (phy->radio_rev == 9) return b43_ntab_tx_gain_ipa_2057_rev9_2g; -- cgit v1.2.3 From ef0d635ed147047afd97bb86510fb7a889fab709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 17 Jul 2014 19:31:03 +0200 Subject: b43: N-PHY: complete 0x2057 radio init calibration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 86 +++++++++++++++++++++++++++++++++++----- drivers/net/wireless/b43/phy_n.h | 2 + 2 files changed, 79 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 3da02ff59cf1..2c5583231d2f 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -820,13 +820,62 @@ static void b43_radio_2057_setup(struct b43_wldev *dev, static u8 b43_radio_2057_rcal(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + u16 saved_regs_phy[12]; + u16 saved_regs_phy_rf[6]; + u16 saved_regs_radio[2] = { }; + static const u16 phy_to_store[] = { + B43_NPHY_RFCTL_RSSIO1, B43_NPHY_RFCTL_RSSIO2, + B43_NPHY_RFCTL_LUT_TRSW_LO1, B43_NPHY_RFCTL_LUT_TRSW_LO2, + B43_NPHY_RFCTL_RXG1, B43_NPHY_RFCTL_RXG2, + B43_NPHY_RFCTL_TXG1, B43_NPHY_RFCTL_TXG2, + B43_NPHY_REV7_RF_CTL_MISC_REG3, B43_NPHY_REV7_RF_CTL_MISC_REG4, + B43_NPHY_REV7_RF_CTL_MISC_REG5, B43_NPHY_REV7_RF_CTL_MISC_REG6, + }; + static const u16 phy_to_store_rf[] = { + B43_NPHY_REV3_RFCTL_OVER0, B43_NPHY_REV3_RFCTL_OVER1, + B43_NPHY_REV7_RF_CTL_OVER3, B43_NPHY_REV7_RF_CTL_OVER4, + B43_NPHY_REV7_RF_CTL_OVER5, B43_NPHY_REV7_RF_CTL_OVER6, + }; u16 tmp; + int i; - if (phy->radio_rev == 5) { - b43_phy_mask(dev, 0x342, ~0x2); + /* Save */ + for (i = 0; i < ARRAY_SIZE(phy_to_store); i++) + saved_regs_phy[i] = b43_phy_read(dev, phy_to_store[i]); + for (i = 0; i < ARRAY_SIZE(phy_to_store_rf); i++) + saved_regs_phy_rf[i] = b43_phy_read(dev, phy_to_store_rf[i]); + + /* Set */ + for (i = 0; i < ARRAY_SIZE(phy_to_store); i++) + b43_phy_write(dev, phy_to_store[i], 0); + b43_phy_write(dev, B43_NPHY_REV3_RFCTL_OVER0, 0x07ff); + b43_phy_write(dev, B43_NPHY_REV3_RFCTL_OVER1, 0x07ff); + b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER3, 0x07ff); + b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER4, 0x07ff); + b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER5, 0x007f); + b43_phy_write(dev, B43_NPHY_REV7_RF_CTL_OVER6, 0x007f); + + switch (phy->radio_rev) { + case 5: + b43_phy_mask(dev, B43_NPHY_REV7_RF_CTL_OVER3, ~0x2); udelay(10); b43_radio_set(dev, R2057_IQTEST_SEL_PU, 0x1); - b43_radio_maskset(dev, 0x1ca, ~0x2, 0x1); + b43_radio_maskset(dev, R2057v7_IQTEST_SEL_PU2, ~0x2, 0x1); + break; + case 9: + b43_phy_set(dev, B43_NPHY_REV7_RF_CTL_OVER3, 0x2); + b43_phy_set(dev, B43_NPHY_REV7_RF_CTL_MISC_REG3, 0x2); + saved_regs_radio[0] = b43_radio_read(dev, R2057_IQTEST_SEL_PU); + b43_radio_write(dev, R2057_IQTEST_SEL_PU, 0x11); + break; + case 14: + saved_regs_radio[0] = b43_radio_read(dev, R2057_IQTEST_SEL_PU); + saved_regs_radio[1] = b43_radio_read(dev, R2057v7_IQTEST_SEL_PU2); + b43_phy_set(dev, B43_NPHY_REV7_RF_CTL_MISC_REG3, 0x2); + b43_phy_set(dev, B43_NPHY_REV7_RF_CTL_OVER3, 0x2); + b43_radio_write(dev, R2057v7_IQTEST_SEL_PU2, 0x2); + b43_radio_write(dev, R2057_IQTEST_SEL_PU, 0x1); + break; } /* Enable */ @@ -850,14 +899,30 @@ static u8 b43_radio_2057_rcal(struct b43_wldev *dev) /* Disable */ b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x1); - if (phy->radio_rev == 5) { - b43_radio_mask(dev, R2057_IPA2G_CASCONV_CORE0, ~0x1); - b43_radio_mask(dev, 0x1ca, ~0x2); - } - if (phy->radio_rev <= 4 || phy->radio_rev == 6) { + /* Restore */ + for (i = 0; i < ARRAY_SIZE(phy_to_store_rf); i++) + b43_phy_write(dev, phy_to_store_rf[i], saved_regs_phy_rf[i]); + for (i = 0; i < ARRAY_SIZE(phy_to_store); i++) + b43_phy_write(dev, phy_to_store[i], saved_regs_phy[i]); + + switch (phy->radio_rev) { + case 0 ... 4: + case 6: b43_radio_maskset(dev, R2057_TEMPSENSE_CONFIG, ~0x3C, tmp); b43_radio_maskset(dev, R2057_BANDGAP_RCAL_TRIM, ~0xF0, tmp << 2); + break; + case 5: + b43_radio_mask(dev, R2057_IPA2G_CASCONV_CORE0, ~0x1); + b43_radio_mask(dev, R2057v7_IQTEST_SEL_PU2, ~0x2); + break; + case 9: + b43_radio_write(dev, R2057_IQTEST_SEL_PU, saved_regs_radio[0]); + break; + case 14: + b43_radio_write(dev, R2057_IQTEST_SEL_PU, saved_regs_radio[0]); + b43_radio_write(dev, R2057v7_IQTEST_SEL_PU2, saved_regs_radio[1]); + break; } return tmp & 0x3e; @@ -879,7 +944,7 @@ static u16 b43_radio_2057_rccal(struct b43_wldev *dev) b43_radio_write(dev, R2057_RCCAL_TRC0, 0xC0); } else { b43_radio_write(dev, R2057v7_RCCAL_MASTER, 0x61); - b43_radio_write(dev, R2057_RCCAL_TRC0, 0xE1); + b43_radio_write(dev, R2057_RCCAL_TRC0, 0xE9); } b43_radio_write(dev, R2057_RCCAL_X1, 0x6E); @@ -959,6 +1024,9 @@ static void b43_radio_2057_init_post(struct b43_wldev *dev) { b43_radio_set(dev, R2057_XTALPUOVR_PINCTRL, 0x1); + if (0) /* FIXME: Is this BCM43217 specific? */ + b43_radio_set(dev, R2057_XTALPUOVR_PINCTRL, 0x2); + b43_radio_set(dev, R2057_RFPLL_MISC_CAL_RESETN, 0x78); b43_radio_set(dev, R2057_XTAL_CONFIG2, 0x80); mdelay(2); diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index 7fd5d5f9161d..474bf758295d 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -366,11 +366,13 @@ #define B43_NPHY_TXF_40CO_B1S0 B43_PHY_N(0x0E5) /* TX filter 40 coeff B1 stage 0 */ #define B43_NPHY_TXF_40CO_B32S1 B43_PHY_N(0x0E6) /* TX filter 40 coeff B32 stage 1 */ #define B43_NPHY_TXF_40CO_B1S1 B43_PHY_N(0x0E7) /* TX filter 40 coeff B1 stage 1 */ +#define B43_NPHY_REV3_RFCTL_OVER0 B43_PHY_N(0x0E7) #define B43_NPHY_TXF_40CO_B32S2 B43_PHY_N(0x0E8) /* TX filter 40 coeff B32 stage 2 */ #define B43_NPHY_TXF_40CO_B1S2 B43_PHY_N(0x0E9) /* TX filter 40 coeff B1 stage 2 */ #define B43_NPHY_BIST_STAT2 B43_PHY_N(0x0EA) /* BIST status 2 */ #define B43_NPHY_BIST_STAT3 B43_PHY_N(0x0EB) /* BIST status 3 */ #define B43_NPHY_RFCTL_OVER B43_PHY_N(0x0EC) /* RF control override */ +#define B43_NPHY_REV3_RFCTL_OVER1 B43_PHY_N(0x0EC) #define B43_NPHY_MIMOCFG B43_PHY_N(0x0ED) /* MIMO config */ #define B43_NPHY_MIMOCFG_GFMIX 0x0004 /* Greenfield or mixed mode */ #define B43_NPHY_MIMOCFG_AUTO 0x0100 /* Greenfield/mixed mode auto */ -- cgit v1.2.3 From c9325e2f2435d93117e9336d72754b68abda26d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 17 Jul 2014 19:31:04 +0200 Subject: b43: N-PHY: set band on every channel switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seems to be required by some hardware, wl does it every time. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 16 ++++++++-------- drivers/net/wireless/b43/phy_n.h | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 2c5583231d2f..ef1acaec7027 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -6058,23 +6058,23 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, struct b43_phy *phy = &dev->phy; struct b43_phy_n *nphy = dev->phy.n; int ch = new_channel->hw_value; - - u16 old_band_5ghz; u16 tmp16; - old_band_5ghz = - b43_phy_read(dev, B43_NPHY_BANDCTL) & B43_NPHY_BANDCTL_5GHZ; - if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) { + if (new_channel->band == IEEE80211_BAND_5GHZ) { tmp16 = b43_read16(dev, B43_MMIO_PSM_PHY_HDR); b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16 | 4); - b43_phy_set(dev, B43_PHY_B_BBCFG, 0xC000); + /* Put BPHY in the reset */ + b43_phy_set(dev, B43_PHY_B_BBCFG, + B43_PHY_B_BBCFG_RSTCCA | B43_PHY_B_BBCFG_RSTRX); b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16); b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ); - } else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) { + } else if (new_channel->band == IEEE80211_BAND_2GHZ) { b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ); tmp16 = b43_read16(dev, B43_MMIO_PSM_PHY_HDR); b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16 | 4); - b43_phy_mask(dev, B43_PHY_B_BBCFG, 0x3FFF); + /* Take BPHY out of the reset */ + b43_phy_mask(dev, B43_PHY_B_BBCFG, + (u16)~(B43_PHY_B_BBCFG_RSTCCA | B43_PHY_B_BBCFG_RSTRX)); b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16); } diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index 474bf758295d..30bec815b969 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -869,6 +869,8 @@ #define B43_NPHY_REV7_RF_CTL_OVER6 B43_PHY_N(0x347) #define B43_PHY_B_BBCFG B43_PHY_N_BMODE(0x001) /* BB config */ +#define B43_PHY_B_BBCFG_RSTCCA 0x4000 /* Reset CCA */ +#define B43_PHY_B_BBCFG_RSTRX 0x8000 /* Reset RX */ #define B43_PHY_B_TEST B43_PHY_N_BMODE(0x00A) struct b43_wldev; -- cgit v1.2.3 From c2cb2c4cf1a089501242a1701b589d2ad5eb0448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 17 Jul 2014 19:31:05 +0200 Subject: b43: use one shared function for setting MAC frequency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By the way add few chipsets that were tracked with "wl" dumps. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 39 ++++++++++++++++++++++++++++++++++++++ drivers/net/wireless/b43/main.h | 1 + drivers/net/wireless/b43/phy_lcn.c | 35 +--------------------------------- drivers/net/wireless/b43/phy_n.c | 7 +------ include/linux/bcma/bcma.h | 1 + 5 files changed, 43 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 3dcd3aa38608..3e127be06bfb 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2964,6 +2964,45 @@ void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on) } } +/* brcms_b_switch_macfreq */ +void b43_mac_switch_freq(struct b43_wldev *dev, u8 spurmode) +{ + u16 chip_id = dev->dev->chip_id; + + if (chip_id == BCMA_CHIP_ID_BCM43217 || + chip_id == BCMA_CHIP_ID_BCM43222 || + chip_id == BCMA_CHIP_ID_BCM43224 || + chip_id == BCMA_CHIP_ID_BCM43225 || + chip_id == BCMA_CHIP_ID_BCM43227 || + chip_id == BCMA_CHIP_ID_BCM43228) { + switch (spurmode) { + case 2: /* 126 Mhz */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x2082); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8); + break; + case 1: /* 123 Mhz */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x5341); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8); + break; + default: /* 120 Mhz */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x8889); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8); + break; + } + } else if (dev->phy.type == B43_PHYTYPE_LCN) { + switch (spurmode) { + case 1: /* 82 Mhz */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x7CE0); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC); + break; + default: /* 80 Mhz */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0xCCCD); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC); + break; + } + } +} + static void b43_adjust_opmode(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index f476fc337d64..9f22e4b4c132 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -99,6 +99,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags); void b43_mac_suspend(struct b43_wldev *dev); void b43_mac_enable(struct b43_wldev *dev); void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on); +void b43_mac_switch_freq(struct b43_wldev *dev, u8 spurmode); struct b43_request_fw_context; diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c index 0bafa3b17035..e76bbdf3247e 100644 --- a/drivers/net/wireless/b43/phy_lcn.c +++ b/drivers/net/wireless/b43/phy_lcn.c @@ -54,39 +54,6 @@ enum lcn_sense_type { B43_SENSE_VBAT, }; -/* In theory it's PHY common function, move if needed */ -/* brcms_b_switch_macfreq */ -static void b43_phy_switch_macfreq(struct b43_wldev *dev, u8 spurmode) -{ - if (dev->dev->chip_id == 43224 || dev->dev->chip_id == 43225) { - switch (spurmode) { - case 2: /* 126 Mhz */ - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x2082); - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8); - break; - case 1: /* 123 Mhz */ - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x5341); - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8); - break; - default: /* 120 Mhz */ - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x8889); - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8); - break; - } - } else if (dev->phy.type == B43_PHYTYPE_LCN) { - switch (spurmode) { - case 1: /* 82 Mhz */ - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x7CE0); - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC); - break; - default: /* 80 Mhz */ - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0xCCCD); - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC); - break; - } - } -} - /************************************************** * Radio 2064. **************************************************/ @@ -609,7 +576,7 @@ static void b43_phy_lcn_txrx_spur_avoidance_mode(struct b43_wldev *dev, b43_phy_write(dev, 0x93b, ((0 << 13) + 23)); b43_phy_write(dev, 0x93c, ((0 << 13) + 1989)); } - b43_phy_switch_macfreq(dev, enable); + b43_mac_switch_freq(dev, enable); } /************************************************** diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index ef1acaec7027..0f0c1306b0ad 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -6113,12 +6113,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, b43_nphy_pmu_spur_avoid(dev, avoid); - if (dev->dev->chip_id == 43222 || dev->dev->chip_id == 43224 || - dev->dev->chip_id == 43225) { - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, - avoid ? 0x5341 : 0x8889); - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8); - } + b43_mac_switch_freq(dev, avoid); if (dev->phy.rev == 3 || dev->phy.rev == 4) ; /* TODO: reset PLL */ diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 7cb2344741cf..969af0f2bdf9 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -159,6 +159,7 @@ struct bcma_host_ops { #define BCMA_CHIP_ID_BCM4313 0x4313 #define BCMA_CHIP_ID_BCM43142 43142 #define BCMA_CHIP_ID_BCM43217 43217 +#define BCMA_CHIP_ID_BCM43222 43222 #define BCMA_CHIP_ID_BCM43224 43224 #define BCMA_PKG_ID_BCM43224_FAB_CSM 0x8 #define BCMA_PKG_ID_BCM43224_FAB_SMIC 0xa -- cgit v1.2.3 From e2f04f7256b3da8411bb9422ccf2ac17d7c51be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 17 Jul 2014 19:31:06 +0200 Subject: b43: N-PHY: update spur avoidance to support newer devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 43 +++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 0f0c1306b0ad..92bfe352ba08 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -6099,26 +6099,45 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, if (dev->phy.rev >= 3 && dev->phy.n->spur_avoid != B43_SPUR_AVOID_DISABLE) { - bool avoid = false; + u8 spuravoid = 0; + if (dev->phy.n->spur_avoid == B43_SPUR_AVOID_FORCE) { - avoid = true; - } else if (!b43_is_40mhz(dev)) { - if ((ch >= 5 && ch <= 8) || ch == 13 || ch == 14) - avoid = true; - } else { /* 40MHz */ - if (nphy->aband_spurwar_en && - (ch == 38 || ch == 102 || ch == 118)) - avoid = dev->dev->chip_id == 0x4716; + spuravoid = 1; + } else if (phy->rev >= 19) { + /* TODO */ + } else if (phy->rev >= 18) { + /* TODO */ + } else if (phy->rev >= 17) { + /* TODO: Off for channels 1-11, but check 12-14! */ + } else if (phy->rev >= 16) { + /* TODO: Off for 2 GHz, but check 5 GHz! */ + } else if (phy->rev >= 7) { + if (!b43_is_40mhz(dev)) { /* 20MHz */ + if (ch == 13 || ch == 14 || ch == 153) + spuravoid = 1; + } else { /* 40 MHz */ + if (ch == 54) + spuravoid = 1; + } + } else { + if (!b43_is_40mhz(dev)) { /* 20MHz */ + if ((ch >= 5 && ch <= 8) || ch == 13 || ch == 14) + spuravoid = 1; + } else { /* 40MHz */ + if (nphy->aband_spurwar_en && + (ch == 38 || ch == 102 || ch == 118)) + spuravoid = dev->dev->chip_id == 0x4716; + } } - b43_nphy_pmu_spur_avoid(dev, avoid); + b43_nphy_pmu_spur_avoid(dev, spuravoid); - b43_mac_switch_freq(dev, avoid); + b43_mac_switch_freq(dev, spuravoid); if (dev->phy.rev == 3 || dev->phy.rev == 4) ; /* TODO: reset PLL */ - if (avoid) + if (spuravoid) b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTRX); else b43_phy_mask(dev, B43_NPHY_BBCFG, -- cgit v1.2.3 From 9435d09146b3ab31e399e6c6ff2cf225dd0955d8 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Thu, 17 Jul 2014 11:48:47 -0700 Subject: mwifiex: remove needless current_bssid variable This local variable is not used anywhere in function. Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/join.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 0b977ea1cddb..8d6c25908b6d 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -1288,8 +1288,6 @@ done: int mwifiex_associate(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc) { - u8 current_bssid[ETH_ALEN]; - /* Return error if the adapter is not STA role or table entry * is not marked as infra. */ @@ -1304,10 +1302,6 @@ int mwifiex_associate(struct mwifiex_private *priv, else mwifiex_set_ba_params(priv); - memcpy(¤t_bssid, - &priv->curr_bss_params.bss_descriptor.mac_address, - sizeof(current_bssid)); - /* Clear any past association response stored for application retrieval */ priv->assoc_rsp_size = 0; -- cgit v1.2.3 From 71954f24c93fd569314985e9a7319b68e0b918e6 Mon Sep 17 00:00:00 2001 From: Ujjal Roy Date: Thu, 17 Jul 2014 11:49:55 -0700 Subject: mwifiex: do not re-associate when already connected In managed mode if the driver is getting a re-associate command from cfg80211, driver deauthenticates with the AP internally and sends a disconnected event to cfg80211 before completion of its association process. The disconnected event then modifies the SSID length as wdev->ssid_len = 0. So, upon receiving the connect result event from driver, cfg80211 is unable to get that BSS from the device's BSS list and generates the following WARN_ON message. WARNING: CPU: 0 PID: 857 at net/wireless/sme.c:658 __cfg80211_connect_result+0x3a6/0x3e0 [cfg80211]() Avoid re-association while the device is already associated to a network. Also remove the internal deauthentication from the association path. Signed-off-by: Ujjal Roy Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: Amitkumar Karwar Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cfg80211.c | 8 +++++--- drivers/net/wireless/mwifiex/sta_ioctl.c | 10 ---------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 6af135fa99f7..a738cc959a47 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1604,9 +1604,6 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, return -EINVAL; } - /* disconnect before try to associate */ - mwifiex_deauthenticate(priv, NULL); - /* As this is new association, clear locally stored * keys and security related flags */ priv->sec_info.wpa_enabled = false; @@ -1744,6 +1741,11 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } + if (priv->wdev && priv->wdev->current_bss) { + wiphy_warn(wiphy, "%s: already connected\n", dev->name); + return -EALREADY; + } + wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", (char *) sme->ssid, sme->bssid); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 1a03d4d8b418..caae9738100a 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -283,10 +283,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) { u8 config_bands; - ret = mwifiex_deauthenticate(priv, NULL); - if (ret) - goto done; - if (!bss_desc) return -1; @@ -345,12 +341,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, goto done; } - /* Exit Adhoc mode first */ - dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); - ret = mwifiex_deauthenticate(priv, NULL); - if (ret) - goto done; - priv->adhoc_is_link_sensed = false; ret = mwifiex_check_network_compatibility(priv, bss_desc); -- cgit v1.2.3 From 1d9e954e8b522ae37c7c0fdd791b5736321684a0 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Thu, 17 Jul 2014 15:55:09 -0700 Subject: mwifiex: remove redundant timestamps in debug prints We don't need wall-clock time here, and in most configurations that care, there are already timestamps in the kernel using CONFIG_PRINTK_TIME=y. Reported-by: Paul Stewart Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/cmdevt.c | 40 +++++++++++------------------------ drivers/net/wireless/mwifiex/pcie.c | 14 ++++-------- drivers/net/wireless/mwifiex/sdio.c | 14 ++++-------- 3 files changed, 20 insertions(+), 48 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 5899eee87fb1..baf0aab63c04 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -137,7 +137,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, struct host_cmd_ds_command *host_cmd; uint16_t cmd_code; uint16_t cmd_size; - struct timeval tstamp; unsigned long flags; __le32 tmp; @@ -198,10 +197,8 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, */ skb_put(cmd_node->cmd_skb, cmd_size - cmd_node->cmd_skb->len); - do_gettimeofday(&tstamp); - dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d," - " seqno %#x\n", - tstamp.tv_sec, tstamp.tv_usec, cmd_code, + dev_dbg(adapter->dev, + "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n", cmd_code, le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size, le16_to_cpu(host_cmd->seq_num)); @@ -273,7 +270,6 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) (struct mwifiex_opt_sleep_confirm *) adapter->sleep_cfm->data; struct sk_buff *sleep_cfm_tmp; - struct timeval ts; __le32 tmp; priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); @@ -284,10 +280,9 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) (adapter->seq_num, priv->bss_num, priv->bss_type))); - do_gettimeofday(&ts); dev_dbg(adapter->dev, - "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d, seqno %#x\n", - ts.tv_sec, ts.tv_usec, le16_to_cpu(sleep_cfm_buf->command), + "cmd: DNLD_CMD: %#x, act %#x, len %d, seqno %#x\n", + le16_to_cpu(sleep_cfm_buf->command), le16_to_cpu(sleep_cfm_buf->action), le16_to_cpu(sleep_cfm_buf->size), le16_to_cpu(sleep_cfm_buf->seq_num)); @@ -442,7 +437,6 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); struct sk_buff *skb = adapter->event_skb; u32 eventcause = adapter->event_cause; - struct timeval tstamp; struct mwifiex_rxinfo *rx_info; /* Save the last event to debug log */ @@ -467,9 +461,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) rx_info->bss_type = priv->bss_type; } - do_gettimeofday(&tstamp); - dev_dbg(adapter->dev, "EVENT: %lu.%lu: cause: %#x\n", - tstamp.tv_sec, tstamp.tv_usec, eventcause); + dev_dbg(adapter->dev, "EVENT: cause: %#x\n", eventcause); if (eventcause == EVENT_PS_SLEEP || eventcause == EVENT_PS_AWAKE) { /* Handle PS_SLEEP/AWAKE events on STA */ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); @@ -781,7 +773,6 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) uint16_t orig_cmdresp_no; uint16_t cmdresp_no; uint16_t cmdresp_result; - struct timeval tstamp; unsigned long flags; /* Now we got response from FW, cancel the command timer */ @@ -839,11 +830,10 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] = orig_cmdresp_no; - do_gettimeofday(&tstamp); - dev_dbg(adapter->dev, "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d," - " len %d, seqno 0x%x\n", - tstamp.tv_sec, tstamp.tv_usec, orig_cmdresp_no, cmdresp_result, - le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num)); + dev_dbg(adapter->dev, + "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n", + orig_cmdresp_no, cmdresp_result, + le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num)); if (!(orig_cmdresp_no & HostCmd_RET_BIT)) { dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n"); @@ -903,7 +893,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) struct mwifiex_adapter *adapter = (struct mwifiex_adapter *) function_context; struct cmd_ctrl_node *cmd_node; - struct timeval tstamp; adapter->is_cmd_timedout = 1; if (!adapter->curr_cmd) { @@ -916,10 +905,8 @@ mwifiex_cmd_timeout_func(unsigned long function_context) adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; adapter->dbg.timeout_cmd_act = adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index]; - do_gettimeofday(&tstamp); dev_err(adapter->dev, - "%s: Timeout cmd id (%lu.%lu) = %#x, act = %#x\n", - __func__, tstamp.tv_sec, tstamp.tv_usec, + "%s: Timeout cmd id = %#x, act = %#x\n", __func__, adapter->dbg.timeout_cmd_id, adapter->dbg.timeout_cmd_act); @@ -1237,18 +1224,15 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, uint16_t result = le16_to_cpu(cmd->result); uint16_t command = le16_to_cpu(cmd->command); uint16_t seq_num = le16_to_cpu(cmd->seq_num); - struct timeval ts; if (!upld_len) { dev_err(adapter->dev, "%s: cmd size is 0\n", __func__); return; } - do_gettimeofday(&ts); dev_dbg(adapter->dev, - "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d, len %d, seqno 0x%x\n", - ts.tv_sec, ts.tv_usec, command, result, le16_to_cpu(cmd->size), - seq_num); + "cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n", + command, result, le16_to_cpu(cmd->size), seq_num); /* Get BSS number and corresponding priv */ priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num), diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 5f7afffdd34e..c16dd2cc8198 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -2238,7 +2238,6 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter) struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *creg = card->pcie.reg; unsigned int reg, reg_start, reg_end; - struct timeval t; u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0; enum rdwr_status stat; u32 memory_size; @@ -2257,9 +2256,7 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter) entry->mem_size = 0; } - do_gettimeofday(&t); - dev_info(adapter->dev, "== mwifiex firmware dump start: %u.%06u ==\n", - (u32)t.tv_sec, (u32)t.tv_usec); + dev_info(adapter->dev, "== mwifiex firmware dump start ==\n"); /* Read the number of the memories which will dump */ stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag); @@ -2303,9 +2300,8 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter) end_ptr = dbg_ptr + memory_size; doneflag = entry->done_flag; - do_gettimeofday(&t); - dev_info(adapter->dev, "Start %s output %u.%06u, please wait...\n", - entry->mem_name, (u32)t.tv_sec, (u32)t.tv_usec); + dev_info(adapter->dev, "Start %s output, please wait...\n", + entry->mem_name); do { stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag); @@ -2331,9 +2327,7 @@ static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter) break; } while (true); } - do_gettimeofday(&t); - dev_info(adapter->dev, "== mwifiex firmware dump end: %u.%06u ==\n", - (u32)t.tv_sec, (u32)t.tv_usec); + dev_info(adapter->dev, "== mwifiex firmware dump end ==\n"); kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 1da04a086bd9..3e48ef5ca53c 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -2012,7 +2012,6 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work) int ret = 0; unsigned int reg, reg_start, reg_end; u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0; - struct timeval t; enum rdwr_status stat; u32 memory_size; static char *env[] = { "DRIVER=mwifiex_sdio", "EVENT=fw_dump", NULL }; @@ -2033,9 +2032,7 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work) mwifiex_pm_wakeup_card(adapter); sdio_claim_host(card->func); - do_gettimeofday(&t); - dev_info(adapter->dev, "== mwifiex firmware dump start: %u.%06u ==\n", - (u32)t.tv_sec, (u32)t.tv_usec); + dev_info(adapter->dev, "== mwifiex firmware dump start ==\n"); stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag); if (stat == RDWR_STATUS_FAILURE) @@ -2087,9 +2084,8 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work) end_ptr = dbg_ptr + memory_size; doneflag = entry->done_flag; - do_gettimeofday(&t); - dev_info(adapter->dev, "Start %s output %u.%06u, please wait...\n", - entry->mem_name, (u32)t.tv_sec, (u32)t.tv_usec); + dev_info(adapter->dev, "Start %s output, please wait...\n", + entry->mem_name); do { stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag); @@ -2120,9 +2116,7 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work) break; } while (1); } - do_gettimeofday(&t); - dev_info(adapter->dev, "== mwifiex firmware dump end: %u.%06u ==\n", - (u32)t.tv_sec, (u32)t.tv_usec); + dev_info(adapter->dev, "== mwifiex firmware dump end ==\n"); kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env); -- cgit v1.2.3 From ae8df494e9ec9d5c2bd907a0b7de712e050cb533 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 18 Jul 2014 14:47:06 -0700 Subject: Bluetooth: add public address configuration for Marvell USB devices Implemented .set_bdaddr handler provided by bluetooth stack for Marvell devices for public address configuration. A reboot restores the bdaddr to its original address. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ed7b33b06b43..b062bed67aaf 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -48,6 +48,7 @@ static struct usb_driver btusb_driver; #define BTUSB_INTEL 0x100 #define BTUSB_INTEL_BOOT 0x200 #define BTUSB_BCM_PATCHRAM 0x400 +#define BTUSB_MARVELL 0x800 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -242,6 +243,10 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, + /* Marvell device */ + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { } /* Terminating entry */ }; @@ -1455,6 +1460,29 @@ static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) return 0; } +static int btusb_set_bdaddr_marvell(struct hci_dev *hdev, + const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + u8 buf[8]; + long ret; + + buf[0] = 0xfe; + buf[1] = sizeof(bdaddr_t); + memcpy(buf + 2, bdaddr, sizeof(bdaddr_t)); + + skb = __hci_cmd_sync(hdev, 0xfc22, sizeof(buf), buf, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: changing Marvell device address failed (%ld)", + hdev->name, ret); + return ret; + } + kfree_skb(skb); + + return 0; +} + #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) static int btusb_setup_bcm_patchram(struct hci_dev *hdev) @@ -1766,6 +1794,9 @@ static int btusb_probe(struct usb_interface *intf, hdev->set_bdaddr = btusb_set_bdaddr_intel; } + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + if (id->driver_info & BTUSB_INTEL_BOOT) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); -- cgit v1.2.3 From 27b869f59d5d989df681291a8449c03777aa8ca6 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 18 Jul 2014 14:47:07 -0700 Subject: Bluetooth: btmrvl: add public address configuration support .set_bdaddr handler is implemented for public address configuration. A reboot restores the bdaddr to its original address. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_drv.h | 1 + drivers/bluetooth/btmrvl_main.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index caf684119a4e..38ad66289ad6 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -91,6 +91,7 @@ struct btmrvl_private { /* Vendor specific Bluetooth commands */ #define BT_CMD_PSCAN_WIN_REPORT_ENABLE 0xFC03 +#define BT_CMD_SET_BDADDR 0xFC22 #define BT_CMD_AUTO_SLEEP_MODE 0xFC23 #define BT_CMD_HOST_SLEEP_CONFIG 0xFC59 #define BT_CMD_HOST_SLEEP_ENABLE 0xFC5A diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index cc65fd2fe856..bae8e6a0ecf6 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -539,6 +539,29 @@ static int btmrvl_setup(struct hci_dev *hdev) return 0; } +static int btmrvl_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + long ret; + u8 buf[8]; + + buf[0] = MRVL_VENDOR_PKT; + buf[1] = sizeof(bdaddr_t); + memcpy(buf + 2, bdaddr, sizeof(bdaddr_t)); + + skb = __hci_cmd_sync(hdev, BT_CMD_SET_BDADDR, sizeof(buf), buf, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: changing btmrvl device address failed (%ld)", + hdev->name, ret); + return ret; + } + kfree_skb(skb); + + return 0; +} + /* * This function handles the event generated by firmware, rx data * received from firmware, and tx data sent from kernel. @@ -632,6 +655,7 @@ int btmrvl_register_hdev(struct btmrvl_private *priv) hdev->flush = btmrvl_flush; hdev->send = btmrvl_send_frame; hdev->setup = btmrvl_setup; + hdev->set_bdaddr = btmrvl_set_bdaddr; hdev->dev_type = priv->btmrvl_dev.dev_type; -- cgit v1.2.3 From e81fbf6cd65247e6c65719eacf2af5856db3d5a9 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Thu, 17 Jul 2014 18:34:44 -0700 Subject: libcxgbi:cxgb4i Guard ipv6 code with a config check Fixes: fc8d0590d914 ("libcxgbi: Add ipv6 api to driver") Fixes: 759a0cc5a3e1 ("cxgb4i: Add ipv6 code to driver, call into libcxgbi ipv6 api") Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 18 +++++++++++++++--- drivers/scsi/cxgbi/libcxgbi.c | 4 ++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 1041574edcfc..a4a4e98effdd 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -1289,8 +1289,14 @@ static int init_act_open(struct cxgbi_sock *csk) if (csk->csk_family == AF_INET) daddr = &csk->daddr.sin_addr.s_addr; - else +#if IS_ENABLED(CONFIG_IPV6) + else if (csk->csk_family == AF_INET6) daddr = &csk->daddr6.sin6_addr; +#endif + else { + pr_err("address family 0x%x not supported\n", csk->csk_family); + goto rel_resource; + } n = dst_neigh_lookup(csk->dst, daddr); @@ -1631,6 +1637,7 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev) return 0; } +#if IS_ENABLED(CONFIG_IPV6) static int cxgbi_inet6addr_handler(struct notifier_block *this, unsigned long event, void *data) { @@ -1755,6 +1762,7 @@ static void cxgbi_update_clip(struct cxgbi_device *cdev) } rcu_read_unlock(); } +#endif /* IS_ENABLED(CONFIG_IPV6) */ static void *t4_uld_add(const struct cxgb4_lld_info *lldi) { @@ -1874,7 +1882,9 @@ static int t4_uld_state_change(void *handle, enum cxgb4_state state) switch (state) { case CXGB4_STATE_UP: pr_info("cdev 0x%p, UP.\n", cdev); +#if IS_ENABLED(CONFIG_IPV6) cxgbi_update_clip(cdev); +#endif /* re-initialize */ break; case CXGB4_STATE_START_RECOVERY: @@ -1906,15 +1916,17 @@ static int __init cxgb4i_init_module(void) return rc; cxgb4_register_uld(CXGB4_ULD_ISCSI, &cxgb4i_uld_info); +#if IS_ENABLED(CONFIG_IPV6) register_inet6addr_notifier(&cxgbi_inet6addr_notifier); - +#endif return 0; } static void __exit cxgb4i_exit_module(void) { +#if IS_ENABLED(CONFIG_IPV6) unregister_inet6addr_notifier(&cxgbi_inet6addr_notifier); - +#endif cxgb4_unregister_uld(CXGB4_ULD_ISCSI); cxgbi_device_unregister_all(CXGBI_FLAG_DEV_T4); cxgbi_iscsi_cleanup(&cxgb4i_iscsi_transport, &cxgb4i_stt); diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index d2fe507fc695..3d5322d59f15 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -602,6 +602,7 @@ err_out: return ERR_PTR(err); } +#if IS_ENABLED(CONFIG_IPV6) static struct rt6_info *find_route_ipv6(const struct in6_addr *saddr, const struct in6_addr *daddr) { @@ -716,6 +717,7 @@ rel_rt: err_out: return ERR_PTR(err); } +#endif /* IS_ENABLED(CONFIG_IPV6) */ void cxgbi_sock_established(struct cxgbi_sock *csk, unsigned int snd_isn, unsigned int opt) @@ -2638,8 +2640,10 @@ struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost, if (dst_addr->sa_family == AF_INET) { csk = cxgbi_check_route(dst_addr); +#if IS_ENABLED(CONFIG_IPV6) } else if (dst_addr->sa_family == AF_INET6) { csk = cxgbi_check_route6(dst_addr); +#endif } else { pr_info("address family 0x%x NOT supported.\n", dst_addr->sa_family); -- cgit v1.2.3 From d1d588c181e35d98113f91c8004f77cdac2bf9d5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 20 Jul 2014 17:10:45 +0300 Subject: Bluetooth: Disable HCI_CONNECTABLE based passive scanning for now When HCI_CONNECTABLE is set the code has been enabling passive scanning in order to be consistent with BR/EDR and accept connections from any device doing directed advertising to us. However, some hardware (particularly CSR) can get very noisy even when doing duplicates filtering, making this feature waste resources. Considering that the feature is for fairly corner-case use (devices who'd use directed advertising would likely be in the whitelist anyway) it's better to disable it for now. It may still be brought back later, possibly with a better implementation (e.g. through improved scan parameters). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f575abdf2b4e..f82a6cf1aaa8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5465,8 +5465,7 @@ void hci_update_background_scan(struct hci_dev *hdev) hci_req_init(&req, hdev); - if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && - list_empty(&hdev->pend_le_conns) && + if (list_empty(&hdev->pend_le_conns) && list_empty(&hdev->pend_le_reports)) { /* If there is no pending LE connections or devices * to be scanned for, we should stop the background -- cgit v1.2.3 From 72dd2b2a44d82118714e0821fa16c65f9e40eb00 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 20 Jul 2014 17:29:59 +0200 Subject: Bluetooth: Fix endian and alignment issue with ath3k version handling The ath3k driver is treating the version information badly when it comes to loading the right firmware version and comparing that it actually matches with the hardware. Initially this showed up as this: CHECK drivers/bluetooth/ath3k.c drivers/bluetooth/ath3k.c:373:17: warning: cast to restricted __le32 drivers/bluetooth/ath3k.c:435:17: warning: cast to restricted __le32 However when fixing this by actually using __packed and __le32 for the ath3_version structure, more issues came up: CHECK drivers/bluetooth/ath3k.c drivers/bluetooth/ath3k.c:381:32: warning: incorrect type in assignment (different base types) drivers/bluetooth/ath3k.c:381:32: expected restricted __le32 [usertype] rom_version drivers/bluetooth/ath3k.c:381:32: got int [signed] drivers/bluetooth/ath3k.c:382:34: warning: incorrect type in assignment (different base types) drivers/bluetooth/ath3k.c:382:34: expected restricted __le32 [usertype] build_version drivers/bluetooth/ath3k.c:382:34: got int [signed] drivers/bluetooth/ath3k.c:386:28: warning: restricted __le32 degrades to integer drivers/bluetooth/ath3k.c:386:56: warning: restricted __le32 degrades to integer This patch fixes every instance of the firmware version handling and makes sure it is endian safe and uses proper unaligned access. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/ath3k.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 230c552daf91..a0d7355ef127 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #define VERSION "1.0" @@ -50,12 +51,12 @@ #define ATH3K_NAME_LEN 0xFF struct ath3k_version { - unsigned int rom_version; - unsigned int build_version; - unsigned int ram_version; - unsigned char ref_clock; - unsigned char reserved[0x07]; -}; + __le32 rom_version; + __le32 build_version; + __le32 ram_version; + __u8 ref_clock; + __u8 reserved[7]; +} __packed; static const struct usb_device_id ath3k_table[] = { /* Atheros AR3011 */ @@ -349,7 +350,8 @@ static int ath3k_load_patch(struct usb_device *udev) unsigned char fw_state; char filename[ATH3K_NAME_LEN] = {0}; const struct firmware *firmware; - struct ath3k_version fw_version, pt_version; + struct ath3k_version fw_version; + __u32 pt_rom_version, pt_build_version; int ret; ret = ath3k_get_state(udev, &fw_state); @@ -370,7 +372,7 @@ static int ath3k_load_patch(struct usb_device *udev) } snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu", - le32_to_cpu(fw_version.rom_version)); + le32_to_cpu(fw_version.rom_version)); ret = request_firmware(&firmware, filename, &udev->dev); if (ret < 0) { @@ -378,12 +380,13 @@ static int ath3k_load_patch(struct usb_device *udev) return ret; } - pt_version.rom_version = *(int *)(firmware->data + firmware->size - 8); - pt_version.build_version = *(int *) - (firmware->data + firmware->size - 4); + pt_rom_version = get_unaligned_le32(firmware->data + + firmware->size - 8); + pt_build_version = get_unaligned_le32(firmware->data + + firmware->size - 4); - if ((pt_version.rom_version != fw_version.rom_version) || - (pt_version.build_version <= fw_version.build_version)) { + if (pt_rom_version != le32_to_cpu(fw_version.rom_version) || + pt_build_version <= le32_to_cpu(fw_version.build_version)) { BT_ERR("Patch file version did not match with firmware"); release_firmware(firmware); return -EINVAL; -- cgit v1.2.3 From 0a961a440d693f0f74d3185728b13b8a11fc5860 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 20 Jul 2014 17:43:07 +0200 Subject: Bluetooth: Remove unneeded variable assignment in hmac_sha256 The variable ret does not need to be assigned when declaring it. So remove this initial assignment. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/amp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index e60603a8969f..016cdb66df6c 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -133,8 +133,8 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, /* AMP crypto key generation interface */ static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output) { - int ret = 0; struct crypto_shash *tfm; + int ret; if (!ksize) return -EINVAL; -- cgit v1.2.3 From 4b4dbca5e49eea2567d0da777fea2c86e7b89622 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Wed, 2 Jul 2014 09:01:56 -0700 Subject: NFC: digital: Check for NFC-DEP before checking for Type 4 tag In digital_in_recv_sel_res(), the code that determines the tag type will interpret bits 7:6 (lsb being b1 as per the Digital Specification) of a SEL RES set to 11b as a Type 4 tag. This is okay except that the neard will interpret the same value as an NFC-DEP device (in src/tag.c:set_tag_type() in the neard source). Make the digital layer's interpretation match neard's interpretation by changing the order of the checks in digital_in_recv_sel_res() so that a value of 11b in bits 7:6 is interpreted as an NFC-DEP device instead of a Type 4 tag. Acked-by: Thierry Escande Signed-off-by: Mark A. Greer Signed-off-by: Samuel Ortiz --- net/nfc/digital_technology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c index c2c1c0189b7c..d1684cbfea68 100644 --- a/net/nfc/digital_technology.c +++ b/net/nfc/digital_technology.c @@ -318,6 +318,8 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, if (DIGITAL_SEL_RES_IS_T2T(sel_res)) { nfc_proto = NFC_PROTO_MIFARE; + } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) { + nfc_proto = NFC_PROTO_NFC_DEP; } else if (DIGITAL_SEL_RES_IS_T4T(sel_res)) { rc = digital_in_send_rats(ddev, target); if (rc) @@ -327,8 +329,6 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, * done when receiving the ATS */ goto exit_free_skb; - } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) { - nfc_proto = NFC_PROTO_NFC_DEP; } else { rc = -EOPNOTSUPP; goto exit; -- cgit v1.2.3 From 0529a7adf3421acf251355444a012073abaffebc Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Wed, 2 Jul 2014 09:03:49 -0700 Subject: NFC: digital: Clear poll_tech_count before activating target Currently, digital_target_found() has a race between the events started by calling nfc_targets_found() (which ultimately expect ddev->poll_tech_count to be zero) and setting ddev->poll_tech_count to zero after the call to nfc_targets_found(). When the race is "lost" (i.e., ddev->poll_tech_count is found to not be zero by the events started by nfc_targets_found()), an error message is printed and the target is not found. A similar race exists when digital_tg_recv_atr_req() calls nfc_tm_activated(). Fix this by first saving the current value of ddev->poll_tech_count and then clearing it before calling nfc_targets_found()/nfc_tm_activated(). Clearing ddev->poll_tech_count before calling nfc_targets_found()/nfc_tm_activated() eliminates the race. Saving the value is required so it can be restored when nfc_targets_found()/nfc_tm_activated() fails and polling needs to continue. Acked-by: Thierry Escande Signed-off-by: Mark A. Greer Signed-off-by: Samuel Ortiz --- net/nfc/digital_core.c | 11 ++++++++--- net/nfc/digital_dep.c | 11 ++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c index a6ce3c627e4e..361bc37d2db1 100644 --- a/net/nfc/digital_core.c +++ b/net/nfc/digital_core.c @@ -299,6 +299,7 @@ int digital_target_found(struct nfc_digital_dev *ddev, int rc; u8 framing; u8 rf_tech; + u8 poll_tech_count; int (*check_crc)(struct sk_buff *skb); void (*add_crc)(struct sk_buff *skb); @@ -375,12 +376,16 @@ int digital_target_found(struct nfc_digital_dev *ddev, return rc; target->supported_protocols = (1 << protocol); - rc = nfc_targets_found(ddev->nfc_dev, target, 1); - if (rc) - return rc; + poll_tech_count = ddev->poll_tech_count; ddev->poll_tech_count = 0; + rc = nfc_targets_found(ddev->nfc_dev, target, 1); + if (rc) { + ddev->poll_tech_count = poll_tech_count; + return rc; + } + return 0; } diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index 171cb9949ab5..7cc1830633cc 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c @@ -673,6 +673,7 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, int rc; struct digital_atr_req *atr_req; size_t gb_len, min_size; + u8 poll_tech_count; if (IS_ERR(resp)) { rc = PTR_ERR(resp); @@ -730,12 +731,16 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, goto exit; gb_len = resp->len - sizeof(struct digital_atr_req); + + poll_tech_count = ddev->poll_tech_count; + ddev->poll_tech_count = 0; + rc = nfc_tm_activated(ddev->nfc_dev, NFC_PROTO_NFC_DEP_MASK, NFC_COMM_PASSIVE, atr_req->gb, gb_len); - if (rc) + if (rc) { + ddev->poll_tech_count = poll_tech_count; goto exit; - - ddev->poll_tech_count = 0; + } rc = 0; exit: -- cgit v1.2.3 From 55537c7e7d76417303c32f84a8dd1a12e02c4409 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Wed, 2 Jul 2014 10:16:15 -0700 Subject: NFC: digital: Add digital framing calls when in target mode Add new "NFC_DIGITAL_FRAMING_*" calls to the digital layer so the driver can make the necessary adjustments when performing anticollision while in target mode. The driver must ensure that the effect of these calls happens after the following response has been sent but before reception of the next request begins. Acked-by: Thierry Escande Signed-off-by: Mark A. Greer Signed-off-by: Samuel Ortiz --- include/net/nfc/digital.h | 2 ++ net/nfc/digital_technology.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/net/nfc/digital.h b/include/net/nfc/digital.h index bdf55c3b7a19..2bc31d10f9eb 100644 --- a/include/net/nfc/digital.h +++ b/include/net/nfc/digital.h @@ -49,6 +49,7 @@ enum { NFC_DIGITAL_FRAMING_NFCA_SHORT = 0, NFC_DIGITAL_FRAMING_NFCA_STANDARD, NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A, + NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE, NFC_DIGITAL_FRAMING_NFCA_T1T, NFC_DIGITAL_FRAMING_NFCA_T2T, @@ -66,6 +67,7 @@ enum { NFC_DIGITAL_FRAMING_NFCB, NFC_DIGITAL_FRAMING_NFCB_T4T, + NFC_DIGITAL_FRAMING_LAST, }; diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c index d1684cbfea68..d276518cc8bf 100644 --- a/net/nfc/digital_technology.c +++ b/net/nfc/digital_technology.c @@ -944,6 +944,13 @@ static int digital_tg_send_sel_res(struct nfc_digital_dev *ddev) if (!DIGITAL_DRV_CAPS_TG_CRC(ddev)) digital_skb_add_crc_a(skb); + rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, + NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE); + if (rc) { + kfree_skb(skb); + return rc; + } + rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_atr_req, NULL); if (rc) @@ -1002,6 +1009,13 @@ static int digital_tg_send_sdd_res(struct nfc_digital_dev *ddev) for (i = 0; i < 4; i++) sdd_res->bcc ^= sdd_res->nfcid1[i]; + rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, + NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A); + if (rc) { + kfree_skb(skb); + return rc; + } + rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sel_req, NULL); if (rc) @@ -1054,6 +1068,13 @@ static int digital_tg_send_sens_res(struct nfc_digital_dev *ddev) sens_res[0] = (DIGITAL_SENS_RES_NFC_DEP >> 8) & 0xFF; sens_res[1] = DIGITAL_SENS_RES_NFC_DEP & 0xFF; + rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, + NFC_DIGITAL_FRAMING_NFCA_STANDARD); + if (rc) { + kfree_skb(skb); + return rc; + } + rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sdd_req, NULL); if (rc) -- cgit v1.2.3 From 224e923cd9b001c612b7b68933264156271722f9 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 16 Jul 2014 14:25:31 -0700 Subject: net_sched: hold tcf_lock in netdevice notifier We modify mirred action (m->tcfm_dev) in netdev event, we need to prevent on-going mirred actions from reading freed m->tcfm_dev. So we need to acquire this spin lock. Cc: Jamal Hadi Salim Cc: "David S. Miller" Signed-off-by: Cong Wang Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/sched/act_mirred.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 4f912c0e225b..eb48306033d9 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -218,10 +218,12 @@ static int mirred_device_event(struct notifier_block *unused, if (event == NETDEV_UNREGISTER) list_for_each_entry(m, &mirred_list, tcfm_list) { + spin_lock_bh(&m->tcf_lock); if (m->tcfm_dev == dev) { dev_put(dev); m->tcfm_dev = NULL; } + spin_unlock_bh(&m->tcf_lock); } return NOTIFY_DONE; -- cgit v1.2.3 From 3e403a77779faf046862d91c36ef79fb4b12be9a Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Thu, 17 Jul 2014 17:02:23 +0200 Subject: bonding: make it possible to have unlimited nested upper vlans Currently we're limited by a constant level of vlan nestings, and fail to find anything beyound that level (currently 2). To fix this - remove the limit of nestings when going through device tree, and when the end device is found - allocate the needed amount of vlan tags and return them, instead of found/not found. CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.c | 8 ++-- drivers/net/bonding/bond_main.c | 82 +++++++++++++++++++++++++---------------- drivers/net/bonding/bonding.h | 7 ++-- 3 files changed, 58 insertions(+), 39 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index d3c6801f101e..95dd1f58c260 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1042,7 +1042,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[], struct bonding *bond = bond_get_bond_by_slave(slave); struct net_device *upper; struct list_head *iter; - struct bond_vlan_tag tags[BOND_MAX_VLAN_ENCAP]; + struct bond_vlan_tag *tags; /* send untagged */ alb_send_lp_vid(slave, mac_addr, 0, 0); @@ -1070,10 +1070,12 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[], * when strict_match is turned off. */ if (netif_is_macvlan(upper) && !strict_match) { - memset(tags, 0, sizeof(tags)); - bond_verify_device_path(bond->dev, upper, tags); + tags = bond_verify_device_path(bond->dev, upper, 0); + if (IS_ERR_OR_NULL(tags)) + BUG(); alb_send_lp_vid(slave, upper->dev_addr, tags[0].vlan_proto, tags[0].vlan_id); + kfree(tags); } } rcu_read_unlock(); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 14f789551616..023ec365209c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2145,7 +2145,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, struct bond_vlan_tag *tags) { struct sk_buff *skb; - int i; + struct bond_vlan_tag *outer_tag = tags; netdev_dbg(slave_dev, "arp %d on slave %s: dst %pI4 src %pI4\n", arp_op, slave_dev->name, &dest_ip, &src_ip); @@ -2158,30 +2158,42 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, return; } + if (!tags || tags->vlan_proto == VLAN_N_VID) + goto xmit; + + tags++; + /* Go through all the tags backwards and add them to the packet */ - for (i = BOND_MAX_VLAN_ENCAP - 1; i > 0; i--) { - if (!tags[i].vlan_id) + while (tags->vlan_proto != VLAN_N_VID) { + if (!tags->vlan_id) { + tags++; continue; + } netdev_dbg(slave_dev, "inner tag: proto %X vid %X\n", - ntohs(tags[i].vlan_proto), tags[i].vlan_id); - skb = __vlan_put_tag(skb, tags[i].vlan_proto, - tags[i].vlan_id); + ntohs(outer_tag->vlan_proto), tags->vlan_id); + skb = __vlan_put_tag(skb, tags->vlan_proto, + tags->vlan_id); if (!skb) { net_err_ratelimited("failed to insert inner VLAN tag\n"); return; } + + tags++; } /* Set the outer tag */ - if (tags[0].vlan_id) { + if (outer_tag->vlan_id) { netdev_dbg(slave_dev, "outer tag: proto %X vid %X\n", - ntohs(tags[0].vlan_proto), tags[0].vlan_id); - skb = vlan_put_tag(skb, tags[0].vlan_proto, tags[0].vlan_id); + ntohs(outer_tag->vlan_proto), outer_tag->vlan_id); + skb = vlan_put_tag(skb, outer_tag->vlan_proto, + outer_tag->vlan_id); if (!skb) { net_err_ratelimited("failed to insert outer VLAN tag\n"); return; } } + +xmit: arp_xmit(skb); } @@ -2191,46 +2203,50 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, * When the path is validated, collect any vlan information in the * path. */ -bool bond_verify_device_path(struct net_device *start_dev, - struct net_device *end_dev, - struct bond_vlan_tag *tags) +struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev, + struct net_device *end_dev, + int level) { + struct bond_vlan_tag *tags; struct net_device *upper; struct list_head *iter; - int idx; - if (start_dev == end_dev) - return true; + if (start_dev == end_dev) { + tags = kzalloc(sizeof(*tags) * (level + 1), GFP_ATOMIC); + if (!tags) + return ERR_PTR(-ENOMEM); + tags[level].vlan_proto = VLAN_N_VID; + return tags; + } netdev_for_each_upper_dev_rcu(start_dev, upper, iter) { - if (bond_verify_device_path(upper, end_dev, tags)) { - if (is_vlan_dev(upper)) { - idx = vlan_get_encap_level(upper); - if (idx >= BOND_MAX_VLAN_ENCAP) - return false; - - tags[idx].vlan_proto = - vlan_dev_vlan_proto(upper); - tags[idx].vlan_id = vlan_dev_vlan_id(upper); - } - return true; + tags = bond_verify_device_path(upper, end_dev, level + 1); + if (IS_ERR_OR_NULL(tags)) { + if (IS_ERR(tags)) + return tags; + continue; } + if (is_vlan_dev(upper)) { + tags[level].vlan_proto = vlan_dev_vlan_proto(upper); + tags[level].vlan_id = vlan_dev_vlan_id(upper); + } + + return tags; } - return false; + return NULL; } static void bond_arp_send_all(struct bonding *bond, struct slave *slave) { struct rtable *rt; - struct bond_vlan_tag tags[BOND_MAX_VLAN_ENCAP]; + struct bond_vlan_tag *tags; __be32 *targets = bond->params.arp_targets, addr; int i; - bool ret; for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) { netdev_dbg(bond->dev, "basa: target %pI4\n", &targets[i]); - memset(tags, 0, sizeof(tags)); + tags = NULL; /* Find out through which dev should the packet go */ rt = ip_route_output(dev_net(bond->dev), targets[i], 0, @@ -2253,10 +2269,10 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) goto found; rcu_read_lock(); - ret = bond_verify_device_path(bond->dev, rt->dst.dev, tags); + tags = bond_verify_device_path(bond->dev, rt->dst.dev, 0); rcu_read_unlock(); - if (ret) + if (!IS_ERR_OR_NULL(tags)) goto found; /* Not our device - skip */ @@ -2271,6 +2287,8 @@ found: ip_rt_put(rt); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], addr, tags); + if (!tags) + kfree(tags); } } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index a85ca51eabf5..aace510d08d1 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -36,7 +36,6 @@ #define bond_version DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n" -#define BOND_MAX_VLAN_ENCAP 2 #define BOND_MAX_ARP_TARGETS 16 #define BOND_DEFAULT_MIIMON 100 @@ -525,9 +524,9 @@ int bond_netlink_init(void); void bond_netlink_fini(void); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); const char *bond_slave_link_status(s8 link); -bool bond_verify_device_path(struct net_device *start_dev, - struct net_device *end_dev, - struct bond_vlan_tag *tags); +struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev, + struct net_device *end_dev, + int level); #ifdef CONFIG_PROC_FS void bond_create_proc_entry(struct bonding *bond); -- cgit v1.2.3 From c6f854d57d704a97adbf952ef0948acc68f3312c Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Thu, 17 Jul 2014 19:46:09 +0200 Subject: net: use dev->name in netdev_pr* when it's available netdev_name() returns dev->name only when the net_device is in NETREG_REGISTERED state. However, dev->name is always populated on creation, so we can easily use it. There are two cases when there's no real name - when it's an empty string or when the name is in form of "eth%d", then netdev_name() returns "unnamed net_device". CC: "David S. Miller" CC: Tom Gundersen Signed-off-by: Veaceslav Falico Acked-by: Tom Gundersen Signed-off-by: David S. Miller --- include/linux/netdevice.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 15ed750458ad..70256aa2ae81 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3383,8 +3383,8 @@ extern struct pernet_operations __net_initdata loopback_net_ops; static inline const char *netdev_name(const struct net_device *dev) { - if (dev->reg_state != NETREG_REGISTERED) - return "(unregistered net_device)"; + if (!dev->name[0] || strchr(dev->name, '%')) + return "(unnamed net_device)"; return dev->name; } -- cgit v1.2.3 From ccc7f4968a18b980994e622006b84e0195754390 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Thu, 17 Jul 2014 19:46:10 +0200 Subject: net: print net_device reg_state in netdev_* unless it's registered This way we'll always know in what status the device is, unless it's running normally (i.e. NETDEV_REGISTERED). Also, emit a warning once in case of a bad reg_state. CC: "David S. Miller" CC: Jason Baron CC: Eric Dumazet CC: Vlad Yasevich CC: stephen hemminger CC: Jerry Chu CC: Ben Hutchings CC: Joe Perches Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- include/linux/netdevice.h | 18 +++++++++++++++++- lib/dynamic_debug.c | 8 +++++--- net/core/dev.c | 8 +++++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 70256aa2ae81..8e8fb3ed574b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3388,6 +3388,21 @@ static inline const char *netdev_name(const struct net_device *dev) return dev->name; } +static inline const char *netdev_reg_state(const struct net_device *dev) +{ + switch (dev->reg_state) { + case NETREG_UNINITIALIZED: return " (uninitialized)"; + case NETREG_REGISTERED: return ""; + case NETREG_UNREGISTERING: return " (unregistering)"; + case NETREG_UNREGISTERED: return " (unregistered)"; + case NETREG_RELEASED: return " (released)"; + case NETREG_DUMMY: return " (dummy)"; + } + + WARN_ONCE(1, "%s: unknown reg_state %d\n", dev->name, dev->reg_state); + return " (unknown)"; +} + __printf(3, 4) int netdev_printk(const char *level, const struct net_device *dev, const char *format, ...); @@ -3444,7 +3459,8 @@ do { \ * file/line information and a backtrace. */ #define netdev_WARN(dev, format, args...) \ - WARN(1, "netdevice: %s\n" format, netdev_name(dev), ##args) + WARN(1, "netdevice: %s%s\n" format, netdev_name(dev), \ + netdev_reg_state(dev), ##args) /* netif printk helpers, similar to netdev_printk */ diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 7288e38e1757..c9afbe2c445a 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -614,13 +614,15 @@ int __dynamic_netdev_dbg(struct _ddebug *descriptor, char buf[PREFIX_SIZE]; res = dev_printk_emit(7, dev->dev.parent, - "%s%s %s %s: %pV", + "%s%s %s %s%s: %pV", dynamic_emit_prefix(descriptor, buf), dev_driver_string(dev->dev.parent), dev_name(dev->dev.parent), - netdev_name(dev), &vaf); + netdev_name(dev), netdev_reg_state(dev), + &vaf); } else if (dev) { - res = printk(KERN_DEBUG "%s: %pV", netdev_name(dev), &vaf); + res = printk(KERN_DEBUG "%s%s: %pV", netdev_name(dev), + netdev_reg_state(dev), &vaf); } else { res = printk(KERN_DEBUG "(NULL net_device): %pV", &vaf); } diff --git a/net/core/dev.c b/net/core/dev.c index 239722af098d..81d61014fd9b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6950,12 +6950,14 @@ static int __netdev_printk(const char *level, const struct net_device *dev, if (dev && dev->dev.parent) { r = dev_printk_emit(level[1] - '0', dev->dev.parent, - "%s %s %s: %pV", + "%s %s %s%s: %pV", dev_driver_string(dev->dev.parent), dev_name(dev->dev.parent), - netdev_name(dev), vaf); + netdev_name(dev), netdev_reg_state(dev), + vaf); } else if (dev) { - r = printk("%s%s: %pV", level, netdev_name(dev), vaf); + r = printk("%s%s%s: %pV", level, netdev_name(dev), + netdev_reg_state(dev), vaf); } else { r = printk("%s(NULL net_device): %pV", level, vaf); } -- cgit v1.2.3 From 6fe82a39e583a50f28f03b294df79c9de9ec0de4 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Thu, 17 Jul 2014 20:33:32 +0200 Subject: net: print a notification on device rename Currently it's done silently (from the kernel part), and thus it might be hard to track the renames from logs. Add a simple netdev_info() to notify the rename, but only in case the previous name was valid. CC: "David S. Miller" CC: Eric Dumazet CC: Vlad Yasevich CC: stephen hemminger CC: Jerry Chu CC: Ben Hutchings CC: David Laight Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- net/core/dev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index 81d61014fd9b..e52a3788d18d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1113,6 +1113,9 @@ int dev_change_name(struct net_device *dev, const char *newname) return err; } + if (oldname[0] && !strchr(oldname, '%')) + netdev_info(dev, "renamed from %s\n", oldname); + old_assign_type = dev->name_assign_type; dev->name_assign_type = NET_NAME_RENAMED; -- cgit v1.2.3 From fa4eff44a65c91c9ad09e5695ba171a107e5c327 Mon Sep 17 00:00:00 2001 From: Andrey Utkin Date: Fri, 18 Jul 2014 18:31:57 +0300 Subject: net/rxrpc/ar-key.c: drop negativity check on unsigned value Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=80611 Reported-by: David Binderman Signed-off-by: Andrey Utkin Signed-off-by: David S. Miller --- net/rxrpc/ar-key.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c index 0ad080790a32..eec998efd020 100644 --- a/net/rxrpc/ar-key.c +++ b/net/rxrpc/ar-key.c @@ -346,7 +346,7 @@ static int rxrpc_krb5_decode_tagged_array(struct krb5_tagged_data **_td, n_elem = ntohl(*xdr++); toklen -= 4; - if (n_elem < 0 || n_elem > max_n_elem) + if (n_elem > max_n_elem) return -EINVAL; *_n_elem = n_elem; if (n_elem > 0) { -- cgit v1.2.3 From 015435e002c6d1984962b8bef1ce38a01133e50a Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:16:09 +0200 Subject: dlci: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wan/dlci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index a463613a0719..43c9960dce1c 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -255,7 +255,6 @@ static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EINVAL; return dlci_config(dev, ifr->ifr_data, cmd == DLCI_GET_CONF); - break; default: return -EOPNOTSUPP; -- cgit v1.2.3 From 2db3a733127d58a9fe2dd9e68a2289c5d2dfe3c2 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:16:10 +0200 Subject: eth_v10: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/cris/eth_v10.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 29e272cc7a98..64c016a99af8 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -1496,7 +1496,6 @@ e100_set_config(struct net_device *dev, struct ifmap *map) case IF_PORT_AUI: spin_unlock(&np->lock); return -EOPNOTSUPP; - break; default: printk(KERN_ERR "%s: Invalid media selected", dev->name); spin_unlock(&np->lock); -- cgit v1.2.3 From 18a12348a5bce991d94f7d8c252f19e46cecb2f6 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:16:11 +0200 Subject: brcm80211: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 1 - drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index 588fdbdb3255..057b982ea8b3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -2364,7 +2364,6 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) return 0; default: return -ENOTSUPP; - break; } clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c index 3e9f5b25be63..93869e89aa3d 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c @@ -22916,7 +22916,6 @@ static void wlc_phy_rssi_cal_nphy_rev2(struct brcms_phy *pi, u8 rssi_type) break; default: return; - break; } classif_state = wlc_phy_classifier_nphy(pi, 0, 0); -- cgit v1.2.3 From 2b203e3cfe38a54270993193414582c3e03e4f26 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:16:12 +0200 Subject: mwl8k: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/mwl8k.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 3c0a0a86ba12..9a3d4d6724f7 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1633,22 +1633,17 @@ static int mwl8k_tid_queue_mapping(u8 tid) case 0: case 3: return IEEE80211_AC_BE; - break; case 1: case 2: return IEEE80211_AC_BK; - break; case 4: case 5: return IEEE80211_AC_VI; - break; case 6: case 7: return IEEE80211_AC_VO; - break; default: return -1; - break; } } -- cgit v1.2.3 From 4625b640b6044e0797f7199f7668bb15fa7dff50 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:16:13 +0200 Subject: rtlwifi: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/rtlwifi/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index b1ed6d0796f6..56e218e0469c 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -1064,7 +1064,6 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, "IEEE80211_AMPDU_TX_START: TID:%d\n", tid); return rtl_tx_agg_start(hw, sta, tid, ssn); - break; case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: -- cgit v1.2.3 From 384f0fcdcb97813ef8254a4229b4762ab9224896 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:16:14 +0200 Subject: rtlwifi: rtl8192ce: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index e2736929b5d0..df98a5e4729a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -1200,7 +1200,6 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Network type %d not supported!\n", type); return 1; - break; } -- cgit v1.2.3 From 4a4730ceab8f9592fa74871a226e578ade3e7175 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:16:15 +0200 Subject: rtlwifi: rtl8192se: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/rtlwifi/rtl8192se/fw.c | 3 --- drivers/net/wireless/rtlwifi/rtl8192se/hw.c | 1 - 2 files changed, 4 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c index 73fa4a1de4df..331b1584a1a2 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c @@ -112,13 +112,10 @@ static u8 _rtl92s_firmware_header_map_rftype(struct ieee80211_hw *hw) switch (rtlphy->rf_type) { case RF_1T1R: return 0x11; - break; case RF_1T2R: return 0x12; - break; case RF_2T2R: return 0x22; - break; default: RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "Unknown RF type(%x)\n", rtlphy->rf_type); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 1c7101bcd790..00e067044c08 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -1198,7 +1198,6 @@ static int _rtl92se_set_media_status(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Network type %d not supported!\n", type); return 1; - break; } -- cgit v1.2.3 From ae702c30e44fb1abbf37129a76663f3958a217bd Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:16:16 +0200 Subject: rtlwifi: rtl8723ae: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index 539e53987372..662a079f76f3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -1103,7 +1103,6 @@ static int _rtl8723ae_set_media_status(struct ieee80211_hw *hw, "Network type %d not supported!\n", type); return 1; - break; } -- cgit v1.2.3 From 7aa5a159fbec44224395c418dcadb7daefe14a16 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:16:17 +0200 Subject: rtlwifi: rtl8723be: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c index e4a507a756fb..4573310c707f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c @@ -124,7 +124,6 @@ bool rtlbe_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, "rtlbe_hal_pwrseqcmdparsing(): " "PWR_CMD_END\n"); return true; - break; default: RT_ASSERT(false, "rtlbe_hal_pwrseqcmdparsing(): " -- cgit v1.2.3 From 14aa5638f67309ed18e2fb67559e38b172abd127 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:25:11 +0200 Subject: rtlwifi: rtl8188ee: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c index a9cfa13be3a8..0f9314205526 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c @@ -125,7 +125,6 @@ bool rtl88_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version, RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_END\n"); return true; - break; default: RT_ASSERT(false, "rtl88_hal_pwrseqcmdparsing(): Unknown CMD!!\n"); -- cgit v1.2.3 From 21dceb6fbb91d0f17e899e4b165d0cc19d334061 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:25:12 +0200 Subject: prism54: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/prism54/oid_mgt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c index 47b34bfe890a..3a8d2dbcfecd 100644 --- a/drivers/net/wireless/prism54/oid_mgt.c +++ b/drivers/net/wireless/prism54/oid_mgt.c @@ -793,7 +793,6 @@ mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str) switch (isl_oid[n].flags & OID_FLAG_TYPE) { case OID_TYPE_U32: return snprintf(str, PRIV_STR_SIZE, "%u\n", r->u); - break; case OID_TYPE_BUFFER:{ struct obj_buffer *buff = r->ptr; return snprintf(str, PRIV_STR_SIZE, -- cgit v1.2.3 From d0421d18b8a314bd59806f804c8deebde4e32c84 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:25:13 +0200 Subject: cw1200: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/cw1200/fwio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c index e23d67e0bfe6..6f1b9aace8b3 100644 --- a/drivers/net/wireless/cw1200/fwio.c +++ b/drivers/net/wireless/cw1200/fwio.c @@ -290,7 +290,6 @@ static int config_reg_write(struct cw1200_common *priv, u32 val) case HIF_8601_SILICON: default: return cw1200_reg_write_32(priv, ST90TDS_CONFIG_REG_ID, val); - break; } return 0; } -- cgit v1.2.3 From 24707aa29932c1b433d9f816068b5e6c418c5715 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:25:14 +0200 Subject: airo: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/airo.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 29d88739454b..b39807579a8a 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -7818,7 +7818,6 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { case AIRORRID: ridcode = comp->ridnum; break; default: return -EINVAL; - break; } if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL) -- cgit v1.2.3 From d3274a056d31df7f572d0fcf259bed45b020dc5b Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:25:15 +0200 Subject: ath6kl: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/ath/ath6kl/init.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index d5ef211f261c..8ee7097f0b25 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1187,7 +1187,6 @@ static int ath6kl_upload_board_file(struct ath6kl *ar) default: WARN_ON(1); return -EINVAL; - break; } if (board_ext_address && -- cgit v1.2.3 From 3f0a4c1d401d1ed5d2055d45428091fc24fd7cc4 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:25:16 +0200 Subject: carl9170: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/wireless/ath/carl9170/phy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c index ab4ee7d39ad3..b80b2138ce3c 100644 --- a/drivers/net/wireless/ath/carl9170/phy.c +++ b/drivers/net/wireless/ath/carl9170/phy.c @@ -1139,7 +1139,6 @@ static int carl9170_set_freq_cal_data(struct ar9170 *ar, default: return -EINVAL; - break; } for (; i >= 0; i--) { -- cgit v1.2.3 From 4097ae93b8e01a669ac2c7f3fdda52295bbc8f1d Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:25:18 +0200 Subject: e1000: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/e1000/e1000_ethtool.c | 3 --- drivers/net/ethernet/intel/e1000/e1000_hw.c | 2 -- 2 files changed, 5 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index d50f78afb56d..cca5bca44e73 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -1316,7 +1316,6 @@ static int e1000_set_phy_loopback(struct e1000_adapter *adapter) case e1000_82547: case e1000_82547_rev_2: return e1000_integrated_phy_loopback(adapter); - break; default: /* Default PHY loopback work is to read the MII * control register and assert bit 14 (loopback mode). @@ -1325,7 +1324,6 @@ static int e1000_set_phy_loopback(struct e1000_adapter *adapter) phy_reg |= MII_CR_LOOPBACK; e1000_write_phy_reg(hw, PHY_CTRL, phy_reg); return 0; - break; } return 8; @@ -1344,7 +1342,6 @@ static int e1000_setup_loopback_test(struct e1000_adapter *adapter) case e1000_82545_rev_3: case e1000_82546_rev_3: return e1000_set_phy_loopback(adapter); - break; default: rctl = er32(RCTL); rctl |= E1000_RCTL_LBM_TCVR; diff --git a/drivers/net/ethernet/intel/e1000/e1000_hw.c b/drivers/net/ethernet/intel/e1000/e1000_hw.c index e9b07ccc0eba..1acf5034db10 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_hw.c +++ b/drivers/net/ethernet/intel/e1000/e1000_hw.c @@ -902,7 +902,6 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw) default: e_dbg("Flow control param set incorrectly\n"); return -E1000_ERR_CONFIG; - break; } /* Since auto-negotiation is enabled, take the link out of reset (the @@ -5041,7 +5040,6 @@ static s32 e1000_get_cable_length(struct e1000_hw *hw, u16 *min_length, break; default: return -E1000_ERR_PHY; - break; } } else if (hw->phy_type == e1000_phy_igp) { /* For IGP PHY */ u16 cur_agc_value; -- cgit v1.2.3 From bc80d0d5186e75de0397b0c818b2a5d507dfd413 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:25:19 +0200 Subject: ixgbe: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c | 1 - drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c index ea1c1ab926e2..75bcb2e08491 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c @@ -460,7 +460,6 @@ static int ixgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num) break; default: return -EINVAL; - break; } } else { return -EINVAL; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index a452730a3278..94a1c07efeb0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -1408,7 +1408,6 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) default: *data = 1; return 1; - break; } /* @@ -2866,7 +2865,6 @@ static int ixgbe_get_ts_info(struct net_device *dev, break; default: return ethtool_op_get_ts_info(dev, info); - break; } return 0; } -- cgit v1.2.3 From 4145ce0f59691820ea7e2c2be5d1c34aab61560e Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:25:20 +0200 Subject: e1000e: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/e1000e/82571.c | 4 ---- drivers/net/ethernet/intel/e1000e/ethtool.c | 2 -- drivers/net/ethernet/intel/e1000e/ich8lan.c | 1 - drivers/net/ethernet/intel/e1000e/mac.c | 1 - 4 files changed, 8 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c index 218481e509f9..dc79ed85030b 100644 --- a/drivers/net/ethernet/intel/e1000e/82571.c +++ b/drivers/net/ethernet/intel/e1000e/82571.c @@ -95,7 +95,6 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) break; default: return -E1000_ERR_PHY; - break; } /* This can only be done after all function pointers are setup. */ @@ -422,7 +421,6 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) break; case e1000_82573: return e1000e_get_phy_id(hw); - break; case e1000_82574: case e1000_82583: ret_val = e1e_rphy(hw, MII_PHYSID1, &phy_id); @@ -440,7 +438,6 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) break; default: return -E1000_ERR_PHY; - break; } return 0; @@ -1458,7 +1455,6 @@ static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw) break; default: return -E1000_ERR_PHY; - break; } if (ret_val) diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 815e26c6d34b..865ce45f9ec3 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -1521,11 +1521,9 @@ static int e1000_setup_loopback_test(struct e1000_adapter *adapter) switch (hw->mac.type) { case e1000_80003es2lan: return e1000_set_es2lan_mac_loopback(adapter); - break; case e1000_82571: case e1000_82572: return e1000_set_82571_fiber_loopback(adapter); - break; default: rctl = er32(RCTL); rctl |= E1000_RCTL_LBM_TCVR; diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 8894ab8ed6bd..f236861c2a31 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -572,7 +572,6 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) break; default: return -E1000_ERR_PHY; - break; } return 0; diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c index 8c386f3a15eb..30b74d590bee 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.c +++ b/drivers/net/ethernet/intel/e1000e/mac.c @@ -787,7 +787,6 @@ static s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw) default: e_dbg("Flow control param set incorrectly\n"); return -E1000_ERR_CONFIG; - break; } ew32(TXCW, txcw); -- cgit v1.2.3 From 2a79febdc28e93425f30ca2ebc491185b5b333bc Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:27:45 +0200 Subject: igb: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/igb/e1000_82575.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 72b454ce05ac..236a6183a865 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -579,7 +579,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) break; default: return -E1000_ERR_MAC_INIT; - break; } /* Set media type */ -- cgit v1.2.3 From d2e5f47a6eafbea47347b9259a6b2fd5050a5444 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:27:46 +0200 Subject: 8390: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/8390/mac8390.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/ethernet/8390/mac8390.c b/drivers/net/ethernet/8390/mac8390.c index 90e825e8abfe..65cf60f6718c 100644 --- a/drivers/net/ethernet/8390/mac8390.c +++ b/drivers/net/ethernet/8390/mac8390.c @@ -178,10 +178,8 @@ static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev) case NUBUS_DRHW_APPLE_SONIC_LC: case NUBUS_DRHW_SONNET: return MAC8390_NONE; - break; default: return MAC8390_APPLE; - break; } break; @@ -189,13 +187,10 @@ static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev) switch (dev->dr_hw) { case NUBUS_DRHW_ASANTE_LC: return MAC8390_NONE; - break; case NUBUS_DRHW_CABLETRON: return MAC8390_CABLETRON; - break; default: return MAC8390_APPLE; - break; } break; @@ -220,10 +215,8 @@ static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev) switch (dev->dr_hw) { case NUBUS_DRHW_INTERLAN: return MAC8390_INTERLAN; - break; default: return MAC8390_KINETICS; - break; } break; @@ -563,7 +556,6 @@ static int __init mac8390_initdev(struct net_device *dev, case ACCESS_UNKNOWN: pr_err("Don't know how to access card memory!\n"); return -ENODEV; - break; case ACCESS_16: /* 16 bit card, register map is reversed */ -- cgit v1.2.3 From 32172654fa92771c612aa59eaa3e6a4349d90dd7 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:27:47 +0200 Subject: net: tulip: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/dec/tulip/de4x5.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/dec/tulip/de4x5.c b/drivers/net/ethernet/dec/tulip/de4x5.c index c05b66dfcc30..7091fa6ed096 100644 --- a/drivers/net/ethernet/dec/tulip/de4x5.c +++ b/drivers/net/ethernet/dec/tulip/de4x5.c @@ -3250,7 +3250,6 @@ srom_map_media(struct net_device *dev) printk("%s: Bad media code [%d] detected in SROM!\n", dev->name, lp->infoblock_media); return -1; - break; } return 0; -- cgit v1.2.3 From 6644db0c6db0a14b81bc4bba444fdace6ccc2647 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:27:48 +0200 Subject: bna: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/brocade/bna/cna_fwimg.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/brocade/bna/cna_fwimg.c b/drivers/net/ethernet/brocade/bna/cna_fwimg.c index 6a68e8d93309..6f72771caea6 100644 --- a/drivers/net/ethernet/brocade/bna/cna_fwimg.c +++ b/drivers/net/ethernet/brocade/bna/cna_fwimg.c @@ -68,10 +68,8 @@ bfa_cb_image_get_chunk(enum bfi_asic_gen asic_gen, u32 off) switch (asic_gen) { case BFI_ASIC_GEN_CT: return (bfi_image_ct_cna + off); - break; case BFI_ASIC_GEN_CT2: return (bfi_image_ct2_cna + off); - break; default: return NULL; } @@ -83,10 +81,8 @@ bfa_cb_image_get_size(enum bfi_asic_gen asic_gen) switch (asic_gen) { case BFI_ASIC_GEN_CT: return bfi_image_ct_cna_size; - break; case BFI_ASIC_GEN_CT2: return bfi_image_ct2_cna_size; - break; default: return 0; } -- cgit v1.2.3 From 3317aeb732e9386e6fec367fe325b17e12e8178d Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:27:49 +0200 Subject: sis900: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/sis/sis900.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c index 6072f093e6b4..7bea17c41dc9 100644 --- a/drivers/net/ethernet/sis/sis900.c +++ b/drivers/net/ethernet/sis/sis900.c @@ -2258,7 +2258,6 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map) case IF_PORT_100BASEFX: /* 100BaseFx */ /* These Modes are not supported (are they?)*/ return -EOPNOTSUPP; - break; default: return -EINVAL; -- cgit v1.2.3 From f6ec2f3204b1c0b3ca468d0cb805784c01b890e5 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:27:50 +0200 Subject: niu: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/sun/niu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index 79606f47a08e..db8ffde491b5 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -2584,7 +2584,6 @@ static int niu_determine_phy_disposition(struct niu *np) break; default: return -EINVAL; - break; } phy_addr_off = niu_atca_port_num[np->port]; break; -- cgit v1.2.3 From 56a7a06ab8e12fa8121c549279fce0b9bc788392 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:27:51 +0200 Subject: ucc_geth: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/ucc_geth.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index 36fc429298e3..8ceaf7a2660c 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -2396,7 +2396,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) pr_err("Bad number of Rx threads value\n"); return -EINVAL; - break; } switch (ug_info->numThreadsTx) { @@ -2419,7 +2418,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) pr_err("Bad number of Tx threads value\n"); return -EINVAL; - break; } /* Calculate rx_extended_features */ -- cgit v1.2.3 From a9690a8c748a9e5c47a3a0ebdeba0516f4acdda6 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:27:52 +0200 Subject: atl1e: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/atheros/atl1e/atl1e_hw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_hw.c b/drivers/net/ethernet/atheros/atl1e/atl1e_hw.c index 923063d2e5bb..113565da155f 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_hw.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_hw.c @@ -618,7 +618,6 @@ int atl1e_get_speed_and_duplex(struct atl1e_hw *hw, u16 *speed, u16 *duplex) break; default: return AT_ERR_PHY_SPEED; - break; } if (phy_data & MII_AT001_PSSR_DPLX) -- cgit v1.2.3 From 9fb1d03acf472da4b2c588bd6921e815e5991cc6 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:27:53 +0200 Subject: atlx: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/atheros/atlx/atl1.c | 1 - drivers/net/ethernet/atheros/atlx/atl2.c | 3 --- 2 files changed, 4 deletions(-) diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c index b460db7919a2..1546d550ac97 100644 --- a/drivers/net/ethernet/atheros/atlx/atl1.c +++ b/drivers/net/ethernet/atheros/atlx/atl1.c @@ -910,7 +910,6 @@ static s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex if (netif_msg_hw(adapter)) dev_dbg(&pdev->dev, "error getting speed\n"); return ATLX_ERR_PHY_SPEED; - break; } if (phy_data & MII_ATLX_PSSR_DPLX) *duplex = FULL_DUPLEX; diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c index 6746bd717146..c194bc687c30 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.c +++ b/drivers/net/ethernet/atheros/atlx/atl2.c @@ -2493,7 +2493,6 @@ static s32 atl2_get_speed_and_duplex(struct atl2_hw *hw, u16 *speed, break; default: return ATLX_ERR_PHY_SPEED; - break; } if (phy_data & MII_ATLX_PSSR_DPLX) @@ -2933,11 +2932,9 @@ static int atl2_validate_option(int *value, struct atl2_option *opt) case OPTION_ENABLED: printk(KERN_INFO "%s Enabled\n", opt->name); return 0; - break; case OPTION_DISABLED: printk(KERN_INFO "%s Disabled\n", opt->name); return 0; - break; } break; case range_option: -- cgit v1.2.3 From cbda50138774eaf5dbce145ebb045424a30880b9 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:27:54 +0200 Subject: atl1c: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/atheros/atl1c/atl1c_hw.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c index 1cda49a28f7f..52fdfe225978 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c @@ -639,7 +639,6 @@ int atl1c_phy_init(struct atl1c_hw *hw) dev_err(&pdev->dev, "Wrong Media type %d\n", hw->media_type); return -1; - break; } ret_val = atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data); @@ -682,7 +681,6 @@ int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex) break; default: return -1; - break; } if (phy_data & GIGA_PSSR_DPLX) -- cgit v1.2.3 From b684106a53c42f1cd089c09809d236036e2af5ad Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 20 Jul 2014 16:30:48 +0200 Subject: ps3_gelic: remove unnecessary break after return Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/ethernet/toshiba/ps3_gelic_wireless.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c index 2553ed5d2ece..0a7f2e77557f 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c +++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c @@ -1828,25 +1828,18 @@ static const char *wpasecstr(enum gelic_eurus_wpa_security sec) switch (sec) { case GELIC_EURUS_WPA_SEC_NONE: return "NONE"; - break; case GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP: return "WPA_TKIP_TKIP"; - break; case GELIC_EURUS_WPA_SEC_WPA_TKIP_AES: return "WPA_TKIP_AES"; - break; case GELIC_EURUS_WPA_SEC_WPA_AES_AES: return "WPA_AES_AES"; - break; case GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP: return "WPA2_TKIP_TKIP"; - break; case GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES: return "WPA2_TKIP_AES"; - break; case GELIC_EURUS_WPA_SEC_WPA2_AES_AES: return "WPA2_AES_AES"; - break; } return ""; }; -- cgit v1.2.3 From 52f50ce556af7008e1c2088d8b2b778ef5e79ff1 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 20 Jul 2014 13:14:28 +0800 Subject: tipc: fix sparse non static symbol warnings Fixes the following sparse warnings: net/tipc/socket.c:545:5: warning: symbol 'tipc_sk_proto_rcv' was not declared. Should it be static? net/tipc/socket.c:2015:5: warning: symbol 'tipc_ioctl' was not declared. Should it be static? Signed-off-by: Wei Yongjun Acked-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/socket.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 5ad42f6137d8..8477d08a6aa0 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -635,7 +635,8 @@ void tipc_sk_mcast_rcv(struct sk_buff *buf) * Returns 0 (TIPC_OK) if message was consumed, 1 (TIPC_FWD_MSG) if * (CONN_PROBE_REPLY) message should be forwarded. */ -int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode, struct sk_buff *buf) +static int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode, + struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); struct tipc_port *port = &tsk->port; @@ -2068,7 +2069,7 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt, return put_user(sizeof(value), ol); } -int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) +static int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) { struct tipc_sioc_ln_req lnr; void __user *argp = (void __user *)arg; -- cgit v1.2.3 From 468f8646df637e3e298e9c3d87211bf1b045c321 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 20 Jul 2014 21:57:17 +0800 Subject: net: mvpp2: Remove redundant dev_err call in mvpp2_port_probe() There is a error message within devm_ioremap_resource already, so remove the dev_err call to avoid redundant error message. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index f4de2a9316ff..f8e1953aeb59 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -6062,7 +6062,6 @@ static int mvpp2_port_probe(struct platform_device *pdev, port->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(port->base)) { err = PTR_ERR(port->base); - dev_err(&pdev->dev, "cannot obtain port base address\n"); goto err_free_irq; } -- cgit v1.2.3 From 575a19354c80fde236382755592256d30d2a27fb Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 20 Jul 2014 22:02:43 +0800 Subject: net: mvpp2: Fix error return code in mvpp2_probe() Fix to return -ENODEV from the no ports enabled error handling case instead of 0. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index f8e1953aeb59..4f6e4a1400e7 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -6307,6 +6307,7 @@ static int mvpp2_probe(struct platform_device *pdev) port_count = of_get_available_child_count(dn); if (port_count == 0) { dev_err(&pdev->dev, "no ports enabled\n"); + err = -ENODEV; goto err_gop_clk; } -- cgit v1.2.3 From 745160ee10b76ed739f78f0116ab3d17b3f77309 Mon Sep 17 00:00:00 2001 From: Oren Givon Date: Mon, 16 Jun 2014 10:54:52 +0300 Subject: iwlwifi: add max RX aggregation size Allow to configure the maximal Rx AMPDU size per device. Signed-off-by: Oren Givon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl-config.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/ops.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 51486cc9d943..44b19e015102 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -85,6 +85,9 @@ #define NVM_HW_SECTION_NUM_FAMILY_8000 10 #define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin" +/* Max SDIO RX aggregation size of the ADDBA request/response */ +#define MAX_RX_AGG_SIZE_8260_SDIO 28 + static const struct iwl_base_params iwl8000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, .num_of_queues = IWLAGN_NUM_QUEUES, @@ -129,6 +132,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, + .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, }; MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 034c2fc4b69f..8da596db9abe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -240,6 +240,7 @@ struct iwl_pwr_tx_backoff { * @d0i3: device uses d0i3 instead of d3 * @nvm_hw_section_num: the ID of the HW NVM section * @pwr_tx_backoffs: translation table between power limits and backoffs + * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -276,6 +277,7 @@ struct iwl_cfg { const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; bool no_power_up_nic_in_init; const char *default_nvm_file; + unsigned int max_rx_agg_size; }; /* diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 7d7b2fbe7cd1..7f0e9afe8f25 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -391,6 +391,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (!hw) return NULL; + if (cfg->max_rx_agg_size) + hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size; + op_mode = hw->priv; op_mode->ops = &iwl_mvm_ops; -- cgit v1.2.3 From ae7486a2b734ee039bec94427c25317c589f1664 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 7 Jul 2014 09:25:42 +0300 Subject: iwlwifi: fix Kconfig issues Randy fixes a few issues in iwlwifi's Kconfig. Because of this, 'Debugging options' was not indented under iwlwifi using menuconfig. I added a few other fixes on the way, like the link to the website and added 7265 in the supported NICs. Reported-by: Larry Finger Signed-off-by: Randy Dunlap Reviewed-by: Johannes Berg [ Commit message + other fixes ] Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/Kconfig | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 7fd50428b934..6451d2b6abcf 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -20,16 +20,17 @@ config IWLWIFI Intel 2000 Series Wi-Fi Adapters Intel 7260 Wi-Fi Adapter Intel 3160 Wi-Fi Adapter + Intel 7265 Wi-Fi Adapter This driver uses the kernel's mac80211 subsystem. - In order to use this driver, you will need a microcode (uCode) + In order to use this driver, you will need a firmware image for it. You can obtain the microcode from: - . + . - The microcode is typically installed in /lib/firmware. You can + The firmware is typically installed in /lib/firmware. You can look in the hotplug script /etc/hotplug/firmware.agent to determine which directory FIRMWARE_DIR is set to when the script runs. @@ -39,9 +40,10 @@ config IWLWIFI say M here and read . The module will be called iwlwifi. +if IWLWIFI + config IWLWIFI_LEDS bool - depends on IWLWIFI depends on LEDS_CLASS=y || LEDS_CLASS=IWLWIFI select LEDS_TRIGGERS select MAC80211_LEDS @@ -49,7 +51,7 @@ config IWLWIFI_LEDS config IWLDVM tristate "Intel Wireless WiFi DVM Firmware support" - depends on IWLWIFI + depends on m default IWLWIFI help This is the driver that supports the DVM firmware which is @@ -58,7 +60,7 @@ config IWLDVM config IWLMVM tristate "Intel Wireless WiFi MVM Firmware support" - depends on IWLWIFI + depends on m help This is the driver that supports the MVM firmware which is currently only available for 7260 and 3160 devices. @@ -70,7 +72,7 @@ config IWLWIFI_OPMODE_MODULAR default y if IWLMVM=m comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM" - depends on IWLWIFI && IWLDVM=n && IWLMVM=n + depends on IWLDVM=n && IWLMVM=n config IWLWIFI_BCAST_FILTERING bool "Enable broadcast filtering" @@ -86,11 +88,9 @@ config IWLWIFI_BCAST_FILTERING expect incoming broadcasts for their normal operations. menu "Debugging Options" - depends on IWLWIFI config IWLWIFI_DEBUG bool "Enable full debugging output in the iwlwifi driver" - depends on IWLWIFI ---help--- This option will enable debug tracing output for the iwlwifi drivers @@ -115,7 +115,7 @@ config IWLWIFI_DEBUG config IWLWIFI_DEBUGFS bool "iwlwifi debugfs support" - depends on IWLWIFI && MAC80211_DEBUGFS + depends on MAC80211_DEBUGFS ---help--- Enable creation of debugfs files for the iwlwifi drivers. This is a low-impact option that allows getting insight into the @@ -123,13 +123,12 @@ config IWLWIFI_DEBUGFS config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE bool "Experimental uCode support" - depends on IWLWIFI && IWLWIFI_DEBUG + depends on IWLWIFI_DEBUG ---help--- Enable use of experimental ucode for testing and debugging. config IWLWIFI_DEVICE_TRACING bool "iwlwifi device access tracing" - depends on IWLWIFI depends on EVENT_TRACING help Say Y here to trace all commands, including TX frames and IO @@ -145,3 +144,5 @@ config IWLWIFI_DEVICE_TRACING If unsure, say Y so we can help you better when problems occur. endmenu + +endif -- cgit v1.2.3 From 4b8265ab4d701989bc70371ecc4347c9debc1a03 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 13 Jul 2014 08:58:04 +0300 Subject: iwlwifi: mvm: use C99 initializers for add_sta Instead of code the fixed values, use a C99 initializer. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/sta.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 812813964847..54459345c967 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -98,23 +98,21 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, bool update) { struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; - struct iwl_mvm_add_sta_cmd add_sta_cmd; + struct iwl_mvm_add_sta_cmd add_sta_cmd = { + .sta_id = mvm_sta->sta_id, + .mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color), + .add_modify = update ? 1 : 0, + .station_flags_msk = cpu_to_le32(STA_FLG_FAT_EN_MSK | + STA_FLG_MIMO_EN_MSK), + }; int ret; u32 status; u32 agg_size = 0, mpdu_dens = 0; - memset(&add_sta_cmd, 0, sizeof(add_sta_cmd)); - - add_sta_cmd.sta_id = mvm_sta->sta_id; - add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); if (!update) { add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); } - add_sta_cmd.add_modify = update ? 1 : 0; - - add_sta_cmd.station_flags_msk |= cpu_to_le32(STA_FLG_FAT_EN_MSK | - STA_FLG_MIMO_EN_MSK); switch (sta->bandwidth) { case IEEE80211_STA_RX_BW_160: -- cgit v1.2.3 From 51ea1c7dbd4c5151b7f5777cabc505d43d2c42cb Mon Sep 17 00:00:00 2001 From: Eytan Lifshitz Date: Wed, 2 Jul 2014 20:52:02 +0300 Subject: iwlwifi: mvm: fix wrong offset while reading from NVM As part of thermal throttling, some data is being read from NVM. The offset is in words, but was addressed as in octets. fixed. Signed-off-by: Eytan Lifshitz Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 868561512783..0c4ff3a57ade 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -140,9 +140,9 @@ static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm) /* TODO: move parsing to NVM code */ calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data; - ptat = calib[OTP_DTS_DIODE_DEVIATION]; - pa1 = calib[OTP_DTS_DIODE_DEVIATION + 1]; - pa2 = calib[OTP_DTS_DIODE_DEVIATION + 2]; + ptat = calib[OTP_DTS_DIODE_DEVIATION * 2]; + pa1 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 1]; + pa2 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 2]; /* get the median: */ if (ptat > pa1) { -- cgit v1.2.3 From 576eeee9d3ab395f47462c03067c8b9381281f1d Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 1 Jul 2014 18:38:38 +0300 Subject: iwlwifi: mvm: add some missing iwl_mvm_ref_sync() calls Add iwl_mvm_ref_sync() calls (with new ref types) to flows that might access the device directly. These calls make sure the device is out of d0i3, and the bus is available for direct access. Since some of these functions are reentrant, convert the refs_bitmap to a ref counter, so multiple refs of the same type could be taken concurrently. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 43 +++++++++++++++---- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 66 ++++++++++++++++++++++++----- drivers/net/wireless/iwlwifi/mvm/mvm.h | 15 ++++++- drivers/net/wireless/iwlwifi/mvm/ops.c | 3 +- drivers/net/wireless/iwlwifi/mvm/tt.c | 6 +++ 5 files changed, 110 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index f131ef0ec5b3..ac9787c09248 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -830,8 +830,14 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { + int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI); + if (ret) + return ret; + iwl_force_nmi(mvm->trans); + iwl_mvm_unref(mvm, IWL_MVM_REF_NMI); + return count; } @@ -1115,11 +1121,11 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, } #endif -#define PRINT_MVM_REF(ref) do { \ - if (test_bit(ref, mvm->ref_bitmap)) \ - pos += scnprintf(buf + pos, bufsz - pos, \ - "\t(0x%lx) %s\n", \ - BIT(ref), #ref); \ +#define PRINT_MVM_REF(ref) do { \ + if (mvm->refs[ref]) \ + pos += scnprintf(buf + pos, bufsz - pos, \ + "\t(0x%lx): %d %s\n", \ + BIT(ref), mvm->refs[ref], #ref); \ } while (0) static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, @@ -1127,12 +1133,17 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - int pos = 0; + int i, pos = 0; char buf[256]; const size_t bufsz = sizeof(buf); + u32 refs = 0; + + for (i = 0; i < IWL_MVM_REF_COUNT; i++) + if (mvm->refs[i]) + refs |= BIT(i); - pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%lx\n", - mvm->ref_bitmap[0]); + pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%x\n", + refs); PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN); PRINT_MVM_REF(IWL_MVM_REF_SCAN); @@ -1158,7 +1169,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf, mutex_lock(&mvm->mutex); - taken = test_bit(IWL_MVM_REF_USER, mvm->ref_bitmap); + taken = mvm->refs[IWL_MVM_REF_USER]; if (value == 1 && !taken) iwl_mvm_ref(mvm, IWL_MVM_REF_USER); else if (value == 0 && taken) @@ -1194,14 +1205,21 @@ iwl_dbgfs_prph_reg_read(struct file *file, int pos = 0; char buf[32]; const size_t bufsz = sizeof(buf); + int ret; if (!mvm->dbgfs_prph_reg_addr) return -EINVAL; + ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_READ); + if (ret) + return ret; + pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n", mvm->dbgfs_prph_reg_addr, iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr)); + iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_READ); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -1211,6 +1229,7 @@ iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf, { u8 args; u32 value; + int ret; args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value); /* if we only want to set the reg address - nothing more to do */ @@ -1221,7 +1240,13 @@ iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf, if (args != 2) return -EINVAL; + ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); + if (ret) + return ret; + iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value); + + iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); out: return count; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 2eb6ebee4467..12a9aed7a5d3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -211,7 +211,9 @@ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) return; IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type); - WARN_ON(test_and_set_bit(ref_type, mvm->ref_bitmap)); + spin_lock_bh(&mvm->refs_lock); + mvm->refs[ref_type]++; + spin_unlock_bh(&mvm->refs_lock); iwl_trans_ref(mvm->trans); } @@ -221,29 +223,35 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) return; IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type); - WARN_ON(!test_and_clear_bit(ref_type, mvm->ref_bitmap)); + spin_lock_bh(&mvm->refs_lock); + WARN_ON(!mvm->refs[ref_type]--); + spin_unlock_bh(&mvm->refs_lock); iwl_trans_unref(mvm->trans); } -static void -iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref) +static void iwl_mvm_unref_all_except(struct iwl_mvm *mvm, + enum iwl_mvm_ref_type except_ref) { - int i; + int i, j; if (!iwl_mvm_is_d0i3_supported(mvm)) return; - for_each_set_bit(i, mvm->ref_bitmap, IWL_MVM_REF_COUNT) { - if (ref == i) + spin_lock_bh(&mvm->refs_lock); + for (i = 0; i < IWL_MVM_REF_COUNT; i++) { + if (except_ref == i || !mvm->refs[i]) continue; - IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d\n", i); - clear_bit(i, mvm->ref_bitmap); - iwl_trans_unref(mvm->trans); + IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d (%d)\n", + i, mvm->refs[i]); + for (j = 0; j < mvm->refs[i]; j++) + iwl_trans_unref(mvm->trans); + mvm->refs[i] = 0; } + spin_unlock_bh(&mvm->refs_lock); } -static int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) +int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) { iwl_mvm_ref(mvm, ref_type); @@ -1533,6 +1541,14 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; + /* + * iwl_mvm_mac_ctxt_add() might read directly from the device + * (the system time), so make sure it is available. + */ + ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_START_AP); + if (ret) + return ret; + mutex_lock(&mvm->mutex); /* Send the beacon template */ @@ -1594,6 +1610,7 @@ out_remove: iwl_mvm_mac_ctxt_remove(mvm, vif); out_unlock: mutex_unlock(&mvm->mutex); + iwl_mvm_unref(mvm, IWL_MVM_REF_START_AP); return ret; } @@ -1671,6 +1688,14 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + /* + * iwl_mvm_bss_info_changed_station() might call + * iwl_mvm_protect_session(), which reads directly from + * the device (the system time), so make sure it is available. + */ + if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_BSS_CHANGED)) + return; + mutex_lock(&mvm->mutex); if (changes & BSS_CHANGED_IDLE && !bss_conf->idle) @@ -1690,6 +1715,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, } mutex_unlock(&mvm->mutex); + iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED); } static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, @@ -2065,10 +2091,19 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, if (WARN_ON_ONCE(vif->bss_conf.assoc)) return; + /* + * iwl_mvm_protect_session() reads directly from the device + * (the system time), so make sure it is available. + */ + if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PREPARE_TX)) + return; + mutex_lock(&mvm->mutex); /* Try really hard to protect the session and hear a beacon */ iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500); mutex_unlock(&mvm->mutex); + + iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX); } static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, @@ -2077,10 +2112,19 @@ static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; + /* + * iwl_mvm_protect_session() reads directly from the device + * (the system time), so make sure it is available. + */ + if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) + return; + mutex_lock(&mvm->mutex); /* Protect the session to hear the TDLS setup response on the channel */ iwl_mvm_protect_session(mvm, vif, duration, duration, 100); mutex_unlock(&mvm->mutex); + + iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); } static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 785e5232c757..24c12c77d93a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -249,6 +249,15 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_TX, IWL_MVM_REF_TX_AGG, IWL_MVM_REF_ADD_IF, + IWL_MVM_REF_START_AP, + IWL_MVM_REF_BSS_CHANGED, + IWL_MVM_REF_PREPARE_TX, + IWL_MVM_REF_PROTECT_TDLS, + IWL_MVM_REF_CHECK_CTKILL, + IWL_MVM_REF_PRPH_READ, + IWL_MVM_REF_PRPH_WRITE, + IWL_MVM_REF_NMI, + IWL_MVM_REF_TM_CMD, IWL_MVM_REF_EXIT_WORK, IWL_MVM_REF_COUNT, @@ -606,8 +615,9 @@ struct iwl_mvm { */ unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; - /* A bitmap of reference types taken by the driver. */ - unsigned long ref_bitmap[BITS_TO_LONGS(IWL_MVM_REF_COUNT)]; + /* references taken by the driver and spinlock protecting them */ + spinlock_t refs_lock; + u8 refs[IWL_MVM_REF_COUNT]; u8 vif_count; @@ -988,6 +998,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, /* D0i3 */ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); +int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 7f0e9afe8f25..19a66b590277 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -428,6 +428,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); spin_lock_init(&mvm->d0i3_tx_lock); + spin_lock_init(&mvm->refs_lock); skb_queue_head_init(&mvm->d0i3_tx); init_waitqueue_head(&mvm->d0i3_exit_waitq); @@ -542,7 +543,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); /* rpm starts with a taken ref. only set the appropriate bit here. */ - set_bit(IWL_MVM_REF_UCODE_DOWN, mvm->ref_bitmap); + mvm->refs[IWL_MVM_REF_UCODE_DOWN] = 1; return op_mode; diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 0c4ff3a57ade..0464599c111e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -338,10 +338,16 @@ static void check_exit_ctkill(struct work_struct *work) duration = tt->params->ct_kill_duration; + /* make sure the device is available for direct read/writes */ + if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) + goto reschedule; + iwl_trans_start_hw(mvm->trans); temp = check_nic_temperature(mvm); iwl_trans_stop_device(mvm->trans); + iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL); + if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); goto reschedule; -- cgit v1.2.3 From 7da91b0ee4884568cb91a77cff122c84953e5698 Mon Sep 17 00:00:00 2001 From: Ariej Marjieh Date: Mon, 7 Jul 2014 12:09:40 +0300 Subject: iwlwifi: mvm: Enabling Aux Queue Enabling the Aux queue and mapping it to FIFO 5. Defining the Aux queue for the Aux station. Signed-off-by: Ariej Marjieh Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/sta.c | 8 ++++++-- drivers/net/wireless/iwlwifi/mvm/tx.c | 10 ++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 54459345c967..763548880399 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -526,8 +526,12 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); - /* Add the aux station, but without any queues */ - ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0, + /* Map Aux queue to fifo - needs to happen before adding Aux station */ + iwl_trans_ac_txq_enable(mvm->trans, mvm->aux_queue, + IWL_MVM_TX_FIFO_MCAST); + + /* Allocate aux station and assign to it the aux queue */ + ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), NL80211_IFTYPE_UNSPECIFIED); if (ret) return ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index e9ff38635c21..dbc870713882 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -310,6 +310,16 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) info->hw_queue != info->control.vif->cab_queue))) return -1; + /* + * IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets that can be used + * in 2 different types of vifs, P2P & STATION. P2P uses the offchannel + * queue. STATION (HS2.0) uses the auxiliary context of the FW, + * and hence needs to be sent on the aux queue + */ + if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && + info->control.vif->type == NL80211_IFTYPE_STATION) + IEEE80211_SKB_CB(skb)->hw_queue = mvm->aux_queue; + /* * If the interface on which frame is sent is the P2P_DEVICE * or an AP/GO interface use the broadcast station associated -- cgit v1.2.3 From 720befbf2ecce8e5851a816fa567584320d721ec Mon Sep 17 00:00:00 2001 From: Ariej Marjieh Date: Mon, 7 Jul 2014 09:04:58 +0300 Subject: iwlwifi: mvm: Define AUX ROC Command Add new AUX ROC command that is intended for HS2.0 purposes. It is used to send ANQP requests on a specific channel. This command requests the firmware to trigger a time event and remain on a certain channel for a given duration. Triggering the time event is done by using the Aux Framework in the firmware, and makes use of the Aux station (similarly to scan). Signed-off-by: Ariej Marjieh Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 67 +++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index b8e4e78d601b..95f5b3274efb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -133,6 +133,7 @@ enum { /* Scan offload */ SCAN_OFFLOAD_REQUEST_CMD = 0x51, SCAN_OFFLOAD_ABORT_CMD = 0x52, + HOT_SPOT_CMD = 0x53, SCAN_OFFLOAD_COMPLETE = 0x6D, SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, SCAN_OFFLOAD_CONFIG_CMD = 0x6f, @@ -910,6 +911,72 @@ struct iwl_phy_context_cmd { __le32 dsp_cfg_flags; } __packed; /* PHY_CONTEXT_CMD_API_VER_1 */ +/* + * Aux ROC command + * + * Command requests the firmware to create a time event for a certain duration + * and remain on the given channel. This is done by using the Aux framework in + * the FW. + * The command was first used for Hot Spot issues - but can be used regardless + * to Hot Spot. + * + * ( HOT_SPOT_CMD 0x53 ) + * + * @id_and_color: ID and color of the MAC + * @action: action to perform, one of FW_CTXT_ACTION_* + * @event_unique_id: If the action FW_CTXT_ACTION_REMOVE then the + * event_unique_id should be the id of the time event assigned by ucode. + * Otherwise ignore the event_unique_id. + * @sta_id_and_color: station id and color, resumed during "Remain On Channel" + * activity. + * @channel_info: channel info + * @node_addr: Our MAC Address + * @reserved: reserved for alignment + * @apply_time: GP2 value to start (should always be the current GP2 value) + * @apply_time_max_delay: Maximum apply time delay value in TU. Defines max + * time by which start of the event is allowed to be postponed. + * @duration: event duration in TU To calculate event duration: + * timeEventDuration = min(duration, remainingQuota) + */ +struct iwl_hs20_roc_req { + /* COMMON_INDEX_HDR_API_S_VER_1 hdr */ + __le32 id_and_color; + __le32 action; + __le32 event_unique_id; + __le32 sta_id_and_color; + struct iwl_fw_channel_info channel_info; + u8 node_addr[ETH_ALEN]; + __le16 reserved; + __le32 apply_time; + __le32 apply_time_max_delay; + __le32 duration; +} __packed; /* HOT_SPOT_CMD_API_S_VER_1 */ + +/* + * values for AUX ROC result values + */ +enum iwl_mvm_hot_spot { + HOT_SPOT_RSP_STATUS_OK, + HOT_SPOT_RSP_STATUS_TOO_MANY_EVENTS, + HOT_SPOT_MAX_NUM_OF_SESSIONS, +}; + +/* + * Aux ROC command response + * + * In response to iwl_hs20_roc_req the FW sends this command to notify the + * driver the uid of the timevent. + * + * ( HOT_SPOT_CMD 0x53 ) + * + * @event_unique_id: Unique ID of time event assigned by ucode + * @status: Return status 0 is success, all the rest used for specific errors + */ +struct iwl_hs20_roc_res { + __le32 event_unique_id; + __le32 status; +} __packed; /* HOT_SPOT_RSP_API_S_VER_1 */ + #define IWL_RX_INFO_PHY_CNT 8 #define IWL_RX_INFO_ENERGY_ANT_ABC_IDX 1 #define IWL_RX_INFO_ENERGY_ANT_A_MSK 0x000000ff -- cgit v1.2.3 From 626911cc60d873b38f7ca4c5c537fcb918c658d7 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:17 +0300 Subject: mac80211: track TDLS initiator internally Infer the TDLS initiator and track it in mac80211 via a STA flag. This avoids breaking old userspace that doesn't pass it via nl80211 APIs. The only case where userspace will need to pass the initiator is when the STA is removed due to unreachability before a teardown packet is sent. Support for unreachability was only recently added to wpa_supplicant, so it won't be a problem in practice. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- net/mac80211/sta_info.h | 3 +++ net/mac80211/tdls.c | 35 ++++++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 2a04361b2162..e37f00969526 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -47,6 +47,8 @@ * @WLAN_STA_TDLS_PEER: Station is a TDLS peer. * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct * packets. This means the link is enabled. + * @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this + * station. * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was * keeping station in power-save mode, reply when the driver * unblocks the station. @@ -76,6 +78,7 @@ enum ieee80211_sta_info_flags { WLAN_STA_PSPOLL, WLAN_STA_TDLS_PEER, WLAN_STA_TDLS_PEER_AUTH, + WLAN_STA_TDLS_INITIATOR, WLAN_STA_UAPSD, WLAN_STA_SP, WLAN_STA_4ADDR_EVENT, diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index f7185338a0fa..b01b3104b445 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -203,6 +203,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, struct sk_buff *skb = NULL; bool send_direct; const u8 *init_addr, *rsp_addr; + struct sta_info *sta; int ret; skb = dev_alloc_skb(local->hw.extra_tx_headroom + @@ -245,32 +246,40 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, if (extra_ies_len) memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); - /* sanity check for initiator */ + rcu_read_lock(); + sta = sta_info_get(sdata, peer); + + /* infer the initiator if we can, to support old userspace */ switch (action_code) { case WLAN_TDLS_SETUP_REQUEST: + if (sta) + set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); + /* fall-through */ case WLAN_TDLS_SETUP_CONFIRM: case WLAN_TDLS_DISCOVERY_REQUEST: - if (!initiator) { - ret = -EINVAL; - goto fail; - } + initiator = true; break; case WLAN_TDLS_SETUP_RESPONSE: + /* + * In some testing scenarios, we send a request and response. + * Make the last packet sent take effect for the initiator + * value. + */ + if (sta) + clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); + /* fall-through */ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: - if (initiator) { - ret = -EINVAL; - goto fail; - } + initiator = false; break; case WLAN_TDLS_TEARDOWN: /* any value is ok */ break; default: ret = -ENOTSUPP; - goto fail; + break; } - if (initiator) { + if (initiator || (sta && test_sta_flag(sta, WLAN_STA_TDLS_INITIATOR))) { init_addr = sdata->vif.addr; rsp_addr = peer; } else { @@ -278,6 +287,10 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, rsp_addr = sdata->vif.addr; } + rcu_read_unlock(); + if (ret < 0) + goto fail; + ieee80211_tdls_add_link_ie(skb, init_addr, rsp_addr, sdata->u.mgd.bssid); -- cgit v1.2.3 From 6ae32e5d284a5db589bfa63561932ad3306f538a Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:18 +0300 Subject: mac80211: fix error path for TDLS setup The patch "8f02e6b mac80211: make sure TDLS peer STA exists during setup" broke TDLS error paths where the STA doesn't exist when sending the error. Fix it by only testing for STA existence during a non-error flow. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index b01b3104b445..53c235de5d1c 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -349,15 +349,19 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, /* * make sure we have a STA representing the peer so we drop or buffer * non-TDLS-setup frames to the peer. We can't send other packets - * during setup through the AP path + * during setup through the AP path. + * Allow error packets to be sent - sometimes we don't even add a STA + * before failing the setup. */ - rcu_read_lock(); - if (!sta_info_get(sdata, peer)) { + if (status_code == 0) { + rcu_read_lock(); + if (!sta_info_get(sdata, peer)) { + rcu_read_unlock(); + ret = -ENOLINK; + goto exit; + } rcu_read_unlock(); - ret = -ENOLINK; - goto exit; } - rcu_read_unlock(); ieee80211_flush_queues(local, sdata); -- cgit v1.2.3 From 46792a2dfcc7e000e6927088fbf06a135aaaa3eb Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:19 +0300 Subject: mac80211: consolidate TDLS IE treatment Add all information elements for TDLS discovery and setup in the same function. Signed-off-by: Arik Nemtsov Reviewed-by: Liad Kaufman Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 69 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 53c235de5d1c..b61448acc438 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -78,13 +78,49 @@ static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr, memcpy(lnkid->resp_sta, peer, ETH_ALEN); } +static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, const u8 *peer, + u8 action_code, bool initiator, + const u8 *extra_ies, size_t extra_ies_len) +{ + const u8 *init_addr, *rsp_addr; + enum ieee80211_band band = ieee80211_get_sdata_band(sdata); + + switch (action_code) { + case WLAN_TDLS_SETUP_REQUEST: + case WLAN_TDLS_SETUP_RESPONSE: + case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: + ieee80211_add_srates_ie(sdata, skb, false, band); + ieee80211_add_ext_srates_ie(sdata, skb, false, band); + ieee80211_tdls_add_ext_capab(skb); + break; + case WLAN_TDLS_SETUP_CONFIRM: + case WLAN_TDLS_TEARDOWN: + case WLAN_TDLS_DISCOVERY_REQUEST: + break; + } + + if (initiator) { + init_addr = sdata->vif.addr; + rsp_addr = peer; + } else { + init_addr = peer; + rsp_addr = sdata->vif.addr; + } + + if (extra_ies_len) + memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); + + ieee80211_tdls_add_link_ie(skb, init_addr, rsp_addr, + sdata->u.mgd.bssid); +} + static int ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, struct sk_buff *skb) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - enum ieee80211_band band = ieee80211_get_sdata_band(sdata); struct ieee80211_tdls_data *tf; tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); @@ -103,10 +139,6 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->u.setup_req.dialog_token = dialog_token; tf->u.setup_req.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - - ieee80211_add_srates_ie(sdata, skb, false, band); - ieee80211_add_ext_srates_ie(sdata, skb, false, band); - ieee80211_tdls_add_ext_capab(skb); break; case WLAN_TDLS_SETUP_RESPONSE: tf->category = WLAN_CATEGORY_TDLS; @@ -117,10 +149,6 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->u.setup_resp.dialog_token = dialog_token; tf->u.setup_resp.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - - ieee80211_add_srates_ie(sdata, skb, false, band); - ieee80211_add_ext_srates_ie(sdata, skb, false, band); - ieee80211_tdls_add_ext_capab(skb); break; case WLAN_TDLS_SETUP_CONFIRM: tf->category = WLAN_CATEGORY_TDLS; @@ -157,7 +185,6 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, u16 status_code, struct sk_buff *skb) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - enum ieee80211_band band = ieee80211_get_sdata_band(sdata); struct ieee80211_mgmt *mgmt; mgmt = (void *)skb_put(skb, 24); @@ -179,10 +206,6 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, dialog_token; mgmt->u.action.u.tdls_discover_resp.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - - ieee80211_add_srates_ie(sdata, skb, false, band); - ieee80211_add_ext_srates_ie(sdata, skb, false, band); - ieee80211_tdls_add_ext_capab(skb); break; default: return -EINVAL; @@ -202,7 +225,6 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_local *local = sdata->local; struct sk_buff *skb = NULL; bool send_direct; - const u8 *init_addr, *rsp_addr; struct sta_info *sta; int ret; @@ -243,9 +265,6 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, if (ret < 0) goto fail; - if (extra_ies_len) - memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); - rcu_read_lock(); sta = sta_info_get(sdata, peer); @@ -279,21 +298,15 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, break; } - if (initiator || (sta && test_sta_flag(sta, WLAN_STA_TDLS_INITIATOR))) { - init_addr = sdata->vif.addr; - rsp_addr = peer; - } else { - init_addr = peer; - rsp_addr = sdata->vif.addr; - } + if (sta && test_sta_flag(sta, WLAN_STA_TDLS_INITIATOR)) + initiator = true; rcu_read_unlock(); if (ret < 0) goto fail; - ieee80211_tdls_add_link_ie(skb, init_addr, rsp_addr, - sdata->u.mgd.bssid); - + ieee80211_tdls_add_ies(sdata, skb, peer, action_code, initiator, + extra_ies, extra_ies_len); if (send_direct) { ieee80211_tx_skb(sdata, skb); return 0; -- cgit v1.2.3 From f09a87d274942bf619f5081ac6e9e9441f3eabc4 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:20 +0300 Subject: mac80211: split extra TDLS IEs in setup frames When building TDLS setup frames, use the IE order mandates in the specification, splitting extra IEs coming from usermode. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index b61448acc438..8d6c9285752f 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -78,25 +78,91 @@ static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr, memcpy(lnkid->resp_sta, peer, ETH_ALEN); } +static void +ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, const u8 *peer, + u8 action_code, const u8 *extra_ies, + size_t extra_ies_len) +{ + enum ieee80211_band band = ieee80211_get_sdata_band(sdata); + size_t offset = 0, noffset; + u8 *pos; + + ieee80211_add_srates_ie(sdata, skb, false, band); + ieee80211_add_ext_srates_ie(sdata, skb, false, band); + + /* add any custom IEs that go before Extended Capabilities */ + if (extra_ies_len) { + static const u8 before_ext_cap[] = { + WLAN_EID_SUPP_RATES, + WLAN_EID_COUNTRY, + WLAN_EID_EXT_SUPP_RATES, + WLAN_EID_SUPPORTED_CHANNELS, + WLAN_EID_RSN, + }; + noffset = ieee80211_ie_split(extra_ies, extra_ies_len, + before_ext_cap, + ARRAY_SIZE(before_ext_cap), + offset); + pos = skb_put(skb, noffset - offset); + memcpy(pos, extra_ies + offset, noffset - offset); + offset = noffset; + } + + ieee80211_tdls_add_ext_capab(skb); + + /* add any custom IEs that go before HT capabilities */ + if (extra_ies_len) { + static const u8 before_ht_cap[] = { + WLAN_EID_SUPP_RATES, + WLAN_EID_COUNTRY, + WLAN_EID_EXT_SUPP_RATES, + WLAN_EID_SUPPORTED_CHANNELS, + WLAN_EID_RSN, + WLAN_EID_EXT_CAPABILITY, + WLAN_EID_QOS_CAPA, + WLAN_EID_FAST_BSS_TRANSITION, + WLAN_EID_TIMEOUT_INTERVAL, + WLAN_EID_SUPPORTED_REGULATORY_CLASSES, + }; + noffset = ieee80211_ie_split(extra_ies, extra_ies_len, + before_ht_cap, + ARRAY_SIZE(before_ht_cap), + offset); + pos = skb_put(skb, noffset - offset); + memcpy(pos, extra_ies + offset, noffset - offset); + offset = noffset; + } + + /* add any remaining IEs */ + if (extra_ies_len) { + noffset = extra_ies_len; + pos = skb_put(skb, noffset - offset); + memcpy(pos, extra_ies + offset, noffset - offset); + } +} + static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, const u8 *peer, u8 action_code, bool initiator, const u8 *extra_ies, size_t extra_ies_len) { const u8 *init_addr, *rsp_addr; - enum ieee80211_band band = ieee80211_get_sdata_band(sdata); switch (action_code) { case WLAN_TDLS_SETUP_REQUEST: case WLAN_TDLS_SETUP_RESPONSE: case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: - ieee80211_add_srates_ie(sdata, skb, false, band); - ieee80211_add_ext_srates_ie(sdata, skb, false, band); - ieee80211_tdls_add_ext_capab(skb); + ieee80211_tdls_add_setup_start_ies(sdata, skb, peer, + action_code, extra_ies, + extra_ies_len); break; case WLAN_TDLS_SETUP_CONFIRM: case WLAN_TDLS_TEARDOWN: case WLAN_TDLS_DISCOVERY_REQUEST: + if (extra_ies_len) + memcpy(skb_put(skb, extra_ies_len), extra_ies, + extra_ies_len); break; } @@ -108,9 +174,6 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, rsp_addr = sdata->vif.addr; } - if (extra_ies_len) - memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); - ieee80211_tdls_add_link_ie(skb, init_addr, rsp_addr, sdata->u.mgd.bssid); } -- cgit v1.2.3 From 1606ef4a9d294dde98a2185e3645468b08925a6f Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:21 +0300 Subject: mac80211: avoid adding some IEs on TDLS setup failure packets Most setup-specific information elements are not to be added when a setup frame is sent with an error status code. Signed-off-by: Arik Nemtsov Reviewed-by: Liad Kaufman Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 58 +++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 8d6c9285752f..99d5ed3aa474 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -63,26 +63,36 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata) return capab; } -static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr, - const u8 *peer, const u8 *bssid) +static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, const u8 *peer, + bool initiator) { struct ieee80211_tdls_lnkie *lnkid; + const u8 *init_addr, *rsp_addr; + + if (initiator) { + init_addr = sdata->vif.addr; + rsp_addr = peer; + } else { + init_addr = peer; + rsp_addr = sdata->vif.addr; + } lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); lnkid->ie_type = WLAN_EID_LINK_ID; lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2; - memcpy(lnkid->bssid, bssid, ETH_ALEN); - memcpy(lnkid->init_sta, src_addr, ETH_ALEN); - memcpy(lnkid->resp_sta, peer, ETH_ALEN); + memcpy(lnkid->bssid, sdata->u.mgd.bssid, ETH_ALEN); + memcpy(lnkid->init_sta, init_addr, ETH_ALEN); + memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN); } static void ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, const u8 *peer, - u8 action_code, const u8 *extra_ies, - size_t extra_ies_len) + u8 action_code, bool initiator, + const u8 *extra_ies, size_t extra_ies_len) { enum ieee80211_band band = ieee80211_get_sdata_band(sdata); size_t offset = 0, noffset; @@ -140,22 +150,26 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, pos = skb_put(skb, noffset - offset); memcpy(pos, extra_ies + offset, noffset - offset); } + + ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); } static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, const u8 *peer, - u8 action_code, bool initiator, - const u8 *extra_ies, size_t extra_ies_len) + u8 action_code, u16 status_code, + bool initiator, const u8 *extra_ies, + size_t extra_ies_len) { - const u8 *init_addr, *rsp_addr; - switch (action_code) { case WLAN_TDLS_SETUP_REQUEST: case WLAN_TDLS_SETUP_RESPONSE: case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: - ieee80211_tdls_add_setup_start_ies(sdata, skb, peer, - action_code, extra_ies, - extra_ies_len); + if (status_code == 0) + ieee80211_tdls_add_setup_start_ies(sdata, skb, peer, + action_code, + initiator, + extra_ies, + extra_ies_len); break; case WLAN_TDLS_SETUP_CONFIRM: case WLAN_TDLS_TEARDOWN: @@ -163,19 +177,11 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, if (extra_ies_len) memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); + if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) + ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); break; } - if (initiator) { - init_addr = sdata->vif.addr; - rsp_addr = peer; - } else { - init_addr = peer; - rsp_addr = sdata->vif.addr; - } - - ieee80211_tdls_add_link_ie(skb, init_addr, rsp_addr, - sdata->u.mgd.bssid); } static int @@ -368,8 +374,8 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, if (ret < 0) goto fail; - ieee80211_tdls_add_ies(sdata, skb, peer, action_code, initiator, - extra_ies, extra_ies_len); + ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code, + initiator, extra_ies, extra_ies_len); if (send_direct) { ieee80211_tx_skb(sdata, skb); return 0; -- cgit v1.2.3 From dd8c0b03d35be7effe20c9e5fda7e231e2c88e19 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:22 +0300 Subject: mac80211: set TDLS capab to zero on failure frames When sending setup-failure frames, set the capability field to zero, as mandated by the specification (IEEE802.11-2012 8.5.13). Signed-off-by: Arik Nemtsov Reviewed-by: Liad Kaufman Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 99d5ed3aa474..398a41302972 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -46,11 +46,16 @@ static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; } -static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata) +static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, + u16 status_code) { struct ieee80211_local *local = sdata->local; u16 capab; + /* The capability will be 0 when sending a failure code */ + if (status_code != 0) + return 0; + capab = 0; if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ) return capab; @@ -207,7 +212,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, skb_put(skb, sizeof(tf->u.setup_req)); tf->u.setup_req.dialog_token = dialog_token; tf->u.setup_req.capability = - cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); + cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, + status_code)); break; case WLAN_TDLS_SETUP_RESPONSE: tf->category = WLAN_CATEGORY_TDLS; @@ -217,7 +223,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->u.setup_resp.status_code = cpu_to_le16(status_code); tf->u.setup_resp.dialog_token = dialog_token; tf->u.setup_resp.capability = - cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); + cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, + status_code)); break; case WLAN_TDLS_SETUP_CONFIRM: tf->category = WLAN_CATEGORY_TDLS; @@ -274,7 +281,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, mgmt->u.action.u.tdls_discover_resp.dialog_token = dialog_token; mgmt->u.action.u.tdls_discover_resp.capability = - cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); + cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, + status_code)); break; default: return -EINVAL; -- cgit v1.2.3 From 40b861a0eeb06bbfa472b456482ebf89b6886926 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:23 +0300 Subject: mac80211: add QoS IE during TDLS setup start If QoS is supported by the card, add an appropriate IE to TDLS setup- request and setup-response frames. Consolidate the setting of the WMM info IE across mac80211. Signed-off-by: Arik Nemtsov Reviewed-by: Liad Kaufman Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 13 ++----------- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 11 +---------- net/mac80211/tdls.c | 7 +++++++ net/mac80211/util.c | 15 +++++++++++++++ 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 713485f9effc..9713dc54ea4b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -189,17 +189,8 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, chandef, 0); } - if (local->hw.queues >= IEEE80211_NUM_ACS) { - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = 7; /* len */ - *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ - *pos++ = 0x50; - *pos++ = 0xf2; - *pos++ = 2; /* WME */ - *pos++ = 0; /* WME info */ - *pos++ = 1; /* WME ver */ - *pos++ = 0; /* U-APSD no in use */ - } + if (local->hw.queues >= IEEE80211_NUM_ACS) + pos = ieee80211_add_wmm_info_ie(pos, 0); /* U-APSD not in use */ presp->head_len = pos - presp->head; if (WARN_ON(presp->head_len > frame_len)) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9e025e1184cc..cb874760e99f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1824,6 +1824,7 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, bool need_basic, enum ieee80211_band band); +u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo); /* channel management */ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 931330bbe00c..d863ff8b6e41 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -830,16 +830,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) qos_info = 0; } - pos = skb_put(skb, 9); - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = 7; /* len */ - *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ - *pos++ = 0x50; - *pos++ = 0xf2; - *pos++ = 2; /* WME */ - *pos++ = 0; /* WME info */ - *pos++ = 1; /* WME ver */ - *pos++ = qos_info; + pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info); } /* add any remaining custom (i.e. vendor specific here) IEs */ diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 398a41302972..bfd8fc4a6b2f 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -100,6 +100,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, const u8 *extra_ies, size_t extra_ies_len) { enum ieee80211_band band = ieee80211_get_sdata_band(sdata); + struct ieee80211_local *local = sdata->local; size_t offset = 0, noffset; u8 *pos; @@ -126,6 +127,11 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, ieee80211_tdls_add_ext_capab(skb); + /* add the QoS element if we support it */ + if (local->hw.queues >= IEEE80211_NUM_ACS && + action_code != WLAN_PUB_ACTION_TDLS_DISCOVER_RES) + ieee80211_add_wmm_info_ie(skb_put(skb, 9), 0); /* no U-APSD */ + /* add any custom IEs that go before HT capabilities */ if (extra_ies_len) { static const u8 before_ht_cap[] = { @@ -310,6 +316,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, sizeof(struct ieee80211_tdls_data)) + 50 + /* supported rates */ 7 + /* ext capab */ + 26 + /* max(WMM-info, WMM-param) */ extra_ies_len + sizeof(struct ieee80211_tdls_lnkie)); if (!skb) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ea79668c2e5f..08ce77664082 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3082,3 +3082,18 @@ int ieee80211_max_num_channels(struct ieee80211_local *local) return max_num_different_channels; } + +u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo) +{ + *buf++ = WLAN_EID_VENDOR_SPECIFIC; + *buf++ = 7; /* len */ + *buf++ = 0x00; /* Microsoft OUI 00:50:F2 */ + *buf++ = 0x50; + *buf++ = 0xf2; + *buf++ = 2; /* WME */ + *buf++ = 0; /* WME info */ + *buf++ = 1; /* WME ver */ + *buf++ = qosinfo; /* U-APSD no in use */ + + return buf; +} -- cgit v1.2.3 From 6f7eaa47e1de30159277f91f1145a6687f13ffd9 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:24 +0300 Subject: mac80211: add TDLS QoS param IE on setup-confirm When TDLS QoS is supported by the the peer and the local card, add the WMM parameter IE to the setup-confirm frame. Take the QoS settings from the current AP, or if unsupported, use the default values from the specification. This behavior is mandated by IEEE802.11-2012 section 10.22.4. Signed-off-by: Arik Nemtsov Reviewed-by: Liad Kaufman Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 20 ++++++++ net/mac80211/tdls.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 75d17e15da33..63ab3873c5ed 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1001,6 +1001,26 @@ struct ieee80211_vendor_ie { u8 oui_type; } __packed; +struct ieee80211_wmm_ac_param { + u8 aci_aifsn; /* AIFSN, ACM, ACI */ + u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ + __le16 txop_limit; +} __packed; + +struct ieee80211_wmm_param_ie { + u8 element_id; /* Element ID: 221 (0xdd); */ + u8 len; /* Length: 24 */ + /* required fields for WMM version 1 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 1 */ + u8 version; /* 1 for WMM version 1.0 */ + u8 qos_info; /* AP/STA specific QoS info */ + u8 reserved; /* 0 */ + /* AC_BE, AC_BK, AC_VI, AC_VO */ + struct ieee80211_wmm_ac_param ac[4]; +} __packed; + /* Control frames */ struct ieee80211_rts { __le16 frame_control; diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index bfd8fc4a6b2f..72eebea7e60a 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -8,6 +8,7 @@ */ #include +#include #include #include "ieee80211_i.h" #include "driver-ops.h" @@ -93,6 +94,74 @@ static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata, memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN); } +/* translate numbering in the WMM parameter IE to the mac80211 notation */ +static enum ieee80211_ac_numbers ieee80211_ac_from_wmm(int ac) +{ + switch (ac) { + default: + WARN_ON_ONCE(1); + case 0: + return IEEE80211_AC_BE; + case 1: + return IEEE80211_AC_BK; + case 2: + return IEEE80211_AC_VI; + case 3: + return IEEE80211_AC_VO; + } +} + +static u8 ieee80211_wmm_aci_aifsn(int aifsn, bool acm, int aci) +{ + u8 ret; + + ret = aifsn & 0x0f; + if (acm) + ret |= 0x10; + ret |= (aci << 5) & 0x60; + return ret; +} + +static u8 ieee80211_wmm_ecw(u16 cw_min, u16 cw_max) +{ + return ((ilog2(cw_min + 1) << 0x0) & 0x0f) | + ((ilog2(cw_max + 1) << 0x4) & 0xf0); +} + +static void ieee80211_tdls_add_wmm_param_ie(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb) +{ + struct ieee80211_wmm_param_ie *wmm; + struct ieee80211_tx_queue_params *txq; + int i; + + wmm = (void *)skb_put(skb, sizeof(*wmm)); + memset(wmm, 0, sizeof(*wmm)); + + wmm->element_id = WLAN_EID_VENDOR_SPECIFIC; + wmm->len = sizeof(*wmm) - 2; + + wmm->oui[0] = 0x00; /* Microsoft OUI 00:50:F2 */ + wmm->oui[1] = 0x50; + wmm->oui[2] = 0xf2; + wmm->oui_type = 2; /* WME */ + wmm->oui_subtype = 1; /* WME param */ + wmm->version = 1; /* WME ver */ + wmm->qos_info = 0; /* U-APSD not in use */ + + /* + * Use the EDCA parameters defined for the BSS, or default if the AP + * doesn't support it, as mandated by 802.11-2012 section 10.22.4 + */ + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + txq = &sdata->tx_conf[ieee80211_ac_from_wmm(i)]; + wmm->ac[i].aci_aifsn = ieee80211_wmm_aci_aifsn(txq->aifs, + txq->acm, i); + wmm->ac[i].cw = ieee80211_wmm_ecw(txq->cw_min, txq->cw_max); + wmm->ac[i].txop_limit = cpu_to_le16(txq->txop); + } +} + static void ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, const u8 *peer, @@ -165,6 +234,56 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); } +static void +ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, const u8 *peer, + bool initiator, const u8 *extra_ies, + size_t extra_ies_len) +{ + struct ieee80211_local *local = sdata->local; + size_t offset = 0, noffset; + struct sta_info *sta; + u8 *pos; + + rcu_read_lock(); + + sta = sta_info_get(sdata, peer); + if (WARN_ON_ONCE(!sta)) { + rcu_read_unlock(); + return; + } + + /* add any custom IEs that go before the QoS IE */ + if (extra_ies_len) { + static const u8 before_qos[] = { + WLAN_EID_RSN, + }; + noffset = ieee80211_ie_split(extra_ies, extra_ies_len, + before_qos, + ARRAY_SIZE(before_qos), + offset); + pos = skb_put(skb, noffset - offset); + memcpy(pos, extra_ies + offset, noffset - offset); + offset = noffset; + } + + /* add the QoS param IE if both the peer and we support it */ + if (local->hw.queues >= IEEE80211_NUM_ACS && + test_sta_flag(sta, WLAN_STA_WME)) + ieee80211_tdls_add_wmm_param_ie(sdata, skb); + + /* add any remaining IEs */ + if (extra_ies_len) { + noffset = extra_ies_len; + pos = skb_put(skb, noffset - offset); + memcpy(pos, extra_ies + offset, noffset - offset); + } + + ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); + + rcu_read_unlock(); +} + static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, const u8 *peer, u8 action_code, u16 status_code, @@ -183,6 +302,11 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, extra_ies_len); break; case WLAN_TDLS_SETUP_CONFIRM: + if (status_code == 0) + ieee80211_tdls_add_setup_cfm_ies(sdata, skb, peer, + initiator, extra_ies, + extra_ies_len); + break; case WLAN_TDLS_TEARDOWN: case WLAN_TDLS_DISCOVERY_REQUEST: if (extra_ies_len) -- cgit v1.2.3 From 81dd2b8822410e56048b927be779d95a2b6dc186 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:25 +0300 Subject: mac80211: move TDLS data to mgd private part We can only be a station for TDLS connections. Also fix a bug where a delayed work could be left scheduled if the station interface was brought down during TDLS setup. Signed-off-by: Arik Nemtsov Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 6 +++--- net/mac80211/iface.c | 2 -- net/mac80211/mlme.c | 3 +++ net/mac80211/tdls.c | 28 ++++++++++++++-------------- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cb874760e99f..0d8539caebca 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -503,6 +503,9 @@ struct ieee80211_if_managed { struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ + + u8 tdls_peer[ETH_ALEN] __aligned(2); + struct delayed_work tdls_peer_del_work; }; struct ieee80211_if_ibss { @@ -815,9 +818,6 @@ struct ieee80211_sub_if_data { bool radar_required; struct delayed_work dfs_cac_timer_work; - u8 tdls_peer[ETH_ALEN] __aligned(2); - struct delayed_work tdls_peer_del_work; - /* * AP this belongs to: self in AP mode and * corresponding AP in VLAN mode, NULL for diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bbf51b2f0651..2a12b8aa6aad 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1672,8 +1672,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, ieee80211_dfs_cac_timer_work); INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, ieee80211_delayed_tailroom_dec); - INIT_DELAYED_WORK(&sdata->tdls_peer_del_work, - ieee80211_tdls_peer_del_work); for (i = 0; i < IEEE80211_NUM_BANDS; i++) { struct ieee80211_supported_band *sband; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d863ff8b6e41..fcc074871d51 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3713,6 +3713,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) INIT_WORK(&ifmgd->csa_connection_drop_work, ieee80211_csa_connection_drop_work); INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work); + INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work, + ieee80211_tdls_peer_del_work); setup_timer(&ifmgd->timer, ieee80211_sta_timer, (unsigned long) sdata); setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, @@ -4576,6 +4578,7 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) cancel_work_sync(&ifmgd->request_smps_work); cancel_work_sync(&ifmgd->csa_connection_drop_work); cancel_work_sync(&ifmgd->chswitch_work); + cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work); sdata_lock(sdata); if (ifmgd->assoc_data) { diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 72eebea7e60a..c59b8f460eb9 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -22,14 +22,14 @@ void ieee80211_tdls_peer_del_work(struct work_struct *wk) struct ieee80211_local *local; sdata = container_of(wk, struct ieee80211_sub_if_data, - tdls_peer_del_work.work); + u.mgd.tdls_peer_del_work.work); local = sdata->local; mutex_lock(&local->mtx); - if (!is_zero_ether_addr(sdata->tdls_peer)) { - tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->tdls_peer); - sta_info_destroy_addr(sdata, sdata->tdls_peer); - eth_zero_addr(sdata->tdls_peer); + if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer)) { + tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->u.mgd.tdls_peer); + sta_info_destroy_addr(sdata, sdata->u.mgd.tdls_peer); + eth_zero_addr(sdata->u.mgd.tdls_peer); } mutex_unlock(&local->mtx); } @@ -561,8 +561,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, mutex_lock(&local->mtx); /* we don't support concurrent TDLS peer setups */ - if (!is_zero_ether_addr(sdata->tdls_peer) && - !ether_addr_equal(sdata->tdls_peer, peer)) { + if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer) && + !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { ret = -EBUSY; goto exit; } @@ -593,9 +593,9 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, if (ret < 0) goto exit; - memcpy(sdata->tdls_peer, peer, ETH_ALEN); + memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN); ieee80211_queue_delayed_work(&sdata->local->hw, - &sdata->tdls_peer_del_work, + &sdata->u.mgd.tdls_peer_del_work, TDLS_PEER_SETUP_TIMEOUT); exit: @@ -751,8 +751,8 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); rcu_read_unlock(); - WARN_ON_ONCE(is_zero_ether_addr(sdata->tdls_peer) || - !ether_addr_equal(sdata->tdls_peer, peer)); + WARN_ON_ONCE(is_zero_ether_addr(sdata->u.mgd.tdls_peer) || + !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)); ret = 0; break; case NL80211_TDLS_DISABLE_LINK: @@ -766,9 +766,9 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, break; } - if (ret == 0 && ether_addr_equal(sdata->tdls_peer, peer)) { - cancel_delayed_work(&sdata->tdls_peer_del_work); - eth_zero_addr(sdata->tdls_peer); + if (ret == 0 && ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { + cancel_delayed_work(&sdata->u.mgd.tdls_peer_del_work); + eth_zero_addr(sdata->u.mgd.tdls_peer); } mutex_unlock(&local->mtx); -- cgit v1.2.3 From 13cc8a4a1d24ff1f3b8b6de16779ef925371b18b Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:26 +0300 Subject: mac80211: support HT for TDLS stations Add the HT capabilities and HT operation information elements to TDLS setup packets where appropriate. Signed-off-by: Arik Nemtsov Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/ht.c | 7 ++--- net/mac80211/tdls.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 15702ff64a4c..568055c02a98 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -150,13 +150,12 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, /* * If user has specified capability over-rides, take care - * of that if the station we're setting up is the AP that + * of that if the station we're setting up is the AP or TDLS peer that * we advertised a restricted capability set to. Override * our own capabilities and then use those below. */ - if ((sdata->vif.type == NL80211_IFTYPE_STATION || - sdata->vif.type == NL80211_IFTYPE_ADHOC) && - !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) + if (sdata->vif.type == NL80211_IFTYPE_STATION || + sdata->vif.type == NL80211_IFTYPE_ADHOC) ieee80211_apply_htcap_overrides(sdata, &own_cap); /* diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index c59b8f460eb9..50d0e0660cc4 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -170,9 +170,23 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, { enum ieee80211_band band = ieee80211_get_sdata_band(sdata); struct ieee80211_local *local = sdata->local; + struct ieee80211_supported_band *sband; + struct ieee80211_sta_ht_cap ht_cap; + struct sta_info *sta = NULL; size_t offset = 0, noffset; u8 *pos; + rcu_read_lock(); + + /* we should have the peer STA if we're already responding */ + if (action_code == WLAN_TDLS_SETUP_RESPONSE) { + sta = sta_info_get(sdata, peer); + if (WARN_ON_ONCE(!sta)) { + rcu_read_unlock(); + return; + } + } + ieee80211_add_srates_ie(sdata, skb, false, band); ieee80211_add_ext_srates_ie(sdata, skb, false, band); @@ -224,6 +238,38 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, offset = noffset; } + /* + * with TDLS we can switch channels, and HT-caps are not necessarily + * the same on all bands. The specification limits the setup to a + * single HT-cap, so use the current band for now. + */ + sband = local->hw.wiphy->bands[band]; + memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); + if ((action_code == WLAN_TDLS_SETUP_REQUEST || + action_code == WLAN_TDLS_SETUP_RESPONSE) && + ht_cap.ht_supported && (!sta || sta->sta.ht_cap.ht_supported)) { + if (action_code == WLAN_TDLS_SETUP_REQUEST) { + ieee80211_apply_htcap_overrides(sdata, &ht_cap); + + /* disable SMPS in TDLS initiator */ + ht_cap.cap |= (WLAN_HT_CAP_SM_PS_DISABLED + << IEEE80211_HT_CAP_SM_PS_SHIFT); + } else { + /* disable SMPS in TDLS responder */ + sta->sta.ht_cap.cap |= + (WLAN_HT_CAP_SM_PS_DISABLED + << IEEE80211_HT_CAP_SM_PS_SHIFT); + + /* the peer caps are already intersected with our own */ + memcpy(&ht_cap, &sta->sta.ht_cap, sizeof(ht_cap)); + } + + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); + ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); + } + + rcu_read_unlock(); + /* add any remaining IEs */ if (extra_ies_len) { noffset = extra_ies_len; @@ -241,14 +287,16 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, size_t extra_ies_len) { struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; size_t offset = 0, noffset; - struct sta_info *sta; + struct sta_info *sta, *ap_sta; u8 *pos; rcu_read_lock(); sta = sta_info_get(sdata, peer); - if (WARN_ON_ONCE(!sta)) { + ap_sta = sta_info_get(sdata, ifmgd->bssid); + if (WARN_ON_ONCE(!sta || !ap_sta)) { rcu_read_unlock(); return; } @@ -272,6 +320,38 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, test_sta_flag(sta, WLAN_STA_WME)) ieee80211_tdls_add_wmm_param_ie(sdata, skb); + /* add any custom IEs that go before HT operation */ + if (extra_ies_len) { + static const u8 before_ht_op[] = { + WLAN_EID_RSN, + WLAN_EID_QOS_CAPA, + WLAN_EID_FAST_BSS_TRANSITION, + WLAN_EID_TIMEOUT_INTERVAL, + }; + noffset = ieee80211_ie_split(extra_ies, extra_ies_len, + before_ht_op, + ARRAY_SIZE(before_ht_op), + offset); + pos = skb_put(skb, noffset - offset); + memcpy(pos, extra_ies + offset, noffset - offset); + offset = noffset; + } + + /* if HT support is only added in TDLS, we need an HT-operation IE */ + if (!ap_sta->sta.ht_cap.ht_supported && sta->sta.ht_cap.ht_supported) { + struct ieee80211_chanctx_conf *chanctx_conf = + rcu_dereference(sdata->vif.chanctx_conf); + if (!WARN_ON(!chanctx_conf)) { + pos = skb_put(skb, 2 + + sizeof(struct ieee80211_ht_operation)); + /* send an empty HT operation IE */ + ieee80211_ie_build_ht_oper(pos, &sta->sta.ht_cap, + &chanctx_conf->def, 0); + } + } + + rcu_read_unlock(); + /* add any remaining IEs */ if (extra_ies_len) { noffset = extra_ies_len; @@ -280,8 +360,6 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, } ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); - - rcu_read_unlock(); } static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, @@ -441,6 +519,8 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, 50 + /* supported rates */ 7 + /* ext capab */ 26 + /* max(WMM-info, WMM-param) */ + 2 + max(sizeof(struct ieee80211_ht_cap), + sizeof(struct ieee80211_ht_operation)) + extra_ies_len + sizeof(struct ieee80211_tdls_lnkie)); if (!skb) -- cgit v1.2.3 From dc5943d54092467b7b56ff6adaeb63165f692fa2 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:27 +0300 Subject: mac80211: set Rx highest rate in ht_cap Set for completeness mostly, currently unused in the code. Signed-off-by: Arik Nemtsov Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/ht.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 568055c02a98..ff630be2ca75 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -227,6 +227,9 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) ht_cap.mcs.rx_mask[32/8] |= 1; + /* set Rx highest rate */ + ht_cap.mcs.rx_highest = ht_cap_ie->mcs.rx_highest; + apply: changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); -- cgit v1.2.3 From bed766bd4cea6413df73e8a314ebf40dd6a920f8 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:28 +0300 Subject: mac80211: disable VHT for TDLS TDLS VHT support requires some more information elements during setup. While these are not there, mask out the peer's VHT capabilities so that VHT rates are not mistakenly used. Signed-off-by: Arik Nemtsov Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/vht.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 9265adfdabfc..671ce0d27a80 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -129,6 +129,10 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, if (!vht_cap_ie || !sband->vht_cap.vht_supported) return; + /* don't support VHT for TDLS peers for now */ + if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) + return; + /* * A VHT STA must support 40 MHz, but if we verify that here * then we break a few things - some APs (e.g. Netgear R6300v2 -- cgit v1.2.3 From c72e1140463a643579c3f9e09f990e71e95671ac Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:29 +0300 Subject: cfg80211: fix TDLS setup with VHT peers Some VHT TDLS peers (Google Nexus 5) include the VHT-AID IE in their TDLS setup request/response. Usermode passes this aid as the station aid, causing it to fail verifiction, since this happens in the "set_station" stage. Make an exception for the TDLS use-case. Signed-off-by: Arik Nemtsov Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c10295138eb5..13997c954249 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3815,7 +3815,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy, { if (params->listen_interval != -1) return -EINVAL; - if (params->aid) + if (params->aid && + !(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) return -EINVAL; /* When you run into this, adjust the code below for the new flag */ -- cgit v1.2.3 From db8e173245535e7e91603e3e69bc63722a82ed81 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 17 Jul 2014 17:14:30 +0300 Subject: mac80211: ignore frames between TDLS peers when operating as AP If the AP receives actions frames destined for other peers, it may mistakenly toggle BA-sessions from itself to a peer. Ignore TDLS data packets as well - the AP should not handle them. Signed-off-by: Arik Nemtsov Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5f572bed1761..5a786d489f7e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3129,6 +3129,14 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx, if (!ieee80211_is_beacon(hdr->frame_control)) return false; status->rx_flags &= ~IEEE80211_RX_RA_MATCH; + } else if (!ieee80211_has_tods(hdr->frame_control)) { + /* ignore data frames to TDLS-peers */ + if (ieee80211_is_data(hdr->frame_control)) + return false; + /* ignore action frames to TDLS-peers */ + if (ieee80211_is_action(hdr->frame_control) && + !ether_addr_equal(bssid, hdr->addr1)) + return false; } break; case NL80211_IFTYPE_WDS: -- cgit v1.2.3 From bb3f848608f070a6e3f6c477ba7ff46cf1fb0f02 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Thu, 17 Jul 2014 17:14:31 +0300 Subject: mac80211: make sure TDLS teardown packet is sent on time Since the teardown packet is created while the queues are stopped, it isn't sent immediately, but rather is pending. To be sure that when we flush the queues prior to destroying the station we also send this packet - the tasklet handling pending packets is invoked to flush the packets. Signed-off-by: Liad Kaufman Reviewed-by: ArikX Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 50d0e0660cc4..1b21050be174 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -836,6 +836,17 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, ret = 0; break; case NL80211_TDLS_DISABLE_LINK: + /* + * The teardown message in ieee80211_tdls_mgmt_teardown() was + * created while the queues were stopped, so it might still be + * pending. Before flushing the queues we need to be sure the + * message is handled by the tasklet handling pending messages, + * otherwise we might start destroying the station before + * sending the teardown packet. + * Note that this only forces the tasklet to flush pendings - + * not to stop the tasklet from rescheduling itself. + */ + tasklet_kill(&local->tx_pending_tasklet); /* flush a potentially queued teardown packet */ ieee80211_flush_queues(local, sdata); -- cgit v1.2.3 From 3e2a0226c624066943259eaa5e1261da9d8a25fc Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Sat, 5 Jul 2014 11:43:01 +0300 Subject: mac80211: remove redundant IEEE80211_STA_CSA_RECEIVED flag The csa_active flag was added in sdata a while ago and made IEEE80211_STA_CSA_RECEIVED redundant. The new flag is also used to mark when CSA is ongoing on other iftypes and took over the old one as the preferred method for checking whether we're in the middle of a channel switch. Remove the old, redundant flag. Signed-off-by: Luciano Coelho Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 - net/mac80211/mlme.c | 8 +------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0d8539caebca..49731dd044bb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -345,7 +345,6 @@ enum ieee80211_sta_flags { IEEE80211_STA_CONNECTION_POLL = BIT(1), IEEE80211_STA_CONTROL_PORT = BIT(2), IEEE80211_STA_DISABLE_HT = BIT(4), - IEEE80211_STA_CSA_RECEIVED = BIT(5), IEEE80211_STA_MFP_ENABLED = BIT(6), IEEE80211_STA_UAPSD_ENABLED = BIT(7), IEEE80211_STA_NULLFUNC_ACKED = BIT(8), diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fcc074871d51..31a8afaf7332 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -996,8 +996,6 @@ static void ieee80211_chswitch_work(struct work_struct *work) sdata->csa_block_tx = false; } - ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; - ieee80211_sta_reset_beacon_monitor(sdata); ieee80211_sta_reset_conn_monitor(sdata); @@ -1055,7 +1053,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, return; /* disregard subsequent announcements if we are already processing */ - if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) + if (sdata->vif.csa_active) return; current_band = cbss->channel->band; @@ -1082,8 +1080,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, return; } - ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; - mutex_lock(&local->mtx); mutex_lock(&local->chanctx_mtx); conf = rcu_dereference_protected(sdata->vif.chanctx_conf, @@ -2099,8 +2095,6 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, true, frame_buf); - ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; - mutex_lock(&local->mtx); sdata->vif.csa_active = false; if (sdata->csa_block_tx) { -- cgit v1.2.3 From fa96aabb6a34eeb86ce6a5e1a3914fe9f106cfcc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 14 Jul 2014 14:19:49 -0700 Subject: wireless: fixup genregdb.awk for remove of antenna gain from wireless-regd Since "wireless-regdb: remove antenna gain" was merged in the wireless-regdb tree, the awk script parser has been incompatible with the 'official' regulatory database. This fixes that up. Without this change the max EIRP is set to 0 making 802.11 devices useless. The fragile nature of the awk parser must be replaced, but ideas over how to do that in the most scalable way are being reviewed. In the meantime update the documentation for CFG80211_INTERNAL_REGDB so folks are aware of expectations for now. Reported-by: John Walker Reported-by: Krishna Chaitanya Signed-off-by: Luis R. Rodriguez Signed-off-by: Johannes Berg --- net/wireless/Kconfig | 6 ++++++ net/wireless/genregdb.awk | 35 ++++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 405f3c4cf70c..29c8675f9a11 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -162,6 +162,12 @@ config CFG80211_INTERNAL_REGDB and includes code to query that database. This is an alternative to using CRDA for defining regulatory rules for the kernel. + Using this option requires some parsing of the db.txt at build time, + the parser will be upkept with the latest wireless-regdb updates but + older wireless-regdb formats will be ignored. The parser may later + be replaced to avoid issues with conflicts on versions of + wireless-regdb. + For details see: http://wireless.kernel.org/en/developers/Regulatory diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 40c37fc5b67c..baf2426b555a 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk @@ -51,32 +51,41 @@ function parse_country_head() { function parse_reg_rule() { + flag_starts_at = 7 + start = $1 sub(/\(/, "", start) end = $3 bw = $5 sub(/\),/, "", bw) - gain = $6 - sub(/\(/, "", gain) - sub(/,/, "", gain) - power = $7 - sub(/\)/, "", power) - sub(/,/, "", power) + gain = 0 + power = $6 # power might be in mW... - units = $8 + units = $7 + dfs_cac = 0 + + sub(/\(/, "", power) + sub(/\),/, "", power) + sub(/\),/, "", units) sub(/\)/, "", units) - sub(/,/, "", units) - dfs_cac = $9 + if (units == "mW") { + flag_starts_at = 8 power = 10 * log(power)/log(10) + if ($8 ~ /[[:digit:]]/) { + flag_starts_at = 9 + dfs_cac = $8 + } } else { - dfs_cac = $8 + if ($7 ~ /[[:digit:]]/) { + flag_starts_at = 8 + dfs_cac = $7 + } } - sub(/,/, "", dfs_cac) sub(/\(/, "", dfs_cac) - sub(/\)/, "", dfs_cac) + sub(/\),/, "", dfs_cac) flagstr = "" - for (i=8; i<=NF; i++) + for (i=flag_starts_at; i<=NF; i++) flagstr = flagstr $i split(flagstr, flagarray, ",") flags = "" -- cgit v1.2.3 From aeb136c5b433377324f030b1a50b96eb7a99193b Mon Sep 17 00:00:00 2001 From: Max Stepanov Date: Wed, 9 Jul 2014 16:55:32 +0300 Subject: mac80211: fix a potential NULL access in ieee80211_crypto_hw_decrypt The NULL pointer access could happen when ieee80211_crypto_hw_decrypt is called from ieee80211_rx_h_decrypt with the following condition: 1. rx->key->conf.cipher is not WEP, CCMP, TKIP or AES_CMAC 2. rx->sta is NULL When ieee80211_crypto_hw_decrypt is called, it verifies rx->sta->cipher_scheme and it will cause Oops if rx->sta is NULL. This path adds an addirional rx->sta == NULL verification in ieee80211_crypto_hw_decrypt for this case. Signed-off-by: Max Stepanov Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/wpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 9b3dcc201145..f7d4ca4c46e0 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -811,7 +811,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) ieee80211_rx_result ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) { - if (rx->sta->cipher_scheme) + if (rx->sta && rx->sta->cipher_scheme) return ieee80211_crypto_cs_decrypt(rx); return RX_DROP_UNUSABLE; -- cgit v1.2.3 From 27f70f3e628c82362def60eb0af79d2129a51da2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 21 Jul 2014 10:50:06 +0300 Subject: Bluetooth: Prefer sizeof(*ptr) when allocating memory It's safer practice to use sizeof(*ptr) instead of sizeof(ptr_type) when allocating memory in case the type changes. This also fixes the following style of warnings from static analyzers: CHECK: Prefer kzalloc(sizeof(*ie)...) over kzalloc(sizeof(struct inquiry_entry)...) + ie = kzalloc(sizeof(struct inquiry_entry), GFP_KERNEL); Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 4 ++-- net/bluetooth/hci_core.c | 6 +++--- net/bluetooth/l2cap_core.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 1ac9f7f52acd..b50dabb3f86a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -428,7 +428,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, BT_DBG("%s dst %pMR", hdev->name, dst); - conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL); + conn = kzalloc(sizeof(*conn), GFP_KERNEL); if (!conn) return NULL; @@ -1282,7 +1282,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) BT_DBG("%s hcon %p", hdev->name, conn); - chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL); + chan = kzalloc(sizeof(*chan), GFP_KERNEL); if (!chan) return NULL; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f82a6cf1aaa8..cfcb6055ced8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2088,7 +2088,7 @@ u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, } /* Entry not in the cache. Add new one. */ - ie = kzalloc(sizeof(struct inquiry_entry), GFP_KERNEL); + ie = kzalloc(sizeof(*ie), GFP_KERNEL); if (!ie) { flags |= MGMT_DEV_FOUND_CONFIRM_NAME; goto done; @@ -3492,7 +3492,7 @@ int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type) if (hci_bdaddr_list_lookup(list, bdaddr, type)) return -EEXIST; - entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -3897,7 +3897,7 @@ struct hci_dev *hci_alloc_dev(void) { struct hci_dev *hdev; - hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL); + hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); if (!hdev) return NULL; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index f3fb61c9f96f..46547b920f88 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6985,7 +6985,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) if (!hchan) return NULL; - conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL); + conn = kzalloc(sizeof(*conn), GFP_KERNEL); if (!conn) { hci_chan_del(hchan); return NULL; -- cgit v1.2.3 From c2aef6e8cbebd60f79555baeb9266e220f135a44 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 21 Jul 2014 14:02:33 +0200 Subject: Bluetooth: Add support for Broadcom device of Asus Z97-DELUXE motherboard The Asus Z97-DELUXE motherboard contains a Broadcom based Bluetooth controller on the USB bus. However vendor and product ID are listed as ASUSTek Computer. T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0b05 ProdID=17cf Rev= 1.12 S: Manufacturer=Broadcom Corp S: Product=BCM20702A0 S: SerialNumber=54271E910064 C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) Reported-by: Jerome Leclanche Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b062bed67aaf..292c38e8aa17 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -114,6 +114,9 @@ static const struct usb_device_id btusb_table[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01), .driver_info = BTUSB_BCM_PATCHRAM }, + /* ASUSTek Computer - Broadcom based */ + { USB_VENDOR_AND_INTERFACE_INFO(0x0b05, 0xff, 0x01, 0x01) }, + /* Belkin F8065bf - Broadcom based */ { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) }, -- cgit v1.2.3 From 60e83deb4c1e7e8b6ab78e7331288bf4211bdeb6 Mon Sep 17 00:00:00 2001 From: Eytan Lifshitz Date: Mon, 21 Jul 2014 15:18:41 +0300 Subject: mac80211: remove useless NULL checks sdata can't be NULL, and key being NULL is really not possible unless the code is modified. The sdata check made a static analyze (klocwork) unhappy because we would get pointer to local (sdata->local) and only then check if sdata is non-NULL. Signed-off-by: Eytan Lifshitz Signed-off-by: Emmanuel Grumbach [remove !key check as well] Signed-off-by: Johannes Berg --- net/mac80211/key.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 16d97f044a20..d808cff80153 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -482,9 +482,6 @@ int ieee80211_key_link(struct ieee80211_key *key, int idx, ret; bool pairwise; - if (WARN_ON(!sdata || !key)) - return -EINVAL; - pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; idx = key->conf.keyidx; key->local = sdata->local; -- cgit v1.2.3 From 83eb935ec74a91468776cd86415abcb6ee23cca8 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 16 Jul 2014 12:09:31 +0200 Subject: mac80211: fix Rx reordering with RX_FLAG_AMSDU_MORE Some drivers (e.g. ath10k) report A-MSDU subframes individually with identical seqno. The A-MPDU Rx reorder code did not account for that which made it practically unusable with drivers using RX_FLAG_AMSDU_MORE because it would end up dropping a lot of frames resulting in confusion in upper network transport layers. Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg --- net/mac80211/agg-rx.c | 9 +++++--- net/mac80211/ieee80211_i.h | 15 ++++++++++++ net/mac80211/rx.c | 57 ++++++++++++++++++++++++++++++---------------- net/mac80211/sta_info.h | 5 ++-- 4 files changed, 62 insertions(+), 24 deletions(-) diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 31bf2586fb84..d38c49b644cd 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -52,7 +52,7 @@ static void ieee80211_free_tid_rx(struct rcu_head *h) del_timer_sync(&tid_rx->reorder_timer); for (i = 0; i < tid_rx->buf_size; i++) - dev_kfree_skb(tid_rx->reorder_buf[i]); + __skb_queue_purge(&tid_rx->reorder_buf[i]); kfree(tid_rx->reorder_buf); kfree(tid_rx->reorder_time); kfree(tid_rx); @@ -232,7 +232,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, struct tid_ampdu_rx *tid_agg_rx; u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; u8 dialog_token; - int ret = -EOPNOTSUPP; + int i, ret = -EOPNOTSUPP; /* extract session parameters from addba request frame */ dialog_token = mgmt->u.action.u.addba_req.dialog_token; @@ -308,7 +308,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, /* prepare reordering buffer */ tid_agg_rx->reorder_buf = - kcalloc(buf_size, sizeof(struct sk_buff *), GFP_KERNEL); + kcalloc(buf_size, sizeof(struct sk_buff_head), GFP_KERNEL); tid_agg_rx->reorder_time = kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL); if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { @@ -318,6 +318,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, goto end; } + for (i = 0; i < buf_size; i++) + __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]); + ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, &sta->sta, tid, &start_seq_num, 0); ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n", diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 49731dd044bb..c504e99a5404 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1729,6 +1729,21 @@ static inline void ieee802_11_parse_elems(const u8 *start, size_t len, ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); } +static inline bool ieee80211_rx_reorder_ready(struct sk_buff_head *frames) +{ + struct sk_buff *tail = skb_peek_tail(frames); + struct ieee80211_rx_status *status; + + if (!tail) + return false; + + status = IEEE80211_SKB_RXCB(tail); + if (status->flag & RX_FLAG_AMSDU_MORE) + return false; + + return true; +} + void ieee80211_dynamic_ps_enable_work(struct work_struct *work); void ieee80211_dynamic_ps_disable_work(struct work_struct *work); void ieee80211_dynamic_ps_timer(unsigned long data); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5a786d489f7e..bd2c9b22c945 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -688,20 +688,27 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, int index, struct sk_buff_head *frames) { - struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; + struct sk_buff_head *skb_list = &tid_agg_rx->reorder_buf[index]; + struct sk_buff *skb; struct ieee80211_rx_status *status; lockdep_assert_held(&tid_agg_rx->reorder_lock); - if (!skb) + if (skb_queue_empty(skb_list)) goto no_frame; - /* release the frame from the reorder ring buffer */ + if (!ieee80211_rx_reorder_ready(skb_list)) { + __skb_queue_purge(skb_list); + goto no_frame; + } + + /* release frames from the reorder ring buffer */ tid_agg_rx->stored_mpdu_num--; - tid_agg_rx->reorder_buf[index] = NULL; - status = IEEE80211_SKB_RXCB(skb); - status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE; - __skb_queue_tail(frames, skb); + while ((skb = __skb_dequeue(skb_list))) { + status = IEEE80211_SKB_RXCB(skb); + status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE; + __skb_queue_tail(frames, skb); + } no_frame: tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num); @@ -738,13 +745,13 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, struct tid_ampdu_rx *tid_agg_rx, struct sk_buff_head *frames) { - int index, j; + int index, i, j; lockdep_assert_held(&tid_agg_rx->reorder_lock); /* release the buffer until next missing frame */ index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; - if (!tid_agg_rx->reorder_buf[index] && + if (!ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index]) && tid_agg_rx->stored_mpdu_num) { /* * No buffers ready to be released, but check whether any @@ -753,7 +760,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, int skipped = 1; for (j = (index + 1) % tid_agg_rx->buf_size; j != index; j = (j + 1) % tid_agg_rx->buf_size) { - if (!tid_agg_rx->reorder_buf[j]) { + if (!ieee80211_rx_reorder_ready( + &tid_agg_rx->reorder_buf[j])) { skipped++; continue; } @@ -762,6 +770,11 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, HT_RX_REORDER_BUF_TIMEOUT)) goto set_release_timer; + /* don't leave incomplete A-MSDUs around */ + for (i = (index + 1) % tid_agg_rx->buf_size; i != j; + i = (i + 1) % tid_agg_rx->buf_size) + __skb_queue_purge(&tid_agg_rx->reorder_buf[i]); + ht_dbg_ratelimited(sdata, "release an RX reorder frame due to timeout on earlier frames\n"); ieee80211_release_reorder_frame(sdata, tid_agg_rx, j, @@ -775,7 +788,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, skipped) & IEEE80211_SN_MASK; skipped = 0; } - } else while (tid_agg_rx->reorder_buf[index]) { + } else while (ieee80211_rx_reorder_ready( + &tid_agg_rx->reorder_buf[index])) { ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, frames); index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; @@ -786,7 +800,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, for (; j != (index - 1) % tid_agg_rx->buf_size; j = (j + 1) % tid_agg_rx->buf_size) { - if (tid_agg_rx->reorder_buf[j]) + if (ieee80211_rx_reorder_ready( + &tid_agg_rx->reorder_buf[j])) break; } @@ -811,6 +826,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata struct sk_buff_head *frames) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); u16 sc = le16_to_cpu(hdr->seq_ctrl); u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; u16 head_seq_num, buf_size; @@ -845,7 +861,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata index = mpdu_seq_num % tid_agg_rx->buf_size; /* check if we already stored this frame */ - if (tid_agg_rx->reorder_buf[index]) { + if (ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index])) { dev_kfree_skb(skb); goto out; } @@ -858,17 +874,20 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata */ if (mpdu_seq_num == tid_agg_rx->head_seq_num && tid_agg_rx->stored_mpdu_num == 0) { - tid_agg_rx->head_seq_num = - ieee80211_sn_inc(tid_agg_rx->head_seq_num); + if (!(status->flag & RX_FLAG_AMSDU_MORE)) + tid_agg_rx->head_seq_num = + ieee80211_sn_inc(tid_agg_rx->head_seq_num); ret = false; goto out; } /* put the frame in the reordering buffer */ - tid_agg_rx->reorder_buf[index] = skb; - tid_agg_rx->reorder_time[index] = jiffies; - tid_agg_rx->stored_mpdu_num++; - ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames); + __skb_queue_tail(&tid_agg_rx->reorder_buf[index], skb); + if (!(status->flag & RX_FLAG_AMSDU_MORE)) { + tid_agg_rx->reorder_time[index] = jiffies; + tid_agg_rx->stored_mpdu_num++; + ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames); + } out: spin_unlock(&tid_agg_rx->reorder_lock); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index e37f00969526..d411bcc8ef08 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -155,7 +155,8 @@ struct tid_ampdu_tx { /** * struct tid_ampdu_rx - TID aggregation information (Rx). * - * @reorder_buf: buffer to reorder incoming aggregated MPDUs + * @reorder_buf: buffer to reorder incoming aggregated MPDUs. An MPDU may be an + * A-MSDU with individually reported subframes. * @reorder_time: jiffies when skb was added * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) * @reorder_timer: releases expired frames from the reorder buffer. @@ -180,7 +181,7 @@ struct tid_ampdu_tx { struct tid_ampdu_rx { struct rcu_head rcu_head; spinlock_t reorder_lock; - struct sk_buff **reorder_buf; + struct sk_buff_head *reorder_buf; unsigned long *reorder_time; struct timer_list session_timer; struct timer_list reorder_timer; -- cgit v1.2.3 From 08cf42e843f9a7e253502011c81677f61f7e5c42 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 16 Jul 2014 12:12:15 +0200 Subject: mac80211: add support for Rx reordering offloading Some drivers may be performing most of Tx/Rx aggregation on their own (e.g. in firmware) including AddBa/DelBa negotiations but may otherwise require Rx reordering assistance. The patch exports 2 new functions for establishing Rx aggregation sessions in assumption device driver has taken care of the necessary negotiations. Signed-off-by: Michal Kazior [fix endian bug] Signed-off-by: Johannes Berg --- include/net/mac80211.h | 34 +++++++++++++++ net/mac80211/agg-rx.c | 101 ++++++++++++++++++++++++++++++++++----------- net/mac80211/ieee80211_i.h | 11 +++++ net/mac80211/iface.c | 29 +++++++++++++ 4 files changed, 152 insertions(+), 23 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9ce5cb17ed82..dae2e24616e1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4552,6 +4552,40 @@ void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap, */ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn); +/** + * ieee80211_start_rx_ba_session_offl - start a Rx BA session + * + * Some device drivers may offload part of the Rx aggregation flow including + * AddBa/DelBa negotiation but may otherwise be incapable of full Rx + * reordering. + * + * Create structures responsible for reordering so device drivers may call here + * when they complete AddBa negotiation. + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback + * @addr: station mac address + * @tid: the rx tid + */ +void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif, + const u8 *addr, u16 tid); + +/** + * ieee80211_stop_rx_ba_session_offl - stop a Rx BA session + * + * Some device drivers may offload part of the Rx aggregation flow including + * AddBa/DelBa negotiation but may otherwise be incapable of full Rx + * reordering. + * + * Destroy structures responsible for reordering so device drivers may call here + * when they complete DelBa negotiation. + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback + * @addr: station mac address + * @tid: the rx tid + */ +void ieee80211_stop_rx_ba_session_offl(struct ieee80211_vif *vif, + const u8 *addr, u16 tid); + /* Rate control API */ /** diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index d38c49b644cd..f0e84bc48038 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -224,28 +224,15 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d ieee80211_tx_skb(sdata, skb); } -void ieee80211_process_addba_request(struct ieee80211_local *local, - struct sta_info *sta, - struct ieee80211_mgmt *mgmt, - size_t len) +void __ieee80211_start_rx_ba_session(struct sta_info *sta, + u8 dialog_token, u16 timeout, + u16 start_seq_num, u16 ba_policy, u16 tid, + u16 buf_size, bool tx) { + struct ieee80211_local *local = sta->sdata->local; struct tid_ampdu_rx *tid_agg_rx; - u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; - u8 dialog_token; int i, ret = -EOPNOTSUPP; - - /* extract session parameters from addba request frame */ - dialog_token = mgmt->u.action.u.addba_req.dialog_token; - timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); - start_seq_num = - le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; - - capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); - ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; - tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; - buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; - - status = WLAN_STATUS_REQUEST_DECLINED; + u16 status = WLAN_STATUS_REQUEST_DECLINED; if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { ht_dbg(sta->sdata, @@ -264,7 +251,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, status = WLAN_STATUS_INVALID_QOS_PARAM; ht_dbg_ratelimited(sta->sdata, "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", - mgmt->sa, tid, ba_policy, buf_size); + sta->sta.addr, tid, ba_policy, buf_size); goto end_no_lock; } /* determine default buffer size */ @@ -281,7 +268,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, if (sta->ampdu_mlme.tid_rx[tid]) { ht_dbg_ratelimited(sta->sdata, "unexpected AddBA Req from %pM on tid %u\n", - mgmt->sa, tid); + sta->sta.addr, tid); /* delete existing Rx BA session on the same tid */ ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, @@ -353,6 +340,74 @@ end: mutex_unlock(&sta->ampdu_mlme.mtx); end_no_lock: - ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, - dialog_token, status, 1, buf_size, timeout); + if (tx) + ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, + dialog_token, status, 1, buf_size, + timeout); +} + +void ieee80211_process_addba_request(struct ieee80211_local *local, + struct sta_info *sta, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num; + u8 dialog_token; + + /* extract session parameters from addba request frame */ + dialog_token = mgmt->u.action.u.addba_req.dialog_token; + timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); + start_seq_num = + le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; + + capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; + tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; + + __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, + start_seq_num, ba_policy, tid, + buf_size, true); +} + +void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif, + const u8 *addr, u16 tid) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; + struct ieee80211_rx_agg *rx_agg; + struct sk_buff *skb = dev_alloc_skb(0); + + if (unlikely(!skb)) + return; + + rx_agg = (struct ieee80211_rx_agg *) &skb->cb; + memcpy(&rx_agg->addr, addr, ETH_ALEN); + rx_agg->tid = tid; + + skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_START; + skb_queue_tail(&sdata->skb_queue, skb); + ieee80211_queue_work(&local->hw, &sdata->work); +} +EXPORT_SYMBOL(ieee80211_start_rx_ba_session_offl); + +void ieee80211_stop_rx_ba_session_offl(struct ieee80211_vif *vif, + const u8 *addr, u16 tid) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; + struct ieee80211_rx_agg *rx_agg; + struct sk_buff *skb = dev_alloc_skb(0); + + if (unlikely(!skb)) + return; + + rx_agg = (struct ieee80211_rx_agg *) &skb->cb; + memcpy(&rx_agg->addr, addr, ETH_ALEN); + rx_agg->tid = tid; + + skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_STOP; + skb_queue_tail(&sdata->skb_queue, skb); + ieee80211_queue_work(&local->hw, &sdata->work); } +EXPORT_SYMBOL(ieee80211_stop_rx_ba_session_offl); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c504e99a5404..ef7a089ac546 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -925,10 +925,17 @@ ieee80211_vif_get_shift(struct ieee80211_vif *vif) return shift; } +struct ieee80211_rx_agg { + u8 addr[ETH_ALEN]; + u16 tid; +}; + enum sdata_queue_type { IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, IEEE80211_SDATA_QUEUE_AGG_START = 1, IEEE80211_SDATA_QUEUE_AGG_STOP = 2, + IEEE80211_SDATA_QUEUE_RX_AGG_START = 3, + IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4, }; enum { @@ -1577,6 +1584,10 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, u16 initiator, u16 reason, bool stop); void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, u16 initiator, u16 reason, bool stop); +void __ieee80211_start_rx_ba_session(struct sta_info *sta, + u8 dialog_token, u16 timeout, + u16 start_seq_num, u16 ba_policy, u16 tid, + u16 buf_size, bool tx); void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, enum ieee80211_agg_stop_reason reason); void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2a12b8aa6aad..29be8854a027 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1140,6 +1140,7 @@ static void ieee80211_iface_work(struct work_struct *work) struct sk_buff *skb; struct sta_info *sta; struct ieee80211_ra_tid *ra_tid; + struct ieee80211_rx_agg *rx_agg; if (!ieee80211_sdata_running(sdata)) return; @@ -1167,6 +1168,34 @@ static void ieee80211_iface_work(struct work_struct *work) ra_tid = (void *)&skb->cb; ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra, ra_tid->tid); + } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_START) { + rx_agg = (void *)&skb->cb; + mutex_lock(&local->sta_mtx); + sta = sta_info_get_bss(sdata, rx_agg->addr); + if (sta) { + u16 last_seq; + + last_seq = le16_to_cpu( + sta->last_seq_ctrl[rx_agg->tid]); + + __ieee80211_start_rx_ba_session(sta, + 0, 0, + ieee80211_sn_inc(last_seq), + 1, rx_agg->tid, + IEEE80211_MAX_AMPDU_BUF, + false); + } + mutex_unlock(&local->sta_mtx); + } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_STOP) { + rx_agg = (void *)&skb->cb; + mutex_lock(&local->sta_mtx); + sta = sta_info_get_bss(sdata, rx_agg->addr); + if (sta) + __ieee80211_stop_rx_ba_session(sta, + rx_agg->tid, + WLAN_BACK_RECIPIENT, 0, + false); + mutex_unlock(&local->sta_mtx); } else if (ieee80211_is_action(mgmt->frame_control) && mgmt->u.action.category == WLAN_CATEGORY_BACK) { int len = skb->len; -- cgit v1.2.3 From da34fad65d84c3bb19eb1e6e5d143d4bf1454fba Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 16 Jul 2014 15:01:39 +0200 Subject: ath10k: workaround boot issues with KVM/PCI-passthrough Apparently iomap writes that unmask CE irqs aren't propagated properly sometimes. Before failing try to poll for the control response message as it may have been delivered without an interrupt. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index e493db4b4a41..5fdc40d3b378 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -546,7 +546,7 @@ static u8 ath10k_htc_get_credit_allocation(struct ath10k_htc *htc, int ath10k_htc_wait_target(struct ath10k_htc *htc) { - int status = 0; + int i, status = 0; struct ath10k_htc_svc_conn_req conn_req; struct ath10k_htc_svc_conn_resp conn_resp; struct ath10k_htc_msg *msg; @@ -556,10 +556,26 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) status = wait_for_completion_timeout(&htc->ctl_resp, ATH10K_HTC_WAIT_TIMEOUT_HZ); - if (status <= 0) { + if (status == 0) { + /* Workaround: In some cases the PCI HIF doesn't + * receive interrupt for the control response message + * even if the buffer was completed. It is suspected + * iomap writes unmasking PCI CE irqs aren't propagated + * properly in KVM PCI-passthrough sometimes. + */ + ath10k_warn("failed to receive control response completion, polling..\n"); + + for (i = 0; i < CE_COUNT; i++) + ath10k_hif_send_complete_check(htc->ar, i, 1); + + status = wait_for_completion_timeout(&htc->ctl_resp, + ATH10K_HTC_WAIT_TIMEOUT_HZ); + if (status == 0) status = -ETIMEDOUT; + } + if (status < 0) { ath10k_err("ctl_resp never came in (%d)\n", status); return status; } -- cgit v1.2.3 From 708b9bde5d8462d7ce47c1c8ddfc84dd2539e39a Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 21 Jul 2014 20:52:59 +0300 Subject: ath10k: prevent some tx flushing failures Firmware could request inspection of some submitted tx requests. Since the callback wasn't implemented it was possible to bleed tx msdu_ids which could translate to tx flushing timeouts. There's nothing ath10k can do to help firmware with tx processing now so just report all tx frames as already inspected to prevent firmware from sending up inspection events and force it to report regular tx completion indications with discard status. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 7 +++++++ drivers/net/wireless/ath/ath10k/htt_tx.c | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index eebc860c3655..318efc35d116 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1516,6 +1516,13 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) trace_ath10k_htt_stats(skb->data, skb->len); break; case HTT_T2H_MSG_TYPE_TX_INSPECT_IND: + /* Firmware can return tx frames if it's unable to fully + * process them and suspects host may be able to fix it. ath10k + * sends all tx frames as already inspected so this shouldn't + * happen unless fw has a bug. + */ + ath10k_warn("received an unexpected htt tx inspect event\n"); + break; case HTT_T2H_MSG_TYPE_RX_ADDBA: case HTT_T2H_MSG_TYPE_RX_DELBA: case HTT_T2H_MSG_TYPE_RX_FLUSH: diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index accb6b4f6faf..8b27bfcc1de3 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -531,6 +531,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; + /* Prevent firmware from sending up tx inspection requests. There's + * nothing ath10k can do with frames requested for inspection so force + * it to simply rely a regular tx completion with discard status. + */ + flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED; + skb_cb->htt.txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; skb_cb->htt.txbuf->cmd_tx.flags0 = flags0; skb_cb->htt.txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1); -- cgit v1.2.3 From ef3d4f11dbb9d65ef2a70c7929467e3f0e7b8399 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Jul 2014 15:29:19 -0700 Subject: net: bcmgenet: remove wol_enabled conditional code Checking for wol_enabled in bcmgenet_close() is bogus, since no other code places set priv->wol_enabled. Remove that as it will conflict with the upcoming and functional Wake-on-LAN implementation. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 --------- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 1 - 2 files changed, 10 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 16281ad2da12..3cbf29095257 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1994,12 +1994,6 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_set_hw_addr(priv, dev->dev_addr); - if (priv->wol_enabled) { - ret = bcmgenet_wol_resume(priv); - if (ret) - return ret; - } - if (phy_is_internal(priv->phydev)) { reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); reg |= EXT_ENERGY_DET_MASK; @@ -2161,9 +2155,6 @@ static int bcmgenet_close(struct net_device *dev) if (phy_is_internal(priv->phydev)) bcmgenet_power_down(priv, GENET_POWER_PASSIVE); - if (priv->wol_enabled) - clk_enable(priv->clk_wol); - if (!IS_ERR(priv->clk)) clk_disable_unprepare(priv->clk); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index e23c993b1362..f4891a1b6758 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -583,7 +583,6 @@ struct bcmgenet_priv { struct platform_device *pdev; /* WOL */ - unsigned long wol_enabled; struct clk *clk_wol; u32 wolopts; -- cgit v1.2.3 From e29585b8d8707686d3f8f66fdfd20d8c66fb5f6d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Jul 2014 15:29:20 -0700 Subject: net: bcmgenet: add umac_enable_set helper Factor the code touching the UniMAC RX/TX enable bits since we are going to re-use it for implementing suspend/resume. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 37 +++++++++++++++++--------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 3cbf29095257..c037c888640d 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1437,6 +1437,25 @@ static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv) } } +static void umac_enable_set(struct bcmgenet_priv *priv, u32 mask, + bool enable) +{ + u32 reg; + + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + if (enable) + reg |= mask; + else + reg &= ~mask; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + + /* UniMAC stops on a packet boundary, wait for a full-size packet + * to be processed + */ + if (enable == 0) + usleep_range(1000, 2000); +} + static int reset_umac(struct bcmgenet_priv *priv) { struct device *kdev = &priv->pdev->dev; @@ -1988,9 +2007,7 @@ static int bcmgenet_open(struct net_device *dev) goto err_clk_disable; /* disable ethernet MAC while updating its registers */ - reg = bcmgenet_umac_readl(priv, UMAC_CMD); - reg &= ~(CMD_TX_EN | CMD_RX_EN); - bcmgenet_umac_writel(priv, reg, UMAC_CMD); + umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false); bcmgenet_set_hw_addr(priv, dev->dev_addr); @@ -2030,11 +2047,10 @@ static int bcmgenet_open(struct net_device *dev) /* Start the network engine */ napi_enable(&priv->napi); - reg = bcmgenet_umac_readl(priv, UMAC_CMD); - reg |= (CMD_TX_EN | CMD_RX_EN); - bcmgenet_umac_writel(priv, reg, UMAC_CMD); + umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true); /* Make sure we reflect the value of CRC_CMD_FWD */ + reg = bcmgenet_umac_readl(priv, UMAC_CMD); priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); device_set_wakeup_capable(&dev->dev, 1); @@ -2115,16 +2131,13 @@ static int bcmgenet_close(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); int ret; - u32 reg; netif_dbg(priv, ifdown, dev, "bcmgenet_close\n"); phy_stop(priv->phydev); /* Disable MAC receive */ - reg = bcmgenet_umac_readl(priv, UMAC_CMD); - reg &= ~CMD_RX_EN; - bcmgenet_umac_writel(priv, reg, UMAC_CMD); + umac_enable_set(priv, CMD_RX_EN, false); netif_tx_stop_all_queues(dev); @@ -2133,9 +2146,7 @@ static int bcmgenet_close(struct net_device *dev) return ret; /* Disable MAC transmit. TX DMA disabled have to done before this */ - reg = bcmgenet_umac_readl(priv, UMAC_CMD); - reg &= ~CMD_TX_EN; - bcmgenet_umac_writel(priv, reg, UMAC_CMD); + umac_enable_set(priv, CMD_TX_EN, false); napi_disable(&priv->napi); -- cgit v1.2.3 From 909ff5efbab85f2724c5f91ec200ebc9df50c440 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Jul 2014 15:29:21 -0700 Subject: net: bcmgenet: modularize bcmgenet_{open,close} Introduce a bunch of helper functions: bcmgenet_netif_start, bcmgenet_netif_stop and bcmgenet_intr_disable to help reuse code that is going to be necessary for suspend/resume. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 86 ++++++++++++++++---------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index c037c888640d..5cab188ee323 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1488,6 +1488,17 @@ static int reset_umac(struct bcmgenet_priv *priv) return 0; } +static void bcmgenet_intr_disable(struct bcmgenet_priv *priv) +{ + /* Mask all interrupts.*/ + bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET); + bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR); + bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + bcmgenet_intrl2_1_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET); + bcmgenet_intrl2_1_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR); + bcmgenet_intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); +} + static int init_umac(struct bcmgenet_priv *priv) { struct device *kdev = &priv->pdev->dev; @@ -1516,10 +1527,7 @@ static int init_umac(struct bcmgenet_priv *priv) if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv)) bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL); - /* Mask all interrupts.*/ - bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET); - bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR); - bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + bcmgenet_intr_disable(priv); cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE; @@ -1986,6 +1994,23 @@ static void bcmgenet_enable_dma(struct bcmgenet_priv *priv, u32 dma_ctrl) bcmgenet_tdma_writel(priv, reg, DMA_CTRL); } +static void bcmgenet_netif_start(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + + /* Start the network engine */ + napi_enable(&priv->napi); + + umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true); + + if (phy_is_internal(priv->phydev)) + bcmgenet_power_up(priv, GENET_POWER_PASSIVE); + + netif_tx_start_all_queues(dev); + + phy_start(priv->phydev); +} + static int bcmgenet_open(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -2009,6 +2034,10 @@ static int bcmgenet_open(struct net_device *dev) /* disable ethernet MAC while updating its registers */ umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false); + /* Make sure we reflect the value of CRC_CMD_FWD */ + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); + bcmgenet_set_hw_addr(priv, dev->dev_addr); if (phy_is_internal(priv->phydev)) { @@ -2017,6 +2046,8 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); } + device_set_wakeup_capable(&dev->dev, 1); + /* Disable RX/TX DMA and flush TX queues */ dma_ctrl = bcmgenet_dma_disable(priv); @@ -2044,23 +2075,7 @@ static int bcmgenet_open(struct net_device *dev) goto err_irq0; } - /* Start the network engine */ - napi_enable(&priv->napi); - - umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true); - - /* Make sure we reflect the value of CRC_CMD_FWD */ - reg = bcmgenet_umac_readl(priv, UMAC_CMD); - priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); - - device_set_wakeup_capable(&dev->dev, 1); - - if (phy_is_internal(priv->phydev)) - bcmgenet_power_up(priv, GENET_POWER_PASSIVE); - - netif_tx_start_all_queues(dev); - - phy_start(priv->phydev); + bcmgenet_netif_start(dev); return 0; @@ -2127,6 +2142,22 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) return ret; } +static void bcmgenet_netif_stop(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + + netif_tx_stop_all_queues(dev); + napi_disable(&priv->napi); + phy_stop(priv->phydev); + + bcmgenet_intr_disable(priv); + + /* Wait for pending work items to complete. Since interrupts are + * disabled no new work will be scheduled. + */ + cancel_work_sync(&priv->bcmgenet_irq_work); +} + static int bcmgenet_close(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -2134,13 +2165,11 @@ static int bcmgenet_close(struct net_device *dev) netif_dbg(priv, ifdown, dev, "bcmgenet_close\n"); - phy_stop(priv->phydev); + bcmgenet_netif_stop(dev); /* Disable MAC receive */ umac_enable_set(priv, CMD_RX_EN, false); - netif_tx_stop_all_queues(dev); - ret = bcmgenet_dma_teardown(priv); if (ret) return ret; @@ -2148,8 +2177,6 @@ static int bcmgenet_close(struct net_device *dev) /* Disable MAC transmit. TX DMA disabled have to done before this */ umac_enable_set(priv, CMD_TX_EN, false); - napi_disable(&priv->napi); - /* tx reclaim */ bcmgenet_tx_reclaim_all(dev); bcmgenet_fini_dma(priv); @@ -2157,12 +2184,6 @@ static int bcmgenet_close(struct net_device *dev) free_irq(priv->irq0, priv); free_irq(priv->irq1, priv); - /* Wait for pending work items to complete - we are stopping - * the clock now. Since interrupts are disabled, no new work - * will be scheduled. - */ - cancel_work_sync(&priv->bcmgenet_irq_work); - if (phy_is_internal(priv->phydev)) bcmgenet_power_down(priv, GENET_POWER_PASSIVE); @@ -2563,7 +2584,6 @@ static int bcmgenet_remove(struct platform_device *pdev) return 0; } - static struct platform_driver bcmgenet_driver = { .probe = bcmgenet_probe, .remove = bcmgenet_remove, -- cgit v1.2.3 From b6e978e50444a063f066f058d134173de877b968 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Jul 2014 15:29:22 -0700 Subject: net: bcmgenet: add suspend/resume callbacks Implement suspend/resume callbacks in the GENET driver. This makes sure that we de-initialize and re-initialize the hardware correctly before entering suspend and when resuming. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 95 ++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 5cab188ee323..bbd8bf326a35 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2584,6 +2584,100 @@ static int bcmgenet_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int bcmgenet_suspend(struct device *d) +{ + struct net_device *dev = dev_get_drvdata(d); + struct bcmgenet_priv *priv = netdev_priv(dev); + int ret; + + if (!netif_running(dev)) + return 0; + + bcmgenet_netif_stop(dev); + + netif_device_detach(dev); + + /* Disable MAC receive */ + umac_enable_set(priv, CMD_RX_EN, false); + + ret = bcmgenet_dma_teardown(priv); + if (ret) + return ret; + + /* Disable MAC transmit. TX DMA disabled have to done before this */ + umac_enable_set(priv, CMD_TX_EN, false); + + /* tx reclaim */ + bcmgenet_tx_reclaim_all(dev); + bcmgenet_fini_dma(priv); + + /* Turn off the clocks */ + clk_disable_unprepare(priv->clk); + + return 0; +} + +static int bcmgenet_resume(struct device *d) +{ + struct net_device *dev = dev_get_drvdata(d); + struct bcmgenet_priv *priv = netdev_priv(dev); + unsigned long dma_ctrl; + int ret; + u32 reg; + + if (!netif_running(dev)) + return 0; + + /* Turn on the clock */ + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + bcmgenet_umac_reset(priv); + + ret = init_umac(priv); + if (ret) + goto out_clk_disable; + + /* disable ethernet MAC while updating its registers */ + umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false); + + bcmgenet_set_hw_addr(priv, dev->dev_addr); + + if (phy_is_internal(priv->phydev)) { + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); + reg |= EXT_ENERGY_DET_MASK; + bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); + } + + /* Disable RX/TX DMA and flush TX queues */ + dma_ctrl = bcmgenet_dma_disable(priv); + + /* Reinitialize TDMA and RDMA and SW housekeeping */ + ret = bcmgenet_init_dma(priv); + if (ret) { + netdev_err(dev, "failed to initialize DMA\n"); + goto out_clk_disable; + } + + /* Always enable ring 16 - descriptor ring */ + bcmgenet_enable_dma(priv, dma_ctrl); + + netif_device_attach(dev); + + bcmgenet_netif_start(dev); + + return 0; + +out_clk_disable: + clk_disable_unprepare(priv->clk); + return ret; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, bcmgenet_suspend, bcmgenet_resume); + static struct platform_driver bcmgenet_driver = { .probe = bcmgenet_probe, .remove = bcmgenet_remove, @@ -2591,6 +2685,7 @@ static struct platform_driver bcmgenet_driver = { .name = "bcmgenet", .owner = THIS_MODULE, .of_match_table = bcmgenet_match, + .pm = &bcmgenet_pm_ops, }, }; module_platform_driver(bcmgenet_driver); -- cgit v1.2.3 From 8562056f267db98f5c078fcf7f071c8a4a752ef3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Jul 2014 15:29:23 -0700 Subject: net: bcmgenet: request Wake-on-LAN interrupt Attempt to the request the Wake-on-LAN interrupt bit, and if successful, advertise wakeup capability instead of doing this unconditionnally. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 19 +++++++++++++++++-- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index bbd8bf326a35..344a889deaaa 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1918,6 +1918,15 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id) +{ + struct bcmgenet_priv *priv = dev_id; + + pm_wakeup_event(&priv->pdev->dev, 0); + + return IRQ_HANDLED; +} + static void bcmgenet_umac_reset(struct bcmgenet_priv *priv) { u32 reg; @@ -2046,8 +2055,6 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); } - device_set_wakeup_capable(&dev->dev, 1); - /* Disable RX/TX DMA and flush TX queues */ dma_ctrl = bcmgenet_dma_disable(priv); @@ -2473,6 +2480,7 @@ static int bcmgenet_probe(struct platform_device *pdev) priv = netdev_priv(dev); priv->irq0 = platform_get_irq(pdev, 0); priv->irq1 = platform_get_irq(pdev, 1); + priv->wol_irq = platform_get_irq(pdev, 2); if (!priv->irq0 || !priv->irq1) { dev_err(&pdev->dev, "can't find IRQs\n"); err = -EINVAL; @@ -2507,6 +2515,13 @@ static int bcmgenet_probe(struct platform_device *pdev) dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; + /* Request the WOL interrupt and advertise suspend if available */ + priv->wol_irq_disabled = true; + err = devm_request_irq(&pdev->dev, priv->wol_irq, bcmgenet_wol_isr, 0, + dev->name, priv); + if (!err) + device_set_wakeup_capable(&pdev->dev, 1); + /* Set the needed headroom to account for any possible * features enabling/disabling at runtime */ diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index f4891a1b6758..64bc53d86480 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -569,6 +569,8 @@ struct bcmgenet_priv { int irq1; unsigned int irq0_stat; unsigned int irq1_stat; + int wol_irq; + bool wol_irq_disabled; /* HW descriptors/checksum variables */ bool desc_64b_en; -- cgit v1.2.3 From c51de7f3976b649d72d3ff006954640aec2fe58c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Jul 2014 15:29:24 -0700 Subject: net: bcmgenet: add Wake-on-LAN support code Add all the required code to program the GENET hardware to enter Wake-on-LAN mode and wake using MagicPackets with or without SecureOn password. This code is hooked to the build system, but is not yet referenced from ethtool or the main bcmgenet driver. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/Makefile | 2 +- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 9 + drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 206 +++++++++++++++++++++ 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c diff --git a/drivers/net/ethernet/broadcom/genet/Makefile b/drivers/net/ethernet/broadcom/genet/Makefile index 31f55a90a197..9b6885efa9e7 100644 --- a/drivers/net/ethernet/broadcom/genet/Makefile +++ b/drivers/net/ethernet/broadcom/genet/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_BCMGENET) += genet.o -genet-objs := bcmgenet.o bcmmii.o +genet-objs := bcmgenet.o bcmmii.o bcmgenet_wol.o diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 64bc53d86480..c61cd98b662e 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -456,6 +456,7 @@ struct enet_cb { enum bcmgenet_power_mode { GENET_POWER_CABLE_SENSE = 0, GENET_POWER_PASSIVE, + GENET_POWER_WOL_MAGIC, }; struct bcmgenet_priv; @@ -626,4 +627,12 @@ int bcmgenet_mii_config(struct net_device *dev); void bcmgenet_mii_exit(struct net_device *dev); void bcmgenet_mii_reset(struct net_device *dev); +/* Wake-on-LAN routines */ +void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol); +int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol); +int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv, + enum bcmgenet_power_mode mode); +void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv, + enum bcmgenet_power_mode mode); + #endif /* __BCMGENET_H__ */ diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c new file mode 100644 index 000000000000..b82b7e4e06b2 --- /dev/null +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c @@ -0,0 +1,206 @@ +/* + * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support + * + * Copyright (c) 2014 Broadcom Corporation + * + * 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 pr_fmt(fmt) "bcmgenet_wol: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bcmgenet.h" + +/* ethtool function - get WOL (Wake on LAN) settings, Only Magic Packet + * Detection is supported through ethtool + */ +void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + u32 reg; + + wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE; + wol->wolopts = priv->wolopts; + memset(wol->sopass, 0, sizeof(wol->sopass)); + + if (wol->wolopts & WAKE_MAGICSECURE) { + reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_MS); + put_unaligned_be16(reg, &wol->sopass[0]); + reg = bcmgenet_umac_readl(priv, UMAC_MPD_PW_LS); + put_unaligned_be32(reg, &wol->sopass[2]); + } +} + +/* ethtool function - set WOL (Wake on LAN) settings. + * Only for magic packet detection mode. + */ +int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + struct device *kdev = &priv->pdev->dev; + u32 reg; + + if (!device_can_wakeup(kdev)) + return -ENOTSUPP; + + if (wol->wolopts & ~(WAKE_MAGIC | WAKE_MAGICSECURE)) + return -EINVAL; + + if (wol->wolopts & WAKE_MAGICSECURE) { + bcmgenet_umac_writel(priv, get_unaligned_be16(&wol->sopass[0]), + UMAC_MPD_PW_MS); + bcmgenet_umac_writel(priv, get_unaligned_be32(&wol->sopass[2]), + UMAC_MPD_PW_LS); + reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL); + reg |= MPD_PW_EN; + bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL); + } + + /* Flag the device and relevant IRQ as wakeup capable */ + if (wol->wolopts) { + device_set_wakeup_enable(kdev, 1); + enable_irq_wake(priv->wol_irq); + priv->wol_irq_disabled = false; + } else { + device_set_wakeup_enable(kdev, 0); + /* Avoid unbalanced disable_irq_wake calls */ + if (!priv->wol_irq_disabled) + disable_irq_wake(priv->wol_irq); + priv->wol_irq_disabled = true; + } + + priv->wolopts = wol->wolopts; + + return 0; +} + +static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv) +{ + struct net_device *dev = priv->dev; + int retries = 0; + + while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS) + & RBUF_STATUS_WOL)) { + retries++; + if (retries > 5) { + netdev_crit(dev, "polling wol mode timeout\n"); + return -ETIMEDOUT; + } + mdelay(1); + } + + return retries; +} + +int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv, + enum bcmgenet_power_mode mode) +{ + struct net_device *dev = priv->dev; + u32 cpu_mask_clear; + int retries = 0; + u32 reg; + + if (mode != GENET_POWER_WOL_MAGIC) { + netif_err(priv, wol, dev, "unsupported mode: %d\n", mode); + return -EINVAL; + } + + /* disable RX */ + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + reg &= ~CMD_RX_EN; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + mdelay(10); + + reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL); + reg |= MPD_EN; + bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL); + + /* Do not leave UniMAC in MPD mode only */ + retries = bcmgenet_poll_wol_status(priv); + if (retries < 0) { + reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL); + reg &= ~MPD_EN; + bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL); + return retries; + } + + netif_dbg(priv, wol, dev, "MPD WOL-ready status set after %d msec\n", + retries); + + /* Enable CRC forward */ + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + priv->crc_fwd_en = 1; + reg |= CMD_CRC_FWD; + + /* Receiver must be enabled for WOL MP detection */ + reg |= CMD_RX_EN; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + + if (priv->hw_params->flags & GENET_HAS_EXT) { + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); + reg &= ~EXT_ENERGY_DET_MASK; + bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); + } + + /* Enable the MPD interrupt */ + cpu_mask_clear = UMAC_IRQ_MPD_R; + + bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR); + + return 0; +} + +void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv, + enum bcmgenet_power_mode mode) +{ + u32 cpu_mask_set; + u32 reg; + + if (mode != GENET_POWER_WOL_MAGIC) { + netif_err(priv, wol, priv->dev, "invalid mode: %d\n", mode); + return; + } + + reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL); + reg &= ~MPD_EN; + bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL); + + /* Disable CRC Forward */ + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + reg &= ~CMD_CRC_FWD; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + priv->crc_fwd_en = 0; + + /* Stop monitoring magic packet IRQ */ + cpu_mask_set = UMAC_IRQ_MPD_R; + + /* Stop monitoring magic packet IRQ */ + bcmgenet_intrl2_0_writel(priv, cpu_mask_set, INTRL2_CPU_MASK_SET); +} -- cgit v1.2.3 From c3ae64ae0c08b3ff7fe0dea4d43c586f02a3adb5 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Jul 2014 15:29:25 -0700 Subject: net: bcmgenet: handle GENET_POWER_WOL_MAGIC Update bcmgenet_power_{up,down} to handle the case where the adapter has been suspend respectively resumed from Wake-on-LAN using MagicPackets. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 344a889deaaa..f5118f4cccf3 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -743,6 +743,10 @@ static void bcmgenet_power_down(struct bcmgenet_priv *priv, phy_detach(priv->phydev); break; + case GENET_POWER_WOL_MAGIC: + bcmgenet_wol_power_down_cfg(priv, mode); + break; + case GENET_POWER_PASSIVE: /* Power down LED */ bcmgenet_mii_reset(priv->dev); @@ -777,6 +781,9 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, /* enable APD */ reg |= EXT_PWR_DN_EN_LD; break; + case GENET_POWER_WOL_MAGIC: + bcmgenet_wol_power_up_cfg(priv, mode); + return; default: break; } -- cgit v1.2.3 From 8fdb0e0fb972f9665dd21aa69825ba748ebbdf45 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Jul 2014 15:29:26 -0700 Subject: net: bcmgenet: handle UMAC_IRQ_MPD_R interrupt bit Handle UMAC_IRQ_MPD_R interrupt bit in our workqueue to make sure that we properly re-configure the GENET adapter from Wake-on-LAN. bcmgenet_power_up() makes sure that we will not leave the UniMAC hardware in MagicPacket matching mode, since that would prevent any other packet from being received. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index f5118f4cccf3..319b94381d2e 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1836,6 +1836,13 @@ static void bcmgenet_irq_task(struct work_struct *work) netif_dbg(priv, intr, priv->dev, "%s\n", __func__); + if (priv->irq0_stat & UMAC_IRQ_MPD_R) { + priv->irq0_stat &= ~UMAC_IRQ_MPD_R; + netif_dbg(priv, wol, priv->dev, + "magic packet detected, waking up\n"); + bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC); + } + /* Link UP/DOWN event */ if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && (priv->irq0_stat & (UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN))) { -- cgit v1.2.3 From 1c3c1e7996c1f99ab96b7d499d9d90072147909e Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Jul 2014 15:29:27 -0700 Subject: net: bcmgenet: fix bcmgenet_wol_resume bcmgenet_wol_resume() will create an unbalanced clock state for the wol_clk clock pointer since everywhere else in the code, we always call clk_prepare_enable() and clk_disable_unprepare(). This function also calls init_umac() which is neither correct nor necessary since bcmgenet_resume() and bcmgenet_open() already does that. Finally calling bcmgenet_wol_resume() in bcmgenet_open() is not correct, since the interface would not have been able to put us in Wake-on-LAN mode if it was not UP before. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 319b94381d2e..1925ae1dc1e6 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1965,14 +1965,8 @@ static void bcmgenet_set_hw_addr(struct bcmgenet_priv *priv, static int bcmgenet_wol_resume(struct bcmgenet_priv *priv) { - int ret; - /* From WOL-enabled suspend, switch to regular clock */ - clk_disable(priv->clk_wol); - /* init umac registers to synchronize s/w with h/w */ - ret = init_umac(priv); - if (ret) - return ret; + clk_disable_unprepare(priv->clk_wol); phy_init_hw(priv->phydev); /* Speed settings must be restored */ -- cgit v1.2.3 From 8c90db72f92603d7972488bb2e7efcf23b311655 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Jul 2014 15:29:28 -0700 Subject: net: bcmgenet: suspend and resume from Wake-on-LAN Update bcmgenet_suspend() to prepare the hardware for being put into Wake-on-LAN mode if the device can wakeup the system, and Wake-on-LAN is enabled. Whether we resume from Wake-on-LAN or not, make sure that bcmgenet_resume() disables the UniMAC MagicPacket matching mode and puts the hardware in a state where it can receive all incoming packets. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 1925ae1dc1e6..62ef49c85980 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2635,6 +2635,12 @@ static int bcmgenet_suspend(struct device *d) bcmgenet_tx_reclaim_all(dev); bcmgenet_fini_dma(priv); + /* Prepare the device for Wake-on-LAN and switch to the slow clock */ + if (device_may_wakeup(d) && priv->wolopts) { + bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC); + clk_prepare_enable(priv->clk_wol); + } + /* Turn off the clocks */ clk_disable_unprepare(priv->clk); @@ -2663,6 +2669,12 @@ static int bcmgenet_resume(struct device *d) if (ret) goto out_clk_disable; + if (priv->wolopts) + ret = bcmgenet_wol_resume(priv); + + if (ret) + goto out_clk_disable; + /* disable ethernet MAC while updating its registers */ umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false); -- cgit v1.2.3 From 06ba8375ec42daae19124eaa106295dbe159731f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Jul 2014 15:29:29 -0700 Subject: net: bcmgenet: hook ethtool set/get_wol operations Now that Wake-on-LAN support mode is fully integrated into the driver, allow an user to query and configure Wake-on-LAN in the driver. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 62ef49c85980..0173a6d355aa 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -730,6 +730,8 @@ static struct ethtool_ops bcmgenet_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = bcmgenet_get_msglevel, .set_msglevel = bcmgenet_set_msglevel, + .get_wol = bcmgenet_get_wol, + .set_wol = bcmgenet_set_wol, }; /* Power down the unimac, based on mode. */ -- cgit v1.2.3 From 240524089d7a5c0396656574e299beb3a55461e3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Jul 2014 17:42:39 -0700 Subject: net: bcmgenet: only update UMAC_CMD if something changed The link adjustment callback can be called as frequently as desired by the PHY library, as such, let's avoid doing a Read/Modify/Write sequence if nothing changed, since these register accesses can be expensive. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmmii.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index add8d8596084..b1338c9e8abb 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -136,17 +136,18 @@ static void bcmgenet_mii_setup(struct net_device *dev) /* pause capability */ if (!phydev->pause) cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE; + } + if (status_changed) { reg = bcmgenet_umac_readl(priv, UMAC_CMD); reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) | CMD_HD_EN | CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE); reg |= cmd_bits; bcmgenet_umac_writel(priv, reg, UMAC_CMD); - } - if (status_changed) phy_print_status(phydev); + } } void bcmgenet_mii_reset(struct net_device *dev) -- cgit v1.2.3 From 45cbb2e499cf4686e809206b29377a7e15037bcc Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Mon, 21 Jul 2014 12:54:43 +0200 Subject: qeth: Display adjacent switch attributes Add support to display the adjacent switch port's forwarding attributes. Currently supports info on forwarding modes '802.1' and 'rr' (reflective relay). Signed-off-by: Stefan Raspl Signed-off-by: Frank Blaschka Reviewed-by: Ursula Braun Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 7 +++++++ drivers/s390/net/qeth_core_main.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/s390/net/qeth_core_mpc.h | 17 +++++++++++++++++ drivers/s390/net/qeth_core_sys.c | 38 +++++++++++++++++++++++++++++++++++++- 4 files changed, 100 insertions(+), 1 deletion(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index a2088af51cc5..bbafbd0e017a 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -766,6 +766,11 @@ struct carrier_info { __u32 port_speed; }; +struct qeth_switch_info { + __u32 capabilities; + __u32 settings; +}; + #define QETH_NAPI_WEIGHT NAPI_POLL_WEIGHT struct qeth_card { @@ -946,6 +951,8 @@ struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *); int qeth_mdio_read(struct net_device *, int, int); int qeth_snmp_command(struct qeth_card *, char __user *); int qeth_query_oat_command(struct qeth_card *, char __user *); +int qeth_query_switch_attributes(struct qeth_card *card, + struct qeth_switch_info *sw_info); int qeth_query_card_info(struct qeth_card *card, struct carrier_info *carrier_info); int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index f54bec54d677..71bfacfc097e 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3037,6 +3037,45 @@ int qeth_query_ipassists(struct qeth_card *card, enum qeth_prot_versions prot) } EXPORT_SYMBOL_GPL(qeth_query_ipassists); +static int qeth_query_switch_attributes_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) +{ + struct qeth_ipa_cmd *cmd; + struct qeth_switch_info *sw_info; + struct qeth_query_switch_attributes *attrs; + + QETH_CARD_TEXT(card, 2, "qswiatcb"); + cmd = (struct qeth_ipa_cmd *) data; + sw_info = (struct qeth_switch_info *)reply->param; + if (cmd->data.setadapterparms.hdr.return_code == 0) { + attrs = &cmd->data.setadapterparms.data.query_switch_attributes; + sw_info->capabilities = attrs->capabilities; + sw_info->settings = attrs->settings; + QETH_CARD_TEXT_(card, 2, "%04x%04x", sw_info->capabilities, + sw_info->settings); + } + qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd); + + return 0; +} + +int qeth_query_switch_attributes(struct qeth_card *card, + struct qeth_switch_info *sw_info) +{ + struct qeth_cmd_buffer *iob; + + QETH_CARD_TEXT(card, 2, "qswiattr"); + if (!qeth_adp_supported(card, IPA_SETADP_QUERY_SWITCH_ATTRIBUTES)) + return -EOPNOTSUPP; + if (!netif_carrier_ok(card->dev)) + return -ENOMEDIUM; + iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_SWITCH_ATTRIBUTES, + sizeof(struct qeth_ipacmd_setadpparms_hdr)); + return qeth_send_ipa_cmd(card, iob, + qeth_query_switch_attributes_cb, sw_info); +} +EXPORT_SYMBOL_GPL(qeth_query_switch_attributes); + static int qeth_query_setdiagass_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index cf6a90ed42ae..1558be1af72d 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -242,6 +242,7 @@ enum qeth_ipa_setadp_cmd { IPA_SETADP_SET_DIAG_ASSIST = 0x00002000L, IPA_SETADP_SET_ACCESS_CONTROL = 0x00010000L, IPA_SETADP_QUERY_OAT = 0x00080000L, + IPA_SETADP_QUERY_SWITCH_ATTRIBUTES = 0x00100000L, }; enum qeth_ipa_mac_ops { CHANGE_ADDR_READ_MAC = 0, @@ -431,6 +432,21 @@ struct qeth_query_card_info { __u32 reserved2; }; +#define QETH_SWITCH_FORW_802_1 0x00000001 +#define QETH_SWITCH_FORW_REFL_RELAY 0x00000002 +#define QETH_SWITCH_CAP_RTE 0x00000004 +#define QETH_SWITCH_CAP_ECP 0x00000008 +#define QETH_SWITCH_CAP_VDP 0x00000010 + +struct qeth_query_switch_attributes { + __u8 version; + __u8 reserved1; + __u16 reserved2; + __u32 capabilities; + __u32 settings; + __u8 reserved3[8]; +}; + struct qeth_ipacmd_setadpparms_hdr { __u32 supp_hw_cmds; __u32 reserved1; @@ -452,6 +468,7 @@ struct qeth_ipacmd_setadpparms { struct qeth_set_access_ctrl set_access_ctrl; struct qeth_query_oat query_oat; struct qeth_query_card_info card_info; + struct qeth_query_switch_attributes query_switch_attributes; __u32 mode; } data; } __attribute__ ((packed)); diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 8a25a2be9890..15523f0e4c03 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -543,7 +543,42 @@ out: } static DEVICE_ATTR(isolation, 0644, qeth_dev_isolation_show, - qeth_dev_isolation_store); + qeth_dev_isolation_store); + +static ssize_t qeth_dev_switch_attrs_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qeth_card *card = dev_get_drvdata(dev); + struct qeth_switch_info sw_info; + int rc = 0; + + if (!card) + return -EINVAL; + + if (card->state != CARD_STATE_SOFTSETUP && card->state != CARD_STATE_UP) + return sprintf(buf, "n/a\n"); + + rc = qeth_query_switch_attributes(card, &sw_info); + if (rc) + return rc; + + if (!sw_info.capabilities) + rc = sprintf(buf, "unknown"); + + if (sw_info.capabilities & QETH_SWITCH_FORW_802_1) + rc = sprintf(buf, (sw_info.settings & QETH_SWITCH_FORW_802_1 ? + "[802.1]" : "802.1")); + if (sw_info.capabilities & QETH_SWITCH_FORW_REFL_RELAY) + rc += sprintf(buf + rc, + (sw_info.settings & QETH_SWITCH_FORW_REFL_RELAY ? + " [rr]" : " rr")); + rc += sprintf(buf + rc, "\n"); + + return rc; +} + +static DEVICE_ATTR(switch_attrs, 0444, + qeth_dev_switch_attrs_show, NULL); static ssize_t qeth_hw_trap_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -728,6 +763,7 @@ static struct attribute *qeth_device_attrs[] = { &dev_attr_layer2.attr, &dev_attr_isolation.attr, &dev_attr_hw_trap.attr, + &dev_attr_switch_attrs.attr, NULL, }; static struct attribute_group qeth_device_attr_group = { -- cgit v1.2.3 From 1042cab8627a2d11491e8b0dd40c4dda3180285a Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Mon, 21 Jul 2014 12:54:44 +0200 Subject: af_iucv: avoid path quiesce of severed path in shutdown() An af_iucv stress test showed -EPIPE results for sendmsg() calls. They are caused by quiescing a path even though it has been already severed by peer. For IUCV transport shutdown() consists of 2 steps: (1) sending the shutdown message to peer (2) quiescing the iucv path If the iucv path between these 2 steps is severed due to peer closing the path, the quiesce step is no longer needed. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Reported-by: Philipp Hachtmann Signed-off-by: David S. Miller --- net/iucv/af_iucv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index d79f5fb695b8..a089b6b91650 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1542,7 +1542,8 @@ static int iucv_sock_shutdown(struct socket *sock, int how) sk->sk_shutdown |= how; if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) { - if (iucv->transport == AF_IUCV_TRANS_IUCV) { + if ((iucv->transport == AF_IUCV_TRANS_IUCV) && + iucv->path) { err = pr_iucv->path_quiesce(iucv->path, NULL); if (err) err = -ENOTCONN; -- cgit v1.2.3 From e3e5af33e6d64a36bce1dfd9f599649f539801de Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Mon, 21 Jul 2014 17:22:17 +0530 Subject: enic: remove #ifdef CONFIG_RFS_ACCEL around filter structures This patch removes the #ifdef CONFIG_RFS_ACCEL around the classifier filter structures. This makes the filter structures available when CONFIG_RFS_ACCEL = n. Introduce enic_rfs_timer_start() & enic_rfs_timer_stop() to start/stop the timer. These two functions are nop when CONFIG_RFS_ACCEL = n. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic.h | 5 --- drivers/net/ethernet/cisco/enic/enic_clsf.c | 69 ++++++++++++++--------------- drivers/net/ethernet/cisco/enic/enic_clsf.h | 22 +++++++-- 3 files changed, 51 insertions(+), 45 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index 4ecbbb3c024a..962510f391df 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -99,7 +99,6 @@ struct enic_port_profile { u8 mac_addr[ETH_ALEN]; }; -#ifdef CONFIG_RFS_ACCEL /* enic_rfs_fltr_node - rfs filter node in hash table * @@keys: IPv4 5 tuple * @flow_id: flow_id of clsf filter provided by kernel @@ -135,8 +134,6 @@ struct enic_rfs_flw_tbl { struct timer_list rfs_may_expire; }; -#endif /* CONFIG_RFS_ACCEL */ - /* Per-instance private data structure */ struct enic { struct net_device *netdev; @@ -188,9 +185,7 @@ struct enic { /* completion queue cache line section */ ____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX]; unsigned int cq_count; -#ifdef CONFIG_RFS_ACCEL struct enic_rfs_flw_tbl rfs_h; -#endif }; static inline struct device *enic_get_dev(struct enic *enic) diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index bc451baac4cd..ee6acbf02ef0 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -65,37 +65,6 @@ int enic_delfltr(struct enic *enic, u16 filter_id) return ret; } -#ifdef CONFIG_RFS_ACCEL -void enic_flow_may_expire(unsigned long data) -{ - struct enic *enic = (struct enic *)data; - bool res; - int j; - - spin_lock(&enic->rfs_h.lock); - for (j = 0; j < ENIC_CLSF_EXPIRE_COUNT; j++) { - struct hlist_head *hhead; - struct hlist_node *tmp; - struct enic_rfs_fltr_node *n; - - hhead = &enic->rfs_h.ht_head[enic->rfs_h.toclean++]; - hlist_for_each_entry_safe(n, tmp, hhead, node) { - res = rps_may_expire_flow(enic->netdev, n->rq_id, - n->flow_id, n->fltr_id); - if (res) { - res = enic_delfltr(enic, n->fltr_id); - if (unlikely(res)) - continue; - hlist_del(&n->node); - kfree(n); - enic->rfs_h.free++; - } - } - } - spin_unlock(&enic->rfs_h.lock); - mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4); -} - /* enic_rfs_flw_tbl_init - initialize enic->rfs_h members * @enic: enic data */ @@ -109,17 +78,14 @@ void enic_rfs_flw_tbl_init(struct enic *enic) enic->rfs_h.max = enic->config.num_arfs; enic->rfs_h.free = enic->rfs_h.max; enic->rfs_h.toclean = 0; - init_timer(&enic->rfs_h.rfs_may_expire); - enic->rfs_h.rfs_may_expire.function = enic_flow_may_expire; - enic->rfs_h.rfs_may_expire.data = (unsigned long)enic; - mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4); + enic_rfs_timer_start(enic); } void enic_rfs_flw_tbl_free(struct enic *enic) { int i; - del_timer_sync(&enic->rfs_h.rfs_may_expire); + enic_rfs_timer_stop(enic); spin_lock(&enic->rfs_h.lock); enic->rfs_h.free = 0; for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) { @@ -137,6 +103,37 @@ void enic_rfs_flw_tbl_free(struct enic *enic) spin_unlock(&enic->rfs_h.lock); } +#ifdef CONFIG_RFS_ACCEL +void enic_flow_may_expire(unsigned long data) +{ + struct enic *enic = (struct enic *)data; + bool res; + int j; + + spin_lock(&enic->rfs_h.lock); + for (j = 0; j < ENIC_CLSF_EXPIRE_COUNT; j++) { + struct hlist_head *hhead; + struct hlist_node *tmp; + struct enic_rfs_fltr_node *n; + + hhead = &enic->rfs_h.ht_head[enic->rfs_h.toclean++]; + hlist_for_each_entry_safe(n, tmp, hhead, node) { + res = rps_may_expire_flow(enic->netdev, n->rq_id, + n->flow_id, n->fltr_id); + if (res) { + res = enic_delfltr(enic, n->fltr_id); + if (unlikely(res)) + continue; + hlist_del(&n->node); + kfree(n); + enic->rfs_h.free++; + } + } + } + spin_unlock(&enic->rfs_h.lock); + mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4); +} + static struct enic_rfs_fltr_node *htbl_key_search(struct hlist_head *h, struct flow_keys *k) { diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.h b/drivers/net/ethernet/cisco/enic/enic_clsf.h index d572704cd117..221f364cd811 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.h +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.h @@ -8,15 +8,29 @@ int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq); int enic_delfltr(struct enic *enic, u16 filter_id); - -#ifdef CONFIG_RFS_ACCEL void enic_rfs_flw_tbl_init(struct enic *enic); void enic_rfs_flw_tbl_free(struct enic *enic); + +#ifdef CONFIG_RFS_ACCEL int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, u16 rxq_index, u32 flow_id); +void enic_flow_may_expire(unsigned long data); + +static inline void enic_rfs_timer_start(struct enic *enic) +{ + init_timer(&enic->rfs_h.rfs_may_expire); + enic->rfs_h.rfs_may_expire.function = enic_flow_may_expire; + enic->rfs_h.rfs_may_expire.data = (unsigned long)enic; + mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4); +} + +static inline void enic_rfs_timer_stop(struct enic *enic) +{ + del_timer_sync(&enic->rfs_h.rfs_may_expire); +} #else -static inline void enic_rfs_flw_tbl_init(struct enic *enic) {} -static inline void enic_rfs_flw_tbl_free(struct enic *enic) {} +static inline void enic_rfs_timer_start(struct enic *enic) {} +static inline void enic_rfs_timer_stop(struct enic *enic) {} #endif /* CONFIG_RFS_ACCEL */ #endif /* _ENIC_CLSF_H_ */ -- cgit v1.2.3 From 3762ff8f0e95f50f78d94e3f62e839103d1303aa Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Mon, 21 Jul 2014 17:22:18 +0530 Subject: enic: Add ethtool support to show classifier filters added by the driver This patch impliments ethtool_ops->get_rxnfc() to display the classifier filter added by the driver. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_clsf.c | 18 +++++ drivers/net/ethernet/cisco/enic/enic_clsf.h | 1 + drivers/net/ethernet/cisco/enic/enic_ethtool.c | 98 ++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index ee6acbf02ef0..69dfd3c9e529 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -103,6 +103,24 @@ void enic_rfs_flw_tbl_free(struct enic *enic) spin_unlock(&enic->rfs_h.lock); } +struct enic_rfs_fltr_node *htbl_fltr_search(struct enic *enic, u16 fltr_id) +{ + int i; + + for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) { + struct hlist_head *hhead; + struct hlist_node *tmp; + struct enic_rfs_fltr_node *n; + + hhead = &enic->rfs_h.ht_head[i]; + hlist_for_each_entry_safe(n, tmp, hhead, node) + if (n->fltr_id == fltr_id) + return n; + } + + return NULL; +} + #ifdef CONFIG_RFS_ACCEL void enic_flow_may_expire(unsigned long data) { diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.h b/drivers/net/ethernet/cisco/enic/enic_clsf.h index 221f364cd811..6aa9f89d073b 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.h +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.h @@ -10,6 +10,7 @@ int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq); int enic_delfltr(struct enic *enic, u16 filter_id); void enic_rfs_flw_tbl_init(struct enic *enic); void enic_rfs_flw_tbl_free(struct enic *enic); +struct enic_rfs_fltr_node *htbl_fltr_search(struct enic *enic, u16 fltr_id); #ifdef CONFIG_RFS_ACCEL int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c index c75f84b42751..523c9ceb04c0 100644 --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c @@ -22,6 +22,7 @@ #include "enic_res.h" #include "enic.h" #include "enic_dev.h" +#include "enic_clsf.h" struct enic_stat { char name[ETH_GSTRING_LEN]; @@ -282,6 +283,102 @@ static int enic_set_coalesce(struct net_device *netdev, return 0; } +static int enic_grxclsrlall(struct enic *enic, struct ethtool_rxnfc *cmd, + u32 *rule_locs) +{ + int j, ret = 0, cnt = 0; + + cmd->data = enic->rfs_h.max - enic->rfs_h.free; + for (j = 0; j < (1 << ENIC_RFS_FLW_BITSHIFT); j++) { + struct hlist_head *hhead; + struct hlist_node *tmp; + struct enic_rfs_fltr_node *n; + + hhead = &enic->rfs_h.ht_head[j]; + hlist_for_each_entry_safe(n, tmp, hhead, node) { + if (cnt == cmd->rule_cnt) + return -EMSGSIZE; + rule_locs[cnt] = n->fltr_id; + cnt++; + } + } + cmd->rule_cnt = cnt; + + return ret; +} + +static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd) +{ + struct ethtool_rx_flow_spec *fsp = + (struct ethtool_rx_flow_spec *)&cmd->fs; + struct enic_rfs_fltr_node *n; + + n = htbl_fltr_search(enic, (u16)fsp->location); + if (!n) + return -EINVAL; + switch (n->keys.ip_proto) { + case IPPROTO_TCP: + fsp->flow_type = TCP_V4_FLOW; + break; + case IPPROTO_UDP: + fsp->flow_type = UDP_V4_FLOW; + break; + default: + return -EINVAL; + break; + } + + fsp->h_u.tcp_ip4_spec.ip4src = n->keys.src; + fsp->m_u.tcp_ip4_spec.ip4src = (__u32)~0; + + fsp->h_u.tcp_ip4_spec.ip4dst = n->keys.dst; + fsp->m_u.tcp_ip4_spec.ip4dst = (__u32)~0; + + fsp->h_u.tcp_ip4_spec.psrc = n->keys.port16[0]; + fsp->m_u.tcp_ip4_spec.psrc = (__u16)~0; + + fsp->h_u.tcp_ip4_spec.pdst = n->keys.port16[1]; + fsp->m_u.tcp_ip4_spec.pdst = (__u16)~0; + + fsp->ring_cookie = n->rq_id; + + return 0; +} + +static int enic_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, + u32 *rule_locs) +{ + struct enic *enic = netdev_priv(dev); + int ret = 0; + + switch (cmd->cmd) { + case ETHTOOL_GRXRINGS: + cmd->data = enic->rq_count; + break; + case ETHTOOL_GRXCLSRLCNT: + spin_lock_bh(&enic->rfs_h.lock); + cmd->rule_cnt = enic->rfs_h.max - enic->rfs_h.free; + cmd->data = enic->rfs_h.max; + spin_unlock_bh(&enic->rfs_h.lock); + break; + case ETHTOOL_GRXCLSRLALL: + spin_lock_bh(&enic->rfs_h.lock); + ret = enic_grxclsrlall(enic, cmd, rule_locs); + spin_unlock_bh(&enic->rfs_h.lock); + break; + case ETHTOOL_GRXCLSRULE: + spin_lock_bh(&enic->rfs_h.lock); + ret = enic_grxclsrule(enic, cmd); + spin_unlock_bh(&enic->rfs_h.lock); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + static const struct ethtool_ops enic_ethtool_ops = { .get_settings = enic_get_settings, .get_drvinfo = enic_get_drvinfo, @@ -293,6 +390,7 @@ static const struct ethtool_ops enic_ethtool_ops = { .get_ethtool_stats = enic_get_ethtool_stats, .get_coalesce = enic_get_coalesce, .set_coalesce = enic_set_coalesce, + .get_rxnfc = enic_get_rxnfc, }; void enic_set_ethtool_ops(struct net_device *netdev) -- cgit v1.2.3 From 822dd8a85c27913da7b58e8fed947529c9965e55 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 21 Jul 2014 20:55:12 +0530 Subject: cxgb4: Add the MC1 registers to read in the interrupt handler Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 16 +++++++++++++--- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 3 +++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index eb5a278e8045..e76885236e9d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -1719,16 +1719,24 @@ static void mps_intr_handler(struct adapter *adapter) */ static void mem_intr_handler(struct adapter *adapter, int idx) { - static const char name[3][5] = { "EDC0", "EDC1", "MC" }; + static const char name[4][7] = { "EDC0", "EDC1", "MC/MC0", "MC1" }; unsigned int addr, cnt_addr, v; if (idx <= MEM_EDC1) { addr = EDC_REG(EDC_INT_CAUSE, idx); cnt_addr = EDC_REG(EDC_ECC_STATUS, idx); + } else if (idx == MEM_MC) { + if (is_t4(adapter->params.chip)) { + addr = MC_INT_CAUSE; + cnt_addr = MC_ECC_STATUS; + } else { + addr = MC_P_INT_CAUSE; + cnt_addr = MC_P_ECC_STATUS; + } } else { - addr = MC_INT_CAUSE; - cnt_addr = MC_ECC_STATUS; + addr = MC_REG(MC_P_INT_CAUSE, 1); + cnt_addr = MC_REG(MC_P_ECC_STATUS, 1); } v = t4_read_reg(adapter, addr) & MEM_INT_MASK; @@ -1892,6 +1900,8 @@ int t4_slow_intr_handler(struct adapter *adapter) pcie_intr_handler(adapter); if (cause & MC) mem_intr_handler(adapter, MEM_MC); + if (!is_t4(adapter->params.chip) && (cause & MC1)) + mem_intr_handler(adapter, MEM_MC1); if (cause & EDC0) mem_intr_handler(adapter, MEM_EDC0); if (cause & EDC1) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 3b244abbf907..e3146e83df20 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -448,11 +448,13 @@ #define TDUE 0x00010000U #define MC_INT_CAUSE 0x7518 +#define MC_P_INT_CAUSE 0x41318 #define ECC_UE_INT_CAUSE 0x00000004U #define ECC_CE_INT_CAUSE 0x00000002U #define PERR_INT_CAUSE 0x00000001U #define MC_ECC_STATUS 0x751c +#define MC_P_ECC_STATUS 0x4131c #define ECC_CECNT_MASK 0xffff0000U #define ECC_CECNT_SHIFT 16 #define ECC_CECNT(x) ((x) << ECC_CECNT_SHIFT) @@ -1101,6 +1103,7 @@ #define I2CM 0x00000002U #define CIM 0x00000001U +#define MC1 0x31 #define PL_INT_ENABLE 0x19410 #define PL_INT_MAP0 0x19414 #define PL_RST 0x19428 -- cgit v1.2.3 From dd92b12453b34850912ccdeefa740a2c96f870c2 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 21 Jul 2014 20:55:13 +0530 Subject: iw_cxgb4: log detailed warnings for negative advice Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/cm.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index df5bd3df08a2..6d61a16d1f5c 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -1813,6 +1813,20 @@ static int is_neg_adv(unsigned int status) status == CPL_ERR_KEEPALV_NEG_ADVICE; } +static char *neg_adv_str(unsigned int status) +{ + switch (status) { + case CPL_ERR_RTX_NEG_ADVICE: + return "Retransmit timeout"; + case CPL_ERR_PERSIST_NEG_ADVICE: + return "Persist timeout"; + case CPL_ERR_KEEPALV_NEG_ADVICE: + return "Keepalive timeout"; + default: + return "Unknown"; + } +} + static void set_tcp_window(struct c4iw_ep *ep, struct port_info *pi) { ep->snd_win = snd_win; @@ -2011,8 +2025,9 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) status, status2errno(status)); if (is_neg_adv(status)) { - printk(KERN_WARNING MOD "Connection problems for atid %u\n", - atid); + dev_warn(&dev->rdev.lldi.pdev->dev, + "Connection problems for atid %u status %u (%s)\n", + atid, status, neg_adv_str(status)); return 0; } @@ -2488,8 +2503,9 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb) ep = lookup_tid(t, tid); if (is_neg_adv(req->status)) { - PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep, - ep->hwtid); + dev_warn(&dev->rdev.lldi.pdev->dev, + "Negative advice on abort - tid %u status %d (%s)\n", + ep->hwtid, req->status, neg_adv_str(req->status)); return 0; } PDBG("%s ep %p tid %u state %u\n", __func__, ep, ep->hwtid, @@ -3894,8 +3910,9 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb) return 0; } if (is_neg_adv(req->status)) { - PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep, - ep->hwtid); + dev_warn(&dev->rdev.lldi.pdev->dev, + "Negative advice on abort - tid %u status %d (%s)\n", + ep->hwtid, req->status, neg_adv_str(req->status)); kfree_skb(skb); return 0; } -- cgit v1.2.3 From 3e5c02c9ef9a86f39014156ddb8a9676a01f41a9 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 21 Jul 2014 20:55:14 +0530 Subject: iw_cxgb4: Support query_qp() verb Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/qp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index fd66bd9a9db0..0e7e0e30fba4 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -1856,5 +1856,11 @@ int c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, memset(attr, 0, sizeof *attr); memset(init_attr, 0, sizeof *init_attr); attr->qp_state = to_ib_qp_state(qhp->attr.state); + init_attr->cap.max_send_wr = qhp->attr.sq_num_entries; + init_attr->cap.max_recv_wr = qhp->attr.rq_num_entries; + init_attr->cap.max_send_sge = qhp->attr.sq_max_sges; + init_attr->cap.max_recv_sge = qhp->attr.sq_max_sges; + init_attr->cap.max_inline_data = T4_MAX_SEND_INLINE; + init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : 0; return 0; } -- cgit v1.2.3 From 66eb19af0b459426a1f6ba3f78235ffecd1bc5ab Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 21 Jul 2014 20:55:15 +0530 Subject: iw_cxgb4: advertise the correct device max attributes Advertise the actual max limits for things like qp depths, number of qps, cqs, etc. Clean up the queue allocation for qps and cqs. Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/cq.c | 8 +------- drivers/infiniband/hw/cxgb4/device.c | 16 ++++++++-------- drivers/infiniband/hw/cxgb4/provider.c | 4 ++-- drivers/infiniband/hw/cxgb4/qp.c | 35 ++++++++++++++++++++-------------- drivers/infiniband/hw/cxgb4/t4.h | 2 -- 5 files changed, 32 insertions(+), 33 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index de9bcf2e6d30..0f773e78e080 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -913,14 +913,8 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries, /* * memsize must be a multiple of the page size if its a user cq. */ - if (ucontext) { + if (ucontext) memsize = roundup(memsize, PAGE_SIZE); - hwentries = memsize / sizeof *chp->cq.queue; - while (hwentries > rhp->rdev.hw_queue.t4_max_iq_size) { - memsize -= PAGE_SIZE; - hwentries = memsize / sizeof *chp->cq.queue; - } - } chp->cq.size = hwentries; chp->cq.memsize = memsize; chp->cq.vector = vector; diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index 03b6fa1291bf..bda949223637 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -934,17 +934,17 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) devp->rdev.hw_queue.t4_eq_status_entries = devp->rdev.lldi.sge_ingpadboundary > 64 ? 2 : 1; - devp->rdev.hw_queue.t4_max_eq_size = - 65520 - devp->rdev.hw_queue.t4_eq_status_entries; - devp->rdev.hw_queue.t4_max_iq_size = 65520 - 1; - devp->rdev.hw_queue.t4_max_rq_size = - 8192 - devp->rdev.hw_queue.t4_eq_status_entries; + devp->rdev.hw_queue.t4_max_eq_size = 65520; + devp->rdev.hw_queue.t4_max_iq_size = 65520; + devp->rdev.hw_queue.t4_max_rq_size = 8192 - + devp->rdev.hw_queue.t4_eq_status_entries - 1; devp->rdev.hw_queue.t4_max_sq_size = - devp->rdev.hw_queue.t4_max_eq_size - 1; + devp->rdev.hw_queue.t4_max_eq_size - + devp->rdev.hw_queue.t4_eq_status_entries - 1; devp->rdev.hw_queue.t4_max_qp_depth = - devp->rdev.hw_queue.t4_max_rq_size - 1; + devp->rdev.hw_queue.t4_max_rq_size; devp->rdev.hw_queue.t4_max_cq_depth = - devp->rdev.hw_queue.t4_max_iq_size - 1; + devp->rdev.hw_queue.t4_max_iq_size - 2; devp->rdev.hw_queue.t4_stat_len = devp->rdev.lldi.sge_egrstatuspagesize; diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 67c4a6908021..72e3b69d1b76 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -318,7 +318,7 @@ static int c4iw_query_device(struct ib_device *ibdev, props->vendor_id = (u32)dev->rdev.lldi.pdev->vendor; props->vendor_part_id = (u32)dev->rdev.lldi.pdev->device; props->max_mr_size = T4_MAX_MR_SIZE; - props->max_qp = T4_MAX_NUM_QP; + props->max_qp = dev->rdev.lldi.vr->qp.size / 2; props->max_qp_wr = dev->rdev.hw_queue.t4_max_qp_depth; props->max_sge = T4_MAX_RECV_SGE; props->max_sge_rd = 1; @@ -326,7 +326,7 @@ static int c4iw_query_device(struct ib_device *ibdev, props->max_qp_rd_atom = min(dev->rdev.lldi.max_ordird_qp, c4iw_max_read_depth); props->max_qp_init_rd_atom = props->max_qp_rd_atom; - props->max_cq = T4_MAX_NUM_CQ; + props->max_cq = dev->rdev.lldi.vr->qp.size; props->max_cqe = dev->rdev.hw_queue.t4_max_cq_depth; props->max_mr = c4iw_num_stags(&dev->rdev); props->max_pd = T4_MAX_NUM_PD; diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 0e7e0e30fba4..c158fcc02bca 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -205,9 +205,9 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, } /* - * RQT must be a power of 2. + * RQT must be a power of 2 and at least 16 deep. */ - wq->rq.rqt_size = roundup_pow_of_two(wq->rq.size); + wq->rq.rqt_size = roundup_pow_of_two(max_t(u16, wq->rq.size, 16)); wq->rq.rqt_hwaddr = c4iw_rqtpool_alloc(rdev, wq->rq.rqt_size); if (!wq->rq.rqt_hwaddr) { ret = -ENOMEM; @@ -1621,13 +1621,17 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, if (attrs->cap.max_inline_data > T4_MAX_SEND_INLINE) return ERR_PTR(-EINVAL); - rqsize = roundup(attrs->cap.max_recv_wr + 1, 16); - if (rqsize > rhp->rdev.hw_queue.t4_max_rq_size) + if (attrs->cap.max_recv_wr > rhp->rdev.hw_queue.t4_max_rq_size) return ERR_PTR(-E2BIG); + rqsize = attrs->cap.max_recv_wr + 1; + if (rqsize < 8) + rqsize = 8; - sqsize = roundup(attrs->cap.max_send_wr + 1, 16); - if (sqsize > rhp->rdev.hw_queue.t4_max_sq_size) + if (attrs->cap.max_send_wr > rhp->rdev.hw_queue.t4_max_sq_size) return ERR_PTR(-E2BIG); + sqsize = attrs->cap.max_send_wr + 1; + if (sqsize < 8) + sqsize = 8; ucontext = pd->uobject ? to_c4iw_ucontext(pd->uobject->context) : NULL; @@ -1635,19 +1639,20 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, if (!qhp) return ERR_PTR(-ENOMEM); qhp->wq.sq.size = sqsize; - qhp->wq.sq.memsize = (sqsize + 1) * sizeof *qhp->wq.sq.queue; + qhp->wq.sq.memsize = + (sqsize + rhp->rdev.hw_queue.t4_eq_status_entries) * + sizeof(*qhp->wq.sq.queue) + 16 * sizeof(__be64); qhp->wq.sq.flush_cidx = -1; qhp->wq.rq.size = rqsize; - qhp->wq.rq.memsize = (rqsize + 1) * sizeof *qhp->wq.rq.queue; + qhp->wq.rq.memsize = + (rqsize + rhp->rdev.hw_queue.t4_eq_status_entries) * + sizeof(*qhp->wq.rq.queue); if (ucontext) { qhp->wq.sq.memsize = roundup(qhp->wq.sq.memsize, PAGE_SIZE); qhp->wq.rq.memsize = roundup(qhp->wq.rq.memsize, PAGE_SIZE); } - PDBG("%s sqsize %u sqmemsize %zu rqsize %u rqmemsize %zu\n", - __func__, sqsize, qhp->wq.sq.memsize, rqsize, qhp->wq.rq.memsize); - ret = create_qp(&rhp->rdev, &qhp->wq, &schp->cq, &rchp->cq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx); if (ret) @@ -1766,9 +1771,11 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, qhp->ibqp.qp_num = qhp->wq.sq.qid; init_timer(&(qhp->timer)); INIT_LIST_HEAD(&qhp->db_fc_entry); - PDBG("%s qhp %p sq_num_entries %d, rq_num_entries %d qpid 0x%0x\n", - __func__, qhp, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries, - qhp->wq.sq.qid); + PDBG("%s sq id %u size %u memsize %zu num_entries %u " + "rq id %u size %u memsize %zu num_entries %u\n", __func__, + qhp->wq.sq.qid, qhp->wq.sq.size, qhp->wq.sq.memsize, + attrs->cap.max_send_wr, qhp->wq.rq.qid, qhp->wq.rq.size, + qhp->wq.rq.memsize, attrs->cap.max_recv_wr); return &qhp->ibqp; err8: kfree(mm5); diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index c9f7034e6647..641ab55b1d55 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -36,8 +36,6 @@ #include "t4_msg.h" #include "t4fw_ri_api.h" -#define T4_MAX_NUM_QP 65536 -#define T4_MAX_NUM_CQ 65536 #define T4_MAX_NUM_PD 65536 #define T4_MAX_NUM_STAG (1<<15) #define T4_MAX_MR_SIZE (~0ULL) -- cgit v1.2.3 From 91244bbd6b383621fd6833cb1d9409c4ab6caecf Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 21 Jul 2014 20:55:16 +0530 Subject: iw_cxgb4: Don't limit TPTE count to 32KB Use the size advertised by FW Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 2 +- drivers/infiniband/hw/cxgb4/t4.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 69f047cdba6a..c378fd25ee0c 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -193,7 +193,7 @@ static inline int c4iw_fatal_error(struct c4iw_rdev *rdev) static inline int c4iw_num_stags(struct c4iw_rdev *rdev) { - return min((int)T4_MAX_NUM_STAG, (int)(rdev->lldi.vr->stag.size >> 5)); + return (int)(rdev->lldi.vr->stag.size >> 5); } #define C4IW_WR_TO (30*HZ) diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index 641ab55b1d55..df5edfa31a8f 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -37,7 +37,6 @@ #include "t4fw_ri_api.h" #define T4_MAX_NUM_PD 65536 -#define T4_MAX_NUM_STAG (1<<15) #define T4_MAX_MR_SIZE (~0ULL) #define T4_PAGESIZE_MASK 0xffff000 /* 4KB-128MB */ #define T4_STAG_UNSET 0xffffffff -- cgit v1.2.3 From 85f5b3086a04c459f9147859fcbf7bdc7578c378 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 27 Jun 2014 13:36:11 +0200 Subject: netfilter: bridge: add reject support So you can reject IPv4 and IPv6 packets from bridge tables. If the ether proto is now known, default on dropping the packet instead. Signed-off-by: Pablo Neira Ayuso --- net/bridge/netfilter/Kconfig | 6 +++ net/bridge/netfilter/Makefile | 1 + net/bridge/netfilter/nft_reject_bridge.c | 67 ++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 net/bridge/netfilter/nft_reject_bridge.c diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig index 4ce0b313f72c..9cebf47ac840 100644 --- a/net/bridge/netfilter/Kconfig +++ b/net/bridge/netfilter/Kconfig @@ -14,6 +14,12 @@ config NFT_BRIDGE_META help Add support for bridge dedicated meta key. +config NFT_BRIDGE_REJECT + tristate "Netfilter nf_tables bridge reject support" + depends on NFT_REJECT && NFT_REJECT_IPV4 && NFT_REJECT_IPV6 + help + Add support to reject packets. + config NF_LOG_BRIDGE tristate "Bridge packet logging" diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile index 1f78ea0d90e4..061d121cf8b9 100644 --- a/net/bridge/netfilter/Makefile +++ b/net/bridge/netfilter/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_NF_TABLES_BRIDGE) += nf_tables_bridge.o obj-$(CONFIG_NFT_BRIDGE_META) += nft_meta_bridge.o +obj-$(CONFIG_NFT_BRIDGE_REJECT) += nft_reject_bridge.o # packet logging obj-$(CONFIG_NF_LOG_BRIDGE) += nf_log_bridge.o diff --git a/net/bridge/netfilter/nft_reject_bridge.c b/net/bridge/netfilter/nft_reject_bridge.c new file mode 100644 index 000000000000..ee3ffe93e14e --- /dev/null +++ b/net/bridge/netfilter/nft_reject_bridge.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014 Pablo Neira Ayuso + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static void nft_reject_bridge_eval(const struct nft_expr *expr, + struct nft_data data[NFT_REG_MAX + 1], + const struct nft_pktinfo *pkt) +{ + switch (eth_hdr(pkt->skb)->h_proto) { + case htons(ETH_P_IP): + return nft_reject_ipv4_eval(expr, data, pkt); + case htons(ETH_P_IPV6): + return nft_reject_ipv6_eval(expr, data, pkt); + default: + /* No explicit way to reject this protocol, drop it. */ + data[NFT_REG_VERDICT].verdict = NF_DROP; + break; + } +} + +static struct nft_expr_type nft_reject_bridge_type; +static const struct nft_expr_ops nft_reject_bridge_ops = { + .type = &nft_reject_bridge_type, + .size = NFT_EXPR_SIZE(sizeof(struct nft_reject)), + .eval = nft_reject_bridge_eval, + .init = nft_reject_init, + .dump = nft_reject_dump, +}; + +static struct nft_expr_type nft_reject_bridge_type __read_mostly = { + .family = NFPROTO_BRIDGE, + .name = "reject", + .ops = &nft_reject_bridge_ops, + .policy = nft_reject_policy, + .maxattr = NFTA_REJECT_MAX, + .owner = THIS_MODULE, +}; + +static int __init nft_reject_bridge_module_init(void) +{ + return nft_register_expr(&nft_reject_bridge_type); +} + +static void __exit nft_reject_bridge_module_exit(void) +{ + nft_unregister_expr(&nft_reject_bridge_type); +} + +module_init(nft_reject_bridge_module_init); +module_exit(nft_reject_bridge_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Pablo Neira Ayuso "); +MODULE_ALIAS_NFT_AF_EXPR(AF_BRIDGE, "reject"); -- cgit v1.2.3 From 5b96af7713546fca812682fed13cfad26d69fed7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 16 Jul 2014 17:35:18 +0200 Subject: netfilter: nf_tables: simplify set dump through netlink This patch uses the cb->data pointer that allows us to store the context when dumping the set list. Thus, we don't need to parse the original netlink message containing the dump request for each recvmsg() call when dumping the set list. The different function flavours depending on the dump criteria has been also merged into one single generic function. This saves us ~100 lines of code. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 131 +++++++++--------------------------------- 1 file changed, 27 insertions(+), 104 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 8746ff9a8357..ecffb26e2f20 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -2247,80 +2247,7 @@ err: return err; } -static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb, - struct netlink_callback *cb) -{ - const struct nft_set *set; - unsigned int idx = 0, s_idx = cb->args[0]; - - if (cb->args[1]) - return skb->len; - - rcu_read_lock(); - cb->seq = ctx->net->nft.base_seq; - - list_for_each_entry_rcu(set, &ctx->table->sets, list) { - if (idx < s_idx) - goto cont; - if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET, - NLM_F_MULTI) < 0) { - cb->args[0] = idx; - goto done; - } - nl_dump_check_consistent(cb, nlmsg_hdr(skb)); -cont: - idx++; - } - cb->args[1] = 1; -done: - rcu_read_unlock(); - return skb->len; -} - -static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb, - struct netlink_callback *cb) -{ - const struct nft_set *set; - unsigned int idx, s_idx = cb->args[0]; - struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2]; - - if (cb->args[1]) - return skb->len; - - rcu_read_lock(); - cb->seq = ctx->net->nft.base_seq; - - list_for_each_entry_rcu(table, &ctx->afi->tables, list) { - if (cur_table) { - if (cur_table != table) - continue; - - cur_table = NULL; - } - ctx->table = table; - idx = 0; - list_for_each_entry_rcu(set, &ctx->table->sets, list) { - if (idx < s_idx) - goto cont; - if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET, - NLM_F_MULTI) < 0) { - cb->args[0] = idx; - cb->args[2] = (unsigned long) table; - goto done; - } - nl_dump_check_consistent(cb, nlmsg_hdr(skb)); -cont: - idx++; - } - } - cb->args[1] = 1; -done: - rcu_read_unlock(); - return skb->len; -} - -static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, - struct netlink_callback *cb) +static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb) { const struct nft_set *set; unsigned int idx, s_idx = cb->args[0]; @@ -2328,6 +2255,7 @@ static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2]; struct net *net = sock_net(skb->sk); int cur_family = cb->args[3]; + struct nft_ctx *ctx = cb->data, ctx_set; if (cb->args[1]) return skb->len; @@ -2336,28 +2264,34 @@ static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, cb->seq = net->nft.base_seq; list_for_each_entry_rcu(afi, &net->nft.af_info, list) { + if (ctx->afi && ctx->afi != afi) + continue; + if (cur_family) { if (afi->family != cur_family) continue; cur_family = 0; } - list_for_each_entry_rcu(table, &afi->tables, list) { + if (ctx->table && ctx->table != table) + continue; + if (cur_table) { if (cur_table != table) continue; cur_table = NULL; } - - ctx->table = table; - ctx->afi = afi; idx = 0; - list_for_each_entry_rcu(set, &ctx->table->sets, list) { + list_for_each_entry_rcu(set, &table->sets, list) { if (idx < s_idx) goto cont; - if (nf_tables_fill_set(skb, ctx, set, + + ctx_set = *ctx; + ctx_set.table = table; + ctx_set.afi = afi; + if (nf_tables_fill_set(skb, &ctx_set, set, NFT_MSG_NEWSET, NLM_F_MULTI) < 0) { cb->args[0] = idx; @@ -2379,31 +2313,10 @@ done: return skb->len; } -static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb) +static int nf_tables_dump_sets_done(struct netlink_callback *cb) { - const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); - struct nlattr *nla[NFTA_SET_MAX + 1]; - struct nft_ctx ctx; - int err, ret; - - err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_MAX, - nft_set_policy); - if (err < 0) - return err; - - err = nft_ctx_init_from_setattr(&ctx, cb->skb, cb->nlh, (void *)nla); - if (err < 0) - return err; - - if (ctx.table == NULL) { - if (ctx.afi == NULL) - ret = nf_tables_dump_sets_all(&ctx, skb, cb); - else - ret = nf_tables_dump_sets_family(&ctx, skb, cb); - } else - ret = nf_tables_dump_sets_table(&ctx, skb, cb); - - return ret; + kfree(cb->data); + return 0; } #define NFT_SET_INACTIVE (1 << 15) /* Internal set flag */ @@ -2426,7 +2339,17 @@ static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb, if (nlh->nlmsg_flags & NLM_F_DUMP) { struct netlink_dump_control c = { .dump = nf_tables_dump_sets, + .done = nf_tables_dump_sets_done, }; + struct nft_ctx *ctx_dump; + + ctx_dump = kmalloc(sizeof(*ctx_dump), GFP_KERNEL); + if (ctx_dump == NULL) + return -ENOMEM; + + *ctx_dump = ctx; + c.data = ctx_dump; + return netlink_dump_start(nlsk, skb, nlh, &c); } -- cgit v1.2.3 From 32333edb82fb2009980eefc5518100068147ab82 Mon Sep 17 00:00:00 2001 From: Vignesh Raman Date: Tue, 22 Jul 2014 19:24:25 +0530 Subject: Bluetooth: Avoid use of session socket after the session gets freed The commits 08c30aca9e698faddebd34f81e1196295f9dc063 "Bluetooth: Remove RFCOMM session refcnt" and 8ff52f7d04d9cc31f1e81dcf9a2ba6335ed34905 "Bluetooth: Return RFCOMM session ptrs to avoid freed session" allow rfcomm_recv_ua and rfcomm_session_close to delete the session (and free the corresponding socket) and propagate NULL session pointer to the upper callers. Additional fix is required to terminate the loop in rfcomm_process_rx function to avoid use of freed 'sk' memory. The issue is only reproducible with kernel option CONFIG_PAGE_POISONING enabled making freed memory being changed and filled up with fixed char value used to unmask use-after-free issues. Signed-off-by: Vignesh Raman Signed-off-by: Vitaly Kuzmichev Acked-by: Dean Jenkins Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org --- net/bluetooth/rfcomm/core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index a0690a84f3e9..af73bc3acb40 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1910,10 +1910,13 @@ static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s) /* Get data directly from socket receive queue without copying it. */ while ((skb = skb_dequeue(&sk->sk_receive_queue))) { skb_orphan(skb); - if (!skb_linearize(skb)) + if (!skb_linearize(skb)) { s = rfcomm_recv_frame(s, skb); - else + if (!s) + break; + } else { kfree_skb(skb); + } } if (s && (sk->sk_state == BT_CLOSED)) -- cgit v1.2.3 From 4b6045586f31c7cc49b641a7ad5298b0c379a1c7 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 21 Jul 2014 21:03:09 +0300 Subject: ath10k: simplify tx helpers It always bugged me how tid is computed and stored in a temporary var before written to the control buffer. It was confusing and it made it difficult to work with tx helpers. While at it rename the qos workaround function as it was misleading - it's not a workaround but preparation for nwifi tx mode. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 49 ++++++++++++++--------------------- drivers/net/wireless/ath/ath10k/mac.h | 4 +-- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 3 files changed, 23 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b8314a534972..bbce3a0f8a39 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1865,13 +1865,10 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, return 0; } -/* - * Frames sent to the FW have to be in "Native Wifi" format. - * Strip the QoS field from the 802.11 header. +/* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS + * Control in the header. */ -static void ath10k_tx_h_qos_workaround(struct ieee80211_hw *hw, - struct ieee80211_tx_control *control, - struct sk_buff *skb) +static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (void *)skb->data; u8 *qos_ctl; @@ -1919,14 +1916,13 @@ unlock: mutex_unlock(&arvif->ar->conf_mutex); } -static void ath10k_tx_h_update_wep_key(struct sk_buff *skb) +static void ath10k_tx_h_update_wep_key(struct ieee80211_vif *vif, + struct ieee80211_key_conf *key, + struct sk_buff *skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_vif *vif = info->control.vif; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k *ar = arvif->ar; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_key_conf *key = info->control.hw_key; if (!ieee80211_has_protected(hdr->frame_control)) return; @@ -1948,11 +1944,11 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb) ieee80211_queue_work(ar->hw, &arvif->wep_key_work); } -static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb) +static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, + struct ieee80211_vif *vif, + struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_vif *vif = info->control.vif; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); /* This is case only for P2P_GO */ @@ -2254,33 +2250,28 @@ static void ath10k_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { + struct ath10k *ar = hw->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ath10k *ar = hw->priv; - u8 tid, vdev_id; /* We should disable CCK RATE due to P2P */ if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE) ath10k_dbg(ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n"); - /* we must calculate tid before we apply qos workaround - * as we'd lose the qos control field */ - tid = ath10k_tx_h_get_tid(hdr); - vdev_id = ath10k_tx_h_get_vdev_id(ar, info); + ATH10K_SKB_CB(skb)->htt.is_offchan = false; + ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr); + ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, info); /* it makes no sense to process injected frames like that */ - if (info->control.vif && - info->control.vif->type != NL80211_IFTYPE_MONITOR) { - ath10k_tx_h_qos_workaround(hw, control, skb); - ath10k_tx_h_update_wep_key(skb); - ath10k_tx_h_add_p2p_noa_ie(ar, skb); - ath10k_tx_h_seq_no(skb); + if (vif && vif->type != NL80211_IFTYPE_MONITOR) { + ath10k_tx_h_nwifi(hw, skb); + ath10k_tx_h_update_wep_key(vif, key, skb); + ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb); + ath10k_tx_h_seq_no(vif, skb); } - ATH10K_SKB_CB(skb)->vdev_id = vdev_id; - ATH10K_SKB_CB(skb)->htt.is_offchan = false; - ATH10K_SKB_CB(skb)->htt.tid = tid; - if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { spin_lock_bh(&ar->data_lock); ATH10K_SKB_CB(skb)->htt.is_offchan = true; diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index ba1021997b8f..ef4f84376d7c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -43,11 +43,11 @@ static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) return (struct ath10k_vif *)vif->drv_priv; } -static inline void ath10k_tx_h_seq_no(struct sk_buff *skb) +static inline void ath10k_tx_h_seq_no(struct ieee80211_vif *vif, + struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_vif *vif = info->control.vif; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6f83cae57655..c2c87c916b5a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1432,7 +1432,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) continue; } - ath10k_tx_h_seq_no(bcn); + ath10k_tx_h_seq_no(arvif->vif, bcn); ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info); ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); -- cgit v1.2.3 From c21c64d145e64d92a6c8f8e13c9b6b5b711832eb Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 21 Jul 2014 21:03:10 +0300 Subject: ath10k: workaround qos nullfunc bug Apparently fw/hw generates a corrupted QoS Control Field in Qos NullFunc frames. The only way to workaround this is to downgrade frames to NullFunc. This should be okay since powersave is done by fw/hw and these frames are only used for CQM purposes (e.g. from hostapd to check if station is still connected). This doesn't fix any user visible bug that I know of. It just prevents from sending out funky frames on the air. Reported-by: Janusz Dziedzic Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index bbce3a0f8a39..3f9afaa93cca 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1871,6 +1871,7 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (void *)skb->data; + struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb); u8 *qos_ctl; if (!ieee80211_is_data_qos(hdr->frame_control)) @@ -1880,6 +1881,16 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb) memmove(skb->data + IEEE80211_QOS_CTL_LEN, skb->data, (void *)qos_ctl - (void *)skb->data); skb_pull(skb, IEEE80211_QOS_CTL_LEN); + + /* Fw/Hw generates a corrupted QoS Control Field for QoS NullFunc + * frames. Powersave is handled by the fw/hw so QoS NyllFunc frames are + * used only for CQM purposes (e.g. hostapd station keepalive ping) so + * it is safe to downgrade to NullFunc. + */ + if (ieee80211_is_qos_nullfunc(hdr->frame_control)) { + hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA); + cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; + } } static void ath10k_tx_wep_key_work(struct work_struct *work) -- cgit v1.2.3 From b112889c5af8124e2b6d884d00859fc172c6748a Mon Sep 17 00:00:00 2001 From: Ariej Marjieh Date: Wed, 16 Jul 2014 21:11:12 +0300 Subject: iwlwifi: mvm: add Aux ROC request/response flow The Remain On Channel framework added to the firmare is a bit like time events. It allows the driver to request the firmware to be on a certain channel for a certain time. Unlike the time events, the ROC infrastructure doesn't need a MAC context in the firmware - it uses a generic context called "auxiliary framework". This is useful for any offchannel activity that is not bound to a specific MAC. The flow is synchronized much like with time events: 1) The driver receives an action frame from the wpa_supplicant via nl80211 that requests to be sent offchannel. 2) The driver sends an Aux ROC command (0x53) to the firmware. 3) The firmware responds with the unique id of the time event. 4) When time event starts, the driver puts the frame in the Aux queue. Special care needs to be taken when the time events ends: the queue needs to be cleaned-up. Signed-off-by: Ariej Marjieh Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 126 +++++++++++++++++++++++++- drivers/net/wireless/iwlwifi/mvm/mvm.h | 7 ++ drivers/net/wireless/iwlwifi/mvm/ops.c | 2 + drivers/net/wireless/iwlwifi/mvm/time-event.c | 89 +++++++++++++++--- 4 files changed, 208 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 12a9aed7a5d3..5219b3a5689d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2310,6 +2310,119 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw, } +static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt, void *data) +{ + struct iwl_mvm *mvm = + container_of(notif_wait, struct iwl_mvm, notif_wait); + struct iwl_hs20_roc_res *resp; + int resp_len = iwl_rx_packet_payload_len(pkt); + struct iwl_mvm_time_event_data *te_data = data; + + if (WARN_ON(pkt->hdr.cmd != HOT_SPOT_CMD)) + return true; + + if (WARN_ON_ONCE(resp_len != sizeof(*resp))) { + IWL_ERR(mvm, "Invalid HOT_SPOT_CMD response\n"); + return true; + } + + resp = (void *)pkt->data; + + IWL_DEBUG_TE(mvm, + "Aux ROC: Recieved response from ucode: status=%d uid=%d\n", + resp->status, resp->event_unique_id); + + te_data->uid = le32_to_cpu(resp->event_unique_id); + IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n", + te_data->uid); + + spin_lock_bh(&mvm->time_event_lock); + list_add_tail(&te_data->list, &mvm->aux_roc_te_list); + spin_unlock_bh(&mvm->time_event_lock); + + return true; +} + +#define AUX_ROC_MAX_DELAY_ON_CHANNEL 5000 +static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, + struct ieee80211_channel *channel, + struct ieee80211_vif *vif, + int duration) +{ + int res, time_reg = DEVICE_SYSTEM_TIME_REG; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_time_event_data *te_data = &mvmvif->hs_time_event_data; + static const u8 time_event_response[] = { HOT_SPOT_CMD }; + struct iwl_notification_wait wait_time_event; + struct iwl_hs20_roc_req aux_roc_req = { + .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .id_and_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(MAC_INDEX_AUX, 0)), + .sta_id_and_color = cpu_to_le32(mvm->aux_sta.sta_id), + /* Set the channel info data */ + .channel_info.band = (channel->band == IEEE80211_BAND_2GHZ) ? + PHY_BAND_24 : PHY_BAND_5, + .channel_info.channel = channel->hw_value, + .channel_info.width = PHY_VHT_CHANNEL_MODE20, + /* Set the time and duration */ + .apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, time_reg)), + .apply_time_max_delay = + cpu_to_le32(MSEC_TO_TU(AUX_ROC_MAX_DELAY_ON_CHANNEL)), + .duration = cpu_to_le32(MSEC_TO_TU(duration)), + }; + + /* Set the node address */ + memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN); + + te_data->vif = vif; + te_data->duration = duration; + te_data->id = HOT_SPOT_CMD; + + lockdep_assert_held(&mvm->mutex); + + spin_lock_bh(&mvm->time_event_lock); + list_add_tail(&te_data->list, &mvm->time_event_list); + spin_unlock_bh(&mvm->time_event_lock); + + /* + * Use a notification wait, which really just processes the + * command response and doesn't wait for anything, in order + * to be able to process the response and get the UID inside + * the RX path. Using CMD_WANT_SKB doesn't work because it + * stores the buffer and then wakes up this thread, by which + * time another notification (that the time event started) + * might already be processed unsuccessfully. + */ + iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, + time_event_response, + ARRAY_SIZE(time_event_response), + iwl_mvm_rx_aux_roc, te_data); + + res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, sizeof(aux_roc_req), + &aux_roc_req); + + if (res) { + IWL_ERR(mvm, "Couldn't send HOT_SPOT_CMD: %d\n", res); + iwl_remove_notification(&mvm->notif_wait, &wait_time_event); + goto out_clear_te; + } + + /* No need to wait for anything, so just pass 1 (0 isn't valid) */ + res = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1); + /* should never fail */ + WARN_ON_ONCE(res); + + if (res) { + out_clear_te: + spin_lock_bh(&mvm->time_event_lock); + iwl_mvm_te_clear_data(mvm, te_data); + spin_unlock_bh(&mvm->time_event_lock); + } + + return res; +} + static int iwl_mvm_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *channel, @@ -2325,8 +2438,17 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, duration, type); - if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { - IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type); + switch (vif->type) { + case NL80211_IFTYPE_STATION: + /* Use aux roc framework (HS20) */ + ret = iwl_mvm_send_aux_roc_cmd(mvm, channel, + vif, duration); + return ret; + case NL80211_IFTYPE_P2P_DEVICE: + /* handle below */ + break; + default: + IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type); return -EINVAL; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 24c12c77d93a..2cead5d44309 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -82,6 +82,8 @@ /* RSSI offset for WkP */ #define IWL_RSSI_OFFSET 50 #define IWL_MVM_MISSED_BEACONS_THRESHOLD 8 +/* A TimeUnit is 1024 microsecond */ +#define MSEC_TO_TU(_msec) (_msec*1000/1024) /* * The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0" @@ -336,6 +338,7 @@ struct iwl_mvm_vif { */ struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; struct iwl_mvm_time_event_data time_event_data; + struct iwl_mvm_time_event_data hs_time_event_data; struct iwl_mvm_int_sta bcast_sta; @@ -669,6 +672,9 @@ struct iwl_mvm { u8 bt_tx_prio; enum iwl_bt_force_ant_mode bt_force_ant_mode; + /* Aux ROC */ + struct list_head aux_roc_te_list; + /* Thermal Throttling and CTkill */ struct iwl_mvm_tt_mgmt thermal_throttle; s32 temperature; /* Celsius */ @@ -707,6 +713,7 @@ enum iwl_mvm_status { IWL_MVM_STATUS_ROC_RUNNING, IWL_MVM_STATUS_IN_HW_RESTART, IWL_MVM_STATUS_IN_D0I3, + IWL_MVM_STATUS_ROC_AUX_RUNNING, }; static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 19a66b590277..904228aa64c4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -289,6 +289,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(MATCH_FOUND_NOTIFICATION), CMD(SCAN_OFFLOAD_REQUEST_CMD), CMD(SCAN_OFFLOAD_ABORT_CMD), + CMD(HOT_SPOT_CMD), CMD(SCAN_OFFLOAD_COMPLETE), CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), CMD(SCAN_ITERATION_COMPLETE), @@ -419,6 +420,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mutex_init(&mvm->d0i3_suspend_mutex); spin_lock_init(&mvm->async_handlers_lock); INIT_LIST_HEAD(&mvm->time_event_list); + INIT_LIST_HEAD(&mvm->aux_roc_te_list); INIT_LIST_HEAD(&mvm->async_handlers_list); spin_lock_init(&mvm->time_event_lock); diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index ae52613b97f2..33e5041f1efc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -72,9 +72,6 @@ #include "iwl-io.h" #include "iwl-prph.h" -/* A TimeUnit is 1024 microsecond */ -#define MSEC_TO_TU(_msec) (_msec*1000/1024) - /* * For the high priority TE use a time event type that has similar priority to * the FW's action scan priority. @@ -100,6 +97,21 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, void iwl_mvm_roc_done_wk(struct work_struct *wk) { struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk); + u32 queues = 0; + + /* + * Clear the ROC_RUNNING /ROC_AUX_RUNNING status bit. + * This will cause the TX path to drop offchannel transmissions. + * That would also be done by mac80211, but it is racy, in particular + * in the case that the time event actually completed in the firmware + * (which is handled in iwl_mvm_te_handle_notif). + */ + if (test_and_clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) + queues |= BIT(IWL_MVM_OFFCHANNEL_QUEUE); + if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) + queues |= BIT(mvm->aux_queue); + + iwl_mvm_unref(mvm, IWL_MVM_REF_ROC); synchronize_net(); @@ -113,21 +125,11 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) * issue as it will have to complete before the next command is * executed, and a new time event means a new command. */ - iwl_mvm_flush_tx_path(mvm, BIT(IWL_MVM_OFFCHANNEL_QUEUE), false); + iwl_mvm_flush_tx_path(mvm, queues, false); } static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) { - /* - * First, clear the ROC_RUNNING status bit. This will cause the TX - * path to drop offchannel transmissions. That would also be done - * by mac80211, but it is racy, in particular in the case that the - * time event actually completed in the firmware (which is handled - * in iwl_mvm_te_handle_notif). - */ - clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); - iwl_mvm_unref(mvm, IWL_MVM_REF_ROC); - /* * Of course, our status bit is just as racy as mac80211, so in * addition, fire off the work struct which will drop all frames @@ -262,6 +264,60 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, } } +/* + * Handle A Aux ROC time event + */ +static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm, + struct iwl_time_event_notif *notif) +{ + struct iwl_mvm_time_event_data *te_data, *tmp; + bool aux_roc_te = false; + + list_for_each_entry_safe(te_data, tmp, &mvm->aux_roc_te_list, list) { + if (le32_to_cpu(notif->unique_id) == te_data->uid) { + aux_roc_te = true; + break; + } + } + if (!aux_roc_te) /* Not a Aux ROC time event */ + return -EINVAL; + + if (!le32_to_cpu(notif->status)) { + IWL_DEBUG_TE(mvm, + "ERROR: Aux ROC Time Event %s notification failure\n", + (le32_to_cpu(notif->action) & + TE_V2_NOTIF_HOST_EVENT_START) ? "start" : "end"); + return -EINVAL; + } + + IWL_DEBUG_TE(mvm, + "Aux ROC time event notification - UID = 0x%x action %d\n", + le32_to_cpu(notif->unique_id), + le32_to_cpu(notif->action)); + + if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_END) { + /* End TE, notify mac80211 */ + ieee80211_remain_on_channel_expired(mvm->hw); + iwl_mvm_roc_finished(mvm); /* flush aux queue */ + list_del(&te_data->list); /* remove from list */ + te_data->running = false; + te_data->vif = NULL; + te_data->uid = 0; + } else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) { + set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); + set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status); + te_data->running = true; + ieee80211_ready_on_channel(mvm->hw); /* Start TE */ + } else { + IWL_DEBUG_TE(mvm, + "ERROR: Unknown Aux ROC Time Event (action = %d)\n", + le32_to_cpu(notif->action)); + return -EINVAL; + } + + return 0; +} + /* * The Rx handler for time event notifications */ @@ -278,10 +334,15 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, le32_to_cpu(notif->action)); spin_lock_bh(&mvm->time_event_lock); + /* This time event is triggered for Aux ROC request */ + if (!iwl_mvm_aux_roc_te_handle_notif(mvm, notif)) + goto unlock; + list_for_each_entry_safe(te_data, tmp, &mvm->time_event_list, list) { if (le32_to_cpu(notif->unique_id) == te_data->uid) iwl_mvm_te_handle_notif(mvm, te_data, notif); } +unlock: spin_unlock_bh(&mvm->time_event_lock); return 0; -- cgit v1.2.3 From 1459f269e836834494e944ea7687177932568d00 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 6 Jul 2014 09:34:38 +0300 Subject: iwlwifi: mvm: BT Coex - fix the ACK / CTS kill mask According to new requirements, the ACK / CTS kill mask is not related to reduced TX power anymore. This allows to remove the code that tracked reduced TX power enablement across different interfaces. The ACK / CTS kill mask is now fetch from a table. It depends on the Activity grading (activity from BT) and on the Look Up Table (LUT) type. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 170 +++++++++++-------------- drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 102 +++------------ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 21 ++- drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | 2 + drivers/net/wireless/iwlwifi/mvm/mvm.h | 13 +- 5 files changed, 115 insertions(+), 193 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index e0a5cf29c38e..a65b1bb12b3d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -72,16 +72,56 @@ #define BT_ANTENNA_COUPLING_THRESHOLD (30) -const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = { - [BT_KILL_MSK_DEFAULT] = 0xffff0000, - [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, - [BT_KILL_MSK_REDUCED_TXPOW] = 0, +const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = { + [BT_KILL_MSK_DEFAULT] = 0xfffffc00, + [BT_KILL_MSK_NEVER] = 0xffffffff, + [BT_KILL_MSK_ALWAYS] = 0, }; -const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = { - [BT_KILL_MSK_DEFAULT] = 0xffff0000, - [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff, - [BT_KILL_MSK_REDUCED_TXPOW] = 0, +const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { + { + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + }, + { + BT_KILL_MSK_NEVER, + BT_KILL_MSK_NEVER, + BT_KILL_MSK_NEVER, + }, + { + BT_KILL_MSK_NEVER, + BT_KILL_MSK_NEVER, + BT_KILL_MSK_NEVER, + }, + { + BT_KILL_MSK_DEFAULT, + BT_KILL_MSK_NEVER, + BT_KILL_MSK_DEFAULT, + }, +}; + +const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { + { + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + }, + { + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + }, + { + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + }, + { + BT_KILL_MSK_DEFAULT, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_DEFAULT, + }, }; static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = { @@ -611,54 +651,43 @@ send_cmd: return ret; } -static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm, - bool reduced_tx_power) +static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm) { - enum iwl_bt_kill_msk bt_kill_msk; - struct iwl_bt_coex_sw_boost_update_cmd cmd = {}; struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; + u32 primary_lut = le32_to_cpu(notif->primary_ch_lut); + u32 secondary_lut = le32_to_cpu(notif->secondary_ch_lut); + u32 ag = le32_to_cpu(notif->bt_activity_grading); + struct iwl_bt_coex_sw_boost_update_cmd cmd = {}; + u8 ack_kill_msk[NUM_PHY_CTX] = {}; + u8 cts_kill_msk[NUM_PHY_CTX] = {}; + int i; lockdep_assert_held(&mvm->mutex); - if (reduced_tx_power) { - /* Reduced Tx power has precedence on the type of the profile */ - bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW; - } else { - /* Low latency BT profile is active: give higher prio to BT */ - if (BT_MBOX_MSG(notif, 3, SCO_STATE) || - BT_MBOX_MSG(notif, 3, A2DP_STATE) || - BT_MBOX_MSG(notif, 3, SNIFF_STATE)) - bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP; - else - bt_kill_msk = BT_KILL_MSK_DEFAULT; - } + ack_kill_msk[0] = iwl_bt_ack_kill_msk[ag][primary_lut]; + cts_kill_msk[0] = iwl_bt_cts_kill_msk[ag][primary_lut]; - IWL_DEBUG_COEX(mvm, - "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n", - bt_kill_msk, - BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in", - BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in", - BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in"); + ack_kill_msk[1] = iwl_bt_ack_kill_msk[ag][secondary_lut]; + cts_kill_msk[1] = iwl_bt_cts_kill_msk[ag][secondary_lut]; /* Don't send HCMD if there is no update */ - if (bt_kill_msk == mvm->bt_kill_msk) + if (!memcmp(ack_kill_msk, mvm->bt_ack_kill_msk, sizeof(ack_kill_msk)) || + !memcmp(cts_kill_msk, mvm->bt_cts_kill_msk, sizeof(cts_kill_msk))) return 0; - mvm->bt_kill_msk = bt_kill_msk; + memcpy(mvm->bt_ack_kill_msk, ack_kill_msk, + sizeof(mvm->bt_ack_kill_msk)); + memcpy(mvm->bt_cts_kill_msk, cts_kill_msk, + sizeof(mvm->bt_cts_kill_msk)); - cmd.boost_values[0].kill_ack_msk = - cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); - cmd.boost_values[0].kill_cts_msk = - cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); + BUILD_BUG_ON(ARRAY_SIZE(ack_kill_msk) < ARRAY_SIZE(cmd.boost_values)); - cmd.boost_values[1].kill_ack_msk = cmd.boost_values[0].kill_ack_msk; - cmd.boost_values[2].kill_cts_msk = cmd.boost_values[0].kill_cts_msk; - cmd.boost_values[1].kill_ack_msk = cmd.boost_values[0].kill_ack_msk; - cmd.boost_values[2].kill_cts_msk = cmd.boost_values[0].kill_cts_msk; - - IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n", - iwl_bt_ack_kill_msk[bt_kill_msk], - iwl_bt_cts_kill_msk[bt_kill_msk]); + for (i = 0; i < ARRAY_SIZE(cmd.boost_values); i++) { + cmd.boost_values[i].kill_ack_msk = + cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk[i]]); + cmd.boost_values[i].kill_cts_msk = + cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk[i]]); + } return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_SW_BOOST, 0, sizeof(cmd), &cmd); @@ -700,8 +729,6 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, struct iwl_bt_iterator_data { struct iwl_bt_coex_profile_notif *notif; struct iwl_mvm *mvm; - u32 num_bss_ifaces; - bool reduced_tx_power; struct ieee80211_chanctx_conf *primary; struct ieee80211_chanctx_conf *secondary; bool primary_ll; @@ -737,8 +764,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, switch (vif->type) { case NL80211_IFTYPE_STATION: - /* Count BSSes vifs */ - data->num_bss_ifaces++; /* default smps_mode for BSS / P2P client is AUTOMATIC */ smps_mode = IEEE80211_SMPS_AUTOMATIC; break; @@ -750,9 +775,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, smps_mode); return; } - - /* the Ack / Cts kill mask must be default if AP / GO */ - data->reduced_tx_power = false; break; default: return; @@ -766,7 +788,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, /* ... relax constraints and disable rssi events */ iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); - data->reduced_tx_power = false; if (vif->type == NL80211_IFTYPE_STATION) { iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); @@ -846,7 +867,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) { - data->reduced_tx_power = false; iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); return; @@ -861,23 +881,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) { if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); - - /* - * bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the - * BSS / P2P clients have rssi above threshold. - * We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before - * the iteration, if one interface's rssi isn't good enough, - * bt_kill_msk will be set to default values. - */ } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) { if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); - - /* - * One interface hasn't rssi above threshold, bt_kill_msk must - * be set to default values. - */ - data->reduced_tx_power = false; } /* Begin to monitor the RSSI: it may influence the reduced Tx power */ @@ -889,7 +895,6 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) struct iwl_bt_iterator_data data = { .mvm = mvm, .notif = &mvm->last_bt_notif, - .reduced_tx_power = true, }; struct iwl_bt_coex_ci_cmd cmd = {}; u8 ci_bw_idx; @@ -959,14 +964,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd)); } - /* - * If there are no BSS / P2P client interfaces, reduced Tx Power is - * irrelevant since it is based on the RSSI coming from the beacon. - * Use BT_KILL_MSK_DEFAULT in that case. - */ - data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; - - if (iwl_mvm_bt_udpate_sw_boost(mvm, data.reduced_tx_power)) + if (iwl_mvm_bt_udpate_sw_boost(mvm)) IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); } @@ -1035,16 +1033,6 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, return; mvmsta = iwl_mvm_sta_from_mac80211(sta); - - data->num_bss_ifaces++; - - /* - * This interface doesn't support reduced Tx power (because of low - * RSSI probably), then set bt_kill_msk to default values. - */ - if (!mvmsta->bt_reduced_txpower) - data->reduced_tx_power = false; - /* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */ } void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -1053,7 +1041,6 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; struct iwl_bt_iterator_data data = { .mvm = mvm, - .reduced_tx_power = true, }; int ret; @@ -1100,14 +1087,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_bt_rssi_iterator, &data); - /* - * If there are no BSS / P2P client interfaces, reduced Tx Power is - * irrelevant since it is based on the RSSI coming from the beacon. - * Use BT_KILL_MSK_DEFAULT in that case. - */ - data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; - - if (iwl_mvm_bt_udpate_sw_boost(mvm, data.reduced_tx_power)) + if (iwl_mvm_bt_udpate_sw_boost(mvm)) IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); } diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index ce50363d314b..9e3ba5a4103d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -649,10 +649,6 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) sizeof(iwl_bt_prio_boost)); memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, sizeof(iwl_bt_mprio_lut)); - bt_cmd->kill_ack_msk = - cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); - bt_cmd->kill_cts_msk = - cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); send_cmd: memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); @@ -664,12 +660,13 @@ send_cmd: return ret; } -static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, - bool reduced_tx_power) +static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm) { - enum iwl_bt_kill_msk bt_kill_msk; - struct iwl_bt_coex_cmd_old *bt_cmd; struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif_old; + u32 primary_lut = le32_to_cpu(notif->primary_ch_lut); + u32 ag = le32_to_cpu(notif->bt_activity_grading); + struct iwl_bt_coex_cmd_old *bt_cmd; + u8 ack_kill_msk, cts_kill_msk; struct iwl_host_cmd cmd = { .id = BT_CONFIG, .data[0] = &bt_cmd, @@ -680,31 +677,15 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - if (reduced_tx_power) { - /* Reduced Tx power has precedence on the type of the profile */ - bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW; - } else { - /* Low latency BT profile is active: give higher prio to BT */ - if (BT_MBOX_MSG(notif, 3, SCO_STATE) || - BT_MBOX_MSG(notif, 3, A2DP_STATE) || - BT_MBOX_MSG(notif, 3, SNIFF_STATE)) - bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP; - else - bt_kill_msk = BT_KILL_MSK_DEFAULT; - } + ack_kill_msk = iwl_bt_ack_kill_msk[ag][primary_lut]; + cts_kill_msk = iwl_bt_cts_kill_msk[ag][primary_lut]; - IWL_DEBUG_COEX(mvm, - "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n", - bt_kill_msk, - BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in", - BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in", - BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in"); - - /* Don't send HCMD if there is no update */ - if (bt_kill_msk == mvm->bt_kill_msk) + if (mvm->bt_ack_kill_msk[0] == ack_kill_msk && + mvm->bt_cts_kill_msk[0] == cts_kill_msk) return 0; - mvm->bt_kill_msk = bt_kill_msk; + mvm->bt_ack_kill_msk[0] = ack_kill_msk; + mvm->bt_cts_kill_msk[0] = cts_kill_msk; bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); if (!bt_cmd) @@ -712,16 +693,12 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, cmd.data[0] = bt_cmd; bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); - bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); - bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); + bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk]); + bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk]); bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE | BT_VALID_KILL_ACK | BT_VALID_KILL_CTS); - IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n", - iwl_bt_ack_kill_msk[bt_kill_msk], - iwl_bt_cts_kill_msk[bt_kill_msk]); - ret = iwl_mvm_send_cmd(mvm, &cmd); kfree(bt_cmd); @@ -777,8 +754,6 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, struct iwl_bt_iterator_data { struct iwl_bt_coex_profile_notif_old *notif; struct iwl_mvm *mvm; - u32 num_bss_ifaces; - bool reduced_tx_power; struct ieee80211_chanctx_conf *primary; struct ieee80211_chanctx_conf *secondary; bool primary_ll; @@ -814,8 +789,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, switch (vif->type) { case NL80211_IFTYPE_STATION: - /* Count BSSes vifs */ - data->num_bss_ifaces++; /* default smps_mode for BSS / P2P client is AUTOMATIC */ smps_mode = IEEE80211_SMPS_AUTOMATIC; break; @@ -827,9 +800,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, smps_mode); return; } - - /* the Ack / Cts kill mask must be default if AP / GO */ - data->reduced_tx_power = false; break; default: return; @@ -843,7 +813,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, /* ... relax constraints and disable rssi events */ iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); - data->reduced_tx_power = false; if (vif->type == NL80211_IFTYPE_STATION) { iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); @@ -920,7 +889,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || !data->notif->bt_status) { - data->reduced_tx_power = false; iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); return; @@ -935,23 +903,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) { if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); - - /* - * bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the - * BSS / P2P clients have rssi above threshold. - * We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before - * the iteration, if one interface's rssi isn't good enough, - * bt_kill_msk will be set to default values. - */ } else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) { if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false)) IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); - - /* - * One interface hasn't rssi above threshold, bt_kill_msk must - * be set to default values. - */ - data->reduced_tx_power = false; } /* Begin to monitor the RSSI: it may influence the reduced Tx power */ @@ -963,7 +917,6 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) struct iwl_bt_iterator_data data = { .mvm = mvm, .notif = &mvm->last_bt_notif_old, - .reduced_tx_power = true, }; struct iwl_bt_coex_ci_cmd_old cmd = {}; u8 ci_bw_idx; @@ -1037,14 +990,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) memcpy(&mvm->last_bt_ci_cmd_old, &cmd, sizeof(cmd)); } - /* - * If there are no BSS / P2P client interfaces, reduced Tx Power is - * irrelevant since it is based on the RSSI coming from the beacon. - * Use BT_KILL_MSK_DEFAULT in that case. - */ - data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; - - if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) + if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm)) IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); } @@ -1115,16 +1061,6 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, return; mvmsta = iwl_mvm_sta_from_mac80211(sta); - - data->num_bss_ifaces++; - - /* - * This interface doesn't support reduced Tx power (because of low - * RSSI probably), then set bt_kill_msk to default values. - */ - if (!mvmsta->bt_reduced_txpower) - data->reduced_tx_power = false; - /* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */ } void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -1133,7 +1069,6 @@ void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; struct iwl_bt_iterator_data data = { .mvm = mvm, - .reduced_tx_power = true, }; int ret; @@ -1175,14 +1110,7 @@ void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_bt_rssi_iterator, &data); - /* - * If there are no BSS / P2P client interfaces, reduced Tx Power is - * irrelevant since it is based on the RSSI coming from the beacon. - * Use BT_KILL_MSK_DEFAULT in that case. - */ - data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces; - - if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power)) + if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm)) IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); } diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index ac9787c09248..b26825921f9b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -514,9 +514,9 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", - iwl_bt_ack_kill_msk[mvm->bt_kill_msk]); + iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]); pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", - iwl_bt_cts_kill_msk[mvm->bt_kill_msk]); + iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]); } else { struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; @@ -531,10 +531,19 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, le64_to_cpu(cmd->bt_secondary_ci)); pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); - pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", - iwl_bt_ack_kill_msk[mvm->bt_kill_msk]); - pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", - iwl_bt_cts_kill_msk[mvm->bt_kill_msk]); + pos += scnprintf(buf+pos, bufsz-pos, + "\tPrimary: ACK Kill Mask 0x%08x\n", + iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]); + pos += scnprintf(buf+pos, bufsz-pos, + "\tPrimary: CTS Kill Mask 0x%08x\n", + iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]); + pos += scnprintf(buf+pos, bufsz-pos, + "\tSecondary: ACK Kill Mask 0x%08x\n", + iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[1]]); + pos += scnprintf(buf+pos, bufsz-pos, + "\tSecondary: CTS Kill Mask 0x%08x\n", + iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[1]]); + } mutex_unlock(&mvm->mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index ab12aaa43034..69875716dcdb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h @@ -385,6 +385,8 @@ enum iwl_bt_activity_grading { BT_ON_NO_CONNECTION = 1, BT_LOW_TRAFFIC = 2, BT_HIGH_TRAFFIC = 3, + + BT_MAX_AG, }; /* BT_COEX_BT_ACTIVITY_GRADING_API_E_VER_1 */ enum iwl_bt_ci_compliance { diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2cead5d44309..5b17fdfafbfa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -660,7 +660,8 @@ struct iwl_mvm { wait_queue_head_t d0i3_exit_waitq; /* BT-Coex */ - u8 bt_kill_msk; + u8 bt_ack_kill_msk[NUM_PHY_CTX]; + u8 bt_cts_kill_msk[NUM_PHY_CTX]; struct iwl_bt_coex_profile_notif_old last_bt_notif_old; struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd_old; @@ -1047,12 +1048,14 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, enum iwl_bt_kill_msk { BT_KILL_MSK_DEFAULT, - BT_KILL_MSK_SCO_HID_A2DP, - BT_KILL_MSK_REDUCED_TXPOW, + BT_KILL_MSK_NEVER, + BT_KILL_MSK_ALWAYS, BT_KILL_MSK_MAX, }; -extern const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX]; -extern const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX]; + +extern const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT]; +extern const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT]; +extern const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX]; /* beacon filtering */ #ifdef CONFIG_IWLWIFI_DEBUGFS -- cgit v1.2.3 From 45bbb2ca1e27c79bd3cbdcec040e7daceceeabbb Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 7 Jul 2014 14:38:39 +0300 Subject: iwlwifi: mvm: BT Coex - don't change AP SMPS mode Leave it to default instead - regardless of the BT activity. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 21 ++++++++------------- drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 17 +++++++---------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index a65b1bb12b3d..2291bbcaaeab 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -768,13 +768,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, smps_mode = IEEE80211_SMPS_AUTOMATIC; break; case NL80211_IFTYPE_AP: - /* default smps_mode for AP / GO is OFF */ - smps_mode = IEEE80211_SMPS_OFF; - if (!mvmvif->ap_ibss_active) { - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, - smps_mode); + if (!mvmvif->ap_ibss_active) return; - } break; default: return; @@ -785,10 +780,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, /* If channel context is invalid or not on 2.4GHz .. */ if ((!chanctx_conf || chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { - /* ... relax constraints and disable rssi events */ - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, - smps_mode); if (vif->type == NL80211_IFTYPE_STATION) { + /* ... relax constraints and disable rssi events */ + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, + smps_mode); iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); @@ -800,9 +795,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, if (bt_activity_grading >= BT_HIGH_TRAFFIC) smps_mode = IEEE80211_SMPS_STATIC; else if (bt_activity_grading >= BT_LOW_TRAFFIC) - smps_mode = vif->type == NL80211_IFTYPE_AP ? - IEEE80211_SMPS_OFF : - IEEE80211_SMPS_DYNAMIC; + smps_mode = IEEE80211_SMPS_DYNAMIC; /* relax SMPS contraints for next association */ if (!vif->bss_conf.assoc) @@ -816,7 +809,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, "mac %d: bt_activity_grading %d smps_req %d\n", mvmvif->id, bt_activity_grading, smps_mode); - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); + if (vif->type == NL80211_IFTYPE_STATION) + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, + smps_mode); /* low latency is always primary */ if (iwl_mvm_vif_low_latency(mvmvif)) { diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index 9e3ba5a4103d..a3be33359927 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -793,13 +793,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, smps_mode = IEEE80211_SMPS_AUTOMATIC; break; case NL80211_IFTYPE_AP: - /* default smps_mode for AP / GO is OFF */ - smps_mode = IEEE80211_SMPS_OFF; - if (!mvmvif->ap_ibss_active) { - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, - smps_mode); + if (!mvmvif->ap_ibss_active) return; - } break; default: return; @@ -810,10 +805,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, /* If channel context is invalid or not on 2.4GHz .. */ if ((!chanctx_conf || chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { - /* ... relax constraints and disable rssi events */ - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, - smps_mode); if (vif->type == NL80211_IFTYPE_STATION) { + /* ... relax constraints and disable rssi events */ + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, + smps_mode); iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); @@ -838,7 +833,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, mvmvif->id, data->notif->bt_status, bt_activity_grading, smps_mode); - iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); + if (vif->type == NL80211_IFTYPE_STATION) + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, + smps_mode); /* low latency is always primary */ if (iwl_mvm_vif_low_latency(mvmvif)) { -- cgit v1.2.3 From 4660dfbbe04cc5777cd7a68916e2c8c5b3b07674 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 22 Jun 2014 18:15:59 +0300 Subject: iwlwifi: mvm: wait for handlers when stopping scans The recent unified scan api change introduced issues when stopping ongoing scans, since both regular and sched scan now use same stopped notification. When issuing a new scan right after a running one, we get the "old" notification and handle it wrongly as notification for the current scan. Fix it by introducing a new function that make sure we consume the pending notifications before issuing a new scan. Signed-off-by: Eliad Peller Reviewed-by: ArikX Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 86 +++++++++++++++++------------ 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 5219b3a5689d..46ff7cd52d92 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1718,6 +1718,47 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED); } +static int iwl_mvm_cancel_scan_wait_notif(struct iwl_mvm *mvm, + enum iwl_scan_status scan_type) +{ + int ret; + bool wait_for_handlers = false; + + mutex_lock(&mvm->mutex); + + if (mvm->scan_status != scan_type) { + ret = 0; + /* make sure there are no pending notifications */ + wait_for_handlers = true; + goto out; + } + + switch (scan_type) { + case IWL_MVM_SCAN_SCHED: + ret = iwl_mvm_scan_offload_stop(mvm, true); + break; + case IWL_MVM_SCAN_OS: + ret = iwl_mvm_cancel_scan(mvm); + break; + case IWL_MVM_SCAN_NONE: + default: + WARN_ON_ONCE(1); + ret = -EINVAL; + break; + } + if (ret) + goto out; + + wait_for_handlers = true; +out: + mutex_unlock(&mvm->mutex); + + /* make sure we consume the completion notification */ + if (wait_for_handlers) + iwl_mvm_wait_for_async_handlers(mvm); + + return ret; +} static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *hw_req) @@ -1730,19 +1771,13 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, req->n_channels > mvm->fw->ucode_capa.n_scan_channels) return -EINVAL; + ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED); + if (ret) + return ret; + mutex_lock(&mvm->mutex); - switch (mvm->scan_status) { - case IWL_MVM_SCAN_SCHED: - ret = iwl_mvm_scan_offload_stop(mvm, true); - if (ret) { - ret = -EBUSY; - goto out; - } - break; - case IWL_MVM_SCAN_NONE: - break; - default: + if (mvm->scan_status != IWL_MVM_SCAN_NONE) { ret = -EBUSY; goto out; } @@ -1758,8 +1793,6 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); out: mutex_unlock(&mvm->mutex); - /* make sure to flush the Rx handler before the next scan arrives */ - iwl_mvm_wait_for_async_handlers(mvm); return ret; } @@ -2135,6 +2168,10 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; + ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS); + if (ret) + return ret; + mutex_lock(&mvm->mutex); if (!iwl_mvm_is_idle(mvm)) { @@ -2142,26 +2179,7 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, goto out; } - switch (mvm->scan_status) { - case IWL_MVM_SCAN_OS: - IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n"); - ret = iwl_mvm_cancel_scan(mvm); - if (ret) { - ret = -EBUSY; - goto out; - } - - /* - * iwl_mvm_rx_scan_complete() will be called soon but will - * not reset the scan status as it won't be IWL_MVM_SCAN_OS - * any more since we queue the next scan immediately (below). - * We make sure it is called before the next scan starts by - * flushing the async-handlers work. - */ - break; - case IWL_MVM_SCAN_NONE: - break; - default: + if (mvm->scan_status != IWL_MVM_SCAN_NONE) { ret = -EBUSY; goto out; } @@ -2189,8 +2207,6 @@ err: mvm->scan_status = IWL_MVM_SCAN_NONE; out: mutex_unlock(&mvm->mutex); - /* make sure to flush the Rx handler before the next scan arrives */ - iwl_mvm_wait_for_async_handlers(mvm); return ret; } -- cgit v1.2.3 From abf09c561312b28e5f51d165bf9270a3741032c7 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Tue, 1 Jul 2014 17:33:29 +0300 Subject: iwlwifi: mvm: minor change in debug print Add OTP to the string: "can't parse empty OTP/NVM section" NVM usually refers to nvm_file while the problem can be in the OTP. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/nvm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index b04805ccb443..cfdd314fdd5d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -265,7 +265,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) { - IWL_ERR(mvm, "Can't parse empty NVM sections\n"); + IWL_ERR(mvm, "Can't parse empty OTP/NVM sections\n"); return NULL; } } else { @@ -273,7 +273,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) { IWL_ERR(mvm, - "Can't parse empty family 8000 NVM sections\n"); + "Can't parse empty family 8000 OTP/NVM sections\n"); return NULL; } /* MAC_OVERRIDE or at least HW section must exist */ -- cgit v1.2.3 From 074279abb93566b3c33c3ef4aecf3e587251880b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 21 Jul 2014 11:44:12 +0300 Subject: iwlwifi: fix inconsistency about power_save module parameter modinfo and kerneldoc disagreed on the meaning of this field. Reported-by: Andrea Oliveri Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-modparams.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index f2d39cb011fc..71507cf490e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -99,7 +99,7 @@ enum iwl_disable_11n { * @wd_disable: disable stuck queue check, default = 1 * @bt_coex_active: enable bt coex, default = true * @led_mode: system default, default = 0 - * @power_save: disable power save, default = false + * @power_save: enable power save, default = false * @power_level: power level, default = 1 * @debug_level: levels are IWL_DL_* * @ant_coupling: antenna coupling in dB, default = 0 -- cgit v1.2.3 From 48eb7b34ff027392985fae213c4d1d0fcc425b9c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 8 Jul 2014 19:45:17 +0300 Subject: iwlwifi: split fw-error-dump between transport and mvm The mvm op_mode won't allocate the buffer for the transport any more. The transport allocates its own buffer and mvm is in charge of splicing the buffers in the debugfs hook. This makes the repartition easier to handle. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 21 ++++++++------- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 40 +++++++++++++++++++++++++---- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 31 +++++++++++----------- drivers/net/wireless/iwlwifi/mvm/mvm.h | 17 +++++++++++- drivers/net/wireless/iwlwifi/mvm/ops.c | 6 ++++- drivers/net/wireless/iwlwifi/pcie/trans.c | 19 +++++++++----- 6 files changed, 95 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 34d49e171fb4..656371a668da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -394,6 +394,11 @@ struct iwl_trans_config { const char *const *command_names; }; +struct iwl_trans_dump_data { + u32 len; + u8 data[]; +}; + struct iwl_trans; /** @@ -461,10 +466,8 @@ struct iwl_trans; * @unref: release a reference previously taken with @ref. Note that * initially the reference count is 1, making an initial @unref * necessary to allow low power states. - * @dump_data: fill a data dump with debug data, maybe containing last - * TX'ed commands and similar. When called with a NULL buffer and - * zero buffer length, provide only the (estimated) required buffer - * length. Return the used buffer length. + * @dump_data: return a vmalloc'ed buffer with debug data, maybe containing last + * TX'ed commands and similar. The buffer will be vfree'd by the caller. * Note that the transport must fill in the proper file headers. */ struct iwl_trans_ops { @@ -518,7 +521,7 @@ struct iwl_trans_ops { void (*unref)(struct iwl_trans *trans); #ifdef CONFIG_IWLWIFI_DEBUGFS - u32 (*dump_data)(struct iwl_trans *trans, void *buf, u32 buflen); + struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); #endif }; @@ -685,12 +688,12 @@ static inline void iwl_trans_unref(struct iwl_trans *trans) } #ifdef CONFIG_IWLWIFI_DEBUGFS -static inline u32 iwl_trans_dump_data(struct iwl_trans *trans, - void *buf, u32 buflen) +static inline struct iwl_trans_dump_data * +iwl_trans_dump_data(struct iwl_trans *trans) { if (!trans->ops->dump_data) - return 0; - return trans->ops->dump_data(trans, buf, buflen); + return NULL; + return trans->ops->dump_data(trans); } #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index b26825921f9b..7d18f466fbb3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -146,17 +146,47 @@ static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct iwl_fw_error_dump_file *dump_file = file->private_data; + struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data; + ssize_t bytes_read = 0; + ssize_t bytes_read_trans = 0; + + if (*ppos < dump_ptrs->op_mode_len) + bytes_read += + simple_read_from_buffer(user_buf, count, ppos, + dump_ptrs->op_mode_ptr, + dump_ptrs->op_mode_len); + + if (bytes_read < 0 || *ppos < dump_ptrs->op_mode_len) + return bytes_read; + + if (dump_ptrs->trans_ptr) { + *ppos -= dump_ptrs->op_mode_len; + bytes_read_trans = + simple_read_from_buffer(user_buf + bytes_read, + count - bytes_read, ppos, + dump_ptrs->trans_ptr->data, + dump_ptrs->trans_ptr->len); + *ppos += dump_ptrs->op_mode_len; + + if (bytes_read_trans >= 0) + bytes_read += bytes_read_trans; + else if (!bytes_read) + /* propagate the failure */ + return bytes_read_trans; + } + + return bytes_read; - return simple_read_from_buffer(user_buf, count, ppos, - dump_file, - le32_to_cpu(dump_file->file_len)); } static int iwl_dbgfs_fw_error_dump_release(struct inode *inode, struct file *file) { - vfree(file->private_data); + struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data; + + vfree(dump_ptrs->op_mode_ptr); + vfree(dump_ptrs->trans_ptr); + kfree(dump_ptrs); return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 46ff7cd52d92..bd924a1f7804 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -676,11 +676,11 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; + struct iwl_mvm_dump_ptrs *fw_error_dump; const struct fw_img *img; u32 sram_len, sram_ofs; u32 file_len, rxf_len; unsigned long flags; - u32 trans_len; int reg_val; lockdep_assert_held(&mvm->mutex); @@ -688,6 +688,10 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) if (mvm->fw_error_dump) return; + fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL); + if (!fw_error_dump) + return; + img = &mvm->fw->img[mvm->cur_ucode]; sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; @@ -705,18 +709,15 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) rxf_len + sizeof(*dump_info); - trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0); - if (trans_len) - file_len += trans_len; - dump_file = vzalloc(file_len); - if (!dump_file) + if (!dump_file) { + kfree(fw_error_dump); return; + } - mvm->fw_error_dump = dump_file; + fw_error_dump->op_mode_ptr = dump_file; dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); - dump_file->file_len = cpu_to_le32(file_len); dump_data = (void *)dump_file->data; dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); @@ -757,14 +758,12 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, sram_len); - if (trans_len) { - void *buf = iwl_fw_error_next_data(dump_data); - u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, - trans_len); - dump_data = (void *)((u8 *)buf + real_trans_len); - dump_file->file_len = - cpu_to_le32(file_len - trans_len + real_trans_len); - } + fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans); + fw_error_dump->op_mode_len = file_len; + if (fw_error_dump->trans_ptr) + file_len += fw_error_dump->trans_ptr->len; + dump_file->file_len = cpu_to_le32(file_len); + mvm->fw_error_dump = fw_error_dump; } #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 5b17fdfafbfa..2e73d3bd7757 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -128,6 +128,21 @@ struct iwl_mvm_mod_params { }; extern struct iwl_mvm_mod_params iwlmvm_mod_params; +/** + * struct iwl_mvm_dump_ptrs - set of pointers needed for the fw-error-dump + * + * @op_mode_ptr: pointer to the buffer coming from the mvm op_mode + * @trans_ptr: pointer to struct %iwl_trans_dump_data which contains the + * transport's data. + * @trans_len: length of the valid data in trans_ptr + * @op_mode_len: length of the valid data in op_mode_ptr + */ +struct iwl_mvm_dump_ptrs { + struct iwl_trans_dump_data *trans_ptr; + void *op_mode_ptr; + u32 op_mode_len; +}; + struct iwl_mvm_phy_ctxt { u16 id; u16 color; @@ -626,7 +641,7 @@ struct iwl_mvm { /* -1 for always, 0 for never, >0 for that many times */ s8 restart_fw; - void *fw_error_dump; + struct iwl_mvm_dump_ptrs *fw_error_dump; #ifdef CONFIG_IWLWIFI_LEDS struct led_classdev led; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 904228aa64c4..610dbcb0dc27 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -573,7 +573,11 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) ieee80211_unregister_hw(mvm->hw); kfree(mvm->scan_cmd); - vfree(mvm->fw_error_dump); + if (mvm->fw_error_dump) { + vfree(mvm->fw_error_dump->op_mode_ptr); + vfree(mvm->fw_error_dump->trans_ptr); + kfree(mvm->fw_error_dump); + } kfree(mvm->mcast_filter_cmd); mvm->mcast_filter_cmd = NULL; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 5b5b0d8c6f60..a90292c79342 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -67,6 +67,7 @@ #include #include #include +#include #include "iwl-drv.h" #include "iwl-trans.h" @@ -1773,28 +1774,30 @@ static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd) return cmdlen; } -static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, - void *buf, u32 buflen) +static +struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_fw_error_dump_data *data; struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue]; struct iwl_fw_error_dump_txcmd *txcmd; + struct iwl_trans_dump_data *dump_data; u32 len; int i, ptr; - len = sizeof(*data) + + len = sizeof(*dump_data) + sizeof(*data) + cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); if (trans_pcie->fw_mon_page) len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + trans_pcie->fw_mon_size; - if (!buf) - return len; + dump_data = vzalloc(len); + if (!dump_data) + return NULL; len = 0; - data = buf; + data = (void *)dump_data->data; data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD); txcmd = (void *)data->data; spin_lock_bh(&cmdq->lock); @@ -1852,7 +1855,9 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, trans_pcie->fw_mon_size; } - return len; + dump_data->len = len; + + return dump_data; } #else static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, -- cgit v1.2.3 From 67c65f2cf7105f139909bad79c048e8aec0dc140 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 26 Jun 2014 11:27:51 +0300 Subject: iwlwifi: dump periphery registers to fw-error-dump Use the fw-error-dump infrastructure to dump the periphery registers. Only certain ranges are readable, so dump only these. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 13 ++ drivers/net/wireless/iwlwifi/pcie/trans.c | 152 ++++++++++++++++++++++- 2 files changed, 164 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index c39a0b899e83..5121479febfe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -77,6 +77,8 @@ * @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info * info on the device / firmware. * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor + * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several + * sections like this in a single file. */ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_SRAM = 0, @@ -85,6 +87,7 @@ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_TXCMD = 3, IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, IWL_FW_ERROR_DUMP_FW_MONITOR = 5, + IWL_FW_ERROR_DUMP_PRPH = 6, IWL_FW_ERROR_DUMP_MAX, }; @@ -162,6 +165,16 @@ struct iwl_fw_error_dump_fw_mon { u8 data[]; } __packed; +/** + * struct iwl_fw_error_dump_prph - periphery registers data + * @prph_start: address of the first register in this chunk + * @data: the content of the registers + */ +struct iwl_fw_error_dump_prph { + __le32 prph_start; + __le32 data[]; +}; + /** * iwl_fw_error_next_data - advance fw error dump data pointer * @data: previous data block diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index a90292c79342..153c3dd88921 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1774,6 +1774,144 @@ static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd) return cmdlen; } +static const struct { + u32 start, end; +} iwl_prph_dump_addr[] = { + { .start = 0x00a00000, .end = 0x00a00000 }, + { .start = 0x00a0000c, .end = 0x00a00024 }, + { .start = 0x00a0002c, .end = 0x00a0003c }, + { .start = 0x00a00410, .end = 0x00a00418 }, + { .start = 0x00a00420, .end = 0x00a00420 }, + { .start = 0x00a00428, .end = 0x00a00428 }, + { .start = 0x00a00430, .end = 0x00a0043c }, + { .start = 0x00a00444, .end = 0x00a00444 }, + { .start = 0x00a004c0, .end = 0x00a004cc }, + { .start = 0x00a004d8, .end = 0x00a004d8 }, + { .start = 0x00a004e0, .end = 0x00a004f0 }, + { .start = 0x00a00840, .end = 0x00a00840 }, + { .start = 0x00a00850, .end = 0x00a00858 }, + { .start = 0x00a01004, .end = 0x00a01008 }, + { .start = 0x00a01010, .end = 0x00a01010 }, + { .start = 0x00a01018, .end = 0x00a01018 }, + { .start = 0x00a01024, .end = 0x00a01024 }, + { .start = 0x00a0102c, .end = 0x00a01034 }, + { .start = 0x00a0103c, .end = 0x00a01040 }, + { .start = 0x00a01048, .end = 0x00a01094 }, + { .start = 0x00a01c00, .end = 0x00a01c20 }, + { .start = 0x00a01c58, .end = 0x00a01c58 }, + { .start = 0x00a01c7c, .end = 0x00a01c7c }, + { .start = 0x00a01c28, .end = 0x00a01c54 }, + { .start = 0x00a01c5c, .end = 0x00a01c5c }, + { .start = 0x00a01c84, .end = 0x00a01c84 }, + { .start = 0x00a01ce0, .end = 0x00a01d0c }, + { .start = 0x00a01d18, .end = 0x00a01d20 }, + { .start = 0x00a01d2c, .end = 0x00a01d30 }, + { .start = 0x00a01d40, .end = 0x00a01d5c }, + { .start = 0x00a01d80, .end = 0x00a01d80 }, + { .start = 0x00a01d98, .end = 0x00a01d98 }, + { .start = 0x00a01dc0, .end = 0x00a01dfc }, + { .start = 0x00a01e00, .end = 0x00a01e2c }, + { .start = 0x00a01e40, .end = 0x00a01e60 }, + { .start = 0x00a01e84, .end = 0x00a01e90 }, + { .start = 0x00a01e9c, .end = 0x00a01ec4 }, + { .start = 0x00a01ed0, .end = 0x00a01ed0 }, + { .start = 0x00a01f00, .end = 0x00a01f14 }, + { .start = 0x00a01f44, .end = 0x00a01f58 }, + { .start = 0x00a01f80, .end = 0x00a01fa8 }, + { .start = 0x00a01fb0, .end = 0x00a01fbc }, + { .start = 0x00a01ff8, .end = 0x00a01ffc }, + { .start = 0x00a02000, .end = 0x00a02048 }, + { .start = 0x00a02068, .end = 0x00a020f0 }, + { .start = 0x00a02100, .end = 0x00a02118 }, + { .start = 0x00a02140, .end = 0x00a0214c }, + { .start = 0x00a02168, .end = 0x00a0218c }, + { .start = 0x00a021c0, .end = 0x00a021c0 }, + { .start = 0x00a02400, .end = 0x00a02410 }, + { .start = 0x00a02418, .end = 0x00a02420 }, + { .start = 0x00a02428, .end = 0x00a0242c }, + { .start = 0x00a02434, .end = 0x00a02434 }, + { .start = 0x00a02440, .end = 0x00a02460 }, + { .start = 0x00a02468, .end = 0x00a024b0 }, + { .start = 0x00a024c8, .end = 0x00a024cc }, + { .start = 0x00a02500, .end = 0x00a02504 }, + { .start = 0x00a0250c, .end = 0x00a02510 }, + { .start = 0x00a02540, .end = 0x00a02554 }, + { .start = 0x00a02580, .end = 0x00a025f4 }, + { .start = 0x00a02600, .end = 0x00a0260c }, + { .start = 0x00a02648, .end = 0x00a02650 }, + { .start = 0x00a02680, .end = 0x00a02680 }, + { .start = 0x00a026c0, .end = 0x00a026d0 }, + { .start = 0x00a02700, .end = 0x00a0270c }, + { .start = 0x00a02804, .end = 0x00a02804 }, + { .start = 0x00a02818, .end = 0x00a0281c }, + { .start = 0x00a02c00, .end = 0x00a02db4 }, + { .start = 0x00a02df4, .end = 0x00a02fb0 }, + { .start = 0x00a03000, .end = 0x00a03014 }, + { .start = 0x00a0301c, .end = 0x00a0302c }, + { .start = 0x00a03034, .end = 0x00a03038 }, + { .start = 0x00a03040, .end = 0x00a03048 }, + { .start = 0x00a03060, .end = 0x00a03068 }, + { .start = 0x00a03070, .end = 0x00a03074 }, + { .start = 0x00a0307c, .end = 0x00a0307c }, + { .start = 0x00a03080, .end = 0x00a03084 }, + { .start = 0x00a0308c, .end = 0x00a03090 }, + { .start = 0x00a03098, .end = 0x00a03098 }, + { .start = 0x00a030a0, .end = 0x00a030a0 }, + { .start = 0x00a030a8, .end = 0x00a030b4 }, + { .start = 0x00a030bc, .end = 0x00a030bc }, + { .start = 0x00a030c0, .end = 0x00a0312c }, + { .start = 0x00a03c00, .end = 0x00a03c5c }, + { .start = 0x00a04400, .end = 0x00a04454 }, + { .start = 0x00a04460, .end = 0x00a04474 }, + { .start = 0x00a044c0, .end = 0x00a044ec }, + { .start = 0x00a04500, .end = 0x00a04504 }, + { .start = 0x00a04510, .end = 0x00a04538 }, + { .start = 0x00a04540, .end = 0x00a04548 }, + { .start = 0x00a04560, .end = 0x00a0457c }, + { .start = 0x00a04590, .end = 0x00a04598 }, + { .start = 0x00a045c0, .end = 0x00a045f4 }, +}; + +static u32 iwl_trans_pcie_dump_prph(struct iwl_trans *trans, + struct iwl_fw_error_dump_data **data) +{ + struct iwl_fw_error_dump_prph *prph; + unsigned long flags; + u32 prph_len = 0, i; + + if (!iwl_trans_grab_nic_access(trans, false, &flags)) + return 0; + + for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { + /* The range includes both boundaries */ + int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - + iwl_prph_dump_addr[i].start + 4; + int reg; + __le32 *val; + + prph_len += sizeof(*data) + sizeof(*prph) + + num_bytes_in_chunk; + + (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH); + (*data)->len = cpu_to_le32(sizeof(*prph) + + num_bytes_in_chunk); + prph = (void *)(*data)->data; + prph->prph_start = cpu_to_le32(iwl_prph_dump_addr[i].start); + val = (void *)prph->data; + + for (reg = iwl_prph_dump_addr[i].start; + reg <= iwl_prph_dump_addr[i].end; + reg += 4) + *val++ = cpu_to_le32(iwl_trans_pcie_read_prph(trans, + reg)); + *data = iwl_fw_error_next_data(*data); + } + + iwl_trans_release_nic_access(trans, &flags); + + return prph_len; +} + static struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) { @@ -1788,6 +1926,15 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) len = sizeof(*dump_data) + sizeof(*data) + cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); + for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { + /* The range includes both boundaries */ + int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - + iwl_prph_dump_addr[i].start + 4; + + len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_prph) + + num_bytes_in_chunk; + } + if (trans_pcie->fw_mon_page) len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + trans_pcie->fw_mon_size; @@ -1823,11 +1970,14 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) data->len = cpu_to_le32(len); len += sizeof(*data); + data = iwl_fw_error_next_data(data); + + len += iwl_trans_pcie_dump_prph(trans, &data); + /* data is already pointing to the next section */ if (trans_pcie->fw_mon_page) { struct iwl_fw_error_dump_fw_mon *fw_mon_data; - data = iwl_fw_error_next_data(data); data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); data->len = cpu_to_le32(trans_pcie->fw_mon_size + sizeof(*fw_mon_data)); -- cgit v1.2.3 From 473ad712a49f8a7d9d2c5924a964a81a7ebf2e06 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 8 Jul 2014 19:44:25 +0300 Subject: iwlwifi: dump CSRs to fw-error-dump Add the Control Status Registers to the firmware error dump infrastructure. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 4 +-- drivers/net/wireless/iwlwifi/pcie/trans.c | 33 +++++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index 5121479febfe..de5994a776c7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -70,7 +70,7 @@ /** * enum iwl_fw_error_dump_type - types of data in the dump file * @IWL_FW_ERROR_DUMP_SRAM: - * @IWL_FW_ERROR_DUMP_REG: + * @IWL_FW_ERROR_DUMP_CSR: Control Status Registers - from offset 0 * @IWL_FW_ERROR_DUMP_RXF: * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as * &struct iwl_fw_error_dump_txcmd packets @@ -82,7 +82,7 @@ */ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_SRAM = 0, - IWL_FW_ERROR_DUMP_REG = 1, + IWL_FW_ERROR_DUMP_CSR = 1, IWL_FW_ERROR_DUMP_RXF = 2, IWL_FW_ERROR_DUMP_TXCMD = 3, IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 153c3dd88921..06e04aaf61ee 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1912,6 +1912,27 @@ static u32 iwl_trans_pcie_dump_prph(struct iwl_trans *trans, return prph_len; } +#define IWL_CSR_TO_DUMP (0x250) + +static u32 iwl_trans_pcie_dump_csr(struct iwl_trans *trans, + struct iwl_fw_error_dump_data **data) +{ + u32 csr_len = sizeof(**data) + IWL_CSR_TO_DUMP; + __le32 *val; + int i; + + (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_CSR); + (*data)->len = cpu_to_le32(IWL_CSR_TO_DUMP); + val = (void *)(*data)->data; + + for (i = 0; i < IWL_CSR_TO_DUMP; i += 4) + *val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i)); + + *data = iwl_fw_error_next_data(*data); + + return csr_len; +} + static struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) { @@ -1923,9 +1944,17 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) u32 len; int i, ptr; - len = sizeof(*dump_data) + sizeof(*data) + + /* transport dump header */ + len = sizeof(*dump_data); + + /* host commands */ + len += sizeof(*data) + cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); + /* CSR registers */ + len += sizeof(*data) + IWL_CSR_TO_DUMP; + + /* PRPH registers */ for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { /* The range includes both boundaries */ int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - @@ -1935,6 +1964,7 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) num_bytes_in_chunk; } + /* FW monitor */ if (trans_pcie->fw_mon_page) len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + trans_pcie->fw_mon_size; @@ -1973,6 +2003,7 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) data = iwl_fw_error_next_data(data); len += iwl_trans_pcie_dump_prph(trans, &data); + len += iwl_trans_pcie_dump_csr(trans, &data); /* data is already pointing to the next section */ if (trans_pcie->fw_mon_page) { -- cgit v1.2.3 From cc87d322930cc8b5bf17d871896faa6752609a66 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Tue, 15 Jul 2014 14:04:23 +0300 Subject: iwlwifi: mvm: update smart fifo / beacon filtering upon association When we associate, we may have heard the beacon before the association. In that case, BSS_CHANGED_BEACON_INFO will be set along with BSS_CHANGED_ASSOC in changes in bss_info_change. In this case, we didn't update the smart fifo nor beacon filtering leaving those two feature disabled. Signed-off-by: Eran Harary Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index bd924a1f7804..01af86af979a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1501,14 +1501,18 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, */ iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); - iwl_mvm_sf_update(mvm, vif, false); - WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS)) { ret = iwl_mvm_power_update_mac(mvm); if (ret) IWL_ERR(mvm, "failed to update power mode\n"); } + + if (changes & BSS_CHANGED_BEACON_INFO) { + iwl_mvm_sf_update(mvm, vif, false); + WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); + } + if (changes & BSS_CHANGED_TXPOWER) { IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n", bss_conf->txpower); -- cgit v1.2.3 From 8a275bad9c0369aefebda90748f91361934dd638 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 13 Jul 2014 09:12:11 +0300 Subject: iwlwifi: mvm: reset beacon filtering and BT Coex data upon FW restart When the firmware asserts, we restart the device and reset the relevant data we hold in the driver. BT Coex data was not reset and because of that, the driver wouldn't reconfigure the firmware properly after firmware restart. Same for beacon filtering. Fix that. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 01af86af979a..634bb7b7499e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -668,6 +668,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, spin_unlock_bh(&mvm->time_event_lock); mvmvif->phy_ctxt = NULL; + memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data)); } #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -795,6 +796,12 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) iwl_mvm_reset_phy_ctxts(mvm); memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); + memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); + memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); + memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); + memset(&mvm->last_bt_ci_cmd_old, 0, sizeof(mvm->last_bt_ci_cmd_old)); + memset(&mvm->bt_ack_kill_msk, 0, sizeof(mvm->bt_ack_kill_msk)); + memset(&mvm->bt_cts_kill_msk, 0, sizeof(mvm->bt_cts_kill_msk)); ieee80211_wake_queues(mvm->hw); -- cgit v1.2.3 From 81df6cafe28b358739d121205e1ddaeec2ed5b15 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Mon, 21 Jul 2014 10:01:52 +0200 Subject: mwifiex: card reset: enable rescan of non-removable card mmc_rescan will scan for non-removable cards only once, hence the card will not be rediscovered. Signed-off-by: Andreas Fenkart Acked-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sdio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 3e48ef5ca53c..1770fa3fc1e6 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1954,6 +1954,7 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) mmc_remove_host(target); /* 20ms delay is based on experiment with sdhci controller */ mdelay(20); + target->rescan_entered = 0; /* rescan non-removable cards */ mmc_add_host(target); } -- cgit v1.2.3 From 5b5ee4504ee90f2d614981574f7cd495743b65b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 19 Jul 2014 12:52:41 +0200 Subject: b43: N-PHY: add helper for setting digital filters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 92bfe352ba08..b5c8a816cde8 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -4809,41 +4809,46 @@ static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core) } } +static void b43_nphy_pa_set_tx_dig_filter(struct b43_wldev *dev, u16 offset, + const s16 *filter) +{ + int i; + + offset = B43_PHY_N(offset); + + for (i = 0; i < 15; i++, offset++) + b43_phy_write(dev, offset, filter[i]); +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ExtPaSetTxDigiFilts */ static void b43_nphy_ext_pa_set_tx_dig_filters(struct b43_wldev *dev) { - int i; - for (i = 0; i < 15; i++) - b43_phy_write(dev, B43_PHY_N(0x2C5 + i), - tbl_tx_filter_coef_rev4[2][i]); + b43_nphy_pa_set_tx_dig_filter(dev, 0x2C5, + tbl_tx_filter_coef_rev4[2]); } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IpaSetTxDigiFilts */ static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev) { - int i, j; /* B43_NPHY_TXF_20CO_S0A1, B43_NPHY_TXF_40CO_S0A1, unknown */ static const u16 offset[] = { 0x186, 0x195, 0x2C5 }; + int i; for (i = 0; i < 3; i++) - for (j = 0; j < 15; j++) - b43_phy_write(dev, B43_PHY_N(offset[i] + j), - tbl_tx_filter_coef_rev4[i][j]); + b43_nphy_pa_set_tx_dig_filter(dev, offset[i], + tbl_tx_filter_coef_rev4[i]); if (b43_is_40mhz(dev)) { - for (j = 0; j < 15; j++) - b43_phy_write(dev, B43_PHY_N(offset[0] + j), - tbl_tx_filter_coef_rev4[3][j]); + b43_nphy_pa_set_tx_dig_filter(dev, 0x186, + tbl_tx_filter_coef_rev4[3]); } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { - for (j = 0; j < 15; j++) - b43_phy_write(dev, B43_PHY_N(offset[0] + j), - tbl_tx_filter_coef_rev4[5][j]); + b43_nphy_pa_set_tx_dig_filter(dev, 0x186, + tbl_tx_filter_coef_rev4[5]); } if (dev->phy.channel == 14) - for (j = 0; j < 15; j++) - b43_phy_write(dev, B43_PHY_N(offset[0] + j), - tbl_tx_filter_coef_rev4[6][j]); + b43_nphy_pa_set_tx_dig_filter(dev, 0x186, + tbl_tx_filter_coef_rev4[6]); } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */ -- cgit v1.2.3 From 6b346e54bf94f65b756ad32902e663785da9eda6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 19 Jul 2014 12:52:42 +0200 Subject: b43: N-PHY: update digital filters setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes handling channel 14 and adds code for BCM43217. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index b5c8a816cde8..1293f51838ba 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -4832,23 +4832,38 @@ static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev) { /* B43_NPHY_TXF_20CO_S0A1, B43_NPHY_TXF_40CO_S0A1, unknown */ static const u16 offset[] = { 0x186, 0x195, 0x2C5 }; + static const s16 dig_filter_phy_rev16[] = { + -375, 136, -407, 208, -1527, + 956, 93, 186, 93, 230, + -44, 230, 201, -191, 201, + }; int i; for (i = 0; i < 3; i++) b43_nphy_pa_set_tx_dig_filter(dev, offset[i], tbl_tx_filter_coef_rev4[i]); + /* Verified with BCM43227 and BCM43228 */ + if (dev->phy.rev == 16) + b43_nphy_pa_set_tx_dig_filter(dev, 0x186, dig_filter_phy_rev16); + + if (dev->dev->chip_id == BCMA_CHIP_ID_BCM43217) { + b43_nphy_pa_set_tx_dig_filter(dev, 0x186, dig_filter_phy_rev16); + b43_nphy_pa_set_tx_dig_filter(dev, 0x195, + tbl_tx_filter_coef_rev4[1]); + } + if (b43_is_40mhz(dev)) { b43_nphy_pa_set_tx_dig_filter(dev, 0x186, tbl_tx_filter_coef_rev4[3]); - } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { - b43_nphy_pa_set_tx_dig_filter(dev, 0x186, - tbl_tx_filter_coef_rev4[5]); + } else { + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + b43_nphy_pa_set_tx_dig_filter(dev, 0x186, + tbl_tx_filter_coef_rev4[5]); + if (dev->phy.channel == 14) + b43_nphy_pa_set_tx_dig_filter(dev, 0x186, + tbl_tx_filter_coef_rev4[6]); } - - if (dev->phy.channel == 14) - b43_nphy_pa_set_tx_dig_filter(dev, 0x186, - tbl_tx_filter_coef_rev4[6]); } /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */ -- cgit v1.2.3 From 49083b47a380b086c3c92ffe5ae7125a16ad4671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 19 Jul 2014 12:52:43 +0200 Subject: b43: N-PHY: update generic rev7+ workarounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some missing ops and prepare for new devices support. This patch is a great stability improvement for BCM43217. Earlier Tenda W322E used to disconnect every 2 minutes (16 times over 30 minutes). With this fix I got it running for 4 hours (with iperf) without any disconnection. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 120 ++++++++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 1293f51838ba..448c676da588 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -2708,15 +2708,19 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) struct ssb_sprom *sprom = dev->dev->bus_sprom; struct b43_phy *phy = &dev->phy; + /* TX to RX */ + u8 tx2rx_events[7] = { 4, 3, 5, 2, 1, 8, 31, }; + u8 tx2rx_delays[7] = { 8, 4, 4, 4, 4, 6, 1, }; + /* RX to TX */ u8 rx2tx_events_ipa[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0xF, 0x3, 0x1F }; u8 rx2tx_delays_ipa[9] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 }; - u16 ntab7_15e_16e[] = { 0x10f, 0x10f }; + static const u16 ntab7_15e_16e[] = { 0, 0x10f, 0x10f }; u8 ntab7_138_146[] = { 0x11, 0x11 }; u8 ntab7_133[] = { 0x77, 0x11, 0x11 }; - u16 lpf_20, lpf_40, lpf_11b; + u16 lpf_ofdm_20mhz, lpf_ofdm_40mhz, lpf_11b; u16 bcap_val, bcap_val_11b, bcap_val_11n_20, bcap_val_11n_40; u16 scap_val, scap_val_11b, scap_val_11n_20, scap_val_11n_40; bool rccal_ovrd = false; @@ -2727,6 +2731,13 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) u32 tmp32; u8 core; + b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x0125); + b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x01b3); + b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x0105); + b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x016e); + b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0x00cd); + b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x0020); + if (phy->rev == 7) { b43_phy_set(dev, B43_NPHY_FINERX2_CGC, 0x10); b43_phy_maskset(dev, B43_NPHY_FREQGAIN0, 0xFF80, 0x0020); @@ -2746,11 +2757,18 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) b43_phy_maskset(dev, B43_NPHY_FREQGAIN7, 0xFF80, 0x0040); b43_phy_maskset(dev, B43_NPHY_FREQGAIN7, 0x80FF, 0x4000); } - if (phy->rev <= 8) { + + if (phy->rev >= 16) { + b43_phy_write(dev, B43_NPHY_FORCEFRONT0, 0x7ff); + b43_phy_write(dev, B43_NPHY_FORCEFRONT1, 0x7ff); + } else if (phy->rev <= 8) { b43_phy_write(dev, B43_NPHY_FORCEFRONT0, 0x1B0); b43_phy_write(dev, B43_NPHY_FORCEFRONT1, 0x1B0); } - if (phy->rev >= 8) + + if (phy->rev >= 16) + b43_phy_maskset(dev, B43_NPHY_TXTAILCNT, ~0xFF, 0xa0); + else if (phy->rev >= 8) b43_phy_maskset(dev, B43_NPHY_TXTAILCNT, ~0xFF, 0x72); b43_ntab_write(dev, B43_NTAB16(8, 0x00), 2); @@ -2758,9 +2776,11 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) tmp32 = b43_ntab_read(dev, B43_NTAB32(30, 0)); tmp32 &= 0xffffff; b43_ntab_write(dev, B43_NTAB32(30, 0), tmp32); - b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x15e), 2, ntab7_15e_16e); - b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x16e), 2, ntab7_15e_16e); + b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x15d), 3, ntab7_15e_16e); + b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x16d), 3, ntab7_15e_16e); + b43_nphy_set_rf_sequence(dev, 1, tx2rx_events, tx2rx_delays, + ARRAY_SIZE(tx2rx_events)); if (b43_nphy_ipa(dev)) b43_nphy_set_rf_sequence(dev, 0, rx2tx_events_ipa, rx2tx_delays_ipa, ARRAY_SIZE(rx2tx_events_ipa)); @@ -2768,44 +2788,53 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) b43_phy_maskset(dev, B43_NPHY_EPS_OVERRIDEI_0, 0x3FFF, 0x4000); b43_phy_maskset(dev, B43_NPHY_EPS_OVERRIDEI_1, 0x3FFF, 0x4000); - lpf_20 = b43_nphy_read_lpf_ctl(dev, 0x154); - lpf_40 = b43_nphy_read_lpf_ctl(dev, 0x159); + lpf_ofdm_20mhz = b43_nphy_read_lpf_ctl(dev, 0x154); + lpf_ofdm_40mhz = b43_nphy_read_lpf_ctl(dev, 0x159); lpf_11b = b43_nphy_read_lpf_ctl(dev, 0x152); + + bcap_val = b43_radio_read(dev, R2057_RCCAL_BCAP_VAL); + scap_val = b43_radio_read(dev, R2057_RCCAL_SCAP_VAL); + if (b43_nphy_ipa(dev)) { - if ((phy->radio_rev == 5 && b43_is_40mhz(dev)) || - phy->radio_rev == 7 || phy->radio_rev == 8) { - bcap_val = b43_radio_read(dev, 0x16b); - scap_val = b43_radio_read(dev, 0x16a); - scap_val_11b = scap_val; - bcap_val_11b = bcap_val; - if (phy->radio_rev == 5 && b43_is_40mhz(dev)) { + switch (phy->radio_rev) { + case 5: + /* Check radio version (to be 0) by PHY rev for now */ + if (phy->rev == 8 && b43_is_40mhz(dev)) { + scap_val_11b = scap_val; + bcap_val_11b = bcap_val; scap_val_11n_20 = scap_val; bcap_val_11n_20 = bcap_val; scap_val_11n_40 = bcap_val_11n_40 = 0xc; rccal_ovrd = true; - } else { /* Rev 7/8 */ - lpf_20 = 4; - lpf_11b = 1; - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - scap_val_11n_20 = 0xc; - bcap_val_11n_20 = 0xc; - scap_val_11n_40 = 0xa; - bcap_val_11n_40 = 0xa; - } else { - scap_val_11n_20 = 0x14; - bcap_val_11n_20 = 0x14; - scap_val_11n_40 = 0xf; - bcap_val_11n_40 = 0xf; - } - rccal_ovrd = true; } + if (phy->rev == 9) { + /* TODO: Radio version 1 (e.g. BCM5357B0) */ + } + break; + case 7: + case 8: + scap_val_11b = scap_val; + bcap_val_11b = bcap_val; + lpf_ofdm_20mhz = 4; + lpf_11b = 1; + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + scap_val_11n_20 = 0xc; + bcap_val_11n_20 = 0xc; + scap_val_11n_40 = 0xa; + bcap_val_11n_40 = 0xa; + } else { + scap_val_11n_20 = 0x14; + bcap_val_11n_20 = 0x14; + scap_val_11n_40 = 0xf; + bcap_val_11n_40 = 0xf; + } + rccal_ovrd = true; + break; } } else { if (phy->radio_rev == 5) { - lpf_20 = 1; - lpf_40 = 3; - bcap_val = b43_radio_read(dev, 0x16b); - scap_val = b43_radio_read(dev, 0x16a); + lpf_ofdm_20mhz = 1; + lpf_ofdm_40mhz = 3; scap_val_11b = scap_val; bcap_val_11b = bcap_val; scap_val_11n_20 = 0x11; @@ -2816,15 +2845,20 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) } } if (rccal_ovrd) { - rx2tx_lut_20_11b = (bcap_val_11b << 8) | + u8 rx2tx_lut_extra = 1; + + rx2tx_lut_20_11b = (rx2tx_lut_extra << 13) | + (bcap_val_11b << 8) | (scap_val_11b << 3) | lpf_11b; - rx2tx_lut_20_11n = (bcap_val_11n_20 << 8) | + rx2tx_lut_20_11n = (rx2tx_lut_extra << 13) | + (bcap_val_11n_20 << 8) | (scap_val_11n_20 << 3) | - lpf_20; - rx2tx_lut_40_11n = (bcap_val_11n_40 << 8) | + lpf_ofdm_20mhz; + rx2tx_lut_40_11n = (rx2tx_lut_extra << 13) | + (bcap_val_11n_40 << 8) | (scap_val_11n_40 << 3) | - lpf_40; + lpf_ofdm_40mhz; for (core = 0; core < 2; core++) { b43_ntab_write(dev, B43_NTAB16(7, 0x152 + core * 16), rx2tx_lut_20_11b); @@ -2893,7 +2927,8 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) 0x7f); } } - if (phy->radio_rev == 3) { + switch (phy->radio_rev) { + case 3: for (core = 0; core < 2; core++) { if (core == 0) { b43_radio_write(dev, 0x64, @@ -2919,7 +2954,9 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) 0x3E); } } - } else if (phy->radio_rev == 7 || phy->radio_rev == 8) { + break; + case 7: + case 8: if (!b43_is_40mhz(dev)) { b43_radio_write(dev, 0x5F, 0x14); b43_radio_write(dev, 0xE8, 0x12); @@ -2927,6 +2964,7 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) b43_radio_write(dev, 0x5F, 0x16); b43_radio_write(dev, 0xE8, 0x16); } + break; } } else { u16 freq = phy->chandef->chan->center_freq; -- cgit v1.2.3 From ce623192c7e63a5db86a876d42382af6cb672c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 19 Jul 2014 12:52:44 +0200 Subject: b43: N-PHY: allow applying separated workarounds per core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Newer devices need different workarounds for cores 0 and 1. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 125 ++++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 448c676da588..376dcf955579 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -2720,12 +2720,13 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) u8 ntab7_138_146[] = { 0x11, 0x11 }; u8 ntab7_133[] = { 0x77, 0x11, 0x11 }; - u16 lpf_ofdm_20mhz, lpf_ofdm_40mhz, lpf_11b; - u16 bcap_val, bcap_val_11b, bcap_val_11n_20, bcap_val_11n_40; - u16 scap_val, scap_val_11b, scap_val_11n_20, scap_val_11n_40; + u16 lpf_ofdm_20mhz[2], lpf_ofdm_40mhz[2], lpf_11b[2]; + u16 bcap_val; + u16 bcap_val_11b[2], bcap_val_11n_20[2], bcap_val_11n_40[2]; + u16 scap_val; + u16 scap_val_11b[2], scap_val_11n_20[2], scap_val_11n_40[2]; bool rccal_ovrd = false; - u16 rx2tx_lut_20_11b, rx2tx_lut_20_11n, rx2tx_lut_40_11n; u16 bias, conv, filt; u32 tmp32; @@ -2788,9 +2789,11 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) b43_phy_maskset(dev, B43_NPHY_EPS_OVERRIDEI_0, 0x3FFF, 0x4000); b43_phy_maskset(dev, B43_NPHY_EPS_OVERRIDEI_1, 0x3FFF, 0x4000); - lpf_ofdm_20mhz = b43_nphy_read_lpf_ctl(dev, 0x154); - lpf_ofdm_40mhz = b43_nphy_read_lpf_ctl(dev, 0x159); - lpf_11b = b43_nphy_read_lpf_ctl(dev, 0x152); + for (core = 0; core < 2; core++) { + lpf_ofdm_20mhz[core] = b43_nphy_read_lpf_ctl(dev, 0x154 + core * 0x10); + lpf_ofdm_40mhz[core] = b43_nphy_read_lpf_ctl(dev, 0x159 + core * 0x10); + lpf_11b[core] = b43_nphy_read_lpf_ctl(dev, 0x152 + core * 0x10); + } bcap_val = b43_radio_read(dev, R2057_RCCAL_BCAP_VAL); scap_val = b43_radio_read(dev, R2057_RCCAL_SCAP_VAL); @@ -2800,11 +2803,15 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) case 5: /* Check radio version (to be 0) by PHY rev for now */ if (phy->rev == 8 && b43_is_40mhz(dev)) { - scap_val_11b = scap_val; - bcap_val_11b = bcap_val; - scap_val_11n_20 = scap_val; - bcap_val_11n_20 = bcap_val; - scap_val_11n_40 = bcap_val_11n_40 = 0xc; + for (core = 0; core < 2; core++) { + scap_val_11b[core] = scap_val; + bcap_val_11b[core] = bcap_val; + scap_val_11n_20[core] = scap_val; + bcap_val_11n_20[core] = bcap_val; + scap_val_11n_40[core] = 0xc; + bcap_val_11n_40[core] = 0xc; + } + rccal_ovrd = true; } if (phy->rev == 9) { @@ -2813,69 +2820,79 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) break; case 7: case 8: - scap_val_11b = scap_val; - bcap_val_11b = bcap_val; - lpf_ofdm_20mhz = 4; - lpf_11b = 1; - if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { - scap_val_11n_20 = 0xc; - bcap_val_11n_20 = 0xc; - scap_val_11n_40 = 0xa; - bcap_val_11n_40 = 0xa; - } else { - scap_val_11n_20 = 0x14; - bcap_val_11n_20 = 0x14; - scap_val_11n_40 = 0xf; - bcap_val_11n_40 = 0xf; + for (core = 0; core < 2; core++) { + scap_val_11b[core] = scap_val; + bcap_val_11b[core] = bcap_val; + lpf_ofdm_20mhz[core] = 4; + lpf_11b[core] = 1; + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + scap_val_11n_20[core] = 0xc; + bcap_val_11n_20[core] = 0xc; + scap_val_11n_40[core] = 0xa; + bcap_val_11n_40[core] = 0xa; + } else { + scap_val_11n_20[core] = 0x14; + bcap_val_11n_20[core] = 0x14; + scap_val_11n_40[core] = 0xf; + bcap_val_11n_40[core] = 0xf; + } } + rccal_ovrd = true; break; } } else { if (phy->radio_rev == 5) { - lpf_ofdm_20mhz = 1; - lpf_ofdm_40mhz = 3; - scap_val_11b = scap_val; - bcap_val_11b = bcap_val; - scap_val_11n_20 = 0x11; - scap_val_11n_40 = 0x11; - bcap_val_11n_20 = 0x13; - bcap_val_11n_40 = 0x13; + for (core = 0; core < 2; core++) { + lpf_ofdm_20mhz[core] = 1; + lpf_ofdm_40mhz[core] = 3; + scap_val_11b[core] = scap_val; + bcap_val_11b[core] = bcap_val; + scap_val_11n_20[core] = 0x11; + scap_val_11n_40[core] = 0x11; + bcap_val_11n_20[core] = 0x13; + bcap_val_11n_40[core] = 0x13; + } + rccal_ovrd = true; } } if (rccal_ovrd) { + u16 rx2tx_lut_20_11b[2], rx2tx_lut_20_11n[2], rx2tx_lut_40_11n[2]; u8 rx2tx_lut_extra = 1; - rx2tx_lut_20_11b = (rx2tx_lut_extra << 13) | - (bcap_val_11b << 8) | - (scap_val_11b << 3) | - lpf_11b; - rx2tx_lut_20_11n = (rx2tx_lut_extra << 13) | - (bcap_val_11n_20 << 8) | - (scap_val_11n_20 << 3) | - lpf_ofdm_20mhz; - rx2tx_lut_40_11n = (rx2tx_lut_extra << 13) | - (bcap_val_11n_40 << 8) | - (scap_val_11n_40 << 3) | - lpf_ofdm_40mhz; + for (core = 0; core < 2; core++) { + rx2tx_lut_20_11b[core] = (rx2tx_lut_extra << 13) | + (bcap_val_11b[core] << 8) | + (scap_val_11b[core] << 3) | + lpf_11b[core]; + rx2tx_lut_20_11n[core] = (rx2tx_lut_extra << 13) | + (bcap_val_11n_20[core] << 8) | + (scap_val_11n_20[core] << 3) | + lpf_ofdm_20mhz[core]; + rx2tx_lut_40_11n[core] = (rx2tx_lut_extra << 13) | + (bcap_val_11n_40[core] << 8) | + (scap_val_11n_40[core] << 3) | + lpf_ofdm_40mhz[core]; + } + for (core = 0; core < 2; core++) { b43_ntab_write(dev, B43_NTAB16(7, 0x152 + core * 16), - rx2tx_lut_20_11b); + rx2tx_lut_20_11b[core]); b43_ntab_write(dev, B43_NTAB16(7, 0x153 + core * 16), - rx2tx_lut_20_11n); + rx2tx_lut_20_11n[core]); b43_ntab_write(dev, B43_NTAB16(7, 0x154 + core * 16), - rx2tx_lut_20_11n); + rx2tx_lut_20_11n[core]); b43_ntab_write(dev, B43_NTAB16(7, 0x155 + core * 16), - rx2tx_lut_40_11n); + rx2tx_lut_40_11n[core]); b43_ntab_write(dev, B43_NTAB16(7, 0x156 + core * 16), - rx2tx_lut_40_11n); + rx2tx_lut_40_11n[core]); b43_ntab_write(dev, B43_NTAB16(7, 0x157 + core * 16), - rx2tx_lut_40_11n); + rx2tx_lut_40_11n[core]); b43_ntab_write(dev, B43_NTAB16(7, 0x158 + core * 16), - rx2tx_lut_40_11n); + rx2tx_lut_40_11n[core]); b43_ntab_write(dev, B43_NTAB16(7, 0x159 + core * 16), - rx2tx_lut_40_11n); + rx2tx_lut_40_11n[core]); } b43_nphy_rf_ctl_override_rev7(dev, 16, 1, 3, false, 2); } -- cgit v1.2.3 From 8b343c3d6b42a649c6f970cad503367896276b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 19 Jul 2014 12:52:45 +0200 Subject: b43: N-PHY: add rev7+ workarounds for radio revs 9 and 14 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 79 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 376dcf955579..1052540c97f8 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -2722,9 +2722,9 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) u16 lpf_ofdm_20mhz[2], lpf_ofdm_40mhz[2], lpf_11b[2]; u16 bcap_val; - u16 bcap_val_11b[2], bcap_val_11n_20[2], bcap_val_11n_40[2]; + s16 bcap_val_11b[2], bcap_val_11n_20[2], bcap_val_11n_40[2]; u16 scap_val; - u16 scap_val_11b[2], scap_val_11n_20[2], scap_val_11n_40[2]; + s16 scap_val_11b[2], scap_val_11n_20[2], scap_val_11n_40[2]; bool rccal_ovrd = false; u16 bias, conv, filt; @@ -2799,6 +2799,8 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) scap_val = b43_radio_read(dev, R2057_RCCAL_SCAP_VAL); if (b43_nphy_ipa(dev)) { + bool ghz2 = b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ; + switch (phy->radio_rev) { case 5: /* Check radio version (to be 0) by PHY rev for now */ @@ -2838,6 +2840,58 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) } } + rccal_ovrd = true; + break; + case 9: + for (core = 0; core < 2; core++) { + bcap_val_11b[core] = bcap_val; + scap_val_11b[core] = scap_val; + lpf_11b[core] = 1; + + if (ghz2) { + bcap_val_11n_20[core] = bcap_val + 13; + scap_val_11n_20[core] = scap_val + 15; + } else { + bcap_val_11n_20[core] = bcap_val + 14; + scap_val_11n_20[core] = scap_val + 15; + } + lpf_ofdm_20mhz[core] = 4; + + if (ghz2) { + bcap_val_11n_40[core] = bcap_val - 7; + scap_val_11n_40[core] = scap_val - 5; + } else { + bcap_val_11n_40[core] = bcap_val + 2; + scap_val_11n_40[core] = scap_val + 4; + } + lpf_ofdm_40mhz[core] = 4; + } + + rccal_ovrd = true; + break; + case 14: + for (core = 0; core < 2; core++) { + bcap_val_11b[core] = bcap_val; + scap_val_11b[core] = scap_val; + lpf_11b[core] = 1; + } + + bcap_val_11n_20[0] = bcap_val + 20; + scap_val_11n_20[0] = scap_val + 20; + lpf_ofdm_20mhz[0] = 3; + + bcap_val_11n_20[1] = bcap_val + 16; + scap_val_11n_20[1] = scap_val + 16; + lpf_ofdm_20mhz[1] = 3; + + bcap_val_11n_40[0] = bcap_val + 20; + scap_val_11n_40[0] = scap_val + 20; + lpf_ofdm_40mhz[0] = 4; + + bcap_val_11n_40[1] = bcap_val + 10; + scap_val_11n_40[1] = scap_val + 10; + lpf_ofdm_40mhz[1] = 4; + rccal_ovrd = true; break; } @@ -2862,6 +2916,13 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) u8 rx2tx_lut_extra = 1; for (core = 0; core < 2; core++) { + bcap_val_11b[core] = clamp_val(bcap_val_11b[core], 0, 0x1f); + scap_val_11b[core] = clamp_val(scap_val_11b[core], 0, 0x1f); + bcap_val_11n_20[core] = clamp_val(bcap_val_11n_20[core], 0, 0x1f); + scap_val_11n_20[core] = clamp_val(scap_val_11n_20[core], 0, 0x1f); + bcap_val_11n_40[core] = clamp_val(bcap_val_11n_40[core], 0, 0x1f); + scap_val_11n_40[core] = clamp_val(scap_val_11n_40[core], 0, 0x1f); + rx2tx_lut_20_11b[core] = (rx2tx_lut_extra << 13) | (bcap_val_11b[core] << 8) | (scap_val_11b[core] << 3) | @@ -2982,6 +3043,20 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) b43_radio_write(dev, 0xE8, 0x16); } break; + case 14: + for (core = 0; core < 2; core++) { + int o = core ? 0x85 : 0; + + b43_radio_write(dev, o + R2057_IPA2G_CASCONV_CORE0, 0x13); + b43_radio_write(dev, o + R2057_TXMIX2G_TUNE_BOOST_PU_CORE0, 0x21); + b43_radio_write(dev, o + R2057_IPA2G_BIAS_FILTER_CORE0, 0xff); + b43_radio_write(dev, o + R2057_PAD2G_IDACS_CORE0, 0x88); + b43_radio_write(dev, o + R2057_PAD2G_TUNE_PUS_CORE0, 0x23); + b43_radio_write(dev, o + R2057_IPA2G_IMAIN_CORE0, 0x16); + b43_radio_write(dev, o + R2057_PAD_BIAS_FILTER_BWS_CORE0, 0x3e); + b43_radio_write(dev, o + R2057_BACKUP1_CORE0, 0x10); + } + break; } } else { u16 freq = phy->chandef->chan->center_freq; -- cgit v1.2.3 From 5af976295eab35b3bb4ad1fc9ed24b2d12930f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 19 Jul 2014 12:52:46 +0200 Subject: b43: N-PHY: final fixes to rev7+ workarounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 1052540c97f8..11d754360d71 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -2729,6 +2729,8 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) u16 bias, conv, filt; + u32 noise_tbl[2]; + u32 tmp32; u8 core; @@ -2955,9 +2957,10 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) b43_ntab_write(dev, B43_NTAB16(7, 0x159 + core * 16), rx2tx_lut_40_11n[core]); } - b43_nphy_rf_ctl_override_rev7(dev, 16, 1, 3, false, 2); } + b43_phy_write(dev, 0x32F, 0x3); + if (phy->radio_rev == 4 || phy->radio_rev == 6) b43_nphy_rf_ctl_override_rev7(dev, 4, 1, 3, false, 0); @@ -3104,8 +3107,8 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x1); b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x1); b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x1); - b43_ntab_write(dev, B43_NTAB16(8, 0x05), 0x20); - b43_ntab_write(dev, B43_NTAB16(8, 0x15), 0x20); + b43_ntab_write(dev, B43_NTAB16(8, 0x05), 0); + b43_ntab_write(dev, B43_NTAB16(8, 0x15), 0); b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x4); b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, ~0x4); @@ -3116,20 +3119,20 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_ENDROP_TLEN, 0x2); b43_ntab_write(dev, B43_NTAB32(16, 0x100), 20); - b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x138), 2, ntab7_138_146); + b43_ntab_write_bulk(dev, B43_NTAB8(7, 0x138), 2, ntab7_138_146); b43_ntab_write(dev, B43_NTAB16(7, 0x141), 0x77); - b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x133), 3, ntab7_133); - b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x146), 2, ntab7_138_146); + b43_ntab_write_bulk(dev, B43_NTAB8(7, 0x133), 3, ntab7_133); + b43_ntab_write_bulk(dev, B43_NTAB8(7, 0x146), 2, ntab7_138_146); b43_ntab_write(dev, B43_NTAB16(7, 0x123), 0x77); b43_ntab_write(dev, B43_NTAB16(7, 0x12A), 0x77); - if (!b43_is_40mhz(dev)) { - b43_ntab_write(dev, B43_NTAB32(16, 0x03), 0x18D); - b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x18D); - } else { - b43_ntab_write(dev, B43_NTAB32(16, 0x03), 0x14D); - b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x14D); - } + b43_ntab_read_bulk(dev, B43_NTAB32(16, 0x02), 1, noise_tbl); + noise_tbl[1] = b43_is_40mhz(dev) ? 0x14D : 0x18D; + b43_ntab_write_bulk(dev, B43_NTAB32(16, 0x02), 2, noise_tbl); + + b43_ntab_read_bulk(dev, B43_NTAB32(16, 0x7E), 1, noise_tbl); + noise_tbl[1] = b43_is_40mhz(dev) ? 0x14D : 0x18D; + b43_ntab_write_bulk(dev, B43_NTAB32(16, 0x7E), 2, noise_tbl); b43_nphy_gain_ctl_workarounds(dev); -- cgit v1.2.3 From c11082f0c00acde7c9049e92dbcafd1f73fb60e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 19 Jul 2014 12:52:47 +0200 Subject: b43: enable radio 0x2057 rev 14 support (AKA BCM43217) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 3e127be06bfb..73f629ccfa0f 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4512,7 +4512,8 @@ static int b43_phy_versioning(struct b43_wldev *dev) if (radio_ver != 0x2055 && radio_ver != 0x2056 && radio_ver != 0x2057) unsupported = 1; - if (radio_ver == 0x2057 && !(radio_rev == 9)) + if (radio_ver == 0x2057 && + !(radio_rev == 9 || radio_rev == 14)) unsupported = 1; break; case B43_PHYTYPE_LP: @@ -5152,7 +5153,8 @@ static int b43_setup_bands(struct b43_wldev *dev, bool limited_2g; /* We don't support all 2 GHz channels on some devices */ - limited_2g = phy->radio_ver == 0x2057 && phy->radio_rev == 9; + limited_2g = phy->radio_ver == 0x2057 && + (phy->radio_rev == 9 || phy->radio_rev == 14); if (have_2ghz_phy) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = limited_2g ? -- cgit v1.2.3 From 16e754535a69152c12494da18eb3ea7947f5a434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 20 Jul 2014 12:57:45 +0200 Subject: b43: extract one more radio parameter: version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some radios may share the same ID and revision but differ by a version. E.g. radio in BCM5357B0 is version 1 and requires specific handling. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 46 ++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 73f629ccfa0f..47b6fa5fa5b2 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4385,8 +4385,9 @@ static int b43_phy_versioning(struct b43_wldev *dev) u8 phy_type; u8 phy_rev; u16 radio_manuf; - u16 radio_ver; + u16 radio_id; u16 radio_rev; + u8 radio_ver; int unsupported = 0; /* Get PHY versioning */ @@ -4452,7 +4453,9 @@ static int b43_phy_versioning(struct b43_wldev *dev) radio_rev = b43_read16(dev, B43_MMIO_RADIO24_DATA); b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 1); - radio_ver = b43_read16(dev, B43_MMIO_RADIO24_DATA); + radio_id = b43_read16(dev, B43_MMIO_RADIO24_DATA); + + radio_ver = 0; /* Is there version somewhere? */ } else if (core_rev >= 24) { u16 radio24[3]; @@ -4461,12 +4464,10 @@ static int b43_phy_versioning(struct b43_wldev *dev) radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA); } - /* Broadcom uses "id" for our "ver" and has separated "ver" */ - /* radio_ver = (radio24[0] & 0xF0) >> 4; */ - radio_manuf = 0x17F; - radio_ver = (radio24[2] << 8) | radio24[1]; + radio_id = (radio24[2] << 8) | radio24[1]; radio_rev = (radio24[0] & 0xF); + radio_ver = (radio24[0] & 0xF0) >> 4; } else { if (dev->dev->chip_id == 0x4317) { if (dev->dev->chip_rev == 0) @@ -4485,15 +4486,16 @@ static int b43_phy_versioning(struct b43_wldev *dev) << 16; } radio_manuf = (tmp & 0x00000FFF); - radio_ver = (tmp & 0x0FFFF000) >> 12; + radio_id = (tmp & 0x0FFFF000) >> 12; radio_rev = (tmp & 0xF0000000) >> 28; + radio_ver = 0; /* Probably not available on old hw */ } if (radio_manuf != 0x17F /* Broadcom */) unsupported = 1; switch (phy_type) { case B43_PHYTYPE_A: - if (radio_ver != 0x2060) + if (radio_id != 0x2060) unsupported = 1; if (radio_rev != 1) unsupported = 1; @@ -4501,31 +4503,31 @@ static int b43_phy_versioning(struct b43_wldev *dev) unsupported = 1; break; case B43_PHYTYPE_B: - if ((radio_ver & 0xFFF0) != 0x2050) + if ((radio_id & 0xFFF0) != 0x2050) unsupported = 1; break; case B43_PHYTYPE_G: - if (radio_ver != 0x2050) + if (radio_id != 0x2050) unsupported = 1; break; case B43_PHYTYPE_N: - if (radio_ver != 0x2055 && radio_ver != 0x2056 && - radio_ver != 0x2057) + if (radio_id != 0x2055 && radio_id != 0x2056 && + radio_id != 0x2057) unsupported = 1; - if (radio_ver == 0x2057 && + if (radio_id == 0x2057 && !(radio_rev == 9 || radio_rev == 14)) unsupported = 1; break; case B43_PHYTYPE_LP: - if (radio_ver != 0x2062 && radio_ver != 0x2063) + if (radio_id != 0x2062 && radio_id != 0x2063) unsupported = 1; break; case B43_PHYTYPE_HT: - if (radio_ver != 0x2059) + if (radio_id != 0x2059) unsupported = 1; break; case B43_PHYTYPE_LCN: - if (radio_ver != 0x2064) + if (radio_id != 0x2064) unsupported = 1; break; default: @@ -4533,15 +4535,17 @@ static int b43_phy_versioning(struct b43_wldev *dev) } if (unsupported) { b43err(dev->wl, - "FOUND UNSUPPORTED RADIO (Manuf 0x%X, ID 0x%X, Revision %u)\n", - radio_manuf, radio_ver, radio_rev); + "FOUND UNSUPPORTED RADIO (Manuf 0x%X, ID 0x%X, Revision %u, Version %u)\n", + radio_manuf, radio_id, radio_rev, radio_ver); return -EOPNOTSUPP; } - b43info(dev->wl, "Found Radio: Manuf 0x%X, ID 0x%X, Revision %u\n", - radio_manuf, radio_ver, radio_rev); + b43info(dev->wl, + "Found Radio: Manuf 0x%X, ID 0x%X, Revision %u, Version %u\n", + radio_manuf, radio_id, radio_rev, radio_ver); + /* FIXME: b43 treats "id" as "ver" and ignores the real "ver" */ phy->radio_manuf = radio_manuf; - phy->radio_ver = radio_ver; + phy->radio_ver = radio_id; phy->radio_rev = radio_rev; phy->analog = analog_type; -- cgit v1.2.3 From c29a380e4a8157f8bf6a91c216a77439a293c93d Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 21 Jul 2014 21:03:10 +0300 Subject: ath10k: prevent endless pci rx loop It was possible to enter an endless loop while processing a single pci copy engine pipe. This could effectively render ath10k incapable of responding to any requests. An example case when this could happen is when firmware generates a lot of events, e.g. spectral scan phyerr via WMI. Reported-by: Janusz Dziedzic Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 06840d101c45..0ffff205478d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -726,18 +726,12 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) unsigned int nbytes, max_nbytes; unsigned int transfer_id; unsigned int flags; - int err; + int err, num_replenish = 0; while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, &ce_data, &nbytes, &transfer_id, &flags) == 0) { - err = ath10k_pci_post_rx_pipe(pipe_info, 1); - if (unlikely(err)) { - /* FIXME: retry */ - ath10k_warn("failed to replenish CE rx ring %d: %d\n", - pipe_info->pipe_num, err); - } - + num_replenish++; skb = transfer_context; max_nbytes = skb->len + skb_tailroom(skb); dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, @@ -753,6 +747,13 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) skb_put(skb, nbytes); cb->rx_completion(ar, skb, pipe_info->pipe_num); } + + err = ath10k_pci_post_rx_pipe(pipe_info, num_replenish); + if (unlikely(err)) { + /* FIXME: retry */ + ath10k_warn("failed to replenish CE rx ring %d (%d bufs): %d\n", + pipe_info->pipe_num, num_replenish, err); + } } static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, -- cgit v1.2.3 From f697267f827516fba4d0c325ed1db1e72f402f11 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 15 Jun 2014 16:03:55 +0300 Subject: iwlwifi: mvm: teardown TDLS peers during chan-switch and AP DCM The DCM condition was not checked well for channel switch in both AP and station scenarios. Teardown was also not done for AP/GO DCM. Add the missing checks. Reported-by: Peer, Ilan Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 52 +++++++++++++++++------------ 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 6639341b2c2c..0d6a8b768a68 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1406,6 +1406,28 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, } #endif +static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + int i; + + lockdep_assert_held(&mvm->mutex); + + for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], + lockdep_is_held(&mvm->mutex)); + if (!sta || IS_ERR(sta) || !sta->tdls) + continue; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, + NL80211_TDLS_TEARDOWN, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, + GFP_KERNEL); + } +} + static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1600,6 +1622,10 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, iwl_mvm_bt_coex_vif_change(mvm); + /* we don't support TDLS during DCM */ + if (iwl_mvm_phy_ctx_count(mvm) > 1) + iwl_mvm_teardown_tdls_peers(mvm); + mutex_unlock(&mvm->mutex); return 0; @@ -1947,28 +1973,6 @@ static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, iwl_mvm_power_update_mac(mvm); } -static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) -{ - struct ieee80211_sta *sta; - struct iwl_mvm_sta *mvmsta; - int i; - - lockdep_assert_held(&mvm->mutex); - - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], - lockdep_is_held(&mvm->mutex)); - if (!sta || IS_ERR(sta) || !sta->tdls) - continue; - - mvmsta = iwl_mvm_sta_from_mac80211(sta); - ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, - NL80211_TDLS_TEARDOWN, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, - GFP_KERNEL); - } -} - static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -2846,6 +2850,10 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, goto out_remove; } + /* we don't support TDLS during DCM - can be caused by channel switch */ + if (iwl_mvm_phy_ctx_count(mvm) > 1) + iwl_mvm_teardown_tdls_peers(mvm); + goto out; out_remove: -- cgit v1.2.3 From 723189faca78f2b70fcf9088f056a2440986cc45 Mon Sep 17 00:00:00 2001 From: David Laight Date: Tue, 22 Jul 2014 08:59:08 +0000 Subject: net: sctp: Open out the check for Nagle The check for Nagle contains 6 separate checks all of which must be true before a data packet is delayed. Separate out each into its own 'if (test) return SCTP_XMIT_OK' so that the reasons can be individually described. Also return directly with SCTP_XMIT_RWND_FULL. Delete the now-unused 'retval' variable and 'finish' label from sctp_packet_can_append_data(). Signed-off-by: David Laight Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/output.c | 69 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/net/sctp/output.c b/net/sctp/output.c index 01ab8e0723f0..f3bf0ae244df 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -633,7 +633,6 @@ nomem: static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, struct sctp_chunk *chunk) { - sctp_xmit_t retval = SCTP_XMIT_OK; size_t datasize, rwnd, inflight, flight_size; struct sctp_transport *transport = packet->transport; struct sctp_association *asoc = transport->asoc; @@ -658,15 +657,11 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, datasize = sctp_data_size(chunk); - if (datasize > rwnd) { - if (inflight > 0) { - /* We have (at least) one data chunk in flight, - * so we can't fall back to rule 6.1 B). - */ - retval = SCTP_XMIT_RWND_FULL; - goto finish; - } - } + if (datasize > rwnd && inflight > 0) + /* We have (at least) one data chunk in flight, + * so we can't fall back to rule 6.1 B). + */ + return SCTP_XMIT_RWND_FULL; /* RFC 2960 6.1 Transmission of DATA Chunks * @@ -680,36 +675,44 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, * When a Fast Retransmit is being performed the sender SHOULD * ignore the value of cwnd and SHOULD NOT delay retransmission. */ - if (chunk->fast_retransmit != SCTP_NEED_FRTX) - if (flight_size >= transport->cwnd) { - retval = SCTP_XMIT_RWND_FULL; - goto finish; - } + if (chunk->fast_retransmit != SCTP_NEED_FRTX && + flight_size >= transport->cwnd) + return SCTP_XMIT_RWND_FULL; /* Nagle's algorithm to solve small-packet problem: * Inhibit the sending of new chunks when new outgoing data arrives * if any previously transmitted data on the connection remains * unacknowledged. */ - if (!sctp_sk(asoc->base.sk)->nodelay && sctp_packet_empty(packet) && - inflight && sctp_state(asoc, ESTABLISHED)) { - unsigned int max = transport->pathmtu - packet->overhead; - unsigned int len = chunk->skb->len + q->out_qlen; - - /* Check whether this chunk and all the rest of pending - * data will fit or delay in hopes of bundling a full - * sized packet. - * Don't delay large message writes that may have been - * fragmeneted into small peices. - */ - if ((len < max) && chunk->msg->can_delay) { - retval = SCTP_XMIT_NAGLE_DELAY; - goto finish; - } - } -finish: - return retval; + if (sctp_sk(asoc->base.sk)->nodelay) + /* Nagle disabled */ + return SCTP_XMIT_OK; + + if (!sctp_packet_empty(packet)) + /* Append to packet */ + return SCTP_XMIT_OK; + + if (inflight == 0) + /* Nothing unacked */ + return SCTP_XMIT_OK; + + if (!sctp_state(asoc, ESTABLISHED)) + return SCTP_XMIT_OK; + + /* Check whether this chunk and all the rest of pending data will fit + * or delay in hopes of bundling a full sized packet. + */ + if (chunk->skb->len + q->out_qlen >= transport->pathmtu - packet->overhead) + /* Enough data queued to fill a packet */ + return SCTP_XMIT_OK; + + /* Don't delay large message writes that may have been fragmented */ + if (!chunk->msg->can_delay) + return SCTP_XMIT_OK; + + /* Defer until all data acked or packet full */ + return SCTP_XMIT_NAGLE_DELAY; } /* This private function does management things when adding DATA chunk */ -- cgit v1.2.3 From 526cbef778ad8e763b95608d7e5c988b96bf4af5 Mon Sep 17 00:00:00 2001 From: David Laight Date: Tue, 22 Jul 2014 08:59:14 +0000 Subject: net: sctp: Rename SCTP_XMIT_NAGLE_DELAY to SCTP_XMIT_DELAY MSG_MORE and 'corking' a socket would require that the transmit of a data chunk be delayed. Rename the return value to be less specific. Signed-off-by: David Laight Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/sctp/constants.h | 2 +- net/sctp/output.c | 4 ++-- net/sctp/outqueue.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 307728f622ef..8c337cd0e1e4 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -311,7 +311,7 @@ typedef enum { SCTP_XMIT_OK, SCTP_XMIT_PMTU_FULL, SCTP_XMIT_RWND_FULL, - SCTP_XMIT_NAGLE_DELAY, + SCTP_XMIT_DELAY, } sctp_xmit_t; /* These are the commands for manipulating transports. */ diff --git a/net/sctp/output.c b/net/sctp/output.c index f3bf0ae244df..1eedba5195a3 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -178,7 +178,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet, case SCTP_XMIT_RWND_FULL: case SCTP_XMIT_OK: - case SCTP_XMIT_NAGLE_DELAY: + case SCTP_XMIT_DELAY: break; } @@ -712,7 +712,7 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, return SCTP_XMIT_OK; /* Defer until all data acked or packet full */ - return SCTP_XMIT_NAGLE_DELAY; + return SCTP_XMIT_DELAY; } /* This private function does management things when adding DATA chunk */ diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index d31435e559b2..7e8f0a117106 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -629,7 +629,7 @@ redo: done = 1; break; - case SCTP_XMIT_NAGLE_DELAY: + case SCTP_XMIT_DELAY: /* Send this packet. */ error = sctp_packet_transmit(pkt); @@ -1015,7 +1015,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) switch (status) { case SCTP_XMIT_PMTU_FULL: case SCTP_XMIT_RWND_FULL: - case SCTP_XMIT_NAGLE_DELAY: + case SCTP_XMIT_DELAY: /* We could not append this chunk, so put * the chunk back on the output queue. */ -- cgit v1.2.3 From 0bec8c88dc2b076a0a4a0437e1e878026cbaccb4 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 22 Jul 2014 12:06:23 +0200 Subject: net: skbuff: Use ALIGN macro instead of open coding it Use ALIGN from linux/kernel.h to define SKB_DATA_ALIGN instead of open coding it. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller --- include/linux/skbuff.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 369430340ed9..b613557132b9 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -112,8 +112,7 @@ #define CHECKSUM_COMPLETE 2 #define CHECKSUM_PARTIAL 3 -#define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES - 1)) & \ - ~(SMP_CACHE_BYTES - 1)) +#define SKB_DATA_ALIGN(X) ALIGN(X, SMP_CACHE_BYTES) #define SKB_WITH_OVERHEAD(X) \ ((X) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) #define SKB_MAX_ORDER(X, ORDER) \ -- cgit v1.2.3 From 35630df68d6030daf12dde12ed07bbe26324e6ac Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sun, 25 May 2014 22:35:38 +0200 Subject: NFC: st21nfcb: Add driver for STMicroelectronics ST21NFCB NFC chip Add driver for STMicroelectronics ST21NFCB NFC controller. ST21NFCB is using NCI protocol and a proprietary low level transport protocol called NDLC used on top. NDLC: The protocol defines 2 types of frame: - One type carrying NCI data (referred as DATAFRAME frames). - One type carrying protocol information used for flow control and error control mechanisms (referred as SUPERVISOR frames). After each frame transmission to the NFC controller, the device host SHALL waitfor an ACK (SUPERVISOR frame) reception before sending a new frame. The NFC controller MAY send a frame at anytime to the device host. The NFC controller MAY send a specific WAIT supervisor frame to indicate to device host that a NCI data packet has been received but that it could take significant time before the NFC controller sends an ACK and thus allows next data reception. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/Kconfig | 2 +- drivers/nfc/Makefile | 3 +- drivers/nfc/st21nfcb/Kconfig | 22 ++ drivers/nfc/st21nfcb/Makefile | 8 + drivers/nfc/st21nfcb/i2c.c | 462 +++++++++++++++++++++++++++++++++ drivers/nfc/st21nfcb/ndlc.c | 298 +++++++++++++++++++++ drivers/nfc/st21nfcb/ndlc.h | 55 ++++ drivers/nfc/st21nfcb/st21nfcb.c | 129 +++++++++ drivers/nfc/st21nfcb/st21nfcb.h | 38 +++ include/linux/platform_data/st21nfcb.h | 32 +++ 10 files changed, 1047 insertions(+), 2 deletions(-) create mode 100644 drivers/nfc/st21nfcb/Kconfig create mode 100644 drivers/nfc/st21nfcb/Makefile create mode 100644 drivers/nfc/st21nfcb/i2c.c create mode 100644 drivers/nfc/st21nfcb/ndlc.c create mode 100644 drivers/nfc/st21nfcb/ndlc.h create mode 100644 drivers/nfc/st21nfcb/st21nfcb.c create mode 100644 drivers/nfc/st21nfcb/st21nfcb.h create mode 100644 include/linux/platform_data/st21nfcb.h diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 26c66a126551..7929fac13e1c 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -72,5 +72,5 @@ source "drivers/nfc/pn544/Kconfig" source "drivers/nfc/microread/Kconfig" source "drivers/nfc/nfcmrvl/Kconfig" source "drivers/nfc/st21nfca/Kconfig" - +source "drivers/nfc/st21nfcb/Kconfig" endmenu diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index 23225b0287fd..6b23a2c6e34a 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_NFC_SIM) += nfcsim.o obj-$(CONFIG_NFC_PORT100) += port100.o obj-$(CONFIG_NFC_MRVL) += nfcmrvl/ obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o -obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/ +obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/ +obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb/ ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG diff --git a/drivers/nfc/st21nfcb/Kconfig b/drivers/nfc/st21nfcb/Kconfig new file mode 100644 index 000000000000..e0322dd03a70 --- /dev/null +++ b/drivers/nfc/st21nfcb/Kconfig @@ -0,0 +1,22 @@ +config NFC_ST21NFCB + tristate "STMicroelectronics ST21NFCB NFC driver" + depends on NFC_NCI + default n + ---help--- + STMicroelectronics ST21NFCB core driver. It implements the chipset + NCI logic and hooks into the NFC kernel APIs. Physical layers will + register against it. + + To compile this driver as a module, choose m here. The module will + be called st21nfcb. + Say N if unsure. + +config NFC_ST21NFCB_I2C + tristate "NFC ST21NFCB i2c support" + depends on NFC_ST21NFCB && I2C + ---help--- + This module adds support for the STMicroelectronics st21nfcb i2c interface. + Select this if your platform is using the i2c bus. + + If you choose to build a module, it'll be called st21nfcb_i2c. + Say N if unsure. diff --git a/drivers/nfc/st21nfcb/Makefile b/drivers/nfc/st21nfcb/Makefile new file mode 100644 index 000000000000..13d9f03b2fea --- /dev/null +++ b/drivers/nfc/st21nfcb/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for ST21NFCB NCI based NFC driver +# + +st21nfcb_i2c-objs = i2c.o + +obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb.o ndlc.o +obj-$(CONFIG_NFC_ST21NFCB_I2C) += st21nfcb_i2c.o diff --git a/drivers/nfc/st21nfcb/i2c.c b/drivers/nfc/st21nfcb/i2c.c new file mode 100644 index 000000000000..0f690baaef7a --- /dev/null +++ b/drivers/nfc/st21nfcb/i2c.c @@ -0,0 +1,462 @@ +/* + * I2C Link Layer for ST21NFCB NCI based Driver + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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, see . + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ndlc.h" + +#define DRIVER_DESC "NCI NFC driver for ST21NFCB" + +/* ndlc header */ +#define ST21NFCB_FRAME_HEADROOM 1 +#define ST21NFCB_FRAME_TAILROOM 0 + +#define ST21NFCB_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */ +#define ST21NFCB_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */ + +#define ST21NFCB_NCI_I2C_DRIVER_NAME "st21nfcb_nci_i2c" + +static struct i2c_device_id st21nfcb_nci_i2c_id_table[] = { + {ST21NFCB_NCI_DRIVER_NAME, 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, st21nfcb_nci_i2c_id_table); + +struct st21nfcb_i2c_phy { + struct i2c_client *i2c_dev; + struct llt_ndlc *ndlc; + + unsigned int gpio_irq; + unsigned int gpio_reset; + unsigned int irq_polarity; + + int powered; + + /* + * < 0 if hardware error occured (e.g. i2c err) + * and prevents normal operation. + */ + int hard_fault; +}; + +#define I2C_DUMP_SKB(info, skb) \ +do { \ + pr_debug("%s:\n", info); \ + print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET, \ + 16, 1, (skb)->data, (skb)->len, 0); \ +} while (0) + +static int st21nfcb_nci_i2c_enable(void *phy_id) +{ + struct st21nfcb_i2c_phy *phy = phy_id; + + gpio_set_value(phy->gpio_reset, 0); + usleep_range(10000, 15000); + gpio_set_value(phy->gpio_reset, 1); + phy->powered = 1; + usleep_range(80000, 85000); + + return 0; +} + +static void st21nfcb_nci_i2c_disable(void *phy_id) +{ + struct st21nfcb_i2c_phy *phy = phy_id; + + pr_info("\n"); + + phy->powered = 0; + /* reset chip in order to flush clf */ + gpio_set_value(phy->gpio_reset, 0); + usleep_range(10000, 15000); + gpio_set_value(phy->gpio_reset, 1); +} + +static void st21nfcb_nci_remove_header(struct sk_buff *skb) +{ + skb_pull(skb, ST21NFCB_FRAME_HEADROOM); +} + +/* + * Writing a frame must not return the number of written bytes. + * It must return either zero for success, or <0 for error. + * In addition, it must not alter the skb + */ +static int st21nfcb_nci_i2c_write(void *phy_id, struct sk_buff *skb) +{ + int r = -1; + struct st21nfcb_i2c_phy *phy = phy_id; + struct i2c_client *client = phy->i2c_dev; + + I2C_DUMP_SKB("st21nfcb_nci_i2c_write", skb); + + if (phy->hard_fault != 0) + return phy->hard_fault; + + r = i2c_master_send(client, skb->data, skb->len); + if (r == -EREMOTEIO) { /* Retry, chip was in standby */ + usleep_range(1000, 4000); + r = i2c_master_send(client, skb->data, skb->len); + } + + if (r >= 0) { + if (r != skb->len) + r = -EREMOTEIO; + else + r = 0; + } + + st21nfcb_nci_remove_header(skb); + + return r; +} + +/* + * Reads an ndlc frame and returns it in a newly allocated sk_buff. + * returns: + * frame size : if received frame is complete (find ST21NFCB_SOF_EOF at + * end of read) + * -EAGAIN : if received frame is incomplete (not find ST21NFCB_SOF_EOF + * at end of read) + * -EREMOTEIO : i2c read error (fatal) + * -EBADMSG : frame was incorrect and discarded + * (value returned from st21nfcb_nci_i2c_repack) + * -EIO : if no ST21NFCB_SOF_EOF is found after reaching + * the read length end sequence + */ +static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy, + struct sk_buff **skb) +{ + int r; + u8 len; + u8 buf[ST21NFCB_NCI_I2C_MAX_SIZE]; + struct i2c_client *client = phy->i2c_dev; + + r = i2c_master_recv(client, buf, 4); + if (r == -EREMOTEIO) { /* Retry, chip was in standby */ + usleep_range(1000, 4000); + r = i2c_master_recv(client, buf, 4); + } else if (r != 4) { + nfc_err(&client->dev, "cannot read ndlc & nci header\n"); + return -EREMOTEIO; + } + + len = be16_to_cpu(*(__be16 *) (buf + 2)); + if (len > ST21NFCB_NCI_I2C_MAX_SIZE) { + nfc_err(&client->dev, "invalid frame len\n"); + return -EBADMSG; + } + + *skb = alloc_skb(4 + len, GFP_KERNEL); + if (*skb == NULL) + return -ENOMEM; + + skb_reserve(*skb, 4); + skb_put(*skb, 4); + memcpy((*skb)->data, buf, 4); + + if (!len) + return 0; + + r = i2c_master_recv(client, buf, len); + if (r != len) { + kfree_skb(*skb); + return -EREMOTEIO; + } + + skb_put(*skb, len); + memcpy((*skb)->data + 4, buf, len); + + I2C_DUMP_SKB("i2c frame read", *skb); + + return 0; +} + +/* + * Reads an ndlc frame from the chip. + * + * On ST21NFCB, IRQ goes in idle state when read starts. + */ +static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id) +{ + struct st21nfcb_i2c_phy *phy = phy_id; + struct i2c_client *client; + struct sk_buff *skb = NULL; + int r; + + if (!phy || irq != phy->i2c_dev->irq) { + WARN_ON_ONCE(1); + return IRQ_NONE; + } + + client = phy->i2c_dev; + dev_dbg(&client->dev, "IRQ\n"); + + if (phy->hard_fault) + return IRQ_HANDLED; + + if (!phy->powered) { + st21nfcb_nci_i2c_disable(phy); + return IRQ_HANDLED; + } + + r = st21nfcb_nci_i2c_read(phy, &skb); + if (r == -EREMOTEIO) { + phy->hard_fault = r; + ndlc_recv(phy->ndlc, NULL); + return IRQ_HANDLED; + } else if (r == -ENOMEM || r == -EBADMSG) { + return IRQ_HANDLED; + } + + ndlc_recv(phy->ndlc, skb); + + return IRQ_HANDLED; +} + +static struct nfc_phy_ops i2c_phy_ops = { + .write = st21nfcb_nci_i2c_write, + .enable = st21nfcb_nci_i2c_enable, + .disable = st21nfcb_nci_i2c_disable, +}; + +#ifdef CONFIG_OF +static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client) +{ + struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client); + struct device_node *pp; + int gpio; + int r; + + pp = client->dev.of_node; + if (!pp) + return -ENODEV; + + /* Get GPIO from device tree */ + gpio = of_get_named_gpio(pp, "reset-gpios", 0); + if (gpio < 0) { + nfc_err(&client->dev, + "Failed to retrieve reset-gpios from device tree\n"); + return gpio; + } + + /* GPIO request and configuration */ + r = devm_gpio_request(&client->dev, gpio, "clf_reset"); + if (r) { + nfc_err(&client->dev, "Failed to request reset pin\n"); + return -ENODEV; + } + + r = gpio_direction_output(gpio, 1); + if (r) { + nfc_err(&client->dev, + "Failed to set reset pin direction as output\n"); + return -ENODEV; + } + phy->gpio_reset = gpio; + + /* IRQ */ + r = irq_of_parse_and_map(pp, 0); + if (r < 0) { + nfc_err(&client->dev, + "Unable to get irq, error: %d\n", r); + return r; + } + + phy->irq_polarity = irq_get_trigger_type(r); + client->irq = r; + + return 0; +} +#else +static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client) +{ + return -ENODEV; +} +#endif + +static int st21nfcb_nci_i2c_request_resources(struct i2c_client *client) +{ + struct st21nfcb_nfc_platform_data *pdata; + struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client); + int r; + int irq; + + pdata = client->dev.platform_data; + if (pdata == NULL) { + nfc_err(&client->dev, "No platform data\n"); + return -EINVAL; + } + + /* store for later use */ + phy->gpio_irq = pdata->gpio_irq; + phy->gpio_reset = pdata->gpio_reset; + phy->irq_polarity = pdata->irq_polarity; + + r = devm_gpio_request(&client->dev, phy->gpio_irq, "wake_up"); + if (r) { + pr_err("%s : gpio_request failed\n", __FILE__); + return -ENODEV; + } + + r = gpio_direction_input(phy->gpio_irq); + if (r) { + pr_err("%s : gpio_direction_input failed\n", __FILE__); + return -ENODEV; + } + + r = devm_gpio_request(&client->dev, + phy->gpio_reset, "clf_reset"); + if (r) { + pr_err("%s : reset gpio_request failed\n", __FILE__); + return -ENODEV; + } + + r = gpio_direction_output(phy->gpio_reset, 1); + if (r) { + pr_err("%s : reset gpio_direction_output failed\n", + __FILE__); + return -ENODEV; + } + + /* IRQ */ + irq = gpio_to_irq(phy->gpio_irq); + if (irq < 0) { + nfc_err(&client->dev, + "Unable to get irq number for GPIO %d error %d\n", + phy->gpio_irq, r); + return -ENODEV; + } + client->irq = irq; + + return 0; +} + +static int st21nfcb_nci_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct st21nfcb_i2c_phy *phy; + struct st21nfcb_nfc_platform_data *pdata; + int r; + + dev_dbg(&client->dev, "%s\n", __func__); + dev_dbg(&client->dev, "IRQ: %d\n", client->irq); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + nfc_err(&client->dev, "Need I2C_FUNC_I2C\n"); + return -ENODEV; + } + + phy = devm_kzalloc(&client->dev, sizeof(struct st21nfcb_i2c_phy), + GFP_KERNEL); + if (!phy) { + nfc_err(&client->dev, + "Cannot allocate memory for st21nfcb i2c phy.\n"); + return -ENOMEM; + } + + phy->i2c_dev = client; + + i2c_set_clientdata(client, phy); + + pdata = client->dev.platform_data; + if (!pdata && client->dev.of_node) { + r = st21nfcb_nci_i2c_of_request_resources(client); + if (r) { + nfc_err(&client->dev, "No platform data\n"); + return r; + } + } else if (pdata) { + r = st21nfcb_nci_i2c_request_resources(client); + if (r) { + nfc_err(&client->dev, + "Cannot get platform resources\n"); + return r; + } + } else { + nfc_err(&client->dev, + "st21nfcb platform resources not available\n"); + return -ENODEV; + } + + r = devm_request_threaded_irq(&client->dev, client->irq, NULL, + st21nfcb_nci_irq_thread_fn, + phy->irq_polarity | IRQF_ONESHOT, + ST21NFCB_NCI_DRIVER_NAME, phy); + if (r < 0) { + nfc_err(&client->dev, "Unable to register IRQ handler\n"); + return r; + } + + return ndlc_probe(phy, &i2c_phy_ops, &client->dev, + ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM, + &phy->ndlc); +} + +static int st21nfcb_nci_i2c_remove(struct i2c_client *client) +{ + struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "%s\n", __func__); + + ndlc_remove(phy->ndlc); + + if (phy->powered) + st21nfcb_nci_i2c_disable(phy); + + return 0; +} + +static const struct of_device_id of_st21nfcb_i2c_match[] = { + { .compatible = "st,st21nfcb_i2c", }, + {} +}; + +static struct i2c_driver st21nfcb_nci_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = ST21NFCB_NCI_I2C_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_st21nfcb_i2c_match), + }, + .probe = st21nfcb_nci_i2c_probe, + .id_table = st21nfcb_nci_i2c_id_table, + .remove = st21nfcb_nci_i2c_remove, +}; + +module_i2c_driver(st21nfcb_nci_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/nfc/st21nfcb/ndlc.c b/drivers/nfc/st21nfcb/ndlc.c new file mode 100644 index 000000000000..83c97c36112b --- /dev/null +++ b/drivers/nfc/st21nfcb/ndlc.c @@ -0,0 +1,298 @@ +/* + * Low Level Transport (NDLC) Driver for STMicroelectronics NFC Chip + * + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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, see . + */ + +#include +#include + +#include "ndlc.h" +#include "st21nfcb.h" + +#define NDLC_TIMER_T1 100 +#define NDLC_TIMER_T1_WAIT 400 +#define NDLC_TIMER_T2 1200 + +#define PCB_TYPE_DATAFRAME 0x80 +#define PCB_TYPE_SUPERVISOR 0xc0 +#define PCB_TYPE_MASK PCB_TYPE_SUPERVISOR + +#define PCB_SYNC_ACK 0x20 +#define PCB_SYNC_NACK 0x10 +#define PCB_SYNC_WAIT 0x30 +#define PCB_SYNC_NOINFO 0x00 +#define PCB_SYNC_MASK PCB_SYNC_WAIT + +#define PCB_DATAFRAME_RETRANSMIT_YES 0x00 +#define PCB_DATAFRAME_RETRANSMIT_NO 0x04 +#define PCB_DATAFRAME_RETRANSMIT_MASK PCB_DATAFRAME_RETRANSMIT_NO + +#define PCB_SUPERVISOR_RETRANSMIT_YES 0x00 +#define PCB_SUPERVISOR_RETRANSMIT_NO 0x02 +#define PCB_SUPERVISOR_RETRANSMIT_MASK PCB_SUPERVISOR_RETRANSMIT_NO + +#define PCB_FRAME_CRC_INFO_PRESENT 0x08 +#define PCB_FRAME_CRC_INFO_NOTPRESENT 0x00 +#define PCB_FRAME_CRC_INFO_MASK PCB_FRAME_CRC_INFO_PRESENT + +#define NDLC_DUMP_SKB(info, skb) \ +do { \ + pr_debug("%s:\n", info); \ + print_hex_dump(KERN_DEBUG, "ndlc: ", DUMP_PREFIX_OFFSET, \ + 16, 1, skb->data, skb->len, 0); \ +} while (0) + +int ndlc_open(struct llt_ndlc *ndlc) +{ + /* toggle reset pin */ + ndlc->ops->enable(ndlc->phy_id); + return 0; +} +EXPORT_SYMBOL(ndlc_open); + +void ndlc_close(struct llt_ndlc *ndlc) +{ + /* toggle reset pin */ + ndlc->ops->disable(ndlc->phy_id); +} +EXPORT_SYMBOL(ndlc_close); + +int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb) +{ + /* add ndlc header */ + u8 pcb = PCB_TYPE_DATAFRAME | PCB_DATAFRAME_RETRANSMIT_NO | + PCB_FRAME_CRC_INFO_NOTPRESENT; + + *skb_push(skb, 1) = pcb; + skb_queue_tail(&ndlc->send_q, skb); + + schedule_work(&ndlc->sm_work); + + return 0; +} +EXPORT_SYMBOL(ndlc_send); + +static void llt_ndlc_send_queue(struct llt_ndlc *ndlc) +{ + struct sk_buff *skb; + int r; + unsigned long time_sent; + + if (ndlc->send_q.qlen) + pr_debug("sendQlen=%d unackQlen=%d\n", + ndlc->send_q.qlen, ndlc->ack_pending_q.qlen); + + while (ndlc->send_q.qlen) { + skb = skb_dequeue(&ndlc->send_q); + NDLC_DUMP_SKB("ndlc frame written", skb); + r = ndlc->ops->write(ndlc->phy_id, skb); + if (r < 0) { + ndlc->hard_fault = r; + break; + } + time_sent = jiffies; + *(unsigned long *)skb->cb = time_sent; + + skb_queue_tail(&ndlc->ack_pending_q, skb); + + /* start timer t1 for ndlc aknowledge */ + ndlc->t1_active = true; + mod_timer(&ndlc->t1_timer, time_sent + + msecs_to_jiffies(NDLC_TIMER_T1)); + } +} + +static void llt_ndlc_requeue_data_pending(struct llt_ndlc *ndlc) +{ + struct sk_buff *skb; + u8 pcb; + + while ((skb = skb_dequeue_tail(&ndlc->ack_pending_q))) { + pcb = skb->data[0]; + switch (pcb & PCB_TYPE_MASK) { + case PCB_TYPE_SUPERVISOR: + skb->data[0] = (pcb & ~PCB_SUPERVISOR_RETRANSMIT_MASK) | + PCB_SUPERVISOR_RETRANSMIT_YES; + break; + case PCB_TYPE_DATAFRAME: + skb->data[0] = (pcb & ~PCB_DATAFRAME_RETRANSMIT_MASK) | + PCB_DATAFRAME_RETRANSMIT_YES; + break; + default: + pr_err("UNKNOWN Packet Control Byte=%d\n", pcb); + kfree_skb(skb); + break; + } + skb_queue_head(&ndlc->send_q, skb); + } +} + +static void llt_ndlc_rcv_queue(struct llt_ndlc *ndlc) +{ + struct sk_buff *skb; + u8 pcb; + unsigned long time_sent; + + if (ndlc->rcv_q.qlen) + pr_debug("rcvQlen=%d\n", ndlc->rcv_q.qlen); + + while ((skb = skb_dequeue(&ndlc->rcv_q)) != NULL) { + pcb = skb->data[0]; + skb_pull(skb, 1); + if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_SUPERVISOR) { + switch (pcb & PCB_SYNC_MASK) { + case PCB_SYNC_ACK: + del_timer_sync(&ndlc->t1_timer); + del_timer_sync(&ndlc->t2_timer); + ndlc->t2_active = false; + ndlc->t1_active = false; + break; + case PCB_SYNC_NACK: + llt_ndlc_requeue_data_pending(ndlc); + llt_ndlc_send_queue(ndlc); + /* start timer t1 for ndlc aknowledge */ + time_sent = jiffies; + ndlc->t1_active = true; + mod_timer(&ndlc->t1_timer, time_sent + + msecs_to_jiffies(NDLC_TIMER_T1)); + break; + case PCB_SYNC_WAIT: + time_sent = jiffies; + ndlc->t1_active = true; + mod_timer(&ndlc->t1_timer, time_sent + + msecs_to_jiffies(NDLC_TIMER_T1_WAIT)); + break; + default: + pr_err("UNKNOWN Packet Control Byte=%d\n", pcb); + kfree_skb(skb); + break; + } + } else { + nci_recv_frame(ndlc->ndev, skb); + } + } +} + +static void llt_ndlc_sm_work(struct work_struct *work) +{ + struct llt_ndlc *ndlc = container_of(work, struct llt_ndlc, sm_work); + + llt_ndlc_send_queue(ndlc); + llt_ndlc_rcv_queue(ndlc); + + if (ndlc->t1_active && timer_pending(&ndlc->t1_timer) == 0) { + pr_debug + ("Handle T1(recv SUPERVISOR) elapsed (T1 now inactive)\n"); + ndlc->t1_active = false; + + llt_ndlc_requeue_data_pending(ndlc); + llt_ndlc_send_queue(ndlc); + } + + if (ndlc->t2_active && timer_pending(&ndlc->t2_timer) == 0) { + pr_debug("Handle T2(recv DATA) elapsed (T2 now inactive)\n"); + ndlc->t2_active = false; + ndlc->t1_active = false; + del_timer_sync(&ndlc->t1_timer); + + ndlc_close(ndlc); + ndlc->hard_fault = -EREMOTEIO; + } +} + +void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb) +{ + if (skb == NULL) { + pr_err("NULL Frame -> link is dead\n"); + ndlc->hard_fault = -EREMOTEIO; + ndlc_close(ndlc); + } else { + NDLC_DUMP_SKB("incoming frame", skb); + skb_queue_tail(&ndlc->rcv_q, skb); + } + + schedule_work(&ndlc->sm_work); +} +EXPORT_SYMBOL(ndlc_recv); + +static void ndlc_t1_timeout(unsigned long data) +{ + struct llt_ndlc *ndlc = (struct llt_ndlc *)data; + + pr_debug("\n"); + + schedule_work(&ndlc->sm_work); +} + +static void ndlc_t2_timeout(unsigned long data) +{ + struct llt_ndlc *ndlc = (struct llt_ndlc *)data; + + pr_debug("\n"); + + schedule_work(&ndlc->sm_work); +} + +int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, + int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id) +{ + struct llt_ndlc *ndlc; + + ndlc = devm_kzalloc(dev, sizeof(struct llt_ndlc), GFP_KERNEL); + if (!ndlc) { + nfc_err(dev, "Cannot allocate memory for ndlc.\n"); + return -ENOMEM; + } + ndlc->ops = phy_ops; + ndlc->phy_id = phy_id; + ndlc->dev = dev; + + *ndlc_id = ndlc; + + /* start timers */ + init_timer(&ndlc->t1_timer); + ndlc->t1_timer.data = (unsigned long)ndlc; + ndlc->t1_timer.function = ndlc_t1_timeout; + + init_timer(&ndlc->t2_timer); + ndlc->t2_timer.data = (unsigned long)ndlc; + ndlc->t2_timer.function = ndlc_t2_timeout; + + skb_queue_head_init(&ndlc->rcv_q); + skb_queue_head_init(&ndlc->send_q); + skb_queue_head_init(&ndlc->ack_pending_q); + + INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work); + + return st21nfcb_nci_probe(ndlc, phy_headroom, phy_tailroom); +} +EXPORT_SYMBOL(ndlc_probe); + +void ndlc_remove(struct llt_ndlc *ndlc) +{ + /* cancel timers */ + del_timer_sync(&ndlc->t1_timer); + del_timer_sync(&ndlc->t2_timer); + ndlc->t2_active = false; + ndlc->t1_active = false; + + skb_queue_purge(&ndlc->rcv_q); + skb_queue_purge(&ndlc->send_q); + + st21nfcb_nci_remove(ndlc->ndev); + kfree(ndlc); +} +EXPORT_SYMBOL(ndlc_remove); diff --git a/drivers/nfc/st21nfcb/ndlc.h b/drivers/nfc/st21nfcb/ndlc.h new file mode 100644 index 000000000000..c30a2f0faa5f --- /dev/null +++ b/drivers/nfc/st21nfcb/ndlc.h @@ -0,0 +1,55 @@ +/* + * NCI based Driver for STMicroelectronics NFC Chip + * + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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, see . + */ + +#ifndef __LOCAL_NDLC_H_ +#define __LOCAL_NDLC_H_ + +#include +#include + +/* Low Level Transport description */ +struct llt_ndlc { + struct nci_dev *ndev; + struct nfc_phy_ops *ops; + void *phy_id; + + struct timer_list t1_timer; + bool t1_active; + + struct timer_list t2_timer; + bool t2_active; + + struct sk_buff_head rcv_q; + struct sk_buff_head send_q; + struct sk_buff_head ack_pending_q; + + struct work_struct sm_work; + + struct device *dev; + + int hard_fault; +}; + +int ndlc_open(struct llt_ndlc *ndlc); +void ndlc_close(struct llt_ndlc *ndlc); +int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb); +void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb); +int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, + int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id); +void ndlc_remove(struct llt_ndlc *ndlc); +#endif /* __LOCAL_NDLC_H__ */ diff --git a/drivers/nfc/st21nfcb/st21nfcb.c b/drivers/nfc/st21nfcb/st21nfcb.c new file mode 100644 index 000000000000..4d95863e3063 --- /dev/null +++ b/drivers/nfc/st21nfcb/st21nfcb.c @@ -0,0 +1,129 @@ +/* + * NCI based Driver for STMicroelectronics NFC Chip + * + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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, see . + */ + +#include +#include +#include +#include + +#include "st21nfcb.h" +#include "ndlc.h" + +#define DRIVER_DESC "NCI NFC driver for ST21NFCB" + +static int st21nfcb_nci_open(struct nci_dev *ndev) +{ + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + int r; + + if (test_and_set_bit(ST21NFCB_NCI_RUNNING, &info->flags)) + return 0; + + r = ndlc_open(info->ndlc); + if (r) + clear_bit(ST21NFCB_NCI_RUNNING, &info->flags); + + return r; +} + +static int st21nfcb_nci_close(struct nci_dev *ndev) +{ + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + + if (!test_and_clear_bit(ST21NFCB_NCI_RUNNING, &info->flags)) + return 0; + + ndlc_close(info->ndlc); + + return 0; +} + +static int st21nfcb_nci_send(struct nci_dev *ndev, struct sk_buff *skb) +{ + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + + skb->dev = (void *)ndev; + + if (!test_bit(ST21NFCB_NCI_RUNNING, &info->flags)) + return -EBUSY; + + return ndlc_send(info->ndlc, skb); +} + +static struct nci_ops st21nfcb_nci_ops = { + .open = st21nfcb_nci_open, + .close = st21nfcb_nci_close, + .send = st21nfcb_nci_send, +}; + +int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, + int phy_tailroom) +{ + struct st21nfcb_nci_info *info; + int r; + u32 protocols; + + info = devm_kzalloc(ndlc->dev, + sizeof(struct st21nfcb_nci_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + protocols = NFC_PROTO_JEWEL_MASK + | NFC_PROTO_MIFARE_MASK + | NFC_PROTO_FELICA_MASK + | NFC_PROTO_ISO14443_MASK + | NFC_PROTO_ISO14443_B_MASK + | NFC_PROTO_NFC_DEP_MASK; + + ndlc->ndev = nci_allocate_device(&st21nfcb_nci_ops, protocols, + phy_headroom, phy_tailroom); + if (!ndlc->ndev) { + pr_err("Cannot allocate nfc ndev\n"); + r = -ENOMEM; + goto err_alloc_ndev; + } + info->ndlc = ndlc; + + nci_set_drvdata(ndlc->ndev, info); + + r = nci_register_device(ndlc->ndev); + if (r) + goto err_regdev; + + return r; +err_regdev: + nci_free_device(ndlc->ndev); + +err_alloc_ndev: + kfree(info); + return r; +} +EXPORT_SYMBOL_GPL(st21nfcb_nci_probe); + +void st21nfcb_nci_remove(struct nci_dev *ndev) +{ + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + + nci_unregister_device(ndev); + nci_free_device(ndev); + kfree(info); +} +EXPORT_SYMBOL_GPL(st21nfcb_nci_remove); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/nfc/st21nfcb/st21nfcb.h b/drivers/nfc/st21nfcb/st21nfcb.h new file mode 100644 index 000000000000..4bbbebb9f34d --- /dev/null +++ b/drivers/nfc/st21nfcb/st21nfcb.h @@ -0,0 +1,38 @@ +/* + * NCI based Driver for STMicroelectronics NFC Chip + * + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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, see . + */ + +#ifndef __LOCAL_ST21NFCB_H_ +#define __LOCAL_ST21NFCB_H_ + +#include + +#include "ndlc.h" + +/* Define private flags: */ +#define ST21NFCB_NCI_RUNNING 1 + +struct st21nfcb_nci_info { + struct llt_ndlc *ndlc; + unsigned long flags; +}; + +void st21nfcb_nci_remove(struct nci_dev *ndev); +int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, + int phy_tailroom); + +#endif /* __LOCAL_ST21NFCB_H_ */ diff --git a/include/linux/platform_data/st21nfcb.h b/include/linux/platform_data/st21nfcb.h new file mode 100644 index 000000000000..2a7b769c714d --- /dev/null +++ b/include/linux/platform_data/st21nfcb.h @@ -0,0 +1,32 @@ +/* + * Driver include for the ST21NFCB NFC chip. + * + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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, see . + */ + +#ifndef _ST21NFCA_HCI_H_ +#define _ST21NFCA_HCI_H_ + +#include + +#define ST21NFCB_NCI_DRIVER_NAME "st21nfcb_nci" + +struct st21nfcb_nfc_platform_data { + unsigned int gpio_irq; + unsigned int gpio_reset; + unsigned int irq_polarity; +}; + +#endif /* _ST21NFCA_HCI_H_ */ -- cgit v1.2.3 From 955164ebb8f8d337ca5b8540ae1f9d4def7f0ad0 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sun, 25 May 2014 22:35:39 +0200 Subject: NFC: dts: st21nfcb_i2c: Add DTS Documentation Describe the properties used by the st21nfcb NFC controller driver. Signed-off-by: Samuel Ortiz --- .../devicetree/bindings/net/nfc/st21nfcb.txt | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/nfc/st21nfcb.txt diff --git a/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt b/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt new file mode 100644 index 000000000000..3b58ae480344 --- /dev/null +++ b/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt @@ -0,0 +1,33 @@ +* STMicroelectronics SAS. ST21NFCB NFC Controller + +Required properties: +- compatible: Should be "st,st21nfcb_i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus +- interrupt-parent: phandle for the interrupt gpio controller +- interrupts: GPIO interrupt to which the chip is connected +- reset-gpios: Output GPIO pin used to reset the ST21NFCB + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2): + +&i2c2 { + + status = "okay"; + + st21nfcb: st21nfcb@8 { + + compatible = "st,st21nfcb_i2c"; + + reg = <0x08>; + clock-frequency = <400000>; + + interrupt-parent = <&gpio5>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + + reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>; + }; +}; -- cgit v1.2.3 From bb15b2170c80b96ea78c0f8c8a6e0ed75fa91c10 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sun, 25 May 2014 22:35:40 +0200 Subject: NFC: nci: Add T1T support notification Add T1T matching with Jewel during notification. It was causing "the target found does not have the desired protocol" to show up. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- net/nfc/nci/ntf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index f8f6af231381..df91bb95b12a 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -166,7 +166,9 @@ static int nci_add_new_protocol(struct nci_dev *ndev, struct rf_tech_specific_params_nfcf_poll *nfcf_poll; __u32 protocol; - if (rf_protocol == NCI_RF_PROTOCOL_T2T) + if (rf_protocol == NCI_RF_PROTOCOL_T1T) + protocol = NFC_PROTO_JEWEL_MASK; + else if (rf_protocol == NCI_RF_PROTOCOL_T2T) protocol = NFC_PROTO_MIFARE_MASK; else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) -- cgit v1.2.3 From fb92ff78f85b6c1a6f1277f7dd04a3762ba725ef Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sun, 25 May 2014 22:46:58 +0200 Subject: NFC: st21nfcb: few code clean up Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfcb/i2c.c | 16 ++++++++-------- include/linux/platform_data/st21nfcb.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/nfc/st21nfcb/i2c.c b/drivers/nfc/st21nfcb/i2c.c index 0f690baaef7a..8af880ead5db 100644 --- a/drivers/nfc/st21nfcb/i2c.c +++ b/drivers/nfc/st21nfcb/i2c.c @@ -164,11 +164,11 @@ static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy, u8 buf[ST21NFCB_NCI_I2C_MAX_SIZE]; struct i2c_client *client = phy->i2c_dev; - r = i2c_master_recv(client, buf, 4); + r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE); if (r == -EREMOTEIO) { /* Retry, chip was in standby */ usleep_range(1000, 4000); - r = i2c_master_recv(client, buf, 4); - } else if (r != 4) { + r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE); + } else if (r != ST21NFCB_NCI_I2C_MIN_SIZE) { nfc_err(&client->dev, "cannot read ndlc & nci header\n"); return -EREMOTEIO; } @@ -179,13 +179,13 @@ static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy, return -EBADMSG; } - *skb = alloc_skb(4 + len, GFP_KERNEL); + *skb = alloc_skb(ST21NFCB_NCI_I2C_MIN_SIZE + len, GFP_KERNEL); if (*skb == NULL) return -ENOMEM; - skb_reserve(*skb, 4); - skb_put(*skb, 4); - memcpy((*skb)->data, buf, 4); + skb_reserve(*skb, ST21NFCB_NCI_I2C_MIN_SIZE); + skb_put(*skb, ST21NFCB_NCI_I2C_MIN_SIZE); + memcpy((*skb)->data, buf, ST21NFCB_NCI_I2C_MIN_SIZE); if (!len) return 0; @@ -197,7 +197,7 @@ static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy, } skb_put(*skb, len); - memcpy((*skb)->data + 4, buf, len); + memcpy((*skb)->data + ST21NFCB_NCI_I2C_MIN_SIZE, buf, len); I2C_DUMP_SKB("i2c frame read", *skb); diff --git a/include/linux/platform_data/st21nfcb.h b/include/linux/platform_data/st21nfcb.h index 2a7b769c714d..2d11f1f5efab 100644 --- a/include/linux/platform_data/st21nfcb.h +++ b/include/linux/platform_data/st21nfcb.h @@ -16,8 +16,8 @@ * along with this program; if not, see . */ -#ifndef _ST21NFCA_HCI_H_ -#define _ST21NFCA_HCI_H_ +#ifndef _ST21NFCB_NCI_H_ +#define _ST21NFCB_NCI_H_ #include -- cgit v1.2.3 From cf577344e2ece0798046402fd88472473c6e7ee8 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 20 May 2014 22:21:54 +0200 Subject: NFC: st21nfca: Free buffer in case no data are retrieved. In case no data are retrieve through i2c or one specific case is not handled. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/i2c.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 3f954ed86d98..d10d837fb888 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -487,6 +487,8 @@ static irqreturn_t st21nfca_hci_irq_thread_fn(int irq, void *phy_id) */ nfc_hci_recv_frame(phy->hdev, phy->pending_skb); phy->crc_trials = 0; + } else { + kfree_skb(phy->pending_skb); } phy->pending_skb = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE * 2, GFP_KERNEL); -- cgit v1.2.3 From 8e9466ccda297c0844a606910152787ce9133b24 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 20 May 2014 22:21:55 +0200 Subject: NFC: st21nfca: Improved start of frame detection A start of frame is 7E 00 not only 7E. Make sure the first read sequence is starting with 7E 00. For example: 7E FF FF FF FF is as a correct crc but it is a bad frame. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/i2c.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index d10d837fb888..70564b3f2ab2 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -397,12 +397,11 @@ static int st21nfca_hci_i2c_read(struct st21nfca_i2c_phy *phy, * The first read sequence does not start with SOF. * Data is corrupeted so we drop it. */ - if (!phy->current_read_len && buf[0] != ST21NFCA_SOF_EOF) { + if (!phy->current_read_len && !IS_START_OF_FRAME(buf)) { skb_trim(skb, 0); phy->current_read_len = 0; return -EIO; - } else if (phy->current_read_len && - IS_START_OF_FRAME(buf)) { + } else if (phy->current_read_len && IS_START_OF_FRAME(buf)) { /* * Previous frame transmission was interrupted and * the frame got repeated. -- cgit v1.2.3 From 0531107e1cdc4f5254116c1bf972c62fb024a466 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 20 May 2014 22:21:56 +0200 Subject: NFC: st21nfca: Improve read length sequence for P2P mode. A DEP_RES with a SUPERVISOR PDU can be up to 16 bytes long. In order to avoid useless read during p2p, extend first read sequence to 16 and reduce third sequence to 12 to keep same total on the full sequence. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 70564b3f2ab2..ff31939978ae 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -93,7 +93,7 @@ struct st21nfca_i2c_phy { int hard_fault; struct mutex phy_lock; }; -static u8 len_seq[] = { 13, 24, 15, 29 }; +static u8 len_seq[] = { 16, 24, 12, 29 }; static u16 wait_tab[] = { 2, 3, 5, 15, 20, 40}; #define I2C_DUMP_SKB(info, skb) \ -- cgit v1.2.3 From 95f7687b209954a8ec94b4974d14fdff005ebaac Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 20 May 2014 22:21:57 +0200 Subject: NFC: hci: Add stop_poll HCI operand. stop_poll allows to stop CLF reader polling. Some other operations might be necessary for some CLF to stop polling. For example in card mode. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- include/net/nfc/hci.h | 1 + net/nfc/hci/core.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 61286db54388..7ee8f4cc610b 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -37,6 +37,7 @@ struct nfc_hci_ops { int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb); int (*start_poll) (struct nfc_hci_dev *hdev, u32 im_protocols, u32 tm_protocols); + void (*stop_poll) (struct nfc_hci_dev *hdev); int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target, u8 comm_mode, u8 *gb, size_t gb_len); int (*dep_link_down)(struct nfc_hci_dev *hdev); diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 47403705197e..117708263ced 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -553,8 +553,11 @@ static void hci_stop_poll(struct nfc_dev *nfc_dev) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); - nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, - NFC_HCI_EVT_END_OPERATION, NULL, 0); + if (hdev->ops->stop_poll) + hdev->ops->stop_poll(hdev); + else + nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); } static int hci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, -- cgit v1.2.3 From d57d74eb7626a2aeefad47a8d4246e9daf2199f5 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 20 May 2014 22:21:58 +0200 Subject: NFC: st21nfca: Implement stop_poll HCI hook Send DM_DISCONNECT command to disconnect Terminal Host from the HCI network. - The persistent states of the terminal host pipes, including registry values, are not modifies. Therefore, there is no NVRAM update to disconnect the terminal host. - The terminal host RF card gates are disabled which means that there will be no event related to card RF gates until communication has been restored. - The terminal host RF reader request is reset so the RF reader polling for terminal host is disabled. To restore the communication, the terminal host can send any HCI command or event. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/st21nfca.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/nfc/st21nfca/st21nfca.c b/drivers/nfc/st21nfca/st21nfca.c index 51e0f00b3a4f..7ff1dcdd16ba 100644 --- a/drivers/nfc/st21nfca/st21nfca.c +++ b/drivers/nfc/st21nfca/st21nfca.c @@ -53,6 +53,7 @@ #define ST21NFCA_DM_PIPE_CREATED 0x02 #define ST21NFCA_DM_PIPE_OPEN 0x04 #define ST21NFCA_DM_RF_ACTIVE 0x80 +#define ST21NFCA_DM_DISCONNECT 0x30 #define ST21NFCA_DM_IS_PIPE_OPEN(p) \ ((p & 0x0f) == (ST21NFCA_DM_PIPE_CREATED | ST21NFCA_DM_PIPE_OPEN)) @@ -356,6 +357,12 @@ static int st21nfca_hci_start_poll(struct nfc_hci_dev *hdev, return r; } +static void st21nfca_hci_stop_poll(struct nfc_hci_dev *hdev) +{ + nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE, + ST21NFCA_DM_DISCONNECT, NULL, 0, NULL); +} + static int st21nfca_get_iso14443_3_atqa(struct nfc_hci_dev *hdev, u16 *atqa) { int r; @@ -601,6 +608,7 @@ static struct nfc_hci_ops st21nfca_hci_ops = { .hci_ready = st21nfca_hci_ready, .xmit = st21nfca_hci_xmit, .start_poll = st21nfca_hci_start_poll, + .stop_poll = st21nfca_hci_stop_poll, .target_from_gate = st21nfca_hci_target_from_gate, .im_transceive = st21nfca_hci_im_transceive, .check_presence = st21nfca_hci_check_presence, -- cgit v1.2.3 From 1892bf844ea0261736bd5e75546fc996e9daeedf Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 20 May 2014 22:21:59 +0200 Subject: NFC: st21nfca: Adding P2P support to st21nfca in Initiator & Target mode Support for Initiator and Target mode with ISO18092 commands support: - ATR_REQ/ATR_RES - PSL_REQ/PSL_RES - DEP_REQ/DEP_RES Work based on net/nfc/digital_dep.c. st21nfca is using: - Gate reader F for P2P in initiator mode. - Gate card F for P2P in target mode. Felica tag and p2p are differentiated with NFCID2. When starting with 01FE it is acting in p2p mode. On complete_target_discovered on ST21NFCA_RF_READER_F_GATE supported_protocols is set to NFC_PROTO_NFC_DEP_MASK for P2P. Tested against: Nexus S, Galaxy S2, Galaxy S3, Galaxy S3 Mini, Nexus 4 & Nexus 5. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/Makefile | 2 +- drivers/nfc/st21nfca/st21nfca.c | 264 +++++++++++++- drivers/nfc/st21nfca/st21nfca.h | 26 +- drivers/nfc/st21nfca/st21nfca_dep.c | 661 ++++++++++++++++++++++++++++++++++++ drivers/nfc/st21nfca/st21nfca_dep.h | 43 +++ 5 files changed, 993 insertions(+), 3 deletions(-) create mode 100644 drivers/nfc/st21nfca/st21nfca_dep.c create mode 100644 drivers/nfc/st21nfca/st21nfca_dep.h diff --git a/drivers/nfc/st21nfca/Makefile b/drivers/nfc/st21nfca/Makefile index 038ed093a119..db7a38ae05f7 100644 --- a/drivers/nfc/st21nfca/Makefile +++ b/drivers/nfc/st21nfca/Makefile @@ -4,5 +4,5 @@ st21nfca_i2c-objs = i2c.o -obj-$(CONFIG_NFC_ST21NFCA) += st21nfca.o +obj-$(CONFIG_NFC_ST21NFCA) += st21nfca.o st21nfca_dep.o obj-$(CONFIG_NFC_ST21NFCA_I2C) += st21nfca_i2c.o diff --git a/drivers/nfc/st21nfca/st21nfca.c b/drivers/nfc/st21nfca/st21nfca.c index 7ff1dcdd16ba..a902b0551c86 100644 --- a/drivers/nfc/st21nfca/st21nfca.c +++ b/drivers/nfc/st21nfca/st21nfca.c @@ -22,6 +22,7 @@ #include #include "st21nfca.h" +#include "st21nfca_dep.h" #define DRIVER_DESC "HCI NFC driver for ST21NFCA" @@ -73,6 +74,7 @@ static struct nfc_hci_gate st21nfca_gates[] = { {ST21NFCA_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE}, {ST21NFCA_RF_READER_14443_3_A_GATE, NFC_HCI_INVALID_PIPE}, {ST21NFCA_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE}, + {ST21NFCA_RF_CARD_F_GATE, NFC_HCI_INVALID_PIPE}, }; struct st21nfca_pipe_info { @@ -300,6 +302,9 @@ static int st21nfca_hci_start_poll(struct nfc_hci_dev *hdev, u32 im_protocols, u32 tm_protocols) { int r; + u32 pol_req; + u8 param[19]; + struct sk_buff *datarate_skb; pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n", __func__, im_protocols, tm_protocols); @@ -332,6 +337,31 @@ static int st21nfca_hci_start_poll(struct nfc_hci_dev *hdev, ST21NFCA_RF_READER_F_GATE); if (r < 0) return r; + } else { + hdev->gb = nfc_get_local_general_bytes(hdev->ndev, + &hdev->gb_len); + + if (hdev->gb == NULL || hdev->gb_len == 0) { + im_protocols &= ~NFC_PROTO_NFC_DEP_MASK; + tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK; + } + + param[0] = ST21NFCA_RF_READER_F_DATARATE_106 | + ST21NFCA_RF_READER_F_DATARATE_212 | + ST21NFCA_RF_READER_F_DATARATE_424; + r = nfc_hci_set_param(hdev, ST21NFCA_RF_READER_F_GATE, + ST21NFCA_RF_READER_F_DATARATE, + param, 1); + if (r < 0) + return r; + + pol_req = + be32_to_cpu(ST21NFCA_RF_READER_F_POL_REQ_DEFAULT); + r = nfc_hci_set_param(hdev, ST21NFCA_RF_READER_F_GATE, + ST21NFCA_RF_READER_F_POL_REQ, + (u8 *) &pol_req, 4); + if (r < 0) + return r; } if ((ST21NFCA_RF_READER_14443_3_A_GATE & im_protocols) == 0) { @@ -354,6 +384,95 @@ static int st21nfca_hci_start_poll(struct nfc_hci_dev *hdev, nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, NFC_HCI_EVT_END_OPERATION, NULL, 0); } + + if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) { + r = nfc_hci_get_param(hdev, ST21NFCA_RF_CARD_F_GATE, + ST21NFCA_RF_CARD_F_DATARATE, + &datarate_skb); + if (r < 0) + return r; + + /* Configure the maximum supported datarate to 424Kbps */ + if (datarate_skb->len > 0 && + datarate_skb->data[0] != + ST21NFCA_RF_CARD_F_DATARATE_212_424) { + param[0] = ST21NFCA_RF_CARD_F_DATARATE_212_424; + r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE, + ST21NFCA_RF_CARD_F_DATARATE, + param, 1); + if (r < 0) + return r; + } + + /* + * Configure sens_res + * + * NFC Forum Digital Spec Table 7: + * NFCID1 size: triple (10 bytes) + */ + param[0] = 0x00; + param[1] = 0x08; + r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE, + ST21NFCA_RF_CARD_F_SENS_RES, param, 2); + if (r < 0) + return r; + + /* + * Configure sel_res + * + * NFC Forum Digistal Spec Table 17: + * b3 set to 0b (value b7-b6): + * - 10b: Configured for NFC-DEP Protocol + */ + param[0] = 0x40; + r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE, + ST21NFCA_RF_CARD_F_SEL_RES, param, 1); + if (r < 0) + return r; + + /* Configure NFCID1 Random uid */ + r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE, + ST21NFCA_RF_CARD_F_NFCID1, NULL, 0); + if (r < 0) + return r; + + /* Configure NFCID2_LIST */ + /* System Code */ + param[0] = 0x00; + param[1] = 0x00; + /* NFCID2 */ + param[2] = 0x01; + param[3] = 0xfe; + param[4] = 'S'; + param[5] = 'T'; + param[6] = 'M'; + param[7] = 'i'; + param[8] = 'c'; + param[9] = 'r'; + /* 8 byte Pad bytes used for polling respone frame */ + + /* + * Configuration byte: + * - bit 0: define the default NFCID2 entry used when the + * system code is equal to 'FFFF' + * - bit 1: use a random value for lowest 6 bytes of + * NFCID2 value + * - bit 2: ignore polling request frame if request code + * is equal to '01' + * - Other bits are RFU + */ + param[18] = 0x01; + r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE, + ST21NFCA_RF_CARD_F_NFCID2_LIST, param, + 19); + if (r < 0) + return r; + + param[0] = 0x02; + r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE, + ST21NFCA_RF_CARD_F_MODE, param, 1); + } + return r; } @@ -458,6 +577,26 @@ exit: return r; } +static int st21nfca_hci_dep_link_up(struct nfc_hci_dev *hdev, + struct nfc_target *target, u8 comm_mode, + u8 *gb, size_t gb_len) +{ + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + info->dep_info.idx = target->idx; + return st21nfca_im_send_atr_req(hdev, gb, gb_len); +} + +static int st21nfca_hci_dep_link_down(struct nfc_hci_dev *hdev) +{ + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + info->state = ST21NFCA_ST_READY; + + return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE, + ST21NFCA_DM_DISCONNECT, NULL, 0, NULL); +} + static int st21nfca_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, struct nfc_target *target) { @@ -512,6 +651,69 @@ static int st21nfca_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, return 0; } +static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev, + u8 gate, + struct nfc_target *target) +{ + int r; + struct sk_buff *nfcid2_skb = NULL, *nfcid1_skb; + + if (gate == ST21NFCA_RF_READER_F_GATE) { + r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE, + ST21NFCA_RF_READER_F_NFCID2, &nfcid2_skb); + if (r < 0) + goto exit; + + if (nfcid2_skb->len > NFC_SENSF_RES_MAXSIZE) { + r = -EPROTO; + goto exit; + } + + /* + * - After the recepton of polling response for type F frame + * at 212 or 424 Kbit/s, NFCID2 registry parameters will be + * updated. + * - After the reception of SEL_RES with NFCIP-1 compliant bit + * set for type A frame NFCID1 will be updated + */ + if (nfcid2_skb->len > 0) { + /* P2P in type F */ + memcpy(target->sensf_res, nfcid2_skb->data, + nfcid2_skb->len); + target->sensf_res_len = nfcid2_skb->len; + /* NFC Forum Digital Protocol Table 44 */ + if (target->sensf_res[0] == 0x01 && + target->sensf_res[1] == 0xfe) + target->supported_protocols = + NFC_PROTO_NFC_DEP_MASK; + else + target->supported_protocols = + NFC_PROTO_FELICA_MASK; + } else { + /* P2P in type A */ + r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE, + ST21NFCA_RF_READER_F_NFCID1, + &nfcid1_skb); + if (r < 0) + goto exit; + + if (nfcid1_skb->len > NFC_NFCID1_MAXSIZE) { + r = -EPROTO; + goto exit; + } + memcpy(target->sensf_res, nfcid1_skb->data, + nfcid1_skb->len); + target->sensf_res_len = nfcid1_skb->len; + target->supported_protocols = NFC_PROTO_NFC_DEP_MASK; + } + target->hci_reader_gate = ST21NFCA_RF_READER_F_GATE; + } + r = 1; +exit: + kfree_skb(nfcid2_skb); + return r; +} + #define ST21NFCA_CB_TYPE_READER_ISO15693 1 static void st21nfca_hci_data_exchange_cb(void *context, struct sk_buff *skb, int err) @@ -548,6 +750,9 @@ static int st21nfca_hci_im_transceive(struct nfc_hci_dev *hdev, switch (target->hci_reader_gate) { case ST21NFCA_RF_READER_F_GATE: + if (target->supported_protocols == NFC_PROTO_NFC_DEP_MASK) + return st21nfca_im_send_dep_req(hdev, skb); + *skb_push(skb, 1) = 0x1a; return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, ST21NFCA_WR_XCHG_DATA, skb->data, @@ -576,6 +781,11 @@ static int st21nfca_hci_im_transceive(struct nfc_hci_dev *hdev, } } +static int st21nfca_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb) +{ + return st21nfca_tm_send_dep_res(hdev, skb); +} + static int st21nfca_hci_check_presence(struct nfc_hci_dev *hdev, struct nfc_target *target) { @@ -601,6 +811,50 @@ static int st21nfca_hci_check_presence(struct nfc_hci_dev *hdev, } } +/* + * Returns: + * <= 0: driver handled the event, skb consumed + * 1: driver does not handle the event, please do standard processing + */ +static int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, + u8 event, struct sk_buff *skb) +{ + int r; + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + pr_debug("hci event: %d\n", event); + + switch (event) { + case ST21NFCA_EVT_CARD_ACTIVATED: + if (gate == ST21NFCA_RF_CARD_F_GATE) + info->dep_info.curr_nfc_dep_pni = 0; + break; + case ST21NFCA_EVT_CARD_DEACTIVATED: + break; + case ST21NFCA_EVT_FIELD_ON: + break; + case ST21NFCA_EVT_FIELD_OFF: + break; + case ST21NFCA_EVT_SEND_DATA: + if (gate == ST21NFCA_RF_CARD_F_GATE) { + r = st21nfca_tm_event_send_data(hdev, skb, gate); + if (r < 0) + goto exit; + return 0; + } else { + info->dep_info.curr_nfc_dep_pni = 0; + return 1; + } + break; + default: + return 1; + } + kfree_skb(skb); + return 0; +exit: + return r; +} + static struct nfc_hci_ops st21nfca_hci_ops = { .open = st21nfca_hci_open, .close = st21nfca_hci_close, @@ -609,9 +863,14 @@ static struct nfc_hci_ops st21nfca_hci_ops = { .xmit = st21nfca_hci_xmit, .start_poll = st21nfca_hci_start_poll, .stop_poll = st21nfca_hci_stop_poll, + .dep_link_up = st21nfca_hci_dep_link_up, + .dep_link_down = st21nfca_hci_dep_link_down, .target_from_gate = st21nfca_hci_target_from_gate, + .complete_target_discovered = st21nfca_hci_complete_target_discovered, .im_transceive = st21nfca_hci_im_transceive, + .tm_send = st21nfca_hci_tm_send, .check_presence = st21nfca_hci_check_presence, + .event_received = st21nfca_hci_event_received, }; int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, @@ -656,7 +915,8 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK | NFC_PROTO_ISO14443_B_MASK | - NFC_PROTO_ISO15693_MASK; + NFC_PROTO_ISO15693_MASK | + NFC_PROTO_NFC_DEP_MASK; set_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &quirks); @@ -679,6 +939,7 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, goto err_regdev; *hdev = info->hdev; + st21nfca_dep_init(info->hdev); return 0; @@ -696,6 +957,7 @@ void st21nfca_hci_remove(struct nfc_hci_dev *hdev) { struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + st21nfca_dep_deinit(hdev); nfc_hci_unregister_device(hdev); nfc_hci_free_device(hdev); kfree(info); diff --git a/drivers/nfc/st21nfca/st21nfca.h b/drivers/nfc/st21nfca/st21nfca.h index 334cd90bcc8c..96fe5a62dc0d 100644 --- a/drivers/nfc/st21nfca/st21nfca.h +++ b/drivers/nfc/st21nfca/st21nfca.h @@ -19,6 +19,8 @@ #include +#include "st21nfca_dep.h" + #define HCI_MODE 0 /* framing in HCI mode */ @@ -73,7 +75,8 @@ struct st21nfca_hci_info { data_exchange_cb_t async_cb; void *async_cb_context; -} __packed; + struct st21nfca_dep_info dep_info; +}; /* Reader RF commands */ #define ST21NFCA_WR_XCHG_DATA 0x10 @@ -83,5 +86,26 @@ struct st21nfca_hci_info { #define ST21NFCA_RF_READER_F_DATARATE_106 0x01 #define ST21NFCA_RF_READER_F_DATARATE_212 0x02 #define ST21NFCA_RF_READER_F_DATARATE_424 0x04 +#define ST21NFCA_RF_READER_F_POL_REQ 0x02 +#define ST21NFCA_RF_READER_F_POL_REQ_DEFAULT 0xffff0000 +#define ST21NFCA_RF_READER_F_NFCID2 0x03 +#define ST21NFCA_RF_READER_F_NFCID1 0x04 +#define ST21NFCA_RF_READER_F_SENS_RES 0x05 + +#define ST21NFCA_RF_CARD_F_GATE 0x24 +#define ST21NFCA_RF_CARD_F_MODE 0x01 +#define ST21NFCA_RF_CARD_F_NFCID2_LIST 0x04 +#define ST21NFCA_RF_CARD_F_NFCID1 0x05 +#define ST21NFCA_RF_CARD_F_SENS_RES 0x06 +#define ST21NFCA_RF_CARD_F_SEL_RES 0x07 +#define ST21NFCA_RF_CARD_F_DATARATE 0x08 +#define ST21NFCA_RF_CARD_F_DATARATE_106 0x00 +#define ST21NFCA_RF_CARD_F_DATARATE_212_424 0x01 + +#define ST21NFCA_EVT_SEND_DATA 0x10 +#define ST21NFCA_EVT_FIELD_ON 0x11 +#define ST21NFCA_EVT_CARD_DEACTIVATED 0x12 +#define ST21NFCA_EVT_CARD_ACTIVATED 0x13 +#define ST21NFCA_EVT_FIELD_OFF 0x14 #endif /* __LOCAL_ST21NFCA_H_ */ diff --git a/drivers/nfc/st21nfca/st21nfca_dep.c b/drivers/nfc/st21nfca/st21nfca_dep.c new file mode 100644 index 000000000000..b2d9957b57f8 --- /dev/null +++ b/drivers/nfc/st21nfca/st21nfca_dep.c @@ -0,0 +1,661 @@ +/* + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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, see . + */ + +#include + +#include "st21nfca.h" +#include "st21nfca_dep.h" + +#define ST21NFCA_NFCIP1_INITIATOR 0x00 +#define ST21NFCA_NFCIP1_REQ 0xd4 +#define ST21NFCA_NFCIP1_RES 0xd5 +#define ST21NFCA_NFCIP1_ATR_REQ 0x00 +#define ST21NFCA_NFCIP1_ATR_RES 0x01 +#define ST21NFCA_NFCIP1_PSL_REQ 0x04 +#define ST21NFCA_NFCIP1_PSL_RES 0x05 +#define ST21NFCA_NFCIP1_DEP_REQ 0x06 +#define ST21NFCA_NFCIP1_DEP_RES 0x07 + +#define ST21NFCA_NFC_DEP_PFB_PNI(pfb) ((pfb) & 0x03) +#define ST21NFCA_NFC_DEP_PFB_TYPE(pfb) ((pfb) & 0xE0) +#define ST21NFCA_NFC_DEP_PFB_IS_TIMEOUT(pfb) \ + ((pfb) & ST21NFCA_NFC_DEP_PFB_TIMEOUT_BIT) +#define ST21NFCA_NFC_DEP_DID_BIT_SET(pfb) ((pfb) & 0x04) +#define ST21NFCA_NFC_DEP_NAD_BIT_SET(pfb) ((pfb) & 0x08) +#define ST21NFCA_NFC_DEP_PFB_TIMEOUT_BIT 0x10 + +#define ST21NFCA_NFC_DEP_PFB_IS_TIMEOUT(pfb) \ + ((pfb) & ST21NFCA_NFC_DEP_PFB_TIMEOUT_BIT) + +#define ST21NFCA_NFC_DEP_PFB_I_PDU 0x00 +#define ST21NFCA_NFC_DEP_PFB_ACK_NACK_PDU 0x40 +#define ST21NFCA_NFC_DEP_PFB_SUPERVISOR_PDU 0x80 + +#define ST21NFCA_ATR_REQ_MIN_SIZE 17 +#define ST21NFCA_ATR_REQ_MAX_SIZE 65 +#define ST21NFCA_LR_BITS_PAYLOAD_SIZE_254B 0x30 +#define ST21NFCA_GB_BIT 0x02 + +#define ST21NFCA_EVT_CARD_F_BITRATE 0x16 +#define ST21NFCA_EVT_READER_F_BITRATE 0x13 +#define ST21NFCA_PSL_REQ_SEND_SPEED(brs) (brs & 0x38) +#define ST21NFCA_PSL_REQ_RECV_SPEED(brs) (brs & 0x07) +#define ST21NFCA_PP2LRI(pp) ((pp & 0x30) >> 4) +#define ST21NFCA_CARD_BITRATE_212 0x01 +#define ST21NFCA_CARD_BITRATE_424 0x02 + +#define ST21NFCA_DEFAULT_TIMEOUT 0x0a + + +#define PROTOCOL_ERR(req) pr_err("%d: ST21NFCA Protocol error: %s\n", \ + __LINE__, req) + +struct st21nfca_atr_req { + u8 length; + u8 cmd0; + u8 cmd1; + u8 nfcid3[NFC_NFCID3_MAXSIZE]; + u8 did; + u8 bsi; + u8 bri; + u8 ppi; + u8 gbi[0]; +} __packed; + +struct st21nfca_atr_res { + u8 length; + u8 cmd0; + u8 cmd1; + u8 nfcid3[NFC_NFCID3_MAXSIZE]; + u8 did; + u8 bsi; + u8 bri; + u8 to; + u8 ppi; + u8 gbi[0]; +} __packed; + +struct st21nfca_psl_req { + u8 length; + u8 cmd0; + u8 cmd1; + u8 did; + u8 brs; + u8 fsl; +} __packed; + +struct st21nfca_psl_res { + u8 length; + u8 cmd0; + u8 cmd1; + u8 did; +} __packed; + +struct st21nfca_dep_req_res { + u8 length; + u8 cmd0; + u8 cmd1; + u8 pfb; + u8 did; + u8 nad; +} __packed; + +static void st21nfca_tx_work(struct work_struct *work) +{ + struct st21nfca_hci_info *info = container_of(work, + struct st21nfca_hci_info, + dep_info.tx_work); + + struct nfc_dev *dev; + struct sk_buff *skb; + if (info) { + dev = info->hdev->ndev; + skb = info->dep_info.tx_pending; + + device_lock(&dev->dev); + + nfc_hci_send_cmd_async(info->hdev, ST21NFCA_RF_READER_F_GATE, + ST21NFCA_WR_XCHG_DATA, + skb->data, skb->len, + info->async_cb, info); + device_unlock(&dev->dev); + kfree_skb(skb); + } +} + +static void st21nfca_im_send_pdu(struct st21nfca_hci_info *info, + struct sk_buff *skb) +{ + info->dep_info.tx_pending = skb; + schedule_work(&info->dep_info.tx_work); +} + +static int st21nfca_tm_send_atr_res(struct nfc_hci_dev *hdev, + struct st21nfca_atr_req *atr_req) +{ + struct st21nfca_atr_res *atr_res; + struct sk_buff *skb; + size_t gb_len; + int r; + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + gb_len = atr_req->length - sizeof(struct st21nfca_atr_req); + skb = alloc_skb(atr_req->length + 1, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + skb_put(skb, sizeof(struct st21nfca_atr_res)); + + atr_res = (struct st21nfca_atr_res *)skb->data; + memset(atr_res, 0, sizeof(struct st21nfca_atr_res)); + + atr_res->length = atr_req->length + 1; + atr_res->cmd0 = ST21NFCA_NFCIP1_RES; + atr_res->cmd1 = ST21NFCA_NFCIP1_ATR_RES; + + memcpy(atr_res->nfcid3, atr_req->nfcid3, 6); + atr_res->bsi = 0x00; + atr_res->bri = 0x00; + atr_res->to = ST21NFCA_DEFAULT_TIMEOUT; + atr_res->ppi = ST21NFCA_LR_BITS_PAYLOAD_SIZE_254B; + + if (gb_len) { + skb_put(skb, gb_len); + + atr_res->ppi |= ST21NFCA_GB_BIT; + memcpy(atr_res->gbi, atr_req->gbi, gb_len); + r = nfc_set_remote_general_bytes(hdev->ndev, atr_res->gbi, + gb_len); + if (r < 0) + return r; + } + + info->dep_info.curr_nfc_dep_pni = 0; + + return nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE, + ST21NFCA_EVT_SEND_DATA, skb->data, skb->len); +} + +static int st21nfca_tm_recv_atr_req(struct nfc_hci_dev *hdev, + struct sk_buff *skb) +{ + struct st21nfca_atr_req *atr_req; + size_t gb_len; + int r; + + skb_trim(skb, skb->len - 1); + if (IS_ERR(skb)) { + r = PTR_ERR(skb); + goto exit; + } + + if (!skb->len) { + r = -EIO; + goto exit; + } + + if (skb->len < ST21NFCA_ATR_REQ_MIN_SIZE) { + r = -EPROTO; + goto exit; + } + + atr_req = (struct st21nfca_atr_req *)skb->data; + + r = st21nfca_tm_send_atr_res(hdev, atr_req); + if (r) + goto exit; + + gb_len = skb->len - sizeof(struct st21nfca_atr_req); + + r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK, + NFC_COMM_PASSIVE, atr_req->gbi, gb_len); + if (r) + goto exit; + + r = 0; + +exit: + return r; +} + +static int st21nfca_tm_send_psl_res(struct nfc_hci_dev *hdev, + struct st21nfca_psl_req *psl_req) +{ + struct st21nfca_psl_res *psl_res; + struct sk_buff *skb; + u8 bitrate[2] = {0, 0}; + + int r; + + skb = alloc_skb(sizeof(struct st21nfca_psl_res), GFP_KERNEL); + if (!skb) + return -ENOMEM; + skb_put(skb, sizeof(struct st21nfca_psl_res)); + + psl_res = (struct st21nfca_psl_res *)skb->data; + + psl_res->length = sizeof(struct st21nfca_psl_res); + psl_res->cmd0 = ST21NFCA_NFCIP1_RES; + psl_res->cmd1 = ST21NFCA_NFCIP1_PSL_RES; + psl_res->did = psl_req->did; + + r = nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE, + ST21NFCA_EVT_SEND_DATA, skb->data, skb->len); + + /* + * ST21NFCA only support P2P passive. + * PSL_REQ BRS value != 0 has only a meaning to + * change technology to type F. + * We change to BITRATE 424Kbits. + * In other case switch to BITRATE 106Kbits. + */ + if (ST21NFCA_PSL_REQ_SEND_SPEED(psl_req->brs) && + ST21NFCA_PSL_REQ_RECV_SPEED(psl_req->brs)) { + bitrate[0] = ST21NFCA_CARD_BITRATE_424; + bitrate[1] = ST21NFCA_CARD_BITRATE_424; + } + + /* Send an event to change bitrate change event to card f */ + return nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE, + ST21NFCA_EVT_CARD_F_BITRATE, bitrate, 2); +} + +static int st21nfca_tm_recv_psl_req(struct nfc_hci_dev *hdev, + struct sk_buff *skb) +{ + struct st21nfca_psl_req *psl_req; + int r; + + skb_trim(skb, skb->len - 1); + if (IS_ERR(skb)) { + r = PTR_ERR(skb); + skb = NULL; + goto exit; + } + + if (!skb->len) { + r = -EIO; + goto exit; + } + + psl_req = (struct st21nfca_psl_req *)skb->data; + + if (skb->len < sizeof(struct st21nfca_psl_req)) { + r = -EIO; + goto exit; + } + + r = st21nfca_tm_send_psl_res(hdev, psl_req); +exit: + return r; +} + +int st21nfca_tm_send_dep_res(struct nfc_hci_dev *hdev, struct sk_buff *skb) +{ + int r; + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + *skb_push(skb, 1) = info->dep_info.curr_nfc_dep_pni; + *skb_push(skb, 1) = ST21NFCA_NFCIP1_DEP_RES; + *skb_push(skb, 1) = ST21NFCA_NFCIP1_RES; + *skb_push(skb, 1) = skb->len; + + r = nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE, + ST21NFCA_EVT_SEND_DATA, skb->data, skb->len); + kfree_skb(skb); + + return r; +} +EXPORT_SYMBOL(st21nfca_tm_send_dep_res); + +static int st21nfca_tm_recv_dep_req(struct nfc_hci_dev *hdev, + struct sk_buff *skb) +{ + struct st21nfca_dep_req_res *dep_req; + u8 size; + int r; + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + skb_trim(skb, skb->len - 1); + if (IS_ERR(skb)) { + r = PTR_ERR(skb); + skb = NULL; + goto exit; + } + + size = 4; + + dep_req = (struct st21nfca_dep_req_res *)skb->data; + if (skb->len < size) { + r = -EIO; + goto exit; + } + + if (ST21NFCA_NFC_DEP_DID_BIT_SET(dep_req->pfb)) + size++; + if (ST21NFCA_NFC_DEP_NAD_BIT_SET(dep_req->pfb)) + size++; + + if (skb->len < size) { + r = -EIO; + goto exit; + } + + /* Receiving DEP_REQ - Decoding */ + switch (ST21NFCA_NFC_DEP_PFB_TYPE(dep_req->pfb)) { + case ST21NFCA_NFC_DEP_PFB_I_PDU: + info->dep_info.curr_nfc_dep_pni = + ST21NFCA_NFC_DEP_PFB_PNI(dep_req->pfb); + break; + case ST21NFCA_NFC_DEP_PFB_ACK_NACK_PDU: + pr_err("Received a ACK/NACK PDU\n"); + break; + case ST21NFCA_NFC_DEP_PFB_SUPERVISOR_PDU: + pr_err("Received a SUPERVISOR PDU\n"); + break; + } + + if (IS_ERR(skb)) { + r = PTR_ERR(skb); + skb = NULL; + goto exit; + } + + skb_pull(skb, size); + + return nfc_tm_data_received(hdev->ndev, skb); +exit: + return r; +} + +int st21nfca_tm_event_send_data(struct nfc_hci_dev *hdev, struct sk_buff *skb, + u8 gate) +{ + u8 cmd0, cmd1; + int r; + + cmd0 = skb->data[1]; + switch (cmd0) { + case ST21NFCA_NFCIP1_REQ: + cmd1 = skb->data[2]; + switch (cmd1) { + case ST21NFCA_NFCIP1_ATR_REQ: + r = st21nfca_tm_recv_atr_req(hdev, skb); + break; + case ST21NFCA_NFCIP1_PSL_REQ: + r = st21nfca_tm_recv_psl_req(hdev, skb); + break; + case ST21NFCA_NFCIP1_DEP_REQ: + r = st21nfca_tm_recv_dep_req(hdev, skb); + break; + default: + return 1; + } + default: + return 1; + } + return r; +} +EXPORT_SYMBOL(st21nfca_tm_event_send_data); + +static void st21nfca_im_send_psl_req(struct nfc_hci_dev *hdev, u8 did, u8 bsi, + u8 bri, u8 lri) +{ + struct sk_buff *skb; + struct st21nfca_psl_req *psl_req; + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + skb = + alloc_skb(sizeof(struct st21nfca_psl_req) + 1, GFP_KERNEL); + if (!skb) + return; + skb_reserve(skb, 1); + + skb_put(skb, sizeof(struct st21nfca_psl_req)); + psl_req = (struct st21nfca_psl_req *) skb->data; + + psl_req->length = sizeof(struct st21nfca_psl_req); + psl_req->cmd0 = ST21NFCA_NFCIP1_REQ; + psl_req->cmd1 = ST21NFCA_NFCIP1_PSL_REQ; + psl_req->did = did; + psl_req->brs = (0x30 & bsi << 4) | (bri & 0x03); + psl_req->fsl = lri; + + *skb_push(skb, 1) = info->dep_info.to | 0x10; + + st21nfca_im_send_pdu(info, skb); + + kfree_skb(skb); +} + +#define ST21NFCA_CB_TYPE_READER_F 1 +static void st21nfca_im_recv_atr_res_cb(void *context, struct sk_buff *skb, + int err) +{ + struct st21nfca_hci_info *info = context; + struct st21nfca_atr_res *atr_res; + int r; + + if (err != 0) + return; + + if (IS_ERR(skb)) + return; + + switch (info->async_cb_type) { + case ST21NFCA_CB_TYPE_READER_F: + skb_trim(skb, skb->len - 1); + atr_res = (struct st21nfca_atr_res *)skb->data; + r = nfc_set_remote_general_bytes(info->hdev->ndev, + atr_res->gbi, + skb->len - sizeof(struct st21nfca_atr_res)); + if (r < 0) + return; + + if (atr_res->to >= 0x0e) + info->dep_info.to = 0x0e; + else + info->dep_info.to = atr_res->to + 1; + + info->dep_info.to |= 0x10; + + r = nfc_dep_link_is_up(info->hdev->ndev, info->dep_info.idx, + NFC_COMM_PASSIVE, NFC_RF_INITIATOR); + if (r < 0) + return; + + info->dep_info.curr_nfc_dep_pni = 0; + if (ST21NFCA_PP2LRI(atr_res->ppi) != info->dep_info.lri) + st21nfca_im_send_psl_req(info->hdev, atr_res->did, + atr_res->bsi, atr_res->bri, + ST21NFCA_PP2LRI(atr_res->ppi)); + break; + default: + if (err == 0) + kfree_skb(skb); + break; + } +} + +int st21nfca_im_send_atr_req(struct nfc_hci_dev *hdev, u8 *gb, size_t gb_len) +{ + struct sk_buff *skb; + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + struct st21nfca_atr_req *atr_req; + struct nfc_target *target; + uint size; + + info->dep_info.to = ST21NFCA_DEFAULT_TIMEOUT; + size = ST21NFCA_ATR_REQ_MIN_SIZE + gb_len; + if (size > ST21NFCA_ATR_REQ_MAX_SIZE) { + PROTOCOL_ERR("14.6.1.1"); + return -EINVAL; + } + + skb = + alloc_skb(sizeof(struct st21nfca_atr_req) + gb_len + 1, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, 1); + + skb_put(skb, sizeof(struct st21nfca_atr_req)); + + atr_req = (struct st21nfca_atr_req *)skb->data; + memset(atr_req, 0, sizeof(struct st21nfca_atr_req)); + + atr_req->cmd0 = ST21NFCA_NFCIP1_REQ; + atr_req->cmd1 = ST21NFCA_NFCIP1_ATR_REQ; + memset(atr_req->nfcid3, 0, NFC_NFCID3_MAXSIZE); + target = hdev->ndev->targets; + + if (target->sensf_res) + memcpy(atr_req->nfcid3, target->sensf_res, + target->sensf_res_len); + else + get_random_bytes(atr_req->nfcid3, NFC_NFCID3_MAXSIZE); + + atr_req->did = 0x0; + + atr_req->bsi = 0x00; + atr_req->bri = 0x00; + atr_req->ppi = ST21NFCA_LR_BITS_PAYLOAD_SIZE_254B; + if (gb_len) { + atr_req->ppi |= ST21NFCA_GB_BIT; + memcpy(skb_put(skb, gb_len), gb, gb_len); + } + atr_req->length = sizeof(struct st21nfca_atr_req) + hdev->gb_len; + + *skb_push(skb, 1) = info->dep_info.to | 0x10; /* timeout */ + + info->async_cb_type = ST21NFCA_CB_TYPE_READER_F; + info->async_cb_context = info; + info->async_cb = st21nfca_im_recv_atr_res_cb; + info->dep_info.bri = atr_req->bri; + info->dep_info.bsi = atr_req->bsi; + info->dep_info.lri = ST21NFCA_PP2LRI(atr_req->ppi); + + return nfc_hci_send_cmd_async(hdev, ST21NFCA_RF_READER_F_GATE, + ST21NFCA_WR_XCHG_DATA, skb->data, + skb->len, info->async_cb, info); +} +EXPORT_SYMBOL(st21nfca_im_send_atr_req); + +static void st21nfca_im_recv_dep_res_cb(void *context, struct sk_buff *skb, + int err) +{ + struct st21nfca_hci_info *info = context; + struct st21nfca_dep_req_res *dep_res; + + int size; + + if (err != 0) + return; + + if (IS_ERR(skb)) + return; + + switch (info->async_cb_type) { + case ST21NFCA_CB_TYPE_READER_F: + dep_res = (struct st21nfca_dep_req_res *)skb->data; + + size = 3; + if (skb->len < size) + goto exit; + + if (ST21NFCA_NFC_DEP_DID_BIT_SET(dep_res->pfb)) + size++; + if (ST21NFCA_NFC_DEP_NAD_BIT_SET(dep_res->pfb)) + size++; + + if (skb->len < size) + goto exit; + + skb_trim(skb, skb->len - 1); + + /* Receiving DEP_REQ - Decoding */ + switch (ST21NFCA_NFC_DEP_PFB_TYPE(dep_res->pfb)) { + case ST21NFCA_NFC_DEP_PFB_ACK_NACK_PDU: + pr_err("Received a ACK/NACK PDU\n"); + case ST21NFCA_NFC_DEP_PFB_I_PDU: + info->dep_info.curr_nfc_dep_pni = + ST21NFCA_NFC_DEP_PFB_PNI(dep_res->pfb + 1); + size++; + skb_pull(skb, size); + nfc_tm_data_received(info->hdev->ndev, skb); + break; + case ST21NFCA_NFC_DEP_PFB_SUPERVISOR_PDU: + pr_err("Received a SUPERVISOR PDU\n"); + skb_pull(skb, size); + *skb_push(skb, 1) = ST21NFCA_NFCIP1_DEP_REQ; + *skb_push(skb, 1) = ST21NFCA_NFCIP1_REQ; + *skb_push(skb, 1) = skb->len; + *skb_push(skb, 1) = info->dep_info.to | 0x10; + + st21nfca_im_send_pdu(info, skb); + break; + } + + return; + default: + break; + } + +exit: + if (err == 0) + kfree_skb(skb); +} + +int st21nfca_im_send_dep_req(struct nfc_hci_dev *hdev, struct sk_buff *skb) +{ + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + info->async_cb_type = ST21NFCA_CB_TYPE_READER_F; + info->async_cb_context = info; + info->async_cb = st21nfca_im_recv_dep_res_cb; + + *skb_push(skb, 1) = info->dep_info.curr_nfc_dep_pni; + *skb_push(skb, 1) = ST21NFCA_NFCIP1_DEP_REQ; + *skb_push(skb, 1) = ST21NFCA_NFCIP1_REQ; + *skb_push(skb, 1) = skb->len; + + *skb_push(skb, 1) = info->dep_info.to | 0x10; + + return nfc_hci_send_cmd_async(hdev, ST21NFCA_RF_READER_F_GATE, + ST21NFCA_WR_XCHG_DATA, + skb->data, skb->len, + info->async_cb, info); +} +EXPORT_SYMBOL(st21nfca_im_send_dep_req); + +void st21nfca_dep_init(struct nfc_hci_dev *hdev) +{ + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + INIT_WORK(&info->dep_info.tx_work, st21nfca_tx_work); + info->dep_info.curr_nfc_dep_pni = 0; + info->dep_info.idx = 0; + info->dep_info.to = ST21NFCA_DEFAULT_TIMEOUT; +} +EXPORT_SYMBOL(st21nfca_dep_init); + +void st21nfca_dep_deinit(struct nfc_hci_dev *hdev) +{ + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + cancel_work_sync(&info->dep_info.tx_work); +} +EXPORT_SYMBOL(st21nfca_dep_deinit); diff --git a/drivers/nfc/st21nfca/st21nfca_dep.h b/drivers/nfc/st21nfca/st21nfca_dep.h new file mode 100644 index 000000000000..ca213dee9c6e --- /dev/null +++ b/drivers/nfc/st21nfca/st21nfca_dep.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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, see . + */ + +#ifndef __ST21NFCA_DEP_H +#define __ST21NFCA_DEP_H + +#include +#include + +struct st21nfca_dep_info { + struct sk_buff *tx_pending; + struct work_struct tx_work; + u8 curr_nfc_dep_pni; + u32 idx; + u8 to; + u8 did; + u8 bsi; + u8 bri; + u8 lri; +} __packed; + +int st21nfca_tm_event_send_data(struct nfc_hci_dev *hdev, struct sk_buff *skb, + u8 gate); +int st21nfca_tm_send_dep_res(struct nfc_hci_dev *hdev, struct sk_buff *skb); + +int st21nfca_im_send_atr_req(struct nfc_hci_dev *hdev, u8 *gb, size_t gb_len); +int st21nfca_im_send_dep_req(struct nfc_hci_dev *hdev, struct sk_buff *skb); +void st21nfca_dep_init(struct nfc_hci_dev *hdev); +void st21nfca_dep_deinit(struct nfc_hci_dev *hdev); +#endif /* __ST21NFCA_DEP_H */ -- cgit v1.2.3 From f63bac94bfe2b7f98d28e5c7d3432a5060841f51 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Mon, 21 Jul 2014 21:22:29 -0700 Subject: NFC: digital: Remove extra blank line Remove extra blank line that was inadvertently added by a recent commit. CC: Thierry Escande Signed-off-by: Mark A. Greer Signed-off-by: Samuel Ortiz --- include/net/nfc/digital.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/net/nfc/digital.h b/include/net/nfc/digital.h index 2bc31d10f9eb..575d668b7852 100644 --- a/include/net/nfc/digital.h +++ b/include/net/nfc/digital.h @@ -67,7 +67,6 @@ enum { NFC_DIGITAL_FRAMING_NFCB, NFC_DIGITAL_FRAMING_NFCB_T4T, - NFC_DIGITAL_FRAMING_LAST, }; -- cgit v1.2.3 From bf30a67c947ed57c1cf7c68a47dc24331458037e Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Mon, 21 Jul 2014 21:24:39 -0700 Subject: NFC: digital: Add 'tg_listen_md' and 'tg_get_rf_tech' driver hooks The digital layer of the NFC subsystem currently supports a 'tg_listen_mdaa' driver hook that supports devices that can do mode detection and automatic anticollision. However, there are some devices that can do mode detection but not automatic anitcollision so add the 'tg_listen_md' hook to support those devices. In order for the digital layer to get the RF technology detected by the device from the driver, add the 'tg_get_rf_tech' hook. It is only valid to call this hook immediately after a successful call to 'tg_listen_md'. CC: Thierry Escande Signed-off-by: Mark A. Greer Signed-off-by: Samuel Ortiz --- include/net/nfc/digital.h | 12 ++++++++ net/nfc/digital.h | 3 ++ net/nfc/digital_core.c | 16 +++++++++- net/nfc/digital_technology.c | 71 +++++++++++++++++++++++++++++++++++++++----- 4 files changed, 93 insertions(+), 9 deletions(-) diff --git a/include/net/nfc/digital.h b/include/net/nfc/digital.h index 575d668b7852..d9a5cf7ac1c4 100644 --- a/include/net/nfc/digital.h +++ b/include/net/nfc/digital.h @@ -127,6 +127,15 @@ typedef void (*nfc_digital_cmd_complete_t)(struct nfc_digital_dev *ddev, * the NFC-DEP ATR_REQ command through cb. The digital stack deducts the RF * tech by analyzing the SoD of the frame containing the ATR_REQ command. * This is an asynchronous function. + * @tg_listen_md: If supported, put the device in automatic listen mode with + * mode detection but without automatic anti-collision. In this mode, the + * device automatically detects the RF technology. What the actual + * RF technology is can be retrieved by calling @tg_get_rf_tech. + * The digital stack will then perform the appropriate anti-collision + * sequence. This is an asynchronous function. + * @tg_get_rf_tech: Required when @tg_listen_md is supported, unused otherwise. + * Return the RF Technology that was detected by the @tg_listen_md call. + * This is a synchronous function. * * @switch_rf: Turns device radio on or off. The stack does not call explicitly * switch_rf to turn the radio on. A call to in|tg_configure_hw must turn @@ -161,6 +170,9 @@ struct nfc_digital_ops { struct digital_tg_mdaa_params *mdaa_params, u16 timeout, nfc_digital_cmd_complete_t cb, void *arg); + int (*tg_listen_md)(struct nfc_digital_dev *ddev, u16 timeout, + nfc_digital_cmd_complete_t cb, void *arg); + int (*tg_get_rf_tech)(struct nfc_digital_dev *ddev, u8 *rf_tech); int (*switch_rf)(struct nfc_digital_dev *ddev, bool on); void (*abort_cmd)(struct nfc_digital_dev *ddev); diff --git a/net/nfc/digital.h b/net/nfc/digital.h index 71ad7eefddd4..3c39c72eb038 100644 --- a/net/nfc/digital.h +++ b/net/nfc/digital.h @@ -29,6 +29,7 @@ #define DIGITAL_CMD_TG_SEND 1 #define DIGITAL_CMD_TG_LISTEN 2 #define DIGITAL_CMD_TG_LISTEN_MDAA 3 +#define DIGITAL_CMD_TG_LISTEN_MD 4 #define DIGITAL_MAX_HEADER_LEN 7 #define DIGITAL_CRC_LEN 2 @@ -121,6 +122,8 @@ int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb); int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech); int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech); +void digital_tg_recv_md_req(struct nfc_digital_dev *ddev, void *arg, + struct sk_buff *resp); typedef u16 (*crc_func_t)(u16, const u8 *, size_t); diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c index 361bc37d2db1..009bcf317101 100644 --- a/net/nfc/digital_core.c +++ b/net/nfc/digital_core.c @@ -201,6 +201,11 @@ static void digital_wq_cmd(struct work_struct *work) digital_send_cmd_complete, cmd); break; + case DIGITAL_CMD_TG_LISTEN_MD: + rc = ddev->ops->tg_listen_md(ddev, cmd->timeout, + digital_send_cmd_complete, cmd); + break; + default: pr_err("Unknown cmd type %d\n", cmd->type); return; @@ -293,6 +298,12 @@ static int digital_tg_listen_mdaa(struct nfc_digital_dev *ddev, u8 rf_tech) 500, digital_tg_recv_atr_req, NULL); } +static int digital_tg_listen_md(struct nfc_digital_dev *ddev, u8 rf_tech) +{ + return digital_send_cmd(ddev, DIGITAL_CMD_TG_LISTEN_MD, NULL, NULL, 500, + digital_tg_recv_md_req, NULL); +} + int digital_target_found(struct nfc_digital_dev *ddev, struct nfc_target *target, u8 protocol) { @@ -510,6 +521,9 @@ static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols, if (ddev->ops->tg_listen_mdaa) { digital_add_poll_tech(ddev, 0, digital_tg_listen_mdaa); + } else if (ddev->ops->tg_listen_md) { + digital_add_poll_tech(ddev, 0, + digital_tg_listen_md); } else { digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A, digital_tg_listen_nfca); @@ -737,7 +751,7 @@ struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops, if (!ops->in_configure_hw || !ops->in_send_cmd || !ops->tg_listen || !ops->tg_configure_hw || !ops->tg_send_cmd || !ops->abort_cmd || - !ops->switch_rf) + !ops->switch_rf || (ops->tg_listen_md && !ops->tg_get_rf_tech)) return NULL; ddev = kzalloc(sizeof(struct nfc_digital_dev), GFP_KERNEL); diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c index d276518cc8bf..fb58ed2dd41d 100644 --- a/net/nfc/digital_technology.c +++ b/net/nfc/digital_technology.c @@ -1218,33 +1218,48 @@ exit: dev_kfree_skb(resp); } -int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech) +static int digital_tg_config_nfca(struct nfc_digital_dev *ddev) { int rc; - rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); + rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, + NFC_DIGITAL_RF_TECH_106A); if (rc) return rc; - rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, - NFC_DIGITAL_FRAMING_NFCA_NFC_DEP); + return digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, + NFC_DIGITAL_FRAMING_NFCA_NFC_DEP); +} + +int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech) +{ + int rc; + + rc = digital_tg_config_nfca(ddev); if (rc) return rc; return digital_tg_listen(ddev, 300, digital_tg_recv_sens_req, NULL); } -int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) +static int digital_tg_config_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) { int rc; - u8 *nfcid2; rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); if (rc) return rc; - rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, - NFC_DIGITAL_FRAMING_NFCF_NFC_DEP); + return digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, + NFC_DIGITAL_FRAMING_NFCF_NFC_DEP); +} + +int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) +{ + int rc; + u8 *nfcid2; + + rc = digital_tg_config_nfcf(ddev, rf_tech); if (rc) return rc; @@ -1258,3 +1273,43 @@ int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech) return digital_tg_listen(ddev, 300, digital_tg_recv_sensf_req, nfcid2); } + +void digital_tg_recv_md_req(struct nfc_digital_dev *ddev, void *arg, + struct sk_buff *resp) +{ + u8 rf_tech; + int rc; + + if (IS_ERR(resp)) { + resp = NULL; + goto exit_free_skb; + } + + rc = ddev->ops->tg_get_rf_tech(ddev, &rf_tech); + if (rc) + goto exit_free_skb; + + switch (rf_tech) { + case NFC_DIGITAL_RF_TECH_106A: + rc = digital_tg_config_nfca(ddev); + if (rc) + goto exit_free_skb; + digital_tg_recv_sens_req(ddev, arg, resp); + break; + case NFC_DIGITAL_RF_TECH_212F: + case NFC_DIGITAL_RF_TECH_424F: + rc = digital_tg_config_nfcf(ddev, rf_tech); + if (rc) + goto exit_free_skb; + digital_tg_recv_sensf_req(ddev, arg, resp); + break; + default: + goto exit_free_skb; + } + + return; + +exit_free_skb: + digital_poll_next_tech(ddev); + dev_kfree_skb(resp); +} -- cgit v1.2.3 From b5c0a8009094d37c73649867c6d7d332a0d4fb4c Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Mon, 21 Jul 2014 13:48:11 -0300 Subject: net: mvpp2: Fix the periodic XON enable bit This bit was originally wrong, the correct value is BIT(1), so fix it. Signed-off-by: Marcin Wojtas Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 4f6e4a1400e7..ed32f97496d3 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -262,7 +262,7 @@ #define MVPP2_GMAC_MAX_RX_SIZE_MASK 0x7ffc #define MVPP2_GMAC_MIB_CNTR_EN_MASK BIT(15) #define MVPP2_GMAC_CTRL_1_REG 0x4 -#define MVPP2_GMAC_PERIODIC_XON_EN_MASK BIT(0) +#define MVPP2_GMAC_PERIODIC_XON_EN_MASK BIT(1) #define MVPP2_GMAC_GMII_LB_EN_MASK BIT(5) #define MVPP2_GMAC_PCS_LB_EN_BIT 6 #define MVPP2_GMAC_PCS_LB_EN_MASK BIT(6) -- cgit v1.2.3 From 08a23755080f590c577ecedb5a444e55daeb258c Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Mon, 21 Jul 2014 13:48:12 -0300 Subject: net: mvpp2: Enable proper PHY polling and fix port functionality Currently, the network interfaces that are not configured by the bootloader (using e.g. tftp or ping) can detect the link status but are unable to transmit data. The network controller has a functionality that allows the hardware to continuously poll the PHY and directly update the MAC configuration accordingly (speed, duplex, etc.). However, this doesn't work well with phylib's software-based polling and updating MAC configuration in the driver's callback. This commit fixes this issue by: 1. Setting MVPP2_PHY_AN_STOP_SMI0_MASK in MVPP2_PHY_AN_CFG0_REG in mvpp2_init(), which disables the harware polling feature. 2. Disabling MVPP2_GMAC_PCS_ENABLE_MASK bit in MVPP2_GMAC_CTRL_2_REG in mvpp2_port_mii_set() for port types other than SGMII. Signed-off-by: Marcin Wojtas Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 40 ++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index ed32f97496d3..ebb63d80ad51 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -248,6 +248,8 @@ /* LMS registers */ #define MVPP2_SRC_ADDR_MIDDLE 0x24 #define MVPP2_SRC_ADDR_HIGH 0x28 +#define MVPP2_PHY_AN_CFG0_REG 0x34 +#define MVPP2_PHY_AN_STOP_SMI0_MASK BIT(7) #define MVPP2_MIB_COUNTERS_BASE(port) (0x1000 + ((port) >> 1) * \ 0x400 + (port) * 0x400) #define MVPP2_MIB_LATE_COLLISION 0x7c @@ -278,6 +280,7 @@ #define MVPP2_GMAC_CONFIG_MII_SPEED BIT(5) #define MVPP2_GMAC_CONFIG_GMII_SPEED BIT(6) #define MVPP2_GMAC_AN_SPEED_EN BIT(7) +#define MVPP2_GMAC_FC_ADV_EN BIT(9) #define MVPP2_GMAC_CONFIG_FULL_DUPLEX BIT(12) #define MVPP2_GMAC_AN_DUPLEX_EN BIT(13) #define MVPP2_GMAC_PORT_FIFO_CFG_1_REG 0x1c @@ -3809,16 +3812,30 @@ static void mvpp2_interrupts_unmask(void *arg) static void mvpp2_port_mii_set(struct mvpp2_port *port) { - u32 reg, val = 0; + u32 val; - if (port->phy_interface == PHY_INTERFACE_MODE_SGMII) - val = MVPP2_GMAC_PCS_ENABLE_MASK | - MVPP2_GMAC_INBAND_AN_MASK; - else if (port->phy_interface == PHY_INTERFACE_MODE_RGMII) - val = MVPP2_GMAC_PORT_RGMII_MASK; + val = readl(port->base + MVPP2_GMAC_CTRL_2_REG); + + switch (port->phy_interface) { + case PHY_INTERFACE_MODE_SGMII: + val |= MVPP2_GMAC_INBAND_AN_MASK; + break; + case PHY_INTERFACE_MODE_RGMII: + val |= MVPP2_GMAC_PORT_RGMII_MASK; + default: + val &= ~MVPP2_GMAC_PCS_ENABLE_MASK; + } + + writel(val, port->base + MVPP2_GMAC_CTRL_2_REG); +} - reg = readl(port->base + MVPP2_GMAC_CTRL_2_REG); - writel(reg | val, port->base + MVPP2_GMAC_CTRL_2_REG); +static void mvpp2_port_fc_adv_enable(struct mvpp2_port *port) +{ + u32 val; + + val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG); + val |= MVPP2_GMAC_FC_ADV_EN; + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG); } static void mvpp2_port_enable(struct mvpp2_port *port) @@ -5877,6 +5894,7 @@ static void mvpp2_port_power_up(struct mvpp2_port *port) { mvpp2_port_mii_set(port); mvpp2_port_periodic_xon_disable(port); + mvpp2_port_fc_adv_enable(port); mvpp2_port_reset(port); } @@ -6197,6 +6215,7 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv) { const struct mbus_dram_target_info *dram_target_info; int err, i; + u32 val; /* Checks for hardware constraints */ if (rxq_number % 4 || (rxq_number > MVPP2_MAX_RXQ) || @@ -6210,6 +6229,11 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv) if (dram_target_info) mvpp2_conf_mbus_windows(dram_target_info, priv); + /* Disable HW PHY polling */ + val = readl(priv->lms_base + MVPP2_PHY_AN_CFG0_REG); + val |= MVPP2_PHY_AN_STOP_SMI0_MASK; + writel(val, priv->lms_base + MVPP2_PHY_AN_CFG0_REG); + /* Allocate and initialize aggregated TXQs */ priv->aggr_txqs = devm_kcalloc(&pdev->dev, num_present_cpus(), sizeof(struct mvpp2_tx_queue), -- cgit v1.2.3 From d74c96c10c03025327c5004900d72bfa03bc957b Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 21 Jul 2014 13:48:13 -0300 Subject: net: mvpp2: Fix the BM pool buffer release check After a call to mvpp2_bm_bufs_free(), the caller usually wants to know if the function successfully freed the requested number. However, this cannot be done by looking into the BM pool count, because the current buffer count was updated by mvpp2_bm_bufs_free(). In fact, the current callers of mvpp2_bm_bufs_free() use it to release all the buffers in the pool, so we can fix this by simply checking if the pool is not empty. Signed-off-by: Ezequiel Garcia Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index ebb63d80ad51..da61d51df067 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -3420,7 +3420,7 @@ static int mvpp2_bm_pool_destroy(struct platform_device *pdev, u32 val; num = mvpp2_bm_bufs_free(priv, bm_pool, bm_pool->buf_num); - if (num != bm_pool->buf_num) { + if (bm_pool->buf_num) { WARN(1, "cannot free all buffers in pool %d\n", bm_pool->id); return 0; } @@ -3748,8 +3748,8 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu) int pkt_size = MVPP2_RX_PKT_SIZE(mtu); /* Update BM pool with new buffer size */ - num = mvpp2_bm_bufs_free(port->priv, port_pool, pkts_num); - if (num != pkts_num) { + mvpp2_bm_bufs_free(port->priv, port_pool, pkts_num); + if (port_pool->buf_num) { WARN(1, "cannot free all buffers in pool %d\n", port_pool->id); return -EIO; } -- cgit v1.2.3 From 7861f12bfd9f63e346b33a2b9841136f541dfbe3 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 21 Jul 2014 13:48:14 -0300 Subject: net: mvpp2: Simplify BM pool buffers freeing Now that all the users of mvpp2_bm_bufs_free() have been fixed, we can safely clean the function prototype. The function is always called to release all the buffers in a BM pool, and the number of buffers freed is not needed. Therefore, we change the return to a void, and remove the "num" parameter. This is a cosmetic change, to make the code slightly cleaner. Signed-off-by: Ezequiel Garcia Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index da61d51df067..3193a7de7197 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -3385,17 +3385,12 @@ static void mvpp2_bm_pool_bufsize_set(struct mvpp2 *priv, mvpp2_write(priv, MVPP2_POOL_BUF_SIZE_REG(bm_pool->id), val); } -/* Free "num" buffers from the pool */ -static int mvpp2_bm_bufs_free(struct mvpp2 *priv, - struct mvpp2_bm_pool *bm_pool, int num) +/* Free all buffers from the pool */ +static void mvpp2_bm_bufs_free(struct mvpp2 *priv, struct mvpp2_bm_pool *bm_pool) { int i; - if (num >= bm_pool->buf_num) - /* Free all buffers from the pool */ - num = bm_pool->buf_num; - - for (i = 0; i < num; i++) { + for (i = 0; i < bm_pool->buf_num; i++) { u32 vaddr; /* Get buffer virtual adress (indirect access) */ @@ -3408,7 +3403,6 @@ static int mvpp2_bm_bufs_free(struct mvpp2 *priv, /* Update BM driver with number of buffers removed from pool */ bm_pool->buf_num -= i; - return i; } /* Cleanup pool */ @@ -3416,10 +3410,9 @@ static int mvpp2_bm_pool_destroy(struct platform_device *pdev, struct mvpp2 *priv, struct mvpp2_bm_pool *bm_pool) { - int num; u32 val; - num = mvpp2_bm_bufs_free(priv, bm_pool, bm_pool->buf_num); + mvpp2_bm_bufs_free(priv, bm_pool); if (bm_pool->buf_num) { WARN(1, "cannot free all buffers in pool %d\n", bm_pool->id); return 0; @@ -3675,7 +3668,7 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type, MVPP2_BM_LONG_BUF_NUM : MVPP2_BM_SHORT_BUF_NUM; else - mvpp2_bm_bufs_free(port->priv, new_pool, pkts_num); + mvpp2_bm_bufs_free(port->priv, new_pool); new_pool->pkt_size = pkt_size; @@ -3748,7 +3741,7 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu) int pkt_size = MVPP2_RX_PKT_SIZE(mtu); /* Update BM pool with new buffer size */ - mvpp2_bm_bufs_free(port->priv, port_pool, pkts_num); + mvpp2_bm_bufs_free(port->priv, port_pool); if (port_pool->buf_num) { WARN(1, "cannot free all buffers in pool %d\n", port_pool->id); return -EIO; -- cgit v1.2.3 From b94901f3ede8fa5ea334f59bf947eba7d0cb24f3 Mon Sep 17 00:00:00 2001 From: Eyal Perry Date: Tue, 22 Jul 2014 15:44:09 +0300 Subject: net/mlx4_en: current_mac isn't updated in port up When port is down dev_addr is changed (e.g. by bonding) but current_mac is not touched. When port is up again, hash_mac is updated to dev_addr, but current_mac isn't. This leads to inconsistency between current_mac and mac_hash. Because of that, mlx4_en_replace_mac() fails to find current_mac in mac_hash. Fix is to reset current_mac to dev_addr when port is up - as we do for mac_hash. Signed-off-by: Eyal Perry Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 887cf01d831d..82708bd5c339 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -644,6 +644,7 @@ static int mlx4_en_get_qp(struct mlx4_en_priv *priv) goto alloc_err; } memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac)); + memcpy(priv->current_mac, entry->mac, sizeof(priv->current_mac)); entry->reg_id = reg_id; hlist_add_head_rcu(&entry->hlist, -- cgit v1.2.3 From 0fef9d0308d4c524da716b4b669d8754594450b2 Mon Sep 17 00:00:00 2001 From: Amir Vadai Date: Tue, 22 Jul 2014 15:44:10 +0300 Subject: net/mlx4_en: Disable blueflame using ethtool private flags Enable the user to turn off the hardware feature called BlueFlame. Since it is something specific to mlx4_en hardware, we control the feature via ethtool private flags. Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 57 +++++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 1 + drivers/net/ethernet/mellanox/mlx4/en_tx.c | 13 ++++-- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 5 +++ 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 68d763d2d030..50e85cc1d61f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -98,6 +98,10 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) drvinfo->eedump_len = 0; } +static const char mlx4_en_priv_flags[][ETH_GSTRING_LEN] = { + "blueflame", +}; + static const char main_strings[][ETH_GSTRING_LEN] = { "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", @@ -235,6 +239,8 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset) case ETH_SS_TEST: return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UC_LOOPBACK) * 2; + case ETH_SS_PRIV_FLAGS: + return ARRAY_SIZE(mlx4_en_priv_flags); default: return -EOPNOTSUPP; } @@ -358,6 +364,12 @@ static void mlx4_en_get_strings(struct net_device *dev, #endif } break; + case ETH_SS_PRIV_FLAGS: + for (i = 0; i < ARRAY_SIZE(mlx4_en_priv_flags); i++) + strcpy(data + i * ETH_GSTRING_LEN, + mlx4_en_priv_flags[i]); + break; + } } @@ -1209,6 +1221,49 @@ static int mlx4_en_get_ts_info(struct net_device *dev, return ret; } +int mlx4_en_set_priv_flags(struct net_device *dev, u32 flags) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + bool bf_enabled_new = !!(flags & MLX4_EN_PRIV_FLAGS_BLUEFLAME); + bool bf_enabled_old = !!(priv->pflags & MLX4_EN_PRIV_FLAGS_BLUEFLAME); + int i; + + if (bf_enabled_new == bf_enabled_old) + return 0; /* Nothing to do */ + + if (bf_enabled_new) { + bool bf_supported = true; + + for (i = 0; i < priv->tx_ring_num; i++) + bf_supported &= priv->tx_ring[i]->bf_alloced; + + if (!bf_supported) { + en_err(priv, "BlueFlame is not supported\n"); + return -EINVAL; + } + + priv->pflags |= MLX4_EN_PRIV_FLAGS_BLUEFLAME; + } else { + priv->pflags &= ~MLX4_EN_PRIV_FLAGS_BLUEFLAME; + } + + for (i = 0; i < priv->tx_ring_num; i++) + priv->tx_ring[i]->bf_enabled = bf_enabled_new; + + en_info(priv, "BlueFlame %s\n", + bf_enabled_new ? "Enabled" : "Disabled"); + + return 0; +} + +u32 mlx4_en_get_priv_flags(struct net_device *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + return priv->pflags; +} + + const struct ethtool_ops mlx4_en_ethtool_ops = { .get_drvinfo = mlx4_en_get_drvinfo, .get_settings = mlx4_en_get_settings, @@ -1236,6 +1291,8 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { .get_channels = mlx4_en_get_channels, .set_channels = mlx4_en_set_channels, .get_ts_info = mlx4_en_get_ts_info, + .set_priv_flags = mlx4_en_set_priv_flags, + .get_priv_flags = mlx4_en_get_priv_flags, }; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 82708bd5c339..bb536aa613f4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2465,6 +2465,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->port = port; priv->port_up = false; priv->flags = prof->flags; + priv->pflags = MLX4_EN_PRIV_FLAGS_BLUEFLAME; priv->ctrl_flags = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE | MLX4_WQE_CTRL_SOLICITED); priv->num_tx_rings_p_up = mdev->profile.num_tx_rings_p_up; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 5045bab59633..dae3da6d8dd0 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -126,8 +126,13 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, ring->bf.uar = &mdev->priv_uar; ring->bf.uar->map = mdev->uar_map; ring->bf_enabled = false; - } else - ring->bf_enabled = true; + ring->bf_alloced = false; + priv->pflags &= ~MLX4_EN_PRIV_FLAGS_BLUEFLAME; + } else { + ring->bf_alloced = true; + ring->bf_enabled = !!(priv->pflags & + MLX4_EN_PRIV_FLAGS_BLUEFLAME); + } ring->hwtstamp_tx_type = priv->hwtstamp_config.tx_type; ring->queue_index = queue_index; @@ -161,7 +166,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring = *pring; en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); - if (ring->bf_enabled) + if (ring->bf_alloced) mlx4_bf_free(mdev->dev, &ring->bf); mlx4_qp_remove(mdev->dev, &ring->qp); mlx4_qp_free(mdev->dev, &ring->qp); @@ -195,7 +200,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn, ring->cqn, user_prio, &ring->context); - if (ring->bf_enabled) + if (ring->bf_alloced) ring->context.usr_page = cpu_to_be32(ring->bf.uar->index); err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context, diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 2b19dd1f2c5d..54c277412e42 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -93,6 +93,8 @@ * OS related constants and tunables */ +#define MLX4_EN_PRIV_FLAGS_BLUEFLAME 1 + #define MLX4_EN_WATCHDOG_TIMEOUT (15 * HZ) /* Use the maximum between 16384 and a single page */ @@ -278,6 +280,7 @@ struct mlx4_en_tx_ring { unsigned long wake_queue; struct mlx4_bf bf; bool bf_enabled; + bool bf_alloced; struct netdev_queue *tx_queue; int hwtstamp_tx_type; int inline_thold; @@ -592,6 +595,8 @@ struct mlx4_en_priv { #endif u64 tunnel_reg_id; __be16 vxlan_port; + + u32 pflags; }; enum mlx4_en_wol { -- cgit v1.2.3 From 2599d8580f93f0794d2fa850501b1068ce1d0aa8 Mon Sep 17 00:00:00 2001 From: Amir Vadai Date: Tue, 22 Jul 2014 15:44:11 +0300 Subject: net/mlx4_core: Use low memory profile on kdump kernel When running in kdump kernel, reduce number of resources allocated for the hardware. This will enable the NIC to operate in this low memory environment at the expense of performance and some features not related to the basic NIC functionality. Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 28 +++++++++++++++++++++++++--- include/linux/mlx4/device.h | 7 +++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 82ab427290c3..80b8c5f30e4e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -120,6 +120,16 @@ static struct mlx4_profile default_profile = { .num_mtt = 1 << 20, /* It is really num mtt segements */ }; +static struct mlx4_profile low_mem_profile = { + .num_qp = 1 << 17, + .num_srq = 1 << 6, + .rdmarc_per_qp = 1 << 4, + .num_cq = 1 << 8, + .num_mcg = 1 << 8, + .num_mpt = 1 << 9, + .num_mtt = 1 << 7, +}; + static int log_num_mac = 7; module_param_named(log_num_mac, log_num_mac, int, 0444); MODULE_PARM_DESC(log_num_mac, "Log2 max number of MACs per ETH port (1-7)"); @@ -129,6 +139,8 @@ module_param_named(log_num_vlan, log_num_vlan, int, 0444); MODULE_PARM_DESC(log_num_vlan, "Log2 max number of VLANs per ETH port (0-7)"); /* Log2 max number of VLANs per ETH port (0-7) */ #define MLX4_LOG_NUM_VLANS 7 +#define MLX4_MIN_LOG_NUM_VLANS 0 +#define MLX4_MIN_LOG_NUM_MAC 1 static bool use_prio; module_param_named(use_prio, use_prio, bool, 0444); @@ -287,8 +299,13 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) if (mlx4_is_mfunc(dev)) dev->caps.flags &= ~MLX4_DEV_CAP_FLAG_SENSE_SUPPORT; - dev->caps.log_num_macs = log_num_mac; - dev->caps.log_num_vlans = MLX4_LOG_NUM_VLANS; + if (mlx4_low_memory_profile()) { + dev->caps.log_num_macs = MLX4_MIN_LOG_NUM_MAC; + dev->caps.log_num_vlans = MLX4_MIN_LOG_NUM_VLANS; + } else { + dev->caps.log_num_macs = log_num_mac; + dev->caps.log_num_vlans = MLX4_LOG_NUM_VLANS; + } for (i = 1; i <= dev->caps.num_ports; ++i) { dev->caps.port_type[i] = MLX4_PORT_TYPE_NONE; @@ -1587,7 +1604,12 @@ static int mlx4_init_hca(struct mlx4_dev *dev) if (mlx4_is_master(dev)) mlx4_parav_master_pf_caps(dev); - profile = default_profile; + if (mlx4_low_memory_profile()) { + mlx4_info(dev, "Running from within kdump kernel. Using low memory profile\n"); + profile = low_mem_profile; + } else { + profile = default_profile; + } if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) profile.num_mcg = MLX4_FS_NUM_MCG; diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index fa660aedb822..e15b1544ea83 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -1254,4 +1254,11 @@ int mlx4_vf_smi_enabled(struct mlx4_dev *dev, int slave, int port); int mlx4_vf_get_enable_smi_admin(struct mlx4_dev *dev, int slave, int port); int mlx4_vf_set_enable_smi_admin(struct mlx4_dev *dev, int slave, int port, int enable); + +/* Returns true if running in low memory profile (kdump kernel) */ +static inline bool mlx4_low_memory_profile(void) +{ + return reset_devices; +} + #endif /* MLX4_DEVICE_H */ -- cgit v1.2.3 From ea1c1af1396cac9f8a1160acdac17f80e4b4f2c4 Mon Sep 17 00:00:00 2001 From: Amir Vadai Date: Tue, 22 Jul 2014 15:44:12 +0300 Subject: net/mlx4_en: Reduce memory consumption on kdump kernel When memory is limited, reduce number of rx and tx rings. Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_main.c | 6 ++++-- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 5 +++-- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index f953c1d7eae6..3626fdf4cb5d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -129,8 +129,10 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) int i; params->udp_rss = udp_rss; - params->num_tx_rings_p_up = min_t(int, num_online_cpus(), - MLX4_EN_MAX_TX_RING_P_UP); + params->num_tx_rings_p_up = mlx4_low_memory_profile() ? + MLX4_EN_MIN_TX_RING_P_UP : + min_t(int, num_online_cpus(), MLX4_EN_MAX_TX_RING_P_UP); + if (params->udp_rss && !(mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UDP_RSS)) { mlx4_warn(mdev, "UDP RSS is not supported on this device\n"); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 7765a08f9e84..9c909d23f14c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -335,8 +335,9 @@ void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev) dev->caps.comp_pool/ dev->caps.num_ports) - 1; - num_rx_rings = min_t(int, num_of_eqs, - netif_get_num_default_rss_queues()); + num_rx_rings = mlx4_low_memory_profile() ? MIN_RX_RINGS : + min_t(int, num_of_eqs, + netif_get_num_default_rss_queues()); mdev->profile.prof[i].rx_ring_num = rounddown_pow_of_two(num_rx_rings); } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 54c277412e42..3de41be49425 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -121,6 +121,7 @@ enum { #define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE) #define MLX4_EN_SMALL_PKT_SIZE 64 +#define MLX4_EN_MIN_TX_RING_P_UP 1 #define MLX4_EN_MAX_TX_RING_P_UP 32 #define MLX4_EN_NUM_UP 8 #define MLX4_EN_DEF_TX_RING_SIZE 512 -- cgit v1.2.3 From 36763266bbe8a2e93a7639b99bac2fee2c42bc5b Mon Sep 17 00:00:00 2001 From: Alexandre Rames Date: Tue, 22 Jul 2014 14:03:25 +0100 Subject: sfc: Add support for busy polling This patch adds the sfc driver code for implementing busy polling. It adds ndo_busy_poll method and locking between it and napi poll. It also adds each napi to the napi_hash right after netif_napi_add(). Uses efx_start_eventq and efx_stop_eventq in the self tests. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/efx.c | 54 ++++++++++++- drivers/net/ethernet/sfc/efx.h | 2 + drivers/net/ethernet/sfc/net_driver.h | 148 ++++++++++++++++++++++++++++++++++ drivers/net/ethernet/sfc/rx.c | 6 +- drivers/net/ethernet/sfc/selftest.c | 5 +- 5 files changed, 208 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 4b80c0be6e57..4cebe9d37816 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -272,6 +272,9 @@ static int efx_poll(struct napi_struct *napi, int budget) struct efx_nic *efx = channel->efx; int spent; + if (!efx_channel_lock_napi(channel)) + return budget; + netif_vdbg(efx, intr, efx->net_dev, "channel %d NAPI poll executing on CPU %d\n", channel->channel, raw_smp_processor_id()); @@ -311,6 +314,7 @@ static int efx_poll(struct napi_struct *napi, int budget) efx_nic_eventq_read_ack(channel); } + efx_channel_unlock_napi(channel); return spent; } @@ -357,7 +361,7 @@ static int efx_init_eventq(struct efx_channel *channel) } /* Enable event queue processing and NAPI */ -static void efx_start_eventq(struct efx_channel *channel) +void efx_start_eventq(struct efx_channel *channel) { netif_dbg(channel->efx, ifup, channel->efx->net_dev, "chan %d start event queue\n", channel->channel); @@ -366,17 +370,20 @@ static void efx_start_eventq(struct efx_channel *channel) channel->enabled = true; smp_wmb(); + efx_channel_enable(channel); napi_enable(&channel->napi_str); efx_nic_eventq_read_ack(channel); } /* Disable event queue processing and NAPI */ -static void efx_stop_eventq(struct efx_channel *channel) +void efx_stop_eventq(struct efx_channel *channel) { if (!channel->enabled) return; napi_disable(&channel->napi_str); + while (!efx_channel_disable(channel)) + usleep_range(1000, 20000); channel->enabled = false; } @@ -1960,6 +1967,8 @@ static void efx_init_napi_channel(struct efx_channel *channel) channel->napi_dev = efx->net_dev; netif_napi_add(channel->napi_dev, &channel->napi_str, efx_poll, napi_weight); + napi_hash_add(&channel->napi_str); + efx_channel_init_lock(channel); } static void efx_init_napi(struct efx_nic *efx) @@ -1972,8 +1981,10 @@ static void efx_init_napi(struct efx_nic *efx) static void efx_fini_napi_channel(struct efx_channel *channel) { - if (channel->napi_dev) + if (channel->napi_dev) { netif_napi_del(&channel->napi_str); + napi_hash_del(&channel->napi_str); + } channel->napi_dev = NULL; } @@ -2008,6 +2019,37 @@ static void efx_netpoll(struct net_device *net_dev) #endif +#ifdef CONFIG_NET_RX_BUSY_POLL +static int efx_busy_poll(struct napi_struct *napi) +{ + struct efx_channel *channel = + container_of(napi, struct efx_channel, napi_str); + struct efx_nic *efx = channel->efx; + int budget = 4; + int old_rx_packets, rx_packets; + + if (!netif_running(efx->net_dev)) + return LL_FLUSH_FAILED; + + if (!efx_channel_lock_poll(channel)) + return LL_FLUSH_BUSY; + + old_rx_packets = channel->rx_queue.rx_packets; + efx_process_channel(channel, budget); + + rx_packets = channel->rx_queue.rx_packets - old_rx_packets; + + /* There is no race condition with NAPI here. + * NAPI will automatically be rescheduled if it yielded during busy + * polling, because it was not able to take the lock and thus returned + * the full budget. + */ + efx_channel_unlock_poll(channel); + + return rx_packets; +} +#endif + /************************************************************************** * * Kernel net device interface @@ -2177,6 +2219,9 @@ static const struct net_device_ops efx_farch_netdev_ops = { .ndo_poll_controller = efx_netpoll, #endif .ndo_setup_tc = efx_setup_tc, +#ifdef CONFIG_NET_RX_BUSY_POLL + .ndo_busy_poll = efx_busy_poll, +#endif #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = efx_filter_rfs, #endif @@ -2197,6 +2242,9 @@ static const struct net_device_ops efx_ef10_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = efx_netpoll, #endif +#ifdef CONFIG_NET_RX_BUSY_POLL + .ndo_busy_poll = efx_busy_poll, +#endif #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = efx_filter_rfs, #endif diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index b41601e052d6..2587c582a821 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -194,6 +194,8 @@ int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, bool rx_may_override_tx); void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, unsigned int *rx_usecs, bool *rx_adaptive); +void efx_stop_eventq(struct efx_channel *channel); +void efx_start_eventq(struct efx_channel *channel); /* Dummy PHY ops for PHY drivers */ int efx_port_dummy_op_int(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index fb2e3bfeb2c2..9ede32064685 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "enum.h" #include "bitfield.h" @@ -387,6 +388,8 @@ enum efx_sync_events_state { * @irq_moderation: IRQ moderation value (in hardware ticks) * @napi_dev: Net device used with NAPI * @napi_str: NAPI control structure + * @state: state for NAPI vs busy polling + * @state_lock: lock protecting @state * @eventq: Event queue buffer * @eventq_mask: Event queue pointer mask * @eventq_read_ptr: Event queue read pointer @@ -424,6 +427,22 @@ struct efx_channel { unsigned int irq_moderation; struct net_device *napi_dev; struct napi_struct napi_str; +#ifdef CONFIG_NET_RX_BUSY_POLL + unsigned int state; + spinlock_t state_lock; +#define EFX_CHANNEL_STATE_IDLE 0 +#define EFX_CHANNEL_STATE_NAPI (1 << 0) /* NAPI owns this channel */ +#define EFX_CHANNEL_STATE_POLL (1 << 1) /* poll owns this channel */ +#define EFX_CHANNEL_STATE_DISABLED (1 << 2) /* channel is disabled */ +#define EFX_CHANNEL_STATE_NAPI_YIELD (1 << 3) /* NAPI yielded this channel */ +#define EFX_CHANNEL_STATE_POLL_YIELD (1 << 4) /* poll yielded this channel */ +#define EFX_CHANNEL_OWNED \ + (EFX_CHANNEL_STATE_NAPI | EFX_CHANNEL_STATE_POLL) +#define EFX_CHANNEL_LOCKED \ + (EFX_CHANNEL_OWNED | EFX_CHANNEL_STATE_DISABLED) +#define EFX_CHANNEL_USER_PEND \ + (EFX_CHANNEL_STATE_POLL | EFX_CHANNEL_STATE_POLL_YIELD) +#endif /* CONFIG_NET_RX_BUSY_POLL */ struct efx_special_buffer eventq; unsigned int eventq_mask; unsigned int eventq_read_ptr; @@ -457,6 +476,135 @@ struct efx_channel { u32 sync_timestamp_minor; }; +#ifdef CONFIG_NET_RX_BUSY_POLL +static inline void efx_channel_init_lock(struct efx_channel *channel) +{ + spin_lock_init(&channel->state_lock); +} + +/* Called from the device poll routine to get ownership of a channel. */ +static inline bool efx_channel_lock_napi(struct efx_channel *channel) +{ + bool rc = true; + + spin_lock_bh(&channel->state_lock); + if (channel->state & EFX_CHANNEL_LOCKED) { + WARN_ON(channel->state & EFX_CHANNEL_STATE_NAPI); + channel->state |= EFX_CHANNEL_STATE_NAPI_YIELD; + rc = false; + } else { + /* we don't care if someone yielded */ + channel->state = EFX_CHANNEL_STATE_NAPI; + } + spin_unlock_bh(&channel->state_lock); + return rc; +} + +static inline void efx_channel_unlock_napi(struct efx_channel *channel) +{ + spin_lock_bh(&channel->state_lock); + WARN_ON(channel->state & + (EFX_CHANNEL_STATE_POLL | EFX_CHANNEL_STATE_NAPI_YIELD)); + + channel->state &= EFX_CHANNEL_STATE_DISABLED; + spin_unlock_bh(&channel->state_lock); +} + +/* Called from efx_busy_poll(). */ +static inline bool efx_channel_lock_poll(struct efx_channel *channel) +{ + bool rc = true; + + spin_lock_bh(&channel->state_lock); + if ((channel->state & EFX_CHANNEL_LOCKED)) { + channel->state |= EFX_CHANNEL_STATE_POLL_YIELD; + rc = false; + } else { + /* preserve yield marks */ + channel->state |= EFX_CHANNEL_STATE_POLL; + } + spin_unlock_bh(&channel->state_lock); + return rc; +} + +/* Returns true if NAPI tried to get the channel while it was locked. */ +static inline void efx_channel_unlock_poll(struct efx_channel *channel) +{ + spin_lock_bh(&channel->state_lock); + WARN_ON(channel->state & EFX_CHANNEL_STATE_NAPI); + + /* will reset state to idle, unless channel is disabled */ + channel->state &= EFX_CHANNEL_STATE_DISABLED; + spin_unlock_bh(&channel->state_lock); +} + +/* True if a socket is polling, even if it did not get the lock. */ +static inline bool efx_channel_busy_polling(struct efx_channel *channel) +{ + WARN_ON(!(channel->state & EFX_CHANNEL_OWNED)); + return channel->state & EFX_CHANNEL_USER_PEND; +} + +static inline void efx_channel_enable(struct efx_channel *channel) +{ + spin_lock_bh(&channel->state_lock); + channel->state = EFX_CHANNEL_STATE_IDLE; + spin_unlock_bh(&channel->state_lock); +} + +/* False if the channel is currently owned. */ +static inline bool efx_channel_disable(struct efx_channel *channel) +{ + bool rc = true; + + spin_lock_bh(&channel->state_lock); + if (channel->state & EFX_CHANNEL_OWNED) + rc = false; + channel->state |= EFX_CHANNEL_STATE_DISABLED; + spin_unlock_bh(&channel->state_lock); + + return rc; +} + +#else /* CONFIG_NET_RX_BUSY_POLL */ + +static inline void efx_channel_init_lock(struct efx_channel *channel) +{ +} + +static inline bool efx_channel_lock_napi(struct efx_channel *channel) +{ + return true; +} + +static inline void efx_channel_unlock_napi(struct efx_channel *channel) +{ +} + +static inline bool efx_channel_lock_poll(struct efx_channel *channel) +{ + return false; +} + +static inline void efx_channel_unlock_poll(struct efx_channel *channel) +{ +} + +static inline bool efx_channel_busy_polling(struct efx_channel *channel) +{ + return false; +} + +static inline void efx_channel_enable(struct efx_channel *channel) +{ +} + +static inline bool efx_channel_disable(struct efx_channel *channel) +{ + return true; +} +#endif /* CONFIG_NET_RX_BUSY_POLL */ + /** * struct efx_msi_context - Context for each MSI * @efx: The associated NIC diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index a7bb63a7a521..c0ad95d2f63d 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -462,6 +462,7 @@ efx_rx_packet_gro(struct efx_channel *channel, struct efx_rx_buffer *rx_buf, skb_record_rx_queue(skb, channel->rx_queue.core_index); + skb_mark_napi_id(skb, &channel->napi_str); gro_result = napi_gro_frags(napi); if (gro_result != GRO_DROP) channel->irq_mod_score += 2; @@ -520,6 +521,8 @@ static struct sk_buff *efx_rx_mk_skb(struct efx_channel *channel, /* Move past the ethernet header */ skb->protocol = eth_type_trans(skb, efx->net_dev); + skb_mark_napi_id(skb, &channel->napi_str); + return skb; } @@ -666,7 +669,8 @@ void __efx_rx_packet(struct efx_channel *channel) if (unlikely(!(efx->net_dev->features & NETIF_F_RXCSUM))) rx_buf->flags &= ~EFX_RX_PKT_CSUMMED; - if ((rx_buf->flags & EFX_RX_PKT_TCP) && !channel->type->receive_skb) + if ((rx_buf->flags & EFX_RX_PKT_TCP) && !channel->type->receive_skb && + !efx_channel_busy_polling(channel)) efx_rx_packet_gro(channel, rx_buf, channel->rx_pkt_n_frags, eh); else efx_rx_deliver(channel, eh, rx_buf, channel->rx_pkt_n_frags); diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 0fc5baef45b1..10b6173d557d 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -188,7 +188,7 @@ static int efx_test_eventq_irq(struct efx_nic *efx, schedule_timeout_uninterruptible(wait); efx_for_each_channel(channel, efx) { - napi_disable(&channel->napi_str); + efx_stop_eventq(channel); if (channel->eventq_read_ptr != read_ptr[channel->channel]) { set_bit(channel->channel, &napi_ran); @@ -200,8 +200,7 @@ static int efx_test_eventq_irq(struct efx_nic *efx, if (efx_nic_event_test_irq_cpu(channel) >= 0) clear_bit(channel->channel, &int_pend); } - napi_enable(&channel->napi_str); - efx_nic_eventq_read_ack(channel); + efx_start_eventq(channel); } wait *= 2; -- cgit v1.2.3 From 63502b8d01631bd41778a64c9f6b72ea409bf97b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Tue, 22 Jul 2014 15:20:45 +0200 Subject: dp83640: Fix receive timestamp race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When timestamping received packets, rx_timestamp_work may be scheduled before the timestamps is received from the hardware resulting in the packet beeing delivered without the timestamp. This is fixed by changing the receive timestamp path: On receiving a packet that need timestamping, the rxts list is traversed. If a match is found, packet+timestamp are delivered, otherwise the packet is added to a rx_queue. When a timestamp arrives rx_queue is traversed and if a matching packet is found, it is delivered with the timestamp. Otherwise the timestamp is added to the rxts list for matching with packets arriving later. In case the hardware drops a timestamp, a workqueue regularly checks the queue for old packets and delivers them without a timestamp. Signed-off-by: Stefan Sørensen Signed-off-by: David S. Miller --- drivers/net/phy/dp83640.c | 173 +++++++++++++++++++++++++++------------------- 1 file changed, 102 insertions(+), 71 deletions(-) diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 255c21ff274c..c301e4cb37ca 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -74,7 +74,10 @@ #define ENDIAN_FLAG PSF_ENDIAN #endif -#define SKB_PTP_TYPE(__skb) (*(unsigned int *)((__skb)->cb)) +struct dp83640_skb_info { + int ptp_type; + unsigned long tmo; +}; struct phy_rxts { u16 ns_lo; /* ns[15:0] */ @@ -768,10 +771,51 @@ static int decode_evnt(struct dp83640_private *dp83640, return parsed * sizeof(u16); } +static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts) +{ + u16 *seqid; + unsigned int offset = 0; + u8 *msgtype, *data = skb_mac_header(skb); + + /* check sequenceID, messageType, 12 bit hash of offset 20-29 */ + + if (type & PTP_CLASS_VLAN) + offset += VLAN_HLEN; + + switch (type & PTP_CLASS_PMASK) { + case PTP_CLASS_IPV4: + offset += ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; + break; + case PTP_CLASS_IPV6: + offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; + break; + case PTP_CLASS_L2: + offset += ETH_HLEN; + break; + default: + return 0; + } + + if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid)) + return 0; + + if (unlikely(type & PTP_CLASS_V1)) + msgtype = data + offset + OFF_PTP_CONTROL; + else + msgtype = data + offset; + + seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID); + + return rxts->msgtype == (*msgtype & 0xf) && + rxts->seqid == ntohs(*seqid); +} + static void decode_rxts(struct dp83640_private *dp83640, struct phy_rxts *phy_rxts) { struct rxts *rxts; + struct skb_shared_hwtstamps *shhwtstamps = NULL; + struct sk_buff *skb; unsigned long flags; spin_lock_irqsave(&dp83640->rx_lock, flags); @@ -785,7 +829,26 @@ static void decode_rxts(struct dp83640_private *dp83640, rxts = list_first_entry(&dp83640->rxpool, struct rxts, list); list_del_init(&rxts->list); phy2rxts(phy_rxts, rxts); - list_add_tail(&rxts->list, &dp83640->rxts); + + spin_lock_irqsave(&dp83640->rx_queue.lock, flags); + skb_queue_walk(&dp83640->rx_queue, skb) { + struct dp83640_skb_info *skb_info; + + skb_info = (struct dp83640_skb_info *)skb->cb; + if (match(skb, skb_info->ptp_type, rxts)) { + __skb_unlink(skb, &dp83640->rx_queue); + shhwtstamps = skb_hwtstamps(skb); + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + shhwtstamps->hwtstamp = ns_to_ktime(rxts->ns); + netif_rx_ni(skb); + list_add(&rxts->list, &dp83640->rxpool); + break; + } + } + spin_unlock_irqrestore(&dp83640->rx_queue.lock, flags); + + if (!shhwtstamps) + list_add_tail(&rxts->list, &dp83640->rxts); out: spin_unlock_irqrestore(&dp83640->rx_lock, flags); } @@ -887,45 +950,6 @@ static int is_sync(struct sk_buff *skb, int type) return (*msgtype & 0xf) == 0; } -static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts) -{ - u16 *seqid; - unsigned int offset = 0; - u8 *msgtype, *data = skb_mac_header(skb); - - /* check sequenceID, messageType, 12 bit hash of offset 20-29 */ - - if (type & PTP_CLASS_VLAN) - offset += VLAN_HLEN; - - switch (type & PTP_CLASS_PMASK) { - case PTP_CLASS_IPV4: - offset += ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; - break; - case PTP_CLASS_IPV6: - offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; - break; - case PTP_CLASS_L2: - offset += ETH_HLEN; - break; - default: - return 0; - } - - if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid)) - return 0; - - if (unlikely(type & PTP_CLASS_V1)) - msgtype = data + offset + OFF_PTP_CONTROL; - else - msgtype = data + offset; - - seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID); - - return rxts->msgtype == (*msgtype & 0xf) && - rxts->seqid == ntohs(*seqid); -} - static void dp83640_free_clocks(void) { struct dp83640_clock *clock; @@ -1302,44 +1326,34 @@ static void rx_timestamp_work(struct work_struct *work) { struct dp83640_private *dp83640 = container_of(work, struct dp83640_private, ts_work); - struct list_head *this, *next; - struct rxts *rxts; - struct skb_shared_hwtstamps *shhwtstamps; struct sk_buff *skb; - unsigned int type; - unsigned long flags; - /* Deliver each deferred packet, with or without a time stamp. */ - - while ((skb = skb_dequeue(&dp83640->rx_queue)) != NULL) { - type = SKB_PTP_TYPE(skb); - spin_lock_irqsave(&dp83640->rx_lock, flags); - list_for_each_safe(this, next, &dp83640->rxts) { - rxts = list_entry(this, struct rxts, list); - if (match(skb, type, rxts)) { - shhwtstamps = skb_hwtstamps(skb); - memset(shhwtstamps, 0, sizeof(*shhwtstamps)); - shhwtstamps->hwtstamp = ns_to_ktime(rxts->ns); - list_del_init(&rxts->list); - list_add(&rxts->list, &dp83640->rxpool); - break; - } + /* Deliver expired packets. */ + while ((skb = skb_dequeue(&dp83640->rx_queue))) { + struct dp83640_skb_info *skb_info; + + skb_info = (struct dp83640_skb_info *)skb->cb; + if (!time_after(jiffies, skb_info->tmo)) { + skb_queue_head(&dp83640->rx_queue, skb); + break; } - spin_unlock_irqrestore(&dp83640->rx_lock, flags); + netif_rx_ni(skb); } - /* Clear out expired time stamps. */ - - spin_lock_irqsave(&dp83640->rx_lock, flags); - prune_rx_ts(dp83640); - spin_unlock_irqrestore(&dp83640->rx_lock, flags); + if (!skb_queue_empty(&dp83640->rx_queue)) + schedule_work(&dp83640->ts_work); } static bool dp83640_rxtstamp(struct phy_device *phydev, struct sk_buff *skb, int type) { struct dp83640_private *dp83640 = phydev->priv; + struct dp83640_skb_info *skb_info = (struct dp83640_skb_info *)skb->cb; + struct list_head *this, *next; + struct rxts *rxts; + struct skb_shared_hwtstamps *shhwtstamps = NULL; + unsigned long flags; if (is_status_frame(skb, type)) { decode_status_frame(dp83640, skb); @@ -1350,9 +1364,27 @@ static bool dp83640_rxtstamp(struct phy_device *phydev, if (!dp83640->hwts_rx_en) return false; - SKB_PTP_TYPE(skb) = type; - skb_queue_tail(&dp83640->rx_queue, skb); - schedule_work(&dp83640->ts_work); + spin_lock_irqsave(&dp83640->rx_lock, flags); + list_for_each_safe(this, next, &dp83640->rxts) { + rxts = list_entry(this, struct rxts, list); + if (match(skb, type, rxts)) { + shhwtstamps = skb_hwtstamps(skb); + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + shhwtstamps->hwtstamp = ns_to_ktime(rxts->ns); + netif_rx_ni(skb); + list_del_init(&rxts->list); + list_add(&rxts->list, &dp83640->rxpool); + break; + } + } + spin_unlock_irqrestore(&dp83640->rx_lock, flags); + + if (!shhwtstamps) { + skb_info->ptp_type = type; + skb_info->tmo = jiffies + 2; + skb_queue_tail(&dp83640->rx_queue, skb); + schedule_work(&dp83640->ts_work); + } return true; } @@ -1373,7 +1405,6 @@ static void dp83640_txtstamp(struct phy_device *phydev, case HWTSTAMP_TX_ON: skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; skb_queue_tail(&dp83640->tx_queue, skb); - schedule_work(&dp83640->ts_work); break; case HWTSTAMP_TX_OFF: -- cgit v1.2.3 From 52c4f0ec662bbf02f1b0bcb311a48af2c8e5ee89 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Tue, 22 Jul 2014 23:25:07 +0530 Subject: drivers: net: cpsw: add support to dump ALE table via ethtool register dump Add support to view addresses added by the driver and learnt by the hardware from ALE table via ethtool register dump interface. Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 24 +++++++++++++++++++++++- drivers/net/ethernet/ti/cpsw_ale.c | 12 ++++++++++-- drivers/net/ethernet/ti/cpsw_ale.h | 4 ++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index ae6379af5b4d..60f925df15e2 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1675,14 +1675,34 @@ static const struct net_device_ops cpsw_netdev_ops = { .ndo_vlan_rx_kill_vid = cpsw_ndo_vlan_rx_kill_vid, }; +static int cpsw_get_regs_len(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + + return priv->data.ale_entries * ALE_ENTRY_WORDS * sizeof(u32); +} + +static void cpsw_get_regs(struct net_device *ndev, + struct ethtool_regs *regs, void *p) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + u32 *reg = p; + + /* update CPSW IP version */ + regs->version = priv->version; + + cpsw_ale_dump(priv->ale, reg); +} + static void cpsw_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) { struct cpsw_priv *priv = netdev_priv(ndev); - strlcpy(info->driver, "TI CPSW Driver v1.0", sizeof(info->driver)); + strlcpy(info->driver, "cpsw", sizeof(info->driver)); strlcpy(info->version, "1.0", sizeof(info->version)); strlcpy(info->bus_info, priv->pdev->name, sizeof(info->bus_info)); + info->regdump_len = cpsw_get_regs_len(ndev); } static u32 cpsw_get_msglevel(struct net_device *ndev) @@ -1790,6 +1810,8 @@ static const struct ethtool_ops cpsw_ethtool_ops = { .get_ethtool_stats = cpsw_get_ethtool_stats, .get_wol = cpsw_get_wol, .set_wol = cpsw_set_wol, + .get_regs_len = cpsw_get_regs_len, + .get_regs = cpsw_get_regs, }; static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv, diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 7f893069c418..0579b2243bb6 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -25,8 +25,6 @@ #include "cpsw_ale.h" #define BITMASK(bits) (BIT(bits) - 1) -#define ALE_ENTRY_BITS 68 -#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) #define ALE_VERSION_MAJOR(rev) ((rev >> 8) & 0xff) #define ALE_VERSION_MINOR(rev) (rev & 0xff) @@ -763,3 +761,13 @@ int cpsw_ale_destroy(struct cpsw_ale *ale) kfree(ale); return 0; } + +void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) +{ + int i; + + for (i = 0; i < ale->params.ale_entries; i++) { + cpsw_ale_read(ale, i, data); + data += ALE_ENTRY_WORDS; + } +} diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h index de409c33b250..31cf43cab42e 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.h +++ b/drivers/net/ethernet/ti/cpsw_ale.h @@ -80,6 +80,9 @@ enum cpsw_ale_port_state { #define ALE_MCAST_FWD_LEARN 2 #define ALE_MCAST_FWD_2 3 +#define ALE_ENTRY_BITS 68 +#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) + struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params); int cpsw_ale_destroy(struct cpsw_ale *ale); @@ -104,5 +107,6 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port); int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control); int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control, int value); +void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data); #endif -- cgit v1.2.3 From c883ad555e074606a27362761da576e20c8ff6c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 22 Jul 2014 21:31:05 +0200 Subject: b43: N-PHY: fix rev7+ typos at random places MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 19 ++++++++++--------- drivers/net/wireless/b43/tables_nphy.c | 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 11d754360d71..44bb58b748dd 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -225,13 +225,13 @@ static void b43_nphy_rf_ctl_override_one_to_many(struct b43_wldev *dev, b43_nphy_rf_ctl_override_rev7(dev, 0x2, value, core, off, 1); b43_nphy_rf_ctl_override_rev7(dev, 0x1, value, core, off, 1); b43_nphy_rf_ctl_override_rev7(dev, 0x2, value, core, off, 2); - b43_nphy_rf_ctl_override_rev7(dev, 0x0800, value, core, off, 1); + b43_nphy_rf_ctl_override_rev7(dev, 0x0800, 0, core, off, 1); break; case N_RF_CTL_OVER_CMD_TX_PU: b43_nphy_rf_ctl_override_rev7(dev, 0x4, value, core, off, 0); b43_nphy_rf_ctl_override_rev7(dev, 0x2, value, core, off, 1); b43_nphy_rf_ctl_override_rev7(dev, 0x1, value, core, off, 2); - b43_nphy_rf_ctl_override_rev7(dev, 0x0800, value, core, off, 1); + b43_nphy_rf_ctl_override_rev7(dev, 0x0800, 1, core, off, 1); break; case N_RF_CTL_OVER_CMD_RX_GAIN: tmp = value & 0xFF; @@ -343,6 +343,7 @@ static void b43_nphy_rf_ctl_intc_override_rev7(struct b43_wldev *dev, switch (intc_override) { case N_INTC_OVERRIDE_OFF: b43_phy_write(dev, reg, 0); + b43_phy_mask(dev, 0x2ff, ~0x2000); b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); break; case N_INTC_OVERRIDE_TRSW: @@ -1596,7 +1597,7 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, bool lpf_bw3, lpf_bw4; lpf_bw3 = b43_phy_read(dev, B43_NPHY_REV7_RF_CTL_OVER3) & 0x80; - lpf_bw4 = b43_phy_read(dev, B43_NPHY_REV7_RF_CTL_OVER3) & 0x80; + lpf_bw4 = b43_phy_read(dev, B43_NPHY_REV7_RF_CTL_OVER4) & 0x80; if (lpf_bw3 || lpf_bw4) { /* TODO */ @@ -2117,7 +2118,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) N_RF_CTL_OVER_CMD_RX_PU, 1, 0, false); b43_nphy_rf_ctl_override_rev7(dev, 0x80, 1, 0, false, 0); - b43_nphy_rf_ctl_override_rev7(dev, 0x80, 1, 0, false, 0); + b43_nphy_rf_ctl_override_rev7(dev, 0x40, 1, 0, false, 0); if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { b43_nphy_rf_ctl_override_rev7(dev, 0x20, 0, 0, false, 0); @@ -3543,7 +3544,7 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev) nphy->bb_mult_save = 0; } - if (phy->rev >= 7) { + if (phy->rev >= 7 && nphy->lpf_bw_overrode_for_sample_play) { if (phy->rev >= 19) b43_nphy_rf_ctl_override_rev19(dev, 0x80, 0, 0, true, 1); @@ -3962,9 +3963,9 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev) b43_nphy_ipa_internal_tssi_setup(dev); if (phy->rev >= 19) - b43_nphy_rf_ctl_override_rev19(dev, 0x2000, 0, 3, false, 0); + b43_nphy_rf_ctl_override_rev19(dev, 0x1000, 0, 3, false, 0); else if (phy->rev >= 7) - b43_nphy_rf_ctl_override_rev7(dev, 0x2000, 0, 3, false, 0); + b43_nphy_rf_ctl_override_rev7(dev, 0x1000, 0, 3, false, 0); else if (phy->rev >= 3) b43_nphy_rf_ctl_override(dev, 0x2000, 0, 3, false); @@ -3977,9 +3978,9 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev) b43_nphy_rssi_select(dev, 0, N_RSSI_W1); if (phy->rev >= 19) - b43_nphy_rf_ctl_override_rev19(dev, 0x2000, 0, 3, true, 0); + b43_nphy_rf_ctl_override_rev19(dev, 0x1000, 0, 3, true, 0); else if (phy->rev >= 7) - b43_nphy_rf_ctl_override_rev7(dev, 0x2000, 0, 3, true, 0); + b43_nphy_rf_ctl_override_rev7(dev, 0x1000, 0, 3, true, 0); else if (phy->rev >= 3) b43_nphy_rf_ctl_override(dev, 0x2000, 0, 3, true); diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index ab27c2de2f43..4b5885077b01 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -3109,11 +3109,11 @@ static const struct nphy_rf_control_override_rev7 { 0x0010, 0x07A, 0x07D, 0x0010, 4 }, { 0x0020, 0x07A, 0x07D, 0x0020, 5 }, { 0x0040, 0x07A, 0x07D, 0x0040, 6 }, - { 0x0080, 0x0F8, 0x0FA, 0x0080, 7 }, + { 0x0080, 0x07A, 0x07D, 0x0080, 7 }, { 0x0400, 0x0F8, 0x0FA, 0x0070, 4 }, { 0x0800, 0x07B, 0x07E, 0xFFFF, 0 }, { 0x1000, 0x07C, 0x07F, 0xFFFF, 0 }, - { 0x6000, 0x348, 0x349, 0xFFFF, 0 }, + { 0x6000, 0x348, 0x349, 0x00FF, 0 }, { 0x2000, 0x348, 0x349, 0x000F, 0 }, }; -- cgit v1.2.3 From 5d26b50813ea6206a7bbab2e645e68044f101ac5 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Tue, 22 Jul 2014 14:43:51 -0700 Subject: mac80211_hwsim: fix compiler warning on MIPS The dividend in do_div() is expected to be an unsigned 64-bit integer, which leads to the following warning when building for 32-bit MIPS: drivers/net/wireless/mac80211_hwsim.c: In function 'mac80211_hwsim_set_tsf': drivers/net/wireless/mac80211_hwsim.c:664:98: warning: comparison of distinct pointer types lacks a cast [enabled by default] data->bcn_delta = do_div(delta, bcn_int); Since we care about the signedness of delta when adjusting tsf_offset and bcm_delta, use the absolute value for the division and compare the two timestamps to determine the sign. Signed-off-by: Andrew Bresticker Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index eba51460a5de..f39f504cc3a0 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -685,11 +685,16 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, struct mac80211_hwsim_data *data = hw->priv; u64 now = mac80211_hwsim_get_tsf(hw, vif); u32 bcn_int = data->beacon_int; - s64 delta = tsf - now; + u64 delta = abs64(tsf - now); - data->tsf_offset += delta; /* adjust after beaconing with new timestamp at old TBTT */ - data->bcn_delta = do_div(delta, bcn_int); + if (tsf > now) { + data->tsf_offset += delta; + data->bcn_delta = do_div(delta, bcn_int); + } else { + data->tsf_offset -= delta; + data->bcn_delta = -do_div(delta, bcn_int); + } } static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, -- cgit v1.2.3 From c0624881187cd06fbcbdc177c507ab589b1b6f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 23 Jul 2014 16:55:44 +0200 Subject: b43: report correct rate to mac80211 for 5 GHz packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far we were assuming only A-PHY supports 5 GHz. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/xmit.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 6e6ef3fc2247..426dc13c44cd 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -80,9 +80,10 @@ static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp) } /* Extract the bitrate index out of an OFDM PLCP header. */ -static int b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy) +static int b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool ghz5) { - int base = aphy ? 0 : 4; + /* For 2 GHz band first OFDM rate is at index 4, see main.c */ + int base = ghz5 ? 0 : 4; switch (plcp->raw[0] & 0xF) { case 0xB: @@ -767,7 +768,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) if (phystat0 & B43_RX_PHYST0_OFDM) rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp, - phytype == B43_PHYTYPE_A); + !!(chanstat & B43_RX_CHAN_5GHZ)); else rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); if (unlikely(rate_idx == -1)) { -- cgit v1.2.3 From e31cd3be75115afcd9372c420c6359be7652610f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 23 Jul 2014 18:54:48 +0200 Subject: b43: N-PHY: don't calculate values for TSSI if we can't transmit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This process requires sending some sample tone, so make sure we're allowed to transmit first. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 44bb58b748dd..d269fbb27b9e 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -3957,7 +3957,8 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev) u32 tmp; s32 rssi[4] = { }; - /* TODO: check if we can transmit */ + if (phy->chandef->chan->flags & IEEE80211_CHAN_NO_IR) + return; if (b43_nphy_ipa(dev)) b43_nphy_ipa_internal_tssi_setup(dev); -- cgit v1.2.3 From b453fda6bad14d1932ef35356c860f3bfd6d9d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 23 Jul 2014 18:54:49 +0200 Subject: b43: register limited amount of 5G channels for BCM43228 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't have all needed channel tables due to RE process for this device. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 47b6fa5fa5b2..3b4b192c0792 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -290,6 +290,14 @@ static struct ieee80211_channel b43_5ghz_nphy_chantable[] = { CHAN5G(182, 0), }; +static struct ieee80211_channel b43_5ghz_nphy_chantable_limited[] = { + CHAN5G(36, 0), CHAN5G(40, 0), + CHAN5G(44, 0), CHAN5G(48, 0), + CHAN5G(149, 0), CHAN5G(153, 0), + CHAN5G(157, 0), CHAN5G(161, 0), + CHAN5G(165, 0), +}; + static struct ieee80211_channel b43_5ghz_aphy_chantable[] = { CHAN5G(34, 0), CHAN5G(36, 0), CHAN5G(38, 0), CHAN5G(40, 0), @@ -322,6 +330,14 @@ static struct ieee80211_supported_band b43_band_5GHz_nphy = { .n_bitrates = b43_a_ratetable_size, }; +static struct ieee80211_supported_band b43_band_5GHz_nphy_limited = { + .band = IEEE80211_BAND_5GHZ, + .channels = b43_5ghz_nphy_chantable_limited, + .n_channels = ARRAY_SIZE(b43_5ghz_nphy_chantable_limited), + .bitrates = b43_a_ratetable, + .n_bitrates = b43_a_ratetable_size, +}; + static struct ieee80211_supported_band b43_band_5GHz_aphy = { .band = IEEE80211_BAND_5GHZ, .channels = b43_5ghz_aphy_chantable, @@ -5155,17 +5171,22 @@ static int b43_setup_bands(struct b43_wldev *dev, struct ieee80211_hw *hw = dev->wl->hw; struct b43_phy *phy = &dev->phy; bool limited_2g; + bool limited_5g; /* We don't support all 2 GHz channels on some devices */ limited_2g = phy->radio_ver == 0x2057 && (phy->radio_rev == 9 || phy->radio_rev == 14); + limited_5g = phy->radio_ver == 0x2057 && + phy->radio_rev == 9; if (have_2ghz_phy) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = limited_2g ? &b43_band_2ghz_limited : &b43_band_2GHz; if (dev->phy.type == B43_PHYTYPE_N) { if (have_5ghz_phy) - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_nphy; + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = limited_5g ? + &b43_band_5GHz_nphy_limited : + &b43_band_5GHz_nphy; } else { if (have_5ghz_phy) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_aphy; -- cgit v1.2.3 From bac9832076ee3b134bc859e07698c99276fc9459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 23 Jul 2014 18:54:50 +0200 Subject: b43: enable 5 GHz support for N-PHY devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This has been tested on 14e4:4328 (BCM4321), 14e4:432b (BCM4322), 14e4:4353 (BCM43224) and 14e4:4359 (BCM43228) which is an almost complete list of 5 GHz capable device (only BCM43222 is missing). Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 3b4b192c0792..d7055febe119 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -5338,7 +5338,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) switch (dev->phy.type) { case B43_PHYTYPE_A: case B43_PHYTYPE_G: - case B43_PHYTYPE_N: case B43_PHYTYPE_LP: case B43_PHYTYPE_HT: b43warn(wl, "5 GHz band is unsupported on this PHY\n"); -- cgit v1.2.3 From 109e3191935a77d123375f045e719b164fa471aa Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 23 Jul 2014 19:24:56 +0200 Subject: Bluetooth: Read list of local codecs supported by the controller If the Bluetooth controller supports Read Local Supported Codecs command, then issue it during initialization so that the list of codecs is known. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 2 ++ net/bluetooth/hci_core.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index f0a3d8890760..5d30919eaba9 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1074,6 +1074,8 @@ struct hci_rp_read_data_block_size { __le16 num_blocks; } __packed; +#define HCI_OP_READ_LOCAL_CODECS 0x100b + #define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b struct hci_rp_read_page_scan_activity { __u8 status; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cfcb6055ced8..f3e14103b76b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1686,6 +1686,10 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) if (hdev->commands[22] & 0x04) hci_set_event_mask_page_2(req); + /* Read local codec list if the HCI command is supported */ + if (hdev->commands[29] & 0x20) + hci_req_add(req, HCI_OP_READ_LOCAL_CODECS, 0, NULL); + /* Check for Synchronization Train support */ if (lmp_sync_train_capable(hdev)) hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); -- cgit v1.2.3 From f4fe73ed564b1c0c375481cb7a773b03767b0216 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 23 Jul 2014 19:24:57 +0200 Subject: Bluetooth: Get MWS transport configuration of the controller If the Bluetooth controller supports Get MWS Transport Layer Configuration command, then issue it during initialization. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 2 ++ net/bluetooth/hci_core.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 5d30919eaba9..e3fd926df13f 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1172,6 +1172,8 @@ struct hci_rp_write_remote_amp_assoc { __u8 phy_handle; } __packed; +#define HCI_OP_GET_MWS_TRANSPORT_CONFIG 0x140c + #define HCI_OP_ENABLE_DUT_MODE 0x1803 #define HCI_OP_WRITE_SSP_DEBUG_MODE 0x1804 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f3e14103b76b..078f1ecbc058 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1690,6 +1690,10 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) if (hdev->commands[29] & 0x20) hci_req_add(req, HCI_OP_READ_LOCAL_CODECS, 0, NULL); + /* Get MWS transport configuration if the HCI command is supported */ + if (hdev->commands[30] & 0x08) + hci_req_add(req, HCI_OP_GET_MWS_TRANSPORT_CONFIG, 0, NULL); + /* Check for Synchronization Train support */ if (lmp_sync_train_capable(hdev)) hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); -- cgit v1.2.3 From 274f482d33a309c87096f2983601ceda2761094e Mon Sep 17 00:00:00 2001 From: Sorin Dumitru Date: Tue, 22 Jul 2014 21:16:51 +0300 Subject: sock: remove skb argument from sk_rcvqueues_full It hasn't been used since commit 0fd7bac(net: relax rcvbuf limits). Signed-off-by: Sorin Dumitru Signed-off-by: David S. Miller --- include/net/sock.h | 5 ++--- net/core/sock.c | 2 +- net/ipv4/udp.c | 2 +- net/ipv6/udp.c | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 28f734601b50..720773304a85 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -810,8 +810,7 @@ static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb) * Do not take into account this skb truesize, * to allow even a single big packet to come. */ -static inline bool sk_rcvqueues_full(const struct sock *sk, const struct sk_buff *skb, - unsigned int limit) +static inline bool sk_rcvqueues_full(const struct sock *sk, unsigned int limit) { unsigned int qsize = sk->sk_backlog.len + atomic_read(&sk->sk_rmem_alloc); @@ -822,7 +821,7 @@ static inline bool sk_rcvqueues_full(const struct sock *sk, const struct sk_buff static inline __must_check int sk_add_backlog(struct sock *sk, struct sk_buff *skb, unsigned int limit) { - if (sk_rcvqueues_full(sk, skb, limit)) + if (sk_rcvqueues_full(sk, limit)) return -ENOBUFS; __sk_add_backlog(sk, skb); diff --git a/net/core/sock.c b/net/core/sock.c index 026e01f70274..ca9b65199d28 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -491,7 +491,7 @@ int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested) skb->dev = NULL; - if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf)) { + if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) { atomic_inc(&sk->sk_drops); goto discard_and_relse; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index f31053b90ee0..f57c0e4c2326 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1567,7 +1567,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) goto csum_error; - if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf)) { + if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) { UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, is_udplite); goto drop; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index f9d8800bb72f..5b6091de5868 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -673,7 +673,7 @@ int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) goto csum_error; } - if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf)) { + if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) { UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, is_udplite); goto drop; -- cgit v1.2.3 From cd4d5671385ba0c6355e013512ea6d06b1ebce02 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 23 Jul 2014 21:55:22 +0200 Subject: Bluetooth: Ignore ADV_DIRECT_IND attempts from unknown devices Unconditionally connecting to devices sending ADV_DIRECT_IND when the controller is in CONNECTABLE mode is a feature that is not fully working. The background scanning trigger for this has been removed, but the statement allowing it to happen in case some other part triggers is still present. So remove that code part as well to avoid unwanted connections. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 4c41774aa556..293dd98ae98f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4266,18 +4266,12 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, if (hdev->conn_hash.le_num_slave > 0) return; - /* If we're connectable, always connect any ADV_DIRECT_IND event */ - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && - adv_type == LE_ADV_DIRECT_IND) - goto connect; - /* If we're not connectable only connect devices that we have in * our pend_le_conns list. */ if (!hci_pend_le_action_lookup(&hdev->pend_le_conns, addr, addr_type)) return; -connect: conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER); if (!IS_ERR(conn)) -- cgit v1.2.3 From 4b9e7e7516135b1d5f047ad59188b5355bacc106 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 23 Jul 2014 21:55:23 +0200 Subject: Bluetooth: Fix issue with ADV_IND reports and auto-connection handling When adding remote devices to the kernel using the Add Device management command, these devices are explicitly allowed to connect. This kind of incoming connections are possible even when the controller itself is not connectable. For BR/EDR this distinction is pretty simple since there is only one type of incoming connections. With LE this is not that simple anymore since there are ADV_IND and ADV_DIRECT_IND advertising events. The ADV_DIRECT_IND advertising events are send for incoming (slave initiated) connections only. And this is the only thing the kernel should allow when adding devices using action 0x01. This meaning of incoming connections is coming from BR/EDR and needs to be mapped to LE the same way. Supporting the auto-connection of devices using ADV_IND advertising events is an important feature as well. However it does not map to incoming connections. So introduce a new action 0x02 that allows the kernel to connect to devices using ADV_DIRECT_IND and in addition ADV_IND advertising reports. This difference is represented by the new HCI_AUTO_CONN_DIRECT value for only connecting to ADV_DIRECT_IND. For connection to ADV_IND and ADV_DIRECT_IND the old value HCI_AUTO_CONN_ALWAYS is used. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 1 + net/bluetooth/hci_event.c | 27 ++++++++++++++++++++++++++- net/bluetooth/mgmt.c | 9 ++++++--- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 996ed065b6c2..747a0c3d9947 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -458,6 +458,7 @@ struct hci_conn_params { enum { HCI_AUTO_CONN_DISABLED, HCI_AUTO_CONN_REPORT, + HCI_AUTO_CONN_DIRECT, HCI_AUTO_CONN_ALWAYS, HCI_AUTO_CONN_LINK_LOSS, } auto_connect; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 078f1ecbc058..d8f91d5b0e56 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3647,6 +3647,7 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, list_add(¶ms->action, &hdev->pend_le_reports); hci_update_background_scan(hdev); break; + case HCI_AUTO_CONN_DIRECT: case HCI_AUTO_CONN_ALWAYS: if (!is_connected(hdev, addr, addr_type)) { list_add(¶ms->action, &hdev->pend_le_conns); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 293dd98ae98f..ba26fbfe481a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2259,6 +2259,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) break; /* Fall through */ + case HCI_AUTO_CONN_DIRECT: case HCI_AUTO_CONN_ALWAYS: list_del_init(¶ms->action); list_add(¶ms->action, &hdev->pend_le_conns); @@ -4251,6 +4252,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, u8 adv_type) { struct hci_conn *conn; + struct hci_conn_params *params; /* If the event is not connectable don't proceed further */ if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND) @@ -4269,8 +4271,31 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, /* If we're not connectable only connect devices that we have in * our pend_le_conns list. */ - if (!hci_pend_le_action_lookup(&hdev->pend_le_conns, addr, addr_type)) + params = hci_pend_le_action_lookup(&hdev->pend_le_conns, + addr, addr_type); + if (!params) + return; + + switch (params->auto_connect) { + case HCI_AUTO_CONN_DIRECT: + /* Only devices advertising with ADV_DIRECT_IND are + * triggering a connection attempt. This is allowing + * incoming connections from slave devices. + */ + if (adv_type != LE_ADV_DIRECT_IND) + return; + break; + case HCI_AUTO_CONN_ALWAYS: + /* Devices advertising with ADV_IND or ADV_DIRECT_IND + * are triggering a connection attempt. This means + * that incoming connectioms from slave device are + * accepted and also outgoing connections to slave + * devices are established when found. + */ + break; + default: return; + } conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 190668367e42..ccc4653ce658 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5271,7 +5271,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, MGMT_STATUS_INVALID_PARAMS, &cp->addr, sizeof(cp->addr)); - if (cp->action != 0x00 && cp->action != 0x01) + if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02) return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, MGMT_STATUS_INVALID_PARAMS, &cp->addr, sizeof(cp->addr)); @@ -5281,7 +5281,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, if (cp->addr.type == BDADDR_BREDR) { bool update_scan; - /* Only "connect" action supported for now */ + /* Only incoming connections action is supported for now */ if (cp->action != 0x01) { err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, MGMT_STATUS_INVALID_PARAMS, @@ -5307,8 +5307,10 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, else addr_type = ADDR_LE_DEV_RANDOM; - if (cp->action) + if (cp->action == 0x02) auto_conn = HCI_AUTO_CONN_ALWAYS; + else if (cp->action == 0x01) + auto_conn = HCI_AUTO_CONN_DIRECT; else auto_conn = HCI_AUTO_CONN_REPORT; @@ -5870,6 +5872,7 @@ static void restart_le_actions(struct hci_dev *hdev) list_del_init(&p->action); switch (p->auto_connect) { + case HCI_AUTO_CONN_DIRECT: case HCI_AUTO_CONN_ALWAYS: list_add(&p->action, &hdev->pend_le_conns); break; -- cgit v1.2.3 From 5490c27218b8b8ea7b9fd7320587f5e65c027a6f Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 23 Jul 2014 09:19:48 +0530 Subject: ethernet: realtek: use module_pci_driver This patch converts to use the macro module_pci_driver, which makes the code smaller and simpler. Previously in this driver we are having driver version info will be printed log buffer based on whether the driver selected as module or statically into image itself. By using the module_pci_driver that part of the code removed. For the first time of the device init, we are making the version info to be printed once. Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/8139cp.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 2bc728e65e24..be101ca8302e 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -1887,11 +1887,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) resource_size_t pciaddr; unsigned int addr_len, i, pci_using_dac; -#ifndef MODULE - static int version_printed; - if (version_printed++ == 0) - pr_info("%s", version); -#endif + pr_info_once("%s", version); if (pdev->vendor == PCI_VENDOR_ID_REALTEK && pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pdev->revision < 0x20) { @@ -2121,18 +2117,4 @@ static struct pci_driver cp_driver = { #endif }; -static int __init cp_init (void) -{ -#ifdef MODULE - pr_info("%s", version); -#endif - return pci_register_driver(&cp_driver); -} - -static void __exit cp_exit (void) -{ - pci_unregister_driver (&cp_driver); -} - -module_init(cp_init); -module_exit(cp_exit); +module_pci_driver(cp_driver); -- cgit v1.2.3 From 96b3bff4c94cebc97726dc7f019cfc7ba3ced2e1 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 23 Jul 2014 09:19:49 +0530 Subject: ethernet: realtek: use pci_device_id This patch use the struct pci_device_id instead of using macro DEFINE_PCI_DEVICE_TABLE which is deprecated and should not be used. And also moves these ids after probe and remove functionalities. Signed-off-by: Varka Bhadram Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/8139cp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index be101ca8302e..75b1693ec8bf 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -382,13 +382,6 @@ static int cp_get_eeprom(struct net_device *dev, static int cp_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data); -static DEFINE_PCI_DEVICE_TABLE(cp_pci_tbl) = { - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139), }, - { PCI_DEVICE(PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322), }, - { }, -}; -MODULE_DEVICE_TABLE(pci, cp_pci_tbl); - static struct { const char str[ETH_GSTRING_LEN]; } ethtool_stats_keys[] = { @@ -2106,6 +2099,13 @@ static int cp_resume (struct pci_dev *pdev) } #endif /* CONFIG_PM */ +static const struct pci_device_id cp_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139), }, + { PCI_DEVICE(PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322), }, + { }, +}; +MODULE_DEVICE_TABLE(pci, cp_pci_tbl); + static struct pci_driver cp_driver = { .name = DRV_NAME, .id_table = cp_pci_tbl, -- cgit v1.2.3 From 2ffa75988fff39741e60141ce4a349e2419b41e6 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 23 Jul 2014 16:33:54 +0800 Subject: virtio-net: introduce virtnet_receive() Move common receive logic to a new helper virtnet_receive(). It will also be used by rx busy polling method. Cc: Rusty Russell Cc: Michael S. Tsirkin Cc: Vlad Yasevich Cc: Eric Dumazet Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 7d9f84a91f37..b647d0d5c00e 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -725,15 +725,12 @@ static void refill_work(struct work_struct *work) } } -static int virtnet_poll(struct napi_struct *napi, int budget) +static int virtnet_receive(struct receive_queue *rq, int budget) { - struct receive_queue *rq = - container_of(napi, struct receive_queue, napi); struct virtnet_info *vi = rq->vq->vdev->priv; + unsigned int len, received = 0; void *buf; - unsigned int r, len, received = 0; -again: while (received < budget && (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) { receive_buf(rq, buf, len); @@ -745,6 +742,18 @@ again: schedule_delayed_work(&vi->refill, 0); } + return received; +} + +static int virtnet_poll(struct napi_struct *napi, int budget) +{ + struct receive_queue *rq = + container_of(napi, struct receive_queue, napi); + unsigned int r, received = 0; + +again: + received += virtnet_receive(rq, budget - received); + /* Out of packets? */ if (received < budget) { r = virtqueue_enable_cb_prepare(rq->vq); -- cgit v1.2.3 From 91815639d8804d1eee7ce2e1f7f60b36771db2c9 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 23 Jul 2014 16:33:55 +0800 Subject: virtio-net: rx busy polling support Add basic support for rx busy polling. Instead of introducing new states and spinlock to synchronize between NAPI and polling method, this patch just reuse NAPI state to avoid extra overhead for fast path and simplified the codes. Test was done between a kvm guest and an external host. Two hosts were connected through 40gb mlx4 cards. With both busy_poll and busy_read are set to 50 in guest, 1 byte netperf tcp_rr shows 127% improvement: transaction rate was increased from 8353.33 to 18966.87. Cc: Rusty Russell Cc: Michael S. Tsirkin Cc: Vlad Yasevich Cc: Eric Dumazet Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b647d0d5c00e..59caa06f34a6 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -27,6 +27,7 @@ #include #include #include +#include static int napi_weight = NAPI_POLL_WEIGHT; module_param(napi_weight, int, 0444); @@ -521,6 +522,8 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len) skb_shinfo(skb)->gso_segs = 0; } + skb_mark_napi_id(skb, &rq->napi); + netif_receive_skb(skb); return; @@ -769,6 +772,43 @@ again: return received; } +#ifdef CONFIG_NET_RX_BUSY_POLL +/* must be called with local_bh_disable()d */ +static int virtnet_busy_poll(struct napi_struct *napi) +{ + struct receive_queue *rq = + container_of(napi, struct receive_queue, napi); + struct virtnet_info *vi = rq->vq->vdev->priv; + int r, received = 0, budget = 4; + + if (!(vi->status & VIRTIO_NET_S_LINK_UP)) + return LL_FLUSH_FAILED; + + if (!napi_schedule_prep(napi)) + return LL_FLUSH_BUSY; + + virtqueue_disable_cb(rq->vq); + +again: + received += virtnet_receive(rq, budget); + + r = virtqueue_enable_cb_prepare(rq->vq); + clear_bit(NAPI_STATE_SCHED, &napi->state); + if (unlikely(virtqueue_poll(rq->vq, r)) && + napi_schedule_prep(napi)) { + virtqueue_disable_cb(rq->vq); + if (received < budget) { + budget -= received; + goto again; + } else { + __napi_schedule(napi); + } + } + + return received; +} +#endif /* CONFIG_NET_RX_BUSY_POLL */ + static int virtnet_open(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); @@ -1356,6 +1396,9 @@ static const struct net_device_ops virtnet_netdev = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = virtnet_netpoll, #endif +#ifdef CONFIG_NET_RX_BUSY_POLL + .ndo_busy_poll = virtnet_busy_poll, +#endif }; static void virtnet_config_changed_work(struct work_struct *work) @@ -1561,6 +1604,7 @@ static int virtnet_alloc_queues(struct virtnet_info *vi) vi->rq[i].pages = NULL; netif_napi_add(vi->dev, &vi->rq[i].napi, virtnet_poll, napi_weight); + napi_hash_add(&vi->rq[i].napi); sg_init_table(vi->rq[i].sg, ARRAY_SIZE(vi->rq[i].sg)); ewma_init(&vi->rq[i].mrg_avg_pkt_len, 1, RECEIVE_AVG_WEIGHT); @@ -1862,11 +1906,13 @@ static int virtnet_freeze(struct virtio_device *vdev) netif_device_detach(vi->dev); cancel_delayed_work_sync(&vi->refill); - if (netif_running(vi->dev)) + if (netif_running(vi->dev)) { for (i = 0; i < vi->max_queue_pairs; i++) { napi_disable(&vi->rq[i].napi); + napi_hash_del(&vi->rq[i].napi); netif_napi_del(&vi->rq[i].napi); } + } remove_vq_common(vi); -- cgit v1.2.3 From f5220d63991f3fcb3d19efe8af0c8f75dcf0309b Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Wed, 23 Jul 2014 09:58:01 +0100 Subject: ipv4: Make IP_MULTICAST_ALL and IP_MSFILTER work on raw sockets Currently, although IP_MULTICAST_ALL and IP_MSFILTER ioctl calls succeed on raw sockets, there is no code to implement the functionality on received packets; it is only implemented for UDP sockets. The raw(7) man page states: "In addition, all ip(7) IPPROTO_IP socket options valid for datagram sockets are supported", which implies these ioctls should work on raw sockets. To fix this, add a call to ip_mc_sf_allow on raw sockets. This should not break any existing code, since the current position of not calling ip_mc_sf_filter makes it behave as if neither the IP_MULTICAST_ALL nor the IP_MSFILTER ioctl had been called. Adding the call to ip_mc_sf_allow will therefore maintain the current behaviour so long as IP_MULTICAST_ALL and IP_MSFILTER ioctls are not called. Any code that currently is calling IP_MULTICAST_ALL or IP_MSFILTER ioctls on raw sockets presumably is wanting the filter to be applied, although no filtering will currently be occurring. Signed-off-by: Quentin Armitage Signed-off-by: David S. Miller --- net/ipv4/raw.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 2054d7136c62..739db3100c23 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -174,7 +175,9 @@ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) while (sk) { delivered = 1; - if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) { + if ((iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) && + ip_mc_sf_allow(sk, iph->daddr, iph->saddr, + skb->dev->ifindex)) { struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); /* Not releasing hash table! */ -- cgit v1.2.3 From 5e811b39a451bbada7ffc8e0dd232252867069bb Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 23 Jul 2014 10:42:11 -0700 Subject: net: bcmgenet: remove FSF mail address Use a smaller GPLv2 header and remove all the boilerplate code as well as the FSF mail address. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 --------- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 14 ++------------ drivers/net/ethernet/broadcom/genet/bcmmii.c | 9 --------- 3 files changed, 2 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 0173a6d355aa..0c7af0b2f164 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -6,15 +6,6 @@ * 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. - * - * 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. */ #define pr_fmt(fmt) "bcmgenet: " fmt diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index c61cd98b662e..2ef8673943de 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -4,18 +4,8 @@ * 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. - * - * 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 __BCMGENET_H__ #define __BCMGENET_H__ diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index b1338c9e8abb..fb801d53c443 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -6,15 +6,6 @@ * 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. - * - * 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. */ -- cgit v1.2.3 From c91b7f668a79b796153921c8e405b3d1633e71d3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 23 Jul 2014 10:42:12 -0700 Subject: net: bcmgenet: re-align multiple lines correctly checkpatch.pl flagged a lot of "CHECK: Alignment should match open parenthesis" checks, fix all of them to make the driver neater. While at it fix some obvious typos and re-arrange some of the lines to avoid going over 80 columns. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 257 ++++++++++++------------- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 4 +- drivers/net/ethernet/broadcom/genet/bcmmii.c | 28 +-- 3 files changed, 142 insertions(+), 147 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 0c7af0b2f164..0f65b4a4d4a4 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -70,13 +70,13 @@ TOTAL_DESC * DMA_DESC_SIZE) static inline void dmadesc_set_length_status(struct bcmgenet_priv *priv, - void __iomem *d, u32 value) + void __iomem *d, u32 value) { __raw_writel(value, d + DMA_DESC_LENGTH_STATUS); } static inline u32 dmadesc_get_length_status(struct bcmgenet_priv *priv, - void __iomem *d) + void __iomem *d) { return __raw_readl(d + DMA_DESC_LENGTH_STATUS); } @@ -99,7 +99,7 @@ static inline void dmadesc_set_addr(struct bcmgenet_priv *priv, /* Combined address + length/status setter */ static inline void dmadesc_set(struct bcmgenet_priv *priv, - void __iomem *d, dma_addr_t addr, u32 val) + void __iomem *d, dma_addr_t addr, u32 val) { dmadesc_set_length_status(priv, d, val); dmadesc_set_addr(priv, d, addr); @@ -233,7 +233,7 @@ static inline struct bcmgenet_priv *dev_to_priv(struct device *dev) } static inline u32 bcmgenet_tdma_readl(struct bcmgenet_priv *priv, - enum dma_reg r) + enum dma_reg r) { return __raw_readl(priv->base + GENET_TDMA_REG_OFF + DMA_RINGS_SIZE + bcmgenet_dma_regs[r]); @@ -247,7 +247,7 @@ static inline void bcmgenet_tdma_writel(struct bcmgenet_priv *priv, } static inline u32 bcmgenet_rdma_readl(struct bcmgenet_priv *priv, - enum dma_reg r) + enum dma_reg r) { return __raw_readl(priv->base + GENET_RDMA_REG_OFF + DMA_RINGS_SIZE + bcmgenet_dma_regs[r]); @@ -324,8 +324,8 @@ static const u8 genet_dma_ring_regs_v123[] = { static const u8 *genet_dma_ring_regs; static inline u32 bcmgenet_tdma_ring_readl(struct bcmgenet_priv *priv, - unsigned int ring, - enum dma_ring_reg r) + unsigned int ring, + enum dma_ring_reg r) { return __raw_readl(priv->base + GENET_TDMA_REG_OFF + (DMA_RING_SIZE * ring) + @@ -333,9 +333,8 @@ static inline u32 bcmgenet_tdma_ring_readl(struct bcmgenet_priv *priv, } static inline void bcmgenet_tdma_ring_writel(struct bcmgenet_priv *priv, - unsigned int ring, - u32 val, - enum dma_ring_reg r) + unsigned int ring, u32 val, + enum dma_ring_reg r) { __raw_writel(val, priv->base + GENET_TDMA_REG_OFF + (DMA_RING_SIZE * ring) + @@ -343,8 +342,8 @@ static inline void bcmgenet_tdma_ring_writel(struct bcmgenet_priv *priv, } static inline u32 bcmgenet_rdma_ring_readl(struct bcmgenet_priv *priv, - unsigned int ring, - enum dma_ring_reg r) + unsigned int ring, + enum dma_ring_reg r) { return __raw_readl(priv->base + GENET_RDMA_REG_OFF + (DMA_RING_SIZE * ring) + @@ -352,9 +351,8 @@ static inline u32 bcmgenet_rdma_ring_readl(struct bcmgenet_priv *priv, } static inline void bcmgenet_rdma_ring_writel(struct bcmgenet_priv *priv, - unsigned int ring, - u32 val, - enum dma_ring_reg r) + unsigned int ring, u32 val, + enum dma_ring_reg r) { __raw_writel(val, priv->base + GENET_RDMA_REG_OFF + (DMA_RING_SIZE * ring) + @@ -362,7 +360,7 @@ static inline void bcmgenet_rdma_ring_writel(struct bcmgenet_priv *priv, } static int bcmgenet_get_settings(struct net_device *dev, - struct ethtool_cmd *cmd) + struct ethtool_cmd *cmd) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -376,7 +374,7 @@ static int bcmgenet_get_settings(struct net_device *dev, } static int bcmgenet_set_settings(struct net_device *dev, - struct ethtool_cmd *cmd) + struct ethtool_cmd *cmd) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -449,7 +447,7 @@ static int bcmgenet_set_tx_csum(struct net_device *dev, } static int bcmgenet_set_features(struct net_device *dev, - netdev_features_t features) + netdev_features_t features) { netdev_features_t changed = features ^ dev->features; netdev_features_t wanted = dev->wanted_features; @@ -616,7 +614,7 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { #define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats) static void bcmgenet_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) + struct ethtool_drvinfo *info) { strlcpy(info->driver, "bcmgenet", sizeof(info->driver)); strlcpy(info->version, "v2.0", sizeof(info->version)); @@ -634,8 +632,8 @@ static int bcmgenet_get_sset_count(struct net_device *dev, int string_set) } } -static void bcmgenet_get_strings(struct net_device *dev, - u32 stringset, u8 *data) +static void bcmgenet_get_strings(struct net_device *dev, u32 stringset, + u8 *data) { int i; @@ -643,8 +641,8 @@ static void bcmgenet_get_strings(struct net_device *dev, case ETH_SS_STATS: for (i = 0; i < BCMGENET_STATS_LEN; i++) { memcpy(data + i * ETH_GSTRING_LEN, - bcmgenet_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); + bcmgenet_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); } break; } @@ -669,8 +667,8 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv) case BCMGENET_STAT_RUNT: if (s->type != BCMGENET_STAT_MIB_RX) offset = BCMGENET_STAT_OFFSET; - val = bcmgenet_umac_readl(priv, UMAC_MIB_START + - j + offset); + val = bcmgenet_umac_readl(priv, + UMAC_MIB_START + j + offset); break; case BCMGENET_STAT_MISC: val = bcmgenet_umac_readl(priv, s->reg_offset); @@ -687,8 +685,8 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv) } static void bcmgenet_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, - u64 *data) + struct ethtool_stats *stats, + u64 *data) { struct bcmgenet_priv *priv = netdev_priv(dev); int i; @@ -756,7 +754,7 @@ static void bcmgenet_power_down(struct bcmgenet_priv *priv, } static void bcmgenet_power_up(struct bcmgenet_priv *priv, - enum bcmgenet_power_mode mode) + enum bcmgenet_power_mode mode) { u32 reg; @@ -841,37 +839,37 @@ static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_priv *priv, struct bcmgenet_tx_ring *ring) { bcmgenet_intrl2_0_writel(priv, - UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE, - INTRL2_CPU_MASK_SET); + UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE, + INTRL2_CPU_MASK_SET); } static inline void bcmgenet_tx_ring16_int_enable(struct bcmgenet_priv *priv, struct bcmgenet_tx_ring *ring) { bcmgenet_intrl2_0_writel(priv, - UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE, - INTRL2_CPU_MASK_CLEAR); + UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE, + INTRL2_CPU_MASK_CLEAR); } static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_priv *priv, - struct bcmgenet_tx_ring *ring) + struct bcmgenet_tx_ring *ring) { - bcmgenet_intrl2_1_writel(priv, - (1 << ring->index), INTRL2_CPU_MASK_CLEAR); + bcmgenet_intrl2_1_writel(priv, (1 << ring->index), + INTRL2_CPU_MASK_CLEAR); priv->int1_mask &= ~(1 << ring->index); } static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_priv *priv, struct bcmgenet_tx_ring *ring) { - bcmgenet_intrl2_1_writel(priv, - (1 << ring->index), INTRL2_CPU_MASK_SET); + bcmgenet_intrl2_1_writel(priv, (1 << ring->index), + INTRL2_CPU_MASK_SET); priv->int1_mask |= (1 << ring->index); } /* Unlocked version of the reclaim routine */ static void __bcmgenet_tx_reclaim(struct net_device *dev, - struct bcmgenet_tx_ring *ring) + struct bcmgenet_tx_ring *ring) { struct bcmgenet_priv *priv = netdev_priv(dev); int last_tx_cn, last_c_index, num_tx_bds; @@ -894,9 +892,9 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev, last_tx_cn = num_tx_bds - last_c_index + c_index; netif_dbg(priv, tx_done, dev, - "%s ring=%d index=%d last_tx_cn=%d last_index=%d\n", - __func__, ring->index, - c_index, last_tx_cn, last_c_index); + "%s ring=%d index=%d last_tx_cn=%d last_index=%d\n", + __func__, ring->index, + c_index, last_tx_cn, last_c_index); /* Reclaim transmitted buffers */ while (last_tx_cn-- > 0) { @@ -904,17 +902,17 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev, if (tx_cb_ptr->skb) { dev->stats.tx_bytes += tx_cb_ptr->skb->len; dma_unmap_single(&dev->dev, - dma_unmap_addr(tx_cb_ptr, dma_addr), - tx_cb_ptr->skb->len, - DMA_TO_DEVICE); + dma_unmap_addr(tx_cb_ptr, dma_addr), + tx_cb_ptr->skb->len, + DMA_TO_DEVICE); bcmgenet_free_cb(tx_cb_ptr); } else if (dma_unmap_addr(tx_cb_ptr, dma_addr)) { dev->stats.tx_bytes += dma_unmap_len(tx_cb_ptr, dma_len); dma_unmap_page(&dev->dev, - dma_unmap_addr(tx_cb_ptr, dma_addr), - dma_unmap_len(tx_cb_ptr, dma_len), - DMA_TO_DEVICE); + dma_unmap_addr(tx_cb_ptr, dma_addr), + dma_unmap_len(tx_cb_ptr, dma_len), + DMA_TO_DEVICE); dma_unmap_addr_set(tx_cb_ptr, dma_addr, 0); } dev->stats.tx_packets++; @@ -934,7 +932,7 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev, } static void bcmgenet_tx_reclaim(struct net_device *dev, - struct bcmgenet_tx_ring *ring) + struct bcmgenet_tx_ring *ring) { unsigned long flags; @@ -1010,9 +1008,9 @@ static int bcmgenet_xmit_single(struct net_device *dev, /* Transmit a SKB fragement */ static int bcmgenet_xmit_frag(struct net_device *dev, - skb_frag_t *frag, - u16 dma_desc_flags, - struct bcmgenet_tx_ring *ring) + skb_frag_t *frag, + u16 dma_desc_flags, + struct bcmgenet_tx_ring *ring) { struct bcmgenet_priv *priv = netdev_priv(dev); struct device *kdev = &priv->pdev->dev; @@ -1027,11 +1025,11 @@ static int bcmgenet_xmit_frag(struct net_device *dev, tx_cb_ptr->skb = NULL; mapping = skb_frag_dma_map(kdev, frag, 0, - skb_frag_size(frag), DMA_TO_DEVICE); + skb_frag_size(frag), DMA_TO_DEVICE); ret = dma_mapping_error(kdev, mapping); if (ret) { netif_err(priv, tx_err, dev, "%s: Tx DMA map failed\n", - __func__); + __func__); return ret; } @@ -1039,8 +1037,8 @@ static int bcmgenet_xmit_frag(struct net_device *dev, dma_unmap_len_set(tx_cb_ptr, dma_len, frag->size); dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping, - (frag->size << DMA_BUFLENGTH_SHIFT) | dma_desc_flags | - (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT)); + (frag->size << DMA_BUFLENGTH_SHIFT) | dma_desc_flags | + (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT)); ring->free_bds -= 1; @@ -1144,7 +1142,7 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) if (ring->free_bds <= nr_frags + 1) { netif_tx_stop_queue(txq); netdev_err(dev, "%s: tx ring %d full when queue %d awake\n", - __func__, index, ring->queue); + __func__, index, ring->queue); ret = NETDEV_TX_BUSY; goto out; } @@ -1172,8 +1170,9 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) /* xmit fragment */ for (i = 0; i < nr_frags; i++) { ret = bcmgenet_xmit_frag(dev, - &skb_shinfo(skb)->frags[i], - (i == nr_frags - 1) ? DMA_EOP : 0, ring); + &skb_shinfo(skb)->frags[i], + (i == nr_frags - 1) ? DMA_EOP : 0, + ring); if (ret) { ret = NETDEV_TX_OK; goto out; @@ -1186,7 +1185,7 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) * producer index, now write it down to the hardware */ bcmgenet_tdma_ring_writel(priv, ring->index, - ring->prod_index, TDMA_PROD_INDEX); + ring->prod_index, TDMA_PROD_INDEX); if (ring->free_bds <= (MAX_SKB_FRAGS + 1)) { netif_tx_stop_queue(txq); @@ -1200,16 +1199,14 @@ out: } -static int bcmgenet_rx_refill(struct bcmgenet_priv *priv, - struct enet_cb *cb) +static int bcmgenet_rx_refill(struct bcmgenet_priv *priv, struct enet_cb *cb) { struct device *kdev = &priv->pdev->dev; struct sk_buff *skb; dma_addr_t mapping; int ret; - skb = netdev_alloc_skb(priv->dev, - priv->rx_buf_len + SKB_ALIGNMENT); + skb = netdev_alloc_skb(priv->dev, priv->rx_buf_len + SKB_ALIGNMENT); if (!skb) return -ENOMEM; @@ -1217,12 +1214,12 @@ static int bcmgenet_rx_refill(struct bcmgenet_priv *priv, WARN_ON(cb->skb != NULL); cb->skb = skb; mapping = dma_map_single(kdev, skb->data, - priv->rx_buf_len, DMA_FROM_DEVICE); + priv->rx_buf_len, DMA_FROM_DEVICE); ret = dma_mapping_error(kdev, mapping); if (ret) { bcmgenet_free_cb(cb); netif_err(priv, rx_err, priv->dev, - "%s DMA map failed\n", __func__); + "%s DMA map failed\n", __func__); return ret; } @@ -1257,8 +1254,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, unsigned int p_index; unsigned int chksum_ok = 0; - p_index = bcmgenet_rdma_ring_readl(priv, - DESC_INDEX, RDMA_PROD_INDEX); + p_index = bcmgenet_rdma_ring_readl(priv, DESC_INDEX, RDMA_PROD_INDEX); p_index &= DMA_P_INDEX_MASK; if (p_index < priv->rx_c_index) @@ -1268,10 +1264,10 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, rxpkttoprocess = p_index - priv->rx_c_index; netif_dbg(priv, rx_status, dev, - "RDMA: rxpkttoprocess=%d\n", rxpkttoprocess); + "RDMA: rxpkttoprocess=%d\n", rxpkttoprocess); while ((rxpktprocessed < rxpkttoprocess) && - (rxpktprocessed < budget)) { + (rxpktprocessed < budget)) { /* Unmap the packet contents such that we can use the * RSV from the 64 bytes descriptor when enabled and save @@ -1280,13 +1276,14 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, cb = &priv->rx_cbs[priv->rx_read_ptr]; skb = cb->skb; dma_unmap_single(&dev->dev, dma_unmap_addr(cb, dma_addr), - priv->rx_buf_len, DMA_FROM_DEVICE); + priv->rx_buf_len, DMA_FROM_DEVICE); if (!priv->desc_64b_en) { - dma_length_status = dmadesc_get_length_status(priv, - priv->rx_bds + - (priv->rx_read_ptr * - DMA_DESC_SIZE)); + dma_length_status = + dmadesc_get_length_status(priv, + priv->rx_bds + + (priv->rx_read_ptr * + DMA_DESC_SIZE)); } else { struct status_64 *status; status = (struct status_64 *)skb->data; @@ -1300,9 +1297,9 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, len = dma_length_status >> DMA_BUFLENGTH_SHIFT; netif_dbg(priv, rx_status, dev, - "%s: p_ind=%d c_ind=%d read_ptr=%d len_stat=0x%08x\n", - __func__, p_index, priv->rx_c_index, priv->rx_read_ptr, - dma_length_status); + "%s:p_ind=%d c_ind=%d read_ptr=%d len_stat=0x%08x\n", + __func__, p_index, priv->rx_c_index, + priv->rx_read_ptr, dma_length_status); rxpktprocessed++; @@ -1318,7 +1315,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) { netif_err(priv, rx_status, dev, - "Droping fragmented packet!\n"); + "dropping fragmented packet!\n"); dev->stats.rx_dropped++; dev->stats.rx_errors++; dev_kfree_skb_any(cb->skb); @@ -1332,7 +1329,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, DMA_RX_LG | DMA_RX_RXER))) { netif_err(priv, rx_status, dev, "dma_flag=0x%x\n", - (unsigned int)dma_flag); + (unsigned int)dma_flag); if (dma_flag & DMA_RX_CRC_ERROR) dev->stats.rx_crc_errors++; if (dma_flag & DMA_RX_OV) @@ -1351,7 +1348,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, } /* error packet */ chksum_ok = (dma_flag & priv->dma_rx_chk_bit) && - priv->desc_rxchk_en; + priv->desc_rxchk_en; skb_put(skb, len); if (priv->desc_64b_en) { @@ -1427,8 +1424,8 @@ static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv) if (dma_unmap_addr(cb, dma_addr)) { dma_unmap_single(&priv->dev->dev, - dma_unmap_addr(cb, dma_addr), - priv->rx_buf_len, DMA_FROM_DEVICE); + dma_unmap_addr(cb, dma_addr), + priv->rx_buf_len, DMA_FROM_DEVICE); dma_unmap_addr_set(cb, dma_addr, 0); } @@ -1437,8 +1434,7 @@ static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv) } } -static void umac_enable_set(struct bcmgenet_priv *priv, u32 mask, - bool enable) +static void umac_enable_set(struct bcmgenet_priv *priv, u32 mask, bool enable) { u32 reg; @@ -1514,7 +1510,8 @@ static int init_umac(struct bcmgenet_priv *priv) bcmgenet_umac_writel(priv, 0, UMAC_CMD); /* clear tx/rx counter */ bcmgenet_umac_writel(priv, - MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT, UMAC_MIB_CTRL); + MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT, + UMAC_MIB_CTRL); bcmgenet_umac_writel(priv, 0, UMAC_MIB_CTRL); bcmgenet_umac_writel(priv, ENET_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN); @@ -1554,8 +1551,7 @@ static int init_umac(struct bcmgenet_priv *priv) if (priv->hw_params->flags & GENET_HAS_MDIO_INTR) cpu_mask_clear |= UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR; - bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, - INTRL2_CPU_MASK_CLEAR); + bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, INTRL2_CPU_MASK_CLEAR); /* Enable rx/tx engine.*/ dev_dbg(kdev, "done init umac\n"); @@ -1604,28 +1600,28 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH); /* Disable rate control for now */ bcmgenet_tdma_ring_writel(priv, index, flow_period_val, - TDMA_FLOW_PERIOD); + TDMA_FLOW_PERIOD); /* Unclassified traffic goes to ring 16 */ bcmgenet_tdma_ring_writel(priv, index, - ((size << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH), - DMA_RING_BUF_SIZE); + ((size << DMA_RING_SIZE_SHIFT) | + RX_BUF_LENGTH), DMA_RING_BUF_SIZE); first_bd = write_ptr; /* Set start and end address, read and write pointers */ bcmgenet_tdma_ring_writel(priv, index, first_bd * words_per_bd, - DMA_START_ADDR); + DMA_START_ADDR); bcmgenet_tdma_ring_writel(priv, index, first_bd * words_per_bd, - TDMA_READ_PTR); + TDMA_READ_PTR); bcmgenet_tdma_ring_writel(priv, index, first_bd, - TDMA_WRITE_PTR); + TDMA_WRITE_PTR); bcmgenet_tdma_ring_writel(priv, index, end_ptr * words_per_bd - 1, - DMA_END_ADDR); + DMA_END_ADDR); } /* Initialize a RDMA ring */ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, - unsigned int index, unsigned int size) + unsigned int index, unsigned int size) { u32 words_per_bd = WORDS_PER_BD(priv); int ret; @@ -1651,14 +1647,15 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_PROD_INDEX); bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_CONS_INDEX); bcmgenet_rdma_ring_writel(priv, index, - ((size << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH), - DMA_RING_BUF_SIZE); + ((size << DMA_RING_SIZE_SHIFT) | + RX_BUF_LENGTH), DMA_RING_BUF_SIZE); bcmgenet_rdma_ring_writel(priv, index, 0, DMA_START_ADDR); bcmgenet_rdma_ring_writel(priv, index, - words_per_bd * size - 1, DMA_END_ADDR); + words_per_bd * size - 1, DMA_END_ADDR); bcmgenet_rdma_ring_writel(priv, index, - (DMA_FC_THRESH_LO << DMA_XOFF_THRESHOLD_SHIFT) | - DMA_FC_THRESH_HI, RDMA_XON_XOFF_THRESH); + (DMA_FC_THRESH_LO << + DMA_XOFF_THRESHOLD_SHIFT) | + DMA_FC_THRESH_HI, RDMA_XON_XOFF_THRESH); bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_READ_PTR); return ret; @@ -1705,8 +1702,8 @@ static void bcmgenet_init_multiq(struct net_device *dev) * (ring 16) */ bcmgenet_init_tx_ring(priv, i, priv->hw_params->bds_cnt, - i * priv->hw_params->bds_cnt, - (i + 1) * priv->hw_params->bds_cnt); + i * priv->hw_params->bds_cnt, + (i + 1) * priv->hw_params->bds_cnt); /* Configure ring as decriptor ring and setup priority */ ring_cfg |= 1 << i; @@ -1778,7 +1775,7 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv) priv->tx_bds = priv->base + priv->hw_params->tdma_offset; priv->num_tx_bds = TOTAL_DESC; priv->tx_cbs = kzalloc(priv->num_tx_bds * sizeof(struct enet_cb), - GFP_KERNEL); + GFP_KERNEL); if (!priv->tx_cbs) { bcmgenet_fini_dma(priv); return -ENOMEM; @@ -1789,8 +1786,9 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv) /* initialize special ring 16 */ bcmgenet_init_tx_ring(priv, DESC_INDEX, GENET_DEFAULT_BD_CNT, - priv->hw_params->tx_queues * priv->hw_params->bds_cnt, - TOTAL_DESC); + priv->hw_params->tx_queues * + priv->hw_params->bds_cnt, + TOTAL_DESC); return 0; } @@ -1811,11 +1809,11 @@ static int bcmgenet_poll(struct napi_struct *napi, int budget) priv->rx_c_index += work_done; priv->rx_c_index &= DMA_C_INDEX_MASK; bcmgenet_rdma_ring_writel(priv, DESC_INDEX, - priv->rx_c_index, RDMA_CONS_INDEX); + priv->rx_c_index, RDMA_CONS_INDEX); if (work_done < budget) { napi_complete(napi); - bcmgenet_intrl2_0_writel(priv, - UMAC_IRQ_RXDMA_BDONE, INTRL2_CPU_MASK_CLEAR); + bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE, + INTRL2_CPU_MASK_CLEAR); } return work_done; @@ -1838,9 +1836,9 @@ static void bcmgenet_irq_task(struct work_struct *work) /* Link UP/DOWN event */ if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && - (priv->irq0_stat & (UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN))) { + (priv->irq0_stat & (UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN))) { phy_mac_interrupt(priv->phydev, - priv->irq0_stat & UMAC_IRQ_LINK_UP); + priv->irq0_stat & UMAC_IRQ_LINK_UP); priv->irq0_stat &= ~(UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN); } } @@ -1859,7 +1857,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR); netif_dbg(priv, intr, priv->dev, - "%s: IRQ=0x%x\n", __func__, priv->irq1_stat); + "%s: IRQ=0x%x\n", __func__, priv->irq1_stat); /* Check the MBDONE interrupts. * packet is done, reclaim descriptors */ @@ -1868,7 +1866,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) for (index = 0; index < 16; index++) { if (priv->irq1_stat & (1 << index)) bcmgenet_tx_reclaim(priv->dev, - &priv->tx_rings[index]); + &priv->tx_rings[index]); } } return IRQ_HANDLED; @@ -1887,7 +1885,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) bcmgenet_intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR); netif_dbg(priv, intr, priv->dev, - "IRQ=0x%x\n", priv->irq0_stat); + "IRQ=0x%x\n", priv->irq0_stat); if (priv->irq0_stat & (UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_RXDMA_PDONE)) { /* We use NAPI(software interrupt throttling, if @@ -1895,8 +1893,8 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) * Disable interrupt, will be enabled in the poll method. */ if (likely(napi_schedule_prep(&priv->napi))) { - bcmgenet_intrl2_0_writel(priv, - UMAC_IRQ_RXDMA_BDONE, INTRL2_CPU_MASK_SET); + bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_BDONE, + INTRL2_CPU_MASK_SET); __napi_schedule(&priv->napi); } } @@ -1917,7 +1915,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) } if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && - priv->irq0_stat & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) { + priv->irq0_stat & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) { priv->irq0_stat &= ~(UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR); wake_up(&priv->wq); } @@ -1949,7 +1947,7 @@ static void bcmgenet_umac_reset(struct bcmgenet_priv *priv) } static void bcmgenet_set_hw_addr(struct bcmgenet_priv *priv, - unsigned char *addr) + unsigned char *addr) { bcmgenet_umac_writel(priv, (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3], UMAC_MAC0); @@ -2070,14 +2068,14 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_enable_dma(priv, dma_ctrl); ret = request_irq(priv->irq0, bcmgenet_isr0, IRQF_SHARED, - dev->name, priv); + dev->name, priv); if (ret < 0) { netdev_err(dev, "can't request IRQ %d\n", priv->irq0); goto err_fini_dma; } ret = request_irq(priv->irq1, bcmgenet_isr1, IRQF_SHARED, - dev->name, priv); + dev->name, priv); if (ret < 0) { netdev_err(dev, "can't request IRQ %d\n", priv->irq1); goto err_irq0; @@ -2118,8 +2116,7 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) } if (timeout == DMA_TIMEOUT_VAL) { - netdev_warn(priv->dev, - "Timed out while disabling TX DMA\n"); + netdev_warn(priv->dev, "Timed out while disabling TX DMA\n"); ret = -ETIMEDOUT; } @@ -2142,9 +2139,8 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) } if (timeout == DMA_TIMEOUT_VAL) { - netdev_warn(priv->dev, - "Timed out while disabling RX DMA\n"); - ret = -ETIMEDOUT; + netdev_warn(priv->dev, "Timed out while disabling RX DMA\n"); + ret = -ETIMEDOUT; } return ret; @@ -2223,12 +2219,11 @@ static inline void bcmgenet_set_mdf_addr(struct bcmgenet_priv *priv, { u32 reg; - bcmgenet_umac_writel(priv, - addr[0] << 8 | addr[1], UMAC_MDF_ADDR + (*i * 4)); - bcmgenet_umac_writel(priv, - addr[2] << 24 | addr[3] << 16 | - addr[4] << 8 | addr[5], - UMAC_MDF_ADDR + ((*i + 1) * 4)); + bcmgenet_umac_writel(priv, addr[0] << 8 | addr[1], + UMAC_MDF_ADDR + (*i * 4)); + bcmgenet_umac_writel(priv, addr[2] << 24 | addr[3] << 16 | + addr[4] << 8 | addr[5], + UMAC_MDF_ADDR + ((*i + 1) * 4)); reg = bcmgenet_umac_readl(priv, UMAC_MDF_CTRL); reg |= (1 << (MAX_MC_COUNT - *mc)); bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL); @@ -2425,7 +2420,7 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv) /* Print the GENET core version */ dev_info(&priv->pdev->dev, "GENET " GENET_VER_FMT, - major, (reg >> 16) & 0x0f, reg & 0xffff); + major, (reg >> 16) & 0x0f, reg & 0xffff); #ifdef CONFIG_PHYS_ADDR_T_64BIT if (!(params->flags & GENET_HAS_40BITS)) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 2ef8673943de..c862d0666771 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -504,9 +504,9 @@ struct bcmgenet_tx_ring { unsigned int cb_ptr; /* Tx ring initial CB ptr */ unsigned int end_ptr; /* Tx ring end CB ptr */ void (*int_enable)(struct bcmgenet_priv *priv, - struct bcmgenet_tx_ring *); + struct bcmgenet_tx_ring *); void (*int_disable)(struct bcmgenet_priv *priv, - struct bcmgenet_tx_ring *); + struct bcmgenet_tx_ring *); }; /* device context */ diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index fb801d53c443..bdd12410fbbe 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -35,15 +35,15 @@ static int bcmgenet_mii_read(struct mii_bus *bus, int phy_id, int location) u32 reg; bcmgenet_umac_writel(priv, (MDIO_RD | (phy_id << MDIO_PMD_SHIFT) | - (location << MDIO_REG_SHIFT)), UMAC_MDIO_CMD); + (location << MDIO_REG_SHIFT)), UMAC_MDIO_CMD); /* Start MDIO transaction*/ reg = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD); reg |= MDIO_START_BUSY; bcmgenet_umac_writel(priv, reg, UMAC_MDIO_CMD); wait_event_timeout(priv->wq, - !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD) - & MDIO_START_BUSY), - HZ / 100); + !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD) + & MDIO_START_BUSY), + HZ / 100); ret = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD); if (ret & MDIO_READ_FAIL) @@ -54,22 +54,22 @@ static int bcmgenet_mii_read(struct mii_bus *bus, int phy_id, int location) /* write a value to the MII */ static int bcmgenet_mii_write(struct mii_bus *bus, int phy_id, - int location, u16 val) + int location, u16 val) { struct net_device *dev = bus->priv; struct bcmgenet_priv *priv = netdev_priv(dev); u32 reg; bcmgenet_umac_writel(priv, (MDIO_WR | (phy_id << MDIO_PMD_SHIFT) | - (location << MDIO_REG_SHIFT) | (0xffff & val)), - UMAC_MDIO_CMD); + (location << MDIO_REG_SHIFT) | (0xffff & val)), + UMAC_MDIO_CMD); reg = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD); reg |= MDIO_START_BUSY; bcmgenet_umac_writel(priv, reg, UMAC_MDIO_CMD); wait_event_timeout(priv->wq, - !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD) & - MDIO_START_BUSY), - HZ / 100); + !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD) & + MDIO_START_BUSY), + HZ / 100); return 0; } @@ -239,7 +239,7 @@ int bcmgenet_mii_config(struct net_device *dev) phy_name = "external MII"; phydev->supported &= PHY_BASIC_FEATURES; bcmgenet_sys_writel(priv, - PORT_MODE_EXT_EPHY, SYS_PORT_CTRL); + PORT_MODE_EXT_EPHY, SYS_PORT_CTRL); break; case PHY_INTERFACE_MODE_REVMII: @@ -275,7 +275,7 @@ int bcmgenet_mii_config(struct net_device *dev) reg |= RGMII_MODE_EN | id_mode_dis; bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); bcmgenet_sys_writel(priv, - PORT_MODE_EXT_GPHY, SYS_PORT_CTRL); + PORT_MODE_EXT_GPHY, SYS_PORT_CTRL); break; default: dev_err(kdev, "unknown phy mode: %d\n", priv->phy_interface); @@ -354,7 +354,7 @@ static int bcmgenet_mii_probe(struct net_device *dev) priv->mii_bus->irq[phydev->addr] = PHY_POLL; pr_info("attached PHY at address %d [%s]\n", - phydev->addr, phydev->drv->name); + phydev->addr, phydev->drv->name); return 0; } @@ -379,7 +379,7 @@ static int bcmgenet_mii_alloc(struct bcmgenet_priv *priv) bus->read = bcmgenet_mii_read; bus->write = bcmgenet_mii_write; snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", - priv->pdev->name, priv->pdev->id); + priv->pdev->name, priv->pdev->id); bus->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); if (!bus->irq) { -- cgit v1.2.3 From 164d4f20d4afa96090fa46ddec6b56341bc6407c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 23 Jul 2014 10:42:13 -0700 Subject: net: bcmgenet: add and remove missing blank lines checkpatch.pl flagged two blank lines which are not needed, and one that was missing, fix them. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 0f65b4a4d4a4..25aa42b6cd34 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -619,7 +619,6 @@ static void bcmgenet_get_drvinfo(struct net_device *dev, strlcpy(info->driver, "bcmgenet", sizeof(info->driver)); strlcpy(info->version, "v2.0", sizeof(info->version)); info->n_stats = BCMGENET_STATS_LEN; - } static int bcmgenet_get_sset_count(struct net_device *dev, int string_set) @@ -1268,7 +1267,6 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, while ((rxpktprocessed < rxpkttoprocess) && (rxpktprocessed < budget)) { - /* Unmap the packet contents such that we can use the * RSV from the 64 bytes descriptor when enabled and save * a 32-bits register read @@ -1286,6 +1284,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, DMA_DESC_SIZE)); } else { struct status_64 *status; + status = (struct status_64 *)skb->data; dma_length_status = status->length_status; } @@ -1408,7 +1407,6 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv) ret = bcmgenet_rx_refill(priv, cb); if (ret) break; - } return ret; -- cgit v1.2.3 From 8900ea570a38740dc2769080b3bda4f90504d9e3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 23 Jul 2014 10:42:14 -0700 Subject: net: bcmgenet: add missing braces to some if statements checkpatch.pl flagged two locations that did not comply to "CHECK: braces {} should be used on all arms of this statement", fix them. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 25aa42b6cd34..6ebc1b979c01 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1100,8 +1100,9 @@ static int bcmgenet_put_tx_csum(struct net_device *dev, struct sk_buff *skb) tx_csum_info |= STATUS_TX_CSUM_LV; if (ip_proto == IPPROTO_UDP && ip_ver == ETH_P_IP) tx_csum_info |= STATUS_TX_CSUM_PROTO_UDP; - } else + } else { tx_csum_info = 0; + } status->tx_csum_info = tx_csum_info; } @@ -1529,11 +1530,11 @@ static int init_umac(struct bcmgenet_priv *priv) dev_dbg(kdev, "%s:Enabling RXDMA_BDONE interrupt\n", __func__); /* Monitor cable plug/unpluged event for internal PHY */ - if (phy_is_internal(priv->phydev)) + if (phy_is_internal(priv->phydev)) { cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP); - else if (priv->ext_phy) + } else if (priv->ext_phy) { cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP); - else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { + } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { reg = bcmgenet_bp_mc_get(priv); reg |= BIT(priv->hw_params->bp_in_en_shift); -- cgit v1.2.3 From c489be085ac89895fda724242814e4fe4d5277da Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 23 Jul 2014 10:42:15 -0700 Subject: net: bcmgenet: use kcalloc instead of kzalloc There were two places that used kzalloc() with a multiplied sizeof(), replace these with kcalloc as recommended by checkpatch.pl. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 +++--- drivers/net/ethernet/broadcom/genet/bcmmii.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 6ebc1b979c01..28c8111502cd 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1631,8 +1631,8 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, priv->rx_bd_assign_index = 0; priv->rx_c_index = 0; priv->rx_read_ptr = 0; - priv->rx_cbs = kzalloc(priv->num_rx_bds * sizeof(struct enet_cb), - GFP_KERNEL); + priv->rx_cbs = kcalloc(priv->num_rx_bds, sizeof(struct enet_cb), + GFP_KERNEL); if (!priv->rx_cbs) return -ENOMEM; @@ -1773,7 +1773,7 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv) /* Initialize commont TX ring structures */ priv->tx_bds = priv->base + priv->hw_params->tdma_offset; priv->num_tx_bds = TOTAL_DESC; - priv->tx_cbs = kzalloc(priv->num_tx_bds * sizeof(struct enet_cb), + priv->tx_cbs = kcalloc(priv->num_tx_bds, sizeof(struct enet_cb), GFP_KERNEL); if (!priv->tx_cbs) { bcmgenet_fini_dma(priv); diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index bdd12410fbbe..18961613d385 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -381,7 +381,7 @@ static int bcmgenet_mii_alloc(struct bcmgenet_priv *priv) snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", priv->pdev->name, priv->pdev->id); - bus->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); if (!bus->irq) { mdiobus_free(priv->mii_bus); return -ENOMEM; -- cgit v1.2.3 From f5bffecda951b59d0d3cdd616d68952abc52bc40 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 22 Jul 2014 23:01:58 -0700 Subject: net: filter: split filter.c into two files BPF is used in several kernel components. This split creates logical boundary between generic eBPF core and the rest kernel/bpf/core.c: eBPF interpreter net/core/filter.c: classic->eBPF converter, classic verifiers, socket filters This patch only moves functions. Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- kernel/Makefile | 1 + kernel/bpf/Makefile | 1 + kernel/bpf/core.c | 536 ++++++++++++++++++++++++++++++++++++++++++++++++++++ net/core/filter.c | 511 ------------------------------------------------- 4 files changed, 538 insertions(+), 511 deletions(-) create mode 100644 kernel/bpf/Makefile create mode 100644 kernel/bpf/core.c diff --git a/kernel/Makefile b/kernel/Makefile index f2a8b6246ce9..e7360b7c2c0e 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -87,6 +87,7 @@ obj-$(CONFIG_RING_BUFFER) += trace/ obj-$(CONFIG_TRACEPOINTS) += trace/ obj-$(CONFIG_IRQ_WORK) += irq_work.o obj-$(CONFIG_CPU_PM) += cpu_pm.o +obj-$(CONFIG_NET) += bpf/ obj-$(CONFIG_PERF_EVENTS) += events/ diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile new file mode 100644 index 000000000000..6a71145e2769 --- /dev/null +++ b/kernel/bpf/Makefile @@ -0,0 +1 @@ +obj-y := core.o diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c new file mode 100644 index 000000000000..77a240a1ce11 --- /dev/null +++ b/kernel/bpf/core.c @@ -0,0 +1,536 @@ +/* + * Linux Socket Filter - Kernel level socket filtering + * + * Based on the design of the Berkeley Packet Filter. The new + * internal format has been designed by PLUMgrid: + * + * Copyright (c) 2011 - 2014 PLUMgrid, http://plumgrid.com + * + * Authors: + * + * Jay Schulist + * Alexei Starovoitov + * Daniel Borkmann + * + * 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. + * + * Andi Kleen - Fix a few bad bugs and races. + * Kris Katterjohn - Added many additional checks in sk_chk_filter() + */ +#include +#include +#include + +/* Registers */ +#define BPF_R0 regs[BPF_REG_0] +#define BPF_R1 regs[BPF_REG_1] +#define BPF_R2 regs[BPF_REG_2] +#define BPF_R3 regs[BPF_REG_3] +#define BPF_R4 regs[BPF_REG_4] +#define BPF_R5 regs[BPF_REG_5] +#define BPF_R6 regs[BPF_REG_6] +#define BPF_R7 regs[BPF_REG_7] +#define BPF_R8 regs[BPF_REG_8] +#define BPF_R9 regs[BPF_REG_9] +#define BPF_R10 regs[BPF_REG_10] + +/* Named registers */ +#define DST regs[insn->dst_reg] +#define SRC regs[insn->src_reg] +#define FP regs[BPF_REG_FP] +#define ARG1 regs[BPF_REG_ARG1] +#define CTX regs[BPF_REG_CTX] +#define IMM insn->imm + +/* No hurry in this branch + * + * Exported for the bpf jit load helper. + */ +void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, unsigned int size) +{ + u8 *ptr = NULL; + + if (k >= SKF_NET_OFF) + ptr = skb_network_header(skb) + k - SKF_NET_OFF; + else if (k >= SKF_LL_OFF) + ptr = skb_mac_header(skb) + k - SKF_LL_OFF; + if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb)) + return ptr; + + return NULL; +} + +/* Base function for offset calculation. Needs to go into .text section, + * therefore keeping it non-static as well; will also be used by JITs + * anyway later on, so do not let the compiler omit it. + */ +noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) +{ + return 0; +} + +/** + * __sk_run_filter - run a filter on a given context + * @ctx: buffer to run the filter on + * @insn: filter to apply + * + * Decode and apply filter instructions to the skb->data. Return length to + * keep, 0 for none. @ctx is the data we are operating on, @insn is the + * array of filter instructions. + */ +static unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn) +{ + u64 stack[MAX_BPF_STACK / sizeof(u64)]; + u64 regs[MAX_BPF_REG], tmp; + static const void *jumptable[256] = { + [0 ... 255] = &&default_label, + /* Now overwrite non-defaults ... */ + /* 32 bit ALU operations */ + [BPF_ALU | BPF_ADD | BPF_X] = &&ALU_ADD_X, + [BPF_ALU | BPF_ADD | BPF_K] = &&ALU_ADD_K, + [BPF_ALU | BPF_SUB | BPF_X] = &&ALU_SUB_X, + [BPF_ALU | BPF_SUB | BPF_K] = &&ALU_SUB_K, + [BPF_ALU | BPF_AND | BPF_X] = &&ALU_AND_X, + [BPF_ALU | BPF_AND | BPF_K] = &&ALU_AND_K, + [BPF_ALU | BPF_OR | BPF_X] = &&ALU_OR_X, + [BPF_ALU | BPF_OR | BPF_K] = &&ALU_OR_K, + [BPF_ALU | BPF_LSH | BPF_X] = &&ALU_LSH_X, + [BPF_ALU | BPF_LSH | BPF_K] = &&ALU_LSH_K, + [BPF_ALU | BPF_RSH | BPF_X] = &&ALU_RSH_X, + [BPF_ALU | BPF_RSH | BPF_K] = &&ALU_RSH_K, + [BPF_ALU | BPF_XOR | BPF_X] = &&ALU_XOR_X, + [BPF_ALU | BPF_XOR | BPF_K] = &&ALU_XOR_K, + [BPF_ALU | BPF_MUL | BPF_X] = &&ALU_MUL_X, + [BPF_ALU | BPF_MUL | BPF_K] = &&ALU_MUL_K, + [BPF_ALU | BPF_MOV | BPF_X] = &&ALU_MOV_X, + [BPF_ALU | BPF_MOV | BPF_K] = &&ALU_MOV_K, + [BPF_ALU | BPF_DIV | BPF_X] = &&ALU_DIV_X, + [BPF_ALU | BPF_DIV | BPF_K] = &&ALU_DIV_K, + [BPF_ALU | BPF_MOD | BPF_X] = &&ALU_MOD_X, + [BPF_ALU | BPF_MOD | BPF_K] = &&ALU_MOD_K, + [BPF_ALU | BPF_NEG] = &&ALU_NEG, + [BPF_ALU | BPF_END | BPF_TO_BE] = &&ALU_END_TO_BE, + [BPF_ALU | BPF_END | BPF_TO_LE] = &&ALU_END_TO_LE, + /* 64 bit ALU operations */ + [BPF_ALU64 | BPF_ADD | BPF_X] = &&ALU64_ADD_X, + [BPF_ALU64 | BPF_ADD | BPF_K] = &&ALU64_ADD_K, + [BPF_ALU64 | BPF_SUB | BPF_X] = &&ALU64_SUB_X, + [BPF_ALU64 | BPF_SUB | BPF_K] = &&ALU64_SUB_K, + [BPF_ALU64 | BPF_AND | BPF_X] = &&ALU64_AND_X, + [BPF_ALU64 | BPF_AND | BPF_K] = &&ALU64_AND_K, + [BPF_ALU64 | BPF_OR | BPF_X] = &&ALU64_OR_X, + [BPF_ALU64 | BPF_OR | BPF_K] = &&ALU64_OR_K, + [BPF_ALU64 | BPF_LSH | BPF_X] = &&ALU64_LSH_X, + [BPF_ALU64 | BPF_LSH | BPF_K] = &&ALU64_LSH_K, + [BPF_ALU64 | BPF_RSH | BPF_X] = &&ALU64_RSH_X, + [BPF_ALU64 | BPF_RSH | BPF_K] = &&ALU64_RSH_K, + [BPF_ALU64 | BPF_XOR | BPF_X] = &&ALU64_XOR_X, + [BPF_ALU64 | BPF_XOR | BPF_K] = &&ALU64_XOR_K, + [BPF_ALU64 | BPF_MUL | BPF_X] = &&ALU64_MUL_X, + [BPF_ALU64 | BPF_MUL | BPF_K] = &&ALU64_MUL_K, + [BPF_ALU64 | BPF_MOV | BPF_X] = &&ALU64_MOV_X, + [BPF_ALU64 | BPF_MOV | BPF_K] = &&ALU64_MOV_K, + [BPF_ALU64 | BPF_ARSH | BPF_X] = &&ALU64_ARSH_X, + [BPF_ALU64 | BPF_ARSH | BPF_K] = &&ALU64_ARSH_K, + [BPF_ALU64 | BPF_DIV | BPF_X] = &&ALU64_DIV_X, + [BPF_ALU64 | BPF_DIV | BPF_K] = &&ALU64_DIV_K, + [BPF_ALU64 | BPF_MOD | BPF_X] = &&ALU64_MOD_X, + [BPF_ALU64 | BPF_MOD | BPF_K] = &&ALU64_MOD_K, + [BPF_ALU64 | BPF_NEG] = &&ALU64_NEG, + /* Call instruction */ + [BPF_JMP | BPF_CALL] = &&JMP_CALL, + /* Jumps */ + [BPF_JMP | BPF_JA] = &&JMP_JA, + [BPF_JMP | BPF_JEQ | BPF_X] = &&JMP_JEQ_X, + [BPF_JMP | BPF_JEQ | BPF_K] = &&JMP_JEQ_K, + [BPF_JMP | BPF_JNE | BPF_X] = &&JMP_JNE_X, + [BPF_JMP | BPF_JNE | BPF_K] = &&JMP_JNE_K, + [BPF_JMP | BPF_JGT | BPF_X] = &&JMP_JGT_X, + [BPF_JMP | BPF_JGT | BPF_K] = &&JMP_JGT_K, + [BPF_JMP | BPF_JGE | BPF_X] = &&JMP_JGE_X, + [BPF_JMP | BPF_JGE | BPF_K] = &&JMP_JGE_K, + [BPF_JMP | BPF_JSGT | BPF_X] = &&JMP_JSGT_X, + [BPF_JMP | BPF_JSGT | BPF_K] = &&JMP_JSGT_K, + [BPF_JMP | BPF_JSGE | BPF_X] = &&JMP_JSGE_X, + [BPF_JMP | BPF_JSGE | BPF_K] = &&JMP_JSGE_K, + [BPF_JMP | BPF_JSET | BPF_X] = &&JMP_JSET_X, + [BPF_JMP | BPF_JSET | BPF_K] = &&JMP_JSET_K, + /* Program return */ + [BPF_JMP | BPF_EXIT] = &&JMP_EXIT, + /* Store instructions */ + [BPF_STX | BPF_MEM | BPF_B] = &&STX_MEM_B, + [BPF_STX | BPF_MEM | BPF_H] = &&STX_MEM_H, + [BPF_STX | BPF_MEM | BPF_W] = &&STX_MEM_W, + [BPF_STX | BPF_MEM | BPF_DW] = &&STX_MEM_DW, + [BPF_STX | BPF_XADD | BPF_W] = &&STX_XADD_W, + [BPF_STX | BPF_XADD | BPF_DW] = &&STX_XADD_DW, + [BPF_ST | BPF_MEM | BPF_B] = &&ST_MEM_B, + [BPF_ST | BPF_MEM | BPF_H] = &&ST_MEM_H, + [BPF_ST | BPF_MEM | BPF_W] = &&ST_MEM_W, + [BPF_ST | BPF_MEM | BPF_DW] = &&ST_MEM_DW, + /* Load instructions */ + [BPF_LDX | BPF_MEM | BPF_B] = &&LDX_MEM_B, + [BPF_LDX | BPF_MEM | BPF_H] = &&LDX_MEM_H, + [BPF_LDX | BPF_MEM | BPF_W] = &&LDX_MEM_W, + [BPF_LDX | BPF_MEM | BPF_DW] = &&LDX_MEM_DW, + [BPF_LD | BPF_ABS | BPF_W] = &&LD_ABS_W, + [BPF_LD | BPF_ABS | BPF_H] = &&LD_ABS_H, + [BPF_LD | BPF_ABS | BPF_B] = &&LD_ABS_B, + [BPF_LD | BPF_IND | BPF_W] = &&LD_IND_W, + [BPF_LD | BPF_IND | BPF_H] = &&LD_IND_H, + [BPF_LD | BPF_IND | BPF_B] = &&LD_IND_B, + }; + void *ptr; + int off; + +#define CONT ({ insn++; goto select_insn; }) +#define CONT_JMP ({ insn++; goto select_insn; }) + + FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; + ARG1 = (u64) (unsigned long) ctx; + + /* Registers used in classic BPF programs need to be reset first. */ + regs[BPF_REG_A] = 0; + regs[BPF_REG_X] = 0; + +select_insn: + goto *jumptable[insn->code]; + + /* ALU */ +#define ALU(OPCODE, OP) \ + ALU64_##OPCODE##_X: \ + DST = DST OP SRC; \ + CONT; \ + ALU_##OPCODE##_X: \ + DST = (u32) DST OP (u32) SRC; \ + CONT; \ + ALU64_##OPCODE##_K: \ + DST = DST OP IMM; \ + CONT; \ + ALU_##OPCODE##_K: \ + DST = (u32) DST OP (u32) IMM; \ + CONT; + + ALU(ADD, +) + ALU(SUB, -) + ALU(AND, &) + ALU(OR, |) + ALU(LSH, <<) + ALU(RSH, >>) + ALU(XOR, ^) + ALU(MUL, *) +#undef ALU + ALU_NEG: + DST = (u32) -DST; + CONT; + ALU64_NEG: + DST = -DST; + CONT; + ALU_MOV_X: + DST = (u32) SRC; + CONT; + ALU_MOV_K: + DST = (u32) IMM; + CONT; + ALU64_MOV_X: + DST = SRC; + CONT; + ALU64_MOV_K: + DST = IMM; + CONT; + ALU64_ARSH_X: + (*(s64 *) &DST) >>= SRC; + CONT; + ALU64_ARSH_K: + (*(s64 *) &DST) >>= IMM; + CONT; + ALU64_MOD_X: + if (unlikely(SRC == 0)) + return 0; + tmp = DST; + DST = do_div(tmp, SRC); + CONT; + ALU_MOD_X: + if (unlikely(SRC == 0)) + return 0; + tmp = (u32) DST; + DST = do_div(tmp, (u32) SRC); + CONT; + ALU64_MOD_K: + tmp = DST; + DST = do_div(tmp, IMM); + CONT; + ALU_MOD_K: + tmp = (u32) DST; + DST = do_div(tmp, (u32) IMM); + CONT; + ALU64_DIV_X: + if (unlikely(SRC == 0)) + return 0; + do_div(DST, SRC); + CONT; + ALU_DIV_X: + if (unlikely(SRC == 0)) + return 0; + tmp = (u32) DST; + do_div(tmp, (u32) SRC); + DST = (u32) tmp; + CONT; + ALU64_DIV_K: + do_div(DST, IMM); + CONT; + ALU_DIV_K: + tmp = (u32) DST; + do_div(tmp, (u32) IMM); + DST = (u32) tmp; + CONT; + ALU_END_TO_BE: + switch (IMM) { + case 16: + DST = (__force u16) cpu_to_be16(DST); + break; + case 32: + DST = (__force u32) cpu_to_be32(DST); + break; + case 64: + DST = (__force u64) cpu_to_be64(DST); + break; + } + CONT; + ALU_END_TO_LE: + switch (IMM) { + case 16: + DST = (__force u16) cpu_to_le16(DST); + break; + case 32: + DST = (__force u32) cpu_to_le32(DST); + break; + case 64: + DST = (__force u64) cpu_to_le64(DST); + break; + } + CONT; + + /* CALL */ + JMP_CALL: + /* Function call scratches BPF_R1-BPF_R5 registers, + * preserves BPF_R6-BPF_R9, and stores return value + * into BPF_R0. + */ + BPF_R0 = (__bpf_call_base + insn->imm)(BPF_R1, BPF_R2, BPF_R3, + BPF_R4, BPF_R5); + CONT; + + /* JMP */ + JMP_JA: + insn += insn->off; + CONT; + JMP_JEQ_X: + if (DST == SRC) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JEQ_K: + if (DST == IMM) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JNE_X: + if (DST != SRC) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JNE_K: + if (DST != IMM) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JGT_X: + if (DST > SRC) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JGT_K: + if (DST > IMM) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JGE_X: + if (DST >= SRC) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JGE_K: + if (DST >= IMM) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JSGT_X: + if (((s64) DST) > ((s64) SRC)) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JSGT_K: + if (((s64) DST) > ((s64) IMM)) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JSGE_X: + if (((s64) DST) >= ((s64) SRC)) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JSGE_K: + if (((s64) DST) >= ((s64) IMM)) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JSET_X: + if (DST & SRC) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_JSET_K: + if (DST & IMM) { + insn += insn->off; + CONT_JMP; + } + CONT; + JMP_EXIT: + return BPF_R0; + + /* STX and ST and LDX*/ +#define LDST(SIZEOP, SIZE) \ + STX_MEM_##SIZEOP: \ + *(SIZE *)(unsigned long) (DST + insn->off) = SRC; \ + CONT; \ + ST_MEM_##SIZEOP: \ + *(SIZE *)(unsigned long) (DST + insn->off) = IMM; \ + CONT; \ + LDX_MEM_##SIZEOP: \ + DST = *(SIZE *)(unsigned long) (SRC + insn->off); \ + CONT; + + LDST(B, u8) + LDST(H, u16) + LDST(W, u32) + LDST(DW, u64) +#undef LDST + STX_XADD_W: /* lock xadd *(u32 *)(dst_reg + off16) += src_reg */ + atomic_add((u32) SRC, (atomic_t *)(unsigned long) + (DST + insn->off)); + CONT; + STX_XADD_DW: /* lock xadd *(u64 *)(dst_reg + off16) += src_reg */ + atomic64_add((u64) SRC, (atomic64_t *)(unsigned long) + (DST + insn->off)); + CONT; + LD_ABS_W: /* BPF_R0 = ntohl(*(u32 *) (skb->data + imm32)) */ + off = IMM; +load_word: + /* BPF_LD + BPD_ABS and BPF_LD + BPF_IND insns are + * only appearing in the programs where ctx == + * skb. All programs keep 'ctx' in regs[BPF_REG_CTX] + * == BPF_R6, sk_convert_filter() saves it in BPF_R6, + * internal BPF verifier will check that BPF_R6 == + * ctx. + * + * BPF_ABS and BPF_IND are wrappers of function calls, + * so they scratch BPF_R1-BPF_R5 registers, preserve + * BPF_R6-BPF_R9, and store return value into BPF_R0. + * + * Implicit input: + * ctx == skb == BPF_R6 == CTX + * + * Explicit input: + * SRC == any register + * IMM == 32-bit immediate + * + * Output: + * BPF_R0 - 8/16/32-bit skb data converted to cpu endianness + */ + + ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &tmp); + if (likely(ptr != NULL)) { + BPF_R0 = get_unaligned_be32(ptr); + CONT; + } + + return 0; + LD_ABS_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + imm32)) */ + off = IMM; +load_half: + ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &tmp); + if (likely(ptr != NULL)) { + BPF_R0 = get_unaligned_be16(ptr); + CONT; + } + + return 0; + LD_ABS_B: /* BPF_R0 = *(u8 *) (skb->data + imm32) */ + off = IMM; +load_byte: + ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &tmp); + if (likely(ptr != NULL)) { + BPF_R0 = *(u8 *)ptr; + CONT; + } + + return 0; + LD_IND_W: /* BPF_R0 = ntohl(*(u32 *) (skb->data + src_reg + imm32)) */ + off = IMM + SRC; + goto load_word; + LD_IND_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + src_reg + imm32)) */ + off = IMM + SRC; + goto load_half; + LD_IND_B: /* BPF_R0 = *(u8 *) (skb->data + src_reg + imm32) */ + off = IMM + SRC; + goto load_byte; + + default_label: + /* If we ever reach this, we have a bug somewhere. */ + WARN_RATELIMIT(1, "unknown opcode %02x\n", insn->code); + return 0; +} + +void __weak bpf_int_jit_compile(struct sk_filter *prog) +{ +} + +/** + * sk_filter_select_runtime - select execution runtime for BPF program + * @fp: sk_filter populated with internal BPF program + * + * try to JIT internal BPF program, if JIT is not available select interpreter + * BPF program will be executed via SK_RUN_FILTER() macro + */ +void sk_filter_select_runtime(struct sk_filter *fp) +{ + fp->bpf_func = (void *) __sk_run_filter; + + /* Probe if internal BPF can be JITed */ + bpf_int_jit_compile(fp); +} +EXPORT_SYMBOL_GPL(sk_filter_select_runtime); + +/* free internal BPF program */ +void sk_filter_free(struct sk_filter *fp) +{ + bpf_jit_free(fp); +} +EXPORT_SYMBOL_GPL(sk_filter_free); diff --git a/net/core/filter.c b/net/core/filter.c index b90ae7fb3b89..1d0e9492e4fa 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -45,45 +45,6 @@ #include #include -/* Registers */ -#define BPF_R0 regs[BPF_REG_0] -#define BPF_R1 regs[BPF_REG_1] -#define BPF_R2 regs[BPF_REG_2] -#define BPF_R3 regs[BPF_REG_3] -#define BPF_R4 regs[BPF_REG_4] -#define BPF_R5 regs[BPF_REG_5] -#define BPF_R6 regs[BPF_REG_6] -#define BPF_R7 regs[BPF_REG_7] -#define BPF_R8 regs[BPF_REG_8] -#define BPF_R9 regs[BPF_REG_9] -#define BPF_R10 regs[BPF_REG_10] - -/* Named registers */ -#define DST regs[insn->dst_reg] -#define SRC regs[insn->src_reg] -#define FP regs[BPF_REG_FP] -#define ARG1 regs[BPF_REG_ARG1] -#define CTX regs[BPF_REG_CTX] -#define IMM insn->imm - -/* No hurry in this branch - * - * Exported for the bpf jit load helper. - */ -void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, unsigned int size) -{ - u8 *ptr = NULL; - - if (k >= SKF_NET_OFF) - ptr = skb_network_header(skb) + k - SKF_NET_OFF; - else if (k >= SKF_LL_OFF) - ptr = skb_mac_header(skb) + k - SKF_LL_OFF; - if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb)) - return ptr; - - return NULL; -} - /** * sk_filter - run a packet through a socket filter * @sk: sock associated with &sk_buff @@ -126,451 +87,6 @@ int sk_filter(struct sock *sk, struct sk_buff *skb) } EXPORT_SYMBOL(sk_filter); -/* Base function for offset calculation. Needs to go into .text section, - * therefore keeping it non-static as well; will also be used by JITs - * anyway later on, so do not let the compiler omit it. - */ -noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) -{ - return 0; -} - -/** - * __sk_run_filter - run a filter on a given context - * @ctx: buffer to run the filter on - * @insn: filter to apply - * - * Decode and apply filter instructions to the skb->data. Return length to - * keep, 0 for none. @ctx is the data we are operating on, @insn is the - * array of filter instructions. - */ -static unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn) -{ - u64 stack[MAX_BPF_STACK / sizeof(u64)]; - u64 regs[MAX_BPF_REG], tmp; - static const void *jumptable[256] = { - [0 ... 255] = &&default_label, - /* Now overwrite non-defaults ... */ - /* 32 bit ALU operations */ - [BPF_ALU | BPF_ADD | BPF_X] = &&ALU_ADD_X, - [BPF_ALU | BPF_ADD | BPF_K] = &&ALU_ADD_K, - [BPF_ALU | BPF_SUB | BPF_X] = &&ALU_SUB_X, - [BPF_ALU | BPF_SUB | BPF_K] = &&ALU_SUB_K, - [BPF_ALU | BPF_AND | BPF_X] = &&ALU_AND_X, - [BPF_ALU | BPF_AND | BPF_K] = &&ALU_AND_K, - [BPF_ALU | BPF_OR | BPF_X] = &&ALU_OR_X, - [BPF_ALU | BPF_OR | BPF_K] = &&ALU_OR_K, - [BPF_ALU | BPF_LSH | BPF_X] = &&ALU_LSH_X, - [BPF_ALU | BPF_LSH | BPF_K] = &&ALU_LSH_K, - [BPF_ALU | BPF_RSH | BPF_X] = &&ALU_RSH_X, - [BPF_ALU | BPF_RSH | BPF_K] = &&ALU_RSH_K, - [BPF_ALU | BPF_XOR | BPF_X] = &&ALU_XOR_X, - [BPF_ALU | BPF_XOR | BPF_K] = &&ALU_XOR_K, - [BPF_ALU | BPF_MUL | BPF_X] = &&ALU_MUL_X, - [BPF_ALU | BPF_MUL | BPF_K] = &&ALU_MUL_K, - [BPF_ALU | BPF_MOV | BPF_X] = &&ALU_MOV_X, - [BPF_ALU | BPF_MOV | BPF_K] = &&ALU_MOV_K, - [BPF_ALU | BPF_DIV | BPF_X] = &&ALU_DIV_X, - [BPF_ALU | BPF_DIV | BPF_K] = &&ALU_DIV_K, - [BPF_ALU | BPF_MOD | BPF_X] = &&ALU_MOD_X, - [BPF_ALU | BPF_MOD | BPF_K] = &&ALU_MOD_K, - [BPF_ALU | BPF_NEG] = &&ALU_NEG, - [BPF_ALU | BPF_END | BPF_TO_BE] = &&ALU_END_TO_BE, - [BPF_ALU | BPF_END | BPF_TO_LE] = &&ALU_END_TO_LE, - /* 64 bit ALU operations */ - [BPF_ALU64 | BPF_ADD | BPF_X] = &&ALU64_ADD_X, - [BPF_ALU64 | BPF_ADD | BPF_K] = &&ALU64_ADD_K, - [BPF_ALU64 | BPF_SUB | BPF_X] = &&ALU64_SUB_X, - [BPF_ALU64 | BPF_SUB | BPF_K] = &&ALU64_SUB_K, - [BPF_ALU64 | BPF_AND | BPF_X] = &&ALU64_AND_X, - [BPF_ALU64 | BPF_AND | BPF_K] = &&ALU64_AND_K, - [BPF_ALU64 | BPF_OR | BPF_X] = &&ALU64_OR_X, - [BPF_ALU64 | BPF_OR | BPF_K] = &&ALU64_OR_K, - [BPF_ALU64 | BPF_LSH | BPF_X] = &&ALU64_LSH_X, - [BPF_ALU64 | BPF_LSH | BPF_K] = &&ALU64_LSH_K, - [BPF_ALU64 | BPF_RSH | BPF_X] = &&ALU64_RSH_X, - [BPF_ALU64 | BPF_RSH | BPF_K] = &&ALU64_RSH_K, - [BPF_ALU64 | BPF_XOR | BPF_X] = &&ALU64_XOR_X, - [BPF_ALU64 | BPF_XOR | BPF_K] = &&ALU64_XOR_K, - [BPF_ALU64 | BPF_MUL | BPF_X] = &&ALU64_MUL_X, - [BPF_ALU64 | BPF_MUL | BPF_K] = &&ALU64_MUL_K, - [BPF_ALU64 | BPF_MOV | BPF_X] = &&ALU64_MOV_X, - [BPF_ALU64 | BPF_MOV | BPF_K] = &&ALU64_MOV_K, - [BPF_ALU64 | BPF_ARSH | BPF_X] = &&ALU64_ARSH_X, - [BPF_ALU64 | BPF_ARSH | BPF_K] = &&ALU64_ARSH_K, - [BPF_ALU64 | BPF_DIV | BPF_X] = &&ALU64_DIV_X, - [BPF_ALU64 | BPF_DIV | BPF_K] = &&ALU64_DIV_K, - [BPF_ALU64 | BPF_MOD | BPF_X] = &&ALU64_MOD_X, - [BPF_ALU64 | BPF_MOD | BPF_K] = &&ALU64_MOD_K, - [BPF_ALU64 | BPF_NEG] = &&ALU64_NEG, - /* Call instruction */ - [BPF_JMP | BPF_CALL] = &&JMP_CALL, - /* Jumps */ - [BPF_JMP | BPF_JA] = &&JMP_JA, - [BPF_JMP | BPF_JEQ | BPF_X] = &&JMP_JEQ_X, - [BPF_JMP | BPF_JEQ | BPF_K] = &&JMP_JEQ_K, - [BPF_JMP | BPF_JNE | BPF_X] = &&JMP_JNE_X, - [BPF_JMP | BPF_JNE | BPF_K] = &&JMP_JNE_K, - [BPF_JMP | BPF_JGT | BPF_X] = &&JMP_JGT_X, - [BPF_JMP | BPF_JGT | BPF_K] = &&JMP_JGT_K, - [BPF_JMP | BPF_JGE | BPF_X] = &&JMP_JGE_X, - [BPF_JMP | BPF_JGE | BPF_K] = &&JMP_JGE_K, - [BPF_JMP | BPF_JSGT | BPF_X] = &&JMP_JSGT_X, - [BPF_JMP | BPF_JSGT | BPF_K] = &&JMP_JSGT_K, - [BPF_JMP | BPF_JSGE | BPF_X] = &&JMP_JSGE_X, - [BPF_JMP | BPF_JSGE | BPF_K] = &&JMP_JSGE_K, - [BPF_JMP | BPF_JSET | BPF_X] = &&JMP_JSET_X, - [BPF_JMP | BPF_JSET | BPF_K] = &&JMP_JSET_K, - /* Program return */ - [BPF_JMP | BPF_EXIT] = &&JMP_EXIT, - /* Store instructions */ - [BPF_STX | BPF_MEM | BPF_B] = &&STX_MEM_B, - [BPF_STX | BPF_MEM | BPF_H] = &&STX_MEM_H, - [BPF_STX | BPF_MEM | BPF_W] = &&STX_MEM_W, - [BPF_STX | BPF_MEM | BPF_DW] = &&STX_MEM_DW, - [BPF_STX | BPF_XADD | BPF_W] = &&STX_XADD_W, - [BPF_STX | BPF_XADD | BPF_DW] = &&STX_XADD_DW, - [BPF_ST | BPF_MEM | BPF_B] = &&ST_MEM_B, - [BPF_ST | BPF_MEM | BPF_H] = &&ST_MEM_H, - [BPF_ST | BPF_MEM | BPF_W] = &&ST_MEM_W, - [BPF_ST | BPF_MEM | BPF_DW] = &&ST_MEM_DW, - /* Load instructions */ - [BPF_LDX | BPF_MEM | BPF_B] = &&LDX_MEM_B, - [BPF_LDX | BPF_MEM | BPF_H] = &&LDX_MEM_H, - [BPF_LDX | BPF_MEM | BPF_W] = &&LDX_MEM_W, - [BPF_LDX | BPF_MEM | BPF_DW] = &&LDX_MEM_DW, - [BPF_LD | BPF_ABS | BPF_W] = &&LD_ABS_W, - [BPF_LD | BPF_ABS | BPF_H] = &&LD_ABS_H, - [BPF_LD | BPF_ABS | BPF_B] = &&LD_ABS_B, - [BPF_LD | BPF_IND | BPF_W] = &&LD_IND_W, - [BPF_LD | BPF_IND | BPF_H] = &&LD_IND_H, - [BPF_LD | BPF_IND | BPF_B] = &&LD_IND_B, - }; - void *ptr; - int off; - -#define CONT ({ insn++; goto select_insn; }) -#define CONT_JMP ({ insn++; goto select_insn; }) - - FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; - ARG1 = (u64) (unsigned long) ctx; - - /* Registers used in classic BPF programs need to be reset first. */ - regs[BPF_REG_A] = 0; - regs[BPF_REG_X] = 0; - -select_insn: - goto *jumptable[insn->code]; - - /* ALU */ -#define ALU(OPCODE, OP) \ - ALU64_##OPCODE##_X: \ - DST = DST OP SRC; \ - CONT; \ - ALU_##OPCODE##_X: \ - DST = (u32) DST OP (u32) SRC; \ - CONT; \ - ALU64_##OPCODE##_K: \ - DST = DST OP IMM; \ - CONT; \ - ALU_##OPCODE##_K: \ - DST = (u32) DST OP (u32) IMM; \ - CONT; - - ALU(ADD, +) - ALU(SUB, -) - ALU(AND, &) - ALU(OR, |) - ALU(LSH, <<) - ALU(RSH, >>) - ALU(XOR, ^) - ALU(MUL, *) -#undef ALU - ALU_NEG: - DST = (u32) -DST; - CONT; - ALU64_NEG: - DST = -DST; - CONT; - ALU_MOV_X: - DST = (u32) SRC; - CONT; - ALU_MOV_K: - DST = (u32) IMM; - CONT; - ALU64_MOV_X: - DST = SRC; - CONT; - ALU64_MOV_K: - DST = IMM; - CONT; - ALU64_ARSH_X: - (*(s64 *) &DST) >>= SRC; - CONT; - ALU64_ARSH_K: - (*(s64 *) &DST) >>= IMM; - CONT; - ALU64_MOD_X: - if (unlikely(SRC == 0)) - return 0; - tmp = DST; - DST = do_div(tmp, SRC); - CONT; - ALU_MOD_X: - if (unlikely(SRC == 0)) - return 0; - tmp = (u32) DST; - DST = do_div(tmp, (u32) SRC); - CONT; - ALU64_MOD_K: - tmp = DST; - DST = do_div(tmp, IMM); - CONT; - ALU_MOD_K: - tmp = (u32) DST; - DST = do_div(tmp, (u32) IMM); - CONT; - ALU64_DIV_X: - if (unlikely(SRC == 0)) - return 0; - do_div(DST, SRC); - CONT; - ALU_DIV_X: - if (unlikely(SRC == 0)) - return 0; - tmp = (u32) DST; - do_div(tmp, (u32) SRC); - DST = (u32) tmp; - CONT; - ALU64_DIV_K: - do_div(DST, IMM); - CONT; - ALU_DIV_K: - tmp = (u32) DST; - do_div(tmp, (u32) IMM); - DST = (u32) tmp; - CONT; - ALU_END_TO_BE: - switch (IMM) { - case 16: - DST = (__force u16) cpu_to_be16(DST); - break; - case 32: - DST = (__force u32) cpu_to_be32(DST); - break; - case 64: - DST = (__force u64) cpu_to_be64(DST); - break; - } - CONT; - ALU_END_TO_LE: - switch (IMM) { - case 16: - DST = (__force u16) cpu_to_le16(DST); - break; - case 32: - DST = (__force u32) cpu_to_le32(DST); - break; - case 64: - DST = (__force u64) cpu_to_le64(DST); - break; - } - CONT; - - /* CALL */ - JMP_CALL: - /* Function call scratches BPF_R1-BPF_R5 registers, - * preserves BPF_R6-BPF_R9, and stores return value - * into BPF_R0. - */ - BPF_R0 = (__bpf_call_base + insn->imm)(BPF_R1, BPF_R2, BPF_R3, - BPF_R4, BPF_R5); - CONT; - - /* JMP */ - JMP_JA: - insn += insn->off; - CONT; - JMP_JEQ_X: - if (DST == SRC) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JEQ_K: - if (DST == IMM) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JNE_X: - if (DST != SRC) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JNE_K: - if (DST != IMM) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JGT_X: - if (DST > SRC) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JGT_K: - if (DST > IMM) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JGE_X: - if (DST >= SRC) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JGE_K: - if (DST >= IMM) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JSGT_X: - if (((s64) DST) > ((s64) SRC)) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JSGT_K: - if (((s64) DST) > ((s64) IMM)) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JSGE_X: - if (((s64) DST) >= ((s64) SRC)) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JSGE_K: - if (((s64) DST) >= ((s64) IMM)) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JSET_X: - if (DST & SRC) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JSET_K: - if (DST & IMM) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_EXIT: - return BPF_R0; - - /* STX and ST and LDX*/ -#define LDST(SIZEOP, SIZE) \ - STX_MEM_##SIZEOP: \ - *(SIZE *)(unsigned long) (DST + insn->off) = SRC; \ - CONT; \ - ST_MEM_##SIZEOP: \ - *(SIZE *)(unsigned long) (DST + insn->off) = IMM; \ - CONT; \ - LDX_MEM_##SIZEOP: \ - DST = *(SIZE *)(unsigned long) (SRC + insn->off); \ - CONT; - - LDST(B, u8) - LDST(H, u16) - LDST(W, u32) - LDST(DW, u64) -#undef LDST - STX_XADD_W: /* lock xadd *(u32 *)(dst_reg + off16) += src_reg */ - atomic_add((u32) SRC, (atomic_t *)(unsigned long) - (DST + insn->off)); - CONT; - STX_XADD_DW: /* lock xadd *(u64 *)(dst_reg + off16) += src_reg */ - atomic64_add((u64) SRC, (atomic64_t *)(unsigned long) - (DST + insn->off)); - CONT; - LD_ABS_W: /* BPF_R0 = ntohl(*(u32 *) (skb->data + imm32)) */ - off = IMM; -load_word: - /* BPF_LD + BPD_ABS and BPF_LD + BPF_IND insns are - * only appearing in the programs where ctx == - * skb. All programs keep 'ctx' in regs[BPF_REG_CTX] - * == BPF_R6, sk_convert_filter() saves it in BPF_R6, - * internal BPF verifier will check that BPF_R6 == - * ctx. - * - * BPF_ABS and BPF_IND are wrappers of function calls, - * so they scratch BPF_R1-BPF_R5 registers, preserve - * BPF_R6-BPF_R9, and store return value into BPF_R0. - * - * Implicit input: - * ctx == skb == BPF_R6 == CTX - * - * Explicit input: - * SRC == any register - * IMM == 32-bit immediate - * - * Output: - * BPF_R0 - 8/16/32-bit skb data converted to cpu endianness - */ - - ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &tmp); - if (likely(ptr != NULL)) { - BPF_R0 = get_unaligned_be32(ptr); - CONT; - } - - return 0; - LD_ABS_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + imm32)) */ - off = IMM; -load_half: - ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &tmp); - if (likely(ptr != NULL)) { - BPF_R0 = get_unaligned_be16(ptr); - CONT; - } - - return 0; - LD_ABS_B: /* BPF_R0 = *(u8 *) (skb->data + imm32) */ - off = IMM; -load_byte: - ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &tmp); - if (likely(ptr != NULL)) { - BPF_R0 = *(u8 *)ptr; - CONT; - } - - return 0; - LD_IND_W: /* BPF_R0 = ntohl(*(u32 *) (skb->data + src_reg + imm32)) */ - off = IMM + SRC; - goto load_word; - LD_IND_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + src_reg + imm32)) */ - off = IMM + SRC; - goto load_half; - LD_IND_B: /* BPF_R0 = *(u8 *) (skb->data + src_reg + imm32) */ - off = IMM + SRC; - goto load_byte; - - default_label: - /* If we ever reach this, we have a bug somewhere. */ - WARN_RATELIMIT(1, "unknown opcode %02x\n", insn->code); - return 0; -} - /* Helper to find the offset of pkt_type in sk_buff structure. We want * to make sure its still a 3bit field starting at a byte boundary; * taken from arch/x86/net/bpf_jit_comp.c. @@ -1455,33 +971,6 @@ out_err: return ERR_PTR(err); } -void __weak bpf_int_jit_compile(struct sk_filter *prog) -{ -} - -/** - * sk_filter_select_runtime - select execution runtime for BPF program - * @fp: sk_filter populated with internal BPF program - * - * try to JIT internal BPF program, if JIT is not available select interpreter - * BPF program will be executed via SK_RUN_FILTER() macro - */ -void sk_filter_select_runtime(struct sk_filter *fp) -{ - fp->bpf_func = (void *) __sk_run_filter; - - /* Probe if internal BPF can be JITed */ - bpf_int_jit_compile(fp); -} -EXPORT_SYMBOL_GPL(sk_filter_select_runtime); - -/* free internal BPF program */ -void sk_filter_free(struct sk_filter *fp) -{ - bpf_jit_free(fp); -} -EXPORT_SYMBOL_GPL(sk_filter_free); - static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp, struct sock *sk) { -- cgit v1.2.3 From b5f4df3483a1679bc11eb2dd7dcf4f3c8b54d387 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 22 Jul 2014 23:01:59 -0700 Subject: bpf: update MAINTAINERS entry Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 78215a5dea28..62bf15f6954f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1912,6 +1912,13 @@ S: Supported F: drivers/net/bonding/ F: include/uapi/linux/if_bonding.h +BPF (Safe dynamic programs and tools) +M: Alexei Starovoitov +L: netdev@vger.kernel.org +L: linux-kernel@vger.kernel.org +S: Supported +F: kernel/bpf/ + BROADCOM B44 10/100 ETHERNET DRIVER M: Gary Zambrano L: netdev@vger.kernel.org -- cgit v1.2.3 From 508a8c9e264e1057f663e578c47c5ffa00adb160 Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Fri, 6 Jun 2014 01:57:00 +0000 Subject: ixgbe: Fix possible null-dereference in error path In ixgbe_probe, the code at label err_dma can dereference adapter when it has a NULL value. The check is there to avoid disabling a disabled device. When adapter is NULL, treat it as if the device is enabled, because it is enabled in that case. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index f5aa3311ea28..16e8e444c616 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -8477,7 +8477,7 @@ err_alloc_etherdev: pci_select_bars(pdev, IORESOURCE_MEM)); err_pci_reg: err_dma: - if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state)) + if (!adapter || !test_and_set_bit(__IXGBE_DISABLED, &adapter->state)) pci_disable_device(pdev); return err; } -- cgit v1.2.3 From 5cd667b0a4567048bb555927d6ee564f4e5620a9 Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Thu, 17 Jul 2014 15:14:13 -0700 Subject: openvswitch: Allow each vport to have an array of 'port_id's. In order to allow handlers directly read upcalls from datapath, we need to support per-handler netlink socket for each vport in datapath. This commit makes this happen. Also, it is guaranteed to be backward compatible with previous branch. Signed-off-by: Alex Wang Acked-by: Thomas Graf Signed-off-by: Pravin B Shelar --- include/uapi/linux/openvswitch.h | 13 +++-- net/openvswitch/datapath.c | 23 ++++++--- net/openvswitch/vport.c | 101 ++++++++++++++++++++++++++++++++++++++- net/openvswitch/vport.h | 27 +++++++++-- 4 files changed, 148 insertions(+), 16 deletions(-) diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index 0b979ee4bfc0..a794d1dd7b40 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h @@ -118,6 +118,9 @@ struct ovs_vport_stats { /* Allow last Netlink attribute to be unaligned */ #define OVS_DP_F_UNALIGNED (1 << 0) +/* Allow datapath to associate multiple Netlink PIDs to each vport */ +#define OVS_DP_F_VPORT_PIDS (1 << 1) + /* Fixed logical ports. */ #define OVSP_LOCAL ((__u32)0) @@ -203,9 +206,10 @@ enum ovs_vport_type { * this is the name of the network device. Maximum length %IFNAMSIZ-1 bytes * plus a null terminator. * @OVS_VPORT_ATTR_OPTIONS: Vport-specific configuration information. - * @OVS_VPORT_ATTR_UPCALL_PID: The Netlink socket in userspace that - * OVS_PACKET_CMD_MISS upcalls will be directed to for packets received on - * this port. A value of zero indicates that upcalls should not be sent. + * @OVS_VPORT_ATTR_UPCALL_PID: The array of Netlink socket pids in userspace + * among which OVS_PACKET_CMD_MISS upcalls will be distributed for packets + * received on this port. If this is a single-element array of value 0, + * upcalls should not be sent. * @OVS_VPORT_ATTR_STATS: A &struct ovs_vport_stats giving statistics for * packets sent or received through the vport. * @@ -228,7 +232,8 @@ enum ovs_vport_attr { OVS_VPORT_ATTR_TYPE, /* u32 OVS_VPORT_TYPE_* constant. */ OVS_VPORT_ATTR_NAME, /* string name, up to IFNAMSIZ bytes long */ OVS_VPORT_ATTR_OPTIONS, /* nested attributes, varies by vport type */ - OVS_VPORT_ATTR_UPCALL_PID, /* u32 Netlink PID to receive upcalls */ + OVS_VPORT_ATTR_UPCALL_PID, /* array of u32 Netlink socket PIDs for */ + /* receiving upcalls */ OVS_VPORT_ATTR_STATS, /* struct ovs_vport_stats */ __OVS_VPORT_ATTR_MAX }; diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 20f59b62721a..65a8e5c089e4 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -266,7 +266,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) upcall.cmd = OVS_PACKET_CMD_MISS; upcall.key = &key; upcall.userdata = NULL; - upcall.portid = p->upcall_portid; + upcall.portid = ovs_vport_find_upcall_portid(p, skb); ovs_dp_upcall(dp, skb, &upcall); consume_skb(skb); stats_counter = &stats->n_missed; @@ -1373,7 +1373,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) parms.options = NULL; parms.dp = dp; parms.port_no = OVSP_LOCAL; - parms.upcall_portid = nla_get_u32(a[OVS_DP_ATTR_UPCALL_PID]); + parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID]; ovs_dp_change(dp, a); @@ -1632,8 +1632,8 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) || nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) || - nla_put_string(skb, OVS_VPORT_ATTR_NAME, vport->ops->get_name(vport)) || - nla_put_u32(skb, OVS_VPORT_ATTR_UPCALL_PID, vport->upcall_portid)) + nla_put_string(skb, OVS_VPORT_ATTR_NAME, + vport->ops->get_name(vport))) goto nla_put_failure; ovs_vport_get_stats(vport, &vport_stats); @@ -1641,6 +1641,9 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, &vport_stats)) goto nla_put_failure; + if (ovs_vport_get_upcall_portids(vport, skb)) + goto nla_put_failure; + err = ovs_vport_get_options(vport, skb); if (err == -EMSGSIZE) goto error; @@ -1762,7 +1765,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) parms.options = a[OVS_VPORT_ATTR_OPTIONS]; parms.dp = dp; parms.port_no = port_no; - parms.upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]); + parms.upcall_portids = a[OVS_VPORT_ATTR_UPCALL_PID]; vport = new_vport(&parms); err = PTR_ERR(vport); @@ -1812,8 +1815,14 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info) goto exit_unlock_free; } - if (a[OVS_VPORT_ATTR_UPCALL_PID]) - vport->upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]); + + if (a[OVS_VPORT_ATTR_UPCALL_PID]) { + struct nlattr *ids = a[OVS_VPORT_ATTR_UPCALL_PID]; + + err = ovs_vport_set_upcall_portids(vport, ids); + if (err) + goto exit_unlock_free; + } err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid, info->snd_seq, 0, OVS_VPORT_CMD_NEW); diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 42c0f4a0b78c..702fb21bfe15 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -134,10 +134,12 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops, vport->dp = parms->dp; vport->port_no = parms->port_no; - vport->upcall_portid = parms->upcall_portid; vport->ops = ops; INIT_HLIST_NODE(&vport->dp_hash_node); + if (ovs_vport_set_upcall_portids(vport, parms->upcall_portids)) + return ERR_PTR(-EINVAL); + vport->percpu_stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); if (!vport->percpu_stats) { kfree(vport); @@ -161,6 +163,10 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops, */ void ovs_vport_free(struct vport *vport) { + /* vport is freed from RCU callback or error path, Therefore + * it is safe to use raw dereference. + */ + kfree(rcu_dereference_raw(vport->upcall_portids)); free_percpu(vport->percpu_stats); kfree(vport); } @@ -326,6 +332,99 @@ int ovs_vport_get_options(const struct vport *vport, struct sk_buff *skb) return 0; } +/** + * ovs_vport_set_upcall_portids - set upcall portids of @vport. + * + * @vport: vport to modify. + * @ids: new configuration, an array of port ids. + * + * Sets the vport's upcall_portids to @ids. + * + * Returns 0 if successful, -EINVAL if @ids is zero length or cannot be parsed + * as an array of U32. + * + * Must be called with ovs_mutex. + */ +int ovs_vport_set_upcall_portids(struct vport *vport, struct nlattr *ids) +{ + struct vport_portids *old, *vport_portids; + + if (!nla_len(ids) || nla_len(ids) % sizeof(u32)) + return -EINVAL; + + old = ovsl_dereference(vport->upcall_portids); + + vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids), + GFP_KERNEL); + if (!vport_portids) + return -ENOMEM; + + vport_portids->n_ids = nla_len(ids) / sizeof(u32); + vport_portids->rn_ids = reciprocal_value(vport_portids->n_ids); + nla_memcpy(vport_portids->ids, ids, nla_len(ids)); + + rcu_assign_pointer(vport->upcall_portids, vport_portids); + + if (old) + kfree_rcu(old, rcu); + return 0; +} + +/** + * ovs_vport_get_upcall_portids - get the upcall_portids of @vport. + * + * @vport: vport from which to retrieve the portids. + * @skb: sk_buff where portids should be appended. + * + * Retrieves the configuration of the given vport, appending the + * %OVS_VPORT_ATTR_UPCALL_PID attribute which is the array of upcall + * portids to @skb. + * + * Returns 0 if successful, -EMSGSIZE if @skb has insufficient room. + * If an error occurs, @skb is left unmodified. Must be called with + * ovs_mutex or rcu_read_lock. + */ +int ovs_vport_get_upcall_portids(const struct vport *vport, + struct sk_buff *skb) +{ + struct vport_portids *ids; + + ids = rcu_dereference_ovsl(vport->upcall_portids); + + if (vport->dp->user_features & OVS_DP_F_VPORT_PIDS) + return nla_put(skb, OVS_VPORT_ATTR_UPCALL_PID, + ids->n_ids * sizeof(u32), (void *)ids->ids); + else + return nla_put_u32(skb, OVS_VPORT_ATTR_UPCALL_PID, ids->ids[0]); +} + +/** + * ovs_vport_find_upcall_portid - find the upcall portid to send upcall. + * + * @vport: vport from which the missed packet is received. + * @skb: skb that the missed packet was received. + * + * Uses the skb_get_hash() to select the upcall portid to send the + * upcall. + * + * Returns the portid of the target socket. Must be called with rcu_read_lock. + */ +u32 ovs_vport_find_upcall_portid(const struct vport *p, struct sk_buff *skb) +{ + struct vport_portids *ids; + u32 ids_index; + u32 hash; + + ids = rcu_dereference(p->upcall_portids); + + if (ids->n_ids == 1 && ids->ids[0] == 0) + return 0; + + hash = skb_get_hash(skb); + ids_index = hash - ids->n_ids * reciprocal_divide(hash, ids->rn_ids); + return ids->ids[ids_index]; +} + /** * ovs_vport_receive - pass up received packet to the datapath for processing * diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 8d721e62f388..35f89d84b45e 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,10 @@ void ovs_vport_get_stats(struct vport *, struct ovs_vport_stats *); int ovs_vport_set_options(struct vport *, struct nlattr *options); int ovs_vport_get_options(const struct vport *, struct sk_buff *); +int ovs_vport_set_upcall_portids(struct vport *, struct nlattr *pids); +int ovs_vport_get_upcall_portids(const struct vport *, struct sk_buff *); +u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *); + int ovs_vport_send(struct vport *, struct sk_buff *); /* The following definitions are for implementers of vport devices: */ @@ -62,13 +67,27 @@ struct vport_err_stats { u64 tx_dropped; u64 tx_errors; }; +/** + * struct vport_portids - array of netlink portids of a vport. + * must be protected by rcu. + * @rn_ids: The reciprocal value of @n_ids. + * @rcu: RCU callback head for deferred destruction. + * @n_ids: Size of @ids array. + * @ids: Array storing the Netlink socket pids to be used for packets received + * on this port that miss the flow table. + */ +struct vport_portids { + struct reciprocal_value rn_ids; + struct rcu_head rcu; + u32 n_ids; + u32 ids[]; +}; /** * struct vport - one port within a datapath * @rcu: RCU callback head for deferred destruction. * @dp: Datapath to which this port belongs. - * @upcall_portid: The Netlink port to use for packets received on this port that - * miss the flow table. + * @upcall_portids: RCU protected 'struct vport_portids'. * @port_no: Index into @dp's @ports array. * @hash_node: Element in @dev_table hash table in vport.c. * @dp_hash_node: Element in @datapath->ports hash table in datapath.c. @@ -80,7 +99,7 @@ struct vport_err_stats { struct vport { struct rcu_head rcu; struct datapath *dp; - u32 upcall_portid; + struct vport_portids __rcu *upcall_portids; u16 port_no; struct hlist_node hash_node; @@ -111,7 +130,7 @@ struct vport_parms { /* For ovs_vport_alloc(). */ struct datapath *dp; u16 port_no; - u32 upcall_portid; + struct nlattr *upcall_portids; }; /** -- cgit v1.2.3 From f6eec614d2252a99b861e288b6301599d2d58da4 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Thu, 17 Jul 2014 15:14:15 -0700 Subject: openvswitch: Enable tunnel GSO for OVS bridge. Following patch enables all available tunnel GSO features for OVS bridge device so that ovs can use hardware offloads available to underling device. Signed-off-by: Pravin B Shelar Acked-by: Andy Zhou --- include/linux/netdev_features.h | 8 ++++++++ net/openvswitch/vport-internal_dev.c | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index d99800cbdcf3..dcfdecbfa0b7 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -176,4 +176,12 @@ enum { NETIF_F_HW_VLAN_STAG_RX | \ NETIF_F_HW_VLAN_STAG_TX) +#define NETIF_F_GSO_ENCAP_ALL (NETIF_F_GSO_GRE | \ + NETIF_F_GSO_GRE_CSUM | \ + NETIF_F_GSO_IPIP | \ + NETIF_F_GSO_SIT | \ + NETIF_F_GSO_UDP_TUNNEL | \ + NETIF_F_GSO_UDP_TUNNEL_CSUM | \ + NETIF_F_GSO_MPLS) + #endif /* _LINUX_NETDEV_FEATURES_H */ diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index bd658555afdf..84516126e5f3 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -140,11 +140,14 @@ static void do_setup(struct net_device *netdev) netdev->tx_queue_len = 0; netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST | - NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE; + NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | + NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ENCAP_ALL; netdev->vlan_features = netdev->features; + netdev->hw_enc_features = netdev->features; netdev->features |= NETIF_F_HW_VLAN_CTAG_TX; netdev->hw_features = netdev->features & ~NETIF_F_LLTX; + eth_hw_addr_random(netdev); } -- cgit v1.2.3 From 339de30f5b40b08574a8ca53670d795f7dd1f8bb Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Fri, 6 Jun 2014 01:57:06 +0000 Subject: ixgbe: Change some uses of strncpy to strlcpy Change some uses of strncpy to use the more appropriate strlcpy when clearing is not needed to prevent information leakage. Also change some length arguments to use the preferred sizeof form. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 16e8e444c616..9aa9d0ba6d3e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -8161,7 +8161,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->netdev_ops = &ixgbe_netdev_ops; ixgbe_set_ethtool_ops(netdev); netdev->watchdog_timeo = 5 * HZ; - strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); + strlcpy(netdev->name, pci_name(pdev), sizeof(netdev->name)); adapter->bd_number = cards_found; @@ -8386,9 +8386,9 @@ skip_sriov: } ixgbe_check_minimum_link(adapter, expected_gts); - err = ixgbe_read_pba_string_generic(hw, part_str, IXGBE_PBANUM_LENGTH); + err = ixgbe_read_pba_string_generic(hw, part_str, sizeof(part_str)); if (err) - strncpy(part_str, "Unknown", IXGBE_PBANUM_LENGTH); + strlcpy(part_str, "Unknown", sizeof(part_str)); if (ixgbe_is_sfp(hw) && hw->phy.sfp_type != ixgbe_sfp_type_not_present) e_dev_info("MAC: %d, PHY: %d, SFP+: %d, PBA No: %s\n", hw->mac.type, hw->phy.type, hw->phy.sfp_type, -- cgit v1.2.3 From 8818970d8d361e358dd61e5d5774e67794cde791 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Sat, 19 Jul 2014 07:17:16 +0000 Subject: ixgbe: fix use of list_for_each in ixgbe_enumerate_functions Fix a bug in the misuse of the list_for_each macro to loop over every entry in the bus_list. Instead of attempting to loop over the list from a random entry point, go up to the bus and use the real list_head entry point. This prevents the possible read or write of unallocated or incorrectly addressed memory. Signed-off-by: Jacob Keller Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 9aa9d0ba6d3e..4268a894ad2d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7973,23 +7973,20 @@ static const struct net_device_ops ixgbe_netdev_ops = { **/ static inline int ixgbe_enumerate_functions(struct ixgbe_adapter *adapter) { - struct list_head *entry; + struct pci_dev *entry; int physfns = 0; /* Some cards can not use the generic count PCIe functions method, * because they are behind a parent switch, so we hardcode these with * the correct number of functions. */ - if (ixgbe_pcie_from_parent(&adapter->hw)) { + if (ixgbe_pcie_from_parent(&adapter->hw)) physfns = 4; - } else { - list_for_each(entry, &adapter->pdev->bus_list) { - struct pci_dev *pdev = - list_entry(entry, struct pci_dev, bus_list); - /* don't count virtual functions */ - if (!pdev->is_virtfn) - physfns++; - } + + list_for_each_entry(entry, &adapter->pdev->bus->devices, bus_list) { + /* don't count virtual functions */ + if (!entry->is_virtfn) + physfns++; } return physfns; -- cgit v1.2.3 From caafb95d6952c4c977c1b9ddf32bb56bfcda8059 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Sat, 19 Jul 2014 07:17:17 +0000 Subject: ixgbe: don't check minimum link when direct assigned to virtual machine This patch prevents the display of the minimum link qualification check if we might be in a virtual machine. This check is incorrect and misleading in this case, since we actually don't really know what the available bandwidth is. To do so, we simply check whether each function on the bus matches our device id. If it doesn't the most likely scenario is that we're directly assigned to a virtual machine. Signed-off-by: Jacob Keller Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 4268a894ad2d..e1f83ee03c6a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7973,7 +7973,7 @@ static const struct net_device_ops ixgbe_netdev_ops = { **/ static inline int ixgbe_enumerate_functions(struct ixgbe_adapter *adapter) { - struct pci_dev *entry; + struct pci_dev *entry, *pdev = adapter->pdev; int physfns = 0; /* Some cards can not use the generic count PCIe functions method, @@ -7985,8 +7985,20 @@ static inline int ixgbe_enumerate_functions(struct ixgbe_adapter *adapter) list_for_each_entry(entry, &adapter->pdev->bus->devices, bus_list) { /* don't count virtual functions */ - if (!entry->is_virtfn) - physfns++; + if (entry->is_virtfn) + continue; + + /* When the devices on the bus don't all match our device ID, + * we can't reliably determine the correct number of + * functions. This can occur if a function has been direct + * attached to a virtual machine using VT-d, for example. In + * this case, simply return -1 to indicate this. + */ + if ((entry->vendor != pdev->vendor) || + (entry->device != pdev->device)) + return -1; + + physfns++; } return physfns; @@ -8381,7 +8393,10 @@ skip_sriov: expected_gts = ixgbe_enumerate_functions(adapter) * 10; break; } - ixgbe_check_minimum_link(adapter, expected_gts); + + /* don't check link if we failed to enumerate functions */ + if (expected_gts > 0) + ixgbe_check_minimum_link(adapter, expected_gts); err = ixgbe_read_pba_string_generic(hw, part_str, sizeof(part_str)); if (err) -- cgit v1.2.3 From 1516f0a6492a3d1bd9fbebeac331950986ec9a9b Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Wed, 9 Jul 2014 04:55:45 +0000 Subject: igb: Add message when malformed packets detected by hw This patch adds a check and prints the error cause register value when the hardware detects a malformed packet. This is a very unlikely scenario but has been seen occasionally, so printing the message to assist the user. Signed-off-by: Carolyn Wyborny Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_regs.h | 1 + drivers/net/ethernet/intel/igb/igb_main.c | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h index f5ba4e4eafb9..6f0490d0e981 100644 --- a/drivers/net/ethernet/intel/igb/e1000_regs.h +++ b/drivers/net/ethernet/intel/igb/e1000_regs.h @@ -355,6 +355,7 @@ #define E1000_UTA 0x0A000 /* Unicast Table Array - RW */ #define E1000_IOVTCL 0x05BBC /* IOV Control Register */ #define E1000_TXSWC 0x05ACC /* Tx Switch Control */ +#define E1000_LVMMC 0x03548 /* Last VM Misbehavior cause */ /* These act per VF so an array friendly macro is used */ #define E1000_P2VMAILBOX(_n) (0x00C00 + (4 * (_n))) #define E1000_VMBMEM(_n) (0x00800 + (64 * (_n))) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 4d2dc17fd31b..bd8de67c17a9 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -4166,6 +4166,26 @@ static bool igb_thermal_sensor_event(struct e1000_hw *hw, u32 event) return ret; } +/** + * igb_check_lvmmc - check for malformed packets received + * and indicated in LVMMC register + * @adapter: pointer to adapter + **/ +static void igb_check_lvmmc(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 lvmmc; + + lvmmc = rd32(E1000_LVMMC); + if (lvmmc) { + if (unlikely(net_ratelimit())) { + netdev_warn(adapter->netdev, + "malformed Tx packet detected and dropped, LVMMC:0x%08x\n", + lvmmc); + } + } +} + /** * igb_watchdog - Timer Call-back * @data: pointer to adapter cast into an unsigned long @@ -4361,6 +4381,11 @@ static void igb_watchdog_task(struct work_struct *work) igb_spoof_check(adapter); igb_ptp_rx_hang(adapter); + /* Check LVMMC register on i350/i354 only */ + if ((adapter->hw.mac.type == e1000_i350) || + (adapter->hw.mac.type == e1000_i354)) + igb_check_lvmmc(adapter); + /* Reset the timer */ if (!test_bit(__IGB_DOWN, &adapter->state)) { if (adapter->flags & IGB_FLAG_NEED_LINK_UPDATE) -- cgit v1.2.3 From bf22a6bd0f461aae2e8270a46accb3aefd1937ce Mon Sep 17 00:00:00 2001 From: Todd Fujinaka Date: Tue, 15 Jul 2014 06:51:11 +0000 Subject: igb: bump igb version to 5.2.13 Bump version number. Signed-off-by: Todd Fujinaka Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index bd8de67c17a9..cb14bbdfb056 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -57,8 +57,8 @@ #include "igb.h" #define MAJ 5 -#define MIN 0 -#define BUILD 5 +#define MIN 2 +#define BUILD 13 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ __stringify(BUILD) "-k" char igb_driver_name[] = "igb"; -- cgit v1.2.3 From efe1ac25d084fd56c5b809634a0444606c2a5cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toralf=20F=C3=B6rster?= Date: Tue, 20 May 2014 08:23:00 +0000 Subject: i40e: fix format mismatch in drivers/net/ethernet/intel/i40e/i40e_debugfs.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit spotted by cppcheck Signed-off-by: Toralf Förster Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index ec07332e109e..9eaed04618a3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1238,7 +1238,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, } else if (strncmp(cmd_buf, "add pvid", 8) == 0) { i40e_status ret; u16 vid; - int v; + unsigned int v; cnt = sscanf(&cmd_buf[8], "%i %u", &vsi_seid, &v); if (cnt != 2) { @@ -1254,7 +1254,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, goto command_write_done; } - vid = (unsigned)v; + vid = v; ret = i40e_vsi_add_pvid(vsi, vid); if (!ret) dev_info(&pf->pdev->dev, -- cgit v1.2.3 From cd552cb49e9ad5fd8748fb6b38a8bd38e9e4d86c Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 9 Jul 2014 07:46:09 +0000 Subject: i40e/i40evf: Add nvmupdate support This implements a state machine intended to support the userland tool for updating the device eeprom. The state machine implements one-shot reads, writes, multi-step write sessions, and checksum requests. If we're in the middle of a multi-step write session, no one should fire off other writes, however, one shot reads are valid. The userland tool is expected to keep track of its session status, arrange the placement and ordering of the writes, and deal with the checksum requirement. This patch also adds nvmupdate support to ethtool callbacks. The get_eeprom() and set_eeprom() services in ethtool are used here to facilitate the userland NVMUpdate tool. The 'magic' value in the get and set commands is used to pass additional control information for managing the read and write steps. The read operation works both as normally expected in the standard ethtool method, as well as with the extra NVM controls. The write operation works only for the expanded NVM functions - the normal ethtool method is not allowed because of the NVM semaphore management needed for multipart writes, as well as the checksum requirement. Change-ID: I1d84a170153a9f437906744e2e350fd68fe7563d Signed-off-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 21 +- drivers/net/ethernet/intel/i40e/i40e_adminq.h | 36 ++ drivers/net/ethernet/intel/i40e/i40e_common.c | 88 ++++ drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 61 ++- drivers/net/ethernet/intel/i40e/i40e_nvm.c | 511 +++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_prototype.h | 7 + drivers/net/ethernet/intel/i40e/i40e_type.h | 58 +++ drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 6 - drivers/net/ethernet/intel/i40evf/i40e_adminq.h | 36 ++ drivers/net/ethernet/intel/i40evf/i40e_type.h | 58 +++ 10 files changed, 866 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 0e551f281d59..1e21fbb1359c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -38,8 +38,8 @@ static void i40e_resume_aq(struct i40e_hw *hw); **/ static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc) { - return (desc->opcode == i40e_aqc_opc_nvm_erase) || - (desc->opcode == i40e_aqc_opc_nvm_update); + return (desc->opcode == cpu_to_le16(i40e_aqc_opc_nvm_erase)) || + (desc->opcode == cpu_to_le16(i40e_aqc_opc_nvm_update)); } /** @@ -889,9 +889,6 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; } - if (i40e_is_nvm_update_op(desc)) - hw->aq.nvm_busy = true; - if (le16_to_cpu(desc->datalen) == buff_size) { i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer writeback:\n"); @@ -907,6 +904,9 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, status = I40E_ERR_ADMIN_QUEUE_TIMEOUT; } + if (!status && i40e_is_nvm_update_op(desc)) + hw->aq.nvm_busy = true; + asq_send_command_error: mutex_unlock(&hw->aq.asq_mutex); asq_send_command_exit: @@ -988,9 +988,6 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw, e->msg_size); } - if (i40e_is_nvm_update_op(&e->desc)) - hw->aq.nvm_busy = false; - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf); @@ -1023,6 +1020,14 @@ clean_arq_element_out: *pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc); mutex_unlock(&hw->aq.arq_mutex); + if (i40e_is_nvm_update_op(&e->desc)) { + hw->aq.nvm_busy = false; + if (hw->aq.nvm_release_on_done) { + i40e_release_nvm(hw); + hw->aq.nvm_release_on_done = false; + } + } + return ret_code; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h index bb76be1d38f7..ba38a89c79d6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h @@ -94,6 +94,7 @@ struct i40e_adminq_info { u16 api_maj_ver; /* api major version */ u16 api_min_ver; /* api minor version */ bool nvm_busy; + bool nvm_release_on_done; struct mutex asq_mutex; /* Send queue lock */ struct mutex arq_mutex; /* Receive queue lock */ @@ -103,6 +104,41 @@ struct i40e_adminq_info { enum i40e_admin_queue_err arq_last_status; }; +/** + * i40e_aq_rc_to_posix - convert errors to user-land codes + * aq_rc: AdminQ error code to convert + **/ +static inline int i40e_aq_rc_to_posix(u16 aq_rc) +{ + int aq_to_posix[] = { + 0, /* I40E_AQ_RC_OK */ + -EPERM, /* I40E_AQ_RC_EPERM */ + -ENOENT, /* I40E_AQ_RC_ENOENT */ + -ESRCH, /* I40E_AQ_RC_ESRCH */ + -EINTR, /* I40E_AQ_RC_EINTR */ + -EIO, /* I40E_AQ_RC_EIO */ + -ENXIO, /* I40E_AQ_RC_ENXIO */ + -E2BIG, /* I40E_AQ_RC_E2BIG */ + -EAGAIN, /* I40E_AQ_RC_EAGAIN */ + -ENOMEM, /* I40E_AQ_RC_ENOMEM */ + -EACCES, /* I40E_AQ_RC_EACCES */ + -EFAULT, /* I40E_AQ_RC_EFAULT */ + -EBUSY, /* I40E_AQ_RC_EBUSY */ + -EEXIST, /* I40E_AQ_RC_EEXIST */ + -EINVAL, /* I40E_AQ_RC_EINVAL */ + -ENOTTY, /* I40E_AQ_RC_ENOTTY */ + -ENOSPC, /* I40E_AQ_RC_ENOSPC */ + -ENOSYS, /* I40E_AQ_RC_ENOSYS */ + -ERANGE, /* I40E_AQ_RC_ERANGE */ + -EPIPE, /* I40E_AQ_RC_EFLUSHED */ + -ESPIPE, /* I40E_AQ_RC_BAD_ADDR */ + -EROFS, /* I40E_AQ_RC_EMODE */ + -EFBIG, /* I40E_AQ_RC_EFBIG */ + }; + + return aq_to_posix[aq_rc]; +} + /* general information */ #define I40E_AQ_LARGE_BUF 512 #define I40E_ASQ_CMD_TIMEOUT 100000 /* usecs */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index c65f4e8e6cee..f4e502a305ff 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -2121,6 +2121,47 @@ i40e_aq_read_nvm_exit: return status; } +/** + * i40e_aq_erase_nvm + * @hw: pointer to the hw struct + * @module_pointer: module pointer location in words from the NVM beginning + * @offset: offset in the module (expressed in 4 KB from module's beginning) + * @length: length of the section to be erased (expressed in 4 KB) + * @last_command: tells if this is the last command in a series + * @cmd_details: pointer to command details structure or NULL + * + * Erase the NVM sector using the admin queue commands + **/ +i40e_status i40e_aq_erase_nvm(struct i40e_hw *hw, u8 module_pointer, + u32 offset, u16 length, bool last_command, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aqc_nvm_update *cmd = + (struct i40e_aqc_nvm_update *)&desc.params.raw; + i40e_status status; + + /* In offset the highest byte must be zeroed. */ + if (offset & 0xFF000000) { + status = I40E_ERR_PARAM; + goto i40e_aq_erase_nvm_exit; + } + + i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_nvm_erase); + + /* If this is the last command in a series, set the proper flag. */ + if (last_command) + cmd->command_flags |= I40E_AQ_NVM_LAST_CMD; + cmd->module_pointer = module_pointer; + cmd->offset = cpu_to_le32(offset); + cmd->length = cpu_to_le16(length); + + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + +i40e_aq_erase_nvm_exit: + return status; +} + #define I40E_DEV_FUNC_CAP_SWITCH_MODE 0x01 #define I40E_DEV_FUNC_CAP_MGMT_MODE 0x02 #define I40E_DEV_FUNC_CAP_NPAR 0x03 @@ -2350,6 +2391,53 @@ exit: return status; } +/** + * i40e_aq_update_nvm + * @hw: pointer to the hw struct + * @module_pointer: module pointer location in words from the NVM beginning + * @offset: byte offset from the module beginning + * @length: length of the section to be written (in bytes from the offset) + * @data: command buffer (size [bytes] = length) + * @last_command: tells if this is the last command in a series + * @cmd_details: pointer to command details structure or NULL + * + * Update the NVM using the admin queue commands + **/ +i40e_status i40e_aq_update_nvm(struct i40e_hw *hw, u8 module_pointer, + u32 offset, u16 length, void *data, + bool last_command, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aqc_nvm_update *cmd = + (struct i40e_aqc_nvm_update *)&desc.params.raw; + i40e_status status; + + /* In offset the highest byte must be zeroed. */ + if (offset & 0xFF000000) { + status = I40E_ERR_PARAM; + goto i40e_aq_update_nvm_exit; + } + + i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_nvm_update); + + /* If this is the last command in a series, set the proper flag. */ + if (last_command) + cmd->command_flags |= I40E_AQ_NVM_LAST_CMD; + cmd->module_pointer = module_pointer; + cmd->offset = cpu_to_le32(offset); + cmd->length = cpu_to_le16(length); + + desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD)); + if (length > I40E_AQ_LARGE_BUF) + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB); + + status = i40e_asq_send_command(hw, &desc, data, length, cmd_details); + +i40e_aq_update_nvm_exit: + return status; +} + /** * i40e_aq_get_lldp_mib * @hw: pointer to the hw struct diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 3abd3cbab75f..f1d241ec1fc3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -759,10 +759,33 @@ static int i40e_get_eeprom(struct net_device *netdev, u8 *eeprom_buff; u16 i, sectors; bool last; + u32 magic; + #define I40E_NVM_SECTOR_SIZE 4096 if (eeprom->len == 0) return -EINVAL; + /* check for NVMUpdate access method */ + magic = hw->vendor_id | (hw->device_id << 16); + if (eeprom->magic && eeprom->magic != magic) { + int errno; + + /* make sure it is the right magic for NVMUpdate */ + if ((eeprom->magic >> 16) != hw->device_id) + return -EINVAL; + + ret_val = i40e_nvmupd_command(hw, + (struct i40e_nvm_access *)eeprom, + bytes, &errno); + if (ret_val) + dev_info(&pf->pdev->dev, + "NVMUpdate read failed err=%d status=0x%x\n", + ret_val, hw->aq.asq_last_status); + + return errno; + } + + /* normal ethtool get_eeprom support */ eeprom->magic = hw->vendor_id | (hw->device_id << 16); eeprom_buff = kzalloc(eeprom->len, GFP_KERNEL); @@ -789,7 +812,7 @@ static int i40e_get_eeprom(struct net_device *netdev, ret_val = i40e_aq_read_nvm(hw, 0x0, eeprom->offset + (I40E_NVM_SECTOR_SIZE * i), len, - eeprom_buff + (I40E_NVM_SECTOR_SIZE * i), + (u8 *)eeprom_buff + (I40E_NVM_SECTOR_SIZE * i), last, NULL); if (ret_val) { dev_info(&pf->pdev->dev, @@ -801,7 +824,7 @@ static int i40e_get_eeprom(struct net_device *netdev, release_nvm: i40e_release_nvm(hw); - memcpy(bytes, eeprom_buff, eeprom->len); + memcpy(bytes, (u8 *)eeprom_buff, eeprom->len); free_buff: kfree(eeprom_buff); return ret_val; @@ -821,6 +844,39 @@ static int i40e_get_eeprom_len(struct net_device *netdev) return val; } +static int i40e_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_hw *hw = &np->vsi->back->hw; + struct i40e_pf *pf = np->vsi->back; + int ret_val = 0; + int errno; + u32 magic; + + /* normal ethtool set_eeprom is not supported */ + magic = hw->vendor_id | (hw->device_id << 16); + if (eeprom->magic == magic) + return -EOPNOTSUPP; + + /* check for NVMUpdate access method */ + if (!eeprom->magic || (eeprom->magic >> 16) != hw->device_id) + return -EINVAL; + + if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) || + test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state)) + return -EBUSY; + + ret_val = i40e_nvmupd_command(hw, (struct i40e_nvm_access *)eeprom, + bytes, &errno); + if (ret_val) + dev_info(&pf->pdev->dev, + "NVMUpdate write failed err=%d status=0x%x\n", + ret_val, hw->aq.asq_last_status); + + return errno; +} + static void i40e_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { @@ -2094,6 +2150,7 @@ static const struct ethtool_ops i40e_ethtool_ops = { .get_link = ethtool_op_get_link, .get_wol = i40e_get_wol, .set_wol = i40e_set_wol, + .set_eeprom = i40e_set_eeprom, .get_eeprom_len = i40e_get_eeprom_len, .get_eeprom = i40e_get_eeprom, .get_ringparam = i40e_get_ringparam, diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index 66bcb15422da..97bda3dffd49 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c @@ -240,6 +240,46 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, return ret_code; } +/** + * i40e_write_nvm_aq - Writes Shadow RAM. + * @hw: pointer to the HW structure. + * @module_pointer: module pointer location in words from the NVM beginning + * @offset: offset in words from module start + * @words: number of words to write + * @data: buffer with words to write to the Shadow RAM + * @last_command: tells the AdminQ that this is the last command + * + * Writes a 16 bit words buffer to the Shadow RAM using the admin command. + **/ +i40e_status i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer, + u32 offset, u16 words, void *data, + bool last_command) +{ + i40e_status ret_code = I40E_ERR_NVM; + + /* Here we are checking the SR limit only for the flat memory model. + * We cannot do it for the module-based model, as we did not acquire + * the NVM resource yet (we cannot get the module pointer value). + * Firmware will check the module-based model. + */ + if ((offset + words) > hw->nvm.sr_size) + hw_dbg(hw, "NVM write error: offset beyond Shadow RAM limit.\n"); + else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS) + /* We can write only up to 4KB (one sector), in one AQ write */ + hw_dbg(hw, "NVM write fail error: cannot write more than 4KB in a single write.\n"); + else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS) + != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS)) + /* A single write cannot spread over two sectors */ + hw_dbg(hw, "NVM write error: cannot spread over two sectors in a single write.\n"); + else + ret_code = i40e_aq_update_nvm(hw, module_pointer, + 2 * offset, /*bytes*/ + 2 * words, /*bytes*/ + data, last_command, NULL); + + return ret_code; +} + /** * i40e_calc_nvm_checksum - Calculates and returns the checksum * @hw: pointer to hardware structure @@ -309,6 +349,27 @@ i40e_calc_nvm_checksum_exit: return ret_code; } +/** + * i40e_update_nvm_checksum - Updates the NVM checksum + * @hw: pointer to hardware structure + * + * NVM ownership must be acquired before calling this function and released + * on ARQ completion event reception by caller. + * This function will commit SR to NVM. + **/ +i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw) +{ + i40e_status ret_code = 0; + u16 checksum; + + ret_code = i40e_calc_nvm_checksum(hw, &checksum); + if (!ret_code) + ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD, + 1, &checksum, true); + + return ret_code; +} + /** * i40e_validate_nvm_checksum - Validate EEPROM checksum * @hw: pointer to hardware structure @@ -346,3 +407,453 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, i40e_validate_nvm_checksum_exit: return ret_code; } + +static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + u8 *bytes, int *errno); +static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + u8 *bytes, int *errno); +static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + u8 *bytes, int *errno); +static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + int *errno); +static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + int *errno); +static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + u8 *bytes, int *errno); +static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + u8 *bytes, int *errno); +static inline u8 i40e_nvmupd_get_module(u32 val) +{ + return (u8)(val & I40E_NVM_MOD_PNT_MASK); +} +static inline u8 i40e_nvmupd_get_transaction(u32 val) +{ + return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT); +} + +/** + * i40e_nvmupd_command - Process an NVM update command + * @hw: pointer to hardware structure + * @cmd: pointer to nvm update command + * @bytes: pointer to the data buffer + * @errno: pointer to return error code + * + * Dispatches command depending on what update state is current + **/ +i40e_status i40e_nvmupd_command(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + u8 *bytes, int *errno) +{ + i40e_status status; + + /* assume success */ + *errno = 0; + + switch (hw->nvmupd_state) { + case I40E_NVMUPD_STATE_INIT: + status = i40e_nvmupd_state_init(hw, cmd, bytes, errno); + break; + + case I40E_NVMUPD_STATE_READING: + status = i40e_nvmupd_state_reading(hw, cmd, bytes, errno); + break; + + case I40E_NVMUPD_STATE_WRITING: + status = i40e_nvmupd_state_writing(hw, cmd, bytes, errno); + break; + + default: + /* invalid state, should never happen */ + status = I40E_NOT_SUPPORTED; + *errno = -ESRCH; + break; + } + return status; +} + +/** + * i40e_nvmupd_state_init - Handle NVM update state Init + * @hw: pointer to hardware structure + * @cmd: pointer to nvm update command buffer + * @bytes: pointer to the data buffer + * @errno: pointer to return error code + * + * Process legitimate commands of the Init state and conditionally set next + * state. Reject all other commands. + **/ +static i40e_status i40e_nvmupd_state_init(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + u8 *bytes, int *errno) +{ + i40e_status status = 0; + enum i40e_nvmupd_cmd upd_cmd; + + upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno); + + switch (upd_cmd) { + case I40E_NVMUPD_READ_SA: + status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); + if (status) { + *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); + } else { + status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); + i40e_release_nvm(hw); + } + break; + + case I40E_NVMUPD_READ_SNT: + status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); + if (status) { + *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); + } else { + status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); + hw->nvmupd_state = I40E_NVMUPD_STATE_READING; + } + break; + + case I40E_NVMUPD_WRITE_ERA: + status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); + if (status) { + *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); + } else { + status = i40e_nvmupd_nvm_erase(hw, cmd, errno); + if (status) + i40e_release_nvm(hw); + else + hw->aq.nvm_release_on_done = true; + } + break; + + case I40E_NVMUPD_WRITE_SA: + status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); + if (status) { + *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); + } else { + status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); + if (status) + i40e_release_nvm(hw); + else + hw->aq.nvm_release_on_done = true; + } + break; + + case I40E_NVMUPD_WRITE_SNT: + status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); + if (status) { + *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); + } else { + status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); + hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING; + } + break; + + case I40E_NVMUPD_CSUM_SA: + status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE); + if (status) { + *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); + } else { + status = i40e_update_nvm_checksum(hw); + if (status) { + *errno = hw->aq.asq_last_status ? + i40e_aq_rc_to_posix(hw->aq.asq_last_status) : + -EIO; + i40e_release_nvm(hw); + } else { + hw->aq.nvm_release_on_done = true; + } + } + break; + + default: + status = I40E_ERR_NVM; + *errno = -ESRCH; + break; + } + return status; +} + +/** + * i40e_nvmupd_state_reading - Handle NVM update state Reading + * @hw: pointer to hardware structure + * @cmd: pointer to nvm update command buffer + * @bytes: pointer to the data buffer + * @errno: pointer to return error code + * + * NVM ownership is already held. Process legitimate commands and set any + * change in state; reject all other commands. + **/ +static i40e_status i40e_nvmupd_state_reading(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + u8 *bytes, int *errno) +{ + i40e_status status; + enum i40e_nvmupd_cmd upd_cmd; + + upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno); + + switch (upd_cmd) { + case I40E_NVMUPD_READ_SA: + case I40E_NVMUPD_READ_CON: + status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); + break; + + case I40E_NVMUPD_READ_LCB: + status = i40e_nvmupd_nvm_read(hw, cmd, bytes, errno); + i40e_release_nvm(hw); + hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; + break; + + default: + status = I40E_NOT_SUPPORTED; + *errno = -ESRCH; + break; + } + return status; +} + +/** + * i40e_nvmupd_state_writing - Handle NVM update state Writing + * @hw: pointer to hardware structure + * @cmd: pointer to nvm update command buffer + * @bytes: pointer to the data buffer + * @errno: pointer to return error code + * + * NVM ownership is already held. Process legitimate commands and set any + * change in state; reject all other commands + **/ +static i40e_status i40e_nvmupd_state_writing(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + u8 *bytes, int *errno) +{ + i40e_status status; + enum i40e_nvmupd_cmd upd_cmd; + + upd_cmd = i40e_nvmupd_validate_command(hw, cmd, errno); + + switch (upd_cmd) { + case I40E_NVMUPD_WRITE_CON: + status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); + break; + + case I40E_NVMUPD_WRITE_LCB: + status = i40e_nvmupd_nvm_write(hw, cmd, bytes, errno); + if (!status) { + hw->aq.nvm_release_on_done = true; + hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; + } + break; + + case I40E_NVMUPD_CSUM_CON: + status = i40e_update_nvm_checksum(hw); + if (status) + *errno = hw->aq.asq_last_status ? + i40e_aq_rc_to_posix(hw->aq.asq_last_status) : + -EIO; + break; + + case I40E_NVMUPD_CSUM_LCB: + status = i40e_update_nvm_checksum(hw); + if (status) { + *errno = hw->aq.asq_last_status ? + i40e_aq_rc_to_posix(hw->aq.asq_last_status) : + -EIO; + } else { + hw->aq.nvm_release_on_done = true; + hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; + } + break; + + default: + status = I40E_NOT_SUPPORTED; + *errno = -ESRCH; + break; + } + return status; +} + +/** + * i40e_nvmupd_validate_command - Validate given command + * @hw: pointer to hardware structure + * @cmd: pointer to nvm update command buffer + * @errno: pointer to return error code + * + * Return one of the valid command types or I40E_NVMUPD_INVALID + **/ +static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + int *errno) +{ + enum i40e_nvmupd_cmd upd_cmd; + u8 transaction, module; + + /* anything that doesn't match a recognized case is an error */ + upd_cmd = I40E_NVMUPD_INVALID; + + transaction = i40e_nvmupd_get_transaction(cmd->config); + module = i40e_nvmupd_get_module(cmd->config); + + /* limits on data size */ + if ((cmd->data_size < 1) || + (cmd->data_size > I40E_NVMUPD_MAX_DATA)) { + hw_dbg(hw, "i40e_nvmupd_validate_command data_size %d\n", + cmd->data_size); + *errno = -EFAULT; + return I40E_NVMUPD_INVALID; + } + + switch (cmd->command) { + case I40E_NVM_READ: + switch (transaction) { + case I40E_NVM_CON: + upd_cmd = I40E_NVMUPD_READ_CON; + break; + case I40E_NVM_SNT: + upd_cmd = I40E_NVMUPD_READ_SNT; + break; + case I40E_NVM_LCB: + upd_cmd = I40E_NVMUPD_READ_LCB; + break; + case I40E_NVM_SA: + upd_cmd = I40E_NVMUPD_READ_SA; + break; + } + break; + + case I40E_NVM_WRITE: + switch (transaction) { + case I40E_NVM_CON: + upd_cmd = I40E_NVMUPD_WRITE_CON; + break; + case I40E_NVM_SNT: + upd_cmd = I40E_NVMUPD_WRITE_SNT; + break; + case I40E_NVM_LCB: + upd_cmd = I40E_NVMUPD_WRITE_LCB; + break; + case I40E_NVM_SA: + upd_cmd = I40E_NVMUPD_WRITE_SA; + break; + case I40E_NVM_ERA: + upd_cmd = I40E_NVMUPD_WRITE_ERA; + break; + case I40E_NVM_CSUM: + upd_cmd = I40E_NVMUPD_CSUM_CON; + break; + case (I40E_NVM_CSUM|I40E_NVM_SA): + upd_cmd = I40E_NVMUPD_CSUM_SA; + break; + case (I40E_NVM_CSUM|I40E_NVM_LCB): + upd_cmd = I40E_NVMUPD_CSUM_LCB; + break; + } + break; + } + + if (upd_cmd == I40E_NVMUPD_INVALID) { + *errno = -EFAULT; + hw_dbg(hw, + "i40e_nvmupd_validate_command returns %d errno: %d\n", + upd_cmd, *errno); + } + return upd_cmd; +} + +/** + * i40e_nvmupd_nvm_read - Read NVM + * @hw: pointer to hardware structure + * @cmd: pointer to nvm update command buffer + * @bytes: pointer to the data buffer + * @errno: pointer to return error code + * + * cmd structure contains identifiers and data buffer + **/ +static i40e_status i40e_nvmupd_nvm_read(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + u8 *bytes, int *errno) +{ + i40e_status status; + u8 module, transaction; + bool last; + + transaction = i40e_nvmupd_get_transaction(cmd->config); + module = i40e_nvmupd_get_module(cmd->config); + last = (transaction == I40E_NVM_LCB) || (transaction == I40E_NVM_SA); + hw_dbg(hw, "i40e_nvmupd_nvm_read mod 0x%x off 0x%x len 0x%x\n", + module, cmd->offset, cmd->data_size); + + status = i40e_aq_read_nvm(hw, module, cmd->offset, (u16)cmd->data_size, + bytes, last, NULL); + hw_dbg(hw, "i40e_nvmupd_nvm_read status %d\n", status); + if (status) + *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); + + return status; +} + +/** + * i40e_nvmupd_nvm_erase - Erase an NVM module + * @hw: pointer to hardware structure + * @cmd: pointer to nvm update command buffer + * @errno: pointer to return error code + * + * module, offset, data_size and data are in cmd structure + **/ +static i40e_status i40e_nvmupd_nvm_erase(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + int *errno) +{ + i40e_status status = 0; + u8 module, transaction; + bool last; + + transaction = i40e_nvmupd_get_transaction(cmd->config); + module = i40e_nvmupd_get_module(cmd->config); + last = (transaction & I40E_NVM_LCB); + hw_dbg(hw, "i40e_nvmupd_nvm_erase mod 0x%x off 0x%x len 0x%x\n", + module, cmd->offset, cmd->data_size); + status = i40e_aq_erase_nvm(hw, module, cmd->offset, (u16)cmd->data_size, + last, NULL); + hw_dbg(hw, "i40e_nvmupd_nvm_erase status %d\n", status); + if (status) + *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); + + return status; +} + +/** + * i40e_nvmupd_nvm_write - Write NVM + * @hw: pointer to hardware structure + * @cmd: pointer to nvm update command buffer + * @bytes: pointer to the data buffer + * @errno: pointer to return error code + * + * module, offset, data_size and data are in cmd structure + **/ +static i40e_status i40e_nvmupd_nvm_write(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + u8 *bytes, int *errno) +{ + i40e_status status = 0; + u8 module, transaction; + bool last; + + transaction = i40e_nvmupd_get_transaction(cmd->config); + module = i40e_nvmupd_get_module(cmd->config); + last = (transaction & I40E_NVM_LCB); + hw_dbg(hw, "i40e_nvmupd_nvm_write mod 0x%x off 0x%x len 0x%x\n", + module, cmd->offset, cmd->data_size); + status = i40e_aq_update_nvm(hw, module, cmd->offset, + (u16)cmd->data_size, bytes, last, NULL); + hw_dbg(hw, "i40e_nvmupd_nvm_write status %d\n", status); + if (status) + *errno = i40e_aq_rc_to_posix(hw->aq.asq_last_status); + + return status; +} diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 9383f08ff4e3..a91d7e1a5b5b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -150,6 +150,9 @@ i40e_status i40e_aq_read_nvm(struct i40e_hw *hw, u8 module_pointer, u32 offset, u16 length, void *data, bool last_command, struct i40e_asq_cmd_details *cmd_details); +i40e_status i40e_aq_erase_nvm(struct i40e_hw *hw, u8 module_pointer, + u32 offset, u16 length, bool last_command, + struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_discover_capabilities(struct i40e_hw *hw, void *buff, u16 buff_size, u16 *data_size, enum i40e_admin_queue_opc list_type_opc, @@ -245,8 +248,12 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, u16 *data); i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, u16 *words, u16 *data); +i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw); i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, u16 *checksum); +i40e_status i40e_nvmupd_command(struct i40e_hw *hw, + struct i40e_nvm_access *cmd, + u8 *bytes, int *); void i40e_set_pci_config_data(struct i40e_hw *hw, u16 link_status); extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[]; diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 1fcf2205ffe6..8bb9049191cb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -269,6 +269,61 @@ struct i40e_nvm_info { u32 eetrack; /* NVM data version */ }; +/* definitions used in NVM update support */ + +enum i40e_nvmupd_cmd { + I40E_NVMUPD_INVALID, + I40E_NVMUPD_READ_CON, + I40E_NVMUPD_READ_SNT, + I40E_NVMUPD_READ_LCB, + I40E_NVMUPD_READ_SA, + I40E_NVMUPD_WRITE_ERA, + I40E_NVMUPD_WRITE_CON, + I40E_NVMUPD_WRITE_SNT, + I40E_NVMUPD_WRITE_LCB, + I40E_NVMUPD_WRITE_SA, + I40E_NVMUPD_CSUM_CON, + I40E_NVMUPD_CSUM_SA, + I40E_NVMUPD_CSUM_LCB, +}; + +enum i40e_nvmupd_state { + I40E_NVMUPD_STATE_INIT, + I40E_NVMUPD_STATE_READING, + I40E_NVMUPD_STATE_WRITING +}; + +/* nvm_access definition and its masks/shifts need to be accessible to + * application, core driver, and shared code. Where is the right file? + */ +#define I40E_NVM_READ 0xB +#define I40E_NVM_WRITE 0xC + +#define I40E_NVM_MOD_PNT_MASK 0xFF + +#define I40E_NVM_TRANS_SHIFT 8 +#define I40E_NVM_TRANS_MASK (0xf << I40E_NVM_TRANS_SHIFT) +#define I40E_NVM_CON 0x0 +#define I40E_NVM_SNT 0x1 +#define I40E_NVM_LCB 0x2 +#define I40E_NVM_SA (I40E_NVM_SNT | I40E_NVM_LCB) +#define I40E_NVM_ERA 0x4 +#define I40E_NVM_CSUM 0x8 + +#define I40E_NVM_ADAPT_SHIFT 16 +#define I40E_NVM_ADAPT_MASK (0xffff << I40E_NVM_ADAPT_SHIFT) + +#define I40E_NVMUPD_MAX_DATA 4096 +#define I40E_NVMUPD_IFACE_TIMEOUT 2 /* seconds */ + +struct i40e_nvm_access { + u32 command; + u32 config; + u32 offset; /* in bytes */ + u32 data_size; /* in bytes */ + u8 data[1]; +}; + /* PCI bus types */ enum i40e_bus_type { i40e_bus_type_unknown = 0, @@ -404,6 +459,9 @@ struct i40e_hw { /* Admin Queue info */ struct i40e_adminq_info aq; + /* state of nvm update process */ + enum i40e_nvmupd_state nvmupd_state; + /* HMC info */ struct i40e_hmc_info hmc; /* HMC info struct */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index 8330744b02f1..ee3a934043bb 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -708,12 +708,6 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, goto asq_send_command_exit; } - if (i40e_is_nvm_update_op(desc) && hw->aq.nvm_busy) { - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: NVM busy.\n"); - status = I40E_ERR_NVM; - goto asq_send_command_exit; - } - details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use); if (cmd_details) { *details = *cmd_details; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h index 162845589bf7..91a5c5bd80f3 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h @@ -94,6 +94,7 @@ struct i40e_adminq_info { u16 api_maj_ver; /* api major version */ u16 api_min_ver; /* api minor version */ bool nvm_busy; + bool nvm_release_on_done; struct mutex asq_mutex; /* Send queue lock */ struct mutex arq_mutex; /* Receive queue lock */ @@ -103,6 +104,41 @@ struct i40e_adminq_info { enum i40e_admin_queue_err arq_last_status; }; +/** + * i40e_aq_rc_to_posix - convert errors to user-land codes + * aq_rc: AdminQ error code to convert + **/ +static inline int i40e_aq_rc_to_posix(u16 aq_rc) +{ + int aq_to_posix[] = { + 0, /* I40E_AQ_RC_OK */ + -EPERM, /* I40E_AQ_RC_EPERM */ + -ENOENT, /* I40E_AQ_RC_ENOENT */ + -ESRCH, /* I40E_AQ_RC_ESRCH */ + -EINTR, /* I40E_AQ_RC_EINTR */ + -EIO, /* I40E_AQ_RC_EIO */ + -ENXIO, /* I40E_AQ_RC_ENXIO */ + -E2BIG, /* I40E_AQ_RC_E2BIG */ + -EAGAIN, /* I40E_AQ_RC_EAGAIN */ + -ENOMEM, /* I40E_AQ_RC_ENOMEM */ + -EACCES, /* I40E_AQ_RC_EACCES */ + -EFAULT, /* I40E_AQ_RC_EFAULT */ + -EBUSY, /* I40E_AQ_RC_EBUSY */ + -EEXIST, /* I40E_AQ_RC_EEXIST */ + -EINVAL, /* I40E_AQ_RC_EINVAL */ + -ENOTTY, /* I40E_AQ_RC_ENOTTY */ + -ENOSPC, /* I40E_AQ_RC_ENOSPC */ + -ENOSYS, /* I40E_AQ_RC_ENOSYS */ + -ERANGE, /* I40E_AQ_RC_ERANGE */ + -EPIPE, /* I40E_AQ_RC_EFLUSHED */ + -ESPIPE, /* I40E_AQ_RC_BAD_ADDR */ + -EROFS, /* I40E_AQ_RC_EMODE */ + -EFBIG, /* I40E_AQ_RC_EFBIG */ + }; + + return aq_to_posix[aq_rc]; +} + /* general information */ #define I40E_AQ_LARGE_BUF 512 #define I40E_ASQ_CMD_TIMEOUT 100000 /* usecs */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 6dd72ad58e7d..15376436cead 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -268,6 +268,61 @@ struct i40e_nvm_info { u32 eetrack; /* NVM data version */ }; +/* definitions used in NVM update support */ + +enum i40e_nvmupd_cmd { + I40E_NVMUPD_INVALID, + I40E_NVMUPD_READ_CON, + I40E_NVMUPD_READ_SNT, + I40E_NVMUPD_READ_LCB, + I40E_NVMUPD_READ_SA, + I40E_NVMUPD_WRITE_ERA, + I40E_NVMUPD_WRITE_CON, + I40E_NVMUPD_WRITE_SNT, + I40E_NVMUPD_WRITE_LCB, + I40E_NVMUPD_WRITE_SA, + I40E_NVMUPD_CSUM_CON, + I40E_NVMUPD_CSUM_SA, + I40E_NVMUPD_CSUM_LCB, +}; + +enum i40e_nvmupd_state { + I40E_NVMUPD_STATE_INIT, + I40E_NVMUPD_STATE_READING, + I40E_NVMUPD_STATE_WRITING +}; + +/* nvm_access definition and its masks/shifts need to be accessible to + * application, core driver, and shared code. Where is the right file? + */ +#define I40E_NVM_READ 0xB +#define I40E_NVM_WRITE 0xC + +#define I40E_NVM_MOD_PNT_MASK 0xFF + +#define I40E_NVM_TRANS_SHIFT 8 +#define I40E_NVM_TRANS_MASK (0xf << I40E_NVM_TRANS_SHIFT) +#define I40E_NVM_CON 0x0 +#define I40E_NVM_SNT 0x1 +#define I40E_NVM_LCB 0x2 +#define I40E_NVM_SA (I40E_NVM_SNT | I40E_NVM_LCB) +#define I40E_NVM_ERA 0x4 +#define I40E_NVM_CSUM 0x8 + +#define I40E_NVM_ADAPT_SHIFT 16 +#define I40E_NVM_ADAPT_MASK (0xffff << I40E_NVM_ADAPT_SHIFT) + +#define I40E_NVMUPD_MAX_DATA 4096 +#define I40E_NVMUPD_IFACE_TIMEOUT 2 /* seconds */ + +struct i40e_nvm_access { + u32 command; + u32 config; + u32 offset; /* in bytes */ + u32 data_size; /* in bytes */ + u8 data[1]; +}; + /* PCI bus types */ enum i40e_bus_type { i40e_bus_type_unknown = 0, @@ -403,6 +458,9 @@ struct i40e_hw { /* Admin Queue info */ struct i40e_adminq_info aq; + /* state of nvm update process */ + enum i40e_nvmupd_state nvmupd_state; + /* HMC info */ struct i40e_hmc_info hmc; /* HMC info struct */ -- cgit v1.2.3 From 22d2fa1d31b74c0f18f09b11331336ca53dbb1ec Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 9 Jul 2014 07:46:13 +0000 Subject: i40e/i40evf: fix extension header csum logic The hardware design requires that the driver avoid indicating checksum offload success on some ipv6 frames with extension headers. The code needs to just check for the IPV6EXADD bit and if it is set punt the checksum to the stack. I don't know why the code was checking TCP on inner protocol, as that code doesn't make any sense to me but seems wrong, so remove it. Change-ID: I10d3aacdbb1819fb60b4b0eb80e6cc67ef2c9599 Signed-off-by: Jesse Brandeburg Tested-By: Jim Young Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 -- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 989866af26e5..d26d6836689d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1237,8 +1237,6 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, /* likely incorrect csum if alternate IP extension headers found */ if (ipv6 && - decoded.inner_prot == I40E_RX_PTYPE_INNER_PROT_TCP && - rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) && rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) /* don't increment checksum err here, non-fatal err */ return; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index b342f212e91f..79bf96ca6489 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -773,8 +773,6 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, /* likely incorrect csum if alternate IP extension headers found */ if (ipv6 && - decoded.inner_prot == I40E_RX_PTYPE_INNER_PROT_TCP && - rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) && rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) /* don't increment checksum err here, non-fatal err */ return; -- cgit v1.2.3 From b65476cd53e074802661f4bdd9bc279b8ab65a23 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 9 Jul 2014 07:46:14 +0000 Subject: i40evf: don't wait so long We really don't need to delay an entire millisecond just to get into our critical section. A microsecond will be sufficient, thank you. Change-ID: I2d02ece6610007d98cabcb3f42df9a774bb54e59 Signed-off-by: Mitch Williams Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index ed1eb1230522..a53e81bb0960 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -768,7 +768,7 @@ i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter, while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) - mdelay(1); + udelay(1); f = i40evf_find_filter(adapter, macaddr); if (NULL == f) { @@ -840,7 +840,7 @@ static void i40evf_set_rx_mode(struct net_device *netdev) while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) - mdelay(1); + udelay(1); /* remove filter if not in netdev list */ list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { bool found = false; -- cgit v1.2.3 From 7bd8490eef9776ced7632345df5133384b6be0fe Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 24 Jul 2014 06:36:50 +0200 Subject: netfilter: xt_hashlimit: perform garbage collection from process context xt_hashlimit cannot be used with large hash tables, because garbage collector is run from a timer. If table is really big, its possible to hold cpu for more than 500 msec, which is unacceptable. Switch to a work queue, and use proper scheduling points to remove latencies spikes. Later, we also could switch to a smoother garbage collection done at lookup time, one bucket at a time... Signed-off-by: Eric Dumazet Cc: Florian Westphal Cc: Patrick McHardy Reviewed-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_hashlimit.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index a3910fc2122b..47dc6836830a 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -104,7 +104,7 @@ struct xt_hashlimit_htable { spinlock_t lock; /* lock for list_head */ u_int32_t rnd; /* random seed for hash */ unsigned int count; /* number entries in table */ - struct timer_list timer; /* timer for gc */ + struct delayed_work gc_work; /* seq_file stuff */ struct proc_dir_entry *pde; @@ -213,7 +213,7 @@ dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent) call_rcu_bh(&ent->rcu, dsthash_free_rcu); ht->count--; } -static void htable_gc(unsigned long htlong); +static void htable_gc(struct work_struct *work); static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, u_int8_t family) @@ -273,9 +273,9 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, } hinfo->net = net; - setup_timer(&hinfo->timer, htable_gc, (unsigned long)hinfo); - hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); - add_timer(&hinfo->timer); + INIT_DEFERRABLE_WORK(&hinfo->gc_work, htable_gc); + queue_delayed_work(system_power_efficient_wq, &hinfo->gc_work, + msecs_to_jiffies(hinfo->cfg.gc_interval)); hlist_add_head(&hinfo->node, &hashlimit_net->htables); @@ -300,29 +300,30 @@ static void htable_selective_cleanup(struct xt_hashlimit_htable *ht, { unsigned int i; - /* lock hash table and iterate over it */ - spin_lock_bh(&ht->lock); for (i = 0; i < ht->cfg.size; i++) { struct dsthash_ent *dh; struct hlist_node *n; + + spin_lock_bh(&ht->lock); hlist_for_each_entry_safe(dh, n, &ht->hash[i], node) { if ((*select)(ht, dh)) dsthash_free(ht, dh); } + spin_unlock_bh(&ht->lock); + cond_resched(); } - spin_unlock_bh(&ht->lock); } -/* hash table garbage collector, run by timer */ -static void htable_gc(unsigned long htlong) +static void htable_gc(struct work_struct *work) { - struct xt_hashlimit_htable *ht = (struct xt_hashlimit_htable *)htlong; + struct xt_hashlimit_htable *ht; + + ht = container_of(work, struct xt_hashlimit_htable, gc_work.work); htable_selective_cleanup(ht, select_gc); - /* re-add the timer accordingly */ - ht->timer.expires = jiffies + msecs_to_jiffies(ht->cfg.gc_interval); - add_timer(&ht->timer); + queue_delayed_work(system_power_efficient_wq, + &ht->gc_work, msecs_to_jiffies(ht->cfg.gc_interval)); } static void htable_remove_proc_entry(struct xt_hashlimit_htable *hinfo) @@ -341,7 +342,7 @@ static void htable_remove_proc_entry(struct xt_hashlimit_htable *hinfo) static void htable_destroy(struct xt_hashlimit_htable *hinfo) { - del_timer_sync(&hinfo->timer); + cancel_delayed_work_sync(&hinfo->gc_work); htable_remove_proc_entry(hinfo); htable_selective_cleanup(hinfo, select_all); kfree(hinfo->name); -- cgit v1.2.3 From 77813d0a9f750f8d5075bcbb59d30417e51ab605 Mon Sep 17 00:00:00 2001 From: Kamil Krawczyk Date: Wed, 9 Jul 2014 07:46:15 +0000 Subject: i40e/i40evf: ARQ copy desc data even for failed commands Copy desc and buffer data even for ARQ events which return error status. Previously, a check for NVM related AQ commands which is done later in this function would not recognize that such a command was received and would not clear nvm_busy flag. This would block access to NVM until a driver reset. This will fix that. Change-ID: If69ad74e165b56081c0686b97402511d2e2880c0 Signed-off-by: Kamil Krawczyk Tested-by: Jim Young Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 14 +++++++------- drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 1e21fbb1359c..c6d767c63f1b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -979,15 +979,15 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: Event received with error 0x%X.\n", hw->aq.arq_last_status); - } else { - e->desc = *desc; - datalen = le16_to_cpu(desc->datalen); - e->msg_size = min(datalen, e->msg_size); - if (e->msg_buf != NULL && (e->msg_size != 0)) - memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va, - e->msg_size); } + e->desc = *desc; + datalen = le16_to_cpu(desc->datalen); + e->msg_size = min(datalen, e->msg_size); + if (e->msg_buf != NULL && (e->msg_size != 0)) + memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va, + e->msg_size); + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n"); i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index ee3a934043bb..3291d2cb2897 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -927,15 +927,15 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: Event received with error 0x%X.\n", hw->aq.arq_last_status); - } else { - e->desc = *desc; - datalen = le16_to_cpu(desc->datalen); - e->msg_size = min(datalen, e->msg_size); - if (e->msg_buf != NULL && (e->msg_size != 0)) - memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va, - e->msg_size); } + e->desc = *desc; + datalen = le16_to_cpu(desc->datalen); + e->msg_size = min(datalen, e->msg_size); + if (e->msg_buf != NULL && (e->msg_size != 0)) + memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va, + e->msg_size); + if (i40e_is_nvm_update_op(&e->desc)) hw->aq.nvm_busy = false; -- cgit v1.2.3 From 7aa67613172734d5d6be99db019e57e453f76862 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 9 Jul 2014 07:46:17 +0000 Subject: i40e: Fix firmware API version errors Reword the error messages. Also add a major version check because We only want to warn on nvm_minor > expected_minor if nvm_major == expected_major. Lastly, change an if to an else if because the two statements will never evaluate to true at the same time. Change-ID: I6ddf9986f26b35f6879cbeac4fcef04a8497a383 Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index c34e39009a8f..821fcc1adb85 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -8642,24 +8642,18 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "%s\n", i40e_fw_version_str(hw)); if (err) { dev_info(&pdev->dev, - "init_adminq failed: %d expecting API %02x.%02x\n", - err, - I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR); + "The driver for the device stopped because the NVM image is newer than expected. You must install the most recent version of the network driver.\n"); goto err_pf_reset; } - if (hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) + if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && + hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) dev_info(&pdev->dev, - "Note: FW API version %02x.%02x newer than expected %02x.%02x, recommend driver update.\n", - hw->aq.api_maj_ver, hw->aq.api_min_ver, - I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR); - - if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || - hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR-1)) + "The driver for the device detected a newer version of the NVM image than expected. Please install the most recent version of the network driver.\n"); + else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || + hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) dev_info(&pdev->dev, - "Note: FW API version %02x.%02x older than expected %02x.%02x, recommend nvm update.\n", - hw->aq.api_maj_ver, hw->aq.api_min_ver, - I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR); + "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n"); i40e_verify_eeprom(pf); -- cgit v1.2.3 From 7d62dac6312efa7824eb59d8161aee8fef1c166c Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 9 Jul 2014 07:46:18 +0000 Subject: i40e: Give link more time after setting flow control Give link a little more time to come back up after setting flow control before resetting. In the new NVMs it is taking longer for link to come back. This causes the driver to attempt to reset the link, which then errors because the firmware was already in the middle of a reset. Also, initialize err to 0. Change-ID: I1cc987a944e389d8909c262da5796f50722b4d6b Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index f1d241ec1fc3..9c93ff28d4aa 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -630,7 +630,7 @@ static int i40e_set_pauseparam(struct net_device *netdev, bool link_up = hw_link_info->link_info & I40E_AQ_LINK_UP; i40e_status status; u8 aq_failures; - int err; + int err = 0; if (vsi != pf->vsi[pf->lan_vsi]) return -EOPNOTSUPP; @@ -683,8 +683,12 @@ static int i40e_set_pauseparam(struct net_device *netdev, err = -EAGAIN; } - if (!test_bit(__I40E_DOWN, &pf->state)) - return i40e_nway_reset(netdev); + if (!test_bit(__I40E_DOWN, &pf->state)) { + /* Give it a little more time to try to come back */ + msleep(75); + if (!test_bit(__I40E_DOWN, &pf->state)) + return i40e_nway_reset(netdev); + } return err; } -- cgit v1.2.3 From e3effd736a72a3df0e00f002c4dbf1da7641d115 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 9 Jul 2014 07:46:19 +0000 Subject: i40e: always print aqtx answer Sometimes the AQTX answer comes back with no data, but we still want to print the descriptor that got written back. Change-ID: I5f734d99b4c95510987413893f0a34626571d474 Signed-off-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 8 +++----- drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index c6d767c63f1b..b29c157b1f57 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -889,11 +889,9 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; } - if (le16_to_cpu(desc->datalen) == buff_size) { - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, - "AQTX: desc and buffer writeback:\n"); - i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff); - } + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "AQTX: desc and buffer writeback:\n"); + i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff); /* update the error if time out occurred */ if ((!cmd_completed) && diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index 3291d2cb2897..003006033614 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -840,11 +840,9 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, if (i40e_is_nvm_update_op(desc)) hw->aq.nvm_busy = true; - if (le16_to_cpu(desc->datalen) == buff_size) { - i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, - "AQTX: desc and buffer writeback:\n"); - i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff); - } + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "AQTX: desc and buffer writeback:\n"); + i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff); /* update the error if time out occurred */ if ((!cmd_completed) && -- cgit v1.2.3 From f53e38317d581399eb67809d6b6b6c2c107db50c Mon Sep 17 00:00:00 2001 From: Andy Zhou Date: Thu, 17 Jul 2014 15:17:44 -0700 Subject: openvswitch: Avoid memory corruption in queue_userspace_packet() In queue_userspace_packet(), the ovs_nla_put_flow return value is not checked. This is fine as long as key_attr_size() returns the correct value. In case it does not, the current code may corrupt buffer memory. Add a run time assertion catch this case to avoid silent failure. Reported-by: Ben Pfaff Signed-off-by: Andy Zhou Signed-off-by: Pravin B Shelar --- net/openvswitch/datapath.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 65a8e5c089e4..3c461e1e4554 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -464,7 +464,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, upcall->dp_ifindex = dp_ifindex; nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); - ovs_nla_put_flow(upcall_info->key, upcall_info->key, user_skb); + err = ovs_nla_put_flow(upcall_info->key, upcall_info->key, user_skb); + BUG_ON(err); nla_nest_end(user_skb, nla); if (upcall_info->userdata) -- cgit v1.2.3 From 651887b0c22cffcfce7eb9c29ee23ffb105bdb0b Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 21 Jul 2014 15:12:34 -0700 Subject: openvswitch: Sample action without side effects The sample action is rather generic, allowing arbitrary actions to be executed based on a probability. However its use, within the Open vSwitch code-base is limited: only a single user-space action is ever nested. A consequence of the current implementation of sample actions is that depending on weather the sample action executed (due to its probability) any side-effects of nested actions may or may not be present before executing subsequent actions. This has the potential to complicate verification of valid actions by the (kernel) datapath. And indeed adding support for push and pop MPLS actions inside sample actions is one case where such case. In order to allow all supported actions to be continue to be nested inside sample actions without the potential need for complex verification code this patch changes the implementation of the sample action in the kernel datapath so that sample actions are more like a function call and any side effects of nested actions are not present when executing subsequent actions. With the above in mind the motivation for this change is twofold: * To contain side-effects the sample action in the hope of making it easier to deal with in the future and; * To avoid some rather complex verification code introduced in the MPLS datapath patch. Signed-off-by: Simon Horman Signed-off-by: Jesse Gross Signed-off-by: Pravin B Shelar --- net/openvswitch/actions.c | 48 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index e70d8b18e962..794a96f6b8d9 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -38,7 +38,7 @@ #include "vport.h" static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, - const struct nlattr *attr, int len, bool keep_skb); + const struct nlattr *attr, int len); static int make_writable(struct sk_buff *skb, int write_len) { @@ -434,11 +434,17 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, return ovs_dp_upcall(dp, skb, &upcall); } +static bool last_action(const struct nlattr *a, int rem) +{ + return a->nla_len == rem; +} + static int sample(struct datapath *dp, struct sk_buff *skb, const struct nlattr *attr) { const struct nlattr *acts_list = NULL; const struct nlattr *a; + struct sk_buff *sample_skb; int rem; for (a = nla_data(attr), rem = nla_len(attr); rem > 0; @@ -455,8 +461,32 @@ static int sample(struct datapath *dp, struct sk_buff *skb, } } - return do_execute_actions(dp, skb, nla_data(acts_list), - nla_len(acts_list), true); + rem = nla_len(acts_list); + a = nla_data(acts_list); + + /* Actions list is either empty or only contains a single user-space + * action, the latter being a special case as it is the only known + * usage of the sample action. + * In these special cases don't clone the skb as there are no + * side-effects in the nested actions. + * Otherwise, clone in case the nested actions have side effects. + */ + if (likely(rem == 0 || (nla_type(a) == OVS_ACTION_ATTR_USERSPACE && + last_action(a, rem)))) { + sample_skb = skb; + skb_get(skb); + } else { + sample_skb = skb_clone(skb, GFP_ATOMIC); + } + + /* Note that do_execute_actions() never consumes skb. + * In the case where skb has been cloned above it is the clone that + * is consumed. Otherwise the skb_get(skb) call prevents + * consumption by do_execute_actions(). Thus, it is safe to simply + * return the error code and let the caller (also + * do_execute_actions()) free skb on error. + */ + return do_execute_actions(dp, sample_skb, a, rem); } static int execute_set_action(struct sk_buff *skb, @@ -507,7 +537,7 @@ static int execute_set_action(struct sk_buff *skb, /* Execute a list of actions against 'skb'. */ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, - const struct nlattr *attr, int len, bool keep_skb) + const struct nlattr *attr, int len) { /* Every output action needs a separate clone of 'skb', but the common * case is just a single output action, so that doing a clone and @@ -562,12 +592,9 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, } } - if (prev_port != -1) { - if (keep_skb) - skb = skb_clone(skb, GFP_ATOMIC); - + if (prev_port != -1) do_output(dp, skb, prev_port); - } else if (!keep_skb) + else consume_skb(skb); return 0; @@ -579,6 +606,5 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb) struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); OVS_CB(skb)->tun_key = NULL; - return do_execute_actions(dp, skb, acts->actions, - acts->actions_len, false); + return do_execute_actions(dp, skb, acts->actions, acts->actions_len); } -- cgit v1.2.3 From d9e0ecb81417c34ef8c02a6880d23c362300cda0 Mon Sep 17 00:00:00 2001 From: Andy Zhou Date: Thu, 17 Jul 2014 15:17:54 -0700 Subject: openvswitch: Add skb_clone NULL check for the sampling action. Fix a bug where skb_clone() NULL check is missing in sample action implementation. Signed-off-by: Andy Zhou Signed-off-by: Pravin B Shelar --- net/openvswitch/actions.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 794a96f6b8d9..fe5cda0deb39 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -477,6 +477,8 @@ static int sample(struct datapath *dp, struct sk_buff *skb, skb_get(skb); } else { sample_skb = skb_clone(skb, GFP_ATOMIC); + if (!sample_skb) /* Skip sample action when out of memory. */ + return 0; } /* Note that do_execute_actions() never consumes skb. -- cgit v1.2.3 From 179542a548f37e1366f7afb7a088c965a2adf7d0 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 25 Jul 2014 01:48:44 +0530 Subject: igmp: remove exceptional & on function name In this file, function names are otherwise used as pointers without &. A simplified version of the Coccinelle semantic patch that makes this change is as follows: // @r@ identifier f; @@ f(...) { ... } @@ identifier r.f; @@ - &f + f // Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- net/ipv4/igmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index db710b059bab..f10eab462282 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1321,7 +1321,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) atomic_set(&im->refcnt, 1); spin_lock_init(&im->lock); #ifdef CONFIG_IP_MULTICAST - setup_timer(&im->timer, &igmp_timer_expire, (unsigned long)im); + setup_timer(&im->timer, igmp_timer_expire, (unsigned long)im); im->unsolicit_count = IGMP_Unsolicited_Report_Count; #endif -- cgit v1.2.3 From 56ec0fb10c9f8b35a2991871ea879840d1a0cbde Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 25 Jul 2014 01:49:37 +0530 Subject: neigh: remove exceptional & on function name In this file, function names are otherwise used as pointers without &. A simplified version of the Coccinelle semantic patch that makes this change is as follows: // @r@ identifier f; @@ f(...) { ... } @@ identifier r.f; @@ - &f + f // Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index b7ece278dd49..339078f95d1b 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1768,7 +1768,7 @@ int __init ndisc_init(void) #ifdef CONFIG_SYSCTL err = neigh_sysctl_register(NULL, &nd_tbl.parms, - &ndisc_ifinfo_sysctl_change); + ndisc_ifinfo_sysctl_change); if (err) goto out_unregister_pernet; out: -- cgit v1.2.3 From e40f5c72347d535352b6631850a26b23a7f11eca Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 25 Jul 2014 01:50:41 +0530 Subject: net_sched: remove exceptional & on function name In this file, function names are otherwise used as pointers without &. A simplified version of the Coccinelle semantic patch that makes this change is as follows: // @r@ identifier f; @@ f(...) { ... } @@ identifier r.f; @@ - &f + f // Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- net/sched/cls_tcindex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index c721cd4a469f..3e9f76413b3b 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -420,7 +420,7 @@ static void tcindex_destroy(struct tcf_proto *tp) pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p); walker.count = 0; walker.skip = 0; - walker.fn = &tcindex_destroy_element; + walker.fn = tcindex_destroy_element; tcindex_walk(tp, &walker); kfree(p->perfect); kfree(p->h); -- cgit v1.2.3 From dd66d386552ad3687530c1bd0e001e96a060cc0f Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 24 Jul 2014 18:24:01 -0300 Subject: fec: Simplify the PM related hooks Get rid of the CONFIG_PM_SLEEP ifdef by annotating the suspend/resume functions with '__maybe_unused' in order to keep the code simpler and shorter. While at it, declare the suspend/resume functions in a single line. Signed-off-by: Fabio Estevam Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index e0efb212223f..66fe1f672499 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2696,9 +2696,7 @@ fec_drv_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int -fec_suspend(struct device *dev) +static int __maybe_unused fec_suspend(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct fec_enet_private *fep = netdev_priv(ndev); @@ -2723,8 +2721,7 @@ fec_suspend(struct device *dev) return 0; } -static int -fec_resume(struct device *dev) +static int __maybe_unused fec_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct fec_enet_private *fep = netdev_priv(ndev); @@ -2759,7 +2756,6 @@ failed_clk: regulator_disable(fep->reg_phy); return ret; } -#endif /* CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(fec_pm_ops, fec_suspend, fec_resume); -- cgit v1.2.3 From 2695fb552cbef1029aa025a98acb80cc51d66de5 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Thu, 24 Jul 2014 16:38:21 -0700 Subject: net: filter: rename 'struct sock_filter_int' into 'struct bpf_insn' eBPF is used by socket filtering, seccomp and soon by tracing and exposed to userspace, therefore 'sock_filter_int' name is not accurate. Rename it to 'bpf_insn' Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- arch/x86/net/bpf_jit_comp.c | 2 +- include/linux/filter.h | 50 ++++++++++++++++++++++----------------------- kernel/bpf/core.c | 2 +- kernel/seccomp.c | 2 +- lib/test_bpf.c | 4 ++-- net/core/filter.c | 18 ++++++++-------- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 99bef86ed6df..71737a83f022 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -214,7 +214,7 @@ struct jit_context { static int do_jit(struct sk_filter *bpf_prog, int *addrs, u8 *image, int oldproglen, struct jit_context *ctx) { - struct sock_filter_int *insn = bpf_prog->insnsi; + struct bpf_insn *insn = bpf_prog->insnsi; int insn_cnt = bpf_prog->len; u8 temp[64]; int i; diff --git a/include/linux/filter.h b/include/linux/filter.h index c43c8258e682..20dd50ef7271 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -82,7 +82,7 @@ enum { /* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */ #define BPF_ALU64_REG(OP, DST, SRC) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \ .dst_reg = DST, \ .src_reg = SRC, \ @@ -90,7 +90,7 @@ enum { .imm = 0 }) #define BPF_ALU32_REG(OP, DST, SRC) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_ALU | BPF_OP(OP) | BPF_X, \ .dst_reg = DST, \ .src_reg = SRC, \ @@ -100,7 +100,7 @@ enum { /* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */ #define BPF_ALU64_IMM(OP, DST, IMM) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ .dst_reg = DST, \ .src_reg = 0, \ @@ -108,7 +108,7 @@ enum { .imm = IMM }) #define BPF_ALU32_IMM(OP, DST, IMM) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_ALU | BPF_OP(OP) | BPF_K, \ .dst_reg = DST, \ .src_reg = 0, \ @@ -118,7 +118,7 @@ enum { /* Endianess conversion, cpu_to_{l,b}e(), {l,b}e_to_cpu() */ #define BPF_ENDIAN(TYPE, DST, LEN) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_ALU | BPF_END | BPF_SRC(TYPE), \ .dst_reg = DST, \ .src_reg = 0, \ @@ -128,7 +128,7 @@ enum { /* Short form of mov, dst_reg = src_reg */ #define BPF_MOV64_REG(DST, SRC) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_ALU64 | BPF_MOV | BPF_X, \ .dst_reg = DST, \ .src_reg = SRC, \ @@ -136,7 +136,7 @@ enum { .imm = 0 }) #define BPF_MOV32_REG(DST, SRC) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_ALU | BPF_MOV | BPF_X, \ .dst_reg = DST, \ .src_reg = SRC, \ @@ -146,7 +146,7 @@ enum { /* Short form of mov, dst_reg = imm32 */ #define BPF_MOV64_IMM(DST, IMM) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_ALU64 | BPF_MOV | BPF_K, \ .dst_reg = DST, \ .src_reg = 0, \ @@ -154,7 +154,7 @@ enum { .imm = IMM }) #define BPF_MOV32_IMM(DST, IMM) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_ALU | BPF_MOV | BPF_K, \ .dst_reg = DST, \ .src_reg = 0, \ @@ -164,7 +164,7 @@ enum { /* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */ #define BPF_MOV64_RAW(TYPE, DST, SRC, IMM) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_ALU64 | BPF_MOV | BPF_SRC(TYPE), \ .dst_reg = DST, \ .src_reg = SRC, \ @@ -172,7 +172,7 @@ enum { .imm = IMM }) #define BPF_MOV32_RAW(TYPE, DST, SRC, IMM) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_ALU | BPF_MOV | BPF_SRC(TYPE), \ .dst_reg = DST, \ .src_reg = SRC, \ @@ -182,7 +182,7 @@ enum { /* Direct packet access, R0 = *(uint *) (skb->data + imm32) */ #define BPF_LD_ABS(SIZE, IMM) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS, \ .dst_reg = 0, \ .src_reg = 0, \ @@ -192,7 +192,7 @@ enum { /* Indirect packet access, R0 = *(uint *) (skb->data + src_reg + imm32) */ #define BPF_LD_IND(SIZE, SRC, IMM) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_LD | BPF_SIZE(SIZE) | BPF_IND, \ .dst_reg = 0, \ .src_reg = SRC, \ @@ -202,7 +202,7 @@ enum { /* Memory load, dst_reg = *(uint *) (src_reg + off16) */ #define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \ .dst_reg = DST, \ .src_reg = SRC, \ @@ -212,7 +212,7 @@ enum { /* Memory store, *(uint *) (dst_reg + off16) = src_reg */ #define BPF_STX_MEM(SIZE, DST, SRC, OFF) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \ .dst_reg = DST, \ .src_reg = SRC, \ @@ -222,7 +222,7 @@ enum { /* Memory store, *(uint *) (dst_reg + off16) = imm32 */ #define BPF_ST_MEM(SIZE, DST, OFF, IMM) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \ .dst_reg = DST, \ .src_reg = 0, \ @@ -232,7 +232,7 @@ enum { /* Conditional jumps against registers, if (dst_reg 'op' src_reg) goto pc + off16 */ #define BPF_JMP_REG(OP, DST, SRC, OFF) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_JMP | BPF_OP(OP) | BPF_X, \ .dst_reg = DST, \ .src_reg = SRC, \ @@ -242,7 +242,7 @@ enum { /* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */ #define BPF_JMP_IMM(OP, DST, IMM, OFF) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ .dst_reg = DST, \ .src_reg = 0, \ @@ -252,7 +252,7 @@ enum { /* Function call */ #define BPF_EMIT_CALL(FUNC) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_JMP | BPF_CALL, \ .dst_reg = 0, \ .src_reg = 0, \ @@ -262,7 +262,7 @@ enum { /* Raw code statement block */ #define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = CODE, \ .dst_reg = DST, \ .src_reg = SRC, \ @@ -272,7 +272,7 @@ enum { /* Program exit */ #define BPF_EXIT_INSN() \ - ((struct sock_filter_int) { \ + ((struct bpf_insn) { \ .code = BPF_JMP | BPF_EXIT, \ .dst_reg = 0, \ .src_reg = 0, \ @@ -298,7 +298,7 @@ enum { /* Macro to invoke filter function. */ #define SK_RUN_FILTER(filter, ctx) (*filter->bpf_func)(ctx, filter->insnsi) -struct sock_filter_int { +struct bpf_insn { __u8 code; /* opcode */ __u8 dst_reg:4; /* dest register */ __u8 src_reg:4; /* source register */ @@ -330,10 +330,10 @@ struct sk_filter { struct sock_fprog_kern *orig_prog; /* Original BPF program */ struct rcu_head rcu; unsigned int (*bpf_func)(const struct sk_buff *skb, - const struct sock_filter_int *filter); + const struct bpf_insn *filter); union { struct sock_filter insns[0]; - struct sock_filter_int insnsi[0]; + struct bpf_insn insnsi[0]; struct work_struct work; }; }; @@ -353,7 +353,7 @@ void sk_filter_select_runtime(struct sk_filter *fp); void sk_filter_free(struct sk_filter *fp); int sk_convert_filter(struct sock_filter *prog, int len, - struct sock_filter_int *new_prog, int *new_len); + struct bpf_insn *new_prog, int *new_len); int sk_unattached_filter_create(struct sk_filter **pfp, struct sock_fprog_kern *fprog); diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 77a240a1ce11..265a02cc822d 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -81,7 +81,7 @@ noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) * keep, 0 for none. @ctx is the data we are operating on, @insn is the * array of filter instructions. */ -static unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn) +static unsigned int __sk_run_filter(void *ctx, const struct bpf_insn *insn) { u64 stack[MAX_BPF_STACK / sizeof(u64)]; u64 regs[MAX_BPF_REG], tmp; diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 301bbc24739c..565743db5384 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -248,7 +248,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) if (ret) goto free_prog; - /* Convert 'sock_filter' insns to 'sock_filter_int' insns */ + /* Convert 'sock_filter' insns to 'bpf_insn' insns */ ret = sk_convert_filter(fp, fprog->len, NULL, &new_len); if (ret) goto free_prog; diff --git a/lib/test_bpf.c b/lib/test_bpf.c index c579e0f58818..5f48623ee1a7 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -66,7 +66,7 @@ struct bpf_test { const char *descr; union { struct sock_filter insns[MAX_INSNS]; - struct sock_filter_int insns_int[MAX_INSNS]; + struct bpf_insn insns_int[MAX_INSNS]; } u; __u8 aux; __u8 data[MAX_DATA]; @@ -1807,7 +1807,7 @@ static struct sk_filter *generate_filter(int which, int *err) fp->len = flen; memcpy(fp->insnsi, tests[which].u.insns_int, - fp->len * sizeof(struct sock_filter_int)); + fp->len * sizeof(struct bpf_insn)); sk_filter_select_runtime(fp); break; diff --git a/net/core/filter.c b/net/core/filter.c index 1d0e9492e4fa..f3b2d5e9fe5f 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -174,9 +174,9 @@ static u64 __get_random_u32(u64 ctx, u64 a, u64 x, u64 r4, u64 r5) } static bool convert_bpf_extensions(struct sock_filter *fp, - struct sock_filter_int **insnp) + struct bpf_insn **insnp) { - struct sock_filter_int *insn = *insnp; + struct bpf_insn *insn = *insnp; switch (fp->k) { case SKF_AD_OFF + SKF_AD_PROTOCOL: @@ -326,7 +326,7 @@ static bool convert_bpf_extensions(struct sock_filter *fp, * * 2) 2nd pass to remap in two passes: 1st pass finds new * jump offsets, 2nd pass remapping: - * new_prog = kmalloc(sizeof(struct sock_filter_int) * new_len); + * new_prog = kmalloc(sizeof(struct bpf_insn) * new_len); * sk_convert_filter(old_prog, old_len, new_prog, &new_len); * * User BPF's register A is mapped to our BPF register 6, user BPF @@ -336,10 +336,10 @@ static bool convert_bpf_extensions(struct sock_filter *fp, * ctx == 'struct seccomp_data *'. */ int sk_convert_filter(struct sock_filter *prog, int len, - struct sock_filter_int *new_prog, int *new_len) + struct bpf_insn *new_prog, int *new_len) { int new_flen = 0, pass = 0, target, i; - struct sock_filter_int *new_insn; + struct bpf_insn *new_insn; struct sock_filter *fp; int *addrs = NULL; u8 bpf_src; @@ -365,8 +365,8 @@ do_pass: new_insn++; for (i = 0; i < len; fp++, i++) { - struct sock_filter_int tmp_insns[6] = { }; - struct sock_filter_int *insn = tmp_insns; + struct bpf_insn tmp_insns[6] = { }; + struct bpf_insn *insn = tmp_insns; if (addrs) addrs[i] = new_insn - new_prog; @@ -913,7 +913,7 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp, * representation. */ BUILD_BUG_ON(sizeof(struct sock_filter) != - sizeof(struct sock_filter_int)); + sizeof(struct bpf_insn)); /* Conversion cannot happen on overlapping memory areas, * so we need to keep the user BPF around until the 2nd @@ -945,7 +945,7 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp, fp->len = new_len; - /* 2nd pass: remap sock_filter insns into sock_filter_int insns. */ + /* 2nd pass: remap sock_filter insns into bpf_insn insns. */ err = sk_convert_filter(old_prog, old_len, fp->insnsi, &new_len); if (err) /* 2nd sk_convert_filter() can fail only if it fails -- cgit v1.2.3 From c81576c225b942496feb9fbef5bca506bc64ce57 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 24 Jul 2014 17:16:30 +0530 Subject: cxgb4: Fixed incorrect check for memory operation in t4_memory_rw Fix incorrect check introduced in commit fc5ab020 ("cxgb4: Replaced the backdoor mechanism to access the HW memory with PCIe Window method"). We where checking for write operation and doing a read, changed it accordingly. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index e76885236e9d..448bec119c3c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -545,7 +545,7 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, unsigned char *bp; int i; - if (dir == T4_MEMORY_WRITE) { + if (dir == T4_MEMORY_READ) { last.word = (__force __be32) t4_read_reg(adap, mem_base + offset); for (bp = (unsigned char *)buf, i = resid; i < 4; i++) -- cgit v1.2.3 From 7b18ef08ba58a91bef7149e64443397cfc2523f3 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Thu, 24 Jul 2014 02:46:38 +0530 Subject: isdn: use constants instead of magicnumbers This patch changes instances of magic numbers like 4 and 8 to equivalent constants. The Coccinelle semantic patch used for making the change is as follows: // @r@ type T; T E; identifier fld; identifier c; @@ E->fld & c @s@ constant C; identifier r.c; @@ #define c C @@ r.T E; identifier r.fld; identifier r.c; constant s.C; @@ E->fld & - C + c // Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/isdn/i4l/isdn_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index c2ed6246a389..94affa5e6f28 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -2918,8 +2918,8 @@ isdn_net_getcfg(isdn_net_ioctl_cfg *cfg) cfg->callback = 2; cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0; cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK; - cfg->chargehup = (lp->hupflags & 4) ? 1 : 0; - cfg->ihup = (lp->hupflags & 8) ? 1 : 0; + cfg->chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0; + cfg->ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0; cfg->cbdelay = lp->cbdelay; cfg->dialmax = lp->dialmax; cfg->triggercps = lp->triggercps; -- cgit v1.2.3 From 6b53dafe23fd1f1228c7dd9b8a1323e757966160 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Wed, 23 Jul 2014 16:09:10 -0700 Subject: net: do not name the pointer to struct net_device net "net" is normally for struct net*, pointer to struct net_device should be named to either "dev" or "ndev" etc. Cc: "David S. Miller" Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/core/net-sysfs.c | 142 +++++++++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 7752f2ad49a5..9dd06699b09c 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -43,12 +43,12 @@ static ssize_t netdev_show(const struct device *dev, struct device_attribute *attr, char *buf, ssize_t (*format)(const struct net_device *, char *)) { - struct net_device *net = to_net_dev(dev); + struct net_device *ndev = to_net_dev(dev); ssize_t ret = -EINVAL; read_lock(&dev_base_lock); - if (dev_isalive(net)) - ret = (*format)(net, buf); + if (dev_isalive(ndev)) + ret = (*format)(ndev, buf); read_unlock(&dev_base_lock); return ret; @@ -56,9 +56,9 @@ static ssize_t netdev_show(const struct device *dev, /* generate a show function for simple field */ #define NETDEVICE_SHOW(field, format_string) \ -static ssize_t format_##field(const struct net_device *net, char *buf) \ +static ssize_t format_##field(const struct net_device *dev, char *buf) \ { \ - return sprintf(buf, format_string, net->field); \ + return sprintf(buf, format_string, dev->field); \ } \ static ssize_t field##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ @@ -112,19 +112,19 @@ NETDEVICE_SHOW_RO(ifindex, fmt_dec); NETDEVICE_SHOW_RO(type, fmt_dec); NETDEVICE_SHOW_RO(link_mode, fmt_dec); -static ssize_t format_name_assign_type(const struct net_device *net, char *buf) +static ssize_t format_name_assign_type(const struct net_device *dev, char *buf) { - return sprintf(buf, fmt_dec, net->name_assign_type); + return sprintf(buf, fmt_dec, dev->name_assign_type); } static ssize_t name_assign_type_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct net_device *net = to_net_dev(dev); + struct net_device *ndev = to_net_dev(dev); ssize_t ret = -EINVAL; - if (net->name_assign_type != NET_NAME_UNKNOWN) + if (ndev->name_assign_type != NET_NAME_UNKNOWN) ret = netdev_show(dev, attr, buf, format_name_assign_type); return ret; @@ -135,12 +135,12 @@ static DEVICE_ATTR_RO(name_assign_type); static ssize_t address_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct net_device *net = to_net_dev(dev); + struct net_device *ndev = to_net_dev(dev); ssize_t ret = -EINVAL; read_lock(&dev_base_lock); - if (dev_isalive(net)) - ret = sysfs_format_mac(buf, net->dev_addr, net->addr_len); + if (dev_isalive(ndev)) + ret = sysfs_format_mac(buf, ndev->dev_addr, ndev->addr_len); read_unlock(&dev_base_lock); return ret; } @@ -149,18 +149,18 @@ static DEVICE_ATTR_RO(address); static ssize_t broadcast_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct net_device *net = to_net_dev(dev); - if (dev_isalive(net)) - return sysfs_format_mac(buf, net->broadcast, net->addr_len); + struct net_device *ndev = to_net_dev(dev); + if (dev_isalive(ndev)) + return sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len); return -EINVAL; } static DEVICE_ATTR_RO(broadcast); -static int change_carrier(struct net_device *net, unsigned long new_carrier) +static int change_carrier(struct net_device *dev, unsigned long new_carrier) { - if (!netif_running(net)) + if (!netif_running(dev)) return -EINVAL; - return dev_change_carrier(net, (bool) new_carrier); + return dev_change_carrier(dev, (bool) new_carrier); } static ssize_t carrier_store(struct device *dev, struct device_attribute *attr, @@ -284,9 +284,9 @@ static DEVICE_ATTR_RO(carrier_changes); /* read-write attributes */ -static int change_mtu(struct net_device *net, unsigned long new_mtu) +static int change_mtu(struct net_device *dev, unsigned long new_mtu) { - return dev_set_mtu(net, (int) new_mtu); + return dev_set_mtu(dev, (int) new_mtu); } static ssize_t mtu_store(struct device *dev, struct device_attribute *attr, @@ -296,9 +296,9 @@ static ssize_t mtu_store(struct device *dev, struct device_attribute *attr, } NETDEVICE_SHOW_RW(mtu, fmt_dec); -static int change_flags(struct net_device *net, unsigned long new_flags) +static int change_flags(struct net_device *dev, unsigned long new_flags) { - return dev_change_flags(net, (unsigned int) new_flags); + return dev_change_flags(dev, (unsigned int) new_flags); } static ssize_t flags_store(struct device *dev, struct device_attribute *attr, @@ -308,9 +308,9 @@ static ssize_t flags_store(struct device *dev, struct device_attribute *attr, } NETDEVICE_SHOW_RW(flags, fmt_hex); -static int change_tx_queue_len(struct net_device *net, unsigned long new_len) +static int change_tx_queue_len(struct net_device *dev, unsigned long new_len) { - net->tx_queue_len = new_len; + dev->tx_queue_len = new_len; return 0; } @@ -363,9 +363,9 @@ static ssize_t ifalias_show(struct device *dev, } static DEVICE_ATTR_RW(ifalias); -static int change_group(struct net_device *net, unsigned long new_group) +static int change_group(struct net_device *dev, unsigned long new_group) { - dev_set_group(net, (int) new_group); + dev_set_group(dev, (int) new_group); return 0; } @@ -796,20 +796,20 @@ static struct kobj_type rx_queue_ktype = { .namespace = rx_queue_namespace }; -static int rx_queue_add_kobject(struct net_device *net, int index) +static int rx_queue_add_kobject(struct net_device *dev, int index) { - struct netdev_rx_queue *queue = net->_rx + index; + struct netdev_rx_queue *queue = dev->_rx + index; struct kobject *kobj = &queue->kobj; int error = 0; - kobj->kset = net->queues_kset; + kobj->kset = dev->queues_kset; error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, "rx-%u", index); if (error) goto exit; - if (net->sysfs_rx_queue_group) { - error = sysfs_create_group(kobj, net->sysfs_rx_queue_group); + if (dev->sysfs_rx_queue_group) { + error = sysfs_create_group(kobj, dev->sysfs_rx_queue_group); if (error) goto exit; } @@ -825,18 +825,18 @@ exit: #endif /* CONFIG_SYSFS */ int -net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num) +net_rx_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) { #ifdef CONFIG_SYSFS int i; int error = 0; #ifndef CONFIG_RPS - if (!net->sysfs_rx_queue_group) + if (!dev->sysfs_rx_queue_group) return 0; #endif for (i = old_num; i < new_num; i++) { - error = rx_queue_add_kobject(net, i); + error = rx_queue_add_kobject(dev, i); if (error) { new_num = old_num; break; @@ -844,10 +844,10 @@ net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num) } while (--i >= new_num) { - if (net->sysfs_rx_queue_group) - sysfs_remove_group(&net->_rx[i].kobj, - net->sysfs_rx_queue_group); - kobject_put(&net->_rx[i].kobj); + if (dev->sysfs_rx_queue_group) + sysfs_remove_group(&dev->_rx[i].kobj, + dev->sysfs_rx_queue_group); + kobject_put(&dev->_rx[i].kobj); } return error; @@ -1155,13 +1155,13 @@ static struct kobj_type netdev_queue_ktype = { .namespace = netdev_queue_namespace, }; -static int netdev_queue_add_kobject(struct net_device *net, int index) +static int netdev_queue_add_kobject(struct net_device *dev, int index) { - struct netdev_queue *queue = net->_tx + index; + struct netdev_queue *queue = dev->_tx + index; struct kobject *kobj = &queue->kobj; int error = 0; - kobj->kset = net->queues_kset; + kobj->kset = dev->queues_kset; error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, "tx-%u", index); if (error) @@ -1184,14 +1184,14 @@ exit: #endif /* CONFIG_SYSFS */ int -netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num) +netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) { #ifdef CONFIG_SYSFS int i; int error = 0; for (i = old_num; i < new_num; i++) { - error = netdev_queue_add_kobject(net, i); + error = netdev_queue_add_kobject(dev, i); if (error) { new_num = old_num; break; @@ -1199,7 +1199,7 @@ netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num) } while (--i >= new_num) { - struct netdev_queue *queue = net->_tx + i; + struct netdev_queue *queue = dev->_tx + i; #ifdef CONFIG_BQL sysfs_remove_group(&queue->kobj, &dql_group); @@ -1213,25 +1213,25 @@ netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num) #endif /* CONFIG_SYSFS */ } -static int register_queue_kobjects(struct net_device *net) +static int register_queue_kobjects(struct net_device *dev) { int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0; #ifdef CONFIG_SYSFS - net->queues_kset = kset_create_and_add("queues", - NULL, &net->dev.kobj); - if (!net->queues_kset) + dev->queues_kset = kset_create_and_add("queues", + NULL, &dev->dev.kobj); + if (!dev->queues_kset) return -ENOMEM; - real_rx = net->real_num_rx_queues; + real_rx = dev->real_num_rx_queues; #endif - real_tx = net->real_num_tx_queues; + real_tx = dev->real_num_tx_queues; - error = net_rx_queue_update_kobjects(net, 0, real_rx); + error = net_rx_queue_update_kobjects(dev, 0, real_rx); if (error) goto error; rxq = real_rx; - error = netdev_queue_update_kobjects(net, 0, real_tx); + error = netdev_queue_update_kobjects(dev, 0, real_tx); if (error) goto error; txq = real_tx; @@ -1239,24 +1239,24 @@ static int register_queue_kobjects(struct net_device *net) return 0; error: - netdev_queue_update_kobjects(net, txq, 0); - net_rx_queue_update_kobjects(net, rxq, 0); + netdev_queue_update_kobjects(dev, txq, 0); + net_rx_queue_update_kobjects(dev, rxq, 0); return error; } -static void remove_queue_kobjects(struct net_device *net) +static void remove_queue_kobjects(struct net_device *dev) { int real_rx = 0, real_tx = 0; #ifdef CONFIG_SYSFS - real_rx = net->real_num_rx_queues; + real_rx = dev->real_num_rx_queues; #endif - real_tx = net->real_num_tx_queues; + real_tx = dev->real_num_tx_queues; - net_rx_queue_update_kobjects(net, real_rx, 0); - netdev_queue_update_kobjects(net, real_tx, 0); + net_rx_queue_update_kobjects(dev, real_rx, 0); + netdev_queue_update_kobjects(dev, real_tx, 0); #ifdef CONFIG_SYSFS - kset_unregister(net->queues_kset); + kset_unregister(dev->queues_kset); #endif } @@ -1349,13 +1349,13 @@ static struct class net_class = { /* Delete sysfs entries but hold kobject reference until after all * netdev references are gone. */ -void netdev_unregister_kobject(struct net_device * net) +void netdev_unregister_kobject(struct net_device *ndev) { - struct device *dev = &(net->dev); + struct device *dev = &(ndev->dev); kobject_get(&dev->kobj); - remove_queue_kobjects(net); + remove_queue_kobjects(ndev); pm_runtime_set_memalloc_noio(dev, false); @@ -1363,18 +1363,18 @@ void netdev_unregister_kobject(struct net_device * net) } /* Create sysfs entries for network device. */ -int netdev_register_kobject(struct net_device *net) +int netdev_register_kobject(struct net_device *ndev) { - struct device *dev = &(net->dev); - const struct attribute_group **groups = net->sysfs_groups; + struct device *dev = &(ndev->dev); + const struct attribute_group **groups = ndev->sysfs_groups; int error = 0; device_initialize(dev); dev->class = &net_class; - dev->platform_data = net; + dev->platform_data = ndev; dev->groups = groups; - dev_set_name(dev, "%s", net->name); + dev_set_name(dev, "%s", ndev->name); #ifdef CONFIG_SYSFS /* Allow for a device specific group */ @@ -1384,10 +1384,10 @@ int netdev_register_kobject(struct net_device *net) *groups++ = &netstat_group; #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) - if (net->ieee80211_ptr) + if (ndev->ieee80211_ptr) *groups++ = &wireless_group; #if IS_ENABLED(CONFIG_WIRELESS_EXT) - else if (net->wireless_handlers) + else if (ndev->wireless_handlers) *groups++ = &wireless_group; #endif #endif @@ -1397,7 +1397,7 @@ int netdev_register_kobject(struct net_device *net) if (error) return error; - error = register_queue_kobjects(net); + error = register_queue_kobjects(ndev); if (error) { device_del(dev); return error; -- cgit v1.2.3 From 159945af1e40db5c15766d9fe6d465d7213cc860 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 24 Jul 2014 17:52:59 +0800 Subject: bfin_mac: convert bfin Ethernet driver to NAPI framework Ethernet RX DMA buffers are polled in NAPI work queue other than received directly in DMA RX interrupt handler. Signed-off-by: Sonic Zhang Signed-off-by: David S. Miller --- drivers/net/ethernet/adi/Kconfig | 3 +- drivers/net/ethernet/adi/bfin_mac.c | 79 +++++++++++++++++++++++-------------- drivers/net/ethernet/adi/bfin_mac.h | 3 ++ 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig index f952fff6a9a9..c9cd3592ab73 100644 --- a/drivers/net/ethernet/adi/Kconfig +++ b/drivers/net/ethernet/adi/Kconfig @@ -52,8 +52,7 @@ config BFIN_TX_DESC_NUM config BFIN_RX_DESC_NUM int "Number of receive buffer packets" depends on BFIN_MAC - range 20 100 if BFIN_MAC_USE_L1 - range 20 800 + range 20 64 default "20" ---help--- Set the number of buffer packets used in driver. diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c index 7ae74d450e8f..afa66847e10b 100644 --- a/drivers/net/ethernet/adi/bfin_mac.c +++ b/drivers/net/ethernet/adi/bfin_mac.c @@ -1218,11 +1218,11 @@ out: #define RX_ERROR_MASK (RX_LONG | RX_ALIGN | RX_CRC | RX_LEN | \ RX_FRAG | RX_ADDR | RX_DMAO | RX_PHY | RX_LATE | RX_RANGE) -static void bfin_mac_rx(struct net_device *dev) +static void bfin_mac_rx(struct bfin_mac_local *lp) { + struct net_device *dev = lp->ndev; struct sk_buff *skb, *new_skb; unsigned short len; - struct bfin_mac_local *lp __maybe_unused = netdev_priv(dev); #if defined(BFIN_MAC_CSUM_OFFLOAD) unsigned int i; unsigned char fcs[ETH_FCS_LEN + 1]; @@ -1256,7 +1256,7 @@ static void bfin_mac_rx(struct net_device *dev) current_rx_ptr->skb = new_skb; current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2; - len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN); + len = (unsigned short)(current_rx_ptr->status.status_word & RX_FRLEN); /* Deduce Ethernet FCS length from Ethernet payload length */ len -= ETH_FCS_LEN; skb_put(skb, len); @@ -1294,7 +1294,8 @@ static void bfin_mac_rx(struct net_device *dev) } #endif - netif_rx(skb); + napi_gro_receive(&lp->napi, skb); + dev->stats.rx_packets++; dev->stats.rx_bytes += len; out: @@ -1302,41 +1303,52 @@ out: current_rx_ptr = current_rx_ptr->next; } +static int bfin_mac_poll(struct napi_struct *napi, int budget) +{ + int i = 0; + struct bfin_mac_local *lp = container_of(napi, + struct bfin_mac_local, + napi); + + while (current_rx_ptr->status.status_word != 0 && i < budget) { + bfin_mac_rx(lp); + i++; + } + + if (i < budget) { + napi_complete(napi); + if (test_and_clear_bit(BFIN_MAC_RX_IRQ_DISABLED, &lp->flags)) + enable_irq(IRQ_MAC_RX); + } + + return i; +} + /* interrupt routine to handle rx and error signal */ static irqreturn_t bfin_mac_interrupt(int irq, void *dev_id) { - struct net_device *dev = dev_id; - int number = 0; - -get_one_packet: - if (current_rx_ptr->status.status_word == 0) { - /* no more new packet received */ - if (number == 0) { - if (current_rx_ptr->next->status.status_word != 0) { - current_rx_ptr = current_rx_ptr->next; - goto real_rx; - } - } - bfin_write_DMA1_IRQ_STATUS(bfin_read_DMA1_IRQ_STATUS() | - DMA_DONE | DMA_ERR); - return IRQ_HANDLED; + struct bfin_mac_local *lp = netdev_priv(dev_id); + u32 status; + + status = bfin_read_DMA1_IRQ_STATUS(); + + bfin_write_DMA1_IRQ_STATUS(status | DMA_DONE | DMA_ERR); + if (status & DMA_DONE) { + disable_irq_nosync(IRQ_MAC_RX); + set_bit(BFIN_MAC_RX_IRQ_DISABLED, &lp->flags); + napi_schedule(&lp->napi); } -real_rx: - bfin_mac_rx(dev); - number++; - goto get_one_packet; + return IRQ_HANDLED; } #ifdef CONFIG_NET_POLL_CONTROLLER -static void bfin_mac_poll(struct net_device *dev) +static void bfin_mac_poll_controller(struct net_device *dev) { struct bfin_mac_local *lp = netdev_priv(dev); - disable_irq(IRQ_MAC_RX); bfin_mac_interrupt(IRQ_MAC_RX, dev); tx_reclaim_skb(lp); - enable_irq(IRQ_MAC_RX); } #endif /* CONFIG_NET_POLL_CONTROLLER */ @@ -1428,14 +1440,13 @@ static void bfin_mac_timeout(struct net_device *dev) tx_list_head = tx_list_head->next; } - if (netif_queue_stopped(lp->ndev)) - netif_wake_queue(lp->ndev); + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); bfin_mac_enable(lp->phydev); /* We can accept TX packets again */ dev->trans_start = jiffies; /* prevent tx timeout */ - netif_wake_queue(dev); } static void bfin_mac_multicast_hash(struct net_device *dev) @@ -1562,6 +1573,7 @@ static int bfin_mac_open(struct net_device *dev) return ret; pr_debug("hardware init finished\n"); + napi_enable(&lp->napi); netif_start_queue(dev); netif_carrier_on(dev); @@ -1579,6 +1591,7 @@ static int bfin_mac_close(struct net_device *dev) pr_debug("%s: %s\n", dev->name, __func__); netif_stop_queue(dev); + napi_disable(&lp->napi); netif_carrier_off(dev); phy_stop(lp->phydev); @@ -1604,7 +1617,7 @@ static const struct net_device_ops bfin_mac_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = bfin_mac_poll, + .ndo_poll_controller = bfin_mac_poll_controller, #endif }; @@ -1689,6 +1702,9 @@ static int bfin_mac_probe(struct platform_device *pdev) lp->tx_reclaim_timer.data = (unsigned long)lp; lp->tx_reclaim_timer.function = tx_reclaim_skb_timeout; + lp->flags = 0; + netif_napi_add(ndev, &lp->napi, bfin_mac_poll, CONFIG_BFIN_RX_DESC_NUM); + spin_lock_init(&lp->lock); /* now, enable interrupts */ @@ -1723,6 +1739,7 @@ out_err_phc: out_err_reg_ndev: free_irq(IRQ_MAC_RX, ndev); out_err_request_irq: + netif_napi_del(&lp->napi); out_err_mii_probe: mdiobus_unregister(lp->mii_bus); mdiobus_free(lp->mii_bus); @@ -1743,6 +1760,8 @@ static int bfin_mac_remove(struct platform_device *pdev) unregister_netdev(ndev); + netif_napi_del(&lp->napi); + free_irq(IRQ_MAC_RX, ndev); free_netdev(ndev); diff --git a/drivers/net/ethernet/adi/bfin_mac.h b/drivers/net/ethernet/adi/bfin_mac.h index 6dec86ac97cd..d1217db70db4 100644 --- a/drivers/net/ethernet/adi/bfin_mac.h +++ b/drivers/net/ethernet/adi/bfin_mac.h @@ -26,6 +26,7 @@ #endif #define TX_RECLAIM_JIFFIES (HZ / 5) +#define BFIN_MAC_RX_IRQ_DISABLED 1 struct dma_descriptor { struct dma_descriptor *next_dma_desc; @@ -80,6 +81,8 @@ struct bfin_mac_local { int irq_wake_requested; struct timer_list tx_reclaim_timer; struct net_device *ndev; + struct napi_struct napi; + unsigned long flags; /* Data for EMAC_VLAN1 regs */ u16 vlan1_mask, vlan2_mask; -- cgit v1.2.3 From 3f6148e76a58eceef1435b65afecaf448b509cfd Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Thu, 24 Jul 2014 09:11:46 +0300 Subject: net/mlx4_en: mlx4_en_[gs]et_priv_flags() can be static Fixes sparse warning intrduced by commit 0fef9d0 ("net/mlx4_en: Disable blueflame using ethtool private flags") Signed-off-by: Fengguang Wu Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 50e85cc1d61f..e22f24f784fc 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1221,7 +1221,7 @@ static int mlx4_en_get_ts_info(struct net_device *dev, return ret; } -int mlx4_en_set_priv_flags(struct net_device *dev, u32 flags) +static int mlx4_en_set_priv_flags(struct net_device *dev, u32 flags) { struct mlx4_en_priv *priv = netdev_priv(dev); bool bf_enabled_new = !!(flags & MLX4_EN_PRIV_FLAGS_BLUEFLAME); @@ -1256,7 +1256,7 @@ int mlx4_en_set_priv_flags(struct net_device *dev, u32 flags) return 0; } -u32 mlx4_en_get_priv_flags(struct net_device *dev) +static u32 mlx4_en_get_priv_flags(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); -- cgit v1.2.3 From ef492001214ba250b3bd18a7a346a047fe079449 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Thu, 24 Jul 2014 16:33:29 +0530 Subject: drivers: net: cpsw: cleanup: remove unused function removing unused function as part of driver cleanup.` Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 60f925df15e2..999fb72688d2 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1003,17 +1003,6 @@ static void cpsw_get_ethtool_stats(struct net_device *ndev, } } -static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val) -{ - static char *leader = "........................................"; - - if (!val) - return 0; - else - return snprintf(buf, maxlen, "%s %s %10d\n", name, - leader + strlen(name), val); -} - static int cpsw_common_res_usage_state(struct cpsw_priv *priv) { u32 i; -- cgit v1.2.3 From e175587f4d32de27182f5d28d70734b1e812905d Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 24 Jul 2014 13:50:58 +0200 Subject: net/macb: configure for FIFO mode and non-gigabit This addition will also allow to configure DMA burst length. Signed-off-by: Nicolas Ferre Acked-by: Cyrille Pitchen Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 75 ++++++++++++++++++++++++++++--------- drivers/net/ethernet/cadence/macb.h | 19 +++++++++- 2 files changed, 74 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index e9daa072ebb4..91870e920732 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -264,7 +264,8 @@ static void macb_handle_link_change(struct net_device *dev) reg |= MACB_BIT(FD); if (phydev->speed == SPEED_100) reg |= MACB_BIT(SPD); - if (phydev->speed == SPEED_1000) + if (phydev->speed == SPEED_1000 && + bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) reg |= GEM_BIT(GBE); macb_or_gem_writel(bp, NCFGR, reg); @@ -337,7 +338,7 @@ static int macb_mii_probe(struct net_device *dev) } /* mask with MAC supported features */ - if (macb_is_gem(bp)) + if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) phydev->supported &= PHY_GBIT_FEATURES; else phydev->supported &= PHY_BASIC_FEATURES; @@ -1342,7 +1343,7 @@ static u32 macb_dbw(struct macb *bp) /* * Configure the receive DMA engine * - use the correct receive buffer size - * - set the possibility to use INCR16 bursts + * - set best burst length for DMA operations * (if not supported by FIFO, it will fallback to default) * - set both rx/tx packet buffers to full memory size * These are configurable parameters for GEM. @@ -1354,24 +1355,16 @@ static void macb_configure_dma(struct macb *bp) if (macb_is_gem(bp)) { dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L); dmacfg |= GEM_BF(RXBS, bp->rx_buffer_size / RX_BUFFER_MULTIPLE); - dmacfg |= GEM_BF(FBLDO, 16); + if (bp->dma_burst_length) + dmacfg = GEM_BFINS(FBLDO, bp->dma_burst_length, dmacfg); dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L); dmacfg &= ~GEM_BIT(ENDIA); + netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n", + dmacfg); gem_writel(bp, DMACFG, dmacfg); } } -/* - * Configure peripheral capacities according to integration options used - */ -static void macb_configure_caps(struct macb *bp) -{ - if (macb_is_gem(bp)) { - if (GEM_BFEXT(IRQCOR, gem_readl(bp, DCFG1)) == 0) - bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE; - } -} - static void macb_init_hw(struct macb *bp) { u32 config; @@ -1394,7 +1387,6 @@ static void macb_init_hw(struct macb *bp) bp->duplex = DUPLEX_HALF; macb_configure_dma(bp); - macb_configure_caps(bp); /* Initialize TX and RX buffers */ macb_writel(bp, RBQP, bp->rx_ring_dma); @@ -1783,17 +1775,61 @@ static const struct net_device_ops macb_netdev_ops = { }; #if defined(CONFIG_OF) +static struct macb_config pc302gem_config = { + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE, + .dma_burst_length = 16, +}; + static const struct of_device_id macb_dt_ids[] = { { .compatible = "cdns,at32ap7000-macb" }, { .compatible = "cdns,at91sam9260-macb" }, { .compatible = "cdns,macb" }, - { .compatible = "cdns,pc302-gem" }, - { .compatible = "cdns,gem" }, + { .compatible = "cdns,pc302-gem", .data = &pc302gem_config }, + { .compatible = "cdns,gem", .data = &pc302gem_config }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, macb_dt_ids); #endif +/* + * Configure peripheral capacities according to device tree + * and integration options used + */ +static void macb_configure_caps(struct macb *bp) +{ + u32 dcfg; + const struct of_device_id *match; + const struct macb_config *config; + + if (bp->pdev->dev.of_node) { + match = of_match_node(macb_dt_ids, bp->pdev->dev.of_node); + if (match && match->data) { + config = (const struct macb_config *)match->data; + + bp->caps = config->caps; + /* + * As we have access to the matching node, configure + * DMA burst length as well + */ + bp->dma_burst_length = config->dma_burst_length; + } + } + + if (MACB_BFEXT(IDNUM, macb_readl(bp, MID)) == 0x2) + bp->caps |= MACB_CAPS_MACB_IS_GEM; + + if (macb_is_gem(bp)) { + dcfg = gem_readl(bp, DCFG1); + if (GEM_BFEXT(IRQCOR, dcfg) == 0) + bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE; + dcfg = gem_readl(bp, DCFG2); + if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0) + bp->caps |= MACB_CAPS_FIFO_MODE; + } + + netdev_dbg(bp->dev, "Cadence caps 0x%08x\n", bp->caps); +} + static int __init macb_probe(struct platform_device *pdev) { struct macb_platform_data *pdata; @@ -1897,6 +1933,9 @@ static int __init macb_probe(struct platform_device *pdev) dev->base_addr = regs->start; + /* setup capacities */ + macb_configure_caps(bp); + /* setup appropriated routines according to adapter type */ if (macb_is_gem(bp)) { bp->macbgem_ops.mog_alloc_rx_buffers = gem_alloc_rx_buffers; diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 51c02442160a..7ce751be133b 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -305,6 +305,12 @@ #define GEM_DBWDEF_OFFSET 25 #define GEM_DBWDEF_SIZE 3 +/* Bitfields in DCFG2. */ +#define GEM_RX_PKT_BUFF_OFFSET 20 +#define GEM_RX_PKT_BUFF_SIZE 1 +#define GEM_TX_PKT_BUFF_OFFSET 21 +#define GEM_TX_PKT_BUFF_SIZE 1 + /* Constants for CLK */ #define MACB_CLK_DIV8 0 #define MACB_CLK_DIV16 1 @@ -326,7 +332,10 @@ #define MACB_MAN_CODE 2 /* Capability mask bits */ -#define MACB_CAPS_ISR_CLEAR_ON_WRITE 0x1 +#define MACB_CAPS_ISR_CLEAR_ON_WRITE 0x00000001 +#define MACB_CAPS_FIFO_MODE 0x10000000 +#define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000 +#define MACB_CAPS_MACB_IS_GEM 0x80000000 /* Bit manipulation macros */ #define MACB_BIT(name) \ @@ -554,6 +563,11 @@ struct macb_or_gem_ops { int (*mog_rx)(struct macb *bp, int budget); }; +struct macb_config { + u32 caps; + unsigned int dma_burst_length; +}; + struct macb { void __iomem *regs; @@ -595,6 +609,7 @@ struct macb { unsigned int duplex; u32 caps; + unsigned int dma_burst_length; phy_interface_t phy_interface; @@ -615,7 +630,7 @@ void macb_get_hwaddr(struct macb *bp); static inline bool macb_is_gem(struct macb *bp) { - return MACB_BFEXT(IDNUM, macb_readl(bp, MID)) == 0x2; + return !!(bp->caps & MACB_CAPS_MACB_IS_GEM); } #endif /* _MACB_H */ -- cgit v1.2.3 From a4c35ed3fb1a1840d58d8ae5ea8070ff63075bc2 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 24 Jul 2014 13:50:59 +0200 Subject: net/macb: add scatter-gather hw feature The scatter-gather feature will allow to enable the Generic Segmentation Offload. Generic Segmentation Offload can be enabled/disabled using ethtool -K DEVNAME gso on|off. e.g: ethtool -K eth0 gso off When enabled, the driver may be provided with socket buffers splitted into many fragments. These fragments need to be queued into the TX ring in reverse order, starting from to the last one down to the first one, to avoid a race condition with the MAC. Especially the 'TX_USED' bit in word 1 of the transmit buffer descriptor of the first fragment should be cleared at the very final step of the queueing algorithm. This will tell the hardware that fragments are ready to be sent. Also since the MAC only update the status word of the first buffer descriptor of the ethernet frame, the queueing algorithm can no longer expect a 'TX_USED' bit to be set by the MAC into the buffer descriptor following the one for last fragment of the skb. This is why the driver sets the 'TX_USED' bit before queueing any fragment, so the end of queue position is well defined for the MAC. Signed-off-by: Cyrille Pitchen Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 277 +++++++++++++++++++++++++++++------- drivers/net/ethernet/cadence/macb.h | 15 +- 2 files changed, 240 insertions(+), 52 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 91870e920732..2e4bfe39b502 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -52,6 +52,9 @@ | MACB_BIT(TXERR)) #define MACB_TX_INT_FLAGS (MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP)) +#define MACB_MAX_TX_LEN ((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1)) +#define GEM_MAX_TX_LEN ((unsigned int)((1 << GEM_TX_FRMLEN_SIZE) - 1)) + /* * Graceful stop timeouts in us. We should allow up to * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions) @@ -468,6 +471,24 @@ static int macb_halt_tx(struct macb *bp) return -ETIMEDOUT; } +static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb) +{ + if (tx_skb->mapping) { + if (tx_skb->mapped_as_page) + dma_unmap_page(&bp->pdev->dev, tx_skb->mapping, + tx_skb->size, DMA_TO_DEVICE); + else + dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, + tx_skb->size, DMA_TO_DEVICE); + tx_skb->mapping = 0; + } + + if (tx_skb->skb) { + dev_kfree_skb_any(tx_skb->skb); + tx_skb->skb = NULL; + } +} + static void macb_tx_error_task(struct work_struct *work) { struct macb *bp = container_of(work, struct macb, tx_error_task); @@ -505,10 +526,23 @@ static void macb_tx_error_task(struct work_struct *work) skb = tx_skb->skb; if (ctrl & MACB_BIT(TX_USED)) { - netdev_vdbg(bp->dev, "txerr skb %u (data %p) TX complete\n", - macb_tx_ring_wrap(tail), skb->data); - bp->stats.tx_packets++; - bp->stats.tx_bytes += skb->len; + /* skb is set for the last buffer of the frame */ + while (!skb) { + macb_tx_unmap(bp, tx_skb); + tail++; + tx_skb = macb_tx_skb(bp, tail); + skb = tx_skb->skb; + } + + /* ctrl still refers to the first buffer descriptor + * since it's the only one written back by the hardware + */ + if (!(ctrl & MACB_BIT(TX_BUF_EXHAUSTED))) { + netdev_vdbg(bp->dev, "txerr skb %u (data %p) TX complete\n", + macb_tx_ring_wrap(tail), skb->data); + bp->stats.tx_packets++; + bp->stats.tx_bytes += skb->len; + } } else { /* * "Buffers exhausted mid-frame" errors may only happen @@ -522,10 +556,7 @@ static void macb_tx_error_task(struct work_struct *work) desc->ctrl = ctrl | MACB_BIT(TX_USED); } - dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, skb->len, - DMA_TO_DEVICE); - tx_skb->skb = NULL; - dev_kfree_skb(skb); + macb_tx_unmap(bp, tx_skb); } /* Make descriptor updates visible to hardware */ @@ -573,20 +604,35 @@ static void macb_tx_interrupt(struct macb *bp) ctrl = desc->ctrl; + /* TX_USED bit is only set by hardware on the very first buffer + * descriptor of the transmitted frame. + */ if (!(ctrl & MACB_BIT(TX_USED))) break; - tx_skb = macb_tx_skb(bp, tail); - skb = tx_skb->skb; + /* Process all buffers of the current transmitted frame */ + for (;; tail++) { + tx_skb = macb_tx_skb(bp, tail); + skb = tx_skb->skb; + + /* First, update TX stats if needed */ + if (skb) { + netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n", + macb_tx_ring_wrap(tail), skb->data); + bp->stats.tx_packets++; + bp->stats.tx_bytes += skb->len; + } - netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n", - macb_tx_ring_wrap(tail), skb->data); - dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, skb->len, - DMA_TO_DEVICE); - bp->stats.tx_packets++; - bp->stats.tx_bytes += skb->len; - tx_skb->skb = NULL; - dev_kfree_skb_irq(skb); + /* Now we can safely release resources */ + macb_tx_unmap(bp, tx_skb); + + /* skb is set only for the last buffer of the frame. + * WARNING: at this point skb has been freed by + * macb_tx_unmap(). + */ + if (skb) + break; + } } bp->tx_tail = tail; @@ -1002,15 +1048,145 @@ static void macb_poll_controller(struct net_device *dev) } #endif -static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) +static inline unsigned int macb_count_tx_descriptors(struct macb *bp, + unsigned int len) +{ + return (len + bp->max_tx_length - 1) / bp->max_tx_length; +} + +static unsigned int macb_tx_map(struct macb *bp, + struct sk_buff *skb) { - struct macb *bp = netdev_priv(dev); dma_addr_t mapping; - unsigned int len, entry; + unsigned int len, entry, i, tx_head = bp->tx_head; + struct macb_tx_skb *tx_skb = NULL; struct macb_dma_desc *desc; - struct macb_tx_skb *tx_skb; + unsigned int offset, size, count = 0; + unsigned int f, nr_frags = skb_shinfo(skb)->nr_frags; + unsigned int eof = 1; u32 ctrl; + + /* First, map non-paged data */ + len = skb_headlen(skb); + offset = 0; + while (len) { + size = min(len, bp->max_tx_length); + entry = macb_tx_ring_wrap(tx_head); + tx_skb = &bp->tx_skb[entry]; + + mapping = dma_map_single(&bp->pdev->dev, + skb->data + offset, + size, DMA_TO_DEVICE); + if (dma_mapping_error(&bp->pdev->dev, mapping)) + goto dma_error; + + /* Save info to properly release resources */ + tx_skb->skb = NULL; + tx_skb->mapping = mapping; + tx_skb->size = size; + tx_skb->mapped_as_page = false; + + len -= size; + offset += size; + count++; + tx_head++; + } + + /* Then, map paged data from fragments */ + for (f = 0; f < nr_frags; f++) { + const skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; + + len = skb_frag_size(frag); + offset = 0; + while (len) { + size = min(len, bp->max_tx_length); + entry = macb_tx_ring_wrap(tx_head); + tx_skb = &bp->tx_skb[entry]; + + mapping = skb_frag_dma_map(&bp->pdev->dev, frag, + offset, size, DMA_TO_DEVICE); + if (dma_mapping_error(&bp->pdev->dev, mapping)) + goto dma_error; + + /* Save info to properly release resources */ + tx_skb->skb = NULL; + tx_skb->mapping = mapping; + tx_skb->size = size; + tx_skb->mapped_as_page = true; + + len -= size; + offset += size; + count++; + tx_head++; + } + } + + /* Should never happen */ + if (unlikely(tx_skb == NULL)) { + netdev_err(bp->dev, "BUG! empty skb!\n"); + return 0; + } + + /* This is the last buffer of the frame: save socket buffer */ + tx_skb->skb = skb; + + /* Update TX ring: update buffer descriptors in reverse order + * to avoid race condition + */ + + /* Set 'TX_USED' bit in buffer descriptor at tx_head position + * to set the end of TX queue + */ + i = tx_head; + entry = macb_tx_ring_wrap(i); + ctrl = MACB_BIT(TX_USED); + desc = &bp->tx_ring[entry]; + desc->ctrl = ctrl; + + do { + i--; + entry = macb_tx_ring_wrap(i); + tx_skb = &bp->tx_skb[entry]; + desc = &bp->tx_ring[entry]; + + ctrl = (u32)tx_skb->size; + if (eof) { + ctrl |= MACB_BIT(TX_LAST); + eof = 0; + } + if (unlikely(entry == (TX_RING_SIZE - 1))) + ctrl |= MACB_BIT(TX_WRAP); + + /* Set TX buffer descriptor */ + desc->addr = tx_skb->mapping; + /* desc->addr must be visible to hardware before clearing + * 'TX_USED' bit in desc->ctrl. + */ + wmb(); + desc->ctrl = ctrl; + } while (i != bp->tx_head); + + bp->tx_head = tx_head; + + return count; + +dma_error: + netdev_err(bp->dev, "TX DMA map failed\n"); + + for (i = bp->tx_head; i != tx_head; i++) { + tx_skb = macb_tx_skb(bp, i); + + macb_tx_unmap(bp, tx_skb); + } + + return 0; +} + +static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); unsigned long flags; + unsigned int count, nr_frags, frag_size, f; #if defined(DEBUG) && defined(VERBOSE_DEBUG) netdev_vdbg(bp->dev, @@ -1021,44 +1197,34 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) skb->data, 16, true); #endif - len = skb->len; + /* Count how many TX buffer descriptors are needed to send this + * socket buffer: skb fragments of jumbo frames may need to be + * splitted into many buffer descriptors. + */ + count = macb_count_tx_descriptors(bp, skb_headlen(skb)); + nr_frags = skb_shinfo(skb)->nr_frags; + for (f = 0; f < nr_frags; f++) { + frag_size = skb_frag_size(&skb_shinfo(skb)->frags[f]); + count += macb_count_tx_descriptors(bp, frag_size); + } + spin_lock_irqsave(&bp->lock, flags); /* This is a hard error, log it. */ - if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < 1) { + if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < count) { netif_stop_queue(dev); spin_unlock_irqrestore(&bp->lock, flags); - netdev_err(bp->dev, "BUG! Tx Ring full when queue awake!\n"); netdev_dbg(bp->dev, "tx_head = %u, tx_tail = %u\n", bp->tx_head, bp->tx_tail); return NETDEV_TX_BUSY; } - entry = macb_tx_ring_wrap(bp->tx_head); - netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry); - mapping = dma_map_single(&bp->pdev->dev, skb->data, - len, DMA_TO_DEVICE); - if (dma_mapping_error(&bp->pdev->dev, mapping)) { + /* Map socket buffer for DMA transfer */ + if (!macb_tx_map(bp, skb)) { dev_kfree_skb_any(skb); goto unlock; } - bp->tx_head++; - tx_skb = &bp->tx_skb[entry]; - tx_skb->skb = skb; - tx_skb->mapping = mapping; - netdev_vdbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n", - skb->data, (unsigned long)mapping); - - ctrl = MACB_BF(TX_FRMLEN, len); - ctrl |= MACB_BIT(TX_LAST); - if (entry == (TX_RING_SIZE - 1)) - ctrl |= MACB_BIT(TX_WRAP); - - desc = &bp->tx_ring[entry]; - desc->addr = mapping; - desc->ctrl = ctrl; - /* Make newly initialized descriptor visible to hardware */ wmb(); @@ -1776,7 +1942,12 @@ static const struct net_device_ops macb_netdev_ops = { #if defined(CONFIG_OF) static struct macb_config pc302gem_config = { - .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE, + .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE, + .dma_burst_length = 16, +}; + +static struct macb_config sama5d3_config = { + .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE, .dma_burst_length = 16, }; @@ -1786,6 +1957,7 @@ static const struct of_device_id macb_dt_ids[] = { { .compatible = "cdns,macb" }, { .compatible = "cdns,pc302-gem", .data = &pc302gem_config }, { .compatible = "cdns,gem", .data = &pc302gem_config }, + { .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, macb_dt_ids); @@ -1864,9 +2036,6 @@ static int __init macb_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); - /* TODO: Actually, we have some interesting features... */ - dev->features |= 0; - bp = netdev_priv(dev); bp->pdev = pdev; bp->dev = dev; @@ -1938,17 +2107,25 @@ static int __init macb_probe(struct platform_device *pdev) /* setup appropriated routines according to adapter type */ if (macb_is_gem(bp)) { + bp->max_tx_length = GEM_MAX_TX_LEN; bp->macbgem_ops.mog_alloc_rx_buffers = gem_alloc_rx_buffers; bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers; bp->macbgem_ops.mog_init_rings = gem_init_rings; bp->macbgem_ops.mog_rx = gem_rx; } else { + bp->max_tx_length = MACB_MAX_TX_LEN; bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers; bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers; bp->macbgem_ops.mog_init_rings = macb_init_rings; bp->macbgem_ops.mog_rx = macb_rx; } + /* Set features */ + dev->hw_features = NETIF_F_SG; + if (bp->caps & MACB_CAPS_SG_DISABLED) + dev->hw_features &= ~NETIF_F_SG; + dev->features = dev->hw_features; + /* Set MII management clock divider */ config = macb_mdc_clk_div(bp); config |= macb_dbw(bp); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 7ce751be133b..7bf82856043e 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -335,6 +335,7 @@ #define MACB_CAPS_ISR_CLEAR_ON_WRITE 0x00000001 #define MACB_CAPS_FIFO_MODE 0x10000000 #define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000 +#define MACB_CAPS_SG_DISABLED 0x40000000 #define MACB_CAPS_MACB_IS_GEM 0x80000000 /* Bit manipulation macros */ @@ -468,14 +469,23 @@ struct macb_dma_desc { #define MACB_TX_USED_OFFSET 31 #define MACB_TX_USED_SIZE 1 +#define GEM_TX_FRMLEN_OFFSET 0 +#define GEM_TX_FRMLEN_SIZE 14 + /** * struct macb_tx_skb - data about an skb which is being transmitted - * @skb: skb currently being transmitted - * @mapping: DMA address of the skb's data buffer + * @skb: skb currently being transmitted, only set for the last buffer + * of the frame + * @mapping: DMA address of the skb's fragment buffer + * @size: size of the DMA mapped buffer + * @mapped_as_page: true when buffer was mapped with skb_frag_dma_map(), + * false when buffer was mapped with dma_map_single() */ struct macb_tx_skb { struct sk_buff *skb; dma_addr_t mapping; + size_t size; + bool mapped_as_page; }; /* @@ -617,6 +627,7 @@ struct macb { struct sk_buff *skb; /* holds skb until xmit interrupt completes */ dma_addr_t skb_physaddr; /* phys addr from pci_map_single */ int skb_length; /* saved skb length for pci_unmap_single */ + unsigned int max_tx_length; }; extern const struct ethtool_ops macb_ethtool_ops; -- cgit v1.2.3 From 85ff3d87bf2ef1fadcde8553628c60f79806fdb4 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 24 Jul 2014 13:51:00 +0200 Subject: net/macb: add TX checksum offload feature Signed-off-by: Cyrille Pitchen Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 2e4bfe39b502..cc36269474a6 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1525,6 +1525,10 @@ static void macb_configure_dma(struct macb *bp) dmacfg = GEM_BFINS(FBLDO, bp->dma_burst_length, dmacfg); dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L); dmacfg &= ~GEM_BIT(ENDIA); + if (bp->dev->features & NETIF_F_HW_CSUM) + dmacfg |= GEM_BIT(TXCOEN); + else + dmacfg &= ~GEM_BIT(TXCOEN); netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n", dmacfg); gem_writel(bp, DMACFG, dmacfg); @@ -1925,6 +1929,27 @@ int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } EXPORT_SYMBOL_GPL(macb_ioctl); +static int macb_set_features(struct net_device *netdev, + netdev_features_t features) +{ + struct macb *bp = netdev_priv(netdev); + netdev_features_t changed = features ^ netdev->features; + + /* TX checksum offload */ + if ((changed & NETIF_F_HW_CSUM) && macb_is_gem(bp)) { + u32 dmacfg; + + dmacfg = gem_readl(bp, DMACFG); + if (features & NETIF_F_HW_CSUM) + dmacfg |= GEM_BIT(TXCOEN); + else + dmacfg &= ~GEM_BIT(TXCOEN); + gem_writel(bp, DMACFG, dmacfg); + } + + return 0; +} + static const struct net_device_ops macb_netdev_ops = { .ndo_open = macb_open, .ndo_stop = macb_close, @@ -1938,6 +1963,7 @@ static const struct net_device_ops macb_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = macb_poll_controller, #endif + .ndo_set_features = macb_set_features, }; #if defined(CONFIG_OF) @@ -2122,6 +2148,9 @@ static int __init macb_probe(struct platform_device *pdev) /* Set features */ dev->hw_features = NETIF_F_SG; + /* Checksum offload is only available on gem with packet buffer */ + if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE)) + dev->hw_features |= NETIF_F_HW_CSUM; if (bp->caps & MACB_CAPS_SG_DISABLED) dev->hw_features &= ~NETIF_F_SG; dev->features = dev->hw_features; -- cgit v1.2.3 From 924ec53c4130a5013161c463330ddbb12ef306cf Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 24 Jul 2014 13:51:01 +0200 Subject: net/macb: add RX checksum offload feature When RX checksum offload is enabled at GEM level (bit 24 set in the Network Control Register), frames with invalid IP, TCP or UDP checksums are discarted even if promiscuous mode is enabled (bit 4 set in the Network Control Register). This was verified with a simple userspace program, which corrupts UDP checksum using libnetfilter_queue. Then both IFF_PROMISC bit must be clear in dev->flags and NETIF_F_RXCSUM bit must be set in dev->features to enable RX checksum offload at GEM level. This way tcpdump is still able to capture corrupted frames. Also skb->ip_summed is set to CHECKSUM_UNNECESSARY only when both TCP/IP or UDP/IP checksums were verified by the GEM. Indeed the GEM may verify only IP checksum but not the one for ICMP (or other protocol than TCP or UDP). Signed-off-by: Cyrille Pitchen Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 36 ++++++++++++++++++++++++++++++++---- drivers/net/ethernet/cadence/macb.h | 19 +++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index cc36269474a6..6836f88dbdc6 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -765,6 +765,10 @@ static int gem_rx(struct macb *bp, int budget) skb->protocol = eth_type_trans(skb, bp->dev); skb_checksum_none_assert(skb); + if (bp->dev->features & NETIF_F_RXCSUM && + !(bp->dev->flags & IFF_PROMISC) && + GEM_BFEXT(RX_CSUM, ctrl) & GEM_RX_CSUM_CHECKED_MASK) + skb->ip_summed = CHECKSUM_UNNECESSARY; bp->stats.rx_packets++; bp->stats.rx_bytes += skb->len; @@ -1549,6 +1553,8 @@ static void macb_init_hw(struct macb *bp) config |= MACB_BIT(BIG); /* Receive oversized frames */ if (bp->dev->flags & IFF_PROMISC) config |= MACB_BIT(CAF); /* Copy All Frames */ + else if (macb_is_gem(bp) && bp->dev->features & NETIF_F_RXCSUM) + config |= GEM_BIT(RXCOEN); if (!(bp->dev->flags & IFF_BROADCAST)) config |= MACB_BIT(NBC); /* No BroadCast */ config |= macb_dbw(bp); @@ -1662,13 +1668,22 @@ void macb_set_rx_mode(struct net_device *dev) cfg = macb_readl(bp, NCFGR); - if (dev->flags & IFF_PROMISC) + if (dev->flags & IFF_PROMISC) { /* Enable promiscuous mode */ cfg |= MACB_BIT(CAF); - else if (dev->flags & (~IFF_PROMISC)) - /* Disable promiscuous mode */ + + /* Disable RX checksum offload */ + if (macb_is_gem(bp)) + cfg &= ~GEM_BIT(RXCOEN); + } else { + /* Disable promiscuous mode */ cfg &= ~MACB_BIT(CAF); + /* Enable RX checksum offload only if requested */ + if (macb_is_gem(bp) && dev->features & NETIF_F_RXCSUM) + cfg |= GEM_BIT(RXCOEN); + } + if (dev->flags & IFF_ALLMULTI) { /* Enable all multicast mode */ macb_or_gem_writel(bp, HRB, -1); @@ -1947,6 +1962,19 @@ static int macb_set_features(struct net_device *netdev, gem_writel(bp, DMACFG, dmacfg); } + /* RX checksum offload */ + if ((changed & NETIF_F_RXCSUM) && macb_is_gem(bp)) { + u32 netcfg; + + netcfg = gem_readl(bp, NCFGR); + if (features & NETIF_F_RXCSUM && + !(netdev->flags & IFF_PROMISC)) + netcfg |= GEM_BIT(RXCOEN); + else + netcfg &= ~GEM_BIT(RXCOEN); + gem_writel(bp, NCFGR, netcfg); + } + return 0; } @@ -2150,7 +2178,7 @@ static int __init macb_probe(struct platform_device *pdev) dev->hw_features = NETIF_F_SG; /* Checksum offload is only available on gem with packet buffer */ if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE)) - dev->hw_features |= NETIF_F_HW_CSUM; + dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; if (bp->caps & MACB_CAPS_SG_DISABLED) dev->hw_features &= ~NETIF_F_SG; dev->features = dev->hw_features; diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 7bf82856043e..517c09d72c4a 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -164,6 +164,8 @@ #define GEM_CLK_SIZE 3 #define GEM_DBW_OFFSET 21 #define GEM_DBW_SIZE 2 +#define GEM_RXCOEN_OFFSET 24 +#define GEM_RXCOEN_SIZE 1 /* Constants for data bus width. */ #define GEM_DBW32 0 @@ -452,6 +454,14 @@ struct macb_dma_desc { #define MACB_RX_BROADCAST_OFFSET 31 #define MACB_RX_BROADCAST_SIZE 1 +/* RX checksum offload disabled: bit 24 clear in NCFGR */ +#define GEM_RX_TYPEID_MATCH_OFFSET 22 +#define GEM_RX_TYPEID_MATCH_SIZE 2 + +/* RX checksum offload enabled: bit 24 set in NCFGR */ +#define GEM_RX_CSUM_OFFSET 22 +#define GEM_RX_CSUM_SIZE 2 + #define MACB_TX_FRMLEN_OFFSET 0 #define MACB_TX_FRMLEN_SIZE 11 #define MACB_TX_LAST_OFFSET 15 @@ -472,6 +482,15 @@ struct macb_dma_desc { #define GEM_TX_FRMLEN_OFFSET 0 #define GEM_TX_FRMLEN_SIZE 14 +/* Buffer descriptor constants */ +#define GEM_RX_CSUM_NONE 0 +#define GEM_RX_CSUM_IP_ONLY 1 +#define GEM_RX_CSUM_IP_TCP 2 +#define GEM_RX_CSUM_IP_UDP 3 + +/* limit RX checksum offload to TCP and UDP packets */ +#define GEM_RX_CSUM_CHECKED_MASK 2 + /** * struct macb_tx_skb - data about an skb which is being transmitted * @skb: skb currently being transmitted, only set for the last buffer -- cgit v1.2.3 From d58c86ec776cfe43f6fd4e9b6b6c711c941422ca Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 24 Jul 2014 13:51:02 +0200 Subject: ARM: at91: change compatibility string for sama5d3x gem this new compatibility string prevents macb/gem driver from using the scatter-gather and gso features on sama5d3x boards. Signed-off-by: Cyrille Pitchen Signed-off-by: David S. Miller --- arch/arm/boot/dts/sama5d3_gmac.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sama5d3_gmac.dtsi b/arch/arm/boot/dts/sama5d3_gmac.dtsi index a6cb0508762f..de5ed59fb446 100644 --- a/arch/arm/boot/dts/sama5d3_gmac.dtsi +++ b/arch/arm/boot/dts/sama5d3_gmac.dtsi @@ -74,7 +74,7 @@ }; macb0: ethernet@f0028000 { - compatible = "cdns,pc302-gem", "cdns,gem"; + compatible = "atmel,sama5d3-gem"; reg = <0xf0028000 0x100>; interrupts = <34 IRQ_TYPE_LEVEL_HIGH 3>; pinctrl-names = "default"; -- cgit v1.2.3 From 4b7b0e4f25612cc204e550018ee8c087a2062a6b Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 24 Jul 2014 13:51:03 +0200 Subject: net/macb: enable scatter-gather feature and set DMA burst length for sama5d4 gem Signed-off-by: Cyrille Pitchen Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 6836f88dbdc6..ca5d7798b265 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2005,6 +2005,11 @@ static struct macb_config sama5d3_config = { .dma_burst_length = 16, }; +static struct macb_config sama5d4_config = { + .caps = 0, + .dma_burst_length = 4, +}; + static const struct of_device_id macb_dt_ids[] = { { .compatible = "cdns,at32ap7000-macb" }, { .compatible = "cdns,at91sam9260-macb" }, @@ -2012,6 +2017,7 @@ static const struct of_device_id macb_dt_ids[] = { { .compatible = "cdns,pc302-gem", .data = &pc302gem_config }, { .compatible = "cdns,gem", .data = &pc302gem_config }, { .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config }, + { .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, macb_dt_ids); -- cgit v1.2.3 From ac3d2e5a9ef2f4d8f57c50070c4883ecb7cec29f Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Fri, 25 Jul 2014 14:45:11 +0800 Subject: ipv6: remove obsolete comment in ip6_append_data() After 11878b40e[net-timestamp: SOCK_RAW and PING timestamping], this comment becomes obsolete since the codes check not only UDP socket, but also RAW sock; and the codes are clear, not need the comments Signed-off-by: Li RongQing Signed-off-by: David S. Miller --- net/ipv6/ip6_output.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 759456f0c207..2e339d241b69 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1270,7 +1270,6 @@ emsgsize: } } - /* For UDP, check if TX timestamp is enabled */ if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) sock_tx_timestamp(sk, &tx_flags); -- cgit v1.2.3 From aa5b4fbcff48234280359da84ac24e6f3057325b Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 23 Jul 2014 12:20:33 +0200 Subject: ath10k: fix Rx aggregation reordering Firmware doesn't perform Rx reordering so it is left to the host driver to do that. Use mac80211 to perform reordering instead of re-inventing the wheel. This fixes TCP throughput issues in some environments. Reported-by: Denton Gentry Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 92 +++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/mac.c | 33 ++++++++++++ drivers/net/wireless/ath/ath10k/txrx.c | 3 +- drivers/net/wireless/ath/ath10k/txrx.h | 1 + 4 files changed, 126 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 318efc35d116..77cdc21e28d7 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -21,6 +21,7 @@ #include "txrx.h" #include "debug.h" #include "trace.h" +#include "mac.h" #include @@ -1422,6 +1423,86 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar, } } +static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp) +{ + struct htt_rx_addba *ev = &resp->rx_addba; + struct ath10k_peer *peer; + struct ath10k_vif *arvif; + u16 info0, tid, peer_id; + + info0 = __le16_to_cpu(ev->info0); + tid = MS(info0, HTT_RX_BA_INFO0_TID); + peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID); + + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx addba tid %hu peer_id %hu size %hhu\n", + tid, peer_id, ev->window_size); + + spin_lock_bh(&ar->data_lock); + peer = ath10k_peer_find_by_id(ar, peer_id); + if (!peer) { + ath10k_warn("received addba event for invalid peer_id: %hu\n", + peer_id); + spin_unlock_bh(&ar->data_lock); + return; + } + + arvif = ath10k_get_arvif(ar, peer->vdev_id); + if (!arvif) { + ath10k_warn("received addba event for invalid vdev_id: %u\n", + peer->vdev_id); + spin_unlock_bh(&ar->data_lock); + return; + } + + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx start rx ba session sta %pM tid %hu size %hhu\n", + peer->addr, tid, ev->window_size); + + ieee80211_start_rx_ba_session_offl(arvif->vif, peer->addr, tid); + spin_unlock_bh(&ar->data_lock); +} + +static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp) +{ + struct htt_rx_delba *ev = &resp->rx_delba; + struct ath10k_peer *peer; + struct ath10k_vif *arvif; + u16 info0, tid, peer_id; + + info0 = __le16_to_cpu(ev->info0); + tid = MS(info0, HTT_RX_BA_INFO0_TID); + peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID); + + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx delba tid %hu peer_id %hu\n", + tid, peer_id); + + spin_lock_bh(&ar->data_lock); + peer = ath10k_peer_find_by_id(ar, peer_id); + if (!peer) { + ath10k_warn("received addba event for invalid peer_id: %hu\n", + peer_id); + spin_unlock_bh(&ar->data_lock); + return; + } + + arvif = ath10k_get_arvif(ar, peer->vdev_id); + if (!arvif) { + ath10k_warn("received addba event for invalid vdev_id: %u\n", + peer->vdev_id); + spin_unlock_bh(&ar->data_lock); + return; + } + + ath10k_dbg(ATH10K_DBG_HTT, + "htt rx stop rx ba session sta %pM tid %hu\n", + peer->addr, tid); + + ieee80211_stop_rx_ba_session_offl(arvif->vif, peer->addr, tid); + spin_unlock_bh(&ar->data_lock); +} + void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) { struct ath10k_htt *htt = &ar->htt; @@ -1524,8 +1605,17 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) ath10k_warn("received an unexpected htt tx inspect event\n"); break; case HTT_T2H_MSG_TYPE_RX_ADDBA: + ath10k_htt_rx_addba(ar, resp); + break; case HTT_T2H_MSG_TYPE_RX_DELBA: - case HTT_T2H_MSG_TYPE_RX_FLUSH: + ath10k_htt_rx_delba(ar, resp); + break; + case HTT_T2H_MSG_TYPE_RX_FLUSH: { + /* Ignore this event because mac80211 takes care of Rx + * aggregation reordering. + */ + break; + } default: ath10k_dbg(ATH10K_DBG_HTT, "htt event (%d) not handled\n", resp->hdr.msg_type); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3f9afaa93cca..3baa22915339 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4333,6 +4333,38 @@ static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) return 0; } +static int ath10k_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) +{ + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + + ath10k_dbg(ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n", + arvif->vdev_id, sta->addr, tid, action); + + switch (action) { + case IEEE80211_AMPDU_RX_START: + case IEEE80211_AMPDU_RX_STOP: + /* HTT AddBa/DelBa events trigger mac80211 Rx BA session + * creation/removal. Do we need to verify this? + */ + return 0; + case IEEE80211_AMPDU_TX_START: + case IEEE80211_AMPDU_TX_STOP_CONT: + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + case IEEE80211_AMPDU_TX_OPERATIONAL: + /* Firmware offloads Tx aggregation entirely so deny mac80211 + * Tx aggregation requests. + */ + return -EOPNOTSUPP; + } + + return -EINVAL; +} + static const struct ieee80211_ops ath10k_ops = { .tx = ath10k_tx, .start = ath10k_start, @@ -4360,6 +4392,7 @@ static const struct ieee80211_ops ath10k_ops = { .set_bitrate_mask = ath10k_set_bitrate_mask, .sta_rc_update = ath10k_sta_rc_update, .get_tsf = ath10k_get_tsf, + .ampdu_action = ath10k_ampdu_action, #ifdef CONFIG_PM .suspend = ath10k_suspend, .resume = ath10k_resume, diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 82669a77e553..f4fa22d1d591 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -119,8 +119,7 @@ struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, return NULL; } -static struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, - int peer_id) +struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id) { struct ath10k_peer *peer; diff --git a/drivers/net/wireless/ath/ath10k/txrx.h b/drivers/net/wireless/ath/ath10k/txrx.h index aee3e20058f8..a90e09f5c7f2 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.h +++ b/drivers/net/wireless/ath/ath10k/txrx.h @@ -24,6 +24,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, const u8 *addr); +struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id); int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id, const u8 *addr); int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id, -- cgit v1.2.3 From cf850d1d23942ad7fb3c22cb848decec86c101b0 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 24 Jul 2014 20:07:00 +0300 Subject: ath10k: don't advertise IBSS iftype for 10.x The 10.x firmware does not support IBSS mode at all. It can't beacon and it crashes when trying to scan. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3baa22915339..9d61bb157189 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4733,7 +4733,6 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { @@ -4803,6 +4802,8 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->iface_combinations = ath10k_if_comb; ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_if_comb); + + ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); } ar->hw->netdev_features = NETIF_F_HW_CSUM; -- cgit v1.2.3 From 0ccb7a3485e5526dca69f036b0d6c5148c78b3f8 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Fri, 25 Jul 2014 11:28:50 +0300 Subject: ath10k: handle attention flags correctly when using A-MSDU In case of A-MSDU RX we should check attention flags correctly to be sure we report correct FCS status for A-MSDU subframes. Without a patch we could report A-MSDU subframes with wrong FCS as a correct to the stack, next get a lot of DUP ACK TCP packets. Finally TP drop is seen and this drop depends on FCS errors ratio for A-MSDU frame. Example test case when TP drop is seen: - ath10k configured as an AP - used ath10k station - forced A-MSDU (7 frames) on STA - other traffic on channel (often FCS errors) - monitor iface added on AP - TCP STA -> AP traffic (iperf) a) Iperf logs for case without the patch: echo "1 64" > htt_max_amsdu_ampdu // disable A-MSDU [ ID] Interval Transfer Bandwidth [ 3] 0.0- 5.0 sec 56.6 MBytes 95.0 Mbits/sec [ 3] 5.0-10.0 sec 60.4 MBytes 101 Mbits/sec [ 3] 10.0-15.0 sec 60.2 MBytes 101 Mbits/sec [ 3] 15.0-20.0 sec 60.2 MBytes 101 Mbits/sec [ 3] 20.0-25.0 sec 63.8 MBytes 107 Mbits/sec [ 3] 25.0-30.0 sec 64.9 MBytes 109 Mbits/sec echo "7 64" > htt_max_amsdu_ampdu // set 7 A-MSDU subframes [ 3] 30.0-35.0 sec 40.0 MBytes 67.1 Mbits/sec [ 3] 35.0-40.0 sec 35.9 MBytes 60.2 Mbits/sec [ 3] 40.0-45.0 sec 36.9 MBytes 61.9 Mbits/sec [ 3] 45.0-50.0 sec 37.9 MBytes 63.5 Mbits/sec [ 3] 50.0-55.0 sec 34.5 MBytes 57.9 Mbits/sec [ 3] 55.0-60.0 sec 25.4 MBytes 42.6 Mbits/sec [ 3] 60.0-65.0 sec 48.2 MBytes 81.0 Mbits/sec [ 3] 65.0-70.0 sec 28.8 MBytes 48.2 Mbits/sec [ 3] 70.0-75.0 sec 29.2 MBytes 49.1 Mbits/sec [ 3] 75.0-80.0 sec 22.9 MBytes 38.4 Mbits/sec [ 3] 80.0-85.0 sec 26.4 MBytes 44.2 Mbits/sec [ 3] 85.0-90.0 sec 31.5 MBytes 52.8 Mbits/sec b) Iperf logs for case with patch: echo "1 64" > htt_max_amsdu_ampdu // disable A-MSDU [ 3] local 192.168.12.2 port 57512 connected with 192.168.12.1 port 5001 [ ID] Interval Transfer Bandwidth [ 3] 0.0- 5.0 sec 60.8 MBytes 102 Mbits/sec [ 3] 5.0-10.0 sec 62.2 MBytes 104 Mbits/sec [ 3] 10.0-15.0 sec 60.9 MBytes 102 Mbits/sec echo "7 64" > htt_max_amsdu_ampdu // set 7 A-MSDU subframes [ 3] 15.0-20.0 sec 68.1 MBytes 114 Mbits/sec [ 3] 20.0-25.0 sec 80.5 MBytes 135 Mbits/sec [ 3] 25.0-30.0 sec 83.0 MBytes 139 Mbits/sec [ 3] 30.0-35.0 sec 79.1 MBytes 133 Mbits/sec [ 3] 35.0-40.0 sec 77.1 MBytes 129 Mbits/sec [ 3] 40.0-45.0 sec 77.4 MBytes 130 Mbits/sec Reported-by: Denton Gentry Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 77cdc21e28d7..80cdac15588a 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -308,7 +308,8 @@ static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb) static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, u8 **fw_desc, int *fw_desc_len, struct sk_buff **head_msdu, - struct sk_buff **tail_msdu) + struct sk_buff **tail_msdu, + u32 *attention) { int msdu_len, msdu_chaining = 0; struct sk_buff *msdu; @@ -358,6 +359,11 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, break; } + *attention |= __le32_to_cpu(rx_desc->attention.flags) & + (RX_ATTENTION_FLAGS_TKIP_MIC_ERR | + RX_ATTENTION_FLAGS_DECRYPT_ERR | + RX_ATTENTION_FLAGS_FCS_ERR | + RX_ATTENTION_FLAGS_MGMT_TYPE); /* * Copy the FW rx descriptor for this MSDU from the rx * indication message into the MSDU's netbuf. HL uses the @@ -1216,13 +1222,15 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) { struct sk_buff *msdu_head, *msdu_tail; + attention = 0; msdu_head = NULL; msdu_tail = NULL; ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, &msdu_head, - &msdu_tail); + &msdu_tail, + &attention); if (ret < 0) { ath10k_warn("failed to pop amsdu from htt rx ring %d\n", @@ -1234,7 +1242,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, rxd = container_of((void *)msdu_head->data, struct htt_rx_desc, msdu_payload); - attention = __le32_to_cpu(rxd->attention.flags); if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head, status, @@ -1287,6 +1294,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, u8 *fw_desc; int fw_desc_len, hdrlen, paramlen; int trim; + u32 attention = 0; fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes); fw_desc = (u8 *)frag->fw_msdu_rx_desc; @@ -1296,7 +1304,8 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, spin_lock_bh(&htt->rx_ring.lock); ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, - &msdu_head, &msdu_tail); + &msdu_head, &msdu_tail, + &attention); spin_unlock_bh(&htt->rx_ring.lock); ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); @@ -1313,10 +1322,8 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, hdr = (struct ieee80211_hdr *)msdu_head->data; rxd = (void *)msdu_head->data - sizeof(*rxd); - tkip_mic_err = !!(__le32_to_cpu(rxd->attention.flags) & - RX_ATTENTION_FLAGS_TKIP_MIC_ERR); - decrypt_err = !!(__le32_to_cpu(rxd->attention.flags) & - RX_ATTENTION_FLAGS_DECRYPT_ERR); + tkip_mic_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR); + decrypt_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR); fmt = MS(__le32_to_cpu(rxd->msdu_start.info1), RX_MSDU_START_INFO1_DECAP_FORMAT); -- cgit v1.2.3 From 5bd3a76f4ba37108101c2ae93172571a70505982 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 25 Jul 2014 01:47:16 +0530 Subject: netfilter: nf_conntrack: remove exceptional & on function name In this file, function names are otherwise used as pointers without &. A simplified version of the Coccinelle semantic patch that makes this change is as follows: // @r@ identifier f; @@ f(...) { ... } @@ identifier r.f; @@ - &f + f // Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 4ce44c4bc57b..a054fe083431 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -358,7 +358,7 @@ static struct nf_sockopt_ops so_getorigdst = { .pf = PF_INET, .get_optmin = SO_ORIGINAL_DST, .get_optmax = SO_ORIGINAL_DST+1, - .get = &getorigdst, + .get = getorigdst, .owner = THIS_MODULE, }; -- cgit v1.2.3 From a2b60c75fa951f6e1ffa46c0f459d164d52699bf Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Fri, 25 Jul 2014 09:06:27 +0800 Subject: netfilter: xt_LED: don't output error message redundantly The function led_trigger_register() will only return -EEXIST when error arises. Signed-off-by: Duan Jiong Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_LED.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c index 993de2ba89d3..f14bcf23dc9f 100644 --- a/net/netfilter/xt_LED.c +++ b/net/netfilter/xt_LED.c @@ -133,9 +133,7 @@ static int led_tg_check(const struct xt_tgchk_param *par) err = led_trigger_register(&ledinternal->netfilter_led_trigger); if (err) { - pr_warning("led_trigger_register() failed\n"); - if (err == -EEXIST) - pr_warning("Trigger name is already in use.\n"); + pr_err("Trigger name is already in use.\n"); goto exit_alloc; } -- cgit v1.2.3 From d4da843e6fad4f278fe82b075d8e394cff05c95c Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Fri, 25 Jul 2014 14:25:31 +0200 Subject: netfilter: kill remnants of ulog targets The ulog targets were recently killed. A few references to the Kconfig macros CONFIG_IP_NF_TARGET_ULOG and CONFIG_BRIDGE_EBT_ULOG were left untouched. Kill these too. Signed-off-by: Paul Bolle Signed-off-by: Pablo Neira Ayuso --- include/net/netns/x_tables.h | 6 ------ net/bridge/netfilter/Makefile | 1 - net/ipv4/netfilter/Makefile | 1 - 3 files changed, 8 deletions(-) diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h index 02fe40f8c8fd..c24060ee411e 100644 --- a/include/net/netns/x_tables.h +++ b/include/net/netns/x_tables.h @@ -15,11 +15,5 @@ struct netns_xt { struct ebt_table *frame_filter; struct ebt_table *frame_nat; #endif -#if IS_ENABLED(CONFIG_IP_NF_TARGET_ULOG) - bool ulog_warn_deprecated; -#endif -#if IS_ENABLED(CONFIG_BRIDGE_EBT_ULOG) - bool ebt_ulog_warn_deprecated; -#endif }; #endif diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile index 061d121cf8b9..be4d0cea78ce 100644 --- a/net/bridge/netfilter/Makefile +++ b/net/bridge/netfilter/Makefile @@ -37,5 +37,4 @@ obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o # watchers obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o -obj-$(CONFIG_BRIDGE_EBT_ULOG) += ebt_ulog.o obj-$(CONFIG_BRIDGE_EBT_NFLOG) += ebt_nflog.o diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 245db9df3337..33001621465b 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -57,7 +57,6 @@ obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o obj-$(CONFIG_IP_NF_TARGET_SYNPROXY) += ipt_SYNPROXY.o -obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o # generic ARP tables obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o -- cgit v1.2.3 From 8452e6ff3efce76335eba9d29d2a5b3b524b9f1f Mon Sep 17 00:00:00 2001 From: Jiri Prchal Date: Fri, 25 Jul 2014 15:58:33 +0200 Subject: netfilter: xt_LED: fix too short led-always-blink If led-always-blink is set, then between switch led OFF and ON is almost zero time. So blink is invisible. This use oneshot led trigger with fixed time 50ms witch is enough to see blink. Signed-off-by: Jiri Prchal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_LED.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c index 993de2ba89d3..92c71cdc4739 100644 --- a/net/netfilter/xt_LED.c +++ b/net/netfilter/xt_LED.c @@ -50,11 +50,14 @@ struct xt_led_info_internal { struct timer_list timer; }; +#define XT_LED_BLINK_DELAY 50 /* ms */ + static unsigned int led_tg(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_led_info *ledinfo = par->targinfo; struct xt_led_info_internal *ledinternal = ledinfo->internal_data; + unsigned long led_delay = XT_LED_BLINK_DELAY; /* * If "always blink" is enabled, and there's still some time until the @@ -62,9 +65,10 @@ led_tg(struct sk_buff *skb, const struct xt_action_param *par) */ if ((ledinfo->delay > 0) && ledinfo->always_blink && timer_pending(&ledinternal->timer)) - led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF); - - led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL); + led_trigger_blink_oneshot(&ledinternal->netfilter_led_trigger, + &led_delay, &led_delay, 1); + else + led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL); /* If there's a positive delay, start/update the timer */ if (ledinfo->delay > 0) { -- cgit v1.2.3 From d819fc52117e18e9e331edc8fe7bd623279825d0 Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 22 Jul 2014 06:50:36 +0000 Subject: ixgbe: Convert some udelays to usleep_range Convert some udelay calls to the preferred usleep_range. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 6 +++--- drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 3f318c52e053..db759f98f9f0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -1386,7 +1386,7 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) status = 0; break; } - udelay(50); + usleep_range(50, 100); } if (i == timeout) { @@ -1399,7 +1399,7 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) */ ixgbe_release_eeprom_semaphore(hw); - udelay(50); + usleep_range(50, 100); /* * one last try * If the SMBI bit is 0 when we read it, then the bit will be @@ -1427,7 +1427,7 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) if (swsm & IXGBE_SWSM_SWESMBI) break; - udelay(50); + usleep_range(50, 100); } /* diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index 40dd798e1290..942ad13c684a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -699,7 +699,7 @@ static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw) status = 0; break; } - udelay(50); + usleep_range(50, 100); } /* Now get the semaphore between SW/FW through the REGSMP bit */ @@ -709,7 +709,7 @@ static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw) if (!(swsm & IXGBE_SWFW_REGSMP)) break; - udelay(50); + usleep_range(50, 100); } } else { hw_dbg(hw, "Software semaphore SMBI between device drivers not granted.\n"); -- cgit v1.2.3 From e4856696b4afbf53a84e0475149369b78b47f713 Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 22 Jul 2014 06:50:42 +0000 Subject: ixgbe: Fix spurious release of semaphore in EEPROM access Failure to acquire the semaphore would lead to a spurious release of the semaphore in several functions. Do not release a semaphore that you did not get. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 123 +++++++++++--------------- 1 file changed, 53 insertions(+), 70 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index 942ad13c684a..efdb517b8fc2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 2014 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -258,13 +258,12 @@ static s32 ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw) **/ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) { - s32 status = 0; + s32 status; - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == - 0) - status = ixgbe_read_eerd_generic(hw, offset, data); - else - status = IXGBE_ERR_SWFW_SYNC; + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM)) + return IXGBE_ERR_SWFW_SYNC; + + status = ixgbe_read_eerd_generic(hw, offset, data); hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; @@ -282,14 +281,12 @@ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) static s32 ixgbe_read_eerd_buffer_X540(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - s32 status = 0; + s32 status; - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == - 0) - status = ixgbe_read_eerd_buffer_generic(hw, offset, - words, data); - else - status = IXGBE_ERR_SWFW_SYNC; + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM)) + return IXGBE_ERR_SWFW_SYNC; + + status = ixgbe_read_eerd_buffer_generic(hw, offset, words, data); hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; @@ -305,12 +302,12 @@ static s32 ixgbe_read_eerd_buffer_X540(struct ixgbe_hw *hw, **/ static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data) { - s32 status = 0; + s32 status; - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) - status = ixgbe_write_eewr_generic(hw, offset, data); - else - status = IXGBE_ERR_SWFW_SYNC; + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM)) + return IXGBE_ERR_SWFW_SYNC; + + status = ixgbe_write_eewr_generic(hw, offset, data); hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; @@ -328,14 +325,12 @@ static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data) static s32 ixgbe_write_eewr_buffer_X540(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - s32 status = 0; + s32 status; - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == - 0) - status = ixgbe_write_eewr_buffer_generic(hw, offset, - words, data); - else - status = IXGBE_ERR_SWFW_SYNC; + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM)) + return IXGBE_ERR_SWFW_SYNC; + + status = ixgbe_write_eewr_buffer_generic(hw, offset, words, data); hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; @@ -430,44 +425,37 @@ static s32 ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw, u16 checksum; u16 read_checksum = 0; - /* - * Read the first word from the EEPROM. If this times out or fails, do + /* Read the first word from the EEPROM. If this times out or fails, do * not continue or we could be in for a very long wait while every * EEPROM read fails */ status = hw->eeprom.ops.read(hw, 0, &checksum); - - if (status != 0) { + if (status) { hw_dbg(hw, "EEPROM read failed\n"); - goto out; + return status; } - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { - checksum = hw->eeprom.ops.calc_checksum(hw); + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM)) + return IXGBE_ERR_SWFW_SYNC; - /* - * Do not use hw->eeprom.ops.read because we do not want to take - * the synchronization semaphores twice here. - */ - ixgbe_read_eerd_generic(hw, IXGBE_EEPROM_CHECKSUM, - &read_checksum); - - /* - * Verify read checksum from EEPROM is the same as - * calculated checksum - */ - if (read_checksum != checksum) - status = IXGBE_ERR_EEPROM_CHECKSUM; + checksum = hw->eeprom.ops.calc_checksum(hw); - /* If the user cares, return the calculated checksum */ - if (checksum_val) - *checksum_val = checksum; - } else { - status = IXGBE_ERR_SWFW_SYNC; - } + /* Do not use hw->eeprom.ops.read because we do not want to take + * the synchronization semaphores twice here. + */ + status = ixgbe_read_eerd_generic(hw, IXGBE_EEPROM_CHECKSUM, + &read_checksum); hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); -out: + + /* If the user cares, return the calculated checksum */ + if (checksum_val) + *checksum_val = checksum; + + /* Verify read and calculated checksums are the same */ + if (read_checksum != checksum) + return IXGBE_ERR_EEPROM_CHECKSUM; + return status; } @@ -484,34 +472,29 @@ static s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw) s32 status; u16 checksum; - /* - * Read the first word from the EEPROM. If this times out or fails, do + /* Read the first word from the EEPROM. If this times out or fails, do * not continue or we could be in for a very long wait while every * EEPROM read fails */ status = hw->eeprom.ops.read(hw, 0, &checksum); - - if (status != 0) + if (status) { hw_dbg(hw, "EEPROM read failed\n"); + return status; + } - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { - checksum = hw->eeprom.ops.calc_checksum(hw); + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM)) + return IXGBE_ERR_SWFW_SYNC; - /* - * Do not use hw->eeprom.ops.write because we do not want to - * take the synchronization semaphores twice here. - */ - status = ixgbe_write_eewr_generic(hw, IXGBE_EEPROM_CHECKSUM, - checksum); + checksum = hw->eeprom.ops.calc_checksum(hw); - if (status == 0) + /* Do not use hw->eeprom.ops.write because we do not want to + * take the synchronization semaphores twice here. + */ + status = ixgbe_write_eewr_generic(hw, IXGBE_EEPROM_CHECKSUM, checksum); + if (!status) status = ixgbe_update_flash_X540(hw); - else - status = IXGBE_ERR_SWFW_SYNC; - } hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); - return status; } -- cgit v1.2.3 From acb1ce223b3e6a340e46fe7b21a9dd4797618ace Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 22 Jul 2014 06:50:47 +0000 Subject: ixgbe: Correct X540 semaphore error In the function ixgbe_get_swfw_sync_semaphore, an incorrect check was treating success as failure and vice-versa. This led to manipulating the IXGBE_SWFW_SYNC register without holding the software semaphore first, which is an error. In addition, if getting the REGSMP bit in the IXGBE_SW_FW_SYNC register timed out, no error code would be returned, making the caller think that it had successfully acquired the lock. Fix both of those issues and clean up the function a bit, such as make the name in the comment match the function. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 34 +++++++++++++-------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index efdb517b8fc2..1e26794febd6 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -659,46 +659,44 @@ static void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) } /** - * ixgbe_get_nvm_semaphore - Get hardware semaphore + * ixgbe_get_swfw_sync_semaphore - Get hardware semaphore * @hw: pointer to hardware structure * * Sets the hardware semaphores so SW/FW can gain control of shared resources - **/ + */ static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw) { - s32 status = IXGBE_ERR_EEPROM; u32 timeout = 2000; u32 i; u32 swsm; /* Get SMBI software semaphore between device drivers first */ for (i = 0; i < timeout; i++) { - /* - * If the SMBI bit is 0 when we read it, then the bit will be + /* If the SMBI bit is 0 when we read it, then the bit will be * set and we have the semaphore */ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); - if (!(swsm & IXGBE_SWSM_SMBI)) { - status = 0; + if (!(swsm & IXGBE_SWSM_SMBI)) break; - } usleep_range(50, 100); } + if (i == timeout) { + hw_dbg(hw, + "Software semaphore SMBI between device drivers not granted.\n"); + return IXGBE_ERR_EEPROM; + } + /* Now get the semaphore between SW/FW through the REGSMP bit */ - if (status) { - for (i = 0; i < timeout; i++) { - swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC); - if (!(swsm & IXGBE_SWFW_REGSMP)) - break; + for (i = 0; i < timeout; i++) { + swsm = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC); + if (!(swsm & IXGBE_SWFW_REGSMP)) + return 0; - usleep_range(50, 100); - } - } else { - hw_dbg(hw, "Software semaphore SMBI between device drivers not granted.\n"); + usleep_range(50, 100); } - return status; + return IXGBE_ERR_EEPROM; } /** -- cgit v1.2.3 From 4e86281b59ce7881cc21dfb6fb4b596f737d6ee5 Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 22 Jul 2014 06:50:52 +0000 Subject: ixgbe: Fix ixgbe_write_mbx error result If ixgbe_write_mbx is called and no mbx->ops.write method exists, no error code is returned. The corresponding read function explicitly returns an error in such a case as do other functions, so this appears to be a minor bug. Fix it for consistency, and generate return values directly to make things clearer. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c index 1918e0abf734..50479575e131 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 2014 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -67,15 +67,14 @@ s32 ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) s32 ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = 0; if (size > mbx->size) - ret_val = IXGBE_ERR_MBX; + return IXGBE_ERR_MBX; - else if (mbx->ops.write) - ret_val = mbx->ops.write(hw, msg, size, mbx_id); + if (!mbx->ops.write) + return IXGBE_ERR_MBX; - return ret_val; + return mbx->ops.write(hw, msg, size, mbx_id); } /** -- cgit v1.2.3 From f0ff353a863f61c5cd1899312e7adaa776e80a92 Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 22 Jul 2014 06:50:58 +0000 Subject: ixgbe: Delete a bunch of dead code All of the code involved with returning the supported physical layer is actually unused, so delete it. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c | 101 -------------------- drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c | 127 ------------------------- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 20 ---- drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 27 ------ 4 files changed, 275 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index 206171f732fb..681e3205038d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -1108,106 +1108,6 @@ static s32 ixgbe_read_i2c_sff8472_82598(struct ixgbe_hw *hw, u8 byte_offset, byte_offset, sff8472_data); } -/** - * ixgbe_get_supported_physical_layer_82598 - Returns physical layer type - * @hw: pointer to hardware structure - * - * Determines physical layer capabilities of the current configuration. - **/ -static u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) -{ - u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; - u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); - u32 pma_pmd_10g = autoc & IXGBE_AUTOC_10G_PMA_PMD_MASK; - u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; - u16 ext_ability = 0; - - hw->phy.ops.identify(hw); - - /* Copper PHY must be checked before AUTOC LMS to determine correct - * physical layer because 10GBase-T PHYs use LMS = KX4/KX */ - switch (hw->phy.type) { - case ixgbe_phy_tn: - case ixgbe_phy_cu_unknown: - hw->phy.ops.read_reg(hw, MDIO_PMA_EXTABLE, - MDIO_MMD_PMAPMD, &ext_ability); - if (ext_ability & MDIO_PMA_EXTABLE_10GBT) - physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T; - if (ext_ability & MDIO_PMA_EXTABLE_1000BT) - physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; - if (ext_ability & MDIO_PMA_EXTABLE_100BTX) - physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX; - goto out; - default: - break; - } - - switch (autoc & IXGBE_AUTOC_LMS_MASK) { - case IXGBE_AUTOC_LMS_1G_AN: - case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: - if (pma_pmd_1g == IXGBE_AUTOC_1G_KX) - physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_KX; - else - physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_BX; - break; - case IXGBE_AUTOC_LMS_10G_LINK_NO_AN: - if (pma_pmd_10g == IXGBE_AUTOC_10G_CX4) - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; - else if (pma_pmd_10g == IXGBE_AUTOC_10G_KX4) - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KX4; - else /* XAUI */ - physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; - break; - case IXGBE_AUTOC_LMS_KX4_AN: - case IXGBE_AUTOC_LMS_KX4_AN_1G_AN: - if (autoc & IXGBE_AUTOC_KX_SUPP) - physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_KX; - if (autoc & IXGBE_AUTOC_KX4_SUPP) - physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_KX4; - break; - default: - break; - } - - if (hw->phy.type == ixgbe_phy_nl) { - hw->phy.ops.identify_sfp(hw); - - switch (hw->phy.sfp_type) { - case ixgbe_sfp_type_da_cu: - physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; - break; - case ixgbe_sfp_type_sr: - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; - break; - case ixgbe_sfp_type_lr: - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; - break; - default: - physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; - break; - } - } - - switch (hw->device_id) { - case IXGBE_DEV_ID_82598_DA_DUAL_PORT: - physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; - break; - case IXGBE_DEV_ID_82598AF_DUAL_PORT: - case IXGBE_DEV_ID_82598AF_SINGLE_PORT: - case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; - break; - case IXGBE_DEV_ID_82598EB_XF_LR: - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; - break; - default: - break; - } - -out: - return physical_layer; -} - /** * ixgbe_set_lan_id_multi_port_pcie_82598 - Set LAN id for PCIe multiple * port devices. @@ -1285,7 +1185,6 @@ static struct ixgbe_mac_operations mac_ops_82598 = { .start_hw = &ixgbe_start_hw_82598, .clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic, .get_media_type = &ixgbe_get_media_type_82598, - .get_supported_physical_layer = &ixgbe_get_supported_physical_layer_82598, .enable_rx_dma = &ixgbe_enable_rx_dma_generic, .get_mac_addr = &ixgbe_get_mac_addr_generic, .stop_adapter = &ixgbe_stop_adapter_generic, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 0373a5b9219f..6fc633a2726a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -1979,132 +1979,6 @@ out: return status; } -/** - * ixgbe_get_supported_physical_layer_82599 - Returns physical layer type - * @hw: pointer to hardware structure - * - * Determines physical layer capabilities of the current configuration. - **/ -static u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw) -{ - u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; - u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); - u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); - u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK; - u32 pma_pmd_10g_parallel = autoc & IXGBE_AUTOC_10G_PMA_PMD_MASK; - u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; - u16 ext_ability = 0; - u8 comp_codes_10g = 0; - u8 comp_codes_1g = 0; - - hw->phy.ops.identify(hw); - - switch (hw->phy.type) { - case ixgbe_phy_tn: - case ixgbe_phy_cu_unknown: - hw->phy.ops.read_reg(hw, MDIO_PMA_EXTABLE, MDIO_MMD_PMAPMD, - &ext_ability); - if (ext_ability & MDIO_PMA_EXTABLE_10GBT) - physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T; - if (ext_ability & MDIO_PMA_EXTABLE_1000BT) - physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; - if (ext_ability & MDIO_PMA_EXTABLE_100BTX) - physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX; - goto out; - default: - break; - } - - switch (autoc & IXGBE_AUTOC_LMS_MASK) { - case IXGBE_AUTOC_LMS_1G_AN: - case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: - if (pma_pmd_1g == IXGBE_AUTOC_1G_KX_BX) { - physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_KX | - IXGBE_PHYSICAL_LAYER_1000BASE_BX; - goto out; - } else - /* SFI mode so read SFP module */ - goto sfp_check; - break; - case IXGBE_AUTOC_LMS_10G_LINK_NO_AN: - if (pma_pmd_10g_parallel == IXGBE_AUTOC_10G_CX4) - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; - else if (pma_pmd_10g_parallel == IXGBE_AUTOC_10G_KX4) - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KX4; - else if (pma_pmd_10g_parallel == IXGBE_AUTOC_10G_XAUI) - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_XAUI; - goto out; - case IXGBE_AUTOC_LMS_10G_SERIAL: - if (pma_pmd_10g_serial == IXGBE_AUTOC2_10G_KR) { - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KR; - goto out; - } else if (pma_pmd_10g_serial == IXGBE_AUTOC2_10G_SFI) - goto sfp_check; - break; - case IXGBE_AUTOC_LMS_KX4_KX_KR: - case IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN: - if (autoc & IXGBE_AUTOC_KX_SUPP) - physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_KX; - if (autoc & IXGBE_AUTOC_KX4_SUPP) - physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_KX4; - if (autoc & IXGBE_AUTOC_KR_SUPP) - physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_KR; - goto out; - default: - goto out; - } - -sfp_check: - /* SFP check must be done last since DA modules are sometimes used to - * test KR mode - we need to id KR mode correctly before SFP module. - * Call identify_sfp because the pluggable module may have changed */ - hw->phy.ops.identify_sfp(hw); - if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) - goto out; - - switch (hw->phy.type) { - case ixgbe_phy_sfp_passive_tyco: - case ixgbe_phy_sfp_passive_unknown: - case ixgbe_phy_qsfp_passive_unknown: - physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; - break; - case ixgbe_phy_sfp_ftl_active: - case ixgbe_phy_sfp_active_unknown: - case ixgbe_phy_qsfp_active_unknown: - physical_layer = IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA; - break; - case ixgbe_phy_sfp_avago: - case ixgbe_phy_sfp_ftl: - case ixgbe_phy_sfp_intel: - case ixgbe_phy_sfp_unknown: - hw->phy.ops.read_i2c_eeprom(hw, - IXGBE_SFF_1GBE_COMP_CODES, &comp_codes_1g); - hw->phy.ops.read_i2c_eeprom(hw, - IXGBE_SFF_10GBE_COMP_CODES, &comp_codes_10g); - if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; - else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; - else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) - physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_T; - break; - case ixgbe_phy_qsfp_intel: - case ixgbe_phy_qsfp_unknown: - hw->phy.ops.read_i2c_eeprom(hw, - IXGBE_SFF_QSFP_10GBE_COMP, &comp_codes_10g); - if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; - else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) - physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; - break; - default: - break; - } - -out: - return physical_layer; -} - /** * ixgbe_enable_rx_dma_82599 - Enable the Rx DMA unit on 82599 * @hw: pointer to hardware structure @@ -2454,7 +2328,6 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .start_hw = &ixgbe_start_hw_82599, .clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic, .get_media_type = &ixgbe_get_media_type_82599, - .get_supported_physical_layer = &ixgbe_get_supported_physical_layer_82599, .enable_rx_dma = &ixgbe_enable_rx_dma_82599, .disable_rx_buff = &ixgbe_disable_rx_buff_generic, .enable_rx_buff = &ixgbe_enable_rx_buff_generic, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 9a89f98b35f0..e6b07c2a01fe 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -2440,25 +2440,6 @@ typedef u32 ixgbe_link_speed; IXGBE_LINK_SPEED_1GB_FULL | \ IXGBE_LINK_SPEED_10GB_FULL) - -/* Physical layer type */ -typedef u32 ixgbe_physical_layer; -#define IXGBE_PHYSICAL_LAYER_UNKNOWN 0 -#define IXGBE_PHYSICAL_LAYER_10GBASE_T 0x0001 -#define IXGBE_PHYSICAL_LAYER_1000BASE_T 0x0002 -#define IXGBE_PHYSICAL_LAYER_100BASE_TX 0x0004 -#define IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU 0x0008 -#define IXGBE_PHYSICAL_LAYER_10GBASE_LR 0x0010 -#define IXGBE_PHYSICAL_LAYER_10GBASE_LRM 0x0020 -#define IXGBE_PHYSICAL_LAYER_10GBASE_SR 0x0040 -#define IXGBE_PHYSICAL_LAYER_10GBASE_KX4 0x0080 -#define IXGBE_PHYSICAL_LAYER_10GBASE_CX4 0x0100 -#define IXGBE_PHYSICAL_LAYER_1000BASE_KX 0x0200 -#define IXGBE_PHYSICAL_LAYER_1000BASE_BX 0x0400 -#define IXGBE_PHYSICAL_LAYER_10GBASE_KR 0x0800 -#define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI 0x1000 -#define IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA 0x2000 - /* Flow Control Data Sheet defined values * Calculation and defines taken from 802.1bb Annex O */ @@ -2860,7 +2841,6 @@ struct ixgbe_mac_operations { s32 (*start_hw)(struct ixgbe_hw *); s32 (*clear_hw_cntrs)(struct ixgbe_hw *); enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); - u32 (*get_supported_physical_layer)(struct ixgbe_hw *); s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *); s32 (*get_san_mac_addr)(struct ixgbe_hw *, u8 *); s32 (*get_device_caps)(struct ixgbe_hw *, u16 *); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index 1e26794febd6..7920ab9a18cb 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -193,31 +193,6 @@ out: return ret_val; } -/** - * ixgbe_get_supported_physical_layer_X540 - Returns physical layer type - * @hw: pointer to hardware structure - * - * Determines physical layer capabilities of the current configuration. - **/ -static u32 ixgbe_get_supported_physical_layer_X540(struct ixgbe_hw *hw) -{ - u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; - u16 ext_ability = 0; - - hw->phy.ops.identify(hw); - - hw->phy.ops.read_reg(hw, MDIO_PMA_EXTABLE, MDIO_MMD_PMAPMD, - &ext_ability); - if (ext_ability & MDIO_PMA_EXTABLE_10GBT) - physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T; - if (ext_ability & MDIO_PMA_EXTABLE_1000BT) - physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T; - if (ext_ability & MDIO_PMA_EXTABLE_100BTX) - physical_layer |= IXGBE_PHYSICAL_LAYER_100BASE_TX; - - return physical_layer; -} - /** * ixgbe_init_eeprom_params_X540 - Initialize EEPROM params * @hw: pointer to hardware structure @@ -792,8 +767,6 @@ static struct ixgbe_mac_operations mac_ops_X540 = { .start_hw = &ixgbe_start_hw_X540, .clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic, .get_media_type = &ixgbe_get_media_type_X540, - .get_supported_physical_layer = - &ixgbe_get_supported_physical_layer_X540, .enable_rx_dma = &ixgbe_enable_rx_dma_generic, .get_mac_addr = &ixgbe_get_mac_addr_generic, .get_san_mac_addr = &ixgbe_get_san_mac_addr_generic, -- cgit v1.2.3 From 9f1fb8acd30c9ace0145e66942481bdb90beca15 Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 22 Jul 2014 06:51:03 +0000 Subject: ixgbevf: Remove unused get_supported_physical_layer pointer Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/vf.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.h b/drivers/net/ethernet/intel/ixgbevf/vf.h index 3061d1890471..aa8cc8dc25d1 100644 --- a/drivers/net/ethernet/intel/ixgbevf/vf.h +++ b/drivers/net/ethernet/intel/ixgbevf/vf.h @@ -49,7 +49,6 @@ struct ixgbe_mac_operations { s32 (*start_hw)(struct ixgbe_hw *); s32 (*clear_hw_cntrs)(struct ixgbe_hw *); enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); - u32 (*get_supported_physical_layer)(struct ixgbe_hw *); s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *); s32 (*stop_adapter)(struct ixgbe_hw *); s32 (*get_bus_info)(struct ixgbe_hw *); -- cgit v1.2.3 From e90dd264566405e2f1bbb8595a4b5612281f6315 Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 22 Jul 2014 06:51:08 +0000 Subject: ixgbe: Make return values more direct Make return values more direct, eliminating some gotos and otherwise unneeded conditionals. This also eliminates some local variables. Also a few minor cleanups in affected code so checkpatch won't complain. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c | 111 ++--- drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c | 184 +++----- drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 574 ++++++++++------------- drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c | 39 +- drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c | 39 +- drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c | 24 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 32 +- drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c | 106 ++--- drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 582 +++++++++++------------- drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c | 31 +- drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 30 +- 11 files changed, 742 insertions(+), 1010 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index 681e3205038d..c5c97b483d7c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -122,7 +122,7 @@ static s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; - s32 ret_val = 0; + s32 ret_val; u16 list_offset, data_offset; /* Identify the PHY */ @@ -147,28 +147,23 @@ static s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw) /* Call SFP+ identify routine to get the SFP+ module type */ ret_val = phy->ops.identify_sfp(hw); - if (ret_val != 0) - goto out; - else if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) { - ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED; - goto out; - } + if (ret_val) + return ret_val; + if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) + return IXGBE_ERR_SFP_NOT_SUPPORTED; /* Check to see if SFP+ module is supported */ ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, &data_offset); - if (ret_val != 0) { - ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED; - goto out; - } + if (ret_val) + return IXGBE_ERR_SFP_NOT_SUPPORTED; break; default: break; } -out: - return ret_val; + return 0; } /** @@ -183,7 +178,7 @@ static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) { u32 regval; u32 i; - s32 ret_val = 0; + s32 ret_val; ret_val = ixgbe_start_hw_generic(hw); @@ -203,11 +198,13 @@ static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval); } + if (ret_val) + return ret_val; + /* set the completion timeout for interface */ - if (ret_val == 0) - ixgbe_set_pcie_completion_timeout(hw); + ixgbe_set_pcie_completion_timeout(hw); - return ret_val; + return 0; } /** @@ -222,7 +219,6 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg) { - s32 status = 0; u32 autoc = 0; /* @@ -262,11 +258,10 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, break; default: - status = IXGBE_ERR_LINK_SETUP; - break; + return IXGBE_ERR_LINK_SETUP; } - return status; + return 0; } /** @@ -277,14 +272,12 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, **/ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) { - enum ixgbe_media_type media_type; - /* Detect if there is a copper PHY attached. */ switch (hw->phy.type) { case ixgbe_phy_cu_unknown: case ixgbe_phy_tn: - media_type = ixgbe_media_type_copper; - goto out; + return ixgbe_media_type_copper; + default: break; } @@ -294,30 +287,27 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82598: case IXGBE_DEV_ID_82598_BX: /* Default device ID is mezzanine card KX/KX4 */ - media_type = ixgbe_media_type_backplane; - break; + return ixgbe_media_type_backplane; + case IXGBE_DEV_ID_82598AF_DUAL_PORT: case IXGBE_DEV_ID_82598AF_SINGLE_PORT: case IXGBE_DEV_ID_82598_DA_DUAL_PORT: case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: case IXGBE_DEV_ID_82598EB_XF_LR: case IXGBE_DEV_ID_82598EB_SFP_LOM: - media_type = ixgbe_media_type_fiber; - break; + return ixgbe_media_type_fiber; + case IXGBE_DEV_ID_82598EB_CX4: case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: - media_type = ixgbe_media_type_cx4; - break; + return ixgbe_media_type_cx4; + case IXGBE_DEV_ID_82598AT: case IXGBE_DEV_ID_82598AT2: - media_type = ixgbe_media_type_copper; - break; + return ixgbe_media_type_copper; + default: - media_type = ixgbe_media_type_unknown; - break; + return ixgbe_media_type_unknown; } -out: - return media_type; } /** @@ -328,7 +318,6 @@ out: **/ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) { - s32 ret_val = 0; u32 fctrl_reg; u32 rmcs_reg; u32 reg; @@ -338,10 +327,8 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) bool link_up; /* Validate the water mark configuration */ - if (!hw->fc.pause_time) { - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } + if (!hw->fc.pause_time) + return IXGBE_ERR_INVALID_LINK_SETTINGS; /* Low water mark of zero causes XOFF floods */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { @@ -350,8 +337,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) if (!hw->fc.low_water[i] || hw->fc.low_water[i] >= hw->fc.high_water[i]) { hw_dbg(hw, "Invalid water mark configuration\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; + return IXGBE_ERR_INVALID_LINK_SETTINGS; } } } @@ -428,8 +414,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) break; default: hw_dbg(hw, "Flow control param set incorrectly\n"); - ret_val = IXGBE_ERR_CONFIG; - goto out; + return IXGBE_ERR_CONFIG; } /* Set 802.3x based flow control settings. */ @@ -460,8 +445,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) /* Configure flow control refresh threshold value */ IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2); -out: - return ret_val; + return 0; } /** @@ -597,7 +581,7 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, } if (!*link_up) - goto out; + return 0; } links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); @@ -628,7 +612,6 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, (ixgbe_validate_link_ready(hw) != 0)) *link_up = false; -out: return 0; } @@ -645,7 +628,6 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw, bool autoneg_wait_to_complete) { bool autoneg = false; - s32 status = 0; ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN; u32 curr_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 autoc = curr_autoc; @@ -656,7 +638,7 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw, speed &= link_capabilities; if (speed == IXGBE_LINK_SPEED_UNKNOWN) - status = IXGBE_ERR_LINK_SETUP; + return IXGBE_ERR_LINK_SETUP; /* Set KX4/KX support according to speed requested */ else if (link_mode == IXGBE_AUTOC_LMS_KX4_AN || @@ -670,17 +652,11 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw, IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); } - if (status == 0) { - /* - * Setup and restart the link based on the new values in - * ixgbe_hw This will write the AUTOC register based on the new - * stored values - */ - status = ixgbe_start_mac_link_82598(hw, - autoneg_wait_to_complete); - } - - return status; + /* Setup and restart the link based on the new values in + * ixgbe_hw This will write the AUTOC register based on the new + * stored values + */ + return ixgbe_start_mac_link_82598(hw, autoneg_wait_to_complete); } @@ -717,7 +693,7 @@ static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, **/ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) { - s32 status = 0; + s32 status; s32 phy_status = 0; u32 ctrl; u32 gheccr; @@ -727,8 +703,8 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) /* Call adapter stop to disable tx/rx and clear interrupts */ status = hw->mac.ops.stop_adapter(hw); - if (status != 0) - goto reset_hw_out; + if (status) + return status; /* * Power up the Atlas Tx lanes if they are currently powered down. @@ -770,7 +746,7 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) /* Init PHY and function pointers, perform SFP setup */ phy_status = hw->phy.ops.init(hw); if (phy_status == IXGBE_ERR_SFP_NOT_SUPPORTED) - goto reset_hw_out; + return phy_status; if (phy_status == IXGBE_ERR_SFP_NOT_PRESENT) goto mac_reset_top; @@ -836,7 +812,6 @@ mac_reset_top: */ hw->mac.ops.init_rx_addrs(hw); -reset_hw_out: if (phy_status) status = phy_status; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 6fc633a2726a..cf55a0df877b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -123,7 +123,7 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) { - s32 ret_val = 0; + s32 ret_val; u16 list_offset, data_offset, data_value; if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) { @@ -133,16 +133,14 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, &data_offset); - if (ret_val != 0) - goto setup_sfp_out; + if (ret_val) + return ret_val; /* PHY config will finish before releasing the semaphore */ ret_val = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); - if (ret_val != 0) { - ret_val = IXGBE_ERR_SWFW_SYNC; - goto setup_sfp_out; - } + if (ret_val) + return IXGBE_ERR_SWFW_SYNC; if (hw->eeprom.ops.read(hw, ++data_offset, &data_value)) goto setup_sfp_err; @@ -169,13 +167,11 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) if (ret_val) { hw_dbg(hw, " sfp module setup not complete\n"); - ret_val = IXGBE_ERR_SFP_SETUP_NOT_COMPLETE; - goto setup_sfp_out; + return IXGBE_ERR_SFP_SETUP_NOT_COMPLETE; } } -setup_sfp_out: - return ret_val; + return 0; setup_sfp_err: /* Release the semaphore */ @@ -294,7 +290,7 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; - s32 ret_val = 0; + s32 ret_val; u32 esdp; if (hw->device_id == IXGBE_DEV_ID_82599_QSFP_SF_QP) { @@ -355,7 +351,6 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg) { - s32 status = 0; u32 autoc = 0; /* Determine 1G link capabilities off of SFP+ type */ @@ -367,7 +362,7 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) { *speed = IXGBE_LINK_SPEED_1GB_FULL; *autoneg = true; - goto out; + return 0; } /* @@ -430,8 +425,7 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, break; default: - status = IXGBE_ERR_LINK_SETUP; - goto out; + return IXGBE_ERR_LINK_SETUP; } if (hw->phy.multispeed_fiber) { @@ -445,8 +439,7 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, *autoneg = true; } -out: - return status; + return 0; } /** @@ -457,14 +450,12 @@ out: **/ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) { - enum ixgbe_media_type media_type; - /* Detect if there is a copper PHY attached. */ switch (hw->phy.type) { case ixgbe_phy_cu_unknown: case ixgbe_phy_tn: - media_type = ixgbe_media_type_copper; - goto out; + return ixgbe_media_type_copper; + default: break; } @@ -477,34 +468,31 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82599_BACKPLANE_FCOE: case IXGBE_DEV_ID_82599_XAUI_LOM: /* Default device ID is mezzanine card KX/KX4 */ - media_type = ixgbe_media_type_backplane; - break; + return ixgbe_media_type_backplane; + case IXGBE_DEV_ID_82599_SFP: case IXGBE_DEV_ID_82599_SFP_FCOE: case IXGBE_DEV_ID_82599_SFP_EM: case IXGBE_DEV_ID_82599_SFP_SF2: case IXGBE_DEV_ID_82599_SFP_SF_QP: case IXGBE_DEV_ID_82599EN_SFP: - media_type = ixgbe_media_type_fiber; - break; + return ixgbe_media_type_fiber; + case IXGBE_DEV_ID_82599_CX4: - media_type = ixgbe_media_type_cx4; - break; + return ixgbe_media_type_cx4; + case IXGBE_DEV_ID_82599_T3_LOM: - media_type = ixgbe_media_type_copper; - break; + return ixgbe_media_type_copper; + case IXGBE_DEV_ID_82599_LS: - media_type = ixgbe_media_type_fiber_lco; - break; + return ixgbe_media_type_fiber_lco; + case IXGBE_DEV_ID_82599_QSFP_SF_QP: - media_type = ixgbe_media_type_fiber_qsfp; - break; + return ixgbe_media_type_fiber_qsfp; + default: - media_type = ixgbe_media_type_unknown; - break; + return ixgbe_media_type_unknown; } -out: - return media_type; } /** @@ -554,7 +542,7 @@ static s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, status = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); if (status) - goto out; + return status; got_lock = true; } @@ -591,7 +579,6 @@ static s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, /* Add delay to filter out noises during initial link setup */ msleep(50); -out: return status; } @@ -958,7 +945,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, bool autoneg_wait_to_complete) { bool autoneg = false; - s32 status = 0; + s32 status; u32 pma_pmd_1g, link_mode, links_reg, i; u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK; @@ -974,15 +961,13 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, /* Check to see if speed passed in is supported. */ status = hw->mac.ops.get_link_capabilities(hw, &link_capabilities, &autoneg); - if (status != 0) - goto out; + if (status) + return status; speed &= link_capabilities; - if (speed == IXGBE_LINK_SPEED_UNKNOWN) { - status = IXGBE_ERR_LINK_SETUP; - goto out; - } + if (speed == IXGBE_LINK_SPEED_UNKNOWN) + return IXGBE_ERR_LINK_SETUP; /* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/ if (hw->mac.orig_link_settings_stored) @@ -1033,7 +1018,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, /* Restart link */ status = hw->mac.ops.prot_autoc_write(hw, autoc, false); if (status) - goto out; + return status; /* Only poll for autoneg to complete if specified to do so */ if (autoneg_wait_to_complete) { @@ -1060,7 +1045,6 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, msleep(50); } -out: return status; } @@ -1105,8 +1089,8 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) /* Call adapter stop to disable tx/rx and clear interrupts */ status = hw->mac.ops.stop_adapter(hw); - if (status != 0) - goto reset_hw_out; + if (status) + return status; /* flush pending Tx transactions */ ixgbe_clear_tx_pending(hw); @@ -1117,7 +1101,7 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) status = hw->phy.ops.init(hw); if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) - goto reset_hw_out; + return status; /* Setup SFP module if there is one present. */ if (hw->phy.sfp_setup_needed) { @@ -1126,7 +1110,7 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) } if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) - goto reset_hw_out; + return status; /* Reset PHY */ if (hw->phy.reset_disable == false && hw->phy.ops.reset != NULL) @@ -1216,7 +1200,7 @@ mac_reset_top: hw->mac.orig_autoc, false); if (status) - goto reset_hw_out; + return status; } if ((autoc2 & IXGBE_AUTOC2_UPPER_MASK) != @@ -1258,7 +1242,6 @@ mac_reset_top: hw->mac.ops.get_wwn_prefix(hw, &hw->mac.wwnn_prefix, &hw->mac.wwpn_prefix); -reset_hw_out: return status; } @@ -1927,20 +1910,20 @@ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) s32 ret_val = 0; ret_val = ixgbe_start_hw_generic(hw); - if (ret_val != 0) - goto out; + if (ret_val) + return ret_val; ret_val = ixgbe_start_hw_gen2(hw); - if (ret_val != 0) - goto out; + if (ret_val) + return ret_val; /* We need to run link autotry after the driver loads */ hw->mac.autotry_restart = true; - if (ret_val == 0) - ret_val = ixgbe_verify_fw_version_82599(hw); -out: - return ret_val; + if (ret_val) + return ret_val; + + return ixgbe_verify_fw_version_82599(hw); } /** @@ -1953,16 +1936,15 @@ out: **/ static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) { - s32 status = IXGBE_ERR_PHY_ADDR_INVALID; + s32 status; /* Detect PHY if not unknown - returns success if already detected. */ status = ixgbe_identify_phy_generic(hw); - if (status != 0) { + if (status) { /* 82599 10GBASE-T requires an external PHY */ if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper) - goto out; - else - status = ixgbe_identify_module_generic(hw); + return status; + status = ixgbe_identify_module_generic(hw); } /* Set PHY type none if no PHY detected */ @@ -1973,9 +1955,8 @@ static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) /* Return error if SFP module has been detected but is not supported */ if (hw->phy.type == ixgbe_phy_sfp_unsupported) - status = IXGBE_ERR_SFP_NOT_SUPPORTED; + return IXGBE_ERR_SFP_NOT_SUPPORTED; -out: return status; } @@ -2021,26 +2002,24 @@ static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw) u16 fw_version = 0; /* firmware check is only necessary for SFI devices */ - if (hw->phy.media_type != ixgbe_media_type_fiber) { - status = 0; - goto fw_version_out; - } + if (hw->phy.media_type != ixgbe_media_type_fiber) + return 0; /* get the offset to the Firmware Module block */ offset = IXGBE_FW_PTR; if (hw->eeprom.ops.read(hw, offset, &fw_offset)) goto fw_version_err; - if ((fw_offset == 0) || (fw_offset == 0xFFFF)) - goto fw_version_out; + if (fw_offset == 0 || fw_offset == 0xFFFF) + return IXGBE_ERR_EEPROM_VERSION; /* get the offset to the Pass Through Patch Configuration block */ offset = fw_offset + IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR; if (hw->eeprom.ops.read(hw, offset, &fw_ptp_cfg_offset)) goto fw_version_err; - if ((fw_ptp_cfg_offset == 0) || (fw_ptp_cfg_offset == 0xFFFF)) - goto fw_version_out; + if (fw_ptp_cfg_offset == 0 || fw_ptp_cfg_offset == 0xFFFF) + return IXGBE_ERR_EEPROM_VERSION; /* get the firmware version */ offset = fw_ptp_cfg_offset + IXGBE_FW_PATCH_VERSION_4; @@ -2050,7 +2029,6 @@ static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw) if (fw_version > 0x5) status = 0; -fw_version_out: return status; fw_version_err: @@ -2067,37 +2045,33 @@ fw_version_err: **/ static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw) { - bool lesm_enabled = false; u16 fw_offset, fw_lesm_param_offset, fw_lesm_state; s32 status; /* get the offset to the Firmware Module block */ status = hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset); - if ((status != 0) || - (fw_offset == 0) || (fw_offset == 0xFFFF)) - goto out; + if (status || fw_offset == 0 || fw_offset == 0xFFFF) + return false; /* get the offset to the LESM Parameters block */ status = hw->eeprom.ops.read(hw, (fw_offset + IXGBE_FW_LESM_PARAMETERS_PTR), &fw_lesm_param_offset); - if ((status != 0) || - (fw_lesm_param_offset == 0) || (fw_lesm_param_offset == 0xFFFF)) - goto out; + if (status || + fw_lesm_param_offset == 0 || fw_lesm_param_offset == 0xFFFF) + return false; /* get the lesm state word */ status = hw->eeprom.ops.read(hw, (fw_lesm_param_offset + IXGBE_FW_LESM_STATE_1), &fw_lesm_state); - if ((status == 0) && - (fw_lesm_state & IXGBE_FW_LESM_STATE_ENABLED)) - lesm_enabled = true; + if (!status && (fw_lesm_state & IXGBE_FW_LESM_STATE_ENABLED)) + return true; -out: - return lesm_enabled; + return false; } /** @@ -2115,22 +2089,16 @@ static s32 ixgbe_read_eeprom_buffer_82599(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { struct ixgbe_eeprom_info *eeprom = &hw->eeprom; - s32 ret_val = IXGBE_ERR_CONFIG; - /* - * If EEPROM is detected and can be addressed using 14 bits, + /* If EEPROM is detected and can be addressed using 14 bits, * use EERD otherwise use bit bang */ - if ((eeprom->type == ixgbe_eeprom_spi) && - (offset + (words - 1) <= IXGBE_EERD_MAX_ADDR)) - ret_val = ixgbe_read_eerd_buffer_generic(hw, offset, words, - data); - else - ret_val = ixgbe_read_eeprom_buffer_bit_bang_generic(hw, offset, - words, - data); + if (eeprom->type == ixgbe_eeprom_spi && + offset + (words - 1) <= IXGBE_EERD_MAX_ADDR) + return ixgbe_read_eerd_buffer_generic(hw, offset, words, data); - return ret_val; + return ixgbe_read_eeprom_buffer_bit_bang_generic(hw, offset, words, + data); } /** @@ -2147,19 +2115,15 @@ static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw, u16 offset, u16 *data) { struct ixgbe_eeprom_info *eeprom = &hw->eeprom; - s32 ret_val = IXGBE_ERR_CONFIG; /* * If EEPROM is detected and can be addressed using 14 bits, * use EERD otherwise use bit bang */ - if ((eeprom->type == ixgbe_eeprom_spi) && - (offset <= IXGBE_EERD_MAX_ADDR)) - ret_val = ixgbe_read_eerd_generic(hw, offset, data); - else - ret_val = ixgbe_read_eeprom_bit_bang_generic(hw, offset, data); + if (eeprom->type == ixgbe_eeprom_spi && offset <= IXGBE_EERD_MAX_ADDR) + return ixgbe_read_eerd_generic(hw, offset, data); - return ret_val; + return ixgbe_read_eeprom_bit_bang_generic(hw, offset, data); } /** diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index db759f98f9f0..b5f484bf3fda 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -122,8 +122,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) */ if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; + return IXGBE_ERR_INVALID_LINK_SETTINGS; } /* @@ -143,7 +142,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) /* some MAC's need RMW protection on AUTOC */ ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, ®_bp); if (ret_val) - goto out; + return ret_val; /* only backplane uses autoc so fall though */ case ixgbe_media_type_fiber: @@ -214,8 +213,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) break; default: hw_dbg(hw, "Flow control param set incorrectly\n"); - ret_val = IXGBE_ERR_CONFIG; - goto out; + return IXGBE_ERR_CONFIG; } if (hw->mac.type != ixgbe_mac_X540) { @@ -246,7 +244,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) */ ret_val = hw->mac.ops.prot_autoc_write(hw, reg_bp, locked); if (ret_val) - goto out; + return ret_val; } else if ((hw->phy.media_type == ixgbe_media_type_copper) && ixgbe_device_supports_autoneg_fc(hw)) { @@ -255,7 +253,6 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) } hw_dbg(hw, "Set up FC; IXGBE_AUTOC = 0x%08X\n", reg); -out: return ret_val; } @@ -294,12 +291,11 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) /* Setup flow control */ ret_val = ixgbe_setup_fc(hw); if (!ret_val) - goto out; + return 0; /* Clear adapter stopped flag */ hw->adapter_stopped = false; -out: return ret_val; } @@ -836,20 +832,16 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - s32 status = 0; + s32 status; u16 i, count; hw->eeprom.ops.init_params(hw); - if (words == 0) { - status = IXGBE_ERR_INVALID_ARGUMENT; - goto out; - } + if (words == 0) + return IXGBE_ERR_INVALID_ARGUMENT; - if (offset + words > hw->eeprom.word_size) { - status = IXGBE_ERR_EEPROM; - goto out; - } + if (offset + words > hw->eeprom.word_size) + return IXGBE_ERR_EEPROM; /* * The EEPROM page size cannot be queried from the chip. We do lazy @@ -874,7 +866,6 @@ s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, break; } -out: return status; } @@ -899,64 +890,61 @@ static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, /* Prepare the EEPROM for writing */ status = ixgbe_acquire_eeprom(hw); + if (status) + return status; - if (status == 0) { - if (ixgbe_ready_eeprom(hw) != 0) { - ixgbe_release_eeprom(hw); - status = IXGBE_ERR_EEPROM; - } + if (ixgbe_ready_eeprom(hw) != 0) { + ixgbe_release_eeprom(hw); + return IXGBE_ERR_EEPROM; } - if (status == 0) { - for (i = 0; i < words; i++) { - ixgbe_standby_eeprom(hw); + for (i = 0; i < words; i++) { + ixgbe_standby_eeprom(hw); + + /* Send the WRITE ENABLE command (8 bit opcode) */ + ixgbe_shift_out_eeprom_bits(hw, + IXGBE_EEPROM_WREN_OPCODE_SPI, + IXGBE_EEPROM_OPCODE_BITS); - /* Send the WRITE ENABLE command (8 bit opcode ) */ - ixgbe_shift_out_eeprom_bits(hw, - IXGBE_EEPROM_WREN_OPCODE_SPI, - IXGBE_EEPROM_OPCODE_BITS); + ixgbe_standby_eeprom(hw); - ixgbe_standby_eeprom(hw); + /* Some SPI eeproms use the 8th address bit embedded + * in the opcode + */ + if ((hw->eeprom.address_bits == 8) && + ((offset + i) >= 128)) + write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; - /* - * Some SPI eeproms use the 8th address bit embedded - * in the opcode - */ - if ((hw->eeprom.address_bits == 8) && - ((offset + i) >= 128)) - write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; - - /* Send the Write command (8-bit opcode + addr) */ - ixgbe_shift_out_eeprom_bits(hw, write_opcode, - IXGBE_EEPROM_OPCODE_BITS); - ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2), - hw->eeprom.address_bits); - - page_size = hw->eeprom.word_page_size; - - /* Send the data in burst via SPI*/ - do { - word = data[i]; - word = (word >> 8) | (word << 8); - ixgbe_shift_out_eeprom_bits(hw, word, 16); - - if (page_size == 0) - break; - - /* do not wrap around page */ - if (((offset + i) & (page_size - 1)) == - (page_size - 1)) - break; - } while (++i < words); - - ixgbe_standby_eeprom(hw); - usleep_range(10000, 20000); - } - /* Done with writing - release the EEPROM */ - ixgbe_release_eeprom(hw); + /* Send the Write command (8-bit opcode + addr) */ + ixgbe_shift_out_eeprom_bits(hw, write_opcode, + IXGBE_EEPROM_OPCODE_BITS); + ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2), + hw->eeprom.address_bits); + + page_size = hw->eeprom.word_page_size; + + /* Send the data in burst via SPI */ + do { + word = data[i]; + word = (word >> 8) | (word << 8); + ixgbe_shift_out_eeprom_bits(hw, word, 16); + + if (page_size == 0) + break; + + /* do not wrap around page */ + if (((offset + i) & (page_size - 1)) == + (page_size - 1)) + break; + } while (++i < words); + + ixgbe_standby_eeprom(hw); + usleep_range(10000, 20000); } + /* Done with writing - release the EEPROM */ + ixgbe_release_eeprom(hw); - return status; + return 0; } /** @@ -970,19 +958,12 @@ static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, **/ s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) { - s32 status; - hw->eeprom.ops.init_params(hw); - if (offset >= hw->eeprom.word_size) { - status = IXGBE_ERR_EEPROM; - goto out; - } + if (offset >= hw->eeprom.word_size) + return IXGBE_ERR_EEPROM; - status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset, 1, &data); - -out: - return status; + return ixgbe_write_eeprom_buffer_bit_bang(hw, offset, 1, &data); } /** @@ -997,20 +978,16 @@ out: s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { - s32 status = 0; + s32 status; u16 i, count; hw->eeprom.ops.init_params(hw); - if (words == 0) { - status = IXGBE_ERR_INVALID_ARGUMENT; - goto out; - } + if (words == 0) + return IXGBE_ERR_INVALID_ARGUMENT; - if (offset + words > hw->eeprom.word_size) { - status = IXGBE_ERR_EEPROM; - goto out; - } + if (offset + words > hw->eeprom.word_size) + return IXGBE_ERR_EEPROM; /* * We cannot hold synchronization semaphores for too long @@ -1024,12 +1001,11 @@ s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset + i, count, &data[i]); - if (status != 0) - break; + if (status) + return status; } -out: - return status; + return 0; } /** @@ -1051,41 +1027,38 @@ static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, /* Prepare the EEPROM for reading */ status = ixgbe_acquire_eeprom(hw); + if (status) + return status; - if (status == 0) { - if (ixgbe_ready_eeprom(hw) != 0) { - ixgbe_release_eeprom(hw); - status = IXGBE_ERR_EEPROM; - } + if (ixgbe_ready_eeprom(hw) != 0) { + ixgbe_release_eeprom(hw); + return IXGBE_ERR_EEPROM; } - if (status == 0) { - for (i = 0; i < words; i++) { - ixgbe_standby_eeprom(hw); - /* - * Some SPI eeproms use the 8th address bit embedded - * in the opcode - */ - if ((hw->eeprom.address_bits == 8) && - ((offset + i) >= 128)) - read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; - - /* Send the READ command (opcode + addr) */ - ixgbe_shift_out_eeprom_bits(hw, read_opcode, - IXGBE_EEPROM_OPCODE_BITS); - ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2), - hw->eeprom.address_bits); - - /* Read the data. */ - word_in = ixgbe_shift_in_eeprom_bits(hw, 16); - data[i] = (word_in >> 8) | (word_in << 8); - } + for (i = 0; i < words; i++) { + ixgbe_standby_eeprom(hw); + /* Some SPI eeproms use the 8th address bit embedded + * in the opcode + */ + if ((hw->eeprom.address_bits == 8) && + ((offset + i) >= 128)) + read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; - /* End this read operation */ - ixgbe_release_eeprom(hw); + /* Send the READ command (opcode + addr) */ + ixgbe_shift_out_eeprom_bits(hw, read_opcode, + IXGBE_EEPROM_OPCODE_BITS); + ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2), + hw->eeprom.address_bits); + + /* Read the data. */ + word_in = ixgbe_shift_in_eeprom_bits(hw, 16); + data[i] = (word_in >> 8) | (word_in << 8); } - return status; + /* End this read operation */ + ixgbe_release_eeprom(hw); + + return 0; } /** @@ -1099,19 +1072,12 @@ static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) { - s32 status; - hw->eeprom.ops.init_params(hw); - if (offset >= hw->eeprom.word_size) { - status = IXGBE_ERR_EEPROM; - goto out; - } - - status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data); + if (offset >= hw->eeprom.word_size) + return IXGBE_ERR_EEPROM; -out: - return status; + return ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data); } /** @@ -1127,20 +1093,16 @@ s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { u32 eerd; - s32 status = 0; + s32 status; u32 i; hw->eeprom.ops.init_params(hw); - if (words == 0) { - status = IXGBE_ERR_INVALID_ARGUMENT; - goto out; - } + if (words == 0) + return IXGBE_ERR_INVALID_ARGUMENT; - if (offset >= hw->eeprom.word_size) { - status = IXGBE_ERR_EEPROM; - goto out; - } + if (offset >= hw->eeprom.word_size) + return IXGBE_ERR_EEPROM; for (i = 0; i < words; i++) { eerd = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) | @@ -1154,11 +1116,11 @@ s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, IXGBE_EEPROM_RW_REG_DATA); } else { hw_dbg(hw, "Eeprom read timed out\n"); - goto out; + return status; } } -out: - return status; + + return 0; } /** @@ -1174,7 +1136,7 @@ static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, u16 offset) { u16 data[IXGBE_EEPROM_PAGE_SIZE_MAX]; - s32 status = 0; + s32 status; u16 i; for (i = 0; i < IXGBE_EEPROM_PAGE_SIZE_MAX; i++) @@ -1184,12 +1146,12 @@ static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset, IXGBE_EEPROM_PAGE_SIZE_MAX, data); hw->eeprom.word_page_size = 0; - if (status != 0) - goto out; + if (status) + return status; status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data); - if (status != 0) - goto out; + if (status) + return status; /* * When writing in burst more than the actual page size @@ -1199,8 +1161,7 @@ static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, hw_dbg(hw, "Detected EEPROM page size = %d words.\n", hw->eeprom.word_page_size); -out: - return status; + return 0; } /** @@ -1229,20 +1190,16 @@ s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data) { u32 eewr; - s32 status = 0; + s32 status; u16 i; hw->eeprom.ops.init_params(hw); - if (words == 0) { - status = IXGBE_ERR_INVALID_ARGUMENT; - goto out; - } + if (words == 0) + return IXGBE_ERR_INVALID_ARGUMENT; - if (offset >= hw->eeprom.word_size) { - status = IXGBE_ERR_EEPROM; - goto out; - } + if (offset >= hw->eeprom.word_size) + return IXGBE_ERR_EEPROM; for (i = 0; i < words; i++) { eewr = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) | @@ -1250,22 +1207,21 @@ s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, IXGBE_EEPROM_RW_REG_START; status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); - if (status != 0) { + if (status) { hw_dbg(hw, "Eeprom write EEWR timed out\n"); - goto out; + return status; } IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr); status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); - if (status != 0) { + if (status) { hw_dbg(hw, "Eeprom write EEWR timed out\n"); - goto out; + return status; } } -out: - return status; + return 0; } /** @@ -1293,7 +1249,6 @@ static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) { u32 i; u32 reg; - s32 status = IXGBE_ERR_EEPROM; for (i = 0; i < IXGBE_EERD_EEWR_ATTEMPTS; i++) { if (ee_reg == IXGBE_NVM_POLL_READ) @@ -1302,12 +1257,11 @@ static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) reg = IXGBE_READ_REG(hw, IXGBE_EEWR); if (reg & IXGBE_EEPROM_RW_REG_DONE) { - status = 0; - break; + return 0; } udelay(5); } - return status; + return IXGBE_ERR_EEPROM; } /** @@ -1319,47 +1273,42 @@ static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) **/ static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw) { - s32 status = 0; u32 eec; u32 i; if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) != 0) - status = IXGBE_ERR_SWFW_SYNC; + return IXGBE_ERR_SWFW_SYNC; - if (status == 0) { - eec = IXGBE_READ_REG(hw, IXGBE_EEC); - - /* Request EEPROM Access */ - eec |= IXGBE_EEC_REQ; - IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + eec = IXGBE_READ_REG(hw, IXGBE_EEC); - for (i = 0; i < IXGBE_EEPROM_GRANT_ATTEMPTS; i++) { - eec = IXGBE_READ_REG(hw, IXGBE_EEC); - if (eec & IXGBE_EEC_GNT) - break; - udelay(5); - } + /* Request EEPROM Access */ + eec |= IXGBE_EEC_REQ; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); - /* Release if grant not acquired */ - if (!(eec & IXGBE_EEC_GNT)) { - eec &= ~IXGBE_EEC_REQ; - IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); - hw_dbg(hw, "Could not acquire EEPROM grant\n"); + for (i = 0; i < IXGBE_EEPROM_GRANT_ATTEMPTS; i++) { + eec = IXGBE_READ_REG(hw, IXGBE_EEC); + if (eec & IXGBE_EEC_GNT) + break; + udelay(5); + } - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); - status = IXGBE_ERR_EEPROM; - } + /* Release if grant not acquired */ + if (!(eec & IXGBE_EEC_GNT)) { + eec &= ~IXGBE_EEC_REQ; + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + hw_dbg(hw, "Could not acquire EEPROM grant\n"); - /* Setup EEPROM for Read/Write */ - if (status == 0) { - /* Clear CS and SK */ - eec &= ~(IXGBE_EEC_CS | IXGBE_EEC_SK); - IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); - IXGBE_WRITE_FLUSH(hw); - udelay(1); - } + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + return IXGBE_ERR_EEPROM; } - return status; + + /* Setup EEPROM for Read/Write */ + /* Clear CS and SK */ + eec &= ~(IXGBE_EEC_CS | IXGBE_EEC_SK); + IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); + IXGBE_WRITE_FLUSH(hw); + udelay(1); + return 0; } /** @@ -1370,7 +1319,6 @@ static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw) **/ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) { - s32 status = IXGBE_ERR_EEPROM; u32 timeout = 2000; u32 i; u32 swsm; @@ -1382,17 +1330,14 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) * set and we have the semaphore */ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); - if (!(swsm & IXGBE_SWSM_SMBI)) { - status = 0; + if (!(swsm & IXGBE_SWSM_SMBI)) break; - } usleep_range(50, 100); } if (i == timeout) { hw_dbg(hw, "Driver can't access the Eeprom - SMBI Semaphore not granted.\n"); - /* - * this release is particularly important because our attempts + /* this release is particularly important because our attempts * above to get the semaphore may have succeeded, and if there * was a timeout, we should unconditionally clear the semaphore * bits to free the driver to make progress @@ -1400,50 +1345,45 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) ixgbe_release_eeprom_semaphore(hw); usleep_range(50, 100); - /* - * one last try + /* one last try * If the SMBI bit is 0 when we read it, then the bit will be * set and we have the semaphore */ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); - if (!(swsm & IXGBE_SWSM_SMBI)) - status = 0; + if (swsm & IXGBE_SWSM_SMBI) { + hw_dbg(hw, "Software semaphore SMBI between device drivers not granted.\n"); + return IXGBE_ERR_EEPROM; + } } /* Now get the semaphore between SW/FW through the SWESMBI bit */ - if (status == 0) { - for (i = 0; i < timeout; i++) { - swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + for (i = 0; i < timeout; i++) { + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); - /* Set the SW EEPROM semaphore bit to request access */ - swsm |= IXGBE_SWSM_SWESMBI; - IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm); + /* Set the SW EEPROM semaphore bit to request access */ + swsm |= IXGBE_SWSM_SWESMBI; + IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm); - /* - * If we set the bit successfully then we got the - * semaphore. - */ - swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); - if (swsm & IXGBE_SWSM_SWESMBI) - break; + /* If we set the bit successfully then we got the + * semaphore. + */ + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + if (swsm & IXGBE_SWSM_SWESMBI) + break; - usleep_range(50, 100); - } + usleep_range(50, 100); + } - /* - * Release semaphores and return error if SW EEPROM semaphore - * was not granted because we don't have access to the EEPROM - */ - if (i >= timeout) { - hw_dbg(hw, "SWESMBI Software EEPROM semaphore not granted.\n"); - ixgbe_release_eeprom_semaphore(hw); - status = IXGBE_ERR_EEPROM; - } - } else { - hw_dbg(hw, "Software semaphore SMBI between device drivers not granted.\n"); + /* Release semaphores and return error if SW EEPROM semaphore + * was not granted because we don't have access to the EEPROM + */ + if (i >= timeout) { + hw_dbg(hw, "SWESMBI Software EEPROM semaphore not granted.\n"); + ixgbe_release_eeprom_semaphore(hw); + return IXGBE_ERR_EEPROM; } - return status; + return 0; } /** @@ -1470,7 +1410,6 @@ static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw) **/ static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw) { - s32 status = 0; u16 i; u8 spi_stat_reg; @@ -1497,10 +1436,10 @@ static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw) */ if (i >= IXGBE_EEPROM_MAX_RETRY_SPI) { hw_dbg(hw, "SPI EEPROM Status error\n"); - status = IXGBE_ERR_EEPROM; + return IXGBE_ERR_EEPROM; } - return status; + return 0; } /** @@ -2099,17 +2038,14 @@ s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw) **/ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) { - s32 ret_val = 0; u32 mflcn_reg, fccfg_reg; u32 reg; u32 fcrtl, fcrth; int i; /* Validate the water mark configuration. */ - if (!hw->fc.pause_time) { - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } + if (!hw->fc.pause_time) + return IXGBE_ERR_INVALID_LINK_SETTINGS; /* Low water mark of zero causes XOFF floods */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { @@ -2118,8 +2054,7 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) if (!hw->fc.low_water[i] || hw->fc.low_water[i] >= hw->fc.high_water[i]) { hw_dbg(hw, "Invalid water mark configuration\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; + return IXGBE_ERR_INVALID_LINK_SETTINGS; } } } @@ -2176,8 +2111,7 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) break; default: hw_dbg(hw, "Flow control param set incorrectly\n"); - ret_val = IXGBE_ERR_CONFIG; - goto out; + return IXGBE_ERR_CONFIG; } /* Set 802.3x based flow control settings. */ @@ -2213,8 +2147,7 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2); -out: - return ret_val; + return 0; } /** @@ -2275,7 +2208,7 @@ static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, static s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw) { u32 pcs_anadv_reg, pcs_lpab_reg, linkstat; - s32 ret_val = IXGBE_ERR_FC_NOT_NEGOTIATED; + s32 ret_val; /* * On multispeed fiber at 1g, bail out if @@ -2286,7 +2219,7 @@ static s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw) linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); if ((!!(linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) || (!!(linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) - goto out; + return IXGBE_ERR_FC_NOT_NEGOTIATED; pcs_anadv_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); pcs_lpab_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); @@ -2297,7 +2230,6 @@ static s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw) IXGBE_PCS1GANA_SYM_PAUSE, IXGBE_PCS1GANA_ASM_PAUSE); -out: return ret_val; } @@ -2310,7 +2242,7 @@ out: static s32 ixgbe_fc_autoneg_backplane(struct ixgbe_hw *hw) { u32 links2, anlp1_reg, autoc_reg, links; - s32 ret_val = IXGBE_ERR_FC_NOT_NEGOTIATED; + s32 ret_val; /* * On backplane, bail out if @@ -2319,12 +2251,12 @@ static s32 ixgbe_fc_autoneg_backplane(struct ixgbe_hw *hw) */ links = IXGBE_READ_REG(hw, IXGBE_LINKS); if ((links & IXGBE_LINKS_KX_AN_COMP) == 0) - goto out; + return IXGBE_ERR_FC_NOT_NEGOTIATED; if (hw->mac.type == ixgbe_mac_82599EB) { links2 = IXGBE_READ_REG(hw, IXGBE_LINKS2); if ((links2 & IXGBE_LINKS2_AN_SUPPORTED) == 0) - goto out; + return IXGBE_ERR_FC_NOT_NEGOTIATED; } /* * Read the 10g AN autoc and LP ability registers and resolve @@ -2337,7 +2269,6 @@ static s32 ixgbe_fc_autoneg_backplane(struct ixgbe_hw *hw) anlp1_reg, IXGBE_AUTOC_SYM_PAUSE, IXGBE_AUTOC_ASM_PAUSE, IXGBE_ANLP1_SYM_PAUSE, IXGBE_ANLP1_ASM_PAUSE); -out: return ret_val; } @@ -2483,7 +2414,6 @@ static u32 ixgbe_pcie_timeout_poll(struct ixgbe_hw *hw) **/ static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) { - s32 status = 0; u32 i, poll; u16 value; @@ -2493,13 +2423,13 @@ static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) /* Exit if master requests are blocked */ if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO) || ixgbe_removed(hw->hw_addr)) - goto out; + return 0; /* Poll for master request bit to clear */ for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) { udelay(100); if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) - goto out; + return 0; } /* @@ -2522,16 +2452,13 @@ static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) udelay(100); value = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_STATUS); if (ixgbe_removed(hw->hw_addr)) - goto out; + return 0; if (!(value & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING)) - goto out; + return 0; } hw_dbg(hw, "PCIe transaction pending bit also did not clear.\n"); - status = IXGBE_ERR_MASTER_REQUESTS_PENDING; - -out: - return status; + return IXGBE_ERR_MASTER_REQUESTS_PENDING; } /** @@ -2706,8 +2633,8 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) bool link_up = false; u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); - s32 ret_val = 0; bool locked = false; + s32 ret_val; /* * Link must be up to auto-blink the LEDs; @@ -2718,14 +2645,14 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) if (!link_up) { ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg); if (ret_val) - goto out; + return ret_val; autoc_reg |= IXGBE_AUTOC_AN_RESTART; autoc_reg |= IXGBE_AUTOC_FLU; ret_val = hw->mac.ops.prot_autoc_write(hw, autoc_reg, locked); if (ret_val) - goto out; + return ret_val; IXGBE_WRITE_FLUSH(hw); @@ -2737,8 +2664,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); IXGBE_WRITE_FLUSH(hw); -out: - return ret_val; + return 0; } /** @@ -2750,19 +2676,19 @@ s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index) { u32 autoc_reg = 0; u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); - s32 ret_val = 0; bool locked = false; + s32 ret_val; ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg); if (ret_val) - goto out; + return ret_val; autoc_reg &= ~IXGBE_AUTOC_FLU; autoc_reg |= IXGBE_AUTOC_AN_RESTART; ret_val = hw->mac.ops.prot_autoc_write(hw, autoc_reg, locked); if (ret_val) - goto out; + return ret_val; led_reg &= ~IXGBE_LED_MODE_MASK(index); led_reg &= ~IXGBE_LED_BLINK(index); @@ -2770,8 +2696,7 @@ s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index) IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); IXGBE_WRITE_FLUSH(hw); -out: - return ret_val; + return 0; } /** @@ -2863,7 +2788,7 @@ san_mac_addr_clr: **/ u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw) { - u16 msix_count = 1; + u16 msix_count; u16 max_msix_count; u16 pcie_offset; @@ -2878,7 +2803,7 @@ u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw) max_msix_count = IXGBE_MAX_MSIX_VECTORS_82599; break; default: - return msix_count; + return 1; } msix_count = ixgbe_read_pci_cfg_word(hw, pcie_offset); @@ -2916,10 +2841,10 @@ s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq) mpsar_hi = IXGBE_READ_REG(hw, IXGBE_MPSAR_HI(rar)); if (ixgbe_removed(hw->hw_addr)) - goto done; + return 0; if (!mpsar_lo && !mpsar_hi) - goto done; + return 0; if (vmdq == IXGBE_CLEAR_VMDQ_ALL) { if (mpsar_lo) { @@ -2941,7 +2866,6 @@ s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq) /* was that the last pool using this rar? */ if (mpsar_lo == 0 && mpsar_hi == 0 && rar != 0) hw->mac.ops.clear_rar(hw, rar); -done: return 0; } @@ -3310,14 +3234,14 @@ s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix, if ((alt_san_mac_blk_offset == 0) || (alt_san_mac_blk_offset == 0xFFFF)) - goto wwn_prefix_out; + return 0; /* check capability in alternative san mac address block */ offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_CAPS_OFFSET; if (hw->eeprom.ops.read(hw, offset, &caps)) goto wwn_prefix_err; if (!(caps & IXGBE_ALT_SAN_MAC_ADDR_CAPS_ALTWWN)) - goto wwn_prefix_out; + return 0; /* get the corresponding prefix for WWNN/WWPN */ offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWNN_OFFSET; @@ -3328,7 +3252,6 @@ s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix, if (hw->eeprom.ops.read(hw, offset, wwpn_prefix)) goto wwn_prefix_err; -wwn_prefix_out: return 0; wwn_prefix_err: @@ -3522,21 +3445,17 @@ static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, u32 hdr_size = sizeof(struct ixgbe_hic_hdr); u8 buf_len, dword_len; - s32 ret_val = 0; - if (length == 0 || length & 0x3 || length > IXGBE_HI_MAX_BLOCK_BYTE_LENGTH) { hw_dbg(hw, "Buffer length failure.\n"); - ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND; - goto out; + return IXGBE_ERR_HOST_INTERFACE_COMMAND; } /* Check that the host interface is enabled. */ hicr = IXGBE_READ_REG(hw, IXGBE_HICR); if ((hicr & IXGBE_HICR_EN) == 0) { hw_dbg(hw, "IXGBE_HOST_EN bit disabled.\n"); - ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND; - goto out; + return IXGBE_ERR_HOST_INTERFACE_COMMAND; } /* Calculate length in DWORDs */ @@ -3564,8 +3483,7 @@ static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, if (i == IXGBE_HI_COMMAND_TIMEOUT || (!(IXGBE_READ_REG(hw, IXGBE_HICR) & IXGBE_HICR_SV))) { hw_dbg(hw, "Command has failed with no status valid.\n"); - ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND; - goto out; + return IXGBE_ERR_HOST_INTERFACE_COMMAND; } /* Calculate length in DWORDs */ @@ -3580,12 +3498,11 @@ static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, /* If there is any thing in data position pull it in */ buf_len = ((struct ixgbe_hic_hdr *)buffer)->buf_len; if (buf_len == 0) - goto out; + return 0; if (length < (buf_len + hdr_size)) { hw_dbg(hw, "Buffer not large enough for reply message.\n"); - ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND; - goto out; + return IXGBE_ERR_HOST_INTERFACE_COMMAND; } /* Calculate length in DWORDs, add 3 for odd lengths */ @@ -3597,8 +3514,7 @@ static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, le32_to_cpus(&buffer[bi]); } -out: - return ret_val; + return 0; } /** @@ -3619,12 +3535,10 @@ s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, { struct ixgbe_hic_drv_info fw_cmd; int i; - s32 ret_val = 0; + s32 ret_val; - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM) != 0) { - ret_val = IXGBE_ERR_SWFW_SYNC; - goto out; - } + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM)) + return IXGBE_ERR_SWFW_SYNC; fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO; fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN; @@ -3656,7 +3570,6 @@ s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, } hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM); -out: return ret_val; } @@ -3725,28 +3638,23 @@ static const u8 ixgbe_emc_therm_limit[4] = { static s32 ixgbe_get_ets_data(struct ixgbe_hw *hw, u16 *ets_cfg, u16 *ets_offset) { - s32 status = 0; + s32 status; status = hw->eeprom.ops.read(hw, IXGBE_ETS_CFG, ets_offset); if (status) - goto out; + return status; - if ((*ets_offset == 0x0000) || (*ets_offset == 0xFFFF)) { - status = IXGBE_NOT_IMPLEMENTED; - goto out; - } + if ((*ets_offset == 0x0000) || (*ets_offset == 0xFFFF)) + return IXGBE_NOT_IMPLEMENTED; status = hw->eeprom.ops.read(hw, *ets_offset, ets_cfg); if (status) - goto out; + return status; - if ((*ets_cfg & IXGBE_ETS_TYPE_MASK) != IXGBE_ETS_TYPE_EMC_SHIFTED) { - status = IXGBE_NOT_IMPLEMENTED; - goto out; - } + if ((*ets_cfg & IXGBE_ETS_TYPE_MASK) != IXGBE_ETS_TYPE_EMC_SHIFTED) + return IXGBE_NOT_IMPLEMENTED; -out: - return status; + return 0; } /** @@ -3757,7 +3665,7 @@ out: **/ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw) { - s32 status = 0; + s32 status; u16 ets_offset; u16 ets_cfg; u16 ets_sensor; @@ -3766,14 +3674,12 @@ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw) struct ixgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data; /* Only support thermal sensors attached to physical port 0 */ - if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) { - status = IXGBE_NOT_IMPLEMENTED; - goto out; - } + if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) + return IXGBE_NOT_IMPLEMENTED; status = ixgbe_get_ets_data(hw, &ets_cfg, &ets_offset); if (status) - goto out; + return status; num_sensors = (ets_cfg & IXGBE_ETS_NUM_SENSORS_MASK); if (num_sensors > IXGBE_MAX_SENSORS) @@ -3786,7 +3692,7 @@ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw) status = hw->eeprom.ops.read(hw, (ets_offset + 1 + i), &ets_sensor); if (status) - goto out; + return status; sensor_index = ((ets_sensor & IXGBE_ETS_DATA_INDEX_MASK) >> IXGBE_ETS_DATA_INDEX_SHIFT); @@ -3799,11 +3705,11 @@ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw) IXGBE_I2C_THERMAL_SENSOR_ADDR, &data->sensor[i].temp); if (status) - goto out; + return status; } } -out: - return status; + + return 0; } /** @@ -3815,7 +3721,7 @@ out: **/ s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw) { - s32 status = 0; + s32 status; u16 ets_offset; u16 ets_cfg; u16 ets_sensor; @@ -3828,14 +3734,12 @@ s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw) memset(data, 0, sizeof(struct ixgbe_thermal_sensor_data)); /* Only support thermal sensors attached to physical port 0 */ - if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) { - status = IXGBE_NOT_IMPLEMENTED; - goto out; - } + if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) + return IXGBE_NOT_IMPLEMENTED; status = ixgbe_get_ets_data(hw, &ets_cfg, &ets_offset); if (status) - goto out; + return status; low_thresh_delta = ((ets_cfg & IXGBE_ETS_LTHRES_DELTA_MASK) >> IXGBE_ETS_LTHRES_DELTA_SHIFT); @@ -3869,7 +3773,7 @@ s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw) data->sensor[i].caution_thresh = therm_limit; data->sensor[i].max_op_thresh = therm_limit - low_thresh_delta; } -out: - return status; + + return 0; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c index a689ee0d4bed..48f35fc963f8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 2014 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -87,7 +87,6 @@ s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *hw, int min_credit; int min_multiplier; int min_percent = 100; - s32 ret_val = 0; /* Initialization values default for Tx settings */ u32 credit_refill = 0; u32 credit_max = 0; @@ -95,10 +94,8 @@ s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *hw, u8 bw_percent = 0; u8 i; - if (dcb_config == NULL) { - ret_val = DCB_ERR_CONFIG; - goto out; - } + if (!dcb_config) + return DCB_ERR_CONFIG; min_credit = ((max_frame / 2) + DCB_CREDIT_QUANTUM - 1) / DCB_CREDIT_QUANTUM; @@ -174,8 +171,7 @@ s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *hw, p->data_credits_max = (u16)credit_max; } -out: - return ret_val; + return 0; } void ixgbe_dcb_unpack_pfc(struct ixgbe_dcb_config *cfg, u8 *pfc_en) @@ -236,7 +232,7 @@ u8 ixgbe_dcb_get_tc_from_up(struct ixgbe_dcb_config *cfg, int direction, u8 up) /* If tc is 0 then DCB is likely not enabled or supported */ if (!tc) - goto out; + return 0; /* * Test from maximum TC to 1 and report the first match we find. If @@ -247,7 +243,7 @@ u8 ixgbe_dcb_get_tc_from_up(struct ixgbe_dcb_config *cfg, int direction, u8 up) if (prio_mask & tc_config[tc].path[direction].up_to_tc_bitmap) break; } -out: + return tc; } @@ -269,7 +265,6 @@ void ixgbe_dcb_unpack_map(struct ixgbe_dcb_config *cfg, int direction, u8 *map) s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, struct ixgbe_dcb_config *dcb_config) { - s32 ret = 0; u8 pfc_en; u8 ptype[MAX_TRAFFIC_CLASS]; u8 bwgid[MAX_TRAFFIC_CLASS]; @@ -287,37 +282,31 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, switch (hw->mac.type) { case ixgbe_mac_82598EB: - ret = ixgbe_dcb_hw_config_82598(hw, pfc_en, refill, max, - bwgid, ptype); - break; + return ixgbe_dcb_hw_config_82598(hw, pfc_en, refill, max, + bwgid, ptype); case ixgbe_mac_82599EB: case ixgbe_mac_X540: - ret = ixgbe_dcb_hw_config_82599(hw, pfc_en, refill, max, - bwgid, ptype, prio_tc); - break; + return ixgbe_dcb_hw_config_82599(hw, pfc_en, refill, max, + bwgid, ptype, prio_tc); default: break; } - return ret; + return 0; } /* Helper routines to abstract HW specifics from DCB netlink ops */ s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) { - int ret = -EINVAL; - switch (hw->mac.type) { case ixgbe_mac_82598EB: - ret = ixgbe_dcb_config_pfc_82598(hw, pfc_en); - break; + return ixgbe_dcb_config_pfc_82598(hw, pfc_en); case ixgbe_mac_82599EB: case ixgbe_mac_X540: - ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en, prio_tc); - break; + return ixgbe_dcb_config_pfc_82599(hw, pfc_en, prio_tc); default: break; } - return ret; + return -EINVAL; } s32 ixgbe_dcb_hw_ets(struct ixgbe_hw *hw, struct ieee_ets *ets, int max_frame) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c index 75bcb2e08491..58a7f5312a96 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 2014 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -153,7 +153,6 @@ static u8 ixgbe_dcbnl_get_state(struct net_device *netdev) static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - int err = 0; /* Fail command if not in CEE mode */ if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) @@ -161,12 +160,10 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) /* verify there is something to do, if not then exit */ if (!state == !(adapter->flags & IXGBE_FLAG_DCB_ENABLED)) - goto out; + return 0; - err = ixgbe_setup_tc(netdev, - state ? adapter->dcb_cfg.num_tcs.pg_tcs : 0); -out: - return !!err; + return !!ixgbe_setup_tc(netdev, + state ? adapter->dcb_cfg.num_tcs.pg_tcs : 0); } static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev, @@ -331,12 +328,12 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) /* Fail command if not in CEE mode */ if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) - return ret; + return DCB_NO_HW_CHG; adapter->dcb_set_bitmap |= ixgbe_copy_dcb_cfg(adapter, MAX_TRAFFIC_CLASS); if (!adapter->dcb_set_bitmap) - return ret; + return DCB_NO_HW_CHG; if (adapter->dcb_set_bitmap & (BIT_PG_TX|BIT_PG_RX)) { u16 refill[MAX_TRAFFIC_CLASS], max[MAX_TRAFFIC_CLASS]; @@ -536,7 +533,7 @@ static int ixgbe_dcbnl_ieee_setets(struct net_device *dev, { struct ixgbe_adapter *adapter = netdev_priv(dev); int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN; - int i, err = 0; + int i, err; __u8 max_tc = 0; __u8 map_chg = 0; @@ -573,17 +570,15 @@ static int ixgbe_dcbnl_ieee_setets(struct net_device *dev, if (max_tc > adapter->dcb_cfg.num_tcs.pg_tcs) return -EINVAL; - if (max_tc != netdev_get_num_tc(dev)) + if (max_tc != netdev_get_num_tc(dev)) { err = ixgbe_setup_tc(dev, max_tc); - else if (map_chg) + if (err) + return err; + } else if (map_chg) { ixgbe_dcbnl_devreset(dev); + } - if (err) - goto err_out; - - err = ixgbe_dcb_hw_ets(&adapter->hw, ets, max_frame); -err_out: - return err; + return ixgbe_dcb_hw_ets(&adapter->hw, ets, max_frame); } static int ixgbe_dcbnl_ieee_getpfc(struct net_device *dev, @@ -647,10 +642,10 @@ static int ixgbe_dcbnl_ieee_setapp(struct net_device *dev, struct dcb_app *app) { struct ixgbe_adapter *adapter = netdev_priv(dev); - int err = -EINVAL; + int err; if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) - return err; + return -EINVAL; err = dcb_ieee_setapp(dev, app); if (err) @@ -662,7 +657,7 @@ static int ixgbe_dcbnl_ieee_setapp(struct net_device *dev, u8 app_mask = dcb_ieee_getapp_mask(dev, app); if (app_mask & (1 << adapter->fcoe.up)) - return err; + return 0; adapter->fcoe.up = app->priority; ixgbe_dcbnl_devreset(dev); @@ -705,7 +700,7 @@ static int ixgbe_dcbnl_ieee_delapp(struct net_device *dev, u8 app_mask = dcb_ieee_getapp_mask(dev, app); if (app_mask & (1 << adapter->fcoe.up)) - return err; + return 0; adapter->fcoe.up = app_mask ? ffs(app_mask) - 1 : IXGBE_FCOE_DEFTC; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c index 25a3dfef33e8..2ad91cb04dab 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 2014 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -67,23 +67,23 @@ static inline void ixgbe_fcoe_clear_ddp(struct ixgbe_fcoe_ddp *ddp) */ int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid) { - int len = 0; + int len; struct ixgbe_fcoe *fcoe; struct ixgbe_adapter *adapter; struct ixgbe_fcoe_ddp *ddp; u32 fcbuff; if (!netdev) - goto out_ddp_put; + return 0; if (xid >= IXGBE_FCOE_DDP_MAX) - goto out_ddp_put; + return 0; adapter = netdev_priv(netdev); fcoe = &adapter->fcoe; ddp = &fcoe->ddp[xid]; if (!ddp->udl) - goto out_ddp_put; + return 0; len = ddp->len; /* if there an error, force to invalidate ddp context */ @@ -114,7 +114,6 @@ int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid) ixgbe_fcoe_clear_ddp(ddp); -out_ddp_put: return len; } @@ -394,17 +393,17 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, xid = be16_to_cpu(fh->fh_rx_id); if (xid >= IXGBE_FCOE_DDP_MAX) - goto ddp_out; + return -EINVAL; fcoe = &adapter->fcoe; ddp = &fcoe->ddp[xid]; if (!ddp->udl) - goto ddp_out; + return -EINVAL; ddp_err = ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_FCEOFE | IXGBE_RXDADV_ERR_FCERR); if (ddp_err) - goto ddp_out; + return -EINVAL; switch (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_FCSTAT)) { /* return 0 to bypass going to ULD for DDPed data */ @@ -447,7 +446,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, crc = (struct fcoe_crc_eof *)skb_put(skb, sizeof(*crc)); crc->fcoe_eof = FC_EOF_T; } -ddp_out: + return rc; } @@ -878,7 +877,6 @@ int ixgbe_fcoe_disable(struct net_device *netdev) */ int ixgbe_fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type) { - int rc = -EINVAL; u16 prefix = 0xffff; struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_mac_info *mac = &adapter->hw.mac; @@ -903,9 +901,9 @@ int ixgbe_fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type) ((u64) mac->san_addr[3] << 16) | ((u64) mac->san_addr[4] << 8) | ((u64) mac->san_addr[5]); - rc = 0; + return 0; } - return rc; + return -EINVAL; } /** diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index e1f83ee03c6a..5384ed30298a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -570,7 +570,7 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter) /* Print TX Ring Summary */ if (!netdev || !netif_running(netdev)) - goto exit; + return; dev_info(&adapter->pdev->dev, "TX Rings Summary\n"); pr_info(" %s %s %s %s\n", @@ -685,7 +685,7 @@ rx_ring_summary: /* Print RX Rings */ if (!netif_msg_rx_status(adapter)) - goto exit; + return; dev_info(&adapter->pdev->dev, "RX Rings Dump\n"); @@ -787,9 +787,6 @@ rx_ring_summary: } } - -exit: - return; } static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter) @@ -1011,7 +1008,6 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_ring *tx_ring) u32 tx_done = ixgbe_get_tx_completed(tx_ring); u32 tx_done_old = tx_ring->tx_stats.tx_done_old; u32 tx_pending = ixgbe_get_tx_pending(tx_ring); - bool ret = false; clear_check_for_tx_hang(tx_ring); @@ -1027,18 +1023,16 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_ring *tx_ring) * run the check_tx_hang logic with a transmit completion * pending but without time to complete it yet. */ - if ((tx_done_old == tx_done) && tx_pending) { + if (tx_done_old == tx_done && tx_pending) /* make sure it is true for two checks in a row */ - ret = test_and_set_bit(__IXGBE_HANG_CHECK_ARMED, - &tx_ring->state); - } else { - /* update completed stats and continue */ - tx_ring->tx_stats.tx_done_old = tx_done; - /* reset the countdown */ - clear_bit(__IXGBE_HANG_CHECK_ARMED, &tx_ring->state); - } + return test_and_set_bit(__IXGBE_HANG_CHECK_ARMED, + &tx_ring->state); + /* update completed stats and continue */ + tx_ring->tx_stats.tx_done_old = tx_done; + /* reset the countdown */ + clear_bit(__IXGBE_HANG_CHECK_ARMED, &tx_ring->state); - return ret; + return false; } /** @@ -4701,18 +4695,18 @@ static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw) ret = hw->mac.ops.check_link(hw, &speed, &link_up, false); if (ret) - goto link_cfg_out; + return ret; speed = hw->phy.autoneg_advertised; if ((!speed) && (hw->mac.ops.get_link_capabilities)) ret = hw->mac.ops.get_link_capabilities(hw, &speed, &autoneg); if (ret) - goto link_cfg_out; + return ret; if (hw->mac.ops.setup_link) ret = hw->mac.ops.setup_link(hw, speed, link_up); -link_cfg_out: + return ret; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c index 50479575e131..cc8f0128286c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c @@ -43,16 +43,15 @@ s32 ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; /* limit read to size of mailbox */ if (size > mbx->size) size = mbx->size; - if (mbx->ops.read) - ret_val = mbx->ops.read(hw, msg, size, mbx_id); + if (!mbx->ops.read) + return IXGBE_ERR_MBX; - return ret_val; + return mbx->ops.read(hw, msg, size, mbx_id); } /** @@ -87,12 +86,11 @@ s32 ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) s32 ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; - if (mbx->ops.check_for_msg) - ret_val = mbx->ops.check_for_msg(hw, mbx_id); + if (!mbx->ops.check_for_msg) + return IXGBE_ERR_MBX; - return ret_val; + return mbx->ops.check_for_msg(hw, mbx_id); } /** @@ -105,12 +103,11 @@ s32 ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id) s32 ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; - if (mbx->ops.check_for_ack) - ret_val = mbx->ops.check_for_ack(hw, mbx_id); + if (!mbx->ops.check_for_ack) + return IXGBE_ERR_MBX; - return ret_val; + return mbx->ops.check_for_ack(hw, mbx_id); } /** @@ -123,12 +120,11 @@ s32 ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id) s32 ixgbe_check_for_rst(struct ixgbe_hw *hw, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; - if (mbx->ops.check_for_rst) - ret_val = mbx->ops.check_for_rst(hw, mbx_id); + if (!mbx->ops.check_for_rst) + return IXGBE_ERR_MBX; - return ret_val; + return mbx->ops.check_for_rst(hw, mbx_id); } /** @@ -144,17 +140,16 @@ static s32 ixgbe_poll_for_msg(struct ixgbe_hw *hw, u16 mbx_id) int countdown = mbx->timeout; if (!countdown || !mbx->ops.check_for_msg) - goto out; + return IXGBE_ERR_MBX; - while (countdown && mbx->ops.check_for_msg(hw, mbx_id)) { + while (mbx->ops.check_for_msg(hw, mbx_id)) { countdown--; if (!countdown) - break; + return IXGBE_ERR_MBX; udelay(mbx->usec_delay); } -out: - return countdown ? 0 : IXGBE_ERR_MBX; + return 0; } /** @@ -170,17 +165,16 @@ static s32 ixgbe_poll_for_ack(struct ixgbe_hw *hw, u16 mbx_id) int countdown = mbx->timeout; if (!countdown || !mbx->ops.check_for_ack) - goto out; + return IXGBE_ERR_MBX; - while (countdown && mbx->ops.check_for_ack(hw, mbx_id)) { + while (mbx->ops.check_for_ack(hw, mbx_id)) { countdown--; if (!countdown) - break; + return IXGBE_ERR_MBX; udelay(mbx->usec_delay); } -out: - return countdown ? 0 : IXGBE_ERR_MBX; + return 0; } /** @@ -197,18 +191,17 @@ static s32 ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; + s32 ret_val; if (!mbx->ops.read) - goto out; + return IXGBE_ERR_MBX; ret_val = ixgbe_poll_for_msg(hw, mbx_id); + if (ret_val) + return ret_val; - /* if ack received read message, otherwise we timed out */ - if (!ret_val) - ret_val = mbx->ops.read(hw, msg, size, mbx_id); -out: - return ret_val; + /* if ack received read message */ + return mbx->ops.read(hw, msg, size, mbx_id); } /** @@ -225,33 +218,31 @@ static s32 ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = IXGBE_ERR_MBX; + s32 ret_val; /* exit if either we can't write or there isn't a defined timeout */ if (!mbx->ops.write || !mbx->timeout) - goto out; + return IXGBE_ERR_MBX; /* send msg */ ret_val = mbx->ops.write(hw, msg, size, mbx_id); + if (ret_val) + return ret_val; /* if msg sent wait until we receive an ack */ - if (!ret_val) - ret_val = ixgbe_poll_for_ack(hw, mbx_id); -out: - return ret_val; + return ixgbe_poll_for_ack(hw, mbx_id); } static s32 ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, u32 mask, s32 index) { u32 mbvficr = IXGBE_READ_REG(hw, IXGBE_MBVFICR(index)); - s32 ret_val = IXGBE_ERR_MBX; if (mbvficr & mask) { - ret_val = 0; IXGBE_WRITE_REG(hw, IXGBE_MBVFICR(index), mask); + return 0; } - return ret_val; + return IXGBE_ERR_MBX; } /** @@ -263,17 +254,16 @@ static s32 ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, u32 mask, s32 index) **/ static s32 ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, u16 vf_number) { - s32 ret_val = IXGBE_ERR_MBX; s32 index = IXGBE_MBVFICR_INDEX(vf_number); u32 vf_bit = vf_number % 16; if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFREQ_VF1 << vf_bit, index)) { - ret_val = 0; hw->mbx.stats.reqs++; + return 0; } - return ret_val; + return IXGBE_ERR_MBX; } /** @@ -285,17 +275,16 @@ static s32 ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, u16 vf_number) **/ static s32 ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_number) { - s32 ret_val = IXGBE_ERR_MBX; s32 index = IXGBE_MBVFICR_INDEX(vf_number); u32 vf_bit = vf_number % 16; if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFACK_VF1 << vf_bit, index)) { - ret_val = 0; hw->mbx.stats.acks++; + return 0; } - return ret_val; + return IXGBE_ERR_MBX; } /** @@ -310,7 +299,6 @@ static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number) u32 reg_offset = (vf_number < 32) ? 0 : 1; u32 vf_shift = vf_number % 32; u32 vflre = 0; - s32 ret_val = IXGBE_ERR_MBX; switch (hw->mac.type) { case ixgbe_mac_82599EB: @@ -324,12 +312,12 @@ static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number) } if (vflre & (1 << vf_shift)) { - ret_val = 0; IXGBE_WRITE_REG(hw, IXGBE_VFLREC(reg_offset), (1 << vf_shift)); hw->mbx.stats.rsts++; + return 0; } - return ret_val; + return IXGBE_ERR_MBX; } /** @@ -341,7 +329,6 @@ static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number) **/ static s32 ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_number) { - s32 ret_val = IXGBE_ERR_MBX; u32 p2v_mailbox; /* Take ownership of the buffer */ @@ -350,9 +337,9 @@ static s32 ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_number) /* reserve mailbox for vf use */ p2v_mailbox = IXGBE_READ_REG(hw, IXGBE_PFMAILBOX(vf_number)); if (p2v_mailbox & IXGBE_PFMAILBOX_PFU) - ret_val = 0; + return 0; - return ret_val; + return IXGBE_ERR_MBX; } /** @@ -373,7 +360,7 @@ static s32 ixgbe_write_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, /* lock the mailbox to prevent pf/vf race condition */ ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_number); if (ret_val) - goto out_no_write; + return ret_val; /* flush msg and acks as we are overwriting the message buffer */ ixgbe_check_for_msg_pf(hw, vf_number); @@ -389,9 +376,7 @@ static s32 ixgbe_write_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, /* update stats */ hw->mbx.stats.msgs_tx++; -out_no_write: - return ret_val; - + return 0; } /** @@ -414,7 +399,7 @@ static s32 ixgbe_read_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, /* lock the mailbox to prevent pf/vf race condition */ ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_number); if (ret_val) - goto out_no_read; + return ret_val; /* copy the message to the mailbox memory buffer */ for (i = 0; i < size; i++) @@ -426,8 +411,7 @@ static s32 ixgbe_read_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size, /* update stats */ hw->mbx.stats.msgs_rx++; -out_no_read: - return ret_val; + return 0; } #ifdef CONFIG_PCI_IOV diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index ff68b7a9deff..11f02ea78c4a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -57,7 +57,6 @@ static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw); **/ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) { - s32 status = IXGBE_ERR_PHY_ADDR_INVALID; u32 phy_addr; u16 ext_ability = 0; @@ -84,18 +83,14 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) ixgbe_phy_generic; } - status = 0; - break; + return 0; } } /* clear value if nothing found */ - if (status != 0) - hw->phy.mdio.prtad = 0; - } else { - status = 0; + hw->phy.mdio.prtad = 0; + return IXGBE_ERR_PHY_ADDR_INVALID; } - - return status; + return 0; } /** @@ -192,16 +187,16 @@ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) status = ixgbe_identify_phy_generic(hw); if (status != 0 || hw->phy.type == ixgbe_phy_none) - goto out; + return status; /* Don't reset PHY if it's shut down due to overtemp. */ if (!hw->phy.reset_if_overtemp && (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw))) - goto out; + return 0; /* Blocked by MNG FW so bail */ if (ixgbe_check_reset_blocked(hw)) - goto out; + return 0; /* * Perform soft PHY reset to the PHY_XS. @@ -227,12 +222,11 @@ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) } if (ctrl & MDIO_CTRL1_RESET) { - status = IXGBE_ERR_RESET_FAILED; hw_dbg(hw, "PHY reset polling failed to complete.\n"); + return IXGBE_ERR_RESET_FAILED; } -out: - return status; + return 0; } /** @@ -333,7 +327,7 @@ s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, phy_data); hw->mac.ops.release_swfw_sync(hw, gssr); } else { - status = IXGBE_ERR_SWFW_SYNC; + return IXGBE_ERR_SWFW_SYNC; } return status; @@ -436,7 +430,7 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, phy_data); hw->mac.ops.release_swfw_sync(hw, gssr); } else { - status = IXGBE_ERR_SWFW_SYNC; + return IXGBE_ERR_SWFW_SYNC; } return status; @@ -509,7 +503,7 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) /* Blocked by MNG FW so don't reset PHY */ if (ixgbe_check_reset_blocked(hw)) - return status; + return 0; /* Restart PHY autonegotiation and wait for completion */ hw->phy.ops.read_reg(hw, MDIO_CTRL1, @@ -535,8 +529,8 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) } if (time_out == max_time_out) { - status = IXGBE_ERR_LINK_SETUP; hw_dbg(hw, "ixgbe_setup_phy_link_generic: time out\n"); + return IXGBE_ERR_LINK_SETUP; } return status; @@ -585,7 +579,7 @@ s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg) { - s32 status = IXGBE_ERR_LINK_SETUP; + s32 status; u16 speed_ability; *speed = 0; @@ -616,7 +610,7 @@ s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up) { - s32 status = 0; + s32 status; u32 time_out; u32 max_time_out = 10; u16 phy_link = 0; @@ -662,7 +656,7 @@ s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, **/ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) { - s32 status = 0; + s32 status; u32 time_out; u32 max_time_out = 10; u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; @@ -719,7 +713,7 @@ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) /* Blocked by MNG FW so don't reset PHY */ if (ixgbe_check_reset_blocked(hw)) - return status; + return 0; /* Restart PHY autonegotiation and wait for completion */ hw->phy.ops.read_reg(hw, MDIO_CTRL1, @@ -744,8 +738,8 @@ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) } if (time_out == max_time_out) { - status = IXGBE_ERR_LINK_SETUP; hw_dbg(hw, "ixgbe_setup_phy_link_tnx: time out\n"); + return IXGBE_ERR_LINK_SETUP; } return status; @@ -759,7 +753,7 @@ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, u16 *firmware_version) { - s32 status = 0; + s32 status; status = hw->phy.ops.read_reg(hw, TNX_FW_REV, MDIO_MMD_VEND1, @@ -776,7 +770,7 @@ s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, s32 ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw *hw, u16 *firmware_version) { - s32 status = 0; + s32 status; status = hw->phy.ops.read_reg(hw, AQ_FW_REV, MDIO_MMD_VEND1, @@ -795,12 +789,12 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) bool end_data = false; u16 list_offset, data_offset; u16 phy_data = 0; - s32 ret_val = 0; + s32 ret_val; u32 i; /* Blocked by MNG FW so bail */ if (ixgbe_check_reset_blocked(hw)) - goto out; + return 0; hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, &phy_data); @@ -818,15 +812,14 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) if ((phy_data & MDIO_CTRL1_RESET) != 0) { hw_dbg(hw, "PHY reset did not complete.\n"); - ret_val = IXGBE_ERR_PHY; - goto out; + return IXGBE_ERR_PHY; } /* Get init offsets */ ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, &data_offset); - if (ret_val != 0) - goto out; + if (ret_val) + return ret_val; ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc); data_offset++; @@ -876,18 +869,15 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) hw_dbg(hw, "SOL\n"); } else { hw_dbg(hw, "Bad control value\n"); - ret_val = IXGBE_ERR_PHY; - goto out; + return IXGBE_ERR_PHY; } break; default: hw_dbg(hw, "Bad control type\n"); - ret_val = IXGBE_ERR_PHY; - goto out; + return IXGBE_ERR_PHY; } } -out: return ret_val; err_eeprom: @@ -903,34 +893,29 @@ err_eeprom: **/ s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw) { - s32 status = IXGBE_ERR_SFP_NOT_PRESENT; - switch (hw->mac.ops.get_media_type(hw)) { case ixgbe_media_type_fiber: - status = ixgbe_identify_sfp_module_generic(hw); - break; + return ixgbe_identify_sfp_module_generic(hw); case ixgbe_media_type_fiber_qsfp: - status = ixgbe_identify_qsfp_module_generic(hw); - break; + return ixgbe_identify_qsfp_module_generic(hw); default: hw->phy.sfp_type = ixgbe_sfp_type_not_present; - status = IXGBE_ERR_SFP_NOT_PRESENT; - break; + return IXGBE_ERR_SFP_NOT_PRESENT; } - return status; + return IXGBE_ERR_SFP_NOT_PRESENT; } /** * ixgbe_identify_sfp_module_generic - Identifies SFP modules * @hw: pointer to hardware structure -* + * * Searches for and identifies the SFP module and assigns appropriate PHY type. **/ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) { struct ixgbe_adapter *adapter = hw->back; - s32 status = IXGBE_ERR_PHY_ADDR_INVALID; + s32 status; u32 vendor_oui = 0; enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; u8 identifier = 0; @@ -943,15 +928,14 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) { hw->phy.sfp_type = ixgbe_sfp_type_not_present; - status = IXGBE_ERR_SFP_NOT_PRESENT; - goto out; + return IXGBE_ERR_SFP_NOT_PRESENT; } status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, &identifier); - if (status != 0) + if (status) goto err_read_i2c_eeprom; /* LAN ID is needed for sfp_type determination */ @@ -959,239 +943,224 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) if (identifier != IXGBE_SFF_IDENTIFIER_SFP) { hw->phy.type = ixgbe_phy_sfp_unsupported; - status = IXGBE_ERR_SFP_NOT_SUPPORTED; - } else { - status = hw->phy.ops.read_i2c_eeprom(hw, - IXGBE_SFF_1GBE_COMP_CODES, - &comp_codes_1g); + return IXGBE_ERR_SFP_NOT_SUPPORTED; + } + status = hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_1GBE_COMP_CODES, + &comp_codes_1g); - if (status != 0) - goto err_read_i2c_eeprom; + if (status) + goto err_read_i2c_eeprom; - status = hw->phy.ops.read_i2c_eeprom(hw, - IXGBE_SFF_10GBE_COMP_CODES, - &comp_codes_10g); + status = hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_10GBE_COMP_CODES, + &comp_codes_10g); - if (status != 0) - goto err_read_i2c_eeprom; - status = hw->phy.ops.read_i2c_eeprom(hw, - IXGBE_SFF_CABLE_TECHNOLOGY, - &cable_tech); + if (status) + goto err_read_i2c_eeprom; + status = hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_CABLE_TECHNOLOGY, + &cable_tech); - if (status != 0) - goto err_read_i2c_eeprom; + if (status) + goto err_read_i2c_eeprom; - /* ID Module - * ========= - * 0 SFP_DA_CU - * 1 SFP_SR - * 2 SFP_LR - * 3 SFP_DA_CORE0 - 82599-specific - * 4 SFP_DA_CORE1 - 82599-specific - * 5 SFP_SR/LR_CORE0 - 82599-specific - * 6 SFP_SR/LR_CORE1 - 82599-specific - * 7 SFP_act_lmt_DA_CORE0 - 82599-specific - * 8 SFP_act_lmt_DA_CORE1 - 82599-specific - * 9 SFP_1g_cu_CORE0 - 82599-specific - * 10 SFP_1g_cu_CORE1 - 82599-specific - * 11 SFP_1g_sx_CORE0 - 82599-specific - * 12 SFP_1g_sx_CORE1 - 82599-specific - */ - if (hw->mac.type == ixgbe_mac_82598EB) { - if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) - hw->phy.sfp_type = ixgbe_sfp_type_da_cu; - else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) - hw->phy.sfp_type = ixgbe_sfp_type_sr; - else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) - hw->phy.sfp_type = ixgbe_sfp_type_lr; + /* ID Module + * ========= + * 0 SFP_DA_CU + * 1 SFP_SR + * 2 SFP_LR + * 3 SFP_DA_CORE0 - 82599-specific + * 4 SFP_DA_CORE1 - 82599-specific + * 5 SFP_SR/LR_CORE0 - 82599-specific + * 6 SFP_SR/LR_CORE1 - 82599-specific + * 7 SFP_act_lmt_DA_CORE0 - 82599-specific + * 8 SFP_act_lmt_DA_CORE1 - 82599-specific + * 9 SFP_1g_cu_CORE0 - 82599-specific + * 10 SFP_1g_cu_CORE1 - 82599-specific + * 11 SFP_1g_sx_CORE0 - 82599-specific + * 12 SFP_1g_sx_CORE1 - 82599-specific + */ + if (hw->mac.type == ixgbe_mac_82598EB) { + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) + hw->phy.sfp_type = ixgbe_sfp_type_da_cu; + else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) + hw->phy.sfp_type = ixgbe_sfp_type_sr; + else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) + hw->phy.sfp_type = ixgbe_sfp_type_lr; + else + hw->phy.sfp_type = ixgbe_sfp_type_unknown; + } else if (hw->mac.type == ixgbe_mac_82599EB) { + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) { + if (hw->bus.lan_id == 0) + hw->phy.sfp_type = + ixgbe_sfp_type_da_cu_core0; else - hw->phy.sfp_type = ixgbe_sfp_type_unknown; - } else if (hw->mac.type == ixgbe_mac_82599EB) { - if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) { - if (hw->bus.lan_id == 0) - hw->phy.sfp_type = - ixgbe_sfp_type_da_cu_core0; - else - hw->phy.sfp_type = - ixgbe_sfp_type_da_cu_core1; - } else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) { - hw->phy.ops.read_i2c_eeprom( - hw, IXGBE_SFF_CABLE_SPEC_COMP, - &cable_spec); - if (cable_spec & - IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) { - if (hw->bus.lan_id == 0) - hw->phy.sfp_type = - ixgbe_sfp_type_da_act_lmt_core0; - else - hw->phy.sfp_type = - ixgbe_sfp_type_da_act_lmt_core1; - } else { - hw->phy.sfp_type = - ixgbe_sfp_type_unknown; - } - } else if (comp_codes_10g & - (IXGBE_SFF_10GBASESR_CAPABLE | - IXGBE_SFF_10GBASELR_CAPABLE)) { - if (hw->bus.lan_id == 0) - hw->phy.sfp_type = - ixgbe_sfp_type_srlr_core0; - else - hw->phy.sfp_type = - ixgbe_sfp_type_srlr_core1; - } else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) { - if (hw->bus.lan_id == 0) - hw->phy.sfp_type = - ixgbe_sfp_type_1g_cu_core0; - else - hw->phy.sfp_type = - ixgbe_sfp_type_1g_cu_core1; - } else if (comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) { - if (hw->bus.lan_id == 0) - hw->phy.sfp_type = - ixgbe_sfp_type_1g_sx_core0; - else - hw->phy.sfp_type = - ixgbe_sfp_type_1g_sx_core1; - } else if (comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) { + hw->phy.sfp_type = + ixgbe_sfp_type_da_cu_core1; + } else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) { + hw->phy.ops.read_i2c_eeprom( + hw, IXGBE_SFF_CABLE_SPEC_COMP, + &cable_spec); + if (cable_spec & + IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) { if (hw->bus.lan_id == 0) hw->phy.sfp_type = - ixgbe_sfp_type_1g_lx_core0; + ixgbe_sfp_type_da_act_lmt_core0; else hw->phy.sfp_type = - ixgbe_sfp_type_1g_lx_core1; + ixgbe_sfp_type_da_act_lmt_core1; } else { - hw->phy.sfp_type = ixgbe_sfp_type_unknown; + hw->phy.sfp_type = + ixgbe_sfp_type_unknown; } + } else if (comp_codes_10g & + (IXGBE_SFF_10GBASESR_CAPABLE | + IXGBE_SFF_10GBASELR_CAPABLE)) { + if (hw->bus.lan_id == 0) + hw->phy.sfp_type = + ixgbe_sfp_type_srlr_core0; + else + hw->phy.sfp_type = + ixgbe_sfp_type_srlr_core1; + } else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) { + if (hw->bus.lan_id == 0) + hw->phy.sfp_type = + ixgbe_sfp_type_1g_cu_core0; + else + hw->phy.sfp_type = + ixgbe_sfp_type_1g_cu_core1; + } else if (comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) { + if (hw->bus.lan_id == 0) + hw->phy.sfp_type = + ixgbe_sfp_type_1g_sx_core0; + else + hw->phy.sfp_type = + ixgbe_sfp_type_1g_sx_core1; + } else if (comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) { + if (hw->bus.lan_id == 0) + hw->phy.sfp_type = + ixgbe_sfp_type_1g_lx_core0; + else + hw->phy.sfp_type = + ixgbe_sfp_type_1g_lx_core1; + } else { + hw->phy.sfp_type = ixgbe_sfp_type_unknown; } + } - if (hw->phy.sfp_type != stored_sfp_type) - hw->phy.sfp_setup_needed = true; - - /* Determine if the SFP+ PHY is dual speed or not. */ - hw->phy.multispeed_fiber = false; - if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && - (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || - ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && - (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE))) - hw->phy.multispeed_fiber = true; - - /* Determine PHY vendor */ - if (hw->phy.type != ixgbe_phy_nl) { - hw->phy.id = identifier; - status = hw->phy.ops.read_i2c_eeprom(hw, - IXGBE_SFF_VENDOR_OUI_BYTE0, - &oui_bytes[0]); - - if (status != 0) - goto err_read_i2c_eeprom; - - status = hw->phy.ops.read_i2c_eeprom(hw, - IXGBE_SFF_VENDOR_OUI_BYTE1, - &oui_bytes[1]); - - if (status != 0) - goto err_read_i2c_eeprom; - - status = hw->phy.ops.read_i2c_eeprom(hw, - IXGBE_SFF_VENDOR_OUI_BYTE2, - &oui_bytes[2]); - - if (status != 0) - goto err_read_i2c_eeprom; - - vendor_oui = - ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | - (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | - (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); - - switch (vendor_oui) { - case IXGBE_SFF_VENDOR_OUI_TYCO: - if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) - hw->phy.type = - ixgbe_phy_sfp_passive_tyco; - break; - case IXGBE_SFF_VENDOR_OUI_FTL: - if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) - hw->phy.type = ixgbe_phy_sfp_ftl_active; - else - hw->phy.type = ixgbe_phy_sfp_ftl; - break; - case IXGBE_SFF_VENDOR_OUI_AVAGO: - hw->phy.type = ixgbe_phy_sfp_avago; - break; - case IXGBE_SFF_VENDOR_OUI_INTEL: - hw->phy.type = ixgbe_phy_sfp_intel; - break; - default: - if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) - hw->phy.type = - ixgbe_phy_sfp_passive_unknown; - else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) - hw->phy.type = - ixgbe_phy_sfp_active_unknown; - else - hw->phy.type = ixgbe_phy_sfp_unknown; - break; - } - } + if (hw->phy.sfp_type != stored_sfp_type) + hw->phy.sfp_setup_needed = true; - /* Allow any DA cable vendor */ - if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE | - IXGBE_SFF_DA_ACTIVE_CABLE)) { - status = 0; - goto out; - } + /* Determine if the SFP+ PHY is dual speed or not. */ + hw->phy.multispeed_fiber = false; + if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && + (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || + ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && + (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE))) + hw->phy.multispeed_fiber = true; - /* Verify supported 1G SFP modules */ - if (comp_codes_10g == 0 && - !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { - hw->phy.type = ixgbe_phy_sfp_unsupported; - status = IXGBE_ERR_SFP_NOT_SUPPORTED; - goto out; - } + /* Determine PHY vendor */ + if (hw->phy.type != ixgbe_phy_nl) { + hw->phy.id = identifier; + status = hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_VENDOR_OUI_BYTE0, + &oui_bytes[0]); - /* Anything else 82598-based is supported */ - if (hw->mac.type == ixgbe_mac_82598EB) { - status = 0; - goto out; - } + if (status != 0) + goto err_read_i2c_eeprom; - hw->mac.ops.get_device_caps(hw, &enforce_sfp); - if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) && - !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { - /* Make sure we're a supported PHY type */ - if (hw->phy.type == ixgbe_phy_sfp_intel) { - status = 0; - } else { - if (hw->allow_unsupported_sfp) { - e_warn(drv, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n"); - status = 0; - } else { - hw_dbg(hw, - "SFP+ module not supported\n"); - hw->phy.type = - ixgbe_phy_sfp_unsupported; - status = IXGBE_ERR_SFP_NOT_SUPPORTED; - } - } - } else { - status = 0; + status = hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_VENDOR_OUI_BYTE1, + &oui_bytes[1]); + + if (status != 0) + goto err_read_i2c_eeprom; + + status = hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_VENDOR_OUI_BYTE2, + &oui_bytes[2]); + + if (status != 0) + goto err_read_i2c_eeprom; + + vendor_oui = + ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | + (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | + (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); + + switch (vendor_oui) { + case IXGBE_SFF_VENDOR_OUI_TYCO: + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) + hw->phy.type = + ixgbe_phy_sfp_passive_tyco; + break; + case IXGBE_SFF_VENDOR_OUI_FTL: + if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) + hw->phy.type = ixgbe_phy_sfp_ftl_active; + else + hw->phy.type = ixgbe_phy_sfp_ftl; + break; + case IXGBE_SFF_VENDOR_OUI_AVAGO: + hw->phy.type = ixgbe_phy_sfp_avago; + break; + case IXGBE_SFF_VENDOR_OUI_INTEL: + hw->phy.type = ixgbe_phy_sfp_intel; + break; + default: + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) + hw->phy.type = + ixgbe_phy_sfp_passive_unknown; + else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) + hw->phy.type = + ixgbe_phy_sfp_active_unknown; + else + hw->phy.type = ixgbe_phy_sfp_unknown; + break; } } -out: - return status; + /* Allow any DA cable vendor */ + if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE | + IXGBE_SFF_DA_ACTIVE_CABLE)) + return 0; + + /* Verify supported 1G SFP modules */ + if (comp_codes_10g == 0 && + !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { + hw->phy.type = ixgbe_phy_sfp_unsupported; + return IXGBE_ERR_SFP_NOT_SUPPORTED; + } + + /* Anything else 82598-based is supported */ + if (hw->mac.type == ixgbe_mac_82598EB) + return 0; + + hw->mac.ops.get_device_caps(hw, &enforce_sfp); + if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) && + !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { + /* Make sure we're a supported PHY type */ + if (hw->phy.type == ixgbe_phy_sfp_intel) + return 0; + if (hw->allow_unsupported_sfp) { + e_warn(drv, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n"); + return 0; + } + hw_dbg(hw, "SFP+ module not supported\n"); + hw->phy.type = ixgbe_phy_sfp_unsupported; + return IXGBE_ERR_SFP_NOT_SUPPORTED; + } + return 0; err_read_i2c_eeprom: hw->phy.sfp_type = ixgbe_sfp_type_not_present; @@ -1211,7 +1180,7 @@ err_read_i2c_eeprom: static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw) { struct ixgbe_adapter *adapter = hw->back; - s32 status = IXGBE_ERR_PHY_ADDR_INVALID; + s32 status; u32 vendor_oui = 0; enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; u8 identifier = 0; @@ -1226,8 +1195,7 @@ static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw) if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber_qsfp) { hw->phy.sfp_type = ixgbe_sfp_type_not_present; - status = IXGBE_ERR_SFP_NOT_PRESENT; - goto out; + return IXGBE_ERR_SFP_NOT_PRESENT; } status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, @@ -1238,8 +1206,7 @@ static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw) if (identifier != IXGBE_SFF_IDENTIFIER_QSFP_PLUS) { hw->phy.type = ixgbe_phy_sfp_unsupported; - status = IXGBE_ERR_SFP_NOT_SUPPORTED; - goto out; + return IXGBE_ERR_SFP_NOT_SUPPORTED; } hw->phy.id = identifier; @@ -1310,8 +1277,7 @@ static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw) } else { /* unsupported module type */ hw->phy.type = ixgbe_phy_sfp_unsupported; - status = IXGBE_ERR_SFP_NOT_SUPPORTED; - goto out; + return IXGBE_ERR_SFP_NOT_SUPPORTED; } } @@ -1363,27 +1329,19 @@ static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw) hw->mac.ops.get_device_caps(hw, &enforce_sfp); if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) { /* Make sure we're a supported PHY type */ - if (hw->phy.type == ixgbe_phy_qsfp_intel) { - status = 0; - } else { - if (hw->allow_unsupported_sfp == true) { - e_warn(drv, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n"); - status = 0; - } else { - hw_dbg(hw, - "QSFP module not supported\n"); - hw->phy.type = - ixgbe_phy_sfp_unsupported; - status = IXGBE_ERR_SFP_NOT_SUPPORTED; - } + if (hw->phy.type == ixgbe_phy_qsfp_intel) + return 0; + if (hw->allow_unsupported_sfp) { + e_warn(drv, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n"); + return 0; } - } else { - status = 0; + hw_dbg(hw, "QSFP module not supported\n"); + hw->phy.type = ixgbe_phy_sfp_unsupported; + return IXGBE_ERR_SFP_NOT_SUPPORTED; } + return 0; } - -out: - return status; + return 0; err_read_i2c_eeprom: hw->phy.sfp_type = ixgbe_sfp_type_not_present; @@ -1544,7 +1502,7 @@ s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data) { - s32 status = 0; + s32 status; u32 max_retry = 10; u32 retry = 0; u16 swfw_mask = 0; @@ -1557,10 +1515,8 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, swfw_mask = IXGBE_GSSR_PHY0_SM; do { - if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != 0) { - status = IXGBE_ERR_SWFW_SYNC; - goto read_byte_out; - } + if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) + return IXGBE_ERR_SWFW_SYNC; ixgbe_i2c_start(hw); @@ -1617,7 +1573,6 @@ fail: hw->mac.ops.release_swfw_sync(hw, swfw_mask); -read_byte_out: return status; } @@ -1633,7 +1588,7 @@ read_byte_out: s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data) { - s32 status = 0; + s32 status; u32 max_retry = 1; u32 retry = 0; u16 swfw_mask = 0; @@ -1643,10 +1598,8 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, else swfw_mask = IXGBE_GSSR_PHY0_SM; - if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != 0) { - status = IXGBE_ERR_SWFW_SYNC; - goto write_byte_out; - } + if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) + return IXGBE_ERR_SWFW_SYNC; do { ixgbe_i2c_start(hw); @@ -1689,7 +1642,6 @@ fail: hw->mac.ops.release_swfw_sync(hw, swfw_mask); -write_byte_out: return status; } @@ -1774,7 +1726,7 @@ static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data) **/ static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data) { - s32 status = 0; + s32 status; s32 i; u32 i2cctl; bool bit = false; @@ -1893,11 +1845,11 @@ static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data) */ udelay(IXGBE_I2C_T_LOW); } else { - status = IXGBE_ERR_I2C; hw_dbg(hw, "I2C data was not set to %X\n", data); + return IXGBE_ERR_I2C; } - return status; + return 0; } /** * ixgbe_raise_i2c_clk - Raises the I2C SCL clock @@ -1954,8 +1906,6 @@ static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) **/ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) { - s32 status = 0; - if (data) *i2cctl |= IXGBE_I2C_DATA_OUT; else @@ -1970,11 +1920,11 @@ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) /* Verify data was set correctly */ *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL); if (data != ixgbe_get_i2c_data(i2cctl)) { - status = IXGBE_ERR_I2C; hw_dbg(hw, "Error - I2C data was not set to %X.\n", data); + return IXGBE_ERR_I2C; } - return status; + return 0; } /** @@ -1986,14 +1936,9 @@ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) **/ static bool ixgbe_get_i2c_data(u32 *i2cctl) { - bool data; - if (*i2cctl & IXGBE_I2C_DATA_IN) - data = true; - else - data = false; - - return data; + return true; + return false; } /** @@ -2038,20 +1983,17 @@ static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw) **/ s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw) { - s32 status = 0; u16 phy_data = 0; if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM) - goto out; + return 0; /* Check that the LASI temp alarm status was triggered */ hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG, MDIO_MMD_PMAPMD, &phy_data); if (!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM)) - goto out; + return 0; - status = IXGBE_ERR_OVERTEMP; -out: - return status; + return IXGBE_ERR_OVERTEMP; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index 16b3a1cd9db6..c14d4d89672f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 2014 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -245,10 +245,10 @@ static int ixgbe_pci_sriov_enable(struct pci_dev *dev, int num_vfs) if (pre_existing_vfs && pre_existing_vfs != num_vfs) err = ixgbe_disable_sriov(adapter); else if (pre_existing_vfs && pre_existing_vfs == num_vfs) - goto out; + return num_vfs; if (err) - goto err_out; + return err; /* While the SR-IOV capability structure reports total VFs to be * 64 we limit the actual number that can be allocated to 63 so @@ -256,16 +256,14 @@ static int ixgbe_pci_sriov_enable(struct pci_dev *dev, int num_vfs) * PF. The PCI bus driver already checks for other values out of * range. */ - if (num_vfs > IXGBE_MAX_VFS_DRV_LIMIT) { - err = -EPERM; - goto err_out; - } + if (num_vfs > IXGBE_MAX_VFS_DRV_LIMIT) + return -EPERM; adapter->num_vfs = num_vfs; err = __ixgbe_enable_sriov(adapter); if (err) - goto err_out; + return err; for (i = 0; i < adapter->num_vfs; i++) ixgbe_vf_configuration(dev, (i | 0x10000000)); @@ -273,17 +271,14 @@ static int ixgbe_pci_sriov_enable(struct pci_dev *dev, int num_vfs) err = pci_enable_sriov(dev, num_vfs); if (err) { e_dev_warn("Failed to enable PCI sriov: %d\n", err); - goto err_out; + return err; } ixgbe_sriov_reinit(adapter); -out: return num_vfs; - -err_out: - return err; -#endif +#else return 0; +#endif } static int ixgbe_pci_sriov_disable(struct pci_dev *dev) @@ -807,7 +802,7 @@ static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter, if (!add && adapter->netdev->flags & IFF_PROMISC) { reg_ndx = ixgbe_find_vlvf_entry(hw, vid); if (reg_ndx < 0) - goto out; + return err; vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(reg_ndx)); /* See if any other pools are set for this VLAN filter * entry other than the PF. @@ -833,8 +828,6 @@ static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter, ixgbe_set_vf_vlan(adapter, add, vid, VMDQ_P(0)); } -out: - return err; } @@ -951,7 +944,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) /* this is a message we already processed, do nothing */ if (msgbuf[0] & (IXGBE_VT_MSGTYPE_ACK | IXGBE_VT_MSGTYPE_NACK)) - return retval; + return 0; /* flush the ack before we write any messages back */ IXGBE_WRITE_FLUSH(hw); @@ -966,7 +959,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) if (!adapter->vfinfo[vf].clear_to_send) { msgbuf[0] |= IXGBE_VT_MSGTYPE_NACK; ixgbe_write_mbx(hw, msgbuf, 1, vf); - return retval; + return 0; } switch ((msgbuf[0] & 0xFFFF)) { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index 7920ab9a18cb..e88305d5d18d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -99,8 +99,8 @@ static s32 ixgbe_reset_hw_X540(struct ixgbe_hw *hw) /* Call adapter stop to disable tx/rx and clear interrupts */ status = hw->mac.ops.stop_adapter(hw); - if (status != 0) - goto reset_hw_out; + if (status) + return status; /* flush pending Tx transactions */ ixgbe_clear_tx_pending(hw); @@ -168,7 +168,6 @@ mac_reset_top: hw->mac.ops.get_wwn_prefix(hw, &hw->mac.wwnn_prefix, &hw->mac.wwpn_prefix); -reset_hw_out: return status; } @@ -182,15 +181,13 @@ reset_hw_out: **/ static s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw) { - s32 ret_val = 0; + s32 ret_val; ret_val = ixgbe_start_hw_generic(hw); - if (ret_val != 0) - goto out; + if (ret_val) + return ret_val; - ret_val = ixgbe_start_hw_gen2(hw); -out: - return ret_val; + return ixgbe_start_hw_gen2(hw); } /** @@ -483,12 +480,12 @@ static s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw) static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) { u32 flup; - s32 status = IXGBE_ERR_EEPROM; + s32 status; status = ixgbe_poll_flash_update_done_X540(hw); if (status == IXGBE_ERR_EEPROM) { hw_dbg(hw, "Flash update time out\n"); - goto out; + return status; } flup = IXGBE_READ_REG(hw, IXGBE_EEC) | IXGBE_EEC_FLUP; @@ -514,7 +511,7 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) else hw_dbg(hw, "Flash update time out\n"); } -out: + return status; } @@ -529,17 +526,14 @@ static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw) { u32 i; u32 reg; - s32 status = IXGBE_ERR_EEPROM; for (i = 0; i < IXGBE_FLUDONE_ATTEMPTS; i++) { reg = IXGBE_READ_REG(hw, IXGBE_EEC); - if (reg & IXGBE_EEC_FLUDONE) { - status = 0; - break; - } + if (reg & IXGBE_EEC_FLUDONE) + return 0; udelay(5); } - return status; + return IXGBE_ERR_EEPROM; } /** -- cgit v1.2.3 From 493004d04f56fd7d642bdbb2938e17e5f7d622d1 Mon Sep 17 00:00:00 2001 From: David Ertman Date: Fri, 4 Jul 2014 01:44:32 +0000 Subject: e1000e: Fix CRC errors with jumbo traffic Modifying the jumbo frame workaround for 82579, i217 and i218 client parts to increase the gap between the read and write pointers in the Tx FIFO. Signed-off-by: Dave Ertman Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/defines.h | 1 + drivers/net/ethernet/intel/e1000e/ich8lan.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index d18e89212575..bb7ab3c321d6 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -342,6 +342,7 @@ #define E1000_TIPG_IPGR2_SHIFT 20 #define MAX_JUMBO_FRAME_SIZE 0x3F00 +#define E1000_TX_PTR_GAP 0x1F /* Extended Configuration Control and Size */ #define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index f236861c2a31..8dbcdc81104e 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -2444,7 +2444,7 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable) return ret_val; e1e_rphy(hw, PHY_REG(776, 20), &data); data &= ~(0x3FF << 2); - data |= (0x1A << 2); + data |= (E1000_TX_PTR_GAP << 2); ret_val = e1e_wphy(hw, PHY_REG(776, 20), data); if (ret_val) return ret_val; -- cgit v1.2.3 From 491a04d2812b0a665bda34ea39875833dc7a1aaf Mon Sep 17 00:00:00 2001 From: David Ertman Date: Wed, 9 Jul 2014 16:07:42 +0000 Subject: e1000e: Add code to check return values on NVM accesses Adding code to check and respond to previously ignored return values from NVM access functions. Issue discovered through static analysis. Signed-off-by: Dave Ertman Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/manage.c | 5 ++++- drivers/net/ethernet/intel/e1000e/netdev.c | 22 ++++++++++++++++------ drivers/net/ethernet/intel/e1000e/nvm.c | 4 +++- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/manage.c b/drivers/net/ethernet/intel/e1000e/manage.c index cb37ff1f1321..58856032298d 100644 --- a/drivers/net/ethernet/intel/e1000e/manage.c +++ b/drivers/net/ethernet/intel/e1000e/manage.c @@ -327,9 +327,12 @@ bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw) } else if ((hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82583)) { u16 data; + s32 ret_val; factps = er32(FACTPS); - e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data); + ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data); + if (ret_val) + return false; if (!(factps & E1000_FACTPS_MNGCG) && ((data & E1000_NVM_INIT_CTRL2_MNGM) == diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 201cc93f3625..fe3e42a6c8e9 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6708,6 +6708,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int bars, i, err, pci_using_dac; u16 eeprom_data = 0; u16 eeprom_apme_mask = E1000_EEPROM_APME; + s32 rval = 0; if (ei->flags2 & FLAG2_DISABLE_ASPM_L0S) aspm_disable_flag = PCIE_LINK_STATE_L0S; @@ -6940,15 +6941,19 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } else if (adapter->flags & FLAG_APME_IN_CTRL3) { if (adapter->flags & FLAG_APME_CHECK_PORT_B && (adapter->hw.bus.func == 1)) - e1000_read_nvm(&adapter->hw, NVM_INIT_CONTROL3_PORT_B, - 1, &eeprom_data); + rval = e1000_read_nvm(&adapter->hw, + NVM_INIT_CONTROL3_PORT_B, + 1, &eeprom_data); else - e1000_read_nvm(&adapter->hw, NVM_INIT_CONTROL3_PORT_A, - 1, &eeprom_data); + rval = e1000_read_nvm(&adapter->hw, + NVM_INIT_CONTROL3_PORT_A, + 1, &eeprom_data); } /* fetch WoL from EEPROM */ - if (eeprom_data & eeprom_apme_mask) + if (rval) + e_dbg("NVM read error getting WoL initial values: %d\n", rval); + else if (eeprom_data & eeprom_apme_mask) adapter->eeprom_wol |= E1000_WUFC_MAG; /* now that we have the eeprom settings, apply the special cases @@ -6967,7 +6972,12 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) device_wakeup_enable(&pdev->dev); /* save off EEPROM version number */ - e1000_read_nvm(&adapter->hw, 5, 1, &adapter->eeprom_vers); + rval = e1000_read_nvm(&adapter->hw, 5, 1, &adapter->eeprom_vers); + + if (rval) { + e_dbg("NVM read error getting EEPROM version: %d\n", rval); + adapter->eeprom_vers = 0; + } /* reset the hardware with the new settings */ e1000e_reset(adapter); diff --git a/drivers/net/ethernet/intel/e1000e/nvm.c b/drivers/net/ethernet/intel/e1000e/nvm.c index b1f212b7baf7..fa6b1036a327 100644 --- a/drivers/net/ethernet/intel/e1000e/nvm.c +++ b/drivers/net/ethernet/intel/e1000e/nvm.c @@ -327,8 +327,10 @@ s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) ew32(EERD, eerd); ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ); - if (ret_val) + if (ret_val) { + e_dbg("NVM read error: %d\n", ret_val); break; + } data[i] = (er32(EERD) >> E1000_NVM_RW_REG_DATA); } -- cgit v1.2.3 From b4c1e6bf1c8522a6c6c8f29226a1e2cf126431df Mon Sep 17 00:00:00 2001 From: David Ertman Date: Fri, 11 Jul 2014 06:20:51 +0000 Subject: e1000e: Add support for EEE in Sx states On I217 and newer hardware, EEE is enabled in the PHY by the software when link is up and disabled by the hardware when link is lost. To enable EEE in Sx (When both ends of the link support, and are enabled for, EEE and 100Mbps), we need to disable LPLU and configure the PHY to automatically enable EEE when link is up, since there will be no software to complete the task. To configure this in the PHY, the Auto Enable LPI bit in the Low Power Idle GPIO Control register must be set. For normal operation in S0, this bit must be cleared. Signed-off-by: Dave Ertman Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ich8lan.c | 18 ++++++++++++++++-- drivers/net/ethernet/intel/e1000e/ich8lan.h | 4 ++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 8dbcdc81104e..48b74a549155 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -4605,14 +4605,23 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw) /* Disable LPLU if both link partners support 100BaseT * EEE and 100Full is advertised on both ends of the - * link. + * link, and enable Auto Enable LPI since there will + * be no driver to enable LPI while in Sx. */ if ((eee_advert & I82579_EEE_100_SUPPORTED) && (dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) && - (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)) + (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)) { phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_NOND0A_LPLU); + + /* Set Auto Enable LPI after link up */ + e1e_rphy_locked(hw, + I217_LPI_GPIO_CTRL, &phy_reg); + phy_reg |= I217_LPI_GPIO_CTRL_AUTO_EN_LPI; + e1e_wphy_locked(hw, + I217_LPI_GPIO_CTRL, phy_reg); + } } /* For i217 Intel Rapid Start Technology support, @@ -4709,6 +4718,11 @@ void e1000_resume_workarounds_pchlan(struct e1000_hw *hw) return; } + /* Clear Auto Enable LPI after link up */ + e1e_rphy_locked(hw, I217_LPI_GPIO_CTRL, &phy_reg); + phy_reg &= ~I217_LPI_GPIO_CTRL_AUTO_EN_LPI; + e1e_wphy_locked(hw, I217_LPI_GPIO_CTRL, phy_reg); + if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) { /* Restore clear on SMB if no manageability engine * is present diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h index 5515126c81c1..8066a498eaac 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h @@ -217,6 +217,10 @@ #define I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK 0x3F00 #define I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT 8 +/* Low Power Idle GPIO Control */ +#define I217_LPI_GPIO_CTRL PHY_REG(772, 18) +#define I217_LPI_GPIO_CTRL_AUTO_EN_LPI 0x0800 + /* PHY Low Power Idle Control */ #define I82579_LPI_CTRL PHY_REG(772, 20) #define I82579_LPI_CTRL_100_ENABLE 0x2000 -- cgit v1.2.3 From 2116bc25e8aefd76503dfa2fc328eb8da684bb38 Mon Sep 17 00:00:00 2001 From: David Ertman Date: Fri, 11 Jul 2014 06:21:23 +0000 Subject: e1000e: Fix EEE in S5 w/ Runtime PM enabled The process of shutting down the system causes a call to the close PM callback. The reset in close causes a loss of link, and the resultant LSC interrupt causes the Runtime PM idle callback to be called. The check for link (while link is down) in the idle callback is wiping the information about the EEE ability of the link partner. The information is still gone when the PHY is powered back up in the shutdown flow. This causes EEE in S5 to fail when Runtime PM is active. Save the link partner's EEE ability in the idle callback so that a Runtime PM event will not cause a loss of this information. Signed-off-by: Dave Ertman Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index fe3e42a6c8e9..1ce0d743029c 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6357,9 +6357,14 @@ static int e1000e_pm_runtime_idle(struct device *dev) struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); + u16 eee_lp; - if (!e1000e_has_link(adapter)) + eee_lp = adapter->hw.dev_spec.ich8lan.eee_lp_ability; + + if (!e1000e_has_link(adapter)) { + adapter->hw.dev_spec.ich8lan.eee_lp_ability = eee_lp; pm_schedule_suspend(dev, 5 * MSEC_PER_SEC); + } return -EBUSY; } -- cgit v1.2.3 From 2a7e19af94104b270d675c52bba2ca1bc20efa70 Mon Sep 17 00:00:00 2001 From: David Ertman Date: Fri, 11 Jul 2014 06:21:31 +0000 Subject: e1000e: Fix Runtime PM blocks EEE link negotiation in S5 Adding a function, and associated calls, to flush writes to (read) the LPIC MAC register before entering the shutdown flow. This fixes the problem of the PHY never negotiating a 100M link (if both sides of the link support EEE and 100M link) when Runtime PM is enabled. Signed-off-by: Dave Ertman Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 1ce0d743029c..65c3aef2bd36 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6033,6 +6033,28 @@ release: return retval; } +static void e1000e_flush_lpic(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 ret_val; + + pm_runtime_get_sync(netdev->dev.parent); + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto fl_out; + + pr_info("EEE TX LPI TIMER: %08X\n", + er32(LPIC) >> E1000_LPIC_LPIET_SHIFT); + + hw->phy.ops.release(hw); + +fl_out: + pm_runtime_put_sync(netdev->dev.parent); +} + static int e1000e_pm_freeze(struct device *dev) { struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev)); @@ -6333,6 +6355,8 @@ static int e1000e_pm_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); + e1000e_flush_lpic(pdev); + e1000e_pm_freeze(dev); return __e1000_shutdown(pdev, false); @@ -6416,6 +6440,8 @@ static int e1000e_pm_runtime_suspend(struct device *dev) static void e1000_shutdown(struct pci_dev *pdev) { + e1000e_flush_lpic(pdev); + e1000e_pm_freeze(&pdev->dev); __e1000_shutdown(pdev, false); -- cgit v1.2.3 From 8540f6c0364722b141547c6c7ac366c3ea77390b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 24 Jul 2014 15:20:57 +0200 Subject: Bluetooth: Add support for using controller white list filtering The Bluetooth controller can use a white list filter when scanning to avoid waking up the host for devices that are of no interest. Devices marked as reporting, direct connection (incoming) or general connection are now added to the controller white list. The update of the white list happens just before enabling passive scanning. In case the white list is full and can not hold all devices, the white list is not used and the filter policy set to accept all advertisements. Using the white list for scanning allows for power saving with controllers that do not handle the duplicate filtering correctly. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d8f91d5b0e56..ecff30ab22a0 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5406,12 +5406,101 @@ void hci_req_add_le_scan_disable(struct hci_request *req) hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); } +static void add_to_white_list(struct hci_request *req, + struct hci_conn_params *params) +{ + struct hci_cp_le_add_to_white_list cp; + + cp.bdaddr_type = params->addr_type; + bacpy(&cp.bdaddr, ¶ms->addr); + + hci_req_add(req, HCI_OP_LE_ADD_TO_WHITE_LIST, sizeof(cp), &cp); +} + +static u8 update_white_list(struct hci_request *req) +{ + struct hci_dev *hdev = req->hdev; + struct hci_conn_params *params; + struct bdaddr_list *b; + uint8_t white_list_entries = 0; + + /* Go through the current white list programmed into the + * controller one by one and check if that address is still + * in the list of pending connections or list of devices to + * report. If not present in either list, then queue the + * command to remove it from the controller. + */ + list_for_each_entry(b, &hdev->le_white_list, list) { + struct hci_cp_le_del_from_white_list cp; + + if (hci_pend_le_action_lookup(&hdev->pend_le_conns, + &b->bdaddr, b->bdaddr_type) || + hci_pend_le_action_lookup(&hdev->pend_le_reports, + &b->bdaddr, b->bdaddr_type)) { + white_list_entries++; + continue; + } + + cp.bdaddr_type = b->bdaddr_type; + bacpy(&cp.bdaddr, &b->bdaddr); + + hci_req_add(req, HCI_OP_LE_DEL_FROM_WHITE_LIST, + sizeof(cp), &cp); + } + + /* Since all no longer valid white list entries have been + * removed, walk through the list of pending connections + * and ensure that any new device gets programmed into + * the controller. + * + * If the list of the devices is larger than the list of + * available white list entries in the controller, then + * just abort and return filer policy value to not use the + * white list. + */ + list_for_each_entry(params, &hdev->pend_le_conns, action) { + if (hci_bdaddr_list_lookup(&hdev->le_white_list, + ¶ms->addr, params->addr_type)) + continue; + + if (white_list_entries >= hdev->le_white_list_size) { + /* Select filter policy to accept all advertising */ + return 0x00; + } + + white_list_entries++; + add_to_white_list(req, params); + } + + /* After adding all new pending connections, walk through + * the list of pending reports and also add these to the + * white list if there is still space. + */ + list_for_each_entry(params, &hdev->pend_le_reports, action) { + if (hci_bdaddr_list_lookup(&hdev->le_white_list, + ¶ms->addr, params->addr_type)) + continue; + + if (white_list_entries >= hdev->le_white_list_size) { + /* Select filter policy to accept all advertising */ + return 0x00; + } + + white_list_entries++; + add_to_white_list(req, params); + } + + /* Select filter policy to use white list */ + return 0x01; +} + void hci_req_add_le_passive_scan(struct hci_request *req) { struct hci_cp_le_set_scan_param param_cp; struct hci_cp_le_set_scan_enable enable_cp; struct hci_dev *hdev = req->hdev; u8 own_addr_type; + u8 filter_policy; /* Set require_privacy to false since no SCAN_REQ are send * during passive scanning. Not using an unresolvable address @@ -5422,11 +5511,18 @@ void hci_req_add_le_passive_scan(struct hci_request *req) if (hci_update_random_address(req, false, &own_addr_type)) return; + /* Adding or removing entries from the white list must + * happen before enabling scanning. The controller does + * not allow white list modification while scanning. + */ + filter_policy = update_white_list(req); + memset(¶m_cp, 0, sizeof(param_cp)); param_cp.type = LE_SCAN_PASSIVE; param_cp.interval = cpu_to_le16(hdev->le_scan_interval); param_cp.window = cpu_to_le16(hdev->le_scan_window); param_cp.own_address_type = own_addr_type; + param_cp.filter_policy = filter_policy; hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp), ¶m_cp); -- cgit v1.2.3 From 66d8e837ab4f58722c56ccbfa5ab9a522cebde78 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 24 Jul 2014 15:20:58 +0200 Subject: Bluetooth: Fix white list handling with resolvable private addresses Devices using resolvable private addresses are required to provide an identity resolving key. These devices can not be found using the current controller white list support. This means if the kernel knows about any devices with an identity resolving key, the white list filtering must be disabled. However so far the kernel kept identity resolving keys around even for devices that are not using resolvable private addresses. The notification to userspace clearly hints to not store the key and so it is best to just remove the key from the kernel as well at that point. With this it easy now to detect when using the white list is possible or when kernel side resolving of addresses is required. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 12 ++++++++++++ net/bluetooth/smp.c | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ecff30ab22a0..2e2961a3cf6f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5468,6 +5468,12 @@ static u8 update_white_list(struct hci_request *req) return 0x00; } + if (hci_find_irk_by_addr(hdev, ¶ms->addr, + params->addr_type)) { + /* White list can not be used with RPAs */ + return 0x00; + } + white_list_entries++; add_to_white_list(req, params); } @@ -5486,6 +5492,12 @@ static u8 update_white_list(struct hci_request *req) return 0x00; } + if (hci_find_irk_by_addr(hdev, ¶ms->addr, + params->addr_type)) { + /* White list can not be used with RPAs */ + return 0x00; + } + white_list_entries++; add_to_white_list(req, params); } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index e49c83d8b957..a7c344b4acbc 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1291,6 +1291,22 @@ static void smp_notify_keys(struct l2cap_conn *conn) bacpy(&hcon->dst, &smp->remote_irk->bdaddr); hcon->dst_type = smp->remote_irk->addr_type; l2cap_conn_update_id_addr(hcon); + + /* When receiving an indentity resolving key for + * a remote device that does not use a resolvable + * private address, just remove the key so that + * it is possible to use the controller white + * list for scanning. + * + * Userspace will have been told to not store + * this key at this point. So it is safe to + * just remove it. + */ + if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) { + list_del(&smp->remote_irk->list); + kfree(smp->remote_irk); + smp->remote_irk = NULL; + } } /* The LTKs and CSRKs should be persistent only if both sides -- cgit v1.2.3 From 628531c9e971f1bd023d9fbd00faff014ca22440 Mon Sep 17 00:00:00 2001 From: Georg Lukas Date: Sat, 26 Jul 2014 13:59:57 +0200 Subject: Bluetooth: Provide defaults for LE advertising interval Store the default values for minimum and maximum advertising interval with all the other controller defaults. These vaules are sent to the adapter whenever advertising is (re)enabled. Signed-off-by: Georg Lukas Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 2 ++ net/bluetooth/mgmt.c | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 747a0c3d9947..b5d5af3aa469 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -203,6 +203,8 @@ struct hci_dev { __u16 page_scan_window; __u8 page_scan_type; __u8 le_adv_channel_map; + __u16 le_adv_min_interval; + __u16 le_adv_max_interval; __u8 le_scan_type; __u16 le_scan_interval; __u16 le_scan_window; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2e2961a3cf6f..475d6003ed15 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3923,6 +3923,8 @@ struct hci_dev *hci_alloc_dev(void) hdev->sniff_min_interval = 80; hdev->le_adv_channel_map = 0x07; + hdev->le_adv_min_interval = 0x0800; + hdev->le_adv_max_interval = 0x0800; hdev->le_scan_interval = 0x0060; hdev->le_scan_window = 0x0030; hdev->le_conn_min_interval = 0x0028; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ccc4653ce658..ff874580d989 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1086,8 +1086,8 @@ static void enable_advertising(struct hci_request *req) return; memset(&cp, 0, sizeof(cp)); - cp.min_interval = cpu_to_le16(0x0800); - cp.max_interval = cpu_to_le16(0x0800); + cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval); + cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval); cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND; cp.own_address_type = own_addr_type; cp.channel_map = hdev->le_adv_channel_map; -- cgit v1.2.3 From 729a1051da6ff92e52ef8773e1676d462dc43b90 Mon Sep 17 00:00:00 2001 From: Georg Lukas Date: Sat, 26 Jul 2014 13:59:58 +0200 Subject: Bluetooth: Expose default LE advertising interval via debugfs Expose the default values for minimum and maximum LE advertising interval via debugfs for testing purposes. Signed-off-by: Georg Lukas Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 475d6003ed15..910f608365f7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -970,6 +970,62 @@ static int adv_channel_map_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get, adv_channel_map_set, "%llu\n"); +static int adv_min_interval_set(void *data, u64 val) +{ + struct hci_dev *hdev = data; + + if (val < 0x0020 || val > 0x4000 || val > hdev->le_adv_max_interval) + return -EINVAL; + + hci_dev_lock(hdev); + hdev->le_adv_min_interval = val; + hci_dev_unlock(hdev); + + return 0; +} + +static int adv_min_interval_get(void *data, u64 *val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock(hdev); + *val = hdev->le_adv_min_interval; + hci_dev_unlock(hdev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(adv_min_interval_fops, adv_min_interval_get, + adv_min_interval_set, "%llu\n"); + +static int adv_max_interval_set(void *data, u64 val) +{ + struct hci_dev *hdev = data; + + if (val < 0x0020 || val > 0x4000 || val < hdev->le_adv_min_interval) + return -EINVAL; + + hci_dev_lock(hdev); + hdev->le_adv_max_interval = val; + hci_dev_unlock(hdev); + + return 0; +} + +static int adv_max_interval_get(void *data, u64 *val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock(hdev); + *val = hdev->le_adv_max_interval; + hci_dev_unlock(hdev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get, + adv_max_interval_set, "%llu\n"); + static int device_list_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; @@ -1833,6 +1889,10 @@ static int __hci_init(struct hci_dev *hdev) hdev, &supervision_timeout_fops); debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, hdev, &adv_channel_map_fops); + debugfs_create_file("adv_min_interval", 0644, hdev->debugfs, + hdev, &adv_min_interval_fops); + debugfs_create_file("adv_max_interval", 0644, hdev->debugfs, + hdev, &adv_max_interval_fops); debugfs_create_file("device_list", 0444, hdev->debugfs, hdev, &device_list_fops); debugfs_create_u16("discov_interleaved_timeout", 0644, -- cgit v1.2.3 From 32226e4f1af2b58983676b577ce33403c08e6c94 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 24 Jul 2014 20:04:16 +0200 Subject: Bluetooth: Set Simultaneous LE and BR/EDR controller option to zero With the Bluetooth 4.1 specification the Simultaneous LE and BR/EDR controller option has been deprecated. It shall be set to zero and ignored otherwise. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 2 +- net/bluetooth/mgmt.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 910f608365f7..61bd1a8c5849 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1623,7 +1623,7 @@ static void hci_set_le_support(struct hci_request *req) if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { cp.le = 0x01; - cp.simul = lmp_le_br_capable(hdev); + cp.simul = 0x00; } if (cp.le != lmp_host_le_capable(hdev)) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ff874580d989..eb25a1259271 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2264,7 +2264,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) if (val) { hci_cp.le = val; - hci_cp.simul = lmp_le_br_capable(hdev); + hci_cp.simul = 0x00; } else { if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) disable_advertising(&req); @@ -5925,8 +5925,8 @@ static int powered_update_hci(struct hci_dev *hdev) lmp_bredr_capable(hdev)) { struct hci_cp_write_le_host_supported cp; - cp.le = 1; - cp.simul = lmp_le_br_capable(hdev); + cp.le = 0x01; + cp.simul = 0x00; /* Check first if we already have the right * host state (host features set) -- cgit v1.2.3 From 36c7778218b93d96d88d68f116a711f6a598b72f Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 24 Jul 2014 16:50:29 +0200 Subject: inet: frag: constify match, hashfn and constructor arguments Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- include/net/inet_frag.h | 11 ++++++----- include/net/ipv6.h | 4 ++-- net/ieee802154/reassembly.c | 14 +++++++------- net/ipv4/ip_fragment.c | 14 +++++++------- net/ipv6/netfilter/nf_conntrack_reasm.c | 2 +- net/ipv6/reassembly.c | 14 +++++++------- 6 files changed, 30 insertions(+), 29 deletions(-) diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 6f59de98dabd..15033057d44e 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -71,10 +71,11 @@ struct inet_frags { u32 rnd; int qsize; - unsigned int (*hashfn)(struct inet_frag_queue *); - bool (*match)(struct inet_frag_queue *q, void *arg); + unsigned int (*hashfn)(const struct inet_frag_queue *); + bool (*match)(const struct inet_frag_queue *q, + const void *arg); void (*constructor)(struct inet_frag_queue *q, - void *arg); + const void *arg); void (*destructor)(struct inet_frag_queue *); void (*skb_free)(struct sk_buff *); void (*frag_expire)(unsigned long data); @@ -131,9 +132,9 @@ static inline void init_frag_mem_limit(struct netns_frags *nf) percpu_counter_init(&nf->mem, 0); } -static inline int sum_frag_mem_limit(struct netns_frags *nf) +static inline unsigned int sum_frag_mem_limit(struct netns_frags *nf) { - int res; + unsigned int res; local_bh_disable(); res = percpu_counter_sum_positive(&nf->mem); diff --git a/include/net/ipv6.h b/include/net/ipv6.h index a25017247457..25c2170e1298 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -496,8 +496,8 @@ struct ip6_create_arg { u8 ecn; }; -void ip6_frag_init(struct inet_frag_queue *q, void *a); -bool ip6_frag_match(struct inet_frag_queue *q, void *a); +void ip6_frag_init(struct inet_frag_queue *q, const void *a); +bool ip6_frag_match(const struct inet_frag_queue *q, const void *a); /* * Equivalent of ipv4 struct ip diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index b85bd3f7048e..a5588be18024 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -61,18 +61,18 @@ static unsigned int lowpan_hash_frag(__be16 tag, u16 d_size, return c & (INETFRAGS_HASHSZ - 1); } -static unsigned int lowpan_hashfn(struct inet_frag_queue *q) +static unsigned int lowpan_hashfn(const struct inet_frag_queue *q) { - struct lowpan_frag_queue *fq; + const struct lowpan_frag_queue *fq; fq = container_of(q, struct lowpan_frag_queue, q); return lowpan_hash_frag(fq->tag, fq->d_size, &fq->saddr, &fq->daddr); } -static bool lowpan_frag_match(struct inet_frag_queue *q, void *a) +static bool lowpan_frag_match(const struct inet_frag_queue *q, const void *a) { - struct lowpan_frag_queue *fq; - struct lowpan_create_arg *arg = a; + const struct lowpan_frag_queue *fq; + const struct lowpan_create_arg *arg = a; fq = container_of(q, struct lowpan_frag_queue, q); return fq->tag == arg->tag && fq->d_size == arg->d_size && @@ -80,10 +80,10 @@ static bool lowpan_frag_match(struct inet_frag_queue *q, void *a) ieee802154_addr_equal(&fq->daddr, arg->dst); } -static void lowpan_frag_init(struct inet_frag_queue *q, void *a) +static void lowpan_frag_init(struct inet_frag_queue *q, const void *a) { + const struct lowpan_create_arg *arg = a; struct lowpan_frag_queue *fq; - struct lowpan_create_arg *arg = a; fq = container_of(q, struct lowpan_frag_queue, q); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index ed32313e307c..586e6aaf9e6e 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -112,18 +112,18 @@ static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot) ip4_frags.rnd) & (INETFRAGS_HASHSZ - 1); } -static unsigned int ip4_hashfn(struct inet_frag_queue *q) +static unsigned int ip4_hashfn(const struct inet_frag_queue *q) { - struct ipq *ipq; + const struct ipq *ipq; ipq = container_of(q, struct ipq, q); return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol); } -static bool ip4_frag_match(struct inet_frag_queue *q, void *a) +static bool ip4_frag_match(const struct inet_frag_queue *q, const void *a) { - struct ipq *qp; - struct ip4_create_arg *arg = a; + const struct ipq *qp; + const struct ip4_create_arg *arg = a; qp = container_of(q, struct ipq, q); return qp->id == arg->iph->id && @@ -133,14 +133,14 @@ static bool ip4_frag_match(struct inet_frag_queue *q, void *a) qp->user == arg->user; } -static void ip4_frag_init(struct inet_frag_queue *q, void *a) +static void ip4_frag_init(struct inet_frag_queue *q, const void *a) { struct ipq *qp = container_of(q, struct ipq, q); struct netns_ipv4 *ipv4 = container_of(q->net, struct netns_ipv4, frags); struct net *net = container_of(ipv4, struct net, ipv4); - struct ip4_create_arg *arg = a; + const struct ip4_create_arg *arg = a; qp->protocol = arg->iph->protocol; qp->id = arg->iph->id; diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 0d5279fd852a..c2c3f2116bc5 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -156,7 +156,7 @@ static unsigned int nf_hash_frag(__be32 id, const struct in6_addr *saddr, } -static unsigned int nf_hashfn(struct inet_frag_queue *q) +static unsigned int nf_hashfn(const struct inet_frag_queue *q) { const struct frag_queue *nq; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index cc85a9ba5010..0c6932cc08cb 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -94,18 +94,18 @@ static unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, return c & (INETFRAGS_HASHSZ - 1); } -static unsigned int ip6_hashfn(struct inet_frag_queue *q) +static unsigned int ip6_hashfn(const struct inet_frag_queue *q) { - struct frag_queue *fq; + const struct frag_queue *fq; fq = container_of(q, struct frag_queue, q); return inet6_hash_frag(fq->id, &fq->saddr, &fq->daddr); } -bool ip6_frag_match(struct inet_frag_queue *q, void *a) +bool ip6_frag_match(const struct inet_frag_queue *q, const void *a) { - struct frag_queue *fq; - struct ip6_create_arg *arg = a; + const struct frag_queue *fq; + const struct ip6_create_arg *arg = a; fq = container_of(q, struct frag_queue, q); return fq->id == arg->id && @@ -115,10 +115,10 @@ bool ip6_frag_match(struct inet_frag_queue *q, void *a) } EXPORT_SYMBOL(ip6_frag_match); -void ip6_frag_init(struct inet_frag_queue *q, void *a) +void ip6_frag_init(struct inet_frag_queue *q, const void *a) { struct frag_queue *fq = container_of(q, struct frag_queue, q); - struct ip6_create_arg *arg = a; + const struct ip6_create_arg *arg = a; fq->id = arg->id; fq->user = arg->user; -- cgit v1.2.3 From fb3cfe6e75b9d05c87265e85e67d7caf6e5b44a7 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 24 Jul 2014 16:50:30 +0200 Subject: inet: frag: remove hash size assumptions from callers hide actual hash size from individual users: The _find function will now fold the given hash value into the required range. Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- net/ieee802154/reassembly.c | 12 ++++-------- net/ipv4/inet_fragment.c | 13 ++++++++++--- net/ipv4/ip_fragment.c | 2 +- net/ipv6/netfilter/nf_conntrack_reasm.c | 7 ++----- net/ipv6/reassembly.c | 8 ++------ 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index a5588be18024..a707995fd4d7 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -50,15 +50,11 @@ static unsigned int lowpan_hash_frag(__be16 tag, u16 d_size, const struct ieee802154_addr *saddr, const struct ieee802154_addr *daddr) { - u32 c; - net_get_random_once(&lowpan_frags.rnd, sizeof(lowpan_frags.rnd)); - c = jhash_3words(ieee802154_addr_hash(saddr), - ieee802154_addr_hash(daddr), - (__force u32)(tag + (d_size << 16)), - lowpan_frags.rnd); - - return c & (INETFRAGS_HASHSZ - 1); + return jhash_3words(ieee802154_addr_hash(saddr), + ieee802154_addr_hash(daddr), + (__force u32)(tag + (d_size << 16)), + lowpan_frags.rnd); } static unsigned int lowpan_hashfn(const struct inet_frag_queue *q) diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 3b01959bf4bb..930d23870811 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -46,6 +46,12 @@ const u8 ip_frag_ecn_table[16] = { }; EXPORT_SYMBOL(ip_frag_ecn_table); +static unsigned int +inet_frag_hashfn(const struct inet_frags *f, const struct inet_frag_queue *q) +{ + return f->hashfn(q) & (INETFRAGS_HASHSZ - 1); +} + static void inet_frag_secret_rebuild(unsigned long dummy) { struct inet_frags *f = (struct inet_frags *)dummy; @@ -63,7 +69,7 @@ static void inet_frag_secret_rebuild(unsigned long dummy) hb = &f->hash[i]; hlist_for_each_entry_safe(q, n, &hb->chain, list) { - unsigned int hval = f->hashfn(q); + unsigned int hval = inet_frag_hashfn(f, q); if (hval != i) { struct inet_frag_bucket *hb_dest; @@ -133,7 +139,7 @@ static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f) unsigned int hash; read_lock(&f->lock); - hash = f->hashfn(fq); + hash = inet_frag_hashfn(f, fq); hb = &f->hash[hash]; spin_lock(&hb->chain_lock); @@ -252,7 +258,7 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, * the rnd seed, so we need to re-calculate the hash * chain. Fortunatelly the qp_in can be used to get one. */ - hash = f->hashfn(qp_in); + hash = inet_frag_hashfn(f, qp_in); hb = &f->hash[hash]; spin_lock(&hb->chain_lock); @@ -326,6 +332,7 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, struct inet_frag_queue *q; int depth = 0; + hash &= (INETFRAGS_HASHSZ - 1); hb = &f->hash[hash]; spin_lock(&hb->chain_lock); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 586e6aaf9e6e..b769eb6c83c0 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -109,7 +109,7 @@ static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot) net_get_random_once(&ip4_frags.rnd, sizeof(ip4_frags.rnd)); return jhash_3words((__force u32)id << 16 | prot, (__force u32)saddr, (__force u32)daddr, - ip4_frags.rnd) & (INETFRAGS_HASHSZ - 1); + ip4_frags.rnd); } static unsigned int ip4_hashfn(const struct inet_frag_queue *q) diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index c2c3f2116bc5..607e4a94ef41 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -147,12 +147,9 @@ static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) static unsigned int nf_hash_frag(__be32 id, const struct in6_addr *saddr, const struct in6_addr *daddr) { - u32 c; - net_get_random_once(&nf_frags.rnd, sizeof(nf_frags.rnd)); - c = jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), - (__force u32)id, nf_frags.rnd); - return c & (INETFRAGS_HASHSZ - 1); + return jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), + (__force u32)id, nf_frags.rnd); } diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 0c6932cc08cb..2b76549a1016 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -85,13 +85,9 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, static unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, const struct in6_addr *daddr) { - u32 c; - net_get_random_once(&ip6_frags.rnd, sizeof(ip6_frags.rnd)); - c = jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), - (__force u32)id, ip6_frags.rnd); - - return c & (INETFRAGS_HASHSZ - 1); + return jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), + (__force u32)id, ip6_frags.rnd); } static unsigned int ip6_hashfn(const struct inet_frag_queue *q) -- cgit v1.2.3 From 86e93e470cadedda9181a2bd9aee1d9d2e5e9c0f Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 24 Jul 2014 16:50:31 +0200 Subject: inet: frag: move evictor calls into frag_find function First step to move eviction handling into a work queue. We lose two spots that accounted evicted fragments in MIB counters. Accounting will be restored since the upcoming work-queue evictor invokes the frag queue timer callbacks instead. Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- include/net/inet_frag.h | 1 - net/ieee802154/reassembly.c | 2 -- net/ipv4/inet_fragment.c | 16 +++++++++------- net/ipv4/ip_fragment.c | 15 --------------- net/ipv6/netfilter/nf_conntrack_reasm.c | 4 ---- net/ipv6/reassembly.c | 6 ------ 6 files changed, 9 insertions(+), 35 deletions(-) diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 15033057d44e..9fe644d1a26e 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -90,7 +90,6 @@ void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f); void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f); void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f, int *work); -int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force); struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, struct inet_frags *f, void *key, unsigned int hash) __releases(&f->lock); diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index a707995fd4d7..9503a48556f7 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -369,8 +369,6 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type) if (frag_info->d_size > ieee802154_lowpan->max_dsize) goto err; - inet_frag_evictor(&ieee802154_lowpan->frags, &lowpan_frags, false); - fq = fq_find(net, frag_info, &source, &dest); if (fq != NULL) { int ret; diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 930d23870811..535636017534 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -46,6 +46,8 @@ const u8 ip_frag_ecn_table[16] = { }; EXPORT_SYMBOL(ip_frag_ecn_table); +static int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force); + static unsigned int inet_frag_hashfn(const struct inet_frags *f, const struct inet_frag_queue *q) { @@ -203,16 +205,11 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f, } EXPORT_SYMBOL(inet_frag_destroy); -int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force) +static int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force) { struct inet_frag_queue *q; int work, evicted = 0; - if (!force) { - if (frag_mem_limit(nf) <= nf->high_thresh) - return 0; - } - work = frag_mem_limit(nf) - nf->low_thresh; while (work > 0 || force) { spin_lock(&nf->lru_lock); @@ -242,7 +239,6 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force) return evicted; } -EXPORT_SYMBOL(inet_frag_evictor); static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, struct inet_frag_queue *qp_in, struct inet_frags *f, @@ -296,6 +292,9 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, { struct inet_frag_queue *q; + if (frag_mem_limit(nf) > nf->high_thresh) + return NULL; + q = kzalloc(f->qsize, GFP_ATOMIC); if (q == NULL) return NULL; @@ -332,6 +331,9 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, struct inet_frag_queue *q; int depth = 0; + if (frag_mem_limit(nf) > nf->high_thresh) + inet_frag_evictor(nf, f, false); + hash &= (INETFRAGS_HASHSZ - 1); hb = &f->hash[hash]; diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index b769eb6c83c0..54988672d00d 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -177,18 +177,6 @@ static void ipq_kill(struct ipq *ipq) inet_frag_kill(&ipq->q, &ip4_frags); } -/* Memory limiting on fragments. Evictor trashes the oldest - * fragment queue until we are back under the threshold. - */ -static void ip_evictor(struct net *net) -{ - int evicted; - - evicted = inet_frag_evictor(&net->ipv4.frags, &ip4_frags, false); - if (evicted) - IP_ADD_STATS_BH(net, IPSTATS_MIB_REASMFAILS, evicted); -} - /* * Oops, a fragment queue timed out. Kill it and send an ICMP reply. */ @@ -655,9 +643,6 @@ int ip_defrag(struct sk_buff *skb, u32 user) net = skb->dev ? dev_net(skb->dev) : dev_net(skb_dst(skb)->dev); IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS); - /* Start by cleaning up the memory. */ - ip_evictor(net); - /* Lookup (or create) queue header */ if ((qp = ip_find(net, ip_hdr(skb), user)) != NULL) { int ret; diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 607e4a94ef41..58e32cf91c95 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -594,10 +594,6 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) hdr = ipv6_hdr(clone); fhdr = (struct frag_hdr *)skb_transport_header(clone); - local_bh_disable(); - inet_frag_evictor(&net->nf_frag.frags, &nf_frags, false); - local_bh_enable(); - fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr, ip6_frag_ecn(hdr)); if (fq == NULL) { diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 2b76549a1016..97acbc490d9e 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -519,7 +519,6 @@ static int ipv6_frag_rcv(struct sk_buff *skb) struct frag_queue *fq; const struct ipv6hdr *hdr = ipv6_hdr(skb); struct net *net = dev_net(skb_dst(skb)->dev); - int evicted; if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED) goto fail_hdr; @@ -548,11 +547,6 @@ static int ipv6_frag_rcv(struct sk_buff *skb) return 1; } - evicted = inet_frag_evictor(&net->ipv6.frags, &ip6_frags, false); - if (evicted) - IP6_ADD_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_REASMFAILS, evicted); - fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, ip6_frag_ecn(hdr)); if (fq != NULL) { -- cgit v1.2.3 From b13d3cbfb8e8a8f53930af67d1ebf05149f32c24 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 24 Jul 2014 16:50:32 +0200 Subject: inet: frag: move eviction of queues to work queue When the high_thresh limit is reached we try to toss the 'oldest' incomplete fragment queues until memory limits are below the low_thresh value. This happens in softirq/packet processing context. This has two drawbacks: 1) processors might evict a queue that was about to be completed by another cpu, because they will compete wrt. resource usage and resource reclaim. 2) LRU list maintenance is expensive. But when constantly overloaded, even the 'least recently used' element is recent, so removing 'lru' queue first is not 'fairer' than removing any other fragment queue. This moves eviction out of the fast path: When the low threshold is reached, a work queue is scheduled which then iterates over the table and removes the queues that exceed the memory limits of the namespace. It sets a new flag called INET_FRAG_EVICTED on the evicted queues so the proper counters will get incremented when the queue is forcefully expired. When the high threshold is reached, no more fragment queues are created until we're below the limit again. The LRU list is now unused and will be removed in a followup patch. Joint work with Nikolay Aleksandrov. Suggested-by: Eric Dumazet Signed-off-by: Florian Westphal Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 4 +- include/net/inet_frag.h | 6 +- net/ipv4/inet_fragment.c | 142 +++++++++++++++++++++++---------- net/ipv4/ip_fragment.c | 3 +- net/ipv6/reassembly.c | 4 +- 5 files changed, 112 insertions(+), 47 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index f35bfe43bf7a..625c8dda4be7 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -104,7 +104,9 @@ ipfrag_high_thresh - INTEGER is reached. ipfrag_low_thresh - INTEGER - See ipfrag_high_thresh + Maximum memory used to reassemble IP fragments before the kernel + begins to remove incomplete fragment queues to free up resources. + The kernel still accepts new fragments for defragmentation. ipfrag_time - INTEGER Time in seconds to keep an IP fragment in memory. diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 9fe644d1a26e..e975032ea11b 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -32,6 +32,7 @@ struct inet_frag_queue { int meat; __u8 last_in; /* first/last segment arrived? */ +#define INET_FRAG_EVICTED 8 #define INET_FRAG_COMPLETE 4 #define INET_FRAG_FIRST_IN 2 #define INET_FRAG_LAST_IN 1 @@ -48,7 +49,7 @@ struct inet_frag_queue { * rounded up (SKB_TRUELEN(0) + sizeof(struct ipq or * struct frag_queue)) */ -#define INETFRAGS_MAXDEPTH 128 +#define INETFRAGS_MAXDEPTH 128 struct inet_frag_bucket { struct hlist_head chain; @@ -65,6 +66,9 @@ struct inet_frags { int secret_interval; struct timer_list secret_timer; + struct work_struct frags_work; + unsigned int next_bucket; + /* The first call to hashfn is responsible to initialize * rnd. This is best done with net_get_random_once. */ diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 535636017534..43315ecb9400 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -25,6 +25,9 @@ #include #include +#define INETFRAGS_EVICT_BUCKETS 128 +#define INETFRAGS_EVICT_MAX 512 + /* Given the OR values of all fragments, apply RFC 3168 5.3 requirements * Value : 0xff if frame should be dropped. * 0 or INET_ECN_CE value, to be ORed in to final iph->tos field @@ -46,8 +49,6 @@ const u8 ip_frag_ecn_table[16] = { }; EXPORT_SYMBOL(ip_frag_ecn_table); -static int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force); - static unsigned int inet_frag_hashfn(const struct inet_frags *f, const struct inet_frag_queue *q) { @@ -89,10 +90,92 @@ static void inet_frag_secret_rebuild(unsigned long dummy) mod_timer(&f->secret_timer, now + f->secret_interval); } +static bool inet_fragq_should_evict(const struct inet_frag_queue *q) +{ + return q->net->low_thresh == 0 || + frag_mem_limit(q->net) >= q->net->low_thresh; +} + +static unsigned int +inet_evict_bucket(struct inet_frags *f, struct inet_frag_bucket *hb) +{ + struct inet_frag_queue *fq; + struct hlist_node *n; + unsigned int evicted = 0; + HLIST_HEAD(expired); + +evict_again: + spin_lock(&hb->chain_lock); + + hlist_for_each_entry_safe(fq, n, &hb->chain, list) { + if (!inet_fragq_should_evict(fq)) + continue; + + if (!del_timer(&fq->timer)) { + /* q expiring right now thus increment its refcount so + * it won't be freed under us and wait until the timer + * has finished executing then destroy it + */ + atomic_inc(&fq->refcnt); + spin_unlock(&hb->chain_lock); + del_timer_sync(&fq->timer); + WARN_ON(atomic_read(&fq->refcnt) != 1); + inet_frag_put(fq, f); + goto evict_again; + } + + /* suppress xmit of (icmp) error packet */ + fq->last_in &= ~INET_FRAG_FIRST_IN; + fq->last_in |= INET_FRAG_EVICTED; + hlist_del(&fq->list); + hlist_add_head(&fq->list, &expired); + ++evicted; + } + + spin_unlock(&hb->chain_lock); + + hlist_for_each_entry_safe(fq, n, &expired, list) + f->frag_expire((unsigned long) fq); + + return evicted; +} + +static void inet_frag_worker(struct work_struct *work) +{ + unsigned int budget = INETFRAGS_EVICT_BUCKETS; + unsigned int i, evicted = 0; + struct inet_frags *f; + + f = container_of(work, struct inet_frags, frags_work); + + BUILD_BUG_ON(INETFRAGS_EVICT_BUCKETS >= INETFRAGS_HASHSZ); + + read_lock_bh(&f->lock); + + for (i = ACCESS_ONCE(f->next_bucket); budget; --budget) { + evicted += inet_evict_bucket(f, &f->hash[i]); + i = (i + 1) & (INETFRAGS_HASHSZ - 1); + if (evicted > INETFRAGS_EVICT_MAX) + break; + } + + f->next_bucket = i; + + read_unlock_bh(&f->lock); +} + +static void inet_frag_schedule_worker(struct inet_frags *f) +{ + if (unlikely(!work_pending(&f->frags_work))) + schedule_work(&f->frags_work); +} + void inet_frags_init(struct inet_frags *f) { int i; + INIT_WORK(&f->frags_work, inet_frag_worker); + for (i = 0; i < INETFRAGS_HASHSZ; i++) { struct inet_frag_bucket *hb = &f->hash[i]; @@ -120,16 +203,22 @@ EXPORT_SYMBOL(inet_frags_init_net); void inet_frags_fini(struct inet_frags *f) { del_timer(&f->secret_timer); + cancel_work_sync(&f->frags_work); } EXPORT_SYMBOL(inet_frags_fini); void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f) { + int i; + nf->low_thresh = 0; - local_bh_disable(); - inet_frag_evictor(nf, f, true); - local_bh_enable(); + read_lock_bh(&f->lock); + + for (i = 0; i < INETFRAGS_HASHSZ ; i++) + inet_evict_bucket(f, &f->hash[i]); + + read_unlock_bh(&f->lock); percpu_counter_destroy(&nf->mem); } @@ -205,41 +294,6 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f, } EXPORT_SYMBOL(inet_frag_destroy); -static int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force) -{ - struct inet_frag_queue *q; - int work, evicted = 0; - - work = frag_mem_limit(nf) - nf->low_thresh; - while (work > 0 || force) { - spin_lock(&nf->lru_lock); - - if (list_empty(&nf->lru_list)) { - spin_unlock(&nf->lru_lock); - break; - } - - q = list_first_entry(&nf->lru_list, - struct inet_frag_queue, lru_list); - atomic_inc(&q->refcnt); - /* Remove q from list to avoid several CPUs grabbing it */ - list_del_init(&q->lru_list); - - spin_unlock(&nf->lru_lock); - - spin_lock(&q->lock); - if (!(q->last_in & INET_FRAG_COMPLETE)) - inet_frag_kill(q, f); - spin_unlock(&q->lock); - - if (atomic_dec_and_test(&q->refcnt)) - inet_frag_destroy(q, f, &work); - evicted++; - } - - return evicted; -} - static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, struct inet_frag_queue *qp_in, struct inet_frags *f, void *arg) @@ -292,8 +346,10 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, { struct inet_frag_queue *q; - if (frag_mem_limit(nf) > nf->high_thresh) + if (frag_mem_limit(nf) > nf->high_thresh) { + inet_frag_schedule_worker(f); return NULL; + } q = kzalloc(f->qsize, GFP_ATOMIC); if (q == NULL) @@ -331,8 +387,8 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, struct inet_frag_queue *q; int depth = 0; - if (frag_mem_limit(nf) > nf->high_thresh) - inet_frag_evictor(nf, f, false); + if (frag_mem_limit(nf) > nf->low_thresh) + inet_frag_schedule_worker(f); hash &= (INETFRAGS_HASHSZ - 1); hb = &f->hash[hash]; diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 54988672d00d..54bd170c5eb4 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -195,7 +195,8 @@ static void ip_expire(unsigned long arg) ipq_kill(qp); - IP_INC_STATS_BH(net, IPSTATS_MIB_REASMTIMEOUT); + if (!(qp->q.last_in & INET_FRAG_EVICTED)) + IP_INC_STATS_BH(net, IPSTATS_MIB_REASMTIMEOUT); IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS); if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 97acbc490d9e..b3924b10dff3 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -141,7 +141,9 @@ void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq, if (!dev) goto out_rcu_unlock; - IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); + if (!(fq->q.last_in & INET_FRAG_EVICTED)) + IP6_INC_STATS_BH(net, __in6_dev_get(dev), + IPSTATS_MIB_REASMTIMEOUT); IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); /* Don't send error if the first segment did not arrive. */ -- cgit v1.2.3 From 434d305405ab86414f6ea3f261307d443a2c3506 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 24 Jul 2014 16:50:33 +0200 Subject: inet: frag: don't account number of fragment queues The 'nqueues' counter is protected by the lru list lock, once thats removed this needs to be converted to atomic counter. Given this isn't used for anything except for reporting it to userspace via /proc, just remove it. We still report the memory currently used by fragment reassembly queues. Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- include/net/inet_frag.h | 3 --- include/net/ip.h | 1 - include/net/ipv6.h | 5 ----- net/ipv4/inet_fragment.c | 1 - net/ipv4/ip_fragment.c | 5 ----- net/ipv4/proc.c | 5 +++-- net/ipv6/proc.c | 4 ++-- 7 files changed, 5 insertions(+), 19 deletions(-) diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index e975032ea11b..68de33765705 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -4,7 +4,6 @@ #include struct netns_frags { - int nqueues; struct list_head lru_list; spinlock_t lru_lock; @@ -158,7 +157,6 @@ static inline void inet_frag_lru_del(struct inet_frag_queue *q) { spin_lock(&q->net->lru_lock); list_del_init(&q->lru_list); - q->net->nqueues--; spin_unlock(&q->net->lru_lock); } @@ -167,7 +165,6 @@ static inline void inet_frag_lru_add(struct netns_frags *nf, { spin_lock(&nf->lru_lock); list_add_tail(&q->lru_list, &nf->lru_list); - q->net->nqueues++; spin_unlock(&nf->lru_lock); } diff --git a/include/net/ip.h b/include/net/ip.h index 2e8f055989c3..ca14799545fd 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -495,7 +495,6 @@ static inline struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user) } #endif int ip_frag_mem(struct net *net); -int ip_frag_nqueues(struct net *net); /* * Functions provided by ip_forward.c diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 25c2170e1298..a2db816e8461 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -299,11 +299,6 @@ static inline bool ipv6_accept_ra(struct inet6_dev *idev) } #if IS_ENABLED(CONFIG_IPV6) -static inline int ip6_frag_nqueues(struct net *net) -{ - return net->ipv6.frags.nqueues; -} - static inline int ip6_frag_mem(struct net *net) { return sum_frag_mem_limit(&net->ipv6.frags); diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 43315ecb9400..231ca0b40811 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -193,7 +193,6 @@ EXPORT_SYMBOL(inet_frags_init); void inet_frags_init_net(struct netns_frags *nf) { - nf->nqueues = 0; init_frag_mem_limit(nf); INIT_LIST_HEAD(&nf->lru_list); spin_lock_init(&nf->lru_lock); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 54bd170c5eb4..1f42c2e3966b 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -86,11 +86,6 @@ static inline u8 ip4_frag_ecn(u8 tos) static struct inet_frags ip4_frags; -int ip_frag_nqueues(struct net *net) -{ - return net->ipv4.frags.nqueues; -} - int ip_frag_mem(struct net *net) { return sum_frag_mem_limit(&net->ipv4.frags); diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index ae0af9386f7c..8e3eb39f84e7 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -52,6 +52,7 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) { struct net *net = seq->private; + unsigned int frag_mem; int orphans, sockets; local_bh_disable(); @@ -71,8 +72,8 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) sock_prot_inuse_get(net, &udplite_prot)); seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse_get(net, &raw_prot)); - seq_printf(seq, "FRAG: inuse %d memory %d\n", - ip_frag_nqueues(net), ip_frag_mem(net)); + frag_mem = ip_frag_mem(net); + seq_printf(seq, "FRAG: inuse %u memory %u\n", !!frag_mem, frag_mem); return 0; } diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 3317440ea341..2d6f860e5c1e 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -33,6 +33,7 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v) { struct net *net = seq->private; + unsigned int frag_mem = ip6_frag_mem(net); seq_printf(seq, "TCP6: inuse %d\n", sock_prot_inuse_get(net, &tcpv6_prot)); @@ -42,8 +43,7 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v) sock_prot_inuse_get(net, &udplitev6_prot)); seq_printf(seq, "RAW6: inuse %d\n", sock_prot_inuse_get(net, &rawv6_prot)); - seq_printf(seq, "FRAG6: inuse %d memory %d\n", - ip6_frag_nqueues(net), ip6_frag_mem(net)); + seq_printf(seq, "FRAG6: inuse %u memory %u\n", !!frag_mem, frag_mem); return 0; } -- cgit v1.2.3 From 3fd588eb90bfbba17091381006ecafe29c45db4a Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 24 Jul 2014 16:50:34 +0200 Subject: inet: frag: remove lru list no longer used. Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- include/net/inet_frag.h | 32 ++------------------------------ net/ieee802154/reassembly.c | 1 - net/ipv4/inet_fragment.c | 12 ++---------- net/ipv4/ip_fragment.c | 1 - net/ipv6/netfilter/nf_conntrack_reasm.c | 1 - net/ipv6/reassembly.c | 1 - 6 files changed, 4 insertions(+), 44 deletions(-) diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 68de33765705..90d21ea62c59 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -4,9 +4,6 @@ #include struct netns_frags { - struct list_head lru_list; - spinlock_t lru_lock; - /* The percpu_counter "mem" need to be cacheline aligned. * mem.count must not share cacheline with other writers */ @@ -21,7 +18,6 @@ struct netns_frags { struct inet_frag_queue { spinlock_t lock; struct timer_list timer; /* when will this queue expire? */ - struct list_head lru_list; /* lru list member */ struct hlist_node list; atomic_t refcnt; struct sk_buff *fragments; /* list of received fragments */ @@ -91,8 +87,7 @@ void inet_frags_init_net(struct netns_frags *nf); void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f); void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f); -void inet_frag_destroy(struct inet_frag_queue *q, - struct inet_frags *f, int *work); +void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f); struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, struct inet_frags *f, void *key, unsigned int hash) __releases(&f->lock); @@ -102,7 +97,7 @@ void inet_frag_maybe_warn_overflow(struct inet_frag_queue *q, static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f) { if (atomic_dec_and_test(&q->refcnt)) - inet_frag_destroy(q, f, NULL); + inet_frag_destroy(q, f); } /* Memory Tracking Functions. */ @@ -145,29 +140,6 @@ static inline unsigned int sum_frag_mem_limit(struct netns_frags *nf) return res; } -static inline void inet_frag_lru_move(struct inet_frag_queue *q) -{ - spin_lock(&q->net->lru_lock); - if (!list_empty(&q->lru_list)) - list_move_tail(&q->lru_list, &q->net->lru_list); - spin_unlock(&q->net->lru_lock); -} - -static inline void inet_frag_lru_del(struct inet_frag_queue *q) -{ - spin_lock(&q->net->lru_lock); - list_del_init(&q->lru_list); - spin_unlock(&q->net->lru_lock); -} - -static inline void inet_frag_lru_add(struct netns_frags *nf, - struct inet_frag_queue *q) -{ - spin_lock(&nf->lru_lock); - list_add_tail(&q->lru_list, &nf->lru_list); - spin_unlock(&nf->lru_lock); -} - /* RFC 3168 support : * We want to check ECN values of all fragments, do detect invalid combinations. * In ipq->ecn, we store the OR value of each ip4_frag_ecn() fragment value. diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index 9503a48556f7..b4bc7a50eccf 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -219,7 +219,6 @@ found: return res; } - inet_frag_lru_move(&fq->q); return -1; err: kfree_skb(skb); diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 231ca0b40811..198a5ed7a815 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -194,8 +194,6 @@ EXPORT_SYMBOL(inet_frags_init); void inet_frags_init_net(struct netns_frags *nf) { init_frag_mem_limit(nf); - INIT_LIST_HEAD(&nf->lru_list); - spin_lock_init(&nf->lru_lock); } EXPORT_SYMBOL(inet_frags_init_net); @@ -237,7 +235,6 @@ static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f) spin_unlock(&hb->chain_lock); read_unlock(&f->lock); - inet_frag_lru_del(fq); } void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f) @@ -261,8 +258,7 @@ static inline void frag_kfree_skb(struct netns_frags *nf, struct inet_frags *f, kfree_skb(skb); } -void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f, - int *work) +void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f) { struct sk_buff *fp; struct netns_frags *nf; @@ -282,14 +278,11 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f, fp = xp; } sum = sum_truesize + f->qsize; - if (work) - *work -= sum; sub_frag_mem_limit(q, sum); if (f->destructor) f->destructor(q); kfree(q); - } EXPORT_SYMBOL(inet_frag_destroy); @@ -333,7 +326,7 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, atomic_inc(&qp->refcnt); hlist_add_head(&qp->list, &hb->chain); - inet_frag_lru_add(nf, qp); + spin_unlock(&hb->chain_lock); read_unlock(&f->lock); @@ -361,7 +354,6 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, setup_timer(&q->timer, f->frag_expire, (unsigned long)q); spin_lock_init(&q->lock); atomic_set(&q->refcnt, 1); - INIT_LIST_HEAD(&q->lru_list); return q; } diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 1f42c2e3966b..8fbeee495037 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -489,7 +489,6 @@ found: } skb_dst_drop(skb); - inet_frag_lru_move(&qp->q); return -EINPROGRESS; err: diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 58e32cf91c95..fb0f72a0ff31 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -349,7 +349,6 @@ found: fq->q.last_in |= INET_FRAG_FIRST_IN; } - inet_frag_lru_move(&fq->q); return 0; discard_fq: diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index b3924b10dff3..af85551682c2 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -351,7 +351,6 @@ found: } skb_dst_drop(skb); - inet_frag_lru_move(&fq->q); return -1; discard_fq: -- cgit v1.2.3 From e3a57d18b06179d68fcf7a0a06ad844493c65e06 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 24 Jul 2014 16:50:35 +0200 Subject: inet: frag: remove periodic secret rebuild timer merge functionality into the eviction workqueue. Instead of rebuilding every n seconds, take advantage of the upper hash chain length limit. If we hit it, mark table for rebuild and schedule workqueue. To prevent frequent rebuilds when we're completely overloaded, don't rebuild more than once every 5 seconds. ipfrag_secret_interval sysctl is now obsolete and has been marked as deprecated, it still can be changed so scripts won't be broken but it won't have any effect. A comment is left above each unused secret_timer variable to avoid confusion. Joint work with Nikolay Aleksandrov. Signed-off-by: Florian Westphal Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 10 -------- include/net/inet_frag.h | 4 +-- net/ieee802154/reassembly.c | 5 ++-- net/ipv4/inet_fragment.c | 43 ++++++++++++++++++++++----------- net/ipv4/ip_fragment.c | 5 ++-- net/ipv6/netfilter/nf_conntrack_reasm.c | 1 - net/ipv6/reassembly.c | 5 ++-- 7 files changed, 40 insertions(+), 33 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 625c8dda4be7..e8c304e37831 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -111,11 +111,6 @@ ipfrag_low_thresh - INTEGER ipfrag_time - INTEGER Time in seconds to keep an IP fragment in memory. -ipfrag_secret_interval - INTEGER - Regeneration interval (in seconds) of the hash secret (or lifetime - for the hash secret) for IP fragments. - Default: 600 - ipfrag_max_dist - INTEGER ipfrag_max_dist is a non-negative integer value which defines the maximum "disorder" which is allowed among fragments which share a @@ -1164,11 +1159,6 @@ ip6frag_low_thresh - INTEGER ip6frag_time - INTEGER Time in seconds to keep an IPv6 fragment in memory. -ip6frag_secret_interval - INTEGER - Regeneration interval (in seconds) of the hash secret (or lifetime - for the hash secret) for IPv6 fragments. - Default: 600 - conf/default/*: Change the interface-specific default settings. diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 90d21ea62c59..d9cc5bb64854 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -58,11 +58,11 @@ struct inet_frags { * Its primarily a rebuild protection rwlock. */ rwlock_t lock ____cacheline_aligned_in_smp; - int secret_interval; - struct timer_list secret_timer; struct work_struct frags_work; unsigned int next_bucket; + unsigned long last_rebuild_jiffies; + bool rebuild; /* The first call to hashfn is responsible to initialize * rnd. This is best done with net_get_random_once. diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index b4bc7a50eccf..20d219682d84 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -419,10 +419,12 @@ static struct ctl_table lowpan_frags_ns_ctl_table[] = { { } }; +/* secret interval has been deprecated */ +static int lowpan_frags_secret_interval_unused; static struct ctl_table lowpan_frags_ctl_table[] = { { .procname = "6lowpanfrag_secret_interval", - .data = &lowpan_frags.secret_interval, + .data = &lowpan_frags_secret_interval_unused, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, @@ -562,7 +564,6 @@ int __init lowpan_net_frag_init(void) lowpan_frags.qsize = sizeof(struct frag_queue); lowpan_frags.match = lowpan_frag_match; lowpan_frags.frag_expire = lowpan_frag_expire; - lowpan_frags.secret_interval = 10 * 60 * HZ; inet_frags_init(&lowpan_frags); return ret; diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 198a5ed7a815..58d4c38534f6 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -28,6 +28,9 @@ #define INETFRAGS_EVICT_BUCKETS 128 #define INETFRAGS_EVICT_MAX 512 +/* don't rebuild inetfrag table with new secret more often than this */ +#define INETFRAGS_MIN_REBUILD_INTERVAL (5 * HZ) + /* Given the OR values of all fragments, apply RFC 3168 5.3 requirements * Value : 0xff if frame should be dropped. * 0 or INET_ECN_CE value, to be ORed in to final iph->tos field @@ -55,16 +58,24 @@ inet_frag_hashfn(const struct inet_frags *f, const struct inet_frag_queue *q) return f->hashfn(q) & (INETFRAGS_HASHSZ - 1); } -static void inet_frag_secret_rebuild(unsigned long dummy) +static bool inet_frag_may_rebuild(struct inet_frags *f) +{ + return time_after(jiffies, + f->last_rebuild_jiffies + INETFRAGS_MIN_REBUILD_INTERVAL); +} + +static void inet_frag_secret_rebuild(struct inet_frags *f) { - struct inet_frags *f = (struct inet_frags *)dummy; - unsigned long now = jiffies; int i; /* Per bucket lock NOT needed here, due to write lock protection */ - write_lock(&f->lock); + write_lock_bh(&f->lock); + + if (!inet_frag_may_rebuild(f)) + goto out; get_random_bytes(&f->rnd, sizeof(u32)); + for (i = 0; i < INETFRAGS_HASHSZ; i++) { struct inet_frag_bucket *hb; struct inet_frag_queue *q; @@ -85,9 +96,11 @@ static void inet_frag_secret_rebuild(unsigned long dummy) } } } - write_unlock(&f->lock); - mod_timer(&f->secret_timer, now + f->secret_interval); + f->rebuild = false; + f->last_rebuild_jiffies = jiffies; +out: + write_unlock_bh(&f->lock); } static bool inet_fragq_should_evict(const struct inet_frag_queue *q) @@ -162,6 +175,8 @@ static void inet_frag_worker(struct work_struct *work) f->next_bucket = i; read_unlock_bh(&f->lock); + if (f->rebuild && inet_frag_may_rebuild(f)) + inet_frag_secret_rebuild(f); } static void inet_frag_schedule_worker(struct inet_frags *f) @@ -183,11 +198,7 @@ void inet_frags_init(struct inet_frags *f) INIT_HLIST_HEAD(&hb->chain); } rwlock_init(&f->lock); - - setup_timer(&f->secret_timer, inet_frag_secret_rebuild, - (unsigned long)f); - f->secret_timer.expires = jiffies + f->secret_interval; - add_timer(&f->secret_timer); + f->last_rebuild_jiffies = 0; } EXPORT_SYMBOL(inet_frags_init); @@ -199,7 +210,6 @@ EXPORT_SYMBOL(inet_frags_init_net); void inet_frags_fini(struct inet_frags *f) { - del_timer(&f->secret_timer); cancel_work_sync(&f->frags_work); } EXPORT_SYMBOL(inet_frags_fini); @@ -399,8 +409,13 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, if (depth <= INETFRAGS_MAXDEPTH) return inet_frag_create(nf, f, key); - else - return ERR_PTR(-ENOBUFS); + + if (inet_frag_may_rebuild(f)) { + f->rebuild = true; + inet_frag_schedule_worker(f); + } + + return ERR_PTR(-ENOBUFS); } EXPORT_SYMBOL(inet_frag_find); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 8fbeee495037..44e591a7e03f 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -720,10 +720,12 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = { { } }; +/* secret interval has been deprecated */ +static int ip4_frags_secret_interval_unused; static struct ctl_table ip4_frags_ctl_table[] = { { .procname = "ipfrag_secret_interval", - .data = &ip4_frags.secret_interval, + .data = &ip4_frags_secret_interval_unused, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, @@ -853,6 +855,5 @@ void __init ipfrag_init(void) ip4_frags.qsize = sizeof(struct ipq); ip4_frags.match = ip4_frag_match; ip4_frags.frag_expire = ip_expire; - ip4_frags.secret_interval = 10 * 60 * HZ; inet_frags_init(&ip4_frags); } diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index fb0f72a0ff31..3b3ef9774cc2 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -669,7 +669,6 @@ int nf_ct_frag6_init(void) nf_frags.qsize = sizeof(struct frag_queue); nf_frags.match = ip6_frag_match; nf_frags.frag_expire = nf_ct_frag6_expire; - nf_frags.secret_interval = 10 * 60 * HZ; inet_frags_init(&nf_frags); ret = register_pernet_subsys(&nf_ct_net_ops); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index af85551682c2..987fea46b915 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -604,10 +604,12 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = { { } }; +/* secret interval has been deprecated */ +static int ip6_frags_secret_interval_unused; static struct ctl_table ip6_frags_ctl_table[] = { { .procname = "ip6frag_secret_interval", - .data = &ip6_frags.secret_interval, + .data = &ip6_frags_secret_interval_unused, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, @@ -737,7 +739,6 @@ int __init ipv6_frag_init(void) ip6_frags.qsize = sizeof(struct frag_queue); ip6_frags.match = ip6_frag_match; ip6_frags.frag_expire = ip6_frag_expire; - ip6_frags.secret_interval = 10 * 60 * HZ; inet_frags_init(&ip6_frags); out: return ret; -- cgit v1.2.3 From ab1c724f633080ed2e8a0cfe61654599b55cf8f9 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 24 Jul 2014 16:50:36 +0200 Subject: inet: frag: use seqlock for hash rebuild rehash is rare operation, don't force readers to take the read-side rwlock. Instead, we only have to detect the (rare) case where the secret was altered while we are trying to insert a new inetfrag queue into the table. If it was changed, drop the bucket lock and recompute the hash to get the 'new' chain bucket that we have to insert into. Joint work with Nikolay Aleksandrov. Signed-off-by: Florian Westphal Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- include/net/inet_frag.h | 13 +++-- net/ieee802154/reassembly.c | 1 - net/ipv4/inet_fragment.c | 88 ++++++++++++++++++++------------- net/ipv4/ip_fragment.c | 1 - net/ipv6/netfilter/nf_conntrack_reasm.c | 2 +- net/ipv6/reassembly.c | 1 - 6 files changed, 62 insertions(+), 44 deletions(-) diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index d9cc5bb64854..6f4930a0b660 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -53,11 +53,6 @@ struct inet_frag_bucket { struct inet_frags { struct inet_frag_bucket hash[INETFRAGS_HASHSZ]; - /* This rwlock is a global lock (seperate per IPv4, IPv6 and - * netfilter). Important to keep this on a seperate cacheline. - * Its primarily a rebuild protection rwlock. - */ - rwlock_t lock ____cacheline_aligned_in_smp; struct work_struct frags_work; unsigned int next_bucket; @@ -66,8 +61,12 @@ struct inet_frags { /* The first call to hashfn is responsible to initialize * rnd. This is best done with net_get_random_once. + * + * rnd_seqlock is used to let hash insertion detect + * when it needs to re-lookup the hash chain to use. */ u32 rnd; + seqlock_t rnd_seqlock; int qsize; unsigned int (*hashfn)(const struct inet_frag_queue *); @@ -89,8 +88,8 @@ void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f); void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f); void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f); struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, - struct inet_frags *f, void *key, unsigned int hash) - __releases(&f->lock); + struct inet_frags *f, void *key, unsigned int hash); + void inet_frag_maybe_warn_overflow(struct inet_frag_queue *q, const char *prefix); diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index 20d219682d84..8da635d92a58 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -124,7 +124,6 @@ fq_find(struct net *net, const struct lowpan_frag_info *frag_info, arg.src = src; arg.dst = dst; - read_lock(&lowpan_frags.lock); hash = lowpan_hash_frag(frag_info->d_tag, frag_info->d_size, src, dst); q = inet_frag_find(&ieee802154_lowpan->frags, diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 58d4c38534f6..62b1f73749dc 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -68,8 +68,7 @@ static void inet_frag_secret_rebuild(struct inet_frags *f) { int i; - /* Per bucket lock NOT needed here, due to write lock protection */ - write_lock_bh(&f->lock); + write_seqlock_bh(&f->rnd_seqlock); if (!inet_frag_may_rebuild(f)) goto out; @@ -82,6 +81,8 @@ static void inet_frag_secret_rebuild(struct inet_frags *f) struct hlist_node *n; hb = &f->hash[i]; + spin_lock(&hb->chain_lock); + hlist_for_each_entry_safe(q, n, &hb->chain, list) { unsigned int hval = inet_frag_hashfn(f, q); @@ -92,15 +93,28 @@ static void inet_frag_secret_rebuild(struct inet_frags *f) /* Relink to new hash chain. */ hb_dest = &f->hash[hval]; + + /* This is the only place where we take + * another chain_lock while already holding + * one. As this will not run concurrently, + * we cannot deadlock on hb_dest lock below, if its + * already locked it will be released soon since + * other caller cannot be waiting for hb lock + * that we've taken above. + */ + spin_lock_nested(&hb_dest->chain_lock, + SINGLE_DEPTH_NESTING); hlist_add_head(&q->list, &hb_dest->chain); + spin_unlock(&hb_dest->chain_lock); } } + spin_unlock(&hb->chain_lock); } f->rebuild = false; f->last_rebuild_jiffies = jiffies; out: - write_unlock_bh(&f->lock); + write_sequnlock_bh(&f->rnd_seqlock); } static bool inet_fragq_should_evict(const struct inet_frag_queue *q) @@ -163,7 +177,7 @@ static void inet_frag_worker(struct work_struct *work) BUILD_BUG_ON(INETFRAGS_EVICT_BUCKETS >= INETFRAGS_HASHSZ); - read_lock_bh(&f->lock); + local_bh_disable(); for (i = ACCESS_ONCE(f->next_bucket); budget; --budget) { evicted += inet_evict_bucket(f, &f->hash[i]); @@ -174,7 +188,8 @@ static void inet_frag_worker(struct work_struct *work) f->next_bucket = i; - read_unlock_bh(&f->lock); + local_bh_enable(); + if (f->rebuild && inet_frag_may_rebuild(f)) inet_frag_secret_rebuild(f); } @@ -197,7 +212,8 @@ void inet_frags_init(struct inet_frags *f) spin_lock_init(&hb->chain_lock); INIT_HLIST_HEAD(&hb->chain); } - rwlock_init(&f->lock); + + seqlock_init(&f->rnd_seqlock); f->last_rebuild_jiffies = 0; } EXPORT_SYMBOL(inet_frags_init); @@ -216,35 +232,56 @@ EXPORT_SYMBOL(inet_frags_fini); void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f) { + unsigned int seq; int i; nf->low_thresh = 0; + local_bh_disable(); - read_lock_bh(&f->lock); +evict_again: + seq = read_seqbegin(&f->rnd_seqlock); for (i = 0; i < INETFRAGS_HASHSZ ; i++) inet_evict_bucket(f, &f->hash[i]); - read_unlock_bh(&f->lock); + if (read_seqretry(&f->rnd_seqlock, seq)) + goto evict_again; + + local_bh_enable(); percpu_counter_destroy(&nf->mem); } EXPORT_SYMBOL(inet_frags_exit_net); -static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f) +static struct inet_frag_bucket * +get_frag_bucket_locked(struct inet_frag_queue *fq, struct inet_frags *f) +__acquires(hb->chain_lock) { struct inet_frag_bucket *hb; - unsigned int hash; + unsigned int seq, hash; + + restart: + seq = read_seqbegin(&f->rnd_seqlock); - read_lock(&f->lock); hash = inet_frag_hashfn(f, fq); hb = &f->hash[hash]; spin_lock(&hb->chain_lock); + if (read_seqretry(&f->rnd_seqlock, seq)) { + spin_unlock(&hb->chain_lock); + goto restart; + } + + return hb; +} + +static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f) +{ + struct inet_frag_bucket *hb; + + hb = get_frag_bucket_locked(fq, f); hlist_del(&fq->list); spin_unlock(&hb->chain_lock); - - read_unlock(&f->lock); } void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f) @@ -300,30 +337,18 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, struct inet_frag_queue *qp_in, struct inet_frags *f, void *arg) { - struct inet_frag_bucket *hb; + struct inet_frag_bucket *hb = get_frag_bucket_locked(qp_in, f); struct inet_frag_queue *qp; - unsigned int hash; - - read_lock(&f->lock); /* Protects against hash rebuild */ - /* - * While we stayed w/o the lock other CPU could update - * the rnd seed, so we need to re-calculate the hash - * chain. Fortunatelly the qp_in can be used to get one. - */ - hash = inet_frag_hashfn(f, qp_in); - hb = &f->hash[hash]; - spin_lock(&hb->chain_lock); #ifdef CONFIG_SMP /* With SMP race we have to recheck hash table, because - * such entry could be created on other cpu, while we - * released the hash bucket lock. + * such entry could have been created on other cpu before + * we acquired hash bucket lock. */ hlist_for_each_entry(qp, &hb->chain, list) { if (qp->net == nf && f->match(qp, arg)) { atomic_inc(&qp->refcnt); spin_unlock(&hb->chain_lock); - read_unlock(&f->lock); qp_in->last_in |= INET_FRAG_COMPLETE; inet_frag_put(qp_in, f); return qp; @@ -338,7 +363,6 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, hlist_add_head(&qp->list, &hb->chain); spin_unlock(&hb->chain_lock); - read_unlock(&f->lock); return qp; } @@ -382,7 +406,6 @@ static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf, struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, struct inet_frags *f, void *key, unsigned int hash) - __releases(&f->lock) { struct inet_frag_bucket *hb; struct inet_frag_queue *q; @@ -399,19 +422,18 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, if (q->net == nf && f->match(q, key)) { atomic_inc(&q->refcnt); spin_unlock(&hb->chain_lock); - read_unlock(&f->lock); return q; } depth++; } spin_unlock(&hb->chain_lock); - read_unlock(&f->lock); if (depth <= INETFRAGS_MAXDEPTH) return inet_frag_create(nf, f, key); if (inet_frag_may_rebuild(f)) { - f->rebuild = true; + if (!f->rebuild) + f->rebuild = true; inet_frag_schedule_worker(f); } diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 44e591a7e03f..ccee68dffd6e 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -244,7 +244,6 @@ static inline struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user) arg.iph = iph; arg.user = user; - read_lock(&ip4_frags.lock); hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol); q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash); diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 3b3ef9774cc2..4d9da1e35f8c 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -193,7 +193,7 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id, arg.dst = dst; arg.ecn = ecn; - read_lock_bh(&nf_frags.lock); + local_bh_disable(); hash = nf_hash_frag(id, src, dst); q = inet_frag_find(&net->nf_frag.frags, &nf_frags, &arg, hash); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 987fea46b915..57a9707b2032 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -190,7 +190,6 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src, arg.dst = dst; arg.ecn = ecn; - read_lock(&ip6_frags.lock); hash = inet6_hash_frag(id, src, dst); q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); -- cgit v1.2.3 From 1bab4c75075b84675b96992ac47580a57c26958d Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Thu, 24 Jul 2014 16:50:37 +0200 Subject: inet: frag: set limits and make init_net's high_thresh limit global This patch makes init_net's high_thresh limit to be the maximum for all namespaces, thus introducing a global memory limit threshold equal to the sum of the individual high_thresh limits which are capped. It also introduces some sane minimums for low_thresh as it shouldn't be able to drop below 0 (or > high_thresh in the unsigned case), and overall low_thresh should not ever be above high_thresh, so we make the following relations for a namespace: init_net: high_thresh - max(not capped), min(init_net low_thresh) low_thresh - max(init_net high_thresh), min (0) all other namespaces: high_thresh = max(init_net high_thresh), min(namespace's low_thresh) low_thresh = max(namespace's high_thresh), min(0) The major issue with having low_thresh > high_thresh is that we'll schedule eviction but never evict anything and thus rely only on the timers. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 3 ++- net/ieee802154/reassembly.c | 12 ++++++++++-- net/ipv4/ip_fragment.c | 10 ++++++++-- net/ipv6/netfilter/nf_conntrack_reasm.c | 12 ++++++++++-- net/ipv6/reassembly.c | 12 ++++++++++-- 5 files changed, 40 insertions(+), 9 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index e8c304e37831..29a93518bf18 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -101,7 +101,8 @@ ipfrag_high_thresh - INTEGER Maximum memory used to reassemble IP fragments. When ipfrag_high_thresh bytes of memory is allocated for this purpose, the fragment handler will toss packets until ipfrag_low_thresh - is reached. + is reached. This also serves as a maximum limit to namespaces + different from the initial one. ipfrag_low_thresh - INTEGER Maximum memory used to reassemble IP fragments before the kernel diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index 8da635d92a58..f13d4f32e207 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -386,20 +386,25 @@ err: EXPORT_SYMBOL(lowpan_frag_rcv); #ifdef CONFIG_SYSCTL +static int zero; + static struct ctl_table lowpan_frags_ns_ctl_table[] = { { .procname = "6lowpanfrag_high_thresh", .data = &init_net.ieee802154_lowpan.frags.high_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .extra1 = &init_net.ieee802154_lowpan.frags.low_thresh }, { .procname = "6lowpanfrag_low_thresh", .data = &init_net.ieee802154_lowpan.frags.low_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &init_net.ieee802154_lowpan.frags.high_thresh }, { .procname = "6lowpanfrag_time", @@ -446,7 +451,10 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net) goto err_alloc; table[0].data = &ieee802154_lowpan->frags.high_thresh; + table[0].extra1 = &ieee802154_lowpan->frags.low_thresh; + table[0].extra2 = &init_net.ieee802154_lowpan.frags.high_thresh; table[1].data = &ieee802154_lowpan->frags.low_thresh; + table[1].extra2 = &ieee802154_lowpan->frags.high_thresh; table[2].data = &ieee802154_lowpan->frags.timeout; table[3].data = &ieee802154_lowpan->max_dsize; diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index ccee68dffd6e..634fc31aa243 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -700,14 +700,17 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = { .data = &init_net.ipv4.frags.high_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .extra1 = &init_net.ipv4.frags.low_thresh }, { .procname = "ipfrag_low_thresh", .data = &init_net.ipv4.frags.low_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &init_net.ipv4.frags.high_thresh }, { .procname = "ipfrag_time", @@ -752,7 +755,10 @@ static int __net_init ip4_frags_ns_ctl_register(struct net *net) goto err_alloc; table[0].data = &net->ipv4.frags.high_thresh; + table[0].extra1 = &net->ipv4.frags.low_thresh; + table[0].extra2 = &init_net.ipv4.frags.high_thresh; table[1].data = &net->ipv4.frags.low_thresh; + table[1].extra2 = &net->ipv4.frags.high_thresh; table[2].data = &net->ipv4.frags.timeout; /* Don't export sysctls to unprivileged users */ diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 4d9da1e35f8c..3d4bccf6d67d 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -63,6 +63,8 @@ struct nf_ct_frag6_skb_cb static struct inet_frags nf_frags; #ifdef CONFIG_SYSCTL +static int zero; + static struct ctl_table nf_ct_frag6_sysctl_table[] = { { .procname = "nf_conntrack_frag6_timeout", @@ -76,14 +78,17 @@ static struct ctl_table nf_ct_frag6_sysctl_table[] = { .data = &init_net.nf_frag.frags.low_thresh, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &init_net.nf_frag.frags.high_thresh }, { .procname = "nf_conntrack_frag6_high_thresh", .data = &init_net.nf_frag.frags.high_thresh, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, + .extra1 = &init_net.nf_frag.frags.low_thresh }, { } }; @@ -102,7 +107,10 @@ static int nf_ct_frag6_sysctl_register(struct net *net) table[0].data = &net->nf_frag.frags.timeout; table[1].data = &net->nf_frag.frags.low_thresh; + table[1].extra2 = &net->nf_frag.frags.high_thresh; table[2].data = &net->nf_frag.frags.high_thresh; + table[2].extra1 = &net->nf_frag.frags.low_thresh; + table[2].extra2 = &init_net.nf_frag.frags.high_thresh; } hdr = register_net_sysctl(net, "net/netfilter", table); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 57a9707b2032..f1709c4a289a 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -578,20 +578,25 @@ static const struct inet6_protocol frag_protocol = }; #ifdef CONFIG_SYSCTL +static int zero; + static struct ctl_table ip6_frags_ns_ctl_table[] = { { .procname = "ip6frag_high_thresh", .data = &init_net.ipv6.frags.high_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .extra1 = &init_net.ipv6.frags.low_thresh }, { .procname = "ip6frag_low_thresh", .data = &init_net.ipv6.frags.low_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &init_net.ipv6.frags.high_thresh }, { .procname = "ip6frag_time", @@ -628,7 +633,10 @@ static int __net_init ip6_frags_ns_sysctl_register(struct net *net) goto err_alloc; table[0].data = &net->ipv6.frags.high_thresh; + table[0].extra1 = &net->ipv6.frags.low_thresh; + table[0].extra2 = &init_net.ipv6.frags.high_thresh; table[1].data = &net->ipv6.frags.low_thresh; + table[1].extra2 = &net->ipv6.frags.high_thresh; table[2].data = &net->ipv6.frags.timeout; /* Don't export sysctls to unprivileged users */ -- cgit v1.2.3 From 6304f8fc398e4c8d2bac884ae2b4467c66620fd1 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 28 Jul 2014 15:16:30 +0200 Subject: MAINTAINERS: add 6lowpan header file Since commit 68d96dcfc6c09b565d57897c127b61afbab74c6f ("MAINTAINERS: add net/6lowpan/ maintainer entry") we have a 6lowpan branch. This patch adds a forgotten file which should also be maintained by this branch. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0057ff580536..1859c2d0f9fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -154,6 +154,7 @@ L: linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-bluetooth@vger.kernel.org S: Maintained F: net/6lowpan/ +F: include/net/6lowpan.h 6PACK NETWORK DRIVER FOR AX.25 M: Andreas Koensgen -- cgit v1.2.3 From 204e399003174ee8ceb7606c61daaa7f4e89e794 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 28 Jul 2014 15:45:31 +0300 Subject: Bluetooth: Fix clearing HCI_PSCAN flag This patch fixes a typo in the hci_cc_write_scan_enable() function where we want to clear the HCI_PSCAN flag if the SCAN_PAGE bit of the HCI command parameter was not set. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ba26fbfe481a..623501ddd1b8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -317,7 +317,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) if (param & SCAN_PAGE) set_bit(HCI_PSCAN, &hdev->flags); else - clear_bit(HCI_ISCAN, &hdev->flags); + clear_bit(HCI_PSCAN, &hdev->flags); done: hci_dev_unlock(hdev); -- cgit v1.2.3 From 3bd2724010a51d5d15afa8065ac3c5fab3725499 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 28 Jul 2014 20:53:58 +0300 Subject: Bluetooth: Fix incorrectly disabling page scan when toggling connectable If we have entries in the whitelist we shouldn't disable page scanning when disabling connectable mode. This patch adds the necessary check to the Set Connectable command handler. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index eb25a1259271..5d18efcb8467 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1881,7 +1881,18 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, if (cp->val) { scan = SCAN_PAGE; } else { - scan = 0; + /* If we don't have any whitelist entries just + * disable all scanning. If there are entries + * and we had both page and inquiry scanning + * enabled then fall back to only page scanning. + * Otherwise no changes are needed. + */ + if (list_empty(&hdev->whitelist)) + scan = SCAN_DISABLED; + else if (test_bit(HCI_ISCAN, &hdev->flags)) + scan = SCAN_PAGE; + else + goto no_scan_update; if (test_bit(HCI_ISCAN, &hdev->flags) && hdev->discov_timeout > 0) @@ -1891,6 +1902,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); } +no_scan_update: /* If we're going from non-connectable to connectable or * vice-versa when fast connectable is enabled ensure that fast * connectable gets disabled. write_fast_connectable won't do -- cgit v1.2.3 From d87de1f3e9635b16345bde54306c949417b689ad Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Fri, 25 Jul 2014 02:18:17 -0700 Subject: netlink: Fix shadow warning on jiffies Change formal parameter name to not shadow the global jiffies. Signed-off-by: Mark Rustad Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- include/net/netlink.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 2b47eaadba8f..6c1076275aaa 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -949,12 +949,12 @@ static inline int nla_put_flag(struct sk_buff *skb, int attrtype) * nla_put_msecs - Add a msecs netlink attribute to a socket buffer * @skb: socket buffer to add attribute to * @attrtype: attribute type - * @jiffies: number of msecs in jiffies + * @njiffies: number of jiffies to convert to msecs */ static inline int nla_put_msecs(struct sk_buff *skb, int attrtype, - unsigned long jiffies) + unsigned long njiffies) { - u64 tmp = jiffies_to_msecs(jiffies); + u64 tmp = jiffies_to_msecs(njiffies); return nla_put(skb, attrtype, sizeof(u64), &tmp); } -- cgit v1.2.3 From a67eed571aa505f51a4d02cab765a9d4f6ef80c4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 25 Jul 2014 15:21:21 +0300 Subject: bonding: fix a memory leak in bond_arp_send_all() This test is reversed so the memory is always leaked. It's better style to remove the test anyway. Fixes: 3e403a77779f ('bonding: make it possible to have unlimited nested upper vlans') Signed-off-by: Dan Carpenter Acked-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 023ec365209c..f0f5eab0fab1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2287,8 +2287,7 @@ found: ip_rt_put(rt); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], addr, tags); - if (!tags) - kfree(tags); + kfree(tags); } } -- cgit v1.2.3 From 13e9b9972fa0f34059e737ae215a26e43966b46f Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Fri, 25 Jul 2014 14:48:09 -0400 Subject: tipc: make tipc_buf_append() more robust As per comment from David Miller, we try to make the buffer reassembly function more resilient to user errors than it is today. - We check that the "*buf" parameter always is set, since this is mandatory input. - We ensure that *buf->next always is set to NULL before linking in the buffer, instead of relying of the caller to have done this. - We ensure that the "tail" pointer in the head buffer's control block is initialized to NULL when the first fragment arrives. Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/msg.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/net/tipc/msg.c b/net/tipc/msg.c index b6f45d029933..9680be6d388a 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -72,27 +72,38 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) struct sk_buff *head = *headbuf; struct sk_buff *frag = *buf; struct sk_buff *tail; - struct tipc_msg *msg = buf_msg(frag); - u32 fragid = msg_type(msg); - bool headstolen; + struct tipc_msg *msg; + u32 fragid; int delta; + bool headstolen; + if (!frag) + goto err; + + msg = buf_msg(frag); + fragid = msg_type(msg); + frag->next = NULL; skb_pull(frag, msg_hdr_sz(msg)); if (fragid == FIRST_FRAGMENT) { - if (head || skb_unclone(frag, GFP_ATOMIC)) - goto out_free; + if (unlikely(head)) + goto err; + if (unlikely(skb_unclone(frag, GFP_ATOMIC))) + goto err; head = *headbuf = frag; skb_frag_list_init(head); + TIPC_SKB_CB(head)->tail = NULL; *buf = NULL; return 0; } + if (!head) - goto out_free; - tail = TIPC_SKB_CB(head)->tail; + goto err; + if (skb_try_coalesce(head, frag, &headstolen, &delta)) { kfree_skb_partial(frag, headstolen); } else { + tail = TIPC_SKB_CB(head)->tail; if (!skb_has_frag_list(head)) skb_shinfo(head)->frag_list = frag; else @@ -102,6 +113,7 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) head->len += frag->len; TIPC_SKB_CB(head)->tail = frag; } + if (fragid == LAST_FRAGMENT) { *buf = head; TIPC_SKB_CB(head)->tail = NULL; @@ -110,7 +122,8 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) } *buf = NULL; return 0; -out_free: + +err: pr_warn_ratelimited("Unable to build fragment list\n"); kfree_skb(*buf); kfree_skb(*headbuf); -- cgit v1.2.3 From 1217dda7cb2e93dc236cba4544239c586f391099 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Sun, 29 Jun 2014 16:16:58 +0200 Subject: dt: bindings: add bindings for Broadcom bcm43xx sdio devices The Broadcom bcm43xx sdio devices are fullmac devices that may be integrated in ARM platforms. Currently, the brcmfmac driver for these devices support use of platform data. This patch specifies the bindings that allow this platform data to be expressed in the devicetree. Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel [hdegoede@redhat.com: drop clk / reg_on gpio handling, as there is no consensus on how to handle this yet] [hdegoede@redhat.com: move from bindings/staging to bindings] Signed-off-by: Hans de Goede Signed-off-by: John W. Linville --- .../bindings/net/wireless/brcm,bcm43xx-fmac.txt | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/wireless/brcm,bcm43xx-fmac.txt diff --git a/Documentation/devicetree/bindings/net/wireless/brcm,bcm43xx-fmac.txt b/Documentation/devicetree/bindings/net/wireless/brcm,bcm43xx-fmac.txt new file mode 100644 index 000000000000..5dbf169cd81c --- /dev/null +++ b/Documentation/devicetree/bindings/net/wireless/brcm,bcm43xx-fmac.txt @@ -0,0 +1,41 @@ +Broadcom BCM43xx Fullmac wireless SDIO devices + +This node provides properties for controlling the Broadcom wireless device. The +node is expected to be specified as a child node to the SDIO controller that +connects the device to the system. + +Required properties: + + - compatible : Should be "brcm,bcm4329-fmac". + +Optional properties: + - brcm,drive-strength : drive strength used for SDIO pins on device in mA + (default = 6). + - interrupt-parent : the phandle for the interrupt controller to which the + device interrupts are connected. + - interrupts : specifies attributes for the out-of-band interrupt (host-wake). + When not specified the device will use in-band SDIO interrupts. + - interrupt-names : name of the out-of-band interrupt, which must be set + to "host-wake". + +Example: + +mmc3: mmc@01c12000 { + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&mmc3_pins_a>; + vmmc-supply = <®_vmmc3>; + bus-width = <4>; + non-removable; + status = "okay"; + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + interrupt-parent = <&pio>; + interrupts = <10 8>; /* PH10 / EINT10 */ + interrupt-names = "host-wake"; + }; +}; -- cgit v1.2.3 From 61f663dfc1a091c7c04fa73666af52a42aaa083f Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sun, 29 Jun 2014 16:16:59 +0200 Subject: brcmfmac: add device tree support for SDIO devices brcmfmac devices can use an out-of-band interrupt on a GPIO line. Currently this is specified using platform data. Add support for specifying out-of-band interrupt via device tree. Signed-off-by: Chen-Yu Tsai [arend@broadcom.com: conditionalize more of-code, use driver debug routines] Signed-off-by: Arend van Spriel [hdegoede@redhat.com: drop clk / reg_on gpio handling, as there is no consensus on how to handle this yet] Signed-off-by: Hans de Goede Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/Makefile | 2 + drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 4 ++ drivers/net/wireless/brcm80211/brcmfmac/of.c | 56 ++++++++++++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/of.h | 22 ++++++++++ 4 files changed, 84 insertions(+) create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/of.c create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/of.h diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index de0cff3df389..14e8a8d33520 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -46,3 +46,5 @@ brcmfmac-$(CONFIG_BRCMDBG) += \ dhd_dbg.o brcmfmac-$(CONFIG_BRCM_TRACING) += \ tracepoint.o +brcmfmac-$(CONFIG_OF) += \ + of.o diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index f467cafe3e8f..dc2db47a1c73 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -42,6 +42,7 @@ #include "dhd_bus.h" #include "dhd_dbg.h" #include "sdio_host.h" +#include "of.h" #define SDIOH_API_ACCESS_RETRY_LIMIT 2 @@ -1044,6 +1045,9 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, sdiodev->dev = &sdiodev->func[1]->dev; sdiodev->pdata = brcmfmac_sdio_pdata; + if (!sdiodev->pdata) + brcmf_of_probe(sdiodev); + atomic_set(&sdiodev->suspend, false); init_waitqueue_head(&sdiodev->request_word_wait); init_waitqueue_head(&sdiodev->request_buffer_wait); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/of.c b/drivers/net/wireless/brcm80211/brcmfmac/of.c new file mode 100644 index 000000000000..f05f5270fec1 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/of.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include +#include + +#include +#include "dhd_dbg.h" +#include "sdio_host.h" + +void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev) +{ + struct device *dev = sdiodev->dev; + struct device_node *np = dev->of_node; + int irq; + u32 irqf; + u32 val; + + if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac")) + return; + + sdiodev->pdata = devm_kzalloc(dev, sizeof(*sdiodev->pdata), GFP_KERNEL); + if (!sdiodev->pdata) + return; + + irq = irq_of_parse_and_map(np, 0); + if (irq < 0) { + brcmf_err("interrupt could not be mapped: err=%d\n", irq); + devm_kfree(dev, sdiodev->pdata); + return; + } + irqf = irqd_get_trigger_type(irq_get_irq_data(irq)); + + sdiodev->pdata->oob_irq_supported = true; + sdiodev->pdata->oob_irq_nr = irq; + sdiodev->pdata->oob_irq_flags = irqf; + + if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0) + sdiodev->pdata->drive_strength = val; +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/of.h b/drivers/net/wireless/brcm80211/brcmfmac/of.h new file mode 100644 index 000000000000..5f7c3550deda --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/of.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef CONFIG_OF +void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev); +#else +static void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev) +{ +} +#endif /* CONFIG_OF */ -- cgit v1.2.3 From 3cdf0a81ab22f64d6160072d52afd29f5f8f4da6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 29 Jun 2014 16:17:00 +0200 Subject: brcmfmac: Fix some wrong register defines Signed-off-by: Hans de Goede Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h index 6c5e585ccda9..f2d06cae366a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h @@ -74,12 +74,12 @@ #define SBSDIO_SPROM_DATA_HIGH 0x10003 /* sprom indirect access addr byte 0 */ #define SBSDIO_SPROM_ADDR_LOW 0x10004 -/* sprom indirect access addr byte 0 */ -#define SBSDIO_SPROM_ADDR_HIGH 0x10005 -/* xtal_pu (gpio) output */ -#define SBSDIO_CHIP_CTRL_DATA 0x10006 -/* xtal_pu (gpio) enable */ -#define SBSDIO_CHIP_CTRL_EN 0x10007 +/* gpio select */ +#define SBSDIO_GPIO_SELECT 0x10005 +/* gpio output */ +#define SBSDIO_GPIO_OUT 0x10006 +/* gpio enable */ +#define SBSDIO_GPIO_EN 0x10007 /* rev < 7, watermark for sdio device */ #define SBSDIO_WATERMARK 0x10008 /* control busy signal generation */ -- cgit v1.2.3 From a67d19d4c5b92853550dc20f4afce8c914a8ea0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 24 Jul 2014 15:29:18 +0200 Subject: b43: add support for BCM43131 chipset with N-PHY rev 17 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It contains radio 0x2057 rev 14 just like a BCM43217, so it doesn't require any magic. The main difference is that BCM4313 is 1x1:1. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 3 ++- drivers/net/wireless/b43/phy_n.c | 3 ++- include/linux/bcma/bcma.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index d7055febe119..2af1ac396eb4 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2985,7 +2985,8 @@ void b43_mac_switch_freq(struct b43_wldev *dev, u8 spurmode) { u16 chip_id = dev->dev->chip_id; - if (chip_id == BCMA_CHIP_ID_BCM43217 || + if (chip_id == BCMA_CHIP_ID_BCM43131 || + chip_id == BCMA_CHIP_ID_BCM43217 || chip_id == BCMA_CHIP_ID_BCM43222 || chip_id == BCMA_CHIP_ID_BCM43224 || chip_id == BCMA_CHIP_ID_BCM43225 || diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index d269fbb27b9e..1eead7af6899 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -4982,7 +4982,8 @@ static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev) if (dev->phy.rev == 16) b43_nphy_pa_set_tx_dig_filter(dev, 0x186, dig_filter_phy_rev16); - if (dev->dev->chip_id == BCMA_CHIP_ID_BCM43217) { + /* Verified with BCM43131 and BCM43217 */ + if (dev->phy.rev == 17) { b43_nphy_pa_set_tx_dig_filter(dev, 0x186, dig_filter_phy_rev16); b43_nphy_pa_set_tx_dig_filter(dev, 0x195, tbl_tx_filter_coef_rev4[1]); diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 969af0f2bdf9..70b8d88b3982 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -158,6 +158,7 @@ struct bcma_host_ops { /* Chip IDs of PCIe devices */ #define BCMA_CHIP_ID_BCM4313 0x4313 #define BCMA_CHIP_ID_BCM43142 43142 +#define BCMA_CHIP_ID_BCM43131 43131 #define BCMA_CHIP_ID_BCM43217 43217 #define BCMA_CHIP_ID_BCM43222 43222 #define BCMA_CHIP_ID_BCM43224 43224 -- cgit v1.2.3 From 27cfdb0505e7bfdd84432823b9697b971d4fa731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 24 Jul 2014 15:29:19 +0200 Subject: bcma: add support for BCM43131 that was found in Tenda W311E MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/bcma/driver_chipcommon_pmu.c | 1 + drivers/bcma/host_pci.c | 1 + drivers/bcma/sprom.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index bb694e2e9f32..fe0d48cb1778 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -603,6 +603,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid) tmp = BCMA_CC_PMU_CTL_PLL_UPD | BCMA_CC_PMU_CTL_NOILPONW; break; + case BCMA_CHIP_ID_BCM43131: case BCMA_CHIP_ID_BCM43217: case BCMA_CHIP_ID_BCM43227: case BCMA_CHIP_ID_BCM43228: diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index 3cf725a49dc1..294a7dd25190 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -280,6 +280,7 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, { 0, }, }; diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 97bb38e9ed65..efb037f9c98a 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -534,6 +534,7 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus) /* for these chips OTP is always available */ present = true; break; + case BCMA_CHIP_ID_BCM43131: case BCMA_CHIP_ID_BCM43217: case BCMA_CHIP_ID_BCM43227: case BCMA_CHIP_ID_BCM43228: -- cgit v1.2.3 From cf9ae8fa0110546c928836957bc54d42fea7828b Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Sat, 26 Jul 2014 10:25:41 +0530 Subject: ath9k: Initialize channel context ops on ahb probe Not doing so, could fail on device probing when use_chanctx module param is set to true. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index be3eb2a8d602..4173838f4684 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -113,6 +113,7 @@ static int ath_ahb_probe(struct platform_device *pdev) irq = res->start; + ath9k_fill_chanctx_ops(); hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); if (hw == NULL) { dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); -- cgit v1.2.3 From 568ba389be505f505b7fbeedb9ab4ece27603fc9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 29 Jul 2014 14:23:23 +0200 Subject: brcmfmac: Fix OOB interrupt not working for BCM43362 It has taken me a long long time to get the OOB interrupt working on the AP6210 sdio wifi/bt module found on various Allwinner A20 boards. In the end I found these magic register pokes in the cubietruck kernel tree: https://github.com/cubieboard2/linux-sunxi/commit/7f08ba395617d17e7a711507503d89a50406fe7a This is also done for the bcm43362 in broadcom's internal/proprietary driver. Signed-off-by: Hans de Goede Reviewed-by: Arend van Spriel [arend@broadcom.com: rebased changing BCM43362 chip id to fix compilation] Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index dc2db47a1c73..8dbd5dbb78fd 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -38,7 +38,9 @@ #include #include #include +#include #include +#include "chip.h" #include "dhd_bus.h" #include "dhd_dbg.h" #include "sdio_host.h" @@ -118,6 +120,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) { int ret = 0; u8 data; + u32 addr, gpiocontrol; unsigned long flags; if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) { @@ -147,6 +150,19 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) sdio_claim_host(sdiodev->func[1]); + if (sdiodev->bus_if->chip == BRCM_CC_43362_CHIP_ID) { + /* assign GPIO to SDIO core */ + addr = CORE_CC_REG(SI_ENUM_BASE, gpiocontrol); + gpiocontrol = brcmf_sdiod_regrl(sdiodev, addr, &ret); + gpiocontrol |= 0x2; + brcmf_sdiod_regwl(sdiodev, addr, gpiocontrol, &ret); + + brcmf_sdiod_regwb(sdiodev, SBSDIO_GPIO_SELECT, 0xf, + &ret); + brcmf_sdiod_regwb(sdiodev, SBSDIO_GPIO_OUT, 0, &ret); + brcmf_sdiod_regwb(sdiodev, SBSDIO_GPIO_EN, 0x2, &ret); + } + /* must configure SDIO_CCCR_IENx to enable irq */ data = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_IENx, &ret); data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1; -- cgit v1.2.3 From c6d5fefaa35eda3dcab5c78a16def6ed555b685c Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Fri, 25 Jul 2014 18:01:29 -0400 Subject: octeon: remove deprecated syststamp timestamp Hardware timestamps can be exposed to userspace in raw hardware format (hwtstamp) as well as converted to system time (syststamp). The second variant is deprecated and only implemented by this driver. The preferred method of hardware timestamp generation is to combine hwtstamp with a device PTP clock. Octeon has its own PTP library that relies on a shared memory interface to the PTP clock device. Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- drivers/net/ethernet/octeon/octeon_mgmt.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c index 7dc3e9b06d75..979c6980639f 100644 --- a/drivers/net/ethernet/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/octeon/octeon_mgmt.c @@ -247,28 +247,6 @@ static void octeon_mgmt_rx_fill_ring(struct net_device *netdev) } } -static ktime_t ptp_to_ktime(u64 ptptime) -{ - ktime_t ktimebase; - u64 ptpbase; - unsigned long flags; - - local_irq_save(flags); - /* Fill the icache with the code */ - ktime_get_real(); - /* Flush all pending operations */ - mb(); - /* Read the time and PTP clock as close together as - * possible. It is important that this sequence take the same - * amount of time to reduce jitter - */ - ktimebase = ktime_get_real(); - ptpbase = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_HI); - local_irq_restore(flags); - - return ktime_sub_ns(ktimebase, ptpbase - ptptime); -} - static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p) { union cvmx_mixx_orcnt mix_orcnt; @@ -312,12 +290,12 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p) /* Read the hardware TX timestamp if one was recorded */ if (unlikely(re.s.tstamp)) { struct skb_shared_hwtstamps ts; + memset(&ts, 0, sizeof(ts)); /* Read the timestamp */ u64 ns = cvmx_read_csr(CVMX_MIXX_TSTAMP(p->port)); /* Remove the timestamp from the FIFO */ cvmx_write_csr(CVMX_MIXX_TSCTL(p->port), 0); /* Tell the kernel about the timestamp */ - ts.syststamp = ptp_to_ktime(ns); ts.hwtstamp = ns_to_ktime(ns); skb_tstamp_tx(skb, &ts); } @@ -429,7 +407,6 @@ good: struct skb_shared_hwtstamps *ts; ts = skb_hwtstamps(skb); ts->hwtstamp = ns_to_ktime(ns); - ts->syststamp = ptp_to_ktime(ns); __skb_pull(skb, 8); } skb->protocol = eth_type_trans(skb, netdev); -- cgit v1.2.3 From ce7505882122d9fd72159e902b1ca9cc9d896679 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Fri, 25 Jul 2014 18:01:30 -0400 Subject: vxge: remove deprecated syststamp timestamp This driver explicitly clears a field that is unused and about to be removed. Remove the initialization. All fields in skb_shared_info before dataref are cleared in __alloc_skb, so the removal is safe even while syststamp exists. Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- drivers/net/ethernet/neterion/vxge/vxge-main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index 7a0deadd53bf..2eda153cb1e0 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -503,7 +503,6 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, skb_hwts = skb_hwtstamps(skb); skb_hwts->hwtstamp = ns_to_ktime(ns); - skb_hwts->syststamp.tv64 = 0; } /* rth_hash_type and rth_it_hit are non-zero regardless of -- cgit v1.2.3 From 68a360e82e55c9b35097e7be7f7991d8f401032f Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Fri, 25 Jul 2014 18:01:31 -0400 Subject: packet: remove deprecated syststamp timestamp No device driver will ever return an skb_shared_info structure with syststamp non-zero, so remove the branch that tests for this and optionally marks the packet timestamp as TP_STATUS_TS_SYS_HARDWARE. Do not remove the definition TP_STATUS_TS_SYS_HARDWARE, as processes may refer to it. Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- Documentation/networking/packet_mmap.txt | 18 ++++++------------ include/uapi/linux/if_packet.h | 2 +- net/packet/af_packet.c | 12 ++++-------- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt index 38112d512f47..a6d7cb91069e 100644 --- a/Documentation/networking/packet_mmap.txt +++ b/Documentation/networking/packet_mmap.txt @@ -1008,14 +1008,9 @@ hardware timestamps to be used. Note: you may need to enable the generation of hardware timestamps with SIOCSHWTSTAMP (see related information from Documentation/networking/timestamping.txt). -PACKET_TIMESTAMP accepts the same integer bit field as -SO_TIMESTAMPING. However, only the SOF_TIMESTAMPING_SYS_HARDWARE -and SOF_TIMESTAMPING_RAW_HARDWARE values are recognized by -PACKET_TIMESTAMP. SOF_TIMESTAMPING_SYS_HARDWARE takes precedence over -SOF_TIMESTAMPING_RAW_HARDWARE if both bits are set. - - int req = 0; - req |= SOF_TIMESTAMPING_SYS_HARDWARE; +PACKET_TIMESTAMP accepts the same integer bit field as SO_TIMESTAMPING: + + int req = SOF_TIMESTAMPING_RAW_HARDWARE; setsockopt(fd, SOL_PACKET, PACKET_TIMESTAMP, (void *) &req, sizeof(req)) For the mmap(2)ed ring buffers, such timestamps are stored in the @@ -1023,14 +1018,13 @@ tpacket{,2,3}_hdr structure's tp_sec and tp_{n,u}sec members. To determine what kind of timestamp has been reported, the tp_status field is binary |'ed with the following possible bits ... - TP_STATUS_TS_SYS_HARDWARE TP_STATUS_TS_RAW_HARDWARE TP_STATUS_TS_SOFTWARE ... that are equivalent to its SOF_TIMESTAMPING_* counterparts. For the -RX_RING, if none of those 3 are set (i.e. PACKET_TIMESTAMP is not set), -then this means that a software fallback was invoked *within* PF_PACKET's -processing code (less precise). +RX_RING, if neither is set (i.e. PACKET_TIMESTAMP is not set), then a +software fallback was invoked *within* PF_PACKET's processing code (less +precise). Getting timestamps for the TX_RING works as follows: i) fill the ring frames, ii) call sendto() e.g. in blocking mode, iii) wait for status of relevant diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h index bac27fa05f5b..da2d668b8cf1 100644 --- a/include/uapi/linux/if_packet.h +++ b/include/uapi/linux/if_packet.h @@ -108,7 +108,7 @@ struct tpacket_auxdata { /* Rx and Tx ring - header status */ #define TP_STATUS_TS_SOFTWARE (1 << 29) -#define TP_STATUS_TS_SYS_HARDWARE (1 << 30) +#define TP_STATUS_TS_SYS_HARDWARE (1 << 30) /* deprecated, never set */ #define TP_STATUS_TS_RAW_HARDWARE (1 << 31) /* Rx ring - feature request bits */ diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 614ca91f785a..8d9f8042705a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -441,14 +441,10 @@ static __u32 tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts, { struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); - if (shhwtstamps) { - if ((flags & SOF_TIMESTAMPING_SYS_HARDWARE) && - ktime_to_timespec_cond(shhwtstamps->syststamp, ts)) - return TP_STATUS_TS_SYS_HARDWARE; - if ((flags & SOF_TIMESTAMPING_RAW_HARDWARE) && - ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts)) - return TP_STATUS_TS_RAW_HARDWARE; - } + if (shhwtstamps && + (flags & SOF_TIMESTAMPING_RAW_HARDWARE) && + ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts)) + return TP_STATUS_TS_RAW_HARDWARE; if (ktime_to_timespec_cond(skb->tstamp, ts)) return TP_STATUS_TS_SOFTWARE; -- cgit v1.2.3 From 4d276eb6a478307a28ae843836c455bf04b37a3c Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Fri, 25 Jul 2014 18:01:32 -0400 Subject: net: remove deprecated syststamp timestamp The SO_TIMESTAMPING API defines three types of timestamps: software, hardware in raw format (hwtstamp) and hardware converted to system format (syststamp). The last has been deprecated in favor of combining hwtstamp with a PTP clock driver. There are no active users in the kernel. The option was device driver dependent. If set, but without hardware support, the correct behavior is to return zero in the relevant field in the SCM_TIMESTAMPING ancillary message. Without device drivers implementing the option, this field is effectively always zero. Remove the internal plumbing to dissuage new drivers from implementing the feature. Keep the SOF_TIMESTAMPING_SYS_HARDWARE flag, however, to avoid breaking existing applications that request the timestamp. Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- Documentation/networking/timestamping.txt | 12 ++---------- Documentation/networking/timestamping/timestamping.c | 7 +------ include/linux/skbuff.h | 14 +------------- include/net/sock.h | 11 +++-------- net/core/sock.c | 4 ---- net/socket.c | 12 ++++-------- 6 files changed, 11 insertions(+), 49 deletions(-) diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index 8b4ad809df27..897f942b976b 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt @@ -88,15 +88,8 @@ hwtimeraw is the original hardware time stamp. Filled in if SOF_TIMESTAMPING_RAW_HARDWARE is set. No assumptions about its relation to system time should be made. -hwtimetrans is the hardware time stamp transformed so that it -corresponds as good as possible to system time. This correlation is -not perfect; as a consequence, sorting packets received via different -NICs by their hwtimetrans may differ from the order in which they were -received. hwtimetrans may be non-monotonic even for the same NIC. -Filled in if SOF_TIMESTAMPING_SYS_HARDWARE is set. Requires support -by the network device and will be empty without that support. This -field is DEPRECATED. Only one driver computes this value. New device -drivers must leave this zero. Instead, they can expose the hardware +hwtimetrans is always zero. This field is deprecated. It used to hold +hw timestamps converted to system time. Instead, expose the hardware clock device on the NIC directly as a HW PTP clock source, to allow time conversion in userspace and optionally synchronize system time with a userspace PTP stack such as linuxptp. For the PTP clock API, @@ -191,7 +184,6 @@ struct skb_shared_hwtstamps { * since arbitrary point in time */ ktime_t hwtstamp; - ktime_t syststamp; /* hwtstamp transformed to system time base */ }; Time stamps for outgoing packets are to be generated as follows: diff --git a/Documentation/networking/timestamping/timestamping.c b/Documentation/networking/timestamping/timestamping.c index 8ba82bfe6a33..5cdfd743447b 100644 --- a/Documentation/networking/timestamping/timestamping.c +++ b/Documentation/networking/timestamping/timestamping.c @@ -76,7 +76,6 @@ static void usage(const char *error) " SOF_TIMESTAMPING_RX_HARDWARE - hardware time stamping of incoming packets\n" " SOF_TIMESTAMPING_RX_SOFTWARE - software fallback for incoming packets\n" " SOF_TIMESTAMPING_SOFTWARE - request reporting of software time stamps\n" - " SOF_TIMESTAMPING_SYS_HARDWARE - request reporting of transformed HW time stamps\n" " SOF_TIMESTAMPING_RAW_HARDWARE - request reporting of raw HW time stamps\n" " SIOCGSTAMP - check last socket time stamp\n" " SIOCGSTAMPNS - more accurate socket time stamp\n"); @@ -202,9 +201,7 @@ static void printpacket(struct msghdr *msg, int res, (long)stamp->tv_sec, (long)stamp->tv_nsec); stamp++; - printf("HW transformed %ld.%09ld ", - (long)stamp->tv_sec, - (long)stamp->tv_nsec); + /* skip deprecated HW transformed */ stamp++; printf("HW raw %ld.%09ld", (long)stamp->tv_sec, @@ -361,8 +358,6 @@ int main(int argc, char **argv) so_timestamping_flags |= SOF_TIMESTAMPING_RX_SOFTWARE; else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SOFTWARE")) so_timestamping_flags |= SOF_TIMESTAMPING_SOFTWARE; - else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SYS_HARDWARE")) - so_timestamping_flags |= SOF_TIMESTAMPING_SYS_HARDWARE; else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RAW_HARDWARE")) so_timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE; else diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index b613557132b9..281deced7469 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -210,20 +210,9 @@ static inline void skb_frag_size_sub(skb_frag_t *frag, int delta) * struct skb_shared_hwtstamps - hardware time stamps * @hwtstamp: hardware time stamp transformed into duration * since arbitrary point in time - * @syststamp: hwtstamp transformed to system time base (deprecated) * * Software time stamps generated by ktime_get_real() are stored in - * skb->tstamp. The relation between the different kinds of time - * stamps is as follows: - * - * syststamp and tstamp can be compared against each other in - * arbitrary combinations. The accuracy of a - * syststamp/tstamp/"syststamp from other device" comparison is - * limited by the accuracy of the transformation into system time - * base. This depends on the device driver and its underlying - * hardware. The syststamp implementation is deprecated in favor - * of hwtstamps and hw PTP clock sources exposed directly to - * userspace. + * skb->tstamp. * * hwtstamps can only be compared against other hwtstamps from * the same device. @@ -233,7 +222,6 @@ static inline void skb_frag_size_sub(skb_frag_t *frag, int delta) */ struct skb_shared_hwtstamps { ktime_t hwtstamp; - ktime_t syststamp; }; /* Definitions for tx_flags in struct skb_shared_info */ diff --git a/include/net/sock.h b/include/net/sock.h index 720773304a85..b91c8868ab8d 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -707,7 +707,6 @@ enum sock_flags { SOCK_TIMESTAMPING_RX_SOFTWARE, /* %SOF_TIMESTAMPING_RX_SOFTWARE */ SOCK_TIMESTAMPING_SOFTWARE, /* %SOF_TIMESTAMPING_SOFTWARE */ SOCK_TIMESTAMPING_RAW_HARDWARE, /* %SOF_TIMESTAMPING_RAW_HARDWARE */ - SOCK_TIMESTAMPING_SYS_HARDWARE, /* %SOF_TIMESTAMPING_SYS_HARDWARE */ SOCK_FASYNC, /* fasync() active */ SOCK_RXQ_OVFL, SOCK_ZEROCOPY, /* buffers from userspace */ @@ -2166,16 +2165,13 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) * - software time stamp available and wanted * (SOCK_TIMESTAMPING_SOFTWARE) * - hardware time stamps available and wanted - * (SOCK_TIMESTAMPING_SYS_HARDWARE or - * SOCK_TIMESTAMPING_RAW_HARDWARE) + * SOCK_TIMESTAMPING_RAW_HARDWARE */ if (sock_flag(sk, SOCK_RCVTSTAMP) || sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE) || (kt.tv64 && sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) || (hwtstamps->hwtstamp.tv64 && - sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE)) || - (hwtstamps->syststamp.tv64 && - sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE))) + sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE))) __sock_recv_timestamp(msg, sk, skb); else sk->sk_stamp = kt; @@ -2193,8 +2189,7 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, #define FLAGS_TS_OR_DROPS ((1UL << SOCK_RXQ_OVFL) | \ (1UL << SOCK_RCVTSTAMP) | \ (1UL << SOCK_TIMESTAMPING_SOFTWARE) | \ - (1UL << SOCK_TIMESTAMPING_RAW_HARDWARE) | \ - (1UL << SOCK_TIMESTAMPING_SYS_HARDWARE)) + (1UL << SOCK_TIMESTAMPING_RAW_HARDWARE)) if (sk->sk_flags & FLAGS_TS_OR_DROPS) __sock_recv_ts_and_drops(msg, sk, skb); diff --git a/net/core/sock.c b/net/core/sock.c index ca9b65199d28..134291d73fcd 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -862,8 +862,6 @@ set_rcvbuf: (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)); sock_valbool_flag(sk, SOCK_TIMESTAMPING_SOFTWARE, val & SOF_TIMESTAMPING_SOFTWARE); - sock_valbool_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE, - val & SOF_TIMESTAMPING_SYS_HARDWARE); sock_valbool_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE, val & SOF_TIMESTAMPING_RAW_HARDWARE); break; @@ -1102,8 +1100,6 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val |= SOF_TIMESTAMPING_RX_SOFTWARE; if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) v.val |= SOF_TIMESTAMPING_SOFTWARE; - if (sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE)) - v.val |= SOF_TIMESTAMPING_SYS_HARDWARE; if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE)) v.val |= SOF_TIMESTAMPING_RAW_HARDWARE; break; diff --git a/net/socket.c b/net/socket.c index abf56b2a14f9..d8222c025061 100644 --- a/net/socket.c +++ b/net/socket.c @@ -725,14 +725,10 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) && ktime_to_timespec_cond(skb->tstamp, ts + 0)) empty = 0; - if (shhwtstamps) { - if (sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE) && - ktime_to_timespec_cond(shhwtstamps->syststamp, ts + 1)) - empty = 0; - if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) && - ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts + 2)) - empty = 0; - } + if (shhwtstamps && + sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) && + ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts + 2)) + empty = 0; if (!empty) put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPING, sizeof(ts), &ts); -- cgit v1.2.3 From 20e61da7ffcfd84a1b6f797e745608572e5bc218 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 25 Jul 2014 15:25:08 -0700 Subject: ipv4: fail early when creating netdev named all or default We create a proc dir for each network device, this will cause conflicts when the devices have name "all" or "default". Rather than emitting an ugly kernel warning, we could just fail earlier by checking the device name. Reported-by: Stephane Chazelas Cc: "David S. Miller" Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- include/net/ip.h | 6 ++++++ net/ipv4/devinet.c | 36 +++++++++++++++++++++++++++--------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index ca14799545fd..09b32da1b929 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -216,6 +216,12 @@ static inline int inet_is_local_reserved_port(struct net *net, int port) return 0; return test_bit(port, net->ipv4.sysctl_local_reserved_ports); } + +static inline bool sysctl_dev_name_is_allowed(const char *name) +{ + return strcmp(name, "default") != 0 && strcmp(name, "all") != 0; +} + #else static inline int inet_is_local_reserved_port(struct net *net, int port) { diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index e9449376b58e..214882e7d6de 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -180,11 +180,12 @@ static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy); #ifdef CONFIG_SYSCTL -static void devinet_sysctl_register(struct in_device *idev); +static int devinet_sysctl_register(struct in_device *idev); static void devinet_sysctl_unregister(struct in_device *idev); #else -static void devinet_sysctl_register(struct in_device *idev) +static int devinet_sysctl_register(struct in_device *idev) { + return 0; } static void devinet_sysctl_unregister(struct in_device *idev) { @@ -232,6 +233,7 @@ EXPORT_SYMBOL(in_dev_finish_destroy); static struct in_device *inetdev_init(struct net_device *dev) { struct in_device *in_dev; + int err = -ENOMEM; ASSERT_RTNL(); @@ -252,7 +254,13 @@ static struct in_device *inetdev_init(struct net_device *dev) /* Account for reference dev->ip_ptr (below) */ in_dev_hold(in_dev); - devinet_sysctl_register(in_dev); + err = devinet_sysctl_register(in_dev); + if (err) { + in_dev->dead = 1; + in_dev_put(in_dev); + in_dev = NULL; + goto out; + } ip_mc_init_dev(in_dev); if (dev->flags & IFF_UP) ip_mc_up(in_dev); @@ -260,7 +268,7 @@ static struct in_device *inetdev_init(struct net_device *dev) /* we can receive as soon as ip_ptr is set -- do this last */ rcu_assign_pointer(dev->ip_ptr, in_dev); out: - return in_dev; + return in_dev ?: ERR_PTR(err); out_kfree: kfree(in_dev); in_dev = NULL; @@ -1347,8 +1355,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, if (!in_dev) { if (event == NETDEV_REGISTER) { in_dev = inetdev_init(dev); - if (!in_dev) - return notifier_from_errno(-ENOMEM); + if (IS_ERR(in_dev)) + return notifier_from_errno(PTR_ERR(in_dev)); if (dev->flags & IFF_LOOPBACK) { IN_DEV_CONF_SET(in_dev, NOXFRM, 1); IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); @@ -2182,11 +2190,21 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf) kfree(t); } -static void devinet_sysctl_register(struct in_device *idev) +static int devinet_sysctl_register(struct in_device *idev) { - neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); - __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, + int err; + + if (!sysctl_dev_name_is_allowed(idev->dev->name)) + return -EINVAL; + + err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); + if (err) + return err; + err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, &idev->cnf); + if (err) + neigh_sysctl_unregister(idev->arp_parms); + return err; } static void devinet_sysctl_unregister(struct in_device *idev) -- cgit v1.2.3 From a317a2f19da7d0af1f068cf4d3ae80cdd73643b7 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 25 Jul 2014 15:25:09 -0700 Subject: ipv6: fail early when creating netdev named all or default We create a proc dir for each network device, this will cause conflicts when the devices have name "all" or "default". Rather than emitting an ugly kernel warning, we could just fail earlier by checking the device name. Reported-by: Stephane Chazelas Cc: "David S. Miller" Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 82 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4c03c2843094..0b239fc1816e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -108,11 +108,12 @@ static inline u32 cstamp_delta(unsigned long cstamp) } #ifdef CONFIG_SYSCTL -static void addrconf_sysctl_register(struct inet6_dev *idev); +static int addrconf_sysctl_register(struct inet6_dev *idev); static void addrconf_sysctl_unregister(struct inet6_dev *idev); #else -static inline void addrconf_sysctl_register(struct inet6_dev *idev) +static inline int addrconf_sysctl_register(struct inet6_dev *idev) { + return 0; } static inline void addrconf_sysctl_unregister(struct inet6_dev *idev) @@ -310,16 +311,16 @@ err_ip: static struct inet6_dev *ipv6_add_dev(struct net_device *dev) { struct inet6_dev *ndev; + int err = -ENOMEM; ASSERT_RTNL(); if (dev->mtu < IPV6_MIN_MTU) - return NULL; + return ERR_PTR(-EINVAL); ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL); - if (ndev == NULL) - return NULL; + return ERR_PTR(err); rwlock_init(&ndev->lock); ndev->dev = dev; @@ -332,7 +333,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); if (ndev->nd_parms == NULL) { kfree(ndev); - return NULL; + return ERR_PTR(err); } if (ndev->cnf.forwarding) dev_disable_lro(dev); @@ -346,17 +347,14 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) neigh_parms_release(&nd_tbl, ndev->nd_parms); dev_put(dev); kfree(ndev); - return NULL; + return ERR_PTR(err); } if (snmp6_register_dev(ndev) < 0) { ADBG(KERN_WARNING "%s: cannot create /proc/net/dev_snmp6/%s\n", __func__, dev->name); - neigh_parms_release(&nd_tbl, ndev->nd_parms); - ndev->dead = 1; - in6_dev_finish_destroy(ndev); - return NULL; + goto err_release; } /* One reference from device. We must do this before @@ -394,7 +392,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) ipv6_mc_init_dev(ndev); ndev->tstamp = jiffies; - addrconf_sysctl_register(ndev); + err = addrconf_sysctl_register(ndev); + if (err) { + ipv6_mc_destroy_dev(ndev); + del_timer(&ndev->regen_timer); + goto err_release; + } /* protected by rtnl_lock */ rcu_assign_pointer(dev->ip6_ptr, ndev); @@ -409,6 +412,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); return ndev; + +err_release: + neigh_parms_release(&nd_tbl, ndev->nd_parms); + ndev->dead = 1; + in6_dev_finish_destroy(ndev); + return ERR_PTR(err); } static struct inet6_dev *ipv6_find_idev(struct net_device *dev) @@ -420,7 +429,7 @@ static struct inet6_dev *ipv6_find_idev(struct net_device *dev) idev = __in6_dev_get(dev); if (!idev) { idev = ipv6_add_dev(dev); - if (!idev) + if (IS_ERR(idev)) return NULL; } @@ -2830,8 +2839,8 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, case NETDEV_REGISTER: if (!idev && dev->mtu >= IPV6_MIN_MTU) { idev = ipv6_add_dev(dev); - if (!idev) - return notifier_from_errno(-ENOMEM); + if (IS_ERR(idev)) + return notifier_from_errno(PTR_ERR(idev)); } break; @@ -2851,7 +2860,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, if (!idev && dev->mtu >= IPV6_MIN_MTU) idev = ipv6_add_dev(dev); - if (idev) { + if (!IS_ERR_OR_NULL(idev)) { idev->if_flags |= IF_READY; run_pending = 1; } @@ -2894,7 +2903,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, break; } - if (idev) { + if (!IS_ERR_OR_NULL(idev)) { if (run_pending) addrconf_dad_run(idev); @@ -2929,7 +2938,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, if (!idev && dev->mtu >= IPV6_MIN_MTU) { idev = ipv6_add_dev(dev); - if (idev) + if (!IS_ERR(idev)) break; } @@ -2950,10 +2959,14 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, if (idev) { snmp6_unregister_dev(idev); addrconf_sysctl_unregister(idev); - addrconf_sysctl_register(idev); - err = snmp6_register_dev(idev); + err = addrconf_sysctl_register(idev); if (err) return notifier_from_errno(err); + err = snmp6_register_dev(idev); + if (err) { + addrconf_sysctl_unregister(idev); + return notifier_from_errno(err); + } } break; @@ -5248,12 +5261,23 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) kfree(t); } -static void addrconf_sysctl_register(struct inet6_dev *idev) +static int addrconf_sysctl_register(struct inet6_dev *idev) { - neigh_sysctl_register(idev->dev, idev->nd_parms, - &ndisc_ifinfo_sysctl_change); - __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, - idev, &idev->cnf); + int err; + + if (!sysctl_dev_name_is_allowed(idev->dev->name)) + return -EINVAL; + + err = neigh_sysctl_register(idev->dev, idev->nd_parms, + &ndisc_ifinfo_sysctl_change); + if (err) + return err; + err = __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, + idev, &idev->cnf); + if (err) + neigh_sysctl_unregister(idev->nd_parms); + + return err; } static void addrconf_sysctl_unregister(struct inet6_dev *idev) @@ -5338,6 +5362,7 @@ static struct rtnl_af_ops inet6_ops = { int __init addrconf_init(void) { + struct inet6_dev *idev; int i, err; err = ipv6_addr_label_init(); @@ -5376,11 +5401,12 @@ int __init addrconf_init(void) * device and it being up should be removed. */ rtnl_lock(); - if (!ipv6_add_dev(init_net.loopback_dev)) - err = -ENOMEM; + idev = ipv6_add_dev(init_net.loopback_dev); rtnl_unlock(); - if (err) + if (IS_ERR(idev)) { + err = PTR_ERR(idev); goto errlo; + } for (i = 0; i < IN6_ADDR_HSIZE; i++) INIT_HLIST_HEAD(&inet6_addr_lst[i]); -- cgit v1.2.3 From 9c5ff24f963919965155cf0c4a2323b22a0c5c84 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 25 Jul 2014 15:25:10 -0700 Subject: vlan: fail early when creating netdev named config Similarly, vlan will create /proc/net/vlan/, so when we create dev with name "config", it will confict with /proc/net/vlan/config. Reported-by: Stephane Chazelas Cc: "David S. Miller" Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/8021q/vlan.c | 21 +++++++++++++-------- net/8021q/vlanproc.c | 2 ++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index cba9c212a730..64c6bed4a3d3 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -325,23 +325,24 @@ static void vlan_transfer_features(struct net_device *dev, netdev_update_features(vlandev); } -static void __vlan_device_event(struct net_device *dev, unsigned long event) +static int __vlan_device_event(struct net_device *dev, unsigned long event) { + int err = 0; + switch (event) { case NETDEV_CHANGENAME: vlan_proc_rem_dev(dev); - if (vlan_proc_add_dev(dev) < 0) - pr_warn("failed to change proc name for %s\n", - dev->name); + err = vlan_proc_add_dev(dev); break; case NETDEV_REGISTER: - if (vlan_proc_add_dev(dev) < 0) - pr_warn("failed to add proc entry for %s\n", dev->name); + err = vlan_proc_add_dev(dev); break; case NETDEV_UNREGISTER: vlan_proc_rem_dev(dev); break; } + + return err; } static int vlan_device_event(struct notifier_block *unused, unsigned long event, @@ -356,8 +357,12 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, bool last = false; LIST_HEAD(list); - if (is_vlan_dev(dev)) - __vlan_device_event(dev, event); + if (is_vlan_dev(dev)) { + int err = __vlan_device_event(dev, event); + + if (err) + return notifier_from_errno(err); + } if ((event == NETDEV_UP) && (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) { diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 1d0e89213a28..ae63cf72a953 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -171,6 +171,8 @@ int vlan_proc_add_dev(struct net_device *vlandev) struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id); + if (!strcmp(vlandev->name, name_conf)) + return -EINVAL; vlan->dent = proc_create_data(vlandev->name, S_IFREG|S_IRUSR|S_IWUSR, vn->proc_vlan_dir, &vlandev_fops, vlandev); -- cgit v1.2.3 From 4984c23735132790e8f2dfdd35849dba3bd7264f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 27 Jul 2014 03:14:39 +0100 Subject: sfc: Use __iowrite64_copy instead of a slightly different local function __iowrite64_copy() isn't quite the same as efx_memcpy_64(), but it looks close enough: - The length is in units of qwords not bytes - It never byte-swaps, but that doesn't make a difference now as PIO is only enabled for x86_64 - It doesn't include any memory barriers, but that's OK as there is a barrier just before pushing the doorbell - mlx4_en uses it for the same purpose Compile-tested only. Signed-off-by: Ben Hutchings Acked-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/tx.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index 283e5f87b09f..65c220f8661d 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -189,18 +189,6 @@ struct efx_short_copy_buffer { u8 buf[L1_CACHE_BYTES]; }; -/* Copy in explicit 64-bit writes. */ -static void efx_memcpy_64(void __iomem *dest, void *src, size_t len) -{ - u64 *src64 = src; - u64 __iomem *dest64 = dest; - size_t l64 = len / 8; - size_t i; - - for (i = 0; i < l64; i++) - writeq(src64[i], &dest64[i]); -} - /* Copy to PIO, respecting that writes to PIO buffers must be dword aligned. * Advances piobuf pointer. Leaves additional data in the copy buffer. */ @@ -210,7 +198,7 @@ static void efx_memcpy_toio_aligned(struct efx_nic *efx, u8 __iomem **piobuf, { int block_len = len & ~(sizeof(copy_buf->buf) - 1); - efx_memcpy_64(*piobuf, data, block_len); + __iowrite64_copy(*piobuf, data, block_len >> 3); *piobuf += block_len; len -= block_len; @@ -242,7 +230,8 @@ static void efx_memcpy_toio_aligned_cb(struct efx_nic *efx, u8 __iomem **piobuf, if (copy_buf->used < sizeof(copy_buf->buf)) return; - efx_memcpy_64(*piobuf, copy_buf->buf, sizeof(copy_buf->buf)); + __iowrite64_copy(*piobuf, copy_buf->buf, + sizeof(copy_buf->buf) >> 3); *piobuf += sizeof(copy_buf->buf); data += copy_to_buf; len -= copy_to_buf; @@ -257,7 +246,8 @@ static void efx_flush_copy_buffer(struct efx_nic *efx, u8 __iomem *piobuf, { /* if there's anything in it, write the whole buffer, including junk */ if (copy_buf->used) - efx_memcpy_64(piobuf, copy_buf->buf, sizeof(copy_buf->buf)); + __iowrite64_copy(piobuf, copy_buf->buf, + sizeof(copy_buf->buf) >> 3); } /* Traverse skb structure and copy fragments in to PIO buffer. @@ -316,8 +306,8 @@ efx_enqueue_skb_pio(struct efx_tx_queue *tx_queue, struct sk_buff *skb) */ BUILD_BUG_ON(L1_CACHE_BYTES > SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); - efx_memcpy_64(tx_queue->piobuf, skb->data, - ALIGN(skb->len, L1_CACHE_BYTES)); + __iowrite64_copy(tx_queue->piobuf, skb->data, + ALIGN(skb->len, L1_CACHE_BYTES) >> 3); } EFX_POPULATE_QWORD_5(buffer->option, -- cgit v1.2.3 From 5a8dbf03ddf6dfe465b9f062e5b969f9606643f5 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sun, 27 Jul 2014 12:36:51 +0530 Subject: net/ipv4: Use IS_ERR_OR_NULL This patch introduces the use of the macro IS_ERR_OR_NULL in place of tests for NULL and IS_ERR. The following Coccinelle semantic patch was used for making the change: @@ expression e; @@ - e == NULL || IS_ERR(e) + IS_ERR_OR_NULL(e) || ... Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- net/ipv4/gre_offload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index f0bdd47bbbcb..6556263c8fa5 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c @@ -74,7 +74,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, /* segment inner packet. */ enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); segs = skb_mac_gso_segment(skb, enc_features); - if (!segs || IS_ERR(segs)) { + if (IS_ERR_OR_NULL(segs)) { skb_gso_error_unwind(skb, protocol, ghl, mac_offset, mac_len); goto out; } -- cgit v1.2.3 From d0e992aa0270663872c56f07473a7f43adee5bd5 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sun, 27 Jul 2014 12:37:46 +0530 Subject: openvswitch: Use IS_ERR_OR_NULL This patch introduces the use of the macro IS_ERR_OR_NULL in place of tests for NULL and IS_ERR. The following Coccinelle semantic patch was used for making the change: @@ expression e; @@ - e == NULL || IS_ERR(e) + IS_ERR_OR_NULL(e) || ... Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/datapath.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 3c461e1e4554..7ad3f029baae 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -781,7 +781,7 @@ static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow, skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), info, always); - if (!skb || IS_ERR(skb)) + if (IS_ERR_OR_NULL(skb)) return skb; retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb, -- cgit v1.2.3 From 27446442a810f29d0fa97356bbc11f45e7ecfa6e Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sun, 27 Jul 2014 12:38:38 +0530 Subject: net/udp_offload: Use IS_ERR_OR_NULL This patch introduces the use of the macro IS_ERR_OR_NULL in place of tests for NULL and IS_ERR. The following Coccinelle semantic patch was used for making the change: @@ expression e; @@ - e == NULL || IS_ERR(e) + IS_ERR_OR_NULL(e) || ... Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- net/ipv4/udp_offload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 4807544d018b..59035bc3008d 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -79,7 +79,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, /* segment inner packet. */ enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); segs = skb_mac_gso_segment(skb, enc_features); - if (!segs || IS_ERR(segs)) { + if (IS_ERR_OR_NULL(segs)) { skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset, mac_len); goto out; -- cgit v1.2.3 From ad025a56a5487d5d443ee790c04517581d39b21b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 28 Jul 2014 21:30:14 +0800 Subject: tipc: remove duplicated include from socket.c Remove duplicated include. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/tipc/socket.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 8477d08a6aa0..7d423ee10897 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -40,7 +40,6 @@ #include "node.h" #include "link.h" #include -#include "link.h" #define SS_LISTENING -1 /* socket is listening */ #define SS_READY -2 /* socket is connectionless */ -- cgit v1.2.3 From c54a5e024777a2fd4b01239d58cf119901e8e5ed Mon Sep 17 00:00:00 2001 From: Karoly Kemeny Date: Sun, 27 Jul 2014 12:29:07 +0200 Subject: ipv4: clean up cast warning in do_ip_getsockopt Sparse warns because of implicit pointer cast. v2: subject line correction, space between "void" and "*" Signed-off-by: Karoly Kemeny Signed-off-by: David S. Miller --- net/ipv4/ip_sockglue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 64741b938632..5cb830c78990 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -1319,7 +1319,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, if (sk->sk_type != SOCK_STREAM) return -ENOPROTOOPT; - msg.msg_control = optval; + msg.msg_control = (__force void *) optval; msg.msg_controllen = len; msg.msg_flags = flags; -- cgit v1.2.3 From 2add511e58dc822a4573dd35280750fb3a21a2db Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Sun, 27 Jul 2014 23:21:35 +0200 Subject: net: mvpp2: fix 10 Mbit/s usage This commit is similar to commit 4d12bc63ab5e ("net: mvneta: fix operation in 10 Mbit/s mode"), but this time for the mvpp2 driver. The driver was properly taking into account the 1 Gbit/s and 100 Mbit/s speeds, but not the 10 Mbit/s, which was handled as 100 Mbit/s. However, the MVPP2_GMAC_CONFIG_MII_SPEED bit in the MVPP2_GMAC_AUTONEG_CONFIG register must remain cleared to allow 10 Mbit/s operation. This commit therefore fixes 10 Mbit/s operation. Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 3193a7de7197..3cae3d2abe7e 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -4842,7 +4842,7 @@ static void mvpp2_link_event(struct net_device *dev) if (phydev->speed == SPEED_1000) val |= MVPP2_GMAC_CONFIG_GMII_SPEED; - else + else if (phydev->speed == SPEED_100) val |= MVPP2_GMAC_CONFIG_MII_SPEED; writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG); -- cgit v1.2.3 From bd695a5f0ccf7b38982c426d86055ff3591c9b5b Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Sun, 27 Jul 2014 23:21:36 +0200 Subject: net: mvpp2: implement ioctl() operation for PHY ioctls This commit implements the ->ndo_do_ioctl() operation so that the PHY-related ioctl() calls can work from userspace, which allows applications like mii-tool or mii-diag to do their job. Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 3cae3d2abe7e..ece83f101526 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -5714,6 +5714,21 @@ mvpp2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) return stats; } +static int mvpp2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct mvpp2_port *port = netdev_priv(dev); + int ret; + + if (!port->phy_dev) + return -ENOTSUPP; + + ret = phy_mii_ioctl(port->phy_dev, ifr, cmd); + if (!ret) + mvpp2_link_event(dev); + + return ret; +} + /* Ethtool methods */ /* Get settings (phy address, speed) for ethtools */ @@ -5868,6 +5883,7 @@ static const struct net_device_ops mvpp2_netdev_ops = { .ndo_set_mac_address = mvpp2_set_mac_address, .ndo_change_mtu = mvpp2_change_mtu, .ndo_get_stats64 = mvpp2_get_stats64, + .ndo_do_ioctl = mvpp2_ioctl, }; static const struct ethtool_ops mvpp2_eth_tool_ops = { -- cgit v1.2.3 From d24675cb1fb0f4f5b44ce4ed9cf5c17caf0efa6b Mon Sep 17 00:00:00 2001 From: Alexey Perevalov Date: Wed, 30 Jul 2014 19:17:55 +0400 Subject: netfilter: nfnetlink_acct: dump unmodified nfacct flags NFNL_MSG_ACCT_GET_CTRZERO modifies dumped flags, in this case client see unmodified (uncleared) counter value and cleared overquota state - end user doesn't know anything about overquota state, unless end user subscribed on overquota report. Signed-off-by: Alexey Perevalov Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nfnetlink_acct.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c index 2baa125c2e8d..11d863c8b11f 100644 --- a/net/netfilter/nfnetlink_acct.c +++ b/net/netfilter/nfnetlink_acct.c @@ -129,6 +129,7 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, struct nfgenmsg *nfmsg; unsigned int flags = portid ? NLM_F_MULTI : 0; u64 pkts, bytes; + u32 old_flags; event |= NFNL_SUBSYS_ACCT << 8; nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); @@ -143,6 +144,7 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, if (nla_put_string(skb, NFACCT_NAME, acct->name)) goto nla_put_failure; + old_flags = acct->flags; if (type == NFNL_MSG_ACCT_GET_CTRZERO) { pkts = atomic64_xchg(&acct->pkts, 0); bytes = atomic64_xchg(&acct->bytes, 0); @@ -160,7 +162,7 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, if (acct->flags & NFACCT_F_QUOTA) { u64 *quota = (u64 *)acct->data; - if (nla_put_be32(skb, NFACCT_FLAGS, htonl(acct->flags)) || + if (nla_put_be32(skb, NFACCT_FLAGS, htonl(old_flags)) || nla_put_be64(skb, NFACCT_QUOTA, cpu_to_be64(*quota))) goto nla_put_failure; } -- cgit v1.2.3 From 616d55be4c754dc7e1e1b7df59fb6cc5aee19ddd Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 29 Jul 2014 14:18:48 +0300 Subject: Bluetooth: Fix SMP context tracking leading to a kernel crash The HCI_CONN_LE_SMP_PEND flag is supposed to indicate whether we have an SMP context or not. If the context creation fails, or some other error is indicated between setting the flag and creating the context the flag must be cleared first. This patch ensures that smp_chan_create() clears the flag in case of allocation failure as well as reorders code in smp_cmd_security_req() that could lead to returning an error between setting the flag and creating the context. Without the patch the following kind of kernel crash could be observed (this one because of unacceptable authentication requirements in a Security Request): [ +0.000855] kernel BUG at net/bluetooth/smp.c:606! [ +0.000000] invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC [ +0.000000] CPU: 0 PID: 58 Comm: kworker/u5:2 Tainted: G W 3.16.0-rc1+ #785 [ +0.008391] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ +0.000000] Workqueue: hci0 hci_rx_work [ +0.000000] task: f4dc8f90 ti: f4ef0000 task.ti: f4ef0000 [ +0.000000] EIP: 0060:[] EFLAGS: 00010246 CPU: 0 [ +0.000000] EIP is at smp_chan_destroy+0x1e/0x145 [ +0.000709] EAX: f46db870 EBX: 00000000 ECX: 00000000 EDX: 00000005 [ +0.000000] ESI: f46db870 EDI: f46db870 EBP: f4ef1dc0 ESP: f4ef1db0 [ +0.000000] DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 [ +0.000000] CR0: 8005003b CR2: b666b0b0 CR3: 00022000 CR4: 00000690 [ +0.000000] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 [ +0.000000] DR6: fffe0ff0 DR7: 00000400 [ +0.000000] Stack: [ +0.000000] 00000005 f17b7840 f46db870 f4ef1dd4 f4ef1de4 c1343441 c134342e 00000000 [ +0.000000] c1343441 00000005 00000002 00000000 f17b7840 f4ef1e38 c134452a 00002aae [ +0.000000] 01ef1e00 00002aae f46bd980 f46db870 00000039 ffffffff 00000007 f4ef1e34 [ +0.000000] Call Trace: [ +0.000000] [] smp_failure+0x64/0x6c [ +0.000000] [] ? smp_failure+0x51/0x6c [ +0.000000] [] ? smp_failure+0x64/0x6c [ +0.000000] [] smp_sig_channel+0xad6/0xafc [ +0.000000] [] ? vprintk_emit+0x343/0x366 [ +0.000000] [] l2cap_recv_frame+0x1337/0x1ac4 [ +0.000000] [] ? l2cap_recv_frame+0x1337/0x1ac4 [ +0.000000] [] ? __dynamic_pr_debug+0x3e/0x40 [ +0.000000] [] ? debug_smp_processor_id+0x12/0x14 [ +0.000000] [] l2cap_recv_acldata+0xe8/0x239 [ +0.000000] [] ? l2cap_recv_acldata+0xe8/0x239 [ +0.000000] [] ? __const_udelay+0x1a/0x1c [ +0.000000] [] hci_rx_work+0x1a1/0x286 [ +0.000000] [] ? mutex_unlock+0x8/0xa [ +0.000000] [] ? hci_rx_work+0x1a1/0x286 [ +0.000000] [] process_one_work+0x128/0x1df [ +0.000000] [] ? process_one_work+0x128/0x1df [ +0.000000] [] worker_thread+0x222/0x2de [ +0.000000] [] ? process_scheduled_works+0x21/0x21 [ +0.000000] [] kthread+0x82/0x87 [ +0.000000] [] ? create_new_namespaces+0x90/0x105 [ +0.000000] [] ret_from_kernel_thread+0x21/0x30 [ +0.000000] [] ? __kthread_parkme+0x50/0x50 [ +0.000000] Code: 65 f4 89 f0 5b 5e 5f 5d 8d 67 f8 5f c3 57 8d 7c 24 08 83 e4 f8 ff 77 fc 55 89 e5 57 89 c7 56 53 52 8b 98 e0 00 00 00 85 db 75 02 <0f> 0b 8b b3 80 00 00 00 8b 00 c1 ee 03 83 e6 01 89 f2 e8 ef 09 [ +0.000000] EIP: [] smp_chan_destroy+0x1e/0x145 SS:ESP 0068:f4ef1db0 Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index a7c344b4acbc..eaa8e7482bb4 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -579,13 +579,16 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) struct smp_chan *smp; smp = kzalloc(sizeof(*smp), GFP_ATOMIC); - if (!smp) + if (!smp) { + clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); return NULL; + } smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(smp->tfm_aes)) { BT_ERR("Unable to create ECB crypto context"); kfree(smp); + clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); return NULL; } @@ -923,14 +926,14 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; - if (!test_bit(HCI_PAIRABLE, &hcon->hdev->dev_flags) && - (rp->auth_req & SMP_AUTH_BONDING)) - return SMP_PAIRING_NOTSUPP; - smp = smp_chan_create(conn); if (!smp) return SMP_UNSPECIFIED; + if (!test_bit(HCI_PAIRABLE, &hcon->hdev->dev_flags) && + (rp->auth_req & SMP_AUTH_BONDING)) + return SMP_PAIRING_NOTSUPP; + skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); -- cgit v1.2.3 From 84ca5e036f41bb2d08accbd3cfd293f0bd955573 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 29 Jul 2014 23:46:58 +0200 Subject: 6lowpan: iphc: rename hc06_ptr pointer to hc_ptr The hc06_ptr pointer variable stands for header compression draft-06. We are mostly rfc complaint. This patch rename the variable to normal hc_ptr. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/6lowpan/iphc.c | 112 ++++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index 211b5686d719..a13eae52e590 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -515,9 +515,9 @@ drop: } EXPORT_SYMBOL_GPL(lowpan_process_data); -static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, - const struct in6_addr *ipaddr, - const unsigned char *lladdr) +static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift, + const struct in6_addr *ipaddr, + const unsigned char *lladdr) { u8 val = 0; @@ -526,24 +526,24 @@ static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, pr_debug("address compression 0 bits\n"); } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { /* compress IID to 16 bits xxxx::XXXX */ - memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2); - *hc06_ptr += 2; + memcpy(*hc_ptr, &ipaddr->s6_addr16[7], 2); + *hc_ptr += 2; val = 2; /* 16-bits */ raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", - *hc06_ptr - 2, 2); + *hc_ptr - 2, 2); } else { /* do not compress IID => xxxx::IID */ - memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8); - *hc06_ptr += 8; + memcpy(*hc_ptr, &ipaddr->s6_addr16[4], 8); + *hc_ptr += 8; val = 1; /* 64-bits */ raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", - *hc06_ptr - 8, 8); + *hc_ptr - 8, 8); } return rol8(val, shift); } -static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) +static void compress_udp_header(u8 **hc_ptr, struct sk_buff *skb) { struct udphdr *uh = udp_hdr(skb); u8 tmp; @@ -555,46 +555,46 @@ static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) pr_debug("UDP header: both ports compression to 4 bits\n"); /* compression value */ tmp = LOWPAN_NHC_UDP_CS_P_11; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); /* source and destination port */ tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT + ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4); - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) == LOWPAN_NHC_UDP_8BIT_PORT) { pr_debug("UDP header: remove 8 bits of dest\n"); /* compression value */ tmp = LOWPAN_NHC_UDP_CS_P_01; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); /* source port */ - lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); + lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source)); /* destination port */ tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) == LOWPAN_NHC_UDP_8BIT_PORT) { pr_debug("UDP header: remove 8 bits of source\n"); /* compression value */ tmp = LOWPAN_NHC_UDP_CS_P_10; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); /* source port */ tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); /* destination port */ - lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); + lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest)); } else { pr_debug("UDP header: can't compress\n"); /* compression value */ tmp = LOWPAN_NHC_UDP_CS_P_00; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp)); /* source port */ - lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); + lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source)); /* destination port */ - lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); + lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest)); } /* checksum is always inline */ - lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check)); + lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check)); /* skip the UDP header */ skb_pull(skb, sizeof(struct udphdr)); @@ -604,7 +604,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *_daddr, const void *_saddr, unsigned int len) { - u8 tmp, iphc0, iphc1, *hc06_ptr; + u8 tmp, iphc0, iphc1, *hc_ptr; struct ipv6hdr *hdr; u8 head[100] = {}; @@ -612,7 +612,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, return -EINVAL; hdr = ipv6_hdr(skb); - hc06_ptr = head + 2; + hc_ptr = head + 2; pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", @@ -649,7 +649,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, * class depends on the presence of version and flow label */ - /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */ + /* hc format of TC is ECN | DSCP , original one is DSCP | ECN */ tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4); tmp = ((tmp & 0x03) << 6) | (tmp >> 2); @@ -663,8 +663,8 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, iphc0 |= LOWPAN_IPHC_TC_C; } else { /* compress only the flow label */ - *hc06_ptr = tmp; - hc06_ptr += 1; + *hc_ptr = tmp; + hc_ptr += 1; } } else { /* Flow label cannot be compressed */ @@ -672,15 +672,15 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, ((hdr->flow_lbl[0] & 0xF0) == 0)) { /* compress only traffic class */ iphc0 |= LOWPAN_IPHC_TC_C; - *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); - memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2); - hc06_ptr += 3; + *hc_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); + memcpy(hc_ptr + 1, &hdr->flow_lbl[1], 2); + hc_ptr += 3; } else { /* compress nothing */ - memcpy(hc06_ptr, hdr, 4); + memcpy(hc_ptr, hdr, 4); /* replace the top byte with new ECN | DSCP format */ - *hc06_ptr = tmp; - hc06_ptr += 4; + *hc_ptr = tmp; + hc_ptr += 4; } } @@ -691,8 +691,8 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, iphc0 |= LOWPAN_IPHC_NH_C; if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { - *hc06_ptr = hdr->nexthdr; - hc06_ptr += 1; + *hc_ptr = hdr->nexthdr; + hc_ptr += 1; } /* @@ -713,8 +713,8 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, iphc0 |= LOWPAN_IPHC_TTL_255; break; default: - *hc06_ptr = hdr->hop_limit; - hc06_ptr += 1; + *hc_ptr = hdr->hop_limit; + hc_ptr += 1; break; } @@ -724,14 +724,14 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, iphc1 |= LOWPAN_IPHC_SAC; /* TODO: context lookup */ } else if (is_addr_link_local(&hdr->saddr)) { - iphc1 |= lowpan_compress_addr_64(&hc06_ptr, + iphc1 |= lowpan_compress_addr_64(&hc_ptr, LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr); pr_debug("source address unicast link-local %pI6c " "iphc1 0x%02x\n", &hdr->saddr, iphc1); } else { pr_debug("send the full source address\n"); - memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16); - hc06_ptr += 16; + memcpy(hc_ptr, &hdr->saddr.s6_addr16[0], 16); + hc_ptr += 16; } /* destination address compression */ @@ -742,55 +742,55 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, pr_debug("compressed to 1 octet\n"); iphc1 |= LOWPAN_IPHC_DAM_11; /* use last byte */ - *hc06_ptr = hdr->daddr.s6_addr[15]; - hc06_ptr += 1; + *hc_ptr = hdr->daddr.s6_addr[15]; + hc_ptr += 1; } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { pr_debug("compressed to 4 octets\n"); iphc1 |= LOWPAN_IPHC_DAM_10; /* second byte + the last three */ - *hc06_ptr = hdr->daddr.s6_addr[1]; - memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3); - hc06_ptr += 4; + *hc_ptr = hdr->daddr.s6_addr[1]; + memcpy(hc_ptr + 1, &hdr->daddr.s6_addr[13], 3); + hc_ptr += 4; } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { pr_debug("compressed to 6 octets\n"); iphc1 |= LOWPAN_IPHC_DAM_01; /* second byte + the last five */ - *hc06_ptr = hdr->daddr.s6_addr[1]; - memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5); - hc06_ptr += 6; + *hc_ptr = hdr->daddr.s6_addr[1]; + memcpy(hc_ptr + 1, &hdr->daddr.s6_addr[11], 5); + hc_ptr += 6; } else { pr_debug("using full address\n"); iphc1 |= LOWPAN_IPHC_DAM_00; - memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16); - hc06_ptr += 16; + memcpy(hc_ptr, &hdr->daddr.s6_addr[0], 16); + hc_ptr += 16; } } else { /* TODO: context lookup */ if (is_addr_link_local(&hdr->daddr)) { - iphc1 |= lowpan_compress_addr_64(&hc06_ptr, + iphc1 |= lowpan_compress_addr_64(&hc_ptr, LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr); pr_debug("dest address unicast link-local %pI6c " "iphc1 0x%02x\n", &hdr->daddr, iphc1); } else { pr_debug("dest address unicast %pI6c\n", &hdr->daddr); - memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16); - hc06_ptr += 16; + memcpy(hc_ptr, &hdr->daddr.s6_addr16[0], 16); + hc_ptr += 16; } } /* UDP header compression */ if (hdr->nexthdr == UIP_PROTO_UDP) - compress_udp_header(&hc06_ptr, skb); + compress_udp_header(&hc_ptr, skb); head[0] = iphc0; head[1] = iphc1; skb_pull(skb, sizeof(struct ipv6hdr)); skb_reset_transport_header(skb); - memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); + memcpy(skb_push(skb, hc_ptr - head), head, hc_ptr - head); skb_reset_network_header(skb); - pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len); + pr_debug("header len %d skb %u\n", (int)(hc_ptr - head), skb->len); raw_dump_table(__func__, "raw skb data dump compressed", skb->data, skb->len); -- cgit v1.2.3 From 8ec1d9be323388550b3eb4390c23217ea0711013 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 29 Jul 2014 23:46:59 +0200 Subject: 6lowpan: iphc: use sizeof in udp uncompression Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/6lowpan/iphc.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index a13eae52e590..d2654d46e0c1 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -271,27 +271,31 @@ uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) if (!uh) goto err; - fail = lowpan_fetch_skb(skb, &tmp, 1); + fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp)); if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { pr_debug("UDP header uncompression\n"); switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { case LOWPAN_NHC_UDP_CS_P_00: - fail |= lowpan_fetch_skb(skb, &uh->source, 2); - fail |= lowpan_fetch_skb(skb, &uh->dest, 2); + fail |= lowpan_fetch_skb(skb, &uh->source, + sizeof(uh->source)); + fail |= lowpan_fetch_skb(skb, &uh->dest, + sizeof(uh->dest)); break; case LOWPAN_NHC_UDP_CS_P_01: - fail |= lowpan_fetch_skb(skb, &uh->source, 2); - fail |= lowpan_fetch_skb(skb, &val, 1); + fail |= lowpan_fetch_skb(skb, &uh->source, + sizeof(uh->source)); + fail |= lowpan_fetch_skb(skb, &val, sizeof(val)); uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); break; case LOWPAN_NHC_UDP_CS_P_10: - fail |= lowpan_fetch_skb(skb, &val, 1); + fail |= lowpan_fetch_skb(skb, &val, sizeof(val)); uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); - fail |= lowpan_fetch_skb(skb, &uh->dest, 2); + fail |= lowpan_fetch_skb(skb, &uh->dest, + sizeof(uh->dest)); break; case LOWPAN_NHC_UDP_CS_P_11: - fail |= lowpan_fetch_skb(skb, &val, 1); + fail |= lowpan_fetch_skb(skb, &val, sizeof(val)); uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT + (val >> 4)); uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT + @@ -311,7 +315,8 @@ uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) pr_debug_ratelimited("checksum elided currently not supported\n"); goto err; } else { - fail |= lowpan_fetch_skb(skb, &uh->check, 2); + fail |= lowpan_fetch_skb(skb, &uh->check, + sizeof(uh->check)); } /* -- cgit v1.2.3 From 4ebc960f9453d2610d150bef4fc9ca227bd33e22 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 29 Jul 2014 23:47:00 +0200 Subject: 6lowpan: iphc: cleanup use of lowpan_fetch_skb We introduced the lowpan_fetch_skb function in some previous patches for 6lowpan to have a generic fetch function. This patch drops the old function and use the generic lowpan_fetch_skb one. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/6lowpan/iphc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index d2654d46e0c1..0376684f28d0 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -357,7 +357,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, /* another if the CID flag is set */ if (iphc1 & LOWPAN_IPHC_CID) { pr_debug("CID flag is set, increase header with one\n"); - if (lowpan_fetch_skb_u8(skb, &num_context)) + if (lowpan_fetch_skb(skb, &num_context, sizeof(num_context))) goto drop; } @@ -370,7 +370,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) */ case 0: /* 00b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) + if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) goto drop; memcpy(&hdr.flow_lbl, &skb->data[0], 3); @@ -384,7 +384,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, * ECN + DSCP (1 byte), Flow Label is elided */ case 2: /* 10b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) + if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) goto drop; hdr.priority = ((tmp >> 2) & 0x0f); @@ -395,7 +395,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided */ case 1: /* 01b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) + if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) goto drop; hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); @@ -412,7 +412,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, /* Next Header */ if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { /* Next header is carried inline */ - if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr))) + if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr))) goto drop; pr_debug("NH flag is set, next header carried inline: %02x\n", @@ -423,7 +423,8 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; else { - if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit))) + if (lowpan_fetch_skb(skb, &hdr.hop_limit, + sizeof(hdr.hop_limit))) goto drop; } -- cgit v1.2.3 From 85c71240a3e6c151038d9ed3fa88fc0fb80043fb Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 29 Jul 2014 23:47:01 +0200 Subject: 6lowpan: iphc: cleanup use of lowpan_push_hc_data This patch uses the lowpan_push_hc_data functions in several places where we can use it. The lowpan_push_hc_data was introduced in some previous patches. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/6lowpan/iphc.c | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index 0376684f28d0..636edd0f3724 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -532,15 +532,13 @@ static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift, pr_debug("address compression 0 bits\n"); } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { /* compress IID to 16 bits xxxx::XXXX */ - memcpy(*hc_ptr, &ipaddr->s6_addr16[7], 2); - *hc_ptr += 2; + lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2); val = 2; /* 16-bits */ raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", *hc_ptr - 2, 2); } else { /* do not compress IID => xxxx::IID */ - memcpy(*hc_ptr, &ipaddr->s6_addr16[4], 8); - *hc_ptr += 8; + lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8); val = 1; /* 64-bits */ raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", *hc_ptr - 8, 8); @@ -696,10 +694,9 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, if (hdr->nexthdr == UIP_PROTO_UDP) iphc0 |= LOWPAN_IPHC_NH_C; - if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { - *hc_ptr = hdr->nexthdr; - hc_ptr += 1; - } + if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) + lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr, + sizeof(hdr->nexthdr)); /* * Hop limit @@ -719,9 +716,8 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, iphc0 |= LOWPAN_IPHC_TTL_255; break; default: - *hc_ptr = hdr->hop_limit; - hc_ptr += 1; - break; + lowpan_push_hc_data(&hc_ptr, &hdr->hop_limit, + sizeof(hdr->hop_limit)); } /* source address compression */ @@ -736,8 +732,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, "iphc1 0x%02x\n", &hdr->saddr, iphc1); } else { pr_debug("send the full source address\n"); - memcpy(hc_ptr, &hdr->saddr.s6_addr16[0], 16); - hc_ptr += 16; + lowpan_push_hc_data(&hc_ptr, &hdr->saddr.s6_addr[0], 16); } /* destination address compression */ @@ -748,27 +743,28 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, pr_debug("compressed to 1 octet\n"); iphc1 |= LOWPAN_IPHC_DAM_11; /* use last byte */ - *hc_ptr = hdr->daddr.s6_addr[15]; - hc_ptr += 1; + lowpan_push_hc_data(&hc_ptr, + &hdr->daddr.s6_addr[15], 1); } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { pr_debug("compressed to 4 octets\n"); iphc1 |= LOWPAN_IPHC_DAM_10; /* second byte + the last three */ - *hc_ptr = hdr->daddr.s6_addr[1]; - memcpy(hc_ptr + 1, &hdr->daddr.s6_addr[13], 3); - hc_ptr += 4; + lowpan_push_hc_data(&hc_ptr, + &hdr->daddr.s6_addr[1], 1); + lowpan_push_hc_data(&hc_ptr, + &hdr->daddr.s6_addr[13], 3); } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { pr_debug("compressed to 6 octets\n"); iphc1 |= LOWPAN_IPHC_DAM_01; /* second byte + the last five */ - *hc_ptr = hdr->daddr.s6_addr[1]; - memcpy(hc_ptr + 1, &hdr->daddr.s6_addr[11], 5); - hc_ptr += 6; + lowpan_push_hc_data(&hc_ptr, + &hdr->daddr.s6_addr[1], 1); + lowpan_push_hc_data(&hc_ptr, + &hdr->daddr.s6_addr[11], 5); } else { pr_debug("using full address\n"); iphc1 |= LOWPAN_IPHC_DAM_00; - memcpy(hc_ptr, &hdr->daddr.s6_addr[0], 16); - hc_ptr += 16; + lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16); } } else { /* TODO: context lookup */ @@ -779,8 +775,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, "iphc1 0x%02x\n", &hdr->daddr, iphc1); } else { pr_debug("dest address unicast %pI6c\n", &hdr->daddr); - memcpy(hc_ptr, &hdr->daddr.s6_addr16[0], 16); - hc_ptr += 16; + lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16); } } -- cgit v1.2.3 From 556a5bfc03c35c6f0b4e85ef6a19d00f0eb6dd00 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 29 Jul 2014 23:47:02 +0200 Subject: 6lowpan: iphc: use ipv6 api to check address scope This patch removes the own implementation to check of link-layer, broadcast and any address type and use the IPv6 api for that. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/6lowpan.h | 13 ------------- net/6lowpan/iphc.c | 29 +++++++++++++++++------------ 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h index 79b530fb2c4d..18010bce68c8 100644 --- a/include/net/6lowpan.h +++ b/include/net/6lowpan.h @@ -75,20 +75,10 @@ (((a)->s6_addr[14]) == (m)[6]) && \ (((a)->s6_addr[15]) == (m)[7])) -/* ipv6 address is unspecified */ -#define is_addr_unspecified(a) \ - ((((a)->s6_addr32[0]) == 0) && \ - (((a)->s6_addr32[1]) == 0) && \ - (((a)->s6_addr32[2]) == 0) && \ - (((a)->s6_addr32[3]) == 0)) - /* compare ipv6 addresses prefixes */ #define ipaddr_prefixcmp(addr1, addr2, length) \ (memcmp(addr1, addr2, length >> 3) == 0) -/* local link, i.e. FE80::/10 */ -#define is_addr_link_local(a) (((a)->s6_addr16[0]) == htons(0xFE80)) - /* * check whether we can compress the IID to 16 bits, * it's possible for unicast adresses with first 49 bits are zero only. @@ -100,9 +90,6 @@ (((a)->s6_addr[12]) == 0xfe) && \ (((a)->s6_addr[13]) == 0)) -/* multicast address */ -#define is_addr_mcast(a) (((a)->s6_addr[0]) == 0xFF) - /* check whether the 112-bit gid of the multicast address is mappable to: */ /* 9 bits, for FF02::1 (all nodes) and FF02::2 (all routers) addresses only. */ diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index 636edd0f3724..d4fc2dd8ad75 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -611,6 +611,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, u8 tmp, iphc0, iphc1, *hc_ptr; struct ipv6hdr *hdr; u8 head[100] = {}; + int addr_type; if (type != ETH_P_IPV6) return -EINVAL; @@ -720,23 +721,27 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, sizeof(hdr->hop_limit)); } + addr_type = ipv6_addr_type(&hdr->saddr); /* source address compression */ - if (is_addr_unspecified(&hdr->saddr)) { + if (addr_type == IPV6_ADDR_ANY) { pr_debug("source address is unspecified, setting SAC\n"); iphc1 |= LOWPAN_IPHC_SAC; - /* TODO: context lookup */ - } else if (is_addr_link_local(&hdr->saddr)) { - iphc1 |= lowpan_compress_addr_64(&hc_ptr, - LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr); - pr_debug("source address unicast link-local %pI6c " - "iphc1 0x%02x\n", &hdr->saddr, iphc1); } else { - pr_debug("send the full source address\n"); - lowpan_push_hc_data(&hc_ptr, &hdr->saddr.s6_addr[0], 16); + if (addr_type & IPV6_ADDR_LINKLOCAL) { + iphc1 |= lowpan_compress_addr_64(&hc_ptr, + LOWPAN_IPHC_SAM_BIT, + &hdr->saddr, _saddr); + pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n", + &hdr->saddr, iphc1); + } else { + pr_debug("send the full source address\n"); + lowpan_push_hc_data(&hc_ptr, hdr->saddr.s6_addr, 16); + } } + addr_type = ipv6_addr_type(&hdr->daddr); /* destination address compression */ - if (is_addr_mcast(&hdr->daddr)) { + if (addr_type & IPV6_ADDR_MULTICAST) { pr_debug("destination address is multicast: "); iphc1 |= LOWPAN_IPHC_M; if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) { @@ -767,8 +772,8 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16); } } else { - /* TODO: context lookup */ - if (is_addr_link_local(&hdr->daddr)) { + if (addr_type & IPV6_ADDR_LINKLOCAL) { + /* TODO: context lookup */ iphc1 |= lowpan_compress_addr_64(&hc_ptr, LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr); pr_debug("dest address unicast link-local %pI6c " -- cgit v1.2.3 From b2e3a479a6ae937b32aa0a8fffc541e4e7778734 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 29 Jul 2014 23:47:03 +0200 Subject: 6lowpan: iphc: remove check on null This memory is placed on stack and can't be null so remove the check on null. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/6lowpan/iphc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index d4fc2dd8ad75..de78deb49959 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -268,9 +268,6 @@ uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) bool fail; u8 tmp = 0, val = 0; - if (!uh) - goto err; - fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp)); if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { -- cgit v1.2.3 From 004942445da78b6fd250dc933c5d7859fde8fb1f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 29 Jul 2014 23:47:04 +0200 Subject: 6lowpan: remove unused LOWPAN_FRAG_SIZE define This define is unused since commit 96cb3eb7a1a5f0c3598500a2348f7d2cc76afbd2 ("6lowpan: fix fragmentation on sending side"). It is a worst case scenario for payload calculation. Since commit 96cb3eb7a1a5f0c3598500a2348f7d2cc76afbd2 we calculation the payload to use the optimal size. This define is also necessary for ieee802154 6lowpan only and the file include/net/6lowpan.h should contain generic 6lowpan things only. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/6lowpan.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h index 18010bce68c8..3bb3503b7ff4 100644 --- a/include/net/6lowpan.h +++ b/include/net/6lowpan.h @@ -154,17 +154,6 @@ #define LOWPAN_FRAG1_HEAD_SIZE 0x4 #define LOWPAN_FRAGN_HEAD_SIZE 0x5 -/* - * According IEEE802.15.4 standard: - * - MTU is 127 octets - * - maximum MHR size is 37 octets - * - MFR size is 2 octets - * - * so minimal payload size that we may guarantee is: - * MTU - MHR - MFR = 88 octets - */ -#define LOWPAN_FRAG_SIZE 88 - /* * Values of fields within the IPHC encoding first byte * (C stands for compressed and I for inline) -- cgit v1.2.3 From 89f534905ad6e7f18d89759efcbfc8225f254de1 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 30 Jul 2014 03:48:40 +0200 Subject: 6lowpan: iphc: Fix block comments to match networking style This patch fixes all the block comment issues found by checkpatch.pl and makes them match the network style now. WARNING: networking block comments don't use an empty /* line, use /* Comment... +/* + * Based on patches from Jon Smirl WARNING: networking block comments don't use an empty /* line, use /* Comment... +/* + * Uncompress address function for source and WARNING: networking block comments don't use an empty /* line, use /* Comment... +/* + * Uncompress address function for source context WARNING: networking block comments don't use an empty /* line, use /* Comment... + /* + * UDP lenght needs to be infered from the lower layers WARNING: networking block comments don't use an empty /* line, use /* Comment... + /* + * Traffic Class and FLow Label carried in-line WARNING: networking block comments don't use an empty /* line, use /* Comment... + /* + * Traffic class carried in-line WARNING: networking block comments don't use an empty /* line, use /* Comment... + /* + * Flow Label carried in-line WARNING: networking block comments don't use an empty /* line, use /* Comment... + /* + * replace the compressed UDP head by the uncompressed UDP WARNING: networking block comments don't use an empty /* line, use /* Comment... + /* + * As we copy some bit-length fields, in the IPHC encoding bytes, WARNING: networking block comments don't use an empty /* line, use /* Comment... + /* + * Traffic class, flow label WARNING: networking block comments don't use an empty /* line, use /* Comment... + /* + * Hop limit Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/6lowpan/iphc.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index de78deb49959..3069eb615ace 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -3,8 +3,7 @@ * written by Alexander Smirnov */ -/* - * Based on patches from Jon Smirl +/* Based on patches from Jon Smirl * Copyright (c) 2011 Jon Smirl * * This program is free software; you can redistribute it and/or modify @@ -58,8 +57,7 @@ #include #include -/* - * Uncompress address function for source and +/* Uncompress address function for source and * destination address(non-multicast). * * address_mode is sam value or dam value. @@ -140,8 +138,7 @@ static int uncompress_addr(struct sk_buff *skb, return 0; } -/* - * Uncompress address function for source context +/* Uncompress address function for source context * based address(non-multicast). */ static int uncompress_context_based_src_addr(struct sk_buff *skb, @@ -316,8 +313,7 @@ uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) sizeof(uh->check)); } - /* - * UDP lenght needs to be infered from the lower layers + /* UDP length needs to be infered from the lower layers * here, we obtain the hint from the remaining size of the * frame */ @@ -362,8 +358,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, /* Traffic Class and Flow Label */ switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) { - /* - * Traffic Class and FLow Label carried in-line + /* Traffic Class and FLow Label carried in-line * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) */ case 0: /* 00b */ @@ -376,8 +371,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | (hdr.flow_lbl[0] & 0x0f); break; - /* - * Traffic class carried in-line + /* Traffic class carried in-line * ECN + DSCP (1 byte), Flow Label is elided */ case 2: /* 10b */ @@ -387,8 +381,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, hdr.priority = ((tmp >> 2) & 0x0f); hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); break; - /* - * Flow Label carried in-line + /* Flow Label carried in-line * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided */ case 1: /* 01b */ @@ -474,8 +467,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, if (uncompress_udp_header(skb, &uh)) goto drop; - /* - * replace the compressed UDP head by the uncompressed UDP + /* replace the compressed UDP head by the uncompressed UDP * header */ new = skb_copy_expand(skb, sizeof(struct udphdr), @@ -624,8 +616,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, raw_dump_table(__func__, "raw skb network header dump", skb_network_header(skb), sizeof(struct ipv6hdr)); - /* - * As we copy some bit-length fields, in the IPHC encoding bytes, + /* As we copy some bit-length fields, in the IPHC encoding bytes, * we sometimes use |= * If the field is 0, and the current bit value in memory is 1, * this does not work. We therefore reset the IPHC encoding here @@ -644,8 +635,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, "sending raw skb network uncompressed packet", skb->data, skb->len); - /* - * Traffic class, flow label + /* Traffic class, flow label * If flow label is 0, compress it. If traffic class is 0, compress it * We have to process both in the same time as the offset of traffic * class depends on the presence of version and flow label @@ -696,8 +686,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr, sizeof(hdr->nexthdr)); - /* - * Hop limit + /* Hop limit * if 1: compress, encoding is 01 * if 64: compress, encoding is 10 * if 255: compress, encoding is 11 -- cgit v1.2.3 From 7fc4cfda757d5d8f31ba2ebb07b3fb31ae6986bc Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 30 Jul 2014 03:48:41 +0200 Subject: 6lowpan: iphc: Fix issues with alignment matching open parenthesis This patch fixes all the issues with alignment matching of open parenthesis found by checkpatch.pl and makes them follow the network coding style now. CHECK: Alignment should match open parenthesis +static int uncompress_addr(struct sk_buff *skb, + struct in6_addr *ipaddr, const u8 address_mode, CHECK: Alignment should match open parenthesis +static int uncompress_context_based_src_addr(struct sk_buff *skb, + struct in6_addr *ipaddr, CHECK: Alignment should match open parenthesis +static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, + struct net_device *dev, skb_delivery_cb deliver_skb) CHECK: Alignment should match open parenthesis + new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), + GFP_ATOMIC); CHECK: Alignment should match open parenthesis + raw_dump_table(__func__, "raw skb data dump before receiving", + new->data, new->len); CHECK: Alignment should match open parenthesis +lowpan_uncompress_multicast_daddr(struct sk_buff *skb, + struct in6_addr *ipaddr, CHECK: Alignment should match open parenthesis + raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", + ipaddr->s6_addr, 16); CHECK: Alignment should match open parenthesis +int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, + const u8 *saddr, const u8 saddr_type, const u8 saddr_len, CHECK: Alignment should match open parenthesis + raw_dump_table(__func__, "raw skb data dump uncompressed", + skb->data, skb->len); CHECK: Alignment should match open parenthesis + err = uncompress_addr(skb, &hdr.saddr, tmp, saddr, + saddr_type, saddr_len); CHECK: Alignment should match open parenthesis + err = uncompress_addr(skb, &hdr.daddr, tmp, daddr, + daddr_type, daddr_len); CHECK: Alignment should match open parenthesis + pr_debug("dest: stateless compression mode %d dest %pI6c\n", + tmp, &hdr.daddr); CHECK: Alignment should match open parenthesis + raw_dump_table(__func__, "raw UDP header dump", + (u8 *)&uh, sizeof(uh)); CHECK: Alignment should match open parenthesis + raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, + sizeof(hdr)); CHECK: Alignment should match open parenthesis +int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *_daddr, CHECK: Alignment should match open parenthesis + raw_dump_table(__func__, "raw skb network header dump", + skb_network_header(skb), sizeof(struct ipv6hdr)); CHECK: Alignment should match open parenthesis + raw_dump_table(__func__, + "sending raw skb network uncompressed packet", CHECK: Alignment should match open parenthesis + if (((hdr->flow_lbl[0] & 0x0F) == 0) && + (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { WARNING: quoted string split across lines + pr_debug("dest address unicast link-local %pI6c " + "iphc1 0x%02x\n", &hdr->daddr, iphc1); CHECK: Alignment should match open parenthesis + raw_dump_table(__func__, "raw skb data dump compressed", + skb->data, skb->len); Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/6lowpan/iphc.c | 74 ++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index 3069eb615ace..c718253a4e07 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -63,9 +63,9 @@ * address_mode is sam value or dam value. */ static int uncompress_addr(struct sk_buff *skb, - struct in6_addr *ipaddr, const u8 address_mode, - const u8 *lladdr, const u8 addr_type, - const u8 addr_len) + struct in6_addr *ipaddr, const u8 address_mode, + const u8 *lladdr, const u8 addr_type, + const u8 addr_len) { bool fail; @@ -142,8 +142,8 @@ static int uncompress_addr(struct sk_buff *skb, * based address(non-multicast). */ static int uncompress_context_based_src_addr(struct sk_buff *skb, - struct in6_addr *ipaddr, - const u8 sam) + struct in6_addr *ipaddr, + const u8 sam) { switch (sam) { case LOWPAN_IPHC_ADDR_00: @@ -172,13 +172,13 @@ static int uncompress_context_based_src_addr(struct sk_buff *skb, } static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, - struct net_device *dev, skb_delivery_cb deliver_skb) + struct net_device *dev, skb_delivery_cb deliver_skb) { struct sk_buff *new; int stat; new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), - GFP_ATOMIC); + GFP_ATOMIC); kfree_skb(skb); if (!new) @@ -193,7 +193,7 @@ static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, new->dev = dev; raw_dump_table(__func__, "raw skb data dump before receiving", - new->data, new->len); + new->data, new->len); stat = deliver_skb(new, dev); @@ -205,10 +205,9 @@ static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, /* Uncompress function for multicast destination address, * when M bit is set. */ -static int -lowpan_uncompress_multicast_daddr(struct sk_buff *skb, - struct in6_addr *ipaddr, - const u8 dam) +static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb, + struct in6_addr *ipaddr, + const u8 dam) { bool fail; @@ -254,13 +253,12 @@ lowpan_uncompress_multicast_daddr(struct sk_buff *skb, } raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", - ipaddr->s6_addr, 16); + ipaddr->s6_addr, 16); return 0; } -static int -uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) +static int uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) { bool fail; u8 tmp = 0, val = 0; @@ -336,16 +334,16 @@ err: static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, - const u8 *saddr, const u8 saddr_type, const u8 saddr_len, - const u8 *daddr, const u8 daddr_type, const u8 daddr_len, - u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) + const u8 *saddr, const u8 saddr_type, const u8 saddr_len, + const u8 *daddr, const u8 daddr_type, const u8 daddr_len, + u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) { struct ipv6hdr hdr = {}; u8 tmp, num_context = 0; int err; raw_dump_table(__func__, "raw skb data dump uncompressed", - skb->data, skb->len); + skb->data, skb->len); /* another if the CID flag is set */ if (iphc1 & LOWPAN_IPHC_CID) { @@ -424,13 +422,12 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, if (iphc1 & LOWPAN_IPHC_SAC) { /* Source address context based uncompression */ pr_debug("SAC bit is set. Handle context based source address.\n"); - err = uncompress_context_based_src_addr( - skb, &hdr.saddr, tmp); + err = uncompress_context_based_src_addr(skb, &hdr.saddr, tmp); } else { /* Source address uncompression */ pr_debug("source address stateless compression\n"); err = uncompress_addr(skb, &hdr.saddr, tmp, saddr, - saddr_type, saddr_len); + saddr_type, saddr_len); } /* Check on error of previous branch */ @@ -446,16 +443,17 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, pr_debug("dest: context-based mcast compression\n"); /* TODO: implement this */ } else { - err = lowpan_uncompress_multicast_daddr( - skb, &hdr.daddr, tmp); + err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr, + tmp); + if (err) goto drop; } } else { err = uncompress_addr(skb, &hdr.daddr, tmp, daddr, - daddr_type, daddr_len); + daddr_type, daddr_len); pr_debug("dest: stateless compression mode %d dest %pI6c\n", - tmp, &hdr.daddr); + tmp, &hdr.daddr); if (err) goto drop; } @@ -484,7 +482,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); raw_dump_table(__func__, "raw UDP header dump", - (u8 *)&uh, sizeof(uh)); + (u8 *)&uh, sizeof(uh)); hdr.nexthdr = UIP_PROTO_UDP; } @@ -499,8 +497,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, hdr.hop_limit, &hdr.daddr); - raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, - sizeof(hdr)); + raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr)); return skb_deliver(skb, &hdr, dev, deliver_skb); @@ -594,8 +591,8 @@ static void compress_udp_header(u8 **hc_ptr, struct sk_buff *skb) } int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *_daddr, - const void *_saddr, unsigned int len) + unsigned short type, const void *_daddr, + const void *_saddr, unsigned int len) { u8 tmp, iphc0, iphc1, *hc_ptr; struct ipv6hdr *hdr; @@ -610,11 +607,11 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", - hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, - hdr->hop_limit, &hdr->daddr); + hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, + hdr->hop_limit, &hdr->daddr); raw_dump_table(__func__, "raw skb network header dump", - skb_network_header(skb), sizeof(struct ipv6hdr)); + skb_network_header(skb), sizeof(struct ipv6hdr)); /* As we copy some bit-length fields, in the IPHC encoding bytes, * we sometimes use |= @@ -631,9 +628,8 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, raw_dump_inline(__func__, "daddr", (unsigned char *)_daddr, IEEE802154_ADDR_LEN); - raw_dump_table(__func__, - "sending raw skb network uncompressed packet", - skb->data, skb->len); + raw_dump_table(__func__, "sending raw skb network uncompressed packet", + skb->data, skb->len); /* Traffic class, flow label * If flow label is 0, compress it. If traffic class is 0, compress it @@ -763,7 +759,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, iphc1 |= lowpan_compress_addr_64(&hc_ptr, LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr); pr_debug("dest address unicast link-local %pI6c " - "iphc1 0x%02x\n", &hdr->daddr, iphc1); + "iphc1 0x%02x\n", &hdr->daddr, iphc1); } else { pr_debug("dest address unicast %pI6c\n", &hdr->daddr); lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16); @@ -785,7 +781,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, pr_debug("header len %d skb %u\n", (int)(hc_ptr - head), skb->len); raw_dump_table(__func__, "raw skb data dump compressed", - skb->data, skb->len); + skb->data, skb->len); return 0; } EXPORT_SYMBOL_GPL(lowpan_header_compress); -- cgit v1.2.3 From 26fff593cd7fea82e2a287a65fa6951eef7f9cd6 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 30 Jul 2014 03:48:42 +0200 Subject: 6lowpan: iphc: Fix missing blank line after variable declarations WARNING: Missing a blank line after declarations + struct sk_buff *new; + if (uncompress_udp_header(skb, &uh)) Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/6lowpan/iphc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index c718253a4e07..e6cf68e8667f 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -462,6 +462,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, if (iphc0 & LOWPAN_IPHC_NH_C) { struct udphdr uh; struct sk_buff *new; + if (uncompress_udp_header(skb, &uh)) goto drop; -- cgit v1.2.3 From 9ab9bb009c16cb785a4358699bbafd4094948893 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 30 Jul 2014 03:48:43 +0200 Subject: 6lowpan: iphc: Fix missing braces for if statement CHECK: braces {} should be used on all arms of this statement + if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) [...] + else { [...] Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/6lowpan/iphc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index e6cf68e8667f..9e47702d24dd 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -408,9 +408,9 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, } /* Hop Limit */ - if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) + if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) { hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; - else { + } else { if (lowpan_fetch_skb(skb, &hdr.hop_limit, sizeof(hdr.hop_limit))) goto drop; -- cgit v1.2.3 From 3fa71fe0b9908144c5e710a4a4fc5d01b60d9dee Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 30 Jul 2014 03:48:44 +0200 Subject: 6lowpan: iphc: Fix parenthesis alignments which off-by-one CHECK: Alignment should match open parenthesis + if (((hdr->flow_lbl[0] & 0x0F) == 0) && + (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { CHECK: Alignment should match open parenthesis + if ((hdr->priority == 0) && + ((hdr->flow_lbl[0] & 0xF0) == 0)) { CHECK: Alignment should match open parenthesis + if ((hdr->priority == 0) && + ((hdr->flow_lbl[0] & 0xF0) == 0)) { Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/6lowpan/iphc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index 9e47702d24dd..350ecfafa8e7 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -643,11 +643,11 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, tmp = ((tmp & 0x03) << 6) | (tmp >> 2); if (((hdr->flow_lbl[0] & 0x0F) == 0) && - (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { + (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { /* flow label can be compressed */ iphc0 |= LOWPAN_IPHC_FL_C; if ((hdr->priority == 0) && - ((hdr->flow_lbl[0] & 0xF0) == 0)) { + ((hdr->flow_lbl[0] & 0xF0) == 0)) { /* compress (elide) all */ iphc0 |= LOWPAN_IPHC_TC_C; } else { @@ -658,7 +658,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, } else { /* Flow label cannot be compressed */ if ((hdr->priority == 0) && - ((hdr->flow_lbl[0] & 0xF0) == 0)) { + ((hdr->flow_lbl[0] & 0xF0) == 0)) { /* compress only traffic class */ iphc0 |= LOWPAN_IPHC_TC_C; *hc_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); -- cgit v1.2.3 From 267ca9fefca70817ca3283f5ae564ee385e742b6 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 30 Jul 2014 11:05:11 +0530 Subject: 6lowpan: remove unused macros This patch removes the unused macros. Signed-off-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- include/net/6lowpan.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h index 3bb3503b7ff4..614920a39bf2 100644 --- a/include/net/6lowpan.h +++ b/include/net/6lowpan.h @@ -75,10 +75,6 @@ (((a)->s6_addr[14]) == (m)[6]) && \ (((a)->s6_addr[15]) == (m)[7])) -/* compare ipv6 addresses prefixes */ -#define ipaddr_prefixcmp(addr1, addr2, length) \ - (memcmp(addr1, addr2, length >> 3) == 0) - /* * check whether we can compress the IID to 16 bits, * it's possible for unicast adresses with first 49 bits are zero only. @@ -92,17 +88,6 @@ /* check whether the 112-bit gid of the multicast address is mappable to: */ -/* 9 bits, for FF02::1 (all nodes) and FF02::2 (all routers) addresses only. */ -#define lowpan_is_mcast_addr_compressable(a) \ - ((((a)->s6_addr16[1]) == 0) && \ - (((a)->s6_addr16[2]) == 0) && \ - (((a)->s6_addr16[3]) == 0) && \ - (((a)->s6_addr16[4]) == 0) && \ - (((a)->s6_addr16[5]) == 0) && \ - (((a)->s6_addr16[6]) == 0) && \ - (((a)->s6_addr[14]) == 0) && \ - ((((a)->s6_addr[15]) == 1) || (((a)->s6_addr[15]) == 2))) - /* 48 bits, FFXX::00XX:XXXX:XXXX */ #define lowpan_is_mcast_addr_compressable48(a) \ ((((a)->s6_addr16[1]) == 0) && \ -- cgit v1.2.3 From 233351bd66f1fadc4a69f350a9a4422c2e3d308d Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 30 Jul 2014 11:05:12 +0530 Subject: 6lowpan: remove unused function This patch removes the unused function. Signed-off-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- include/net/6lowpan.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h index 614920a39bf2..d184df1d0d41 100644 --- a/include/net/6lowpan.h +++ b/include/net/6lowpan.h @@ -240,17 +240,6 @@ static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val) return 0; } -static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val) -{ - if (unlikely(!pskb_may_pull(skb, 2))) - return -EINVAL; - - *val = (skb->data[0] << 8) | skb->data[1]; - skb_pull(skb, 2); - - return 0; -} - static inline bool lowpan_fetch_skb(struct sk_buff *skb, void *data, const unsigned int len) { -- cgit v1.2.3 From 6f78fd4bb93e17543f2f6f25112687c633c12eb7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 30 Jul 2014 08:35:48 +0300 Subject: Bluetooth: Fix check for connected state when pairing Both BT_CONNECTED and BT_CONFIG state mean that we have a baseband link available. We should therefore check for either of these when pairing and deciding whether to call hci_conn_security() directly. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5d18efcb8467..0b15b7618beb 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3213,7 +3213,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, conn->io_capability = cp->io_cap; cmd->user_data = conn; - if (conn->state == BT_CONNECTED && + if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) && hci_conn_security(conn, sec_level, auth_type, true)) pairing_complete(cmd, 0); -- cgit v1.2.3 From bdb9434664d026ea63ad086443160dd4ed347758 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 30 Jul 2014 08:08:45 +0200 Subject: Bluetooth: Fix sparse warning from HID new leds handling The new leds bit handling produces this spares warning. CHECK net/bluetooth/hidp/core.c net/bluetooth/hidp/core.c:156:60: warning: dubious: x | !y Just fix it by doing an explicit x << 0 shift operation. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hidp/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 8181ea4bc2f2..6c7ecf116e74 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -154,7 +154,7 @@ static int hidp_input_event(struct input_dev *dev, unsigned int type, (!!test_bit(LED_COMPOSE, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | - (!!test_bit(LED_NUML, dev->led)); + (!!test_bit(LED_NUML, dev->led) << 0); if (session->leds == newleds) return 0; -- cgit v1.2.3 From b6ae8457ac5c727a2bb85eb8f2e22375d44d2b2d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 30 Jul 2014 09:22:22 +0300 Subject: Bluetooth: Rename HCI_PAIRABLE to HCI_BONDABLE The HCI_PAIRABLE flag isn't actually controlling whether we're pairable but whether we're bondable. Therefore, rename it accordingly. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 2 +- net/bluetooth/hci_core.c | 4 ++-- net/bluetooth/hci_event.c | 4 ++-- net/bluetooth/mgmt.c | 8 ++++---- net/bluetooth/smp.c | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index e3fd926df13f..3f8547f1c6f8 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -167,7 +167,7 @@ enum { HCI_AUTO_OFF, HCI_RFKILLED, HCI_MGMT, - HCI_PAIRABLE, + HCI_BONDABLE, HCI_SERVICE_CACHE, HCI_KEEP_DEBUG_KEYS, HCI_USE_DEBUG_KEYS, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 61bd1a8c5849..32b96f1aaf42 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2521,14 +2521,14 @@ int hci_dev_open(__u16 dev) flush_workqueue(hdev->req_workqueue); /* For controllers not using the management interface and that - * are brought up using legacy ioctl, set the HCI_PAIRABLE bit + * are brought up using legacy ioctl, set the HCI_BONDABLE bit * so that pairing works for them. Once the management interface * is in use this bit will be cleared again and userspace has * to explicitly enable it. */ if (!test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && !test_bit(HCI_MGMT, &hdev->dev_flags)) - set_bit(HCI_PAIRABLE, &hdev->dev_flags); + set_bit(HCI_BONDABLE, &hdev->dev_flags); err = hci_dev_do_open(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 623501ddd1b8..c43cee4fcffd 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3119,7 +3119,7 @@ static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_conn_drop(conn); } - if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags) && + if (!test_bit(HCI_BONDABLE, &hdev->dev_flags) && !test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags)) { hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); @@ -3652,7 +3652,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) /* Allow pairing if we're pairable, the initiators of the * pairing or if the remote is not requesting bonding. */ - if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) || + if (test_bit(HCI_BONDABLE, &hdev->dev_flags) || test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags) || (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { struct hci_cp_io_capability_reply cp; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0b15b7618beb..edb1a62054c9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -603,7 +603,7 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) settings |= MGMT_SETTING_DISCOVERABLE; - if (test_bit(HCI_PAIRABLE, &hdev->dev_flags)) + if (test_bit(HCI_BONDABLE, &hdev->dev_flags)) settings |= MGMT_SETTING_PAIRABLE; if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) @@ -1152,7 +1152,7 @@ static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) * for mgmt we require user-space to explicitly enable * it */ - clear_bit(HCI_PAIRABLE, &hdev->dev_flags); + clear_bit(HCI_BONDABLE, &hdev->dev_flags); } static int read_controller_info(struct sock *sk, struct hci_dev *hdev, @@ -1946,9 +1946,9 @@ static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, hci_dev_lock(hdev); if (cp->val) - changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags); + changed = !test_and_set_bit(HCI_BONDABLE, &hdev->dev_flags); else - changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags); + changed = test_and_clear_bit(HCI_BONDABLE, &hdev->dev_flags); err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev); if (err < 0) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index eaa8e7482bb4..fd3294300803 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -307,7 +307,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, struct hci_dev *hdev = hcon->hdev; u8 local_dist = 0, remote_dist = 0; - if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) { + if (test_bit(HCI_BONDABLE, &conn->hcon->hdev->dev_flags)) { local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; remote_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; authreq |= SMP_AUTH_BONDING; @@ -704,7 +704,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (!smp) return SMP_UNSPECIFIED; - if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags) && + if (!test_bit(HCI_BONDABLE, &hdev->dev_flags) && (req->auth_req & SMP_AUTH_BONDING)) return SMP_PAIRING_NOTSUPP; @@ -930,7 +930,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (!smp) return SMP_UNSPECIFIED; - if (!test_bit(HCI_PAIRABLE, &hcon->hdev->dev_flags) && + if (!test_bit(HCI_BONDABLE, &hcon->hdev->dev_flags) && (rp->auth_req & SMP_AUTH_BONDING)) return SMP_PAIRING_NOTSUPP; -- cgit v1.2.3 From b2939475eb6a3575fe542c06f3f879b93d48ae1b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 30 Jul 2014 09:22:23 +0300 Subject: Bluetooth: Rename pairable mgmt setting to bondable This setting maps to the HCI_BONDABLE flag which tracks whether we're bondable or not. Therefore, rename the mgmt setting and respective command accordingly. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/mgmt.h | 4 ++-- net/bluetooth/mgmt.c | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 623d5203c592..414cd2f9a437 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -87,7 +87,7 @@ struct mgmt_rp_read_index_list { #define MGMT_SETTING_CONNECTABLE 0x00000002 #define MGMT_SETTING_FAST_CONNECTABLE 0x00000004 #define MGMT_SETTING_DISCOVERABLE 0x00000008 -#define MGMT_SETTING_PAIRABLE 0x00000010 +#define MGMT_SETTING_BONDABLE 0x00000010 #define MGMT_SETTING_LINK_SECURITY 0x00000020 #define MGMT_SETTING_SSP 0x00000040 #define MGMT_SETTING_BREDR 0x00000080 @@ -131,7 +131,7 @@ struct mgmt_cp_set_discoverable { #define MGMT_OP_SET_FAST_CONNECTABLE 0x0008 -#define MGMT_OP_SET_PAIRABLE 0x0009 +#define MGMT_OP_SET_BONDABLE 0x0009 #define MGMT_OP_SET_LINK_SECURITY 0x000A diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index edb1a62054c9..b8554d429d88 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -44,7 +44,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_SET_DISCOVERABLE, MGMT_OP_SET_CONNECTABLE, MGMT_OP_SET_FAST_CONNECTABLE, - MGMT_OP_SET_PAIRABLE, + MGMT_OP_SET_BONDABLE, MGMT_OP_SET_LINK_SECURITY, MGMT_OP_SET_SSP, MGMT_OP_SET_HS, @@ -553,7 +553,7 @@ static u32 get_supported_settings(struct hci_dev *hdev) u32 settings = 0; settings |= MGMT_SETTING_POWERED; - settings |= MGMT_SETTING_PAIRABLE; + settings |= MGMT_SETTING_BONDABLE; settings |= MGMT_SETTING_DEBUG_KEYS; settings |= MGMT_SETTING_CONNECTABLE; settings |= MGMT_SETTING_DISCOVERABLE; @@ -604,7 +604,7 @@ static u32 get_current_settings(struct hci_dev *hdev) settings |= MGMT_SETTING_DISCOVERABLE; if (test_bit(HCI_BONDABLE, &hdev->dev_flags)) - settings |= MGMT_SETTING_PAIRABLE; + settings |= MGMT_SETTING_BONDABLE; if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) settings |= MGMT_SETTING_BREDR; @@ -1930,7 +1930,7 @@ failed: return err; } -static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, +static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { struct mgmt_mode *cp = data; @@ -1940,7 +1940,7 @@ static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); if (cp->val != 0x00 && cp->val != 0x01) - return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE, + return cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE, MGMT_STATUS_INVALID_PARAMS); hci_dev_lock(hdev); @@ -1950,7 +1950,7 @@ static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data, else changed = test_and_clear_bit(HCI_BONDABLE, &hdev->dev_flags); - err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev); + err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev); if (err < 0) goto unlock; @@ -5679,7 +5679,7 @@ static const struct mgmt_handler { { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE }, { set_connectable, false, MGMT_SETTING_SIZE }, { set_fast_connectable, false, MGMT_SETTING_SIZE }, - { set_pairable, false, MGMT_SETTING_SIZE }, + { set_bondable, false, MGMT_SETTING_SIZE }, { set_link_security, false, MGMT_SETTING_SIZE }, { set_ssp, false, MGMT_SETTING_SIZE }, { set_hs, false, MGMT_SETTING_SIZE }, -- cgit v1.2.3 From 82c295b1b07595d21e9931c58f08ccd9fa151de0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 30 Jul 2014 09:22:24 +0300 Subject: Bluetooth: Always use non-bonding requirement when not bondable When we're not bondable we should never send any other SSP authentication requirement besides one of the non-bonding ones. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c43cee4fcffd..be35598984d9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3671,13 +3671,18 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && conn->auth_type != HCI_AT_NO_BONDING) conn->auth_type |= 0x01; - - cp.authentication = conn->auth_type; } else { conn->auth_type = hci_get_auth_req(conn); - cp.authentication = conn->auth_type; } + /* If we're not bondable, force one of the non-bondable + * authentication requirement values. + */ + if (!test_bit(HCI_BONDABLE, &hdev->dev_flags)) + conn->auth_type &= HCI_AT_NO_BONDING_MITM; + + cp.authentication = conn->auth_type; + if (hci_find_remote_oob_data(hdev, &conn->dst) && (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags))) cp.oob_data = 0x01; -- cgit v1.2.3 From 4ada97abe937cdb3fc029a871d5b0f21aa661a60 Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Mon, 28 Jul 2014 14:01:38 +0200 Subject: random32: mix in entropy from core to late initcall Currently, we have a 3-stage seeding process in prandom(): Phase 1 is from the early actual initialization of prandom() subsystem which happens during core_initcall() and remains most likely until the beginning of late_initcall() phase. Here, the system might not have enough entropy available for seeding with strong randomness from the random driver. That means, we currently have a 32bit weak LCG() seeding the PRNG status register 1 and mixing that successively into the other 3 registers just to get it up and running. Phase 2 starts with late_initcall() phase resp. when the random driver has initialized its non-blocking pool with enough entropy. At that time, we throw away *all* inner state from its 4 registers and do a full reseed with strong randomness. Phase 3 starts right after that and does a periodic reseed with random slack of status register 1 by a strong random source again. A problem in phase 1 is that during bootup data structures can be initialized, e.g. on module load time, and thus access a weakly seeded prandom and are never changed for the rest of their live-time, thus carrying along the results from a week seed. Lets make sure that current but also future users access a possibly better early seeded prandom. This patch therefore improves phase 1 by trying to make it more 'unpredictable' through mixing in seed from a possible hardware source. Now, the mix-in xors inner state with the outcome of either of the two functions arch_get_random_{,seed}_int(), preferably arch_get_random_seed_int() as it likely represents a non-deterministic random bit generator in hw rather than a cryptographically secure PRNG in hw. However, not all might have the first one, so we use the PRNG as a fallback if available. As we xor the seed into the current state, the worst case would be that a hardware source could be unverifiable compromised or backdoored. In that case nevertheless it would be as good as our original early seeding function prandom_seed_very_weak() since we mix through xor which is entropy preserving. Joint work with Daniel Borkmann. Signed-off-by: Daniel Borkmann Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- lib/random32.c | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/lib/random32.c b/lib/random32.c index fa5da61ce7ad..c9b6bf3afe0c 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -40,6 +40,10 @@ #ifdef CONFIG_RANDOM32_SELFTEST static void __init prandom_state_selftest(void); +#else +static inline void prandom_state_selftest(void) +{ +} #endif static DEFINE_PER_CPU(struct rnd_state, net_rand_state); @@ -53,8 +57,7 @@ static DEFINE_PER_CPU(struct rnd_state, net_rand_state); */ u32 prandom_u32_state(struct rnd_state *state) { -#define TAUSWORTHE(s,a,b,c,d) ((s&c)<>b) - +#define TAUSWORTHE(s, a, b, c, d) ((s & c) << d) ^ (((s << a) ^ s) >> b) state->s1 = TAUSWORTHE(state->s1, 6U, 13U, 4294967294U, 18U); state->s2 = TAUSWORTHE(state->s2, 2U, 27U, 4294967288U, 2U); state->s3 = TAUSWORTHE(state->s3, 13U, 21U, 4294967280U, 7U); @@ -147,21 +150,25 @@ static void prandom_warmup(struct rnd_state *state) prandom_u32_state(state); } -static void prandom_seed_very_weak(struct rnd_state *state, u32 seed) +static u32 __extract_hwseed(void) { - /* Note: This sort of seeding is ONLY used in test cases and - * during boot at the time from core_initcall until late_initcall - * as we don't have a stronger entropy source available yet. - * After late_initcall, we reseed entire state, we have to (!), - * otherwise an attacker just needs to search 32 bit space to - * probe for our internal 128 bit state if he knows a couple - * of prandom32 outputs! - */ -#define LCG(x) ((x) * 69069U) /* super-duper LCG */ - state->s1 = __seed(LCG(seed), 2U); - state->s2 = __seed(LCG(state->s1), 8U); - state->s3 = __seed(LCG(state->s2), 16U); - state->s4 = __seed(LCG(state->s3), 128U); + u32 val = 0; + + (void)(arch_get_random_seed_int(&val) || + arch_get_random_int(&val)); + + return val; +} + +static void prandom_seed_early(struct rnd_state *state, u32 seed, + bool mix_with_hwseed) +{ +#define LCG(x) ((x) * 69069U) /* super-duper LCG */ +#define HWSEED() (mix_with_hwseed ? __extract_hwseed() : 0) + state->s1 = __seed(HWSEED() ^ LCG(seed), 2U); + state->s2 = __seed(HWSEED() ^ LCG(state->s1), 8U); + state->s3 = __seed(HWSEED() ^ LCG(state->s2), 16U); + state->s4 = __seed(HWSEED() ^ LCG(state->s3), 128U); } /** @@ -194,14 +201,13 @@ static int __init prandom_init(void) { int i; -#ifdef CONFIG_RANDOM32_SELFTEST prandom_state_selftest(); -#endif for_each_possible_cpu(i) { struct rnd_state *state = &per_cpu(net_rand_state,i); + u32 weak_seed = (i + jiffies) ^ random_get_entropy(); - prandom_seed_very_weak(state, (i + jiffies) ^ random_get_entropy()); + prandom_seed_early(state, weak_seed, true); prandom_warmup(state); } @@ -210,6 +216,7 @@ static int __init prandom_init(void) core_initcall(prandom_init); static void __prandom_timer(unsigned long dontcare); + static DEFINE_TIMER(seed_timer, __prandom_timer, 0, 0); static void __prandom_timer(unsigned long dontcare) @@ -419,7 +426,7 @@ static void __init prandom_state_selftest(void) for (i = 0; i < ARRAY_SIZE(test1); i++) { struct rnd_state state; - prandom_seed_very_weak(&state, test1[i].seed); + prandom_seed_early(&state, test1[i].seed, false); prandom_warmup(&state); if (test1[i].result != prandom_u32_state(&state)) @@ -434,7 +441,7 @@ static void __init prandom_state_selftest(void) for (i = 0; i < ARRAY_SIZE(test2); i++) { struct rnd_state state; - prandom_seed_very_weak(&state, test2[i].seed); + prandom_seed_early(&state, test2[i].seed, false); prandom_warmup(&state); for (j = 0; j < test2[i].iteration - 1; j++) -- cgit v1.2.3 From dabf24d168ae7da5c3dc8c383db64b200e9ab483 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Mon, 28 Jul 2014 15:03:52 +0200 Subject: bna: fill the magic in bnad_get_eeprom() instead of validating A driver should fill magic field of ethtool_eeprom struct in .get_eeprom and validate it in .set_eeprom. The bna incorrectly validates it in both and this makes its .get_eeprom interface unusable. Signed-off-by: Ivan Vecera Signed-off-by: David S. Miller --- drivers/net/ethernet/brocade/bna/bnad_ethtool.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/brocade/bna/bnad_ethtool.c b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c index 882cad71ad62..d26adac6ab99 100644 --- a/drivers/net/ethernet/brocade/bna/bnad_ethtool.c +++ b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c @@ -997,10 +997,8 @@ bnad_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, unsigned long flags = 0; int ret = 0; - /* Check if the flash read request is valid */ - if (eeprom->magic != (bnad->pcidev->vendor | - (bnad->pcidev->device << 16))) - return -EFAULT; + /* Fill the magic value */ + eeprom->magic = bnad->pcidev->vendor | (bnad->pcidev->device << 16); /* Query the flash partition based on the offset */ flash_part = bnad_get_flash_partition_by_offset(bnad, -- cgit v1.2.3 From 9603b61de1eee92977d74ff42541be20c0c5b1a7 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Mon, 28 Jul 2014 23:30:22 +0300 Subject: mlx5: Move pci device handling from mlx5_ib to mlx5_core In preparation for a new mlx5 device which is VPI (i.e., ports can be either IB or ETH), move the pci device functionality from mlx5_ib to mlx5_core. This involves the following changes: 1. Move mlx5_core_dev struct out of mlx5_ib_dev. mlx5_core_dev is now an independent structure maintained by mlx5_core. mlx5_ib_dev now has a pointer to that struct. This requires changing a lot of places where the core_dev struct was accessed via mlx5_ib_dev (now, this needs to be a pointer dereference). 2. All PCI initializations are now done in mlx5_core. Thus, it is now mlx5_core which does pci_register_device (and not mlx5_ib, as was previously). 3. mlx5_ib now registers itself with mlx5_core as an "interface" driver. This is very similar to the mechanism employed for the mlx4 (ConnectX) driver. Once the HCA is initialized (by mlx5_core), it invokes the interface drivers to do their initializations. 4. There is a new event handler which the core registers: mlx5_core_event(). This event handler invokes the event handlers registered by the interfaces. Based on a patch by Eli Cohen Signed-off-by: Jack Morgenstein Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/cq.c | 46 ++-- drivers/infiniband/hw/mlx5/mad.c | 4 +- drivers/infiniband/hw/mlx5/main.c | 281 ++++++++---------------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 12 +- drivers/infiniband/hw/mlx5/mr.c | 48 ++-- drivers/infiniband/hw/mlx5/qp.c | 84 +++---- drivers/infiniband/hw/mlx5/srq.c | 26 +-- drivers/net/ethernet/mellanox/mlx5/core/main.c | 290 ++++++++++++++++++++++++- include/linux/mlx5/driver.h | 17 +- 9 files changed, 498 insertions(+), 310 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 8ae4f896cb41..3b4dc858cef9 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -180,7 +180,7 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, struct mlx5_core_srq *msrq = NULL; if (qp->ibqp.xrcd) { - msrq = mlx5_core_get_srq(&dev->mdev, + msrq = mlx5_core_get_srq(dev->mdev, be32_to_cpu(cqe->srqn)); srq = to_mibsrq(msrq); } else { @@ -364,7 +364,7 @@ static void handle_atomics(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64, static void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf) { - mlx5_buf_free(&dev->mdev, &buf->buf); + mlx5_buf_free(dev->mdev, &buf->buf); } static void get_sig_err_item(struct mlx5_sig_err_cqe *cqe, @@ -450,7 +450,7 @@ repoll: * because CQs will be locked while QPs are removed * from the table. */ - mqp = __mlx5_qp_lookup(&dev->mdev, qpn); + mqp = __mlx5_qp_lookup(dev->mdev, qpn); if (unlikely(!mqp)) { mlx5_ib_warn(dev, "CQE@CQ %06x for unknown QPN %6x\n", cq->mcq.cqn, qpn); @@ -514,11 +514,11 @@ repoll: case MLX5_CQE_SIG_ERR: sig_err_cqe = (struct mlx5_sig_err_cqe *)cqe64; - read_lock(&dev->mdev.priv.mr_table.lock); - mmr = __mlx5_mr_lookup(&dev->mdev, + read_lock(&dev->mdev->priv.mr_table.lock); + mmr = __mlx5_mr_lookup(dev->mdev, mlx5_base_mkey(be32_to_cpu(sig_err_cqe->mkey))); if (unlikely(!mmr)) { - read_unlock(&dev->mdev.priv.mr_table.lock); + read_unlock(&dev->mdev->priv.mr_table.lock); mlx5_ib_warn(dev, "CQE@CQ %06x for unknown MR %6x\n", cq->mcq.cqn, be32_to_cpu(sig_err_cqe->mkey)); return -EINVAL; @@ -536,7 +536,7 @@ repoll: mr->sig->err_item.expected, mr->sig->err_item.actual); - read_unlock(&dev->mdev.priv.mr_table.lock); + read_unlock(&dev->mdev->priv.mr_table.lock); goto repoll; } @@ -575,8 +575,8 @@ int mlx5_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) mlx5_cq_arm(&to_mcq(ibcq)->mcq, (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? MLX5_CQ_DB_REQ_NOT_SOL : MLX5_CQ_DB_REQ_NOT, - to_mdev(ibcq->device)->mdev.priv.uuari.uars[0].map, - MLX5_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->mdev.priv.cq_uar_lock)); + to_mdev(ibcq->device)->mdev->priv.uuari.uars[0].map, + MLX5_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->mdev->priv.cq_uar_lock)); return 0; } @@ -586,7 +586,7 @@ static int alloc_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf, { int err; - err = mlx5_buf_alloc(&dev->mdev, nent * cqe_size, + err = mlx5_buf_alloc(dev->mdev, nent * cqe_size, PAGE_SIZE * 2, &buf->buf); if (err) return err; @@ -691,7 +691,7 @@ static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, { int err; - err = mlx5_db_alloc(&dev->mdev, &cq->db); + err = mlx5_db_alloc(dev->mdev, &cq->db); if (err) return err; @@ -716,7 +716,7 @@ static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, mlx5_fill_page_array(&cq->buf.buf, (*cqb)->pas); (*cqb)->ctx.log_pg_sz = cq->buf.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT; - *index = dev->mdev.priv.uuari.uars[0].index; + *index = dev->mdev->priv.uuari.uars[0].index; return 0; @@ -724,14 +724,14 @@ err_buf: free_cq_buf(dev, &cq->buf); err_db: - mlx5_db_free(&dev->mdev, &cq->db); + mlx5_db_free(dev->mdev, &cq->db); return err; } static void destroy_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq) { free_cq_buf(dev, &cq->buf); - mlx5_db_free(&dev->mdev, &cq->db); + mlx5_db_free(dev->mdev, &cq->db); } struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries, @@ -752,7 +752,7 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries, return ERR_PTR(-EINVAL); entries = roundup_pow_of_two(entries + 1); - if (entries > dev->mdev.caps.max_cqes) + if (entries > dev->mdev->caps.max_cqes) return ERR_PTR(-EINVAL); cq = kzalloc(sizeof(*cq), GFP_KERNEL); @@ -789,7 +789,7 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries, cqb->ctx.c_eqn = cpu_to_be16(eqn); cqb->ctx.db_record_addr = cpu_to_be64(cq->db.dma); - err = mlx5_core_create_cq(&dev->mdev, &cq->mcq, cqb, inlen); + err = mlx5_core_create_cq(dev->mdev, &cq->mcq, cqb, inlen); if (err) goto err_cqb; @@ -809,7 +809,7 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries, return &cq->ibcq; err_cmd: - mlx5_core_destroy_cq(&dev->mdev, &cq->mcq); + mlx5_core_destroy_cq(dev->mdev, &cq->mcq); err_cqb: mlx5_vfree(cqb); @@ -834,7 +834,7 @@ int mlx5_ib_destroy_cq(struct ib_cq *cq) if (cq->uobject) context = cq->uobject->context; - mlx5_core_destroy_cq(&dev->mdev, &mcq->mcq); + mlx5_core_destroy_cq(dev->mdev, &mcq->mcq); if (context) destroy_cq_user(mcq, context); else @@ -919,7 +919,7 @@ int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) int err; u32 fsel; - if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_CQ_MODER)) + if (!(dev->mdev->caps.flags & MLX5_DEV_CAP_FLAG_CQ_MODER)) return -ENOSYS; in = kzalloc(sizeof(*in), GFP_KERNEL); @@ -931,7 +931,7 @@ int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) in->ctx.cq_period = cpu_to_be16(cq_period); in->ctx.cq_max_count = cpu_to_be16(cq_count); in->field_select = cpu_to_be32(fsel); - err = mlx5_core_modify_cq(&dev->mdev, &mcq->mcq, in, sizeof(*in)); + err = mlx5_core_modify_cq(dev->mdev, &mcq->mcq, in, sizeof(*in)); kfree(in); if (err) @@ -1074,7 +1074,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) int uninitialized_var(cqe_size); unsigned long flags; - if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_RESIZE_CQ)) { + if (!(dev->mdev->caps.flags & MLX5_DEV_CAP_FLAG_RESIZE_CQ)) { pr_info("Firmware does not support resize CQ\n"); return -ENOSYS; } @@ -1083,7 +1083,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) return -EINVAL; entries = roundup_pow_of_two(entries + 1); - if (entries > dev->mdev.caps.max_cqes + 1) + if (entries > dev->mdev->caps.max_cqes + 1) return -EINVAL; if (entries == ibcq->cqe + 1) @@ -1128,7 +1128,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) in->hdr.opmod = cpu_to_be16(MLX5_CQ_OPMOD_RESIZE); in->cqn = cpu_to_be32(cq->mcq.cqn); - err = mlx5_core_modify_cq(&dev->mdev, &cq->mcq, in, inlen); + err = mlx5_core_modify_cq(dev->mdev, &cq->mcq, in, inlen); if (err) goto ex_alloc; diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c index 5c8938be0e08..e259e7393152 100644 --- a/drivers/infiniband/hw/mlx5/mad.c +++ b/drivers/infiniband/hw/mlx5/mad.c @@ -54,7 +54,7 @@ int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey, if (ignore_bkey || !in_wc) op_modifier |= 0x2; - return mlx5_core_mad_ifc(&dev->mdev, in_mad, response_mad, op_modifier, port); + return mlx5_core_mad_ifc(dev->mdev, in_mad, response_mad, op_modifier, port); } int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, @@ -129,7 +129,7 @@ int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port) packet_error = be16_to_cpu(out_mad->status); - dev->mdev.caps.ext_port_cap[port - 1] = (!err && !packet_error) ? + dev->mdev->caps.ext_port_cap[port - 1] = (!err && !packet_error) ? MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO : 0; out: diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 364d4b6937f5..f2cfd363a705 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -54,96 +54,17 @@ MODULE_DESCRIPTION("Mellanox Connect-IB HCA IB driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRIVER_VERSION); -static int prof_sel = 2; -module_param_named(prof_sel, prof_sel, int, 0444); -MODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2"); +static int deprecated_prof_sel = 2; +module_param_named(prof_sel, deprecated_prof_sel, int, 0444); +MODULE_PARM_DESC(prof_sel, "profile selector. Deprecated here. Moved to module mlx5_core"); static char mlx5_version[] = DRIVER_NAME ": Mellanox Connect-IB Infiniband driver v" DRIVER_VERSION " (" DRIVER_RELDATE ")\n"; -static struct mlx5_profile profile[] = { - [0] = { - .mask = 0, - }, - [1] = { - .mask = MLX5_PROF_MASK_QP_SIZE, - .log_max_qp = 12, - }, - [2] = { - .mask = MLX5_PROF_MASK_QP_SIZE | - MLX5_PROF_MASK_MR_CACHE, - .log_max_qp = 17, - .mr_cache[0] = { - .size = 500, - .limit = 250 - }, - .mr_cache[1] = { - .size = 500, - .limit = 250 - }, - .mr_cache[2] = { - .size = 500, - .limit = 250 - }, - .mr_cache[3] = { - .size = 500, - .limit = 250 - }, - .mr_cache[4] = { - .size = 500, - .limit = 250 - }, - .mr_cache[5] = { - .size = 500, - .limit = 250 - }, - .mr_cache[6] = { - .size = 500, - .limit = 250 - }, - .mr_cache[7] = { - .size = 500, - .limit = 250 - }, - .mr_cache[8] = { - .size = 500, - .limit = 250 - }, - .mr_cache[9] = { - .size = 500, - .limit = 250 - }, - .mr_cache[10] = { - .size = 500, - .limit = 250 - }, - .mr_cache[11] = { - .size = 500, - .limit = 250 - }, - .mr_cache[12] = { - .size = 64, - .limit = 32 - }, - .mr_cache[13] = { - .size = 32, - .limit = 16 - }, - .mr_cache[14] = { - .size = 16, - .limit = 8 - }, - .mr_cache[15] = { - .size = 8, - .limit = 4 - }, - }, -}; - int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn) { - struct mlx5_eq_table *table = &dev->mdev.priv.eq_table; + struct mlx5_eq_table *table = &dev->mdev->priv.eq_table; struct mlx5_eq *eq, *n; int err = -ENOENT; @@ -163,7 +84,7 @@ int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn) static int alloc_comp_eqs(struct mlx5_ib_dev *dev) { - struct mlx5_eq_table *table = &dev->mdev.priv.eq_table; + struct mlx5_eq_table *table = &dev->mdev->priv.eq_table; char name[MLX5_MAX_EQ_NAME]; struct mlx5_eq *eq, *n; int ncomp_vec; @@ -182,9 +103,9 @@ static int alloc_comp_eqs(struct mlx5_ib_dev *dev) } snprintf(name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i); - err = mlx5_create_map_eq(&dev->mdev, eq, + err = mlx5_create_map_eq(dev->mdev, eq, i + MLX5_EQ_VEC_COMP_BASE, nent, 0, - name, &dev->mdev.priv.uuari.uars[0]); + name, &dev->mdev->priv.uuari.uars[0]); if (err) { kfree(eq); goto clean; @@ -204,7 +125,7 @@ clean: list_for_each_entry_safe(eq, n, &dev->eqs_list, list) { list_del(&eq->list); spin_unlock(&table->lock); - if (mlx5_destroy_unmap_eq(&dev->mdev, eq)) + if (mlx5_destroy_unmap_eq(dev->mdev, eq)) mlx5_ib_warn(dev, "failed to destroy EQ 0x%x\n", eq->eqn); kfree(eq); spin_lock(&table->lock); @@ -215,14 +136,14 @@ clean: static void free_comp_eqs(struct mlx5_ib_dev *dev) { - struct mlx5_eq_table *table = &dev->mdev.priv.eq_table; + struct mlx5_eq_table *table = &dev->mdev->priv.eq_table; struct mlx5_eq *eq, *n; spin_lock(&table->lock); list_for_each_entry_safe(eq, n, &dev->eqs_list, list) { list_del(&eq->list); spin_unlock(&table->lock); - if (mlx5_destroy_unmap_eq(&dev->mdev, eq)) + if (mlx5_destroy_unmap_eq(dev->mdev, eq)) mlx5_ib_warn(dev, "failed to destroy EQ 0x%x\n", eq->eqn); kfree(eq); spin_lock(&table->lock); @@ -255,14 +176,14 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, memset(props, 0, sizeof(*props)); - props->fw_ver = ((u64)fw_rev_maj(&dev->mdev) << 32) | - (fw_rev_min(&dev->mdev) << 16) | - fw_rev_sub(&dev->mdev); + props->fw_ver = ((u64)fw_rev_maj(dev->mdev) << 32) | + (fw_rev_min(dev->mdev) << 16) | + fw_rev_sub(dev->mdev); props->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT | IB_DEVICE_PORT_ACTIVE_EVENT | IB_DEVICE_SYS_IMAGE_GUID | IB_DEVICE_RC_RNR_NAK_GEN; - flags = dev->mdev.caps.flags; + flags = dev->mdev->caps.flags; if (flags & MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR) props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; if (flags & MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR) @@ -292,30 +213,30 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, memcpy(&props->sys_image_guid, out_mad->data + 4, 8); props->max_mr_size = ~0ull; - props->page_size_cap = dev->mdev.caps.min_page_sz; - props->max_qp = 1 << dev->mdev.caps.log_max_qp; - props->max_qp_wr = dev->mdev.caps.max_wqes; - max_rq_sg = dev->mdev.caps.max_rq_desc_sz / sizeof(struct mlx5_wqe_data_seg); - max_sq_sg = (dev->mdev.caps.max_sq_desc_sz - sizeof(struct mlx5_wqe_ctrl_seg)) / + props->page_size_cap = dev->mdev->caps.min_page_sz; + props->max_qp = 1 << dev->mdev->caps.log_max_qp; + props->max_qp_wr = dev->mdev->caps.max_wqes; + max_rq_sg = dev->mdev->caps.max_rq_desc_sz / sizeof(struct mlx5_wqe_data_seg); + max_sq_sg = (dev->mdev->caps.max_sq_desc_sz - sizeof(struct mlx5_wqe_ctrl_seg)) / sizeof(struct mlx5_wqe_data_seg); props->max_sge = min(max_rq_sg, max_sq_sg); - props->max_cq = 1 << dev->mdev.caps.log_max_cq; - props->max_cqe = dev->mdev.caps.max_cqes - 1; - props->max_mr = 1 << dev->mdev.caps.log_max_mkey; - props->max_pd = 1 << dev->mdev.caps.log_max_pd; - props->max_qp_rd_atom = dev->mdev.caps.max_ra_req_qp; - props->max_qp_init_rd_atom = dev->mdev.caps.max_ra_res_qp; + props->max_cq = 1 << dev->mdev->caps.log_max_cq; + props->max_cqe = dev->mdev->caps.max_cqes - 1; + props->max_mr = 1 << dev->mdev->caps.log_max_mkey; + props->max_pd = 1 << dev->mdev->caps.log_max_pd; + props->max_qp_rd_atom = dev->mdev->caps.max_ra_req_qp; + props->max_qp_init_rd_atom = dev->mdev->caps.max_ra_res_qp; props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; - props->max_srq = 1 << dev->mdev.caps.log_max_srq; - props->max_srq_wr = dev->mdev.caps.max_srq_wqes - 1; + props->max_srq = 1 << dev->mdev->caps.log_max_srq; + props->max_srq_wr = dev->mdev->caps.max_srq_wqes - 1; props->max_srq_sge = max_rq_sg - 1; props->max_fast_reg_page_list_len = (unsigned int)-1; - props->local_ca_ack_delay = dev->mdev.caps.local_ca_ack_delay; + props->local_ca_ack_delay = dev->mdev->caps.local_ca_ack_delay; props->atomic_cap = IB_ATOMIC_NONE; props->masked_atomic_cap = IB_ATOMIC_NONE; props->max_pkeys = be16_to_cpup((__be16 *)(out_mad->data + 28)); - props->max_mcast_grp = 1 << dev->mdev.caps.log_max_mcg; - props->max_mcast_qp_attach = dev->mdev.caps.max_qp_mcg; + props->max_mcast_grp = 1 << dev->mdev->caps.log_max_mcg; + props->max_mcast_qp_attach = dev->mdev->caps.max_qp_mcg; props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * props->max_mcast_grp; props->max_map_per_fmr = INT_MAX; /* no limit in ConnectIB */ @@ -336,7 +257,7 @@ int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, int ext_active_speed; int err = -ENOMEM; - if (port < 1 || port > dev->mdev.caps.num_ports) { + if (port < 1 || port > dev->mdev->caps.num_ports) { mlx5_ib_warn(dev, "invalid port number %d\n", port); return -EINVAL; } @@ -367,8 +288,8 @@ int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, props->phys_state = out_mad->data[33] >> 4; props->port_cap_flags = be32_to_cpup((__be32 *)(out_mad->data + 20)); props->gid_tbl_len = out_mad->data[50]; - props->max_msg_sz = 1 << to_mdev(ibdev)->mdev.caps.log_max_msg; - props->pkey_tbl_len = to_mdev(ibdev)->mdev.caps.port[port - 1].pkey_table_len; + props->max_msg_sz = 1 << to_mdev(ibdev)->mdev->caps.log_max_msg; + props->pkey_tbl_len = to_mdev(ibdev)->mdev->caps.port[port - 1].pkey_table_len; props->bad_pkey_cntr = be16_to_cpup((__be16 *)(out_mad->data + 46)); props->qkey_viol_cntr = be16_to_cpup((__be16 *)(out_mad->data + 48)); props->active_width = out_mad->data[31] & 0xf; @@ -395,7 +316,7 @@ int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, /* If reported active speed is QDR, check if is FDR-10 */ if (props->active_speed == 4) { - if (dev->mdev.caps.ext_port_cap[port - 1] & + if (dev->mdev->caps.ext_port_cap[port - 1] & MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO) { init_query_mad(in_mad); in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO; @@ -508,7 +429,7 @@ static int mlx5_ib_modify_device(struct ib_device *ibdev, int mask, * a 144 trap. If cmd fails, just ignore. */ memcpy(&in, props->node_desc, 64); - err = mlx5_core_access_reg(&dev->mdev, &in, sizeof(in), &out, + err = mlx5_core_access_reg(dev->mdev, &in, sizeof(in), &out, sizeof(out), MLX5_REG_NODE_DESC, 0, 1); if (err) return err; @@ -535,7 +456,7 @@ static int mlx5_ib_modify_port(struct ib_device *ibdev, u8 port, int mask, tmp = (attr.port_cap_flags | props->set_port_cap_mask) & ~props->clr_port_cap_mask; - err = mlx5_set_port_caps(&dev->mdev, port, tmp); + err = mlx5_set_port_caps(dev->mdev, port, tmp); out: mutex_unlock(&dev->cap_mask_mutex); @@ -591,14 +512,14 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, num_uars = req.total_num_uuars / MLX5_NON_FP_BF_REGS_PER_PAGE; gross_uuars = num_uars * MLX5_BF_REGS_PER_PAGE; - resp.qp_tab_size = 1 << dev->mdev.caps.log_max_qp; - resp.bf_reg_size = dev->mdev.caps.bf_reg_size; + resp.qp_tab_size = 1 << dev->mdev->caps.log_max_qp; + resp.bf_reg_size = dev->mdev->caps.bf_reg_size; resp.cache_line_size = L1_CACHE_BYTES; - resp.max_sq_desc_sz = dev->mdev.caps.max_sq_desc_sz; - resp.max_rq_desc_sz = dev->mdev.caps.max_rq_desc_sz; - resp.max_send_wqebb = dev->mdev.caps.max_wqes; - resp.max_recv_wr = dev->mdev.caps.max_wqes; - resp.max_srq_recv_wr = dev->mdev.caps.max_srq_wqes; + resp.max_sq_desc_sz = dev->mdev->caps.max_sq_desc_sz; + resp.max_rq_desc_sz = dev->mdev->caps.max_rq_desc_sz; + resp.max_send_wqebb = dev->mdev->caps.max_wqes; + resp.max_recv_wr = dev->mdev->caps.max_wqes; + resp.max_srq_recv_wr = dev->mdev->caps.max_srq_wqes; context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) @@ -635,7 +556,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, } for (i = 0; i < num_uars; i++) { - err = mlx5_cmd_alloc_uar(&dev->mdev, &uars[i].index); + err = mlx5_cmd_alloc_uar(dev->mdev, &uars[i].index); if (err) goto out_count; } @@ -644,7 +565,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, mutex_init(&context->db_page_mutex); resp.tot_uuars = req.total_num_uuars; - resp.num_ports = dev->mdev.caps.num_ports; + resp.num_ports = dev->mdev->caps.num_ports; err = ib_copy_to_udata(udata, &resp, sizeof(resp) - sizeof(resp.reserved)); if (err) @@ -658,7 +579,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, out_uars: for (i--; i >= 0; i--) - mlx5_cmd_free_uar(&dev->mdev, uars[i].index); + mlx5_cmd_free_uar(dev->mdev, uars[i].index); out_count: kfree(uuari->count); @@ -681,7 +602,7 @@ static int mlx5_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) int i; for (i = 0; i < uuari->num_uars; i++) { - if (mlx5_cmd_free_uar(&dev->mdev, uuari->uars[i].index)) + if (mlx5_cmd_free_uar(dev->mdev, uuari->uars[i].index)) mlx5_ib_warn(dev, "failed to free UAR 0x%x\n", uuari->uars[i].index); } @@ -695,7 +616,7 @@ static int mlx5_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) static phys_addr_t uar_index2pfn(struct mlx5_ib_dev *dev, int index) { - return (pci_resource_start(dev->mdev.pdev, 0) >> PAGE_SHIFT) + index; + return (pci_resource_start(dev->mdev->pdev, 0) >> PAGE_SHIFT) + index; } static int get_command(unsigned long offset) @@ -773,7 +694,7 @@ static int alloc_pa_mkey(struct mlx5_ib_dev *dev, u32 *key, u32 pdn) seg->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); seg->start_addr = 0; - err = mlx5_core_create_mkey(&dev->mdev, &mr, in, sizeof(*in), + err = mlx5_core_create_mkey(dev->mdev, &mr, in, sizeof(*in), NULL, NULL, NULL); if (err) { mlx5_ib_warn(dev, "failed to create mkey, %d\n", err); @@ -798,7 +719,7 @@ static void free_pa_mkey(struct mlx5_ib_dev *dev, u32 key) memset(&mr, 0, sizeof(mr)); mr.key = key; - err = mlx5_core_destroy_mkey(&dev->mdev, &mr); + err = mlx5_core_destroy_mkey(dev->mdev, &mr); if (err) mlx5_ib_warn(dev, "failed to destroy mkey 0x%x\n", key); } @@ -815,7 +736,7 @@ static struct ib_pd *mlx5_ib_alloc_pd(struct ib_device *ibdev, if (!pd) return ERR_PTR(-ENOMEM); - err = mlx5_core_alloc_pd(&to_mdev(ibdev)->mdev, &pd->pdn); + err = mlx5_core_alloc_pd(to_mdev(ibdev)->mdev, &pd->pdn); if (err) { kfree(pd); return ERR_PTR(err); @@ -824,14 +745,14 @@ static struct ib_pd *mlx5_ib_alloc_pd(struct ib_device *ibdev, if (context) { resp.pdn = pd->pdn; if (ib_copy_to_udata(udata, &resp, sizeof(resp))) { - mlx5_core_dealloc_pd(&to_mdev(ibdev)->mdev, pd->pdn); + mlx5_core_dealloc_pd(to_mdev(ibdev)->mdev, pd->pdn); kfree(pd); return ERR_PTR(-EFAULT); } } else { err = alloc_pa_mkey(to_mdev(ibdev), &pd->pa_lkey, pd->pdn); if (err) { - mlx5_core_dealloc_pd(&to_mdev(ibdev)->mdev, pd->pdn); + mlx5_core_dealloc_pd(to_mdev(ibdev)->mdev, pd->pdn); kfree(pd); return ERR_PTR(err); } @@ -848,7 +769,7 @@ static int mlx5_ib_dealloc_pd(struct ib_pd *pd) if (!pd->uobject) free_pa_mkey(mdev, mpd->pa_lkey); - mlx5_core_dealloc_pd(&mdev->mdev, mpd->pdn); + mlx5_core_dealloc_pd(mdev->mdev, mpd->pdn); kfree(mpd); return 0; @@ -859,7 +780,7 @@ static int mlx5_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) struct mlx5_ib_dev *dev = to_mdev(ibqp->device); int err; - err = mlx5_core_attach_mcg(&dev->mdev, gid, ibqp->qp_num); + err = mlx5_core_attach_mcg(dev->mdev, gid, ibqp->qp_num); if (err) mlx5_ib_warn(dev, "failed attaching QPN 0x%x, MGID %pI6\n", ibqp->qp_num, gid->raw); @@ -872,7 +793,7 @@ static int mlx5_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) struct mlx5_ib_dev *dev = to_mdev(ibqp->device); int err; - err = mlx5_core_detach_mcg(&dev->mdev, gid, ibqp->qp_num); + err = mlx5_core_detach_mcg(dev->mdev, gid, ibqp->qp_num); if (err) mlx5_ib_warn(dev, "failed detaching QPN 0x%x, MGID %pI6\n", ibqp->qp_num, gid->raw); @@ -906,7 +827,7 @@ static int init_node_data(struct mlx5_ib_dev *dev) if (err) goto out; - dev->mdev.rev_id = be32_to_cpup((__be32 *)(out_mad->data + 32)); + dev->mdev->rev_id = be32_to_cpup((__be32 *)(out_mad->data + 32)); memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8); out: @@ -921,7 +842,7 @@ static ssize_t show_fw_pages(struct device *device, struct device_attribute *att struct mlx5_ib_dev *dev = container_of(device, struct mlx5_ib_dev, ib_dev.dev); - return sprintf(buf, "%d\n", dev->mdev.priv.fw_pages); + return sprintf(buf, "%d\n", dev->mdev->priv.fw_pages); } static ssize_t show_reg_pages(struct device *device, @@ -930,7 +851,7 @@ static ssize_t show_reg_pages(struct device *device, struct mlx5_ib_dev *dev = container_of(device, struct mlx5_ib_dev, ib_dev.dev); - return sprintf(buf, "%d\n", dev->mdev.priv.reg_pages); + return sprintf(buf, "%d\n", dev->mdev->priv.reg_pages); } static ssize_t show_hca(struct device *device, struct device_attribute *attr, @@ -938,7 +859,7 @@ static ssize_t show_hca(struct device *device, struct device_attribute *attr, { struct mlx5_ib_dev *dev = container_of(device, struct mlx5_ib_dev, ib_dev.dev); - return sprintf(buf, "MT%d\n", dev->mdev.pdev->device); + return sprintf(buf, "MT%d\n", dev->mdev->pdev->device); } static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr, @@ -946,8 +867,8 @@ static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr, { struct mlx5_ib_dev *dev = container_of(device, struct mlx5_ib_dev, ib_dev.dev); - return sprintf(buf, "%d.%d.%d\n", fw_rev_maj(&dev->mdev), - fw_rev_min(&dev->mdev), fw_rev_sub(&dev->mdev)); + return sprintf(buf, "%d.%d.%d\n", fw_rev_maj(dev->mdev), + fw_rev_min(dev->mdev), fw_rev_sub(dev->mdev)); } static ssize_t show_rev(struct device *device, struct device_attribute *attr, @@ -955,7 +876,7 @@ static ssize_t show_rev(struct device *device, struct device_attribute *attr, { struct mlx5_ib_dev *dev = container_of(device, struct mlx5_ib_dev, ib_dev.dev); - return sprintf(buf, "%x\n", dev->mdev.rev_id); + return sprintf(buf, "%x\n", dev->mdev->rev_id); } static ssize_t show_board(struct device *device, struct device_attribute *attr, @@ -964,7 +885,7 @@ static ssize_t show_board(struct device *device, struct device_attribute *attr, struct mlx5_ib_dev *dev = container_of(device, struct mlx5_ib_dev, ib_dev.dev); return sprintf(buf, "%.*s\n", MLX5_BOARD_ID_LEN, - dev->mdev.board_id); + dev->mdev->board_id); } static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); @@ -983,11 +904,12 @@ static struct device_attribute *mlx5_class_attributes[] = { &dev_attr_reg_pages, }; -static void mlx5_ib_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, - void *data) +static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context, + enum mlx5_dev_event event, void *data) { - struct mlx5_ib_dev *ibdev = container_of(dev, struct mlx5_ib_dev, mdev); + struct mlx5_ib_dev *ibdev = (struct mlx5_ib_dev *)context; struct ib_event ibev; + u8 port = 0; switch (event) { @@ -1047,7 +969,7 @@ static void get_ext_port_caps(struct mlx5_ib_dev *dev) { int port; - for (port = 1; port <= dev->mdev.caps.num_ports; port++) + for (port = 1; port <= dev->mdev->caps.num_ports; port++) mlx5_query_ext_port_caps(dev, port); } @@ -1072,14 +994,14 @@ static int get_port_caps(struct mlx5_ib_dev *dev) goto out; } - for (port = 1; port <= dev->mdev.caps.num_ports; port++) { + for (port = 1; port <= dev->mdev->caps.num_ports; port++) { err = mlx5_ib_query_port(&dev->ib_dev, port, pprops); if (err) { mlx5_ib_warn(dev, "query_port %d failed %d\n", port, err); break; } - dev->mdev.caps.port[port - 1].pkey_table_len = dprops->max_pkeys; - dev->mdev.caps.port[port - 1].gid_table_len = pprops->gid_tbl_len; + dev->mdev->caps.port[port - 1].pkey_table_len = dprops->max_pkeys; + dev->mdev->caps.port[port - 1].gid_table_len = pprops->gid_tbl_len; mlx5_ib_dbg(dev, "pkey_table_len %d, gid_table_len %d\n", dprops->max_pkeys, pprops->gid_tbl_len); } @@ -1328,10 +1250,8 @@ static void destroy_dev_resources(struct mlx5_ib_resources *devr) mlx5_ib_dealloc_pd(devr->p0); } -static int init_one(struct pci_dev *pdev, - const struct pci_device_id *id) +static void *mlx5_ib_add(struct mlx5_core_dev *mdev) { - struct mlx5_core_dev *mdev; struct mlx5_ib_dev *dev; int err; int i; @@ -1340,28 +1260,19 @@ static int init_one(struct pci_dev *pdev, dev = (struct mlx5_ib_dev *)ib_alloc_device(sizeof(*dev)); if (!dev) - return -ENOMEM; + return NULL; - mdev = &dev->mdev; - mdev->event = mlx5_ib_event; - if (prof_sel >= ARRAY_SIZE(profile)) { - pr_warn("selected pofile out of range, selceting default\n"); - prof_sel = 0; - } - mdev->profile = &profile[prof_sel]; - err = mlx5_dev_init(mdev, pdev); - if (err) - goto err_free; + dev->mdev = mdev; err = get_port_caps(dev); if (err) - goto err_cleanup; + goto err_dealloc; get_ext_port_caps(dev); err = alloc_comp_eqs(dev); if (err) - goto err_cleanup; + goto err_dealloc; MLX5_INIT_DOORBELL_LOCK(&dev->uar_lock); @@ -1480,7 +1391,7 @@ static int init_one(struct pci_dev *pdev, dev->ib_active = true; - return 0; + return dev; err_umrc: destroy_umrc_res(dev); @@ -1494,49 +1405,39 @@ err_rsrc: err_eqs: free_comp_eqs(dev); -err_cleanup: - mlx5_dev_cleanup(mdev); - -err_free: +err_dealloc: ib_dealloc_device((struct ib_device *)dev); - return err; + return NULL; } -static void remove_one(struct pci_dev *pdev) +static void mlx5_ib_remove(struct mlx5_core_dev *mdev, void *context) { - struct mlx5_ib_dev *dev = mlx5_pci2ibdev(pdev); - + struct mlx5_ib_dev *dev = context; destroy_umrc_res(dev); ib_unregister_device(&dev->ib_dev); destroy_dev_resources(&dev->devr); free_comp_eqs(dev); - mlx5_dev_cleanup(&dev->mdev); ib_dealloc_device(&dev->ib_dev); } -static DEFINE_PCI_DEVICE_TABLE(mlx5_ib_pci_table) = { - { PCI_VDEVICE(MELLANOX, 4113) }, /* MT4113 Connect-IB */ - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, mlx5_ib_pci_table); - -static struct pci_driver mlx5_ib_driver = { - .name = DRIVER_NAME, - .id_table = mlx5_ib_pci_table, - .probe = init_one, - .remove = remove_one +static struct mlx5_interface mlx5_ib_interface = { + .add = mlx5_ib_add, + .remove = mlx5_ib_remove, + .event = mlx5_ib_event, }; static int __init mlx5_ib_init(void) { - return pci_register_driver(&mlx5_ib_driver); + if (deprecated_prof_sel != 2) + pr_warn("prof_sel is deprecated for mlx5_ib, set it for mlx5_core\n"); + + return mlx5_register_interface(&mlx5_ib_interface); } static void __exit mlx5_ib_cleanup(void) { - pci_unregister_driver(&mlx5_ib_driver); + mlx5_unregister_interface(&mlx5_ib_interface); } module_init(mlx5_ib_init); diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index f2ccf1a5a291..a0e204ffe367 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -360,7 +360,7 @@ struct mlx5_ib_resources { struct mlx5_ib_dev { struct ib_device ib_dev; - struct mlx5_core_dev mdev; + struct mlx5_core_dev *mdev; MLX5_DECLARE_DOORBELL_LOCK(uar_lock); struct list_head eqs_list; int num_ports; @@ -454,16 +454,6 @@ static inline struct mlx5_ib_ah *to_mah(struct ib_ah *ibah) return container_of(ibah, struct mlx5_ib_ah, ibah); } -static inline struct mlx5_ib_dev *mlx5_core2ibdev(struct mlx5_core_dev *dev) -{ - return container_of(dev, struct mlx5_ib_dev, mdev); -} - -static inline struct mlx5_ib_dev *mlx5_pci2ibdev(struct pci_dev *pdev) -{ - return mlx5_core2ibdev(pci2mlx5_core_dev(pdev)); -} - int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt, struct mlx5_db *db); void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db); diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index afa873bd028e..80b3c63eab5d 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -73,7 +73,7 @@ static void reg_mr_callback(int status, void *context) struct mlx5_cache_ent *ent = &cache->ent[c]; u8 key; unsigned long flags; - struct mlx5_mr_table *table = &dev->mdev.priv.mr_table; + struct mlx5_mr_table *table = &dev->mdev->priv.mr_table; int err; spin_lock_irqsave(&ent->lock, flags); @@ -97,9 +97,9 @@ static void reg_mr_callback(int status, void *context) return; } - spin_lock_irqsave(&dev->mdev.priv.mkey_lock, flags); - key = dev->mdev.priv.mkey_key++; - spin_unlock_irqrestore(&dev->mdev.priv.mkey_lock, flags); + spin_lock_irqsave(&dev->mdev->priv.mkey_lock, flags); + key = dev->mdev->priv.mkey_key++; + spin_unlock_irqrestore(&dev->mdev->priv.mkey_lock, flags); mr->mmr.key = mlx5_idx_to_mkey(be32_to_cpu(mr->out.mkey) & 0xffffff) | key; cache->last_add = jiffies; @@ -155,7 +155,7 @@ static int add_keys(struct mlx5_ib_dev *dev, int c, int num) spin_lock_irq(&ent->lock); ent->pending++; spin_unlock_irq(&ent->lock); - err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, + err = mlx5_core_create_mkey(dev->mdev, &mr->mmr, in, sizeof(*in), reg_mr_callback, mr, &mr->out); if (err) { @@ -188,7 +188,7 @@ static void remove_keys(struct mlx5_ib_dev *dev, int c, int num) ent->cur--; ent->size--; spin_unlock_irq(&ent->lock); - err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); + err = mlx5_core_destroy_mkey(dev->mdev, &mr->mmr); if (err) mlx5_ib_warn(dev, "failed destroy mkey\n"); else @@ -479,7 +479,7 @@ static void clean_keys(struct mlx5_ib_dev *dev, int c) ent->cur--; ent->size--; spin_unlock_irq(&ent->lock); - err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); + err = mlx5_core_destroy_mkey(dev->mdev, &mr->mmr); if (err) mlx5_ib_warn(dev, "failed destroy mkey\n"); else @@ -496,7 +496,7 @@ static int mlx5_mr_cache_debugfs_init(struct mlx5_ib_dev *dev) if (!mlx5_debugfs_root) return 0; - cache->root = debugfs_create_dir("mr_cache", dev->mdev.priv.dbg_root); + cache->root = debugfs_create_dir("mr_cache", dev->mdev->priv.dbg_root); if (!cache->root) return -ENOMEM; @@ -571,8 +571,8 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev) ent->order = i + 2; ent->dev = dev; - if (dev->mdev.profile->mask & MLX5_PROF_MASK_MR_CACHE) - limit = dev->mdev.profile->mr_cache[i].limit; + if (dev->mdev->profile->mask & MLX5_PROF_MASK_MR_CACHE) + limit = dev->mdev->profile->mr_cache[i].limit; else limit = 0; @@ -610,7 +610,7 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev) struct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc) { struct mlx5_ib_dev *dev = to_mdev(pd->device); - struct mlx5_core_dev *mdev = &dev->mdev; + struct mlx5_core_dev *mdev = dev->mdev; struct mlx5_create_mkey_mbox_in *in; struct mlx5_mkey_seg *seg; struct mlx5_ib_mr *mr; @@ -846,7 +846,7 @@ static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr, in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); in->xlat_oct_act_size = cpu_to_be32(get_octo_len(virt_addr, length, 1 << page_shift)); - err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, inlen, NULL, + err = mlx5_core_create_mkey(dev->mdev, &mr->mmr, in, inlen, NULL, NULL, NULL); if (err) { mlx5_ib_warn(dev, "create mkey failed\n"); @@ -923,7 +923,7 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, mr->umem = umem; mr->npages = npages; spin_lock(&dev->mr_lock); - dev->mdev.priv.reg_pages += npages; + dev->mdev->priv.reg_pages += npages; spin_unlock(&dev->mr_lock); mr->ibmr.lkey = mr->mmr.key; mr->ibmr.rkey = mr->mmr.key; @@ -978,7 +978,7 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr) int err; if (!umred) { - err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); + err = mlx5_core_destroy_mkey(dev->mdev, &mr->mmr); if (err) { mlx5_ib_warn(dev, "failed to destroy mkey 0x%x (%d)\n", mr->mmr.key, err); @@ -996,7 +996,7 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr) if (umem) { ib_umem_release(umem); spin_lock(&dev->mr_lock); - dev->mdev.priv.reg_pages -= npages; + dev->mdev->priv.reg_pages -= npages; spin_unlock(&dev->mr_lock); } @@ -1044,7 +1044,7 @@ struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd, } /* create mem & wire PSVs */ - err = mlx5_core_create_psv(&dev->mdev, to_mpd(pd)->pdn, + err = mlx5_core_create_psv(dev->mdev, to_mpd(pd)->pdn, 2, psv_index); if (err) goto err_free_sig; @@ -1060,7 +1060,7 @@ struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd, } in->seg.flags = MLX5_PERM_UMR_EN | access_mode; - err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, sizeof(*in), + err = mlx5_core_create_mkey(dev->mdev, &mr->mmr, in, sizeof(*in), NULL, NULL, NULL); if (err) goto err_destroy_psv; @@ -1074,11 +1074,11 @@ struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd, err_destroy_psv: if (mr->sig) { - if (mlx5_core_destroy_psv(&dev->mdev, + if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_memory.psv_idx)) mlx5_ib_warn(dev, "failed to destroy mem psv %d\n", mr->sig->psv_memory.psv_idx); - if (mlx5_core_destroy_psv(&dev->mdev, + if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_wire.psv_idx)) mlx5_ib_warn(dev, "failed to destroy wire psv %d\n", mr->sig->psv_wire.psv_idx); @@ -1099,18 +1099,18 @@ int mlx5_ib_destroy_mr(struct ib_mr *ibmr) int err; if (mr->sig) { - if (mlx5_core_destroy_psv(&dev->mdev, + if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_memory.psv_idx)) mlx5_ib_warn(dev, "failed to destroy mem psv %d\n", mr->sig->psv_memory.psv_idx); - if (mlx5_core_destroy_psv(&dev->mdev, + if (mlx5_core_destroy_psv(dev->mdev, mr->sig->psv_wire.psv_idx)) mlx5_ib_warn(dev, "failed to destroy wire psv %d\n", mr->sig->psv_wire.psv_idx); kfree(mr->sig); } - err = mlx5_core_destroy_mkey(&dev->mdev, &mr->mmr); + err = mlx5_core_destroy_mkey(dev->mdev, &mr->mmr); if (err) { mlx5_ib_warn(dev, "failed to destroy mkey 0x%x (%d)\n", mr->mmr.key, err); @@ -1149,7 +1149,7 @@ struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd, * TBD not needed - issue 197292 */ in->seg.log2_page_size = PAGE_SHIFT; - err = mlx5_core_create_mkey(&dev->mdev, &mr->mmr, in, sizeof(*in), NULL, + err = mlx5_core_create_mkey(dev->mdev, &mr->mmr, in, sizeof(*in), NULL, NULL, NULL); kfree(in); if (err) @@ -1202,7 +1202,7 @@ void mlx5_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list) struct mlx5_ib_dev *dev = to_mdev(page_list->device); int size = page_list->max_page_list_len * sizeof(u64); - dma_free_coherent(&dev->mdev.pdev->dev, size, mfrpl->mapped_page_list, + dma_free_coherent(&dev->mdev->pdev->dev, size, mfrpl->mapped_page_list, mfrpl->map); kfree(mfrpl->ibfrpl.page_list); kfree(mfrpl); diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index bbbcf389272c..b8bb6ad6350c 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -162,7 +162,7 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap, int wq_size; /* Sanity check RQ size before proceeding */ - if (cap->max_recv_wr > dev->mdev.caps.max_wqes) + if (cap->max_recv_wr > dev->mdev->caps.max_wqes) return -EINVAL; if (!has_rq) { @@ -182,10 +182,10 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap, wq_size = roundup_pow_of_two(cap->max_recv_wr) * wqe_size; wq_size = max_t(int, wq_size, MLX5_SEND_WQE_BB); qp->rq.wqe_cnt = wq_size / wqe_size; - if (wqe_size > dev->mdev.caps.max_rq_desc_sz) { + if (wqe_size > dev->mdev->caps.max_rq_desc_sz) { mlx5_ib_dbg(dev, "wqe_size %d, max %d\n", wqe_size, - dev->mdev.caps.max_rq_desc_sz); + dev->mdev->caps.max_rq_desc_sz); return -EINVAL; } qp->rq.wqe_shift = ilog2(wqe_size); @@ -277,9 +277,9 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, if (wqe_size < 0) return wqe_size; - if (wqe_size > dev->mdev.caps.max_sq_desc_sz) { + if (wqe_size > dev->mdev->caps.max_sq_desc_sz) { mlx5_ib_dbg(dev, "wqe_size(%d) > max_sq_desc_sz(%d)\n", - wqe_size, dev->mdev.caps.max_sq_desc_sz); + wqe_size, dev->mdev->caps.max_sq_desc_sz); return -EINVAL; } @@ -292,9 +292,9 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size); qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB; - if (qp->sq.wqe_cnt > dev->mdev.caps.max_wqes) { + if (qp->sq.wqe_cnt > dev->mdev->caps.max_wqes) { mlx5_ib_dbg(dev, "wqe count(%d) exceeds limits(%d)\n", - qp->sq.wqe_cnt, dev->mdev.caps.max_wqes); + qp->sq.wqe_cnt, dev->mdev->caps.max_wqes); return -ENOMEM; } qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB); @@ -311,9 +311,9 @@ static int set_user_buf_size(struct mlx5_ib_dev *dev, { int desc_sz = 1 << qp->sq.wqe_shift; - if (desc_sz > dev->mdev.caps.max_sq_desc_sz) { + if (desc_sz > dev->mdev->caps.max_sq_desc_sz) { mlx5_ib_warn(dev, "desc_sz %d, max_sq_desc_sz %d\n", - desc_sz, dev->mdev.caps.max_sq_desc_sz); + desc_sz, dev->mdev->caps.max_sq_desc_sz); return -EINVAL; } @@ -325,9 +325,9 @@ static int set_user_buf_size(struct mlx5_ib_dev *dev, qp->sq.wqe_cnt = ucmd->sq_wqe_count; - if (qp->sq.wqe_cnt > dev->mdev.caps.max_wqes) { + if (qp->sq.wqe_cnt > dev->mdev->caps.max_wqes) { mlx5_ib_warn(dev, "wqe_cnt %d, max_wqes %d\n", - qp->sq.wqe_cnt, dev->mdev.caps.max_wqes); + qp->sq.wqe_cnt, dev->mdev->caps.max_wqes); return -EINVAL; } @@ -674,7 +674,7 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev, int uuarn; int err; - uuari = &dev->mdev.priv.uuari; + uuari = &dev->mdev->priv.uuari; if (init_attr->create_flags & ~(IB_QP_CREATE_SIGNATURE_EN | IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)) return -EINVAL; @@ -700,7 +700,7 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev, qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift; qp->buf_size = err + (qp->rq.wqe_cnt << qp->rq.wqe_shift); - err = mlx5_buf_alloc(&dev->mdev, qp->buf_size, PAGE_SIZE * 2, &qp->buf); + err = mlx5_buf_alloc(dev->mdev, qp->buf_size, PAGE_SIZE * 2, &qp->buf); if (err) { mlx5_ib_dbg(dev, "err %d\n", err); goto err_uuar; @@ -722,7 +722,7 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev, mlx5_fill_page_array(&qp->buf, (*in)->pas); - err = mlx5_db_alloc(&dev->mdev, &qp->db); + err = mlx5_db_alloc(dev->mdev, &qp->db); if (err) { mlx5_ib_dbg(dev, "err %d\n", err); goto err_free; @@ -747,7 +747,7 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev, return 0; err_wrid: - mlx5_db_free(&dev->mdev, &qp->db); + mlx5_db_free(dev->mdev, &qp->db); kfree(qp->sq.wqe_head); kfree(qp->sq.w_list); kfree(qp->sq.wrid); @@ -758,23 +758,23 @@ err_free: mlx5_vfree(*in); err_buf: - mlx5_buf_free(&dev->mdev, &qp->buf); + mlx5_buf_free(dev->mdev, &qp->buf); err_uuar: - free_uuar(&dev->mdev.priv.uuari, uuarn); + free_uuar(&dev->mdev->priv.uuari, uuarn); return err; } static void destroy_qp_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp) { - mlx5_db_free(&dev->mdev, &qp->db); + mlx5_db_free(dev->mdev, &qp->db); kfree(qp->sq.wqe_head); kfree(qp->sq.w_list); kfree(qp->sq.wrid); kfree(qp->sq.wr_data); kfree(qp->rq.wrid); - mlx5_buf_free(&dev->mdev, &qp->buf); - free_uuar(&dev->mdev.priv.uuari, qp->bf->uuarn); + mlx5_buf_free(dev->mdev, &qp->buf); + free_uuar(&dev->mdev->priv.uuari, qp->bf->uuarn); } static __be32 get_rx_type(struct mlx5_ib_qp *qp, struct ib_qp_init_attr *attr) @@ -812,7 +812,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, spin_lock_init(&qp->rq.lock); if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) { - if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_BLOCK_MCAST)) { + if (!(dev->mdev->caps.flags & MLX5_DEV_CAP_FLAG_BLOCK_MCAST)) { mlx5_ib_dbg(dev, "block multicast loopback isn't supported\n"); return -EINVAL; } else { @@ -851,9 +851,9 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, mlx5_ib_dbg(dev, "invalid rq params\n"); return -EINVAL; } - if (ucmd.sq_wqe_count > dev->mdev.caps.max_wqes) { + if (ucmd.sq_wqe_count > dev->mdev->caps.max_wqes) { mlx5_ib_dbg(dev, "requested sq_wqe_count (%d) > max allowed (%d)\n", - ucmd.sq_wqe_count, dev->mdev.caps.max_wqes); + ucmd.sq_wqe_count, dev->mdev->caps.max_wqes); return -EINVAL; } err = create_user_qp(dev, pd, qp, udata, &in, &resp, &inlen); @@ -957,7 +957,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, in->ctx.db_rec_addr = cpu_to_be64(qp->db.dma); - err = mlx5_core_create_qp(&dev->mdev, &qp->mqp, in, inlen); + err = mlx5_core_create_qp(dev->mdev, &qp->mqp, in, inlen); if (err) { mlx5_ib_dbg(dev, "create qp failed\n"); goto err_create; @@ -1081,7 +1081,7 @@ static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp) if (!in) return; if (qp->state != IB_QPS_RESET) - if (mlx5_core_qp_modify(&dev->mdev, to_mlx5_state(qp->state), + if (mlx5_core_qp_modify(dev->mdev, to_mlx5_state(qp->state), MLX5_QP_STATE_RST, in, sizeof(*in), &qp->mqp)) mlx5_ib_warn(dev, "mlx5_ib: modify QP %06x to RESET failed\n", qp->mqp.qpn); @@ -1097,7 +1097,7 @@ static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp) mlx5_ib_unlock_cqs(send_cq, recv_cq); } - err = mlx5_core_destroy_qp(&dev->mdev, &qp->mqp); + err = mlx5_core_destroy_qp(dev->mdev, &qp->mqp); if (err) mlx5_ib_warn(dev, "failed to destroy QP 0x%x\n", qp->mqp.qpn); kfree(in); @@ -1165,7 +1165,7 @@ struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd, switch (init_attr->qp_type) { case IB_QPT_XRC_TGT: case IB_QPT_XRC_INI: - if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_XRC)) { + if (!(dev->mdev->caps.flags & MLX5_DEV_CAP_FLAG_XRC)) { mlx5_ib_dbg(dev, "XRC not supported\n"); return ERR_PTR(-ENOSYS); } @@ -1279,7 +1279,7 @@ static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate) } else { while (rate != IB_RATE_2_5_GBPS && !(1 << (rate + MLX5_STAT_RATE_OFFSET) & - dev->mdev.caps.stat_rate_support)) + dev->mdev->caps.stat_rate_support)) --rate; } @@ -1318,9 +1318,9 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah, path->port = port; if (ah->ah_flags & IB_AH_GRH) { - if (ah->grh.sgid_index >= dev->mdev.caps.port[port - 1].gid_table_len) { + if (ah->grh.sgid_index >= dev->mdev->caps.port[port - 1].gid_table_len) { pr_err(KERN_ERR "sgid_index (%u) too large. max is %d\n", - ah->grh.sgid_index, dev->mdev.caps.port[port - 1].gid_table_len); + ah->grh.sgid_index, dev->mdev->caps.port[port - 1].gid_table_len); return -EINVAL; } @@ -1539,7 +1539,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, err = -EINVAL; goto out; } - context->mtu_msgmax = (attr->path_mtu << 5) | dev->mdev.caps.log_max_msg; + context->mtu_msgmax = (attr->path_mtu << 5) | dev->mdev->caps.log_max_msg; } if (attr_mask & IB_QP_DEST_QPN) @@ -1637,7 +1637,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, optpar = ib_mask_to_mlx5_opt(attr_mask); optpar &= opt_mask[mlx5_cur][mlx5_new][mlx5_st]; in->optparam = cpu_to_be32(optpar); - err = mlx5_core_qp_modify(&dev->mdev, to_mlx5_state(cur_state), + err = mlx5_core_qp_modify(dev->mdev, to_mlx5_state(cur_state), to_mlx5_state(new_state), in, sqd_event, &qp->mqp); if (err) @@ -1699,21 +1699,21 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, goto out; if ((attr_mask & IB_QP_PORT) && - (attr->port_num == 0 || attr->port_num > dev->mdev.caps.num_ports)) + (attr->port_num == 0 || attr->port_num > dev->mdev->caps.num_ports)) goto out; if (attr_mask & IB_QP_PKEY_INDEX) { port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; - if (attr->pkey_index >= dev->mdev.caps.port[port - 1].pkey_table_len) + if (attr->pkey_index >= dev->mdev->caps.port[port - 1].pkey_table_len) goto out; } if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && - attr->max_rd_atomic > dev->mdev.caps.max_ra_res_qp) + attr->max_rd_atomic > dev->mdev->caps.max_ra_res_qp) goto out; if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && - attr->max_dest_rd_atomic > dev->mdev.caps.max_ra_req_qp) + attr->max_dest_rd_atomic > dev->mdev->caps.max_ra_req_qp) goto out; if (cur_state == new_state && cur_state == IB_QPS_RESET) { @@ -2479,7 +2479,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, { struct mlx5_wqe_ctrl_seg *ctrl = NULL; /* compiler warning */ struct mlx5_ib_dev *dev = to_mdev(ibqp->device); - struct mlx5_core_dev *mdev = &dev->mdev; + struct mlx5_core_dev *mdev = dev->mdev; struct mlx5_ib_qp *qp = to_mqp(ibqp); struct mlx5_ib_mr *mr; struct mlx5_wqe_data_seg *dpseg; @@ -2888,7 +2888,7 @@ static int to_ib_qp_access_flags(int mlx5_flags) static void to_ib_ah_attr(struct mlx5_ib_dev *ibdev, struct ib_ah_attr *ib_ah_attr, struct mlx5_qp_path *path) { - struct mlx5_core_dev *dev = &ibdev->mdev; + struct mlx5_core_dev *dev = ibdev->mdev; memset(ib_ah_attr, 0, sizeof(*ib_ah_attr)); ib_ah_attr->port_num = path->port; @@ -2931,7 +2931,7 @@ int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr goto out; } context = &outb->ctx; - err = mlx5_core_qp_query(&dev->mdev, &qp->mqp, outb, sizeof(*outb)); + err = mlx5_core_qp_query(dev->mdev, &qp->mqp, outb, sizeof(*outb)); if (err) goto out_free; @@ -3014,14 +3014,14 @@ struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev, struct mlx5_ib_xrcd *xrcd; int err; - if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_XRC)) + if (!(dev->mdev->caps.flags & MLX5_DEV_CAP_FLAG_XRC)) return ERR_PTR(-ENOSYS); xrcd = kmalloc(sizeof(*xrcd), GFP_KERNEL); if (!xrcd) return ERR_PTR(-ENOMEM); - err = mlx5_core_xrcd_alloc(&dev->mdev, &xrcd->xrcdn); + err = mlx5_core_xrcd_alloc(dev->mdev, &xrcd->xrcdn); if (err) { kfree(xrcd); return ERR_PTR(-ENOMEM); @@ -3036,7 +3036,7 @@ int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd) u32 xrcdn = to_mxrcd(xrcd)->xrcdn; int err; - err = mlx5_core_xrcd_dealloc(&dev->mdev, xrcdn); + err = mlx5_core_xrcd_dealloc(dev->mdev, xrcdn); if (err) { mlx5_ib_warn(dev, "failed to dealloc xrcdn 0x%x\n", xrcdn); return err; diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 384af6dec5eb..70bd131ba646 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -159,7 +159,7 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, int page_shift; int npages; - err = mlx5_db_alloc(&dev->mdev, &srq->db); + err = mlx5_db_alloc(dev->mdev, &srq->db); if (err) { mlx5_ib_warn(dev, "alloc dbell rec failed\n"); return err; @@ -167,7 +167,7 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, *srq->db.db = 0; - if (mlx5_buf_alloc(&dev->mdev, buf_size, PAGE_SIZE * 2, &srq->buf)) { + if (mlx5_buf_alloc(dev->mdev, buf_size, PAGE_SIZE * 2, &srq->buf)) { mlx5_ib_dbg(dev, "buf alloc failed\n"); err = -ENOMEM; goto err_db; @@ -212,10 +212,10 @@ err_in: mlx5_vfree(*in); err_buf: - mlx5_buf_free(&dev->mdev, &srq->buf); + mlx5_buf_free(dev->mdev, &srq->buf); err_db: - mlx5_db_free(&dev->mdev, &srq->db); + mlx5_db_free(dev->mdev, &srq->db); return err; } @@ -229,8 +229,8 @@ static void destroy_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq) static void destroy_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq) { kfree(srq->wrid); - mlx5_buf_free(&dev->mdev, &srq->buf); - mlx5_db_free(&dev->mdev, &srq->db); + mlx5_buf_free(dev->mdev, &srq->buf); + mlx5_db_free(dev->mdev, &srq->db); } struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, @@ -248,10 +248,10 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, u32 flgs, xrcdn; /* Sanity check SRQ size before proceeding */ - if (init_attr->attr.max_wr >= dev->mdev.caps.max_srq_wqes) { + if (init_attr->attr.max_wr >= dev->mdev->caps.max_srq_wqes) { mlx5_ib_dbg(dev, "max_wr %d, cap %d\n", init_attr->attr.max_wr, - dev->mdev.caps.max_srq_wqes); + dev->mdev->caps.max_srq_wqes); return ERR_PTR(-EINVAL); } @@ -303,7 +303,7 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, in->ctx.pd = cpu_to_be32(to_mpd(pd)->pdn); in->ctx.db_record = cpu_to_be64(srq->db.dma); - err = mlx5_core_create_srq(&dev->mdev, &srq->msrq, in, inlen); + err = mlx5_core_create_srq(dev->mdev, &srq->msrq, in, inlen); mlx5_vfree(in); if (err) { mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err); @@ -327,7 +327,7 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, return &srq->ibsrq; err_core: - mlx5_core_destroy_srq(&dev->mdev, &srq->msrq); + mlx5_core_destroy_srq(dev->mdev, &srq->msrq); err_usr_kern_srq: if (pd->uobject) @@ -357,7 +357,7 @@ int mlx5_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, return -EINVAL; mutex_lock(&srq->mutex); - ret = mlx5_core_arm_srq(&dev->mdev, &srq->msrq, attr->srq_limit, 1); + ret = mlx5_core_arm_srq(dev->mdev, &srq->msrq, attr->srq_limit, 1); mutex_unlock(&srq->mutex); if (ret) @@ -378,7 +378,7 @@ int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) if (!out) return -ENOMEM; - ret = mlx5_core_query_srq(&dev->mdev, &srq->msrq, out); + ret = mlx5_core_query_srq(dev->mdev, &srq->msrq, out); if (ret) goto out_box; @@ -396,7 +396,7 @@ int mlx5_ib_destroy_srq(struct ib_srq *srq) struct mlx5_ib_dev *dev = to_mdev(srq->device); struct mlx5_ib_srq *msrq = to_msrq(srq); - mlx5_core_destroy_srq(&dev->mdev, &msrq->msrq); + mlx5_core_destroy_srq(dev->mdev, &msrq->msrq); if (srq->uobject) { mlx5_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index ee24f132e319..4b7f9da4bf11 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -58,7 +58,100 @@ int mlx5_core_debug_mask; module_param_named(debug_mask, mlx5_core_debug_mask, int, 0644); MODULE_PARM_DESC(debug_mask, "debug mask: 1 = dump cmd data, 2 = dump cmd exec time, 3 = both. Default=0"); +#define MLX5_DEFAULT_PROF 2 +static int prof_sel = MLX5_DEFAULT_PROF; +module_param_named(prof_sel, prof_sel, int, 0444); +MODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2"); + struct workqueue_struct *mlx5_core_wq; +static LIST_HEAD(intf_list); +static LIST_HEAD(dev_list); +static DEFINE_MUTEX(intf_mutex); + +struct mlx5_device_context { + struct list_head list; + struct mlx5_interface *intf; + void *context; +}; + +static struct mlx5_profile profile[] = { + [0] = { + .mask = 0, + }, + [1] = { + .mask = MLX5_PROF_MASK_QP_SIZE, + .log_max_qp = 12, + }, + [2] = { + .mask = MLX5_PROF_MASK_QP_SIZE | + MLX5_PROF_MASK_MR_CACHE, + .log_max_qp = 17, + .mr_cache[0] = { + .size = 500, + .limit = 250 + }, + .mr_cache[1] = { + .size = 500, + .limit = 250 + }, + .mr_cache[2] = { + .size = 500, + .limit = 250 + }, + .mr_cache[3] = { + .size = 500, + .limit = 250 + }, + .mr_cache[4] = { + .size = 500, + .limit = 250 + }, + .mr_cache[5] = { + .size = 500, + .limit = 250 + }, + .mr_cache[6] = { + .size = 500, + .limit = 250 + }, + .mr_cache[7] = { + .size = 500, + .limit = 250 + }, + .mr_cache[8] = { + .size = 500, + .limit = 250 + }, + .mr_cache[9] = { + .size = 500, + .limit = 250 + }, + .mr_cache[10] = { + .size = 500, + .limit = 250 + }, + .mr_cache[11] = { + .size = 500, + .limit = 250 + }, + .mr_cache[12] = { + .size = 64, + .limit = 32 + }, + .mr_cache[13] = { + .size = 32, + .limit = 16 + }, + .mr_cache[14] = { + .size = 16, + .limit = 8 + }, + .mr_cache[15] = { + .size = 8, + .limit = 4 + }, + }, +}; static int set_dma_caps(struct pci_dev *pdev) { @@ -299,7 +392,7 @@ static int mlx5_core_disable_hca(struct mlx5_core_dev *dev) return 0; } -int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) +static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) { struct mlx5_priv *priv = &dev->priv; int err; @@ -489,7 +582,7 @@ err_dbg: } EXPORT_SYMBOL(mlx5_dev_init); -void mlx5_dev_cleanup(struct mlx5_core_dev *dev) +static void mlx5_dev_cleanup(struct mlx5_core_dev *dev) { struct mlx5_priv *priv = &dev->priv; @@ -516,7 +609,190 @@ void mlx5_dev_cleanup(struct mlx5_core_dev *dev) pci_disable_device(dev->pdev); debugfs_remove(priv->dbg_root); } -EXPORT_SYMBOL(mlx5_dev_cleanup); + +static void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv) +{ + struct mlx5_device_context *dev_ctx; + struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv); + + dev_ctx = kmalloc(sizeof(*dev_ctx), GFP_KERNEL); + if (!dev_ctx) { + pr_warn("mlx5_add_device: alloc context failed\n"); + return; + } + + dev_ctx->intf = intf; + dev_ctx->context = intf->add(dev); + + if (dev_ctx->context) { + spin_lock_irq(&priv->ctx_lock); + list_add_tail(&dev_ctx->list, &priv->ctx_list); + spin_unlock_irq(&priv->ctx_lock); + } else { + kfree(dev_ctx); + } +} + +static void mlx5_remove_device(struct mlx5_interface *intf, struct mlx5_priv *priv) +{ + struct mlx5_device_context *dev_ctx; + struct mlx5_core_dev *dev = container_of(priv, struct mlx5_core_dev, priv); + + list_for_each_entry(dev_ctx, &priv->ctx_list, list) + if (dev_ctx->intf == intf) { + spin_lock_irq(&priv->ctx_lock); + list_del(&dev_ctx->list); + spin_unlock_irq(&priv->ctx_lock); + + intf->remove(dev, dev_ctx->context); + kfree(dev_ctx); + return; + } +} +static int mlx5_register_device(struct mlx5_core_dev *dev) +{ + struct mlx5_priv *priv = &dev->priv; + struct mlx5_interface *intf; + + mutex_lock(&intf_mutex); + list_add_tail(&priv->dev_list, &dev_list); + list_for_each_entry(intf, &intf_list, list) + mlx5_add_device(intf, priv); + mutex_unlock(&intf_mutex); + + return 0; +} +static void mlx5_unregister_device(struct mlx5_core_dev *dev) +{ + struct mlx5_priv *priv = &dev->priv; + struct mlx5_interface *intf; + + mutex_lock(&intf_mutex); + list_for_each_entry(intf, &intf_list, list) + mlx5_remove_device(intf, priv); + list_del(&priv->dev_list); + mutex_unlock(&intf_mutex); +} + +int mlx5_register_interface(struct mlx5_interface *intf) +{ + struct mlx5_priv *priv; + + if (!intf->add || !intf->remove) + return -EINVAL; + + mutex_lock(&intf_mutex); + list_add_tail(&intf->list, &intf_list); + list_for_each_entry(priv, &dev_list, dev_list) + mlx5_add_device(intf, priv); + mutex_unlock(&intf_mutex); + + return 0; +} +EXPORT_SYMBOL(mlx5_register_interface); + +void mlx5_unregister_interface(struct mlx5_interface *intf) +{ + struct mlx5_priv *priv; + + mutex_lock(&intf_mutex); + list_for_each_entry(priv, &dev_list, dev_list) + mlx5_remove_device(intf, priv); + list_del(&intf->list); + mutex_unlock(&intf_mutex); +} +EXPORT_SYMBOL(mlx5_unregister_interface); + +static void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, + void *data) +{ + struct mlx5_priv *priv = &dev->priv; + struct mlx5_device_context *dev_ctx; + unsigned long flags; + + spin_lock_irqsave(&priv->ctx_lock, flags); + + list_for_each_entry(dev_ctx, &priv->ctx_list, list) + if (dev_ctx->intf->event) + dev_ctx->intf->event(dev, dev_ctx->context, event, data); + + spin_unlock_irqrestore(&priv->ctx_lock, flags); +} + +struct mlx5_core_event_handler { + void (*event)(struct mlx5_core_dev *dev, + enum mlx5_dev_event event, + void *data); +}; + +static int init_one(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct mlx5_core_dev *dev; + struct mlx5_priv *priv; + int err; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&pdev->dev, "kzalloc failed\n"); + return -ENOMEM; + } + priv = &dev->priv; + + pci_set_drvdata(pdev, dev); + + if (prof_sel < 0 || prof_sel >= ARRAY_SIZE(profile)) { + pr_warn("selected profile out of range, selecting default (%d)\n", + MLX5_DEFAULT_PROF); + prof_sel = MLX5_DEFAULT_PROF; + } + dev->profile = &profile[prof_sel]; + dev->event = mlx5_core_event; + + err = mlx5_dev_init(dev, pdev); + if (err) { + dev_err(&pdev->dev, "mlx5_dev_init failed %d\n", err); + goto out; + } + + INIT_LIST_HEAD(&priv->ctx_list); + spin_lock_init(&priv->ctx_lock); + err = mlx5_register_device(dev); + if (err) { + dev_err(&pdev->dev, "mlx5_register_device failed %d\n", err); + goto out_init; + } + + return 0; + +out_init: + mlx5_dev_cleanup(dev); +out: + kfree(dev); + return err; +} +static void remove_one(struct pci_dev *pdev) +{ + struct mlx5_core_dev *dev = pci_get_drvdata(pdev); + + mlx5_unregister_device(dev); + mlx5_dev_cleanup(dev); + kfree(dev); +} + +static const struct pci_device_id mlx5_core_pci_table[] = { + { PCI_VDEVICE(MELLANOX, 4113) }, /* MT4113 Connect-IB */ + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, mlx5_core_pci_table); + +static struct pci_driver mlx5_core_driver = { + .name = DRIVER_NAME, + .id_table = mlx5_core_pci_table, + .probe = init_one, + .remove = remove_one +}; static int __init init(void) { @@ -530,8 +806,15 @@ static int __init init(void) } mlx5_health_init(); + err = pci_register_driver(&mlx5_core_driver); + if (err) + goto err_health; + return 0; +err_health: + mlx5_health_cleanup(); + destroy_workqueue(mlx5_core_wq); err_debug: mlx5_unregister_debugfs(); return err; @@ -539,6 +822,7 @@ err_debug: static void __exit cleanup(void) { + pci_unregister_driver(&mlx5_core_driver); mlx5_health_cleanup(); destroy_workqueue(mlx5_core_wq); mlx5_unregister_debugfs(); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 2bce4aad2570..d0cb5984a45f 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -543,6 +543,10 @@ struct mlx5_priv { /* protect mkey key part */ spinlock_t mkey_lock; u8 mkey_key; + + struct list_head dev_list; + struct list_head ctx_list; + spinlock_t ctx_lock; }; struct mlx5_core_dev { @@ -686,8 +690,6 @@ static inline u32 mlx5_base_mkey(const u32 key) return key & 0xffffff00u; } -int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev); -void mlx5_dev_cleanup(struct mlx5_core_dev *dev); int mlx5_cmd_init(struct mlx5_core_dev *dev); void mlx5_cmd_cleanup(struct mlx5_core_dev *dev); void mlx5_cmd_use_events(struct mlx5_core_dev *dev); @@ -811,6 +813,17 @@ enum { MAX_MR_CACHE_ENTRIES = 16, }; +struct mlx5_interface { + void * (*add)(struct mlx5_core_dev *dev); + void (*remove)(struct mlx5_core_dev *dev, void *context); + void (*event)(struct mlx5_core_dev *dev, void *context, + enum mlx5_dev_event event, void *data); + struct list_head list; +}; + +int mlx5_register_interface(struct mlx5_interface *intf); +void mlx5_unregister_interface(struct mlx5_interface *intf); + struct mlx5_profile { u64 mask; u32 log_max_qp; -- cgit v1.2.3 From f241e7497ec2d22b83002b17ae91a851d4034cb7 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Mon, 28 Jul 2014 23:30:23 +0300 Subject: mlx5: minor fixes (mainly avoidance of hidden casts) There were many places where parameters which should be u8/u16 were integer type. Additionally, in 2 places, a check for a non-null pointer was added before dereferencing the pointer (this is actually a bug fix). Signed-off-by: Jack Morgenstein Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/cq.c | 2 +- drivers/infiniband/hw/mlx5/mad.c | 2 +- drivers/infiniband/hw/mlx5/main.c | 2 +- drivers/infiniband/hw/mlx5/mem.c | 2 +- drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 +- drivers/infiniband/hw/mlx5/qp.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/alloc.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/eq.c | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/mad.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/main.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/port.c | 2 +- include/linux/mlx5/device.h | 4 ---- include/linux/mlx5/driver.h | 8 ++++---- 15 files changed, 19 insertions(+), 22 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 3b4dc858cef9..e4056279166d 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -348,7 +348,7 @@ static void handle_atomic(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64, static void handle_atomics(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64, u16 tail, u16 head) { - int idx; + u16 idx; do { idx = tail & (qp->sq.wqe_cnt - 1); diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c index e259e7393152..b514bbb5610f 100644 --- a/drivers/infiniband/hw/mlx5/mad.c +++ b/drivers/infiniband/hw/mlx5/mad.c @@ -41,7 +41,7 @@ enum { }; int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey, - int port, struct ib_wc *in_wc, struct ib_grh *in_grh, + u8 port, struct ib_wc *in_wc, struct ib_grh *in_grh, void *in_mad, void *response_mad) { u8 op_modifier = 0; diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index f2cfd363a705..166335a95c59 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -478,7 +478,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, int uuarn; int err; int i; - int reqlen; + size_t reqlen; if (!dev->ib_active) return ERR_PTR(-EAGAIN); diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c index 8499aec94db6..a3e81444c825 100644 --- a/drivers/infiniband/hw/mlx5/mem.c +++ b/drivers/infiniband/hw/mlx5/mem.c @@ -148,7 +148,7 @@ int mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset) u64 off_mask; u64 buf_off; - page_size = 1 << page_shift; + page_size = (u64)1 << page_shift; page_mask = page_size - 1; buf_off = addr & page_mask; off_size = page_size >> 6; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index a0e204ffe367..386780f0d1e1 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -461,7 +461,7 @@ void __mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq) void mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq); void mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index); int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey, - int port, struct ib_wc *in_wc, struct ib_grh *in_grh, + u8 port, struct ib_wc *in_wc, struct ib_grh *in_grh, void *in_mad, void *response_mad); struct ib_ah *create_ib_ah(struct ib_ah_attr *ah_attr, struct mlx5_ib_ah *ah); diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index b8bb6ad6350c..7efe6e3f3542 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2539,7 +2539,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, case IB_WR_RDMA_WRITE_WITH_IMM: set_raddr_seg(seg, wr->wr.rdma.remote_addr, wr->wr.rdma.rkey); - seg += sizeof(struct mlx5_wqe_raddr_seg); + seg += sizeof(struct mlx5_wqe_raddr_seg); size += sizeof(struct mlx5_wqe_raddr_seg) / 16; break; @@ -2668,7 +2668,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, case IB_QPT_SMI: case IB_QPT_GSI: set_datagram_seg(seg, wr); - seg += sizeof(struct mlx5_wqe_datagram_seg); + seg += sizeof(struct mlx5_wqe_datagram_seg); size += sizeof(struct mlx5_wqe_datagram_seg) / 16; if (unlikely((seg == qend))) seg = mlx5_get_send_wqe(qp, 0); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c index b215742b842f..56779c1c7811 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c @@ -56,7 +56,7 @@ int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, int max_direct, if (size <= max_direct) { buf->nbufs = 1; buf->npages = 1; - buf->page_shift = get_order(size) + PAGE_SHIFT; + buf->page_shift = (u8)get_order(size) + PAGE_SHIFT; buf->direct.buf = dma_zalloc_coherent(&dev->pdev->dev, size, &t, GFP_KERNEL); if (!buf->direct.buf) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 87d1b018a9c3..4671747dd365 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -464,7 +464,7 @@ static void dump_command(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg = input ? ent->in : ent->out; struct mlx5_cmd_mailbox *next = msg->next; int data_only; - int offset = 0; + u32 offset = 0; int dump_len; data_only = !!(mlx5_core_debug_mask & (1 << MLX5_CMD_DATA)); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 7f39ebcd6ad0..67cead2c079e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -252,7 +252,8 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq) case MLX5_PORT_CHANGE_SUBTYPE_GUID: case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG: case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED: - dev->event(dev, port_subtype_event(eqe->sub_type), &port); + if (dev->event) + dev->event(dev, port_subtype_event(eqe->sub_type), &port); break; default: mlx5_core_warn(dev, "Port event with unrecognized subtype: port %d, sub_type %d\n", diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mad.c b/drivers/net/ethernet/mellanox/mlx5/core/mad.c index 18d6fd5dd90b..fd80ecfa7195 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mad.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/mad.c @@ -37,7 +37,7 @@ #include "mlx5_core.h" int mlx5_core_mad_ifc(struct mlx5_core_dev *dev, void *inb, void *outb, - u16 opmod, int port) + u16 opmod, u8 port) { struct mlx5_mad_ifc_mbox_in *in = NULL; struct mlx5_mad_ifc_mbox_out *out = NULL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 4b7f9da4bf11..fd782bf49dc6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -311,7 +311,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev) copy_rw_fields(&set_ctx->hca_cap, &query_out->hca_cap); - if (dev->profile->mask & MLX5_PROF_MASK_QP_SIZE) + if (dev->profile && dev->profile->mask & MLX5_PROF_MASK_QP_SIZE) set_ctx->hca_cap.log_max_qp = dev->profile->log_max_qp; flags = be64_to_cpu(query_out->hca_cap.flags); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index c2a953ef0e67..d476918ef269 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -51,7 +51,7 @@ enum { struct mlx5_pages_req { struct mlx5_core_dev *dev; - u32 func_id; + u16 func_id; s32 npages; struct work_struct work; }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 8c9ac870ecb1..313965853e10 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -86,7 +86,7 @@ struct mlx5_reg_pcap { __be32 caps_31_0; }; -int mlx5_set_port_caps(struct mlx5_core_dev *dev, int port_num, u32 caps) +int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps) { struct mlx5_reg_pcap in; struct mlx5_reg_pcap out; diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 3406cfb1267a..334947151dfc 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -456,9 +456,6 @@ struct mlx5_eqe_cq_err { u8 syndrome; }; -struct mlx5_eqe_dropped_packet { -}; - struct mlx5_eqe_port_state { u8 reserved0[8]; u8 port; @@ -498,7 +495,6 @@ union ev_data { struct mlx5_eqe_comp comp; struct mlx5_eqe_qp_srq qp_srq; struct mlx5_eqe_cq_err cq_err; - struct mlx5_eqe_dropped_packet dp; struct mlx5_eqe_port_state port; struct mlx5_eqe_gpio gpio; struct mlx5_eqe_congestion cong; diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index d0cb5984a45f..76de0cc41640 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -381,8 +381,8 @@ struct mlx5_buf { struct mlx5_buf_list *page_list; int nbufs; int npages; - int page_shift; int size; + u8 page_shift; }; struct mlx5_eq { @@ -736,7 +736,7 @@ int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, int mlx5_core_alloc_pd(struct mlx5_core_dev *dev, u32 *pdn); int mlx5_core_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn); int mlx5_core_mad_ifc(struct mlx5_core_dev *dev, void *inb, void *outb, - u16 opmod, int port); + u16 opmod, u8 port); void mlx5_pagealloc_init(struct mlx5_core_dev *dev); void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev); int mlx5_pagealloc_start(struct mlx5_core_dev *dev); @@ -769,7 +769,7 @@ void mlx5_qp_debugfs_cleanup(struct mlx5_core_dev *dev); int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in, int size_in, void *data_out, int size_out, u16 reg_num, int arg, int write); -int mlx5_set_port_caps(struct mlx5_core_dev *dev, int port_num, u32 caps); +int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps); int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq); void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq); @@ -826,7 +826,7 @@ void mlx5_unregister_interface(struct mlx5_interface *intf); struct mlx5_profile { u64 mask; - u32 log_max_qp; + u8 log_max_qp; struct { int size; int limit; -- cgit v1.2.3 From 4d2f9bbb654b91a262638ac2c84dcb169d014aa6 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Mon, 28 Jul 2014 23:30:24 +0300 Subject: mlx5: Adjust events to use unsigned long param instead of void * In the event flow, we currently pass only a port number in the void *data argument. Rather than pass a pointer to the event handlers, we should use an "unsigned long" parameter, and pass the port number value directly. In the future, if necessary for some events, we can use the unsigned long parameter to pass a pointer. Based on a patch by Eli Cohen Signed-off-by: Jack Morgenstein Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/main.c | 14 +++++++------- drivers/net/ethernet/mellanox/mlx5/core/eq.c | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/main.c | 4 ++-- include/linux/mlx5/driver.h | 4 ++-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 166335a95c59..d8907b20522a 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -905,7 +905,7 @@ static struct device_attribute *mlx5_class_attributes[] = { }; static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context, - enum mlx5_dev_event event, void *data) + enum mlx5_dev_event event, unsigned long param) { struct mlx5_ib_dev *ibdev = (struct mlx5_ib_dev *)context; struct ib_event ibev; @@ -920,12 +920,12 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context, case MLX5_DEV_EVENT_PORT_UP: ibev.event = IB_EVENT_PORT_ACTIVE; - port = *(u8 *)data; + port = (u8)param; break; case MLX5_DEV_EVENT_PORT_DOWN: ibev.event = IB_EVENT_PORT_ERR; - port = *(u8 *)data; + port = (u8)param; break; case MLX5_DEV_EVENT_PORT_INITIALIZED: @@ -934,22 +934,22 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context, case MLX5_DEV_EVENT_LID_CHANGE: ibev.event = IB_EVENT_LID_CHANGE; - port = *(u8 *)data; + port = (u8)param; break; case MLX5_DEV_EVENT_PKEY_CHANGE: ibev.event = IB_EVENT_PKEY_CHANGE; - port = *(u8 *)data; + port = (u8)param; break; case MLX5_DEV_EVENT_GUID_CHANGE: ibev.event = IB_EVENT_GID_CHANGE; - port = *(u8 *)data; + port = (u8)param; break; case MLX5_DEV_EVENT_CLIENT_REREG: ibev.event = IB_EVENT_CLIENT_REREGISTER; - port = *(u8 *)data; + port = (u8)param; break; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 67cead2c079e..4e8bd0b34bb0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -253,7 +253,8 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq) case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG: case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED: if (dev->event) - dev->event(dev, port_subtype_event(eqe->sub_type), &port); + dev->event(dev, port_subtype_event(eqe->sub_type), + (unsigned long)port); break; default: mlx5_core_warn(dev, "Port event with unrecognized subtype: port %d, sub_type %d\n", diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index fd782bf49dc6..f2716cc1f51d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -704,7 +704,7 @@ void mlx5_unregister_interface(struct mlx5_interface *intf) EXPORT_SYMBOL(mlx5_unregister_interface); static void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, - void *data) + unsigned long param) { struct mlx5_priv *priv = &dev->priv; struct mlx5_device_context *dev_ctx; @@ -714,7 +714,7 @@ static void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event list_for_each_entry(dev_ctx, &priv->ctx_list, list) if (dev_ctx->intf->event) - dev_ctx->intf->event(dev, dev_ctx->context, event, data); + dev_ctx->intf->event(dev, dev_ctx->context, event, param); spin_unlock_irqrestore(&priv->ctx_lock, flags); } diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 76de0cc41640..9f3a5476bb71 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -559,7 +559,7 @@ struct mlx5_core_dev { struct mlx5_init_seg __iomem *iseg; void (*event) (struct mlx5_core_dev *dev, enum mlx5_dev_event event, - void *data); + unsigned long param); struct mlx5_priv priv; struct mlx5_profile *profile; atomic_t num_qps; @@ -817,7 +817,7 @@ struct mlx5_interface { void * (*add)(struct mlx5_core_dev *dev); void (*remove)(struct mlx5_core_dev *dev, void *context); void (*event)(struct mlx5_core_dev *dev, void *context, - enum mlx5_dev_event event, void *data); + enum mlx5_dev_event event, unsigned long param); struct list_head list; }; -- cgit v1.2.3 From 2d871aa07136fe6e576bde63072cf33e2c664e95 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Mon, 28 Jul 2014 14:07:58 -0500 Subject: net: stmmac: add platform init/exit for Altera's ARM socfpga This patch adds platform init/exit functions and modifications to support suspend/resume for the Altera Cyclone 5 SOC Ethernet controller. The platform exit function puts the controller into reset using the socfpga reset controller driver. The platform init function sets up the Synopsys mac by first making sure the Ethernet controller is held in reset, programming the phy mode through external support logic, then deasserts reset through the socfpga reset manager driver. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 69 ++++++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++ 2 files changed, 73 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index fd8a217556a1..ec632e666c56 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -20,7 +20,9 @@ #include #include #include +#include #include +#include "stmmac.h" #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 @@ -34,6 +36,7 @@ struct socfpga_dwmac { u32 reg_shift; struct device *dev; struct regmap *sys_mgr_base_addr; + struct reset_control *stmmac_rst; }; static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) @@ -43,6 +46,13 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device * u32 reg_offset, reg_shift; int ret; + dwmac->stmmac_rst = devm_reset_control_get(dev, + STMMAC_RESOURCE_NAME); + if (IS_ERR(dwmac->stmmac_rst)) { + dev_info(dev, "Could not get reset control!\n"); + return -EINVAL; + } + dwmac->interface = of_get_phy_mode(np); sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); @@ -125,6 +135,65 @@ static void *socfpga_dwmac_probe(struct platform_device *pdev) return dwmac; } +static void socfpga_dwmac_exit(struct platform_device *pdev, void *priv) +{ + struct socfpga_dwmac *dwmac = priv; + + /* On socfpga platform exit, assert and hold reset to the + * enet controller - the default state after a hard reset. + */ + if (dwmac->stmmac_rst) + reset_control_assert(dwmac->stmmac_rst); +} + +static int socfpga_dwmac_init(struct platform_device *pdev, void *priv) +{ + struct socfpga_dwmac *dwmac = priv; + struct net_device *ndev = platform_get_drvdata(pdev); + struct stmmac_priv *stpriv = NULL; + int ret = 0; + + if (ndev) + stpriv = netdev_priv(ndev); + + /* Assert reset to the enet controller before changing the phy mode */ + if (dwmac->stmmac_rst) + reset_control_assert(dwmac->stmmac_rst); + + /* Setup the phy mode in the system manager registers according to + * devicetree configuration + */ + ret = socfpga_dwmac_setup(dwmac); + + /* Deassert reset for the phy configuration to be sampled by + * the enet controller, and operation to start in requested mode + */ + if (dwmac->stmmac_rst) + reset_control_deassert(dwmac->stmmac_rst); + + /* Before the enet controller is suspended, the phy is suspended. + * This causes the phy clock to be gated. The enet controller is + * resumed before the phy, so the clock is still gated "off" when + * the enet controller is resumed. This code makes sure the phy + * is "resumed" before reinitializing the enet controller since + * the enet controller depends on an active phy clock to complete + * a DMA reset. A DMA reset will "time out" if executed + * with no phy clock input on the Synopsys enet controller. + * Verified through Synopsys Case #8000711656. + * + * Note that the phy clock is also gated when the phy is isolated. + * Phy "suspend" and "isolate" controls are located in phy basic + * control register 0, and can be modified by the phy driver + * framework. + */ + if (stpriv && stpriv->phydev) + phy_resume(stpriv->phydev); + + return ret; +} + const struct stmmac_of_data socfpga_gmac_data = { .setup = socfpga_dwmac_probe, + .init = socfpga_dwmac_init, + .exit = socfpga_dwmac_exit, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 057a1208e594..18315f34938b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2878,6 +2878,10 @@ int stmmac_suspend(struct net_device *ndev) clk_disable_unprepare(priv->stmmac_clk); } spin_unlock_irqrestore(&priv->lock, flags); + + priv->oldlink = 0; + priv->speed = 0; + priv->oldduplex = -1; return 0; } -- cgit v1.2.3 From 95cb5745983c222867cc9ac593aebb2ad67d72c0 Mon Sep 17 00:00:00 2001 From: Dmitry Popov Date: Tue, 29 Jul 2014 03:07:52 +0400 Subject: ip_tunnel(ipv4): fix tunnels with "local any remote $remote_ip" Ipv4 tunnels created with "local any remote $ip" didn't work properly since 7d442fab0 (ipv4: Cache dst in tunnels). 99% of packets sent via those tunnels had src addr = 0.0.0.0. That was because only dst_entry was cached, although fl4.saddr has to be cached too. Every time ip_tunnel_xmit used cached dst_entry (tunnel_rtable_get returned non-NULL), fl4.saddr was initialized with tnl_params->saddr (= 0 in our case), and wasn't changed until iptunnel_xmit(). This patch adds saddr to ip_tunnel->dst_cache, fixing this issue. Reported-by: Sergey Popov Signed-off-by: Dmitry Popov Signed-off-by: David S. Miller --- include/net/ip_tunnels.h | 1 + net/ipv4/ip_tunnel.c | 29 ++++++++++++++++++----------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index a4daf9eb8562..8dd8cab88b87 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -40,6 +40,7 @@ struct ip_tunnel_prl_entry { struct ip_tunnel_dst { struct dst_entry __rcu *dst; + __be32 saddr; }; struct ip_tunnel { diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 6f9de61dce5f..45920d928341 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -69,23 +69,25 @@ static unsigned int ip_tunnel_hash(__be32 key, __be32 remote) } static void __tunnel_dst_set(struct ip_tunnel_dst *idst, - struct dst_entry *dst) + struct dst_entry *dst, __be32 saddr) { struct dst_entry *old_dst; dst_clone(dst); old_dst = xchg((__force struct dst_entry **)&idst->dst, dst); dst_release(old_dst); + idst->saddr = saddr; } -static void tunnel_dst_set(struct ip_tunnel *t, struct dst_entry *dst) +static void tunnel_dst_set(struct ip_tunnel *t, + struct dst_entry *dst, __be32 saddr) { - __tunnel_dst_set(this_cpu_ptr(t->dst_cache), dst); + __tunnel_dst_set(this_cpu_ptr(t->dst_cache), dst, saddr); } static void tunnel_dst_reset(struct ip_tunnel *t) { - tunnel_dst_set(t, NULL); + tunnel_dst_set(t, NULL, 0); } void ip_tunnel_dst_reset_all(struct ip_tunnel *t) @@ -93,20 +95,25 @@ void ip_tunnel_dst_reset_all(struct ip_tunnel *t) int i; for_each_possible_cpu(i) - __tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL); + __tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL, 0); } EXPORT_SYMBOL(ip_tunnel_dst_reset_all); -static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, u32 cookie) +static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, + u32 cookie, __be32 *saddr) { + struct ip_tunnel_dst *idst; struct dst_entry *dst; rcu_read_lock(); - dst = rcu_dereference(this_cpu_ptr(t->dst_cache)->dst); + idst = this_cpu_ptr(t->dst_cache); + dst = rcu_dereference(idst->dst); if (dst && !atomic_inc_not_zero(&dst->__refcnt)) dst = NULL; if (dst) { - if (dst->obsolete && dst->ops->check(dst, cookie) == NULL) { + if (!dst->obsolete || dst->ops->check(dst, cookie)) { + *saddr = idst->saddr; + } else { tunnel_dst_reset(t); dst_release(dst); dst = NULL; @@ -367,7 +374,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev) if (!IS_ERR(rt)) { tdev = rt->dst.dev; - tunnel_dst_set(tunnel, &rt->dst); + tunnel_dst_set(tunnel, &rt->dst, fl4.saddr); ip_rt_put(rt); } if (dev->type != ARPHRD_ETHER) @@ -610,7 +617,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); - rt = connected ? tunnel_rtable_get(tunnel, 0) : NULL; + rt = connected ? tunnel_rtable_get(tunnel, 0, &fl4.saddr) : NULL; if (!rt) { rt = ip_route_output_key(tunnel->net, &fl4); @@ -620,7 +627,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, goto tx_error; } if (connected) - tunnel_dst_set(tunnel, &rt->dst); + tunnel_dst_set(tunnel, &rt->dst, fl4.saddr); } if (rt->dst.dev == dev) { -- cgit v1.2.3 From 8500d791c458ccbbb3e2d3fa9a0320ffd5729069 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Wed, 30 Jul 2014 15:57:03 -0700 Subject: Bluetooth: Fix crash in the Marvell driver initialization codepath btmrvl_add_card() function calls kthread_run that might return error (e.g. if current thread is killed). If one tries to use the error value as a pointer then invalid memory access oops happens. Check kthread_run() return value, if it is an error then release resources correctly. TEST=boot computer with BT modules enabled. I see the error message that BT device initialization failed. Now kernel does not crash. Hint: to enable BT run 'rmmod btmrvl_sdio; modprobe btmrvl_sdio' Signed-off-by: Anatol Pomozov Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index bae8e6a0ecf6..1d7db2064889 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -710,12 +710,17 @@ struct btmrvl_private *btmrvl_add_card(void *card) init_waitqueue_head(&priv->main_thread.wait_q); priv->main_thread.task = kthread_run(btmrvl_service_main_thread, &priv->main_thread, "btmrvl_main_service"); + if (IS_ERR(priv->main_thread.task)) + goto err_thread; priv->btmrvl_dev.card = card; priv->btmrvl_dev.tx_dnld_rdy = true; return priv; +err_thread: + btmrvl_free_adapter(priv); + err_adapter: kfree(priv); -- cgit v1.2.3 From 16eecd9be4b05e3216b8b12707aa6f51fb197903 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Mon, 28 Jul 2014 20:57:07 -0700 Subject: dcbnl : Fix misleading dcb_app->priority explanation Current explanation of dcb_app->priority is wrong. It says priority is expected to be a 3-bit unsigned integer which is only true when working with DCBx-IEEE. Use of dcb_app->priority by DCBx-CEE expects it to be 802.1p user priority bitmap. Updated accordingly This affects the cxgb4 driver, but I will post those changes as part of a larger changeset shortly. Fixes: 3e29027af4372 ("dcbnl: add support for ieee8021Qaz attributes") Signed-off-by: Anish Bhatt Acked-by: John Fastabend Signed-off-by: David S. Miller --- include/uapi/linux/dcbnl.h | 3 ++- net/dcb/dcbnl.c | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/dcbnl.h b/include/uapi/linux/dcbnl.h index 6bb43382f3f3..e711f20dc522 100644 --- a/include/uapi/linux/dcbnl.h +++ b/include/uapi/linux/dcbnl.h @@ -148,7 +148,8 @@ struct cee_pfc { * * @selector: protocol identifier type * @protocol: protocol of type indicated - * @priority: 3-bit unsigned integer indicating priority + * @priority: 3-bit unsigned integer indicating priority for IEEE + * 8-bit 802.1p user priority bitmap for CEE * * ---- * Selector field values diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index c34af7a1d2d4..ca11d283bbeb 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -1776,7 +1776,7 @@ EXPORT_SYMBOL(dcb_getapp); * * Priority 0 is an invalid priority in CEE spec. This routine * removes applications from the app list if the priority is - * set to zero. + * set to zero. Priority is expected to be 8-bit 802.1p user priority bitmap */ int dcb_setapp(struct net_device *dev, struct dcb_app *new) { @@ -1837,7 +1837,8 @@ EXPORT_SYMBOL(dcb_ieee_getapp_mask); * * This adds Application data to the list. Multiple application * entries may exists for the same selector and protocol as long - * as the priorities are different. + * as the priorities are different. Priority is expected to be a + * 3-bit unsigned integer */ int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) { -- cgit v1.2.3 From 45a07695bc64b3ab5d6d2215f9677e5b8c05a7d0 Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Tue, 29 Jul 2014 12:07:27 +0200 Subject: tcp: Fix integer-overflows in TCP veno In veno we do a multiplication of the cwnd and the rtt. This may overflow and thus their result is stored in a u64. However, we first need to cast the cwnd so that actually 64-bit arithmetic is done. A first attempt at fixing 76f1017757aa0 ([TCP]: TCP Veno congestion control) was made by 159131149c2 (tcp: Overflow bug in Vegas), but it failed to add the required cast in tcp_veno_cong_avoid(). Fixes: 76f1017757aa0 ([TCP]: TCP Veno congestion control) Signed-off-by: Christoph Paasch Signed-off-by: David S. Miller --- net/ipv4/tcp_veno.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c index 27b9825753d1..8276977d2c85 100644 --- a/net/ipv4/tcp_veno.c +++ b/net/ipv4/tcp_veno.c @@ -144,7 +144,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked) rtt = veno->minrtt; - target_cwnd = (tp->snd_cwnd * veno->basertt); + target_cwnd = (u64)tp->snd_cwnd * veno->basertt; target_cwnd <<= V_PARAM_SHIFT; do_div(target_cwnd, rtt); -- cgit v1.2.3 From 1f74e613ded11517db90b2bd57e9464d9e0fb161 Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Tue, 29 Jul 2014 13:40:57 +0200 Subject: tcp: Fix integer-overflow in TCP vegas In vegas we do a multiplication of the cwnd and the rtt. This may overflow and thus their result is stored in a u64. However, we first need to cast the cwnd so that actually 64-bit arithmetic is done. Then, we need to do do_div to allow this to be used on 32-bit arches. Cc: Stephen Hemminger Cc: Neal Cardwell Cc: Eric Dumazet Cc: David Laight Cc: Doug Leith Fixes: 8d3a564da34e (tcp: tcp_vegas cong avoid fix) Signed-off-by: Christoph Paasch Signed-off-by: David S. Miller --- net/ipv4/tcp_vegas.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index 9a5e05f27f4f..b40ad897f945 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c @@ -218,7 +218,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) * This is: * (actual rate in segments) * baseRTT */ - target_cwnd = tp->snd_cwnd * vegas->baseRTT / rtt; + target_cwnd = (u64)tp->snd_cwnd * vegas->baseRTT; + do_div(target_cwnd, rtt); /* Calculate the difference between the window we had, * and the window we would like to have. This quantity -- cgit v1.2.3 From 80019d310f9fb4f8c9eeda0a5d76144ad3132fdf Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 30 Jul 2014 02:31:08 +0200 Subject: net: Remove unlikely() for WARN_ON() conditions No need for the unlikely(), WARN_ON() and BUG_ON() internally use unlikely() on the condition. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- net/openvswitch/datapath.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index e1b7cfaccd65..b370230fe1d3 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2326,7 +2326,7 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth) */ if (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) { if (vlan_depth) { - if (unlikely(WARN_ON(vlan_depth < VLAN_HLEN))) + if (WARN_ON(vlan_depth < VLAN_HLEN)) return 0; vlan_depth -= VLAN_HLEN; } else { diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 7ede507500d7..701b5738c38a 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -144,7 +144,7 @@ int lockdep_ovsl_is_held(void); #define lockdep_ovsl_is_held() 1 #endif -#define ASSERT_OVSL() WARN_ON(unlikely(!lockdep_ovsl_is_held())) +#define ASSERT_OVSL() WARN_ON(!lockdep_ovsl_is_held()) #define ovsl_dereference(p) \ rcu_dereference_protected(p, lockdep_ovsl_is_held()) #define rcu_dereference_ovsl(p) \ -- cgit v1.2.3 From 1a2a909bad464fc9ebdb03482049336fe2e7cbc8 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 29 Jul 2014 08:57:14 -0500 Subject: amd-xgbe: Add dma-coherent to device bindings documentation An earlier patch added support for the "dma-coherent" device property. This patch adds this optional property to the amd-xgbe device bindings documentation. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/amd-xgbe.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/net/amd-xgbe.txt b/Documentation/devicetree/bindings/net/amd-xgbe.txt index ea0c7908a3b8..f6db1ba87a3f 100644 --- a/Documentation/devicetree/bindings/net/amd-xgbe.txt +++ b/Documentation/devicetree/bindings/net/amd-xgbe.txt @@ -18,6 +18,7 @@ Required properties: Optional properties: - mac-address: mac address to be assigned to the device. Can be overridden by UEFI. +- dma-coherent: Present if dma operations are coherent Example: xgbe@e0700000 { -- cgit v1.2.3 From 23e4eef7cf56b5e36e76af9078f0012826c86b2f Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 29 Jul 2014 08:57:19 -0500 Subject: amd-xgbe: Add hardware timestamp support This patch adds support for Tx and Rx hardware timestamping. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/amd-xgbe.txt | 16 +- drivers/net/ethernet/amd/Kconfig | 1 + drivers/net/ethernet/amd/xgbe/Makefile | 3 +- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 71 ++++ drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 9 + drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 143 +++++++- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 372 ++++++++++++++++++--- drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 35 ++ drivers/net/ethernet/amd/xgbe/xgbe-main.c | 21 +- drivers/net/ethernet/amd/xgbe/xgbe-ptp.c | 285 ++++++++++++++++ drivers/net/ethernet/amd/xgbe/xgbe.h | 56 +++- 11 files changed, 954 insertions(+), 58 deletions(-) create mode 100644 drivers/net/ethernet/amd/xgbe/xgbe-ptp.c diff --git a/Documentation/devicetree/bindings/net/amd-xgbe.txt b/Documentation/devicetree/bindings/net/amd-xgbe.txt index f6db1ba87a3f..41354f730beb 100644 --- a/Documentation/devicetree/bindings/net/amd-xgbe.txt +++ b/Documentation/devicetree/bindings/net/amd-xgbe.txt @@ -8,10 +8,14 @@ Required properties: - interrupt-parent: Should be the phandle for the interrupt controller that services interrupts for this device - interrupts: Should contain the amd-xgbe interrupt -- clocks: Should be the DMA clock for the amd-xgbe device (used for - calculating the correct Rx interrupt watchdog timer value on a DMA - channel for coalescing) -- clock-names: Should be the name of the DMA clock, "dma_clk" +- clocks: + - DMA clock for the amd-xgbe device (used for calculating the + correct Rx interrupt watchdog timer value on a DMA channel + for coalescing) + - PTP clock for the amd-xgbe device +- clock-names: Should be the names of the clocks + - "dma_clk" for the DMA clock + - "ptp_clk" for the PTP clock - phy-handle: See ethernet.txt file in the same directory - phy-mode: See ethernet.txt file in the same directory @@ -27,8 +31,8 @@ Example: <0 0xe0780000 0 0x80000>; interrupt-parent = <&gic>; interrupts = <0 325 4>; - clocks = <&xgbe_clk>; - clock-names = "dma_clk"; + clocks = <&xgbe_dma_clk>, <&xgbe_ptp_clk>; + clock-names = "dma_clk", "ptp_clk"; phy-handle = <&phy>; phy-mode = "xgmii"; mac-address = [ 02 a1 a2 a3 a4 a5 ]; diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 6e314dbba805..98ef8ff8fa08 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -184,6 +184,7 @@ config AMD_XGBE select AMD_XGBE_PHY select BITREVERSE select CRC32 + select PTP_1588_CLOCK ---help--- This driver supports the AMD 10GbE Ethernet device found on an AMD SoC. diff --git a/drivers/net/ethernet/amd/xgbe/Makefile b/drivers/net/ethernet/amd/xgbe/Makefile index 26cf9af1642f..66c49b43e5f2 100644 --- a/drivers/net/ethernet/amd/xgbe/Makefile +++ b/drivers/net/ethernet/amd/xgbe/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_AMD_XGBE) += amd-xgbe.o amd-xgbe-objs := xgbe-main.o xgbe-drv.o xgbe-dev.o \ - xgbe-desc.o xgbe-ethtool.o xgbe-mdio.o + xgbe-desc.o xgbe-ethtool.o xgbe-mdio.o \ + xgbe-ptp.o amd-xgbe-$(CONFIG_DEBUG_FS) += xgbe-debugfs.o diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index 7ec80ac7043f..646702cd75fb 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -307,6 +307,16 @@ #define MAC_MACA0LR 0x0304 #define MAC_MACA1HR 0x0308 #define MAC_MACA1LR 0x030c +#define MAC_TSCR 0x0d00 +#define MAC_SSIR 0x0d04 +#define MAC_STSR 0x0d08 +#define MAC_STNR 0x0d0c +#define MAC_STSUR 0x0d10 +#define MAC_STNUR 0x0d14 +#define MAC_TSAR 0x0d18 +#define MAC_TSSR 0x0d20 +#define MAC_TXSNR 0x0d30 +#define MAC_TXSSR 0x0d34 #define MAC_QTFCR_INC 4 #define MAC_MACA_INC 4 @@ -373,12 +383,16 @@ #define MAC_HWF2R_TXCHCNT_WIDTH 4 #define MAC_HWF2R_TXQCNT_INDEX 6 #define MAC_HWF2R_TXQCNT_WIDTH 4 +#define MAC_IER_TSIE_INDEX 12 +#define MAC_IER_TSIE_WIDTH 1 #define MAC_ISR_MMCRXIS_INDEX 9 #define MAC_ISR_MMCRXIS_WIDTH 1 #define MAC_ISR_MMCTXIS_INDEX 10 #define MAC_ISR_MMCTXIS_WIDTH 1 #define MAC_ISR_PMTIS_INDEX 4 #define MAC_ISR_PMTIS_WIDTH 1 +#define MAC_ISR_TSIS_INDEX 12 +#define MAC_ISR_TSIS_WIDTH 1 #define MAC_MACA1HR_AE_INDEX 31 #define MAC_MACA1HR_AE_WIDTH 1 #define MAC_PFR_HMC_INDEX 2 @@ -423,10 +437,48 @@ #define MAC_RFCR_RFE_WIDTH 1 #define MAC_RQC0R_RXQ0EN_INDEX 0 #define MAC_RQC0R_RXQ0EN_WIDTH 2 +#define MAC_SSIR_SNSINC_INDEX 8 +#define MAC_SSIR_SNSINC_WIDTH 8 +#define MAC_SSIR_SSINC_INDEX 16 +#define MAC_SSIR_SSINC_WIDTH 8 #define MAC_TCR_SS_INDEX 29 #define MAC_TCR_SS_WIDTH 2 #define MAC_TCR_TE_INDEX 0 #define MAC_TCR_TE_WIDTH 1 +#define MAC_TSCR_AV8021ASMEN_INDEX 28 +#define MAC_TSCR_AV8021ASMEN_WIDTH 1 +#define MAC_TSCR_SNAPTYPSEL_INDEX 16 +#define MAC_TSCR_SNAPTYPSEL_WIDTH 2 +#define MAC_TSCR_TSADDREG_INDEX 5 +#define MAC_TSCR_TSADDREG_WIDTH 1 +#define MAC_TSCR_TSCFUPDT_INDEX 1 +#define MAC_TSCR_TSCFUPDT_WIDTH 1 +#define MAC_TSCR_TSCTRLSSR_INDEX 9 +#define MAC_TSCR_TSCTRLSSR_WIDTH 1 +#define MAC_TSCR_TSENA_INDEX 0 +#define MAC_TSCR_TSENA_WIDTH 1 +#define MAC_TSCR_TSENALL_INDEX 8 +#define MAC_TSCR_TSENALL_WIDTH 1 +#define MAC_TSCR_TSEVNTENA_INDEX 14 +#define MAC_TSCR_TSEVNTENA_WIDTH 1 +#define MAC_TSCR_TSINIT_INDEX 2 +#define MAC_TSCR_TSINIT_WIDTH 1 +#define MAC_TSCR_TSIPENA_INDEX 11 +#define MAC_TSCR_TSIPENA_WIDTH 1 +#define MAC_TSCR_TSIPV4ENA_INDEX 13 +#define MAC_TSCR_TSIPV4ENA_WIDTH 1 +#define MAC_TSCR_TSIPV6ENA_INDEX 12 +#define MAC_TSCR_TSIPV6ENA_WIDTH 1 +#define MAC_TSCR_TSMSTRENA_INDEX 15 +#define MAC_TSCR_TSMSTRENA_WIDTH 1 +#define MAC_TSCR_TSVER2ENA_INDEX 10 +#define MAC_TSCR_TSVER2ENA_WIDTH 1 +#define MAC_TSCR_TXTSSTSM_INDEX 24 +#define MAC_TSCR_TXTSSTSM_WIDTH 1 +#define MAC_TSSR_TXTSC_INDEX 15 +#define MAC_TSSR_TXTSC_WIDTH 1 +#define MAC_TXSNR_TXTSSTSMIS_INDEX 31 +#define MAC_TXSNR_TXTSSTSMIS_WIDTH 1 #define MAC_VLANHTR_VLHT_INDEX 0 #define MAC_VLANHTR_VLHT_WIDTH 16 #define MAC_VLANIR_VLTI_INDEX 20 @@ -778,9 +830,19 @@ #define RX_PACKET_ATTRIBUTES_VLAN_CTAG_WIDTH 1 #define RX_PACKET_ATTRIBUTES_INCOMPLETE_INDEX 2 #define RX_PACKET_ATTRIBUTES_INCOMPLETE_WIDTH 1 +#define RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_INDEX 3 +#define RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_WIDTH 1 +#define RX_PACKET_ATTRIBUTES_CONTEXT_INDEX 4 +#define RX_PACKET_ATTRIBUTES_CONTEXT_WIDTH 1 +#define RX_PACKET_ATTRIBUTES_RX_TSTAMP_INDEX 5 +#define RX_PACKET_ATTRIBUTES_RX_TSTAMP_WIDTH 1 #define RX_NORMAL_DESC0_OVT_INDEX 0 #define RX_NORMAL_DESC0_OVT_WIDTH 16 +#define RX_NORMAL_DESC3_CDA_INDEX 27 +#define RX_NORMAL_DESC3_CDA_WIDTH 1 +#define RX_NORMAL_DESC3_CTXT_INDEX 30 +#define RX_NORMAL_DESC3_CTXT_WIDTH 1 #define RX_NORMAL_DESC3_ES_INDEX 15 #define RX_NORMAL_DESC3_ES_WIDTH 1 #define RX_NORMAL_DESC3_ETLT_INDEX 16 @@ -794,12 +856,19 @@ #define RX_NORMAL_DESC3_PL_INDEX 0 #define RX_NORMAL_DESC3_PL_WIDTH 14 +#define RX_CONTEXT_DESC3_TSA_INDEX 4 +#define RX_CONTEXT_DESC3_TSA_WIDTH 1 +#define RX_CONTEXT_DESC3_TSD_INDEX 6 +#define RX_CONTEXT_DESC3_TSD_WIDTH 1 + #define TX_PACKET_ATTRIBUTES_CSUM_ENABLE_INDEX 0 #define TX_PACKET_ATTRIBUTES_CSUM_ENABLE_WIDTH 1 #define TX_PACKET_ATTRIBUTES_TSO_ENABLE_INDEX 1 #define TX_PACKET_ATTRIBUTES_TSO_ENABLE_WIDTH 1 #define TX_PACKET_ATTRIBUTES_VLAN_CTAG_INDEX 2 #define TX_PACKET_ATTRIBUTES_VLAN_CTAG_WIDTH 1 +#define TX_PACKET_ATTRIBUTES_PTP_INDEX 3 +#define TX_PACKET_ATTRIBUTES_PTP_WIDTH 1 #define TX_CONTEXT_DESC2_MSS_INDEX 0 #define TX_CONTEXT_DESC2_MSS_WIDTH 15 @@ -816,6 +885,8 @@ #define TX_NORMAL_DESC2_HL_B1L_WIDTH 14 #define TX_NORMAL_DESC2_IC_INDEX 31 #define TX_NORMAL_DESC2_IC_WIDTH 1 +#define TX_NORMAL_DESC2_TTSE_INDEX 30 +#define TX_NORMAL_DESC2_TTSE_WIDTH 1 #define TX_NORMAL_DESC2_VTIR_INDEX 14 #define TX_NORMAL_DESC2_VTIR_WIDTH 2 #define TX_NORMAL_DESC3_CIC_INDEX 16 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c index a9ce56d5e988..1c5d62e8dab6 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c @@ -359,6 +359,15 @@ static void xgbe_unmap_skb(struct xgbe_prv_data *pdata, rdata->len = 0; rdata->interrupt = 0; rdata->mapped_as_page = 0; + + if (rdata->state_saved) { + rdata->state_saved = 0; + rdata->state.incomplete = 0; + rdata->state.context_next = 0; + rdata->state.skb = NULL; + rdata->state.len = 0; + rdata->state.error = 0; + } } static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 699cff5d3184..098a7461db2d 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -131,7 +131,7 @@ static unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata, DBGPR("-->xgbe_usec_to_riwt\n"); - rate = clk_get_rate(pdata->sysclock); + rate = clk_get_rate(pdata->sysclk); /* * Convert the input usec value to the watchdog timer value. Each @@ -154,7 +154,7 @@ static unsigned int xgbe_riwt_to_usec(struct xgbe_prv_data *pdata, DBGPR("-->xgbe_riwt_to_usec\n"); - rate = clk_get_rate(pdata->sysclock); + rate = clk_get_rate(pdata->sysclk); /* * Convert the input watchdog timer value to the usec value. Each @@ -492,8 +492,12 @@ static void xgbe_enable_mtl_interrupts(struct xgbe_prv_data *pdata) static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata) { - /* No MAC interrupts to be enabled */ - XGMAC_IOWRITE(pdata, MAC_IER, 0); + unsigned int mac_ier = 0; + + /* Enable Timestamp interrupt */ + XGMAC_SET_BITS(mac_ier, MAC_IER, TSIE, 1); + + XGMAC_IOWRITE(pdata, MAC_IER, mac_ier); /* Enable all counter interrupts */ XGMAC_IOWRITE_BITS(pdata, MMC_RIER, ALL_INTERRUPTS, 0xff); @@ -1012,6 +1016,107 @@ static void xgbe_rx_desc_init(struct xgbe_channel *channel) DBGPR("<--rx_desc_init\n"); } +static void xgbe_update_tstamp_addend(struct xgbe_prv_data *pdata, + unsigned int addend) +{ + /* Set the addend register value and tell the device */ + XGMAC_IOWRITE(pdata, MAC_TSAR, addend); + XGMAC_IOWRITE_BITS(pdata, MAC_TSCR, TSADDREG, 1); + + /* Wait for addend update to complete */ + while (XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSADDREG)) + udelay(5); +} + +static void xgbe_set_tstamp_time(struct xgbe_prv_data *pdata, unsigned int sec, + unsigned int nsec) +{ + /* Set the time values and tell the device */ + XGMAC_IOWRITE(pdata, MAC_STSUR, sec); + XGMAC_IOWRITE(pdata, MAC_STNUR, nsec); + XGMAC_IOWRITE_BITS(pdata, MAC_TSCR, TSINIT, 1); + + /* Wait for time update to complete */ + while (XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSINIT)) + udelay(5); +} + +static u64 xgbe_get_tstamp_time(struct xgbe_prv_data *pdata) +{ + u64 nsec; + + nsec = XGMAC_IOREAD(pdata, MAC_STSR); + nsec *= NSEC_PER_SEC; + nsec += XGMAC_IOREAD(pdata, MAC_STNR); + + return nsec; +} + +static u64 xgbe_get_tx_tstamp(struct xgbe_prv_data *pdata) +{ + unsigned int tx_snr; + u64 nsec; + + tx_snr = XGMAC_IOREAD(pdata, MAC_TXSNR); + if (XGMAC_GET_BITS(tx_snr, MAC_TXSNR, TXTSSTSMIS)) + return 0; + + nsec = XGMAC_IOREAD(pdata, MAC_TXSSR); + nsec *= NSEC_PER_SEC; + nsec += tx_snr; + + return nsec; +} + +static void xgbe_get_rx_tstamp(struct xgbe_packet_data *packet, + struct xgbe_ring_desc *rdesc) +{ + u64 nsec; + + if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_CONTEXT_DESC3, TSA) && + !XGMAC_GET_BITS_LE(rdesc->desc3, RX_CONTEXT_DESC3, TSD)) { + nsec = le32_to_cpu(rdesc->desc1); + nsec <<= 32; + nsec |= le32_to_cpu(rdesc->desc0); + if (nsec != 0xffffffffffffffffULL) { + packet->rx_tstamp = nsec; + XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, + RX_TSTAMP, 1); + } + } +} + +static int xgbe_config_tstamp(struct xgbe_prv_data *pdata, + unsigned int mac_tscr) +{ + /* Set one nano-second accuracy */ + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCTRLSSR, 1); + + /* Set fine timestamp update */ + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCFUPDT, 1); + + /* Overwrite earlier timestamps */ + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TXTSSTSM, 1); + + XGMAC_IOWRITE(pdata, MAC_TSCR, mac_tscr); + + /* Exit if timestamping is not enabled */ + if (!XGMAC_GET_BITS(mac_tscr, MAC_TSCR, TSENA)) + return 0; + + /* Initialize time registers */ + XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SSINC, XGBE_TSTAMP_SSINC); + XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SNSINC, XGBE_TSTAMP_SNSINC); + xgbe_update_tstamp_addend(pdata, pdata->tstamp_addend); + xgbe_set_tstamp_time(pdata, 0, 0); + + /* Initialize the timecounter */ + timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, + ktime_to_ns(ktime_get_real())); + + return 0; +} + static void xgbe_pre_xmit(struct xgbe_channel *channel) { struct xgbe_prv_data *pdata = channel->pdata; @@ -1110,6 +1215,10 @@ static void xgbe_pre_xmit(struct xgbe_channel *channel) XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, VTIR, TX_NORMAL_DESC2_VLAN_INSERT); + /* Timestamp enablement check */ + if (XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, PTP)) + XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, TTSE, 1); + /* Set IC bit based on Tx coalescing settings */ XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 1); if (tx_coalesce && (!tx_frames || @@ -1245,6 +1354,25 @@ static int xgbe_dev_read(struct xgbe_channel *channel) xgbe_dump_rx_desc(ring, rdesc, ring->cur); #endif + if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, CTXT)) { + /* Timestamp Context Descriptor */ + xgbe_get_rx_tstamp(packet, rdesc); + + XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, + CONTEXT, 1); + XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, + CONTEXT_NEXT, 0); + return 0; + } + + /* Normal Descriptor, be sure Context Descriptor bit is off */ + XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, CONTEXT, 0); + + /* Indicate if a Context Descriptor is next */ + if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, CDA)) + XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, + CONTEXT_NEXT, 1); + /* Get the packet length */ rdata->len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL); @@ -2313,5 +2441,12 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) hw_if->rx_mmc_int = xgbe_rx_mmc_int; hw_if->read_mmc_stats = xgbe_read_mmc_stats; + /* For PTP config */ + hw_if->config_tstamp = xgbe_config_tstamp; + hw_if->update_tstamp_addend = xgbe_update_tstamp_addend; + hw_if->set_tstamp_time = xgbe_set_tstamp_time; + hw_if->get_tstamp_time = xgbe_get_tstamp_time; + hw_if->get_tx_tstamp = xgbe_get_tx_tstamp; + DBGPR("<--xgbe_init_function_ptrs\n"); } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 344e6b19ec0e..47a1e25b5609 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -121,6 +121,7 @@ #include #include #include +#include #include "xgbe.h" #include "xgbe-common.h" @@ -202,7 +203,7 @@ static irqreturn_t xgbe_isr(int irq, void *data) struct xgbe_hw_if *hw_if = &pdata->hw_if; struct xgbe_channel *channel; unsigned int dma_isr, dma_ch_isr; - unsigned int mac_isr; + unsigned int mac_isr, mac_tssr; unsigned int i; /* The DMA interrupt status register also reports MAC and MTL @@ -255,6 +256,17 @@ static irqreturn_t xgbe_isr(int irq, void *data) if (XGMAC_GET_BITS(mac_isr, MAC_ISR, MMCRXIS)) hw_if->rx_mmc_int(pdata); + + if (XGMAC_GET_BITS(mac_isr, MAC_ISR, TSIS)) { + mac_tssr = XGMAC_IOREAD(pdata, MAC_TSSR); + + if (XGMAC_GET_BITS(mac_tssr, MAC_TSSR, TXTSC)) { + /* Read Tx Timestamp to clear interrupt */ + pdata->tx_tstamp = + hw_if->get_tx_tstamp(pdata); + schedule_work(&pdata->tx_tstamp_work); + } + } } DBGPR(" DMA_ISR = %08x\n", XGMAC_IOREAD(pdata, DMA_ISR)); @@ -668,6 +680,197 @@ static void xgbe_restart(struct work_struct *work) rtnl_unlock(); } +static void xgbe_tx_tstamp(struct work_struct *work) +{ + struct xgbe_prv_data *pdata = container_of(work, + struct xgbe_prv_data, + tx_tstamp_work); + struct skb_shared_hwtstamps hwtstamps; + u64 nsec; + unsigned long flags; + + if (pdata->tx_tstamp) { + nsec = timecounter_cyc2time(&pdata->tstamp_tc, + pdata->tx_tstamp); + + memset(&hwtstamps, 0, sizeof(hwtstamps)); + hwtstamps.hwtstamp = ns_to_ktime(nsec); + skb_tstamp_tx(pdata->tx_tstamp_skb, &hwtstamps); + } + + dev_kfree_skb_any(pdata->tx_tstamp_skb); + + spin_lock_irqsave(&pdata->tstamp_lock, flags); + pdata->tx_tstamp_skb = NULL; + spin_unlock_irqrestore(&pdata->tstamp_lock, flags); +} + +static int xgbe_get_hwtstamp_settings(struct xgbe_prv_data *pdata, + struct ifreq *ifreq) +{ + if (copy_to_user(ifreq->ifr_data, &pdata->tstamp_config, + sizeof(pdata->tstamp_config))) + return -EFAULT; + + return 0; +} + +static int xgbe_set_hwtstamp_settings(struct xgbe_prv_data *pdata, + struct ifreq *ifreq) +{ + struct hwtstamp_config config; + unsigned int mac_tscr; + + if (copy_from_user(&config, ifreq->ifr_data, sizeof(config))) + return -EFAULT; + + if (config.flags) + return -EINVAL; + + mac_tscr = 0; + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + break; + + case HWTSTAMP_TX_ON: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); + break; + + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + break; + + case HWTSTAMP_FILTER_ALL: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENALL, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); + break; + + /* PTP v2, UDP, any kind of event packet */ + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1); + /* PTP v1, UDP, any kind of event packet */ + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, SNAPTYPSEL, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); + break; + + /* PTP v2, UDP, Sync packet */ + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1); + /* PTP v1, UDP, Sync packet */ + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSEVNTENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); + break; + + /* PTP v2, UDP, Delay_req packet */ + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1); + /* PTP v1, UDP, Delay_req packet */ + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSEVNTENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSMSTRENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); + break; + + /* 802.AS1, Ethernet, any kind of event packet */ + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, AV8021ASMEN, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, SNAPTYPSEL, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); + break; + + /* 802.AS1, Ethernet, Sync packet */ + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, AV8021ASMEN, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSEVNTENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); + break; + + /* 802.AS1, Ethernet, Delay_req packet */ + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, AV8021ASMEN, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSMSTRENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSEVNTENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); + break; + + /* PTP v2/802.AS1, any layer, any kind of event packet */ + case HWTSTAMP_FILTER_PTP_V2_EVENT: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, SNAPTYPSEL, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); + break; + + /* PTP v2/802.AS1, any layer, Sync packet */ + case HWTSTAMP_FILTER_PTP_V2_SYNC: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSEVNTENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); + break; + + /* PTP v2/802.AS1, any layer, Delay_req packet */ + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSMSTRENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSEVNTENA, 1); + XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); + break; + + default: + return -ERANGE; + } + + pdata->hw_if.config_tstamp(pdata, mac_tscr); + + memcpy(&pdata->tstamp_config, &config, sizeof(config)); + + return 0; +} + +static void xgbe_prep_tx_tstamp(struct xgbe_prv_data *pdata, + struct sk_buff *skb, + struct xgbe_packet_data *packet) +{ + unsigned long flags; + + if (XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, PTP)) { + spin_lock_irqsave(&pdata->tstamp_lock, flags); + if (pdata->tx_tstamp_skb) { + /* Another timestamp in progress, ignore this one */ + XGMAC_SET_BITS(packet->attributes, + TX_PACKET_ATTRIBUTES, PTP, 0); + } else { + pdata->tx_tstamp_skb = skb_get(skb); + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + } + spin_unlock_irqrestore(&pdata->tstamp_lock, flags); + } + + if (!XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, PTP)) + skb_tx_timestamp(skb); +} + static void xgbe_prep_vlan(struct sk_buff *skb, struct xgbe_packet_data *packet) { if (vlan_tx_tag_present(skb)) @@ -711,7 +914,8 @@ static int xgbe_is_tso(struct sk_buff *skb) return 1; } -static void xgbe_packet_info(struct xgbe_ring *ring, struct sk_buff *skb, +static void xgbe_packet_info(struct xgbe_prv_data *pdata, + struct xgbe_ring *ring, struct sk_buff *skb, struct xgbe_packet_data *packet) { struct skb_frag_struct *frag; @@ -753,6 +957,11 @@ static void xgbe_packet_info(struct xgbe_ring *ring, struct sk_buff *skb, VLAN_CTAG, 1); } + if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && + (pdata->tstamp_config.tx_type == HWTSTAMP_TX_ON)) + XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, + PTP, 1); + for (len = skb_headlen(skb); len;) { packet->rdesc_count++; len -= min_t(unsigned int, len, XGBE_TX_MAX_BUF_SIZE); @@ -776,26 +985,33 @@ static int xgbe_open(struct net_device *netdev) DBGPR("-->xgbe_open\n"); - /* Enable the clock */ - ret = clk_prepare_enable(pdata->sysclock); + /* Enable the clocks */ + ret = clk_prepare_enable(pdata->sysclk); if (ret) { - netdev_alert(netdev, "clk_prepare_enable failed\n"); + netdev_alert(netdev, "dma clk_prepare_enable failed\n"); return ret; } + ret = clk_prepare_enable(pdata->ptpclk); + if (ret) { + netdev_alert(netdev, "ptp clk_prepare_enable failed\n"); + goto err_sysclk; + } + /* Calculate the Rx buffer size before allocating rings */ ret = xgbe_calc_rx_buf_size(netdev, netdev->mtu); if (ret < 0) - goto err_clk; + goto err_ptpclk; pdata->rx_buf_size = ret; /* Allocate the ring descriptors and buffers */ ret = desc_if->alloc_ring_resources(pdata); if (ret) - goto err_clk; + goto err_ptpclk; - /* Initialize the device restart work struct */ + /* Initialize the device restart and Tx timestamp work struct */ INIT_WORK(&pdata->restart_work, xgbe_restart); + INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp); /* Request interrupts */ ret = devm_request_irq(pdata->dev, netdev->irq, xgbe_isr, 0, @@ -824,8 +1040,11 @@ err_start: err_irq: desc_if->free_ring_resources(pdata); -err_clk: - clk_disable_unprepare(pdata->sysclock); +err_ptpclk: + clk_disable_unprepare(pdata->ptpclk); + +err_sysclk: + clk_disable_unprepare(pdata->sysclk); return ret; } @@ -853,8 +1072,9 @@ static int xgbe_close(struct net_device *netdev) pdata->irq_number = 0; } - /* Disable the clock */ - clk_disable_unprepare(pdata->sysclock); + /* Disable the clocks */ + clk_disable_unprepare(pdata->ptpclk); + clk_disable_unprepare(pdata->sysclk); DBGPR("<--xgbe_close\n"); @@ -890,7 +1110,7 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) /* Calculate preliminary packet info */ memset(packet, 0, sizeof(*packet)); - xgbe_packet_info(ring, skb, packet); + xgbe_packet_info(pdata, ring, skb, packet); /* Check that there are enough descriptors available */ if (packet->rdesc_count > xgbe_tx_avail_desc(ring)) { @@ -914,6 +1134,8 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) goto tx_netdev_return; } + xgbe_prep_tx_tstamp(pdata, skb, packet); + /* Configure required descriptor fields for transmission */ hw_if->pre_xmit(channel); @@ -968,6 +1190,27 @@ static int xgbe_set_mac_address(struct net_device *netdev, void *addr) return 0; } +static int xgbe_ioctl(struct net_device *netdev, struct ifreq *ifreq, int cmd) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + int ret; + + switch (cmd) { + case SIOCGHWTSTAMP: + ret = xgbe_get_hwtstamp_settings(pdata, ifreq); + break; + + case SIOCSHWTSTAMP: + ret = xgbe_set_hwtstamp_settings(pdata, ifreq); + break; + + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + static int xgbe_change_mtu(struct net_device *netdev, int mtu) { struct xgbe_prv_data *pdata = netdev_priv(netdev); @@ -1109,6 +1352,7 @@ static const struct net_device_ops xgbe_netdev_ops = { .ndo_set_rx_mode = xgbe_set_rx_mode, .ndo_set_mac_address = xgbe_set_mac_address, .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = xgbe_ioctl, .ndo_change_mtu = xgbe_change_mtu, .ndo_get_stats64 = xgbe_get_stats64, .ndo_vlan_rx_add_vid = xgbe_vlan_rx_add_vid, @@ -1202,8 +1446,9 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) struct xgbe_packet_data *packet; struct net_device *netdev = pdata->netdev; struct sk_buff *skb; - unsigned int incomplete, error; - unsigned int cur_len, put_len, max_len; + struct skb_shared_hwtstamps *hwtstamps; + unsigned int incomplete, error, context_next, context; + unsigned int len, put_len, max_len; int received = 0; DBGPR("-->xgbe_rx_poll: budget=%d\n", budget); @@ -1212,22 +1457,33 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) if (!ring) return 0; + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); packet = &ring->packet_data; while (received < budget) { DBGPR(" cur = %d\n", ring->cur); - /* Clear the packet data information */ - memset(packet, 0, sizeof(*packet)); - skb = NULL; - error = 0; - cur_len = 0; + /* First time in loop see if we need to restore state */ + if (!received && rdata->state_saved) { + incomplete = rdata->state.incomplete; + context_next = rdata->state.context_next; + skb = rdata->state.skb; + error = rdata->state.error; + len = rdata->state.len; + } else { + memset(packet, 0, sizeof(*packet)); + incomplete = 0; + context_next = 0; + skb = NULL; + error = 0; + len = 0; + } read_again: + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); + if (ring->dirty > (XGBE_RX_DESC_CNT >> 3)) xgbe_rx_refresh(channel); - rdata = XGBE_GET_DESC_DATA(ring, ring->cur); - if (hw_if->dev_read(channel)) break; @@ -1242,9 +1498,15 @@ read_again: incomplete = XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, INCOMPLETE); + context_next = XGMAC_GET_BITS(packet->attributes, + RX_PACKET_ATTRIBUTES, + CONTEXT_NEXT); + context = XGMAC_GET_BITS(packet->attributes, + RX_PACKET_ATTRIBUTES, + CONTEXT); /* Earlier error, just drain the remaining data */ - if (incomplete && error) + if ((incomplete || context_next) && error) goto read_again; if (error || packet->errors) { @@ -1254,30 +1516,37 @@ read_again: continue; } - put_len = rdata->len - cur_len; - if (skb) { - if (pskb_expand_head(skb, 0, put_len, GFP_ATOMIC)) { - DBGPR("pskb_expand_head error\n"); - if (incomplete) { - error = 1; - goto read_again; + if (!context) { + put_len = rdata->len - len; + if (skb) { + if (pskb_expand_head(skb, 0, put_len, + GFP_ATOMIC)) { + DBGPR("pskb_expand_head error\n"); + if (incomplete) { + error = 1; + goto read_again; + } + + dev_kfree_skb(skb); + continue; } - - dev_kfree_skb(skb); - continue; + memcpy(skb_tail_pointer(skb), rdata->skb->data, + put_len); + } else { + skb = rdata->skb; + rdata->skb = NULL; } - memcpy(skb_tail_pointer(skb), rdata->skb->data, - put_len); - } else { - skb = rdata->skb; - rdata->skb = NULL; + skb_put(skb, put_len); + len += put_len; } - skb_put(skb, put_len); - cur_len += put_len; - if (incomplete) + if (incomplete || context_next) goto read_again; + /* Stray Context Descriptor? */ + if (!skb) + continue; + /* Be sure we don't exceed the configured MTU */ max_len = netdev->mtu + ETH_HLEN; if (!(netdev->features & NETIF_F_HW_VLAN_CTAG_RX) && @@ -1304,6 +1573,16 @@ read_again: __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), packet->vlan_ctag); + if (XGMAC_GET_BITS(packet->attributes, + RX_PACKET_ATTRIBUTES, RX_TSTAMP)) { + u64 nsec; + + nsec = timecounter_cyc2time(&pdata->tstamp_tc, + packet->rx_tstamp); + hwtstamps = skb_hwtstamps(skb); + hwtstamps->hwtstamp = ns_to_ktime(nsec); + } + skb->dev = netdev; skb->protocol = eth_type_trans(skb, netdev); skb_record_rx_queue(skb, channel->queue_index); @@ -1313,6 +1592,17 @@ read_again: napi_gro_receive(&pdata->napi, skb); } + /* Check if we need to save state before leaving */ + if (received && (incomplete || context_next)) { + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); + rdata->state_saved = 1; + rdata->state.incomplete = incomplete; + rdata->state.context_next = context_next; + rdata->state.skb = skb; + rdata->state.len = len; + rdata->state.error = error; + } + DBGPR("<--xgbe_rx_poll: received = %d\n", received); return received; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index f7405261f23e..4961666fa55f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -116,6 +116,7 @@ #include #include +#include #include "xgbe.h" #include "xgbe-common.h" @@ -480,6 +481,39 @@ static int xgbe_set_coalesce(struct net_device *netdev, return 0; } +static int xgbe_get_ts_info(struct net_device *netdev, + struct ethtool_ts_info *ts_info) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + + ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + if (pdata->ptp_clock) + ts_info->phc_index = ptp_clock_index(pdata->ptp_clock); + else + ts_info->phc_index = -1; + + ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); + ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_ALL); + + return 0; +} + static const struct ethtool_ops xgbe_ethtool_ops = { .get_settings = xgbe_get_settings, .set_settings = xgbe_set_settings, @@ -492,6 +526,7 @@ static const struct ethtool_ops xgbe_ethtool_ops = { .get_strings = xgbe_get_strings, .get_ethtool_stats = xgbe_get_ethtool_stats, .get_sset_count = xgbe_get_sset_count, + .get_ts_info = xgbe_get_ts_info, }; struct ethtool_ops *xgbe_get_ethtool_ops(void) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index e56c3d45b30e..ca6a6af00f9f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -245,6 +245,7 @@ static int xgbe_probe(struct platform_device *pdev) spin_lock_init(&pdata->lock); mutex_init(&pdata->xpcs_mutex); + spin_lock_init(&pdata->tstamp_lock); /* Set and validate the number of descriptors for a ring */ BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT); @@ -265,10 +266,18 @@ static int xgbe_probe(struct platform_device *pdev) } /* Obtain the system clock setting */ - pdata->sysclock = devm_clk_get(dev, NULL); - if (IS_ERR(pdata->sysclock)) { - dev_err(dev, "devm_clk_get failed\n"); - ret = PTR_ERR(pdata->sysclock); + pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK); + if (IS_ERR(pdata->sysclk)) { + dev_err(dev, "dma devm_clk_get failed\n"); + ret = PTR_ERR(pdata->sysclk); + goto err_io; + } + + /* Obtain the PTP clock setting */ + pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK); + if (IS_ERR(pdata->ptpclk)) { + dev_err(dev, "ptp devm_clk_get failed\n"); + ret = PTR_ERR(pdata->ptpclk); goto err_io; } @@ -420,6 +429,8 @@ static int xgbe_probe(struct platform_device *pdev) goto err_reg_netdev; } + xgbe_ptp_register(pdata); + xgbe_debugfs_init(pdata); netdev_notice(netdev, "net device enabled\n"); @@ -452,6 +463,8 @@ static int xgbe_remove(struct platform_device *pdev) xgbe_debugfs_exit(pdata); + xgbe_ptp_unregister(pdata); + unregister_netdev(netdev); xgbe_mdio_unregister(pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c new file mode 100644 index 000000000000..37e64cfa5718 --- /dev/null +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c @@ -0,0 +1,285 @@ +/* + * AMD 10Gb Ethernet driver + * + * This file is available to you under your choice of the following two + * licenses: + * + * License 1: GPLv2 + * + * Copyright (c) 2014 Advanced Micro Devices, Inc. + * + * This file is free software; you may copy, redistribute 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 file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * The Synopsys DWC ETHER XGMAC Software Driver and documentation + * (hereinafter "Software") is an unsupported proprietary work of Synopsys, + * Inc. unless otherwise expressly agreed to in writing between Synopsys + * and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product + * under any End User Software License Agreement or Agreement for Licensed + * Product with Synopsys or any supplement thereto. Permission is hereby + * granted, free of charge, to any person obtaining a copy of this software + * annotated with this license and the Software, to deal in the Software + * without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * + * License 2: Modified BSD + * + * Copyright (c) 2014 Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Advanced Micro Devices, Inc. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * The Synopsys DWC ETHER XGMAC Software Driver and documentation + * (hereinafter "Software") is an unsupported proprietary work of Synopsys, + * Inc. unless otherwise expressly agreed to in writing between Synopsys + * and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product + * under any End User Software License Agreement or Agreement for Licensed + * Product with Synopsys or any supplement thereto. Permission is hereby + * granted, free of charge, to any person obtaining a copy of this software + * annotated with this license and the Software, to deal in the Software + * without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "xgbe.h" +#include "xgbe-common.h" + + +static cycle_t xgbe_cc_read(const struct cyclecounter *cc) +{ + struct xgbe_prv_data *pdata = container_of(cc, + struct xgbe_prv_data, + tstamp_cc); + u64 nsec; + + nsec = pdata->hw_if.get_tstamp_time(pdata); + + return nsec; +} + +static int xgbe_adjfreq(struct ptp_clock_info *info, s32 delta) +{ + struct xgbe_prv_data *pdata = container_of(info, + struct xgbe_prv_data, + ptp_clock_info); + unsigned long flags; + u64 adjust; + u32 addend, diff; + unsigned int neg_adjust = 0; + + if (delta < 0) { + neg_adjust = 1; + delta = -delta; + } + + adjust = pdata->tstamp_addend; + adjust *= delta; + diff = div_u64(adjust, 1000000000UL); + + addend = (neg_adjust) ? pdata->tstamp_addend - diff : + pdata->tstamp_addend + diff; + + spin_lock_irqsave(&pdata->tstamp_lock, flags); + + pdata->hw_if.update_tstamp_addend(pdata, addend); + + spin_unlock_irqrestore(&pdata->tstamp_lock, flags); + + return 0; +} + +static int xgbe_adjtime(struct ptp_clock_info *info, s64 delta) +{ + struct xgbe_prv_data *pdata = container_of(info, + struct xgbe_prv_data, + ptp_clock_info); + unsigned long flags; + u64 nsec; + + spin_lock_irqsave(&pdata->tstamp_lock, flags); + + nsec = timecounter_read(&pdata->tstamp_tc); + + nsec += delta; + timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec); + + spin_unlock_irqrestore(&pdata->tstamp_lock, flags); + + return 0; +} + +static int xgbe_gettime(struct ptp_clock_info *info, struct timespec *ts) +{ + struct xgbe_prv_data *pdata = container_of(info, + struct xgbe_prv_data, + ptp_clock_info); + unsigned long flags; + u64 nsec; + + spin_lock_irqsave(&pdata->tstamp_lock, flags); + + nsec = timecounter_read(&pdata->tstamp_tc); + + spin_unlock_irqrestore(&pdata->tstamp_lock, flags); + + *ts = ns_to_timespec(nsec); + + return 0; +} + +static int xgbe_settime(struct ptp_clock_info *info, const struct timespec *ts) +{ + struct xgbe_prv_data *pdata = container_of(info, + struct xgbe_prv_data, + ptp_clock_info); + unsigned long flags; + u64 nsec; + + nsec = timespec_to_ns(ts); + + spin_lock_irqsave(&pdata->tstamp_lock, flags); + + timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec); + + spin_unlock_irqrestore(&pdata->tstamp_lock, flags); + + return 0; +} + +static int xgbe_enable(struct ptp_clock_info *info, + struct ptp_clock_request *request, int on) +{ + return -EOPNOTSUPP; +} + +void xgbe_ptp_register(struct xgbe_prv_data *pdata) +{ + struct ptp_clock_info *info = &pdata->ptp_clock_info; + struct ptp_clock *clock; + struct cyclecounter *cc = &pdata->tstamp_cc; + u64 dividend; + + snprintf(info->name, sizeof(info->name), "%s", + netdev_name(pdata->netdev)); + info->owner = THIS_MODULE; + info->max_adj = clk_get_rate(pdata->ptpclk); + info->adjfreq = xgbe_adjfreq; + info->adjtime = xgbe_adjtime; + info->gettime = xgbe_gettime; + info->settime = xgbe_settime; + info->enable = xgbe_enable; + + clock = ptp_clock_register(info, pdata->dev); + if (IS_ERR(clock)) { + dev_err(pdata->dev, "ptp_clock_register failed\n"); + return; + } + + pdata->ptp_clock = clock; + + /* Calculate the addend: + * addend = 2^32 / (PTP ref clock / 50Mhz) + * = (2^32 * 50Mhz) / PTP ref clock + */ + dividend = 50000000; + dividend <<= 32; + pdata->tstamp_addend = div_u64(dividend, clk_get_rate(pdata->ptpclk)); + + /* Setup the timecounter */ + cc->read = xgbe_cc_read; + cc->mask = CLOCKSOURCE_MASK(64); + cc->mult = 1; + cc->shift = 0; + + timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, + ktime_to_ns(ktime_get_real())); + + /* Disable all timestamping to start */ + XGMAC_IOWRITE(pdata, MAC_TCR, 0); + pdata->tstamp_config.tx_type = HWTSTAMP_TX_OFF; + pdata->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; +} + +void xgbe_ptp_unregister(struct xgbe_prv_data *pdata) +{ + if (pdata->ptp_clock) + ptp_clock_unregister(pdata->ptp_clock); +} diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 9e24b296e272..8b6ad3e82c34 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -123,6 +123,9 @@ #include #include #include +#include +#include +#include #define XGBE_DRV_NAME "amd-xgbe" @@ -164,6 +167,16 @@ #define XGBE_PHY_NAME "amd_xgbe_phy" #define XGBE_PRTAD 0 +/* Device-tree clock names */ +#define XGBE_DMA_CLOCK "dma_clk" +#define XGBE_PTP_CLOCK "ptp_clk" + +/* Timestamp support - values based on 50MHz PTP clock + * 50MHz => 20 nsec + */ +#define XGBE_TSTAMP_SSINC 20 +#define XGBE_TSTAMP_SNSINC 0 + /* Driver PMT macros */ #define XGMAC_DRIVER_CONTEXT 1 #define XGMAC_IOCTL_CONTEXT 2 @@ -214,6 +227,8 @@ struct xgbe_packet_data { unsigned short mss; unsigned short vlan_ctag; + + u64 rx_tstamp; }; /* Common Rx and Tx descriptor mapping */ @@ -242,6 +257,20 @@ struct xgbe_ring_data { unsigned int interrupt; /* Interrupt indicator */ unsigned int mapped_as_page; + + /* Incomplete receive save location. If the budget is exhausted + * or the last descriptor (last normal descriptor or a following + * context descriptor) has not been DMA'd yet the current state + * of the receive processing needs to be saved. + */ + unsigned int state_saved; + struct { + unsigned int incomplete; + unsigned int context_next; + struct sk_buff *skb; + unsigned int len; + unsigned int error; + } state; }; struct xgbe_ring { @@ -467,6 +496,14 @@ struct xgbe_hw_if { void (*rx_mmc_int)(struct xgbe_prv_data *); void (*tx_mmc_int)(struct xgbe_prv_data *); void (*read_mmc_stats)(struct xgbe_prv_data *); + + /* For Timestamp config */ + int (*config_tstamp)(struct xgbe_prv_data *, unsigned int); + void (*update_tstamp_addend)(struct xgbe_prv_data *, unsigned int); + void (*set_tstamp_time)(struct xgbe_prv_data *, unsigned int sec, + unsigned int nsec); + u64 (*get_tstamp_time)(struct xgbe_prv_data *); + u64 (*get_tx_tstamp)(struct xgbe_prv_data *); }; struct xgbe_desc_if { @@ -607,8 +644,21 @@ struct xgbe_prv_data { /* Filtering support */ unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; - /* System clock value used for Rx watchdog */ - struct clk *sysclock; + /* Device clocks */ + struct clk *sysclk; + struct clk *ptpclk; + + /* Timestamp support */ + spinlock_t tstamp_lock; + struct ptp_clock_info ptp_clock_info; + struct ptp_clock *ptp_clock; + struct hwtstamp_config tstamp_config; + struct cyclecounter tstamp_cc; + struct timecounter tstamp_tc; + unsigned int tstamp_addend; + struct work_struct tx_tstamp_work; + struct sk_buff *tx_tstamp_skb; + u64 tx_tstamp; /* Hardware features of the device */ struct xgbe_hw_features hw_feat; @@ -639,6 +689,8 @@ struct ethtool_ops *xgbe_get_ethtool_ops(void); int xgbe_mdio_register(struct xgbe_prv_data *); void xgbe_mdio_unregister(struct xgbe_prv_data *); void xgbe_dump_phy_registers(struct xgbe_prv_data *); +void xgbe_ptp_register(struct xgbe_prv_data *); +void xgbe_ptp_unregister(struct xgbe_prv_data *); void xgbe_dump_tx_desc(struct xgbe_ring *, unsigned int, unsigned int, unsigned int); void xgbe_dump_rx_desc(struct xgbe_ring *, struct xgbe_ring_desc *, -- cgit v1.2.3 From f047604a3ff1a1d7c8bd4a43c72de3936d71f3c1 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 29 Jul 2014 08:57:25 -0500 Subject: amd-xgbe: Update/fix 2.5GbE support Update the amd-xgbe driver and phylib driver to better support the 2.5GbE mode for the hardware. In order to be able establish 2.5GbE using clause 73 auto negotiation the device will support speed sets of 1GbE/10GbE and 2.5GbE/10GbE. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- .../devicetree/bindings/net/amd-xgbe-phy.txt | 6 ++ drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 17 +++- drivers/net/phy/amd-xgbe-phy.c | 92 ++++++++++++++++++---- 3 files changed, 96 insertions(+), 19 deletions(-) diff --git a/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt b/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt index d01ed63d3ebb..42409bfe04c4 100644 --- a/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt +++ b/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt @@ -8,10 +8,16 @@ Required properties: - SerDes integration registers (1/2) - SerDes integration registers (2/2) +Optional properties: +- amd,speed-set: Speed capabilities of the device + 0 - 1GbE and 10GbE (default) + 1 - 2.5GbE and 10GbE + Example: xgbe_phy@e1240800 { compatible = "amd,xgbe-phy-seattle-v1a", "ethernet-phy-ieee802.3-c45"; reg = <0 0xe1240800 0 0x00400>, <0 0xe1250000 0 0x00060>, <0 0xe1250080 0 0x00004>; + amd,speed-set = <0>; }; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index 4961666fa55f..6005b6021f78 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -327,10 +327,19 @@ static int xgbe_set_settings(struct net_device *netdev, (cmd->autoneg != AUTONEG_DISABLE)) goto unlock; - if ((cmd->autoneg == AUTONEG_DISABLE) && - (((speed != SPEED_10000) && (speed != SPEED_1000)) || - (cmd->duplex != DUPLEX_FULL))) - goto unlock; + if (cmd->autoneg == AUTONEG_DISABLE) { + switch (speed) { + case SPEED_10000: + case SPEED_2500: + case SPEED_1000: + break; + default: + goto unlock; + } + + if (cmd->duplex != DUPLEX_FULL) + goto unlock; + } cmd->advertising &= phydev->supported; if ((cmd->autoneg == AUTONEG_ENABLE) && !cmd->advertising) diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index b57c22442867..b35293da9f87 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -74,7 +74,6 @@ #include #include #include -#include MODULE_AUTHOR("Tom Lendacky "); @@ -85,6 +84,8 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define XGBE_PHY_ID 0x000162d0 #define XGBE_PHY_MASK 0xfffffff0 +#define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set" + #define XGBE_AN_INT_CMPLT 0x01 #define XGBE_AN_INC_LINK 0x02 #define XGBE_AN_PG_RCV 0x04 @@ -145,7 +146,7 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define SPEED_2500_CDR 0x2 #define SPEED_2500_PLL 0x0 -#define SPEED_2500_RATE 0x2 +#define SPEED_2500_RATE 0x1 #define SPEED_2500_TXAMP 0xf #define SPEED_2500_WORD 0x1 @@ -292,6 +293,11 @@ enum amd_xgbe_phy_mode { AMD_XGBE_MODE_KX, }; +enum amd_xgbe_phy_speedset { + AMD_XGBE_PHY_SPEEDSET_1000_10000, + AMD_XGBE_PHY_SPEEDSET_2500_10000, +}; + struct amd_xgbe_phy_priv { struct platform_device *pdev; struct device *dev; @@ -311,6 +317,7 @@ struct amd_xgbe_phy_priv { /* Maintain link status for re-starting auto-negotiation */ unsigned int link; enum amd_xgbe_phy_mode mode; + unsigned int speed_set; /* Auto-negotiation state machine support */ struct mutex an_mutex; @@ -546,10 +553,14 @@ static int amd_xgbe_phy_switch_mode(struct phy_device *phydev) int ret; /* If we are in KR switch to KX, and vice-versa */ - if (priv->mode == AMD_XGBE_MODE_KR) - ret = amd_xgbe_phy_gmii_mode(phydev); - else + if (priv->mode == AMD_XGBE_MODE_KR) { + if (priv->speed_set == AMD_XGBE_PHY_SPEEDSET_1000_10000) + ret = amd_xgbe_phy_gmii_mode(phydev); + else + ret = amd_xgbe_phy_gmii_2500_mode(phydev); + } else { ret = amd_xgbe_phy_xgmii_mode(phydev); + } return ret; } @@ -713,7 +724,8 @@ static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev) else ret &= ~0x80; - if (phydev->supported & SUPPORTED_1000baseKX_Full) + if ((phydev->supported & SUPPORTED_1000baseKX_Full) || + (phydev->supported & SUPPORTED_2500baseX_Full)) ret |= 0x20; else ret &= ~0x20; @@ -896,14 +908,22 @@ static int amd_xgbe_phy_soft_reset(struct phy_device *phydev) static int amd_xgbe_phy_config_init(struct phy_device *phydev) { + struct amd_xgbe_phy_priv *priv = phydev->priv; + /* Initialize supported features */ phydev->supported = SUPPORTED_Autoneg; phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; phydev->supported |= SUPPORTED_Backplane; - phydev->supported |= SUPPORTED_1000baseKX_Full | - SUPPORTED_2500baseX_Full; phydev->supported |= SUPPORTED_10000baseKR_Full | SUPPORTED_10000baseR_FEC; + switch (priv->speed_set) { + case AMD_XGBE_PHY_SPEEDSET_1000_10000: + phydev->supported |= SUPPORTED_1000baseKX_Full; + break; + case AMD_XGBE_PHY_SPEEDSET_2500_10000: + phydev->supported |= SUPPORTED_2500baseX_Full; + break; + } phydev->advertising = phydev->supported; /* Turn off and clear interrupts */ @@ -1020,9 +1040,9 @@ static int amd_xgbe_phy_update_link(struct phy_device *phydev) * (re-)established (cable connected after the interface is * up, etc.), the link status may report no link. If there * is no link, try switching modes and checking the status - * again. + * again if auto negotiation is enabled. */ - check_again = 1; + check_again = (phydev->autoneg == AUTONEG_ENABLE) ? 1 : 0; again: /* Link status is latched low, so read once to clear * and then read again to get current state @@ -1038,8 +1058,10 @@ again: phydev->link = (ret & MDIO_STAT1_LSTATUS) ? 1 : 0; if (!phydev->link) { - ret = amd_xgbe_phy_switch_mode(phydev); if (check_again) { + ret = amd_xgbe_phy_switch_mode(phydev); + if (ret < 0) + return ret; check_again = 0; goto again; } @@ -1059,6 +1081,7 @@ again: static int amd_xgbe_phy_read_status(struct phy_device *phydev) { + struct amd_xgbe_phy_priv *priv = phydev->priv; u32 mmd_mask = phydev->c45_ids.devices_in_package; int ret, mode, ad_ret, lp_ret; @@ -1108,9 +1131,19 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev) return ret; } } else { - phydev->speed = SPEED_1000; + int (*mode_fcn)(struct phy_device *); + + if (priv->speed_set == + AMD_XGBE_PHY_SPEEDSET_1000_10000) { + phydev->speed = SPEED_1000; + mode_fcn = amd_xgbe_phy_gmii_mode; + } else { + phydev->speed = SPEED_2500; + mode_fcn = amd_xgbe_phy_gmii_2500_mode; + } + if (mode == MDIO_PCS_CTRL2_10GBR) { - ret = amd_xgbe_phy_gmii_mode(phydev); + ret = mode_fcn(phydev); if (ret < 0) return ret; } @@ -1118,8 +1151,15 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev) phydev->duplex = DUPLEX_FULL; } else { - phydev->speed = (mode == MDIO_PCS_CTRL2_10GBR) ? SPEED_10000 - : SPEED_1000; + if (mode == MDIO_PCS_CTRL2_10GBR) { + phydev->speed = SPEED_10000; + } else { + if (priv->speed_set == + AMD_XGBE_PHY_SPEEDSET_1000_10000) + phydev->speed = SPEED_1000; + else + phydev->speed = SPEED_2500; + } phydev->duplex = DUPLEX_FULL; phydev->pause = 0; phydev->asym_pause = 0; @@ -1176,6 +1216,8 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) struct platform_device *pdev; struct device *dev; char *wq_name; + const __be32 *property; + unsigned int speed_set; int ret; if (!phydev->dev.of_node) @@ -1227,6 +1269,26 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) goto err_sir0; } + /* Get the device speed set property */ + speed_set = 0; + property = of_get_property(dev->of_node, XGBE_PHY_SPEEDSET_PROPERTY, + NULL); + if (property) + speed_set = be32_to_cpu(*property); + + switch (speed_set) { + case 0: + priv->speed_set = AMD_XGBE_PHY_SPEEDSET_1000_10000; + break; + case 1: + priv->speed_set = AMD_XGBE_PHY_SPEEDSET_2500_10000; + break; + default: + dev_err(dev, "invalid amd,speed-set property\n"); + ret = -EINVAL; + goto err_sir1; + } + priv->link = 1; ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); -- cgit v1.2.3 From 853eb16b8b6a347315443f2ef010e5b97d8c1577 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 29 Jul 2014 08:57:31 -0500 Subject: amd-xgbe: Base queue fifo size and enablement on ring count When setting the fifo sizes for the queues and enabling the queues use the number of active Tx and Rx queues that have been enabled not the maximum number available. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 42 +++++++++++++++---------------- drivers/net/ethernet/amd/xgbe/xgbe-main.c | 10 +++++++- drivers/net/ethernet/amd/xgbe/xgbe.h | 3 +++ 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 098a7461db2d..2cdf34f6139f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -247,7 +247,7 @@ static int xgbe_config_rsf_mode(struct xgbe_prv_data *pdata, unsigned int val) { unsigned int i; - for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++) + for (i = 0; i < pdata->rx_q_count; i++) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RSF, val); return 0; @@ -257,7 +257,7 @@ static int xgbe_config_tsf_mode(struct xgbe_prv_data *pdata, unsigned int val) { unsigned int i; - for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++) + for (i = 0; i < pdata->tx_q_count; i++) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TSF, val); return 0; @@ -268,7 +268,7 @@ static int xgbe_config_rx_threshold(struct xgbe_prv_data *pdata, { unsigned int i; - for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++) + for (i = 0; i < pdata->rx_q_count; i++) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RTC, val); return 0; @@ -279,7 +279,7 @@ static int xgbe_config_tx_threshold(struct xgbe_prv_data *pdata, { unsigned int i; - for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++) + for (i = 0; i < pdata->tx_q_count; i++) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TTC, val); return 0; @@ -343,12 +343,12 @@ static int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata) unsigned int i; /* Clear MTL flow control */ - for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++) + for (i = 0; i < pdata->rx_q_count; i++) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 0); /* Clear MAC flow control */ max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES; - q_count = min_t(unsigned int, pdata->hw_feat.rx_q_cnt, max_q_count); + q_count = min_t(unsigned int, pdata->rx_q_count, max_q_count); reg = MAC_Q0TFCR; for (i = 0; i < q_count; i++) { reg_val = XGMAC_IOREAD(pdata, reg); @@ -368,12 +368,12 @@ static int xgbe_enable_tx_flow_control(struct xgbe_prv_data *pdata) unsigned int i; /* Set MTL flow control */ - for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++) + for (i = 0; i < pdata->rx_q_count; i++) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 1); /* Set MAC flow control */ max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES; - q_count = min_t(unsigned int, pdata->hw_feat.rx_q_cnt, max_q_count); + q_count = min_t(unsigned int, pdata->rx_q_count, max_q_count); reg = MAC_Q0TFCR; for (i = 0; i < q_count; i++) { reg_val = XGMAC_IOREAD(pdata, reg); @@ -1551,11 +1551,11 @@ static int xgbe_flush_tx_queues(struct xgbe_prv_data *pdata) { unsigned int i, count; - for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++) + for (i = 0; i < pdata->tx_q_count; i++) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, FTQ, 1); /* Poll Until Poll Condition */ - for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++) { + for (i = 0; i < pdata->tx_q_count; i++) { count = 2000; while (count-- && XGMAC_MTL_IOREAD_BITS(pdata, i, MTL_Q_TQOMR, FTQ)) @@ -1700,13 +1700,13 @@ static void xgbe_config_tx_fifo_size(struct xgbe_prv_data *pdata) unsigned int i; fifo_size = xgbe_calculate_per_queue_fifo(pdata->hw_feat.tx_fifo_size, - pdata->hw_feat.tx_q_cnt); + pdata->tx_q_count); - for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++) + for (i = 0; i < pdata->tx_q_count; i++) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TQS, fifo_size); netdev_notice(pdata->netdev, "%d Tx queues, %d byte fifo per queue\n", - pdata->hw_feat.tx_q_cnt, ((fifo_size + 1) * 256)); + pdata->tx_q_count, ((fifo_size + 1) * 256)); } static void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata) @@ -1715,19 +1715,19 @@ static void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata) unsigned int i; fifo_size = xgbe_calculate_per_queue_fifo(pdata->hw_feat.rx_fifo_size, - pdata->hw_feat.rx_q_cnt); + pdata->rx_q_count); - for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++) + for (i = 0; i < pdata->rx_q_count; i++) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RQS, fifo_size); netdev_notice(pdata->netdev, "%d Rx queues, %d byte fifo per queue\n", - pdata->hw_feat.rx_q_cnt, ((fifo_size + 1) * 256)); + pdata->rx_q_count, ((fifo_size + 1) * 256)); } static void xgbe_config_rx_queue_mapping(struct xgbe_prv_data *pdata) { unsigned int i, reg, reg_val; - unsigned int q_count = pdata->hw_feat.rx_q_cnt; + unsigned int q_count = pdata->rx_q_count; /* Select dynamic mapping of MTL Rx queue to DMA Rx channel */ reg = MTL_RQDCM0R; @@ -1749,7 +1749,7 @@ static void xgbe_config_flow_control_threshold(struct xgbe_prv_data *pdata) { unsigned int i; - for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++) { + for (i = 0; i < pdata->rx_q_count; i++) { /* Activate flow control when less than 4k left in fifo */ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RFA, 2); @@ -2141,7 +2141,7 @@ static void xgbe_enable_tx(struct xgbe_prv_data *pdata) } /* Enable each Tx queue */ - for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++) + for (i = 0; i < pdata->tx_q_count; i++) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TXQEN, MTL_Q_ENABLED); @@ -2158,7 +2158,7 @@ static void xgbe_disable_tx(struct xgbe_prv_data *pdata) XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 0); /* Disable each Tx queue */ - for (i = 0; i < pdata->hw_feat.tx_q_cnt; i++) + for (i = 0; i < pdata->tx_q_count; i++) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TXQEN, 0); /* Disable each Tx DMA channel */ @@ -2187,7 +2187,7 @@ static void xgbe_enable_rx(struct xgbe_prv_data *pdata) /* Enable each Rx queue */ reg_val = 0; - for (i = 0; i < pdata->hw_feat.rx_q_cnt; i++) + for (i = 0; i < pdata->rx_q_count; i++) reg_val |= (0x02 << (i << 1)); XGMAC_IOWRITE(pdata, MAC_RQC0R, reg_val); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index ca6a6af00f9f..04e6c72eb3c8 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -355,9 +355,16 @@ static int xgbe_probe(struct platform_device *pdev) /* Set default configuration data */ xgbe_default_config(pdata); - /* Calculate the number of Tx and Rx rings to be created */ + /* Calculate the number of Tx and Rx rings to be created + * -Tx (DMA) Channels map 1-to-1 to Tx Queues so set + * the number of Tx queues to the number of Tx channels + * enabled + * -Rx (DMA) Channels do not map 1-to-1 so use the actual + * number of Rx queues + */ pdata->tx_ring_count = min_t(unsigned int, num_online_cpus(), pdata->hw_feat.tx_ch_cnt); + pdata->tx_q_count = pdata->tx_ring_count; ret = netif_set_real_num_tx_queues(netdev, pdata->tx_ring_count); if (ret) { dev_err(dev, "error setting real tx queue count\n"); @@ -367,6 +374,7 @@ static int xgbe_probe(struct platform_device *pdev) pdata->rx_ring_count = min_t(unsigned int, netif_get_num_default_rss_queues(), pdata->hw_feat.rx_ch_cnt); + pdata->rx_q_count = pdata->hw_feat.rx_q_cnt; ret = netif_set_real_num_rx_queues(netdev, pdata->rx_ring_count); if (ret) { dev_err(dev, "error setting real rx queue count\n"); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 8b6ad3e82c34..f011d88d2211 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -590,6 +590,9 @@ struct xgbe_prv_data { unsigned int rx_ring_count; unsigned int rx_desc_count; + unsigned int tx_q_count; + unsigned int rx_q_count; + /* Tx/Rx common settings */ unsigned int pblx8; -- cgit v1.2.3 From 169a6303b89a99c807328f6f9772a81605b17116 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 29 Jul 2014 08:57:37 -0500 Subject: amd-xgbe-phy: Updates to rate change complete check Currently, the logic will loop endlessly waiting for a rate change to complete. Add a counter so that if the rate change signals never indicate complete the loop will eventually exit. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/phy/amd-xgbe-phy.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index b35293da9f87..a2d778aefadf 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -95,6 +95,8 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define XNP_MP_FORMATTED (1 << 13) #define XNP_NP_EXCHANGE (1 << 15) +#define XGBE_PHY_RATECHANGE_COUNT 100 + #ifndef MDIO_PMA_10GBR_PMD_CTRL #define MDIO_PMA_10GBR_PMD_CTRL 0x0096 #endif @@ -193,6 +195,16 @@ do { \ (_var) |= (((_val) & ((0x1 << (_width)) - 1)) << (_index)); \ } while (0) +#define XSIR_GET_BITS(_var, _prefix, _field) \ + GET_BITS((_var), \ + _prefix##_##_field##_INDEX, \ + _prefix##_##_field##_WIDTH) + +#define XSIR_SET_BITS(_var, _prefix, _field, _val) \ + SET_BITS((_var), \ + _prefix##_##_field##_INDEX, \ + _prefix##_##_field##_WIDTH, (_val)) + /* Macros for reading or writing SerDes integration registers * The ioread macros will get bit fields or full values using the * register definitions formed using the input names @@ -387,14 +399,25 @@ static void amd_xgbe_phy_serdes_start_ratechange(struct phy_device *phydev) static void amd_xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; + unsigned int wait; + u16 status; /* Release Rx and Tx ratechange */ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, RATECHANGE, 0); /* Wait for Rx and Tx ready */ - while (!XSIR0_IOREAD_BITS(priv, SIR0_STATUS, RX_READY) && - !XSIR0_IOREAD_BITS(priv, SIR0_STATUS, TX_READY)) + wait = XGBE_PHY_RATECHANGE_COUNT; + while (wait--) { usleep_range(10, 20); + + status = XSIR0_IOREAD(priv, SIR0_STATUS); + if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) && + XSIR_GET_BITS(status, SIR0_STATUS, TX_READY)) + return; + } + + netdev_err(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n", + status); } static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) -- cgit v1.2.3 From 5c10e5cb0fbdde6cc79ca406b8bdcb05aa0c9489 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 29 Jul 2014 08:57:43 -0500 Subject: amd-xgbe-phy: Updates to KR training initiation As part of changing rates to KR mode, KR training is initiated. If the KR training is restarted it is possible to enter an invalid logic state. This can be avoided by asserting a training reset bit before initiating the KR training and then clearing the training reset bit. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/phy/amd-xgbe-phy.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index a2d778aefadf..39428e5a1700 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -119,10 +119,13 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #endif /* SerDes integration register offsets */ +#define SIR0_KR_RT_1 0x002c #define SIR0_STATUS 0x0040 #define SIR1_SPEED 0x0000 /* SerDes integration register entry bit positions and sizes */ +#define SIR0_KR_RT_1_RESET_INDEX 11 +#define SIR0_KR_RT_1_RESET_WIDTH 1 #define SIR0_STATUS_RX_READY_INDEX 0 #define SIR0_STATUS_RX_READY_WIDTH 1 #define SIR0_STATUS_TX_READY_INDEX 8 @@ -636,9 +639,13 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, if (ret < 0) return AMD_XGBE_AN_ERROR; + XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1); + ret |= 0x01; phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); + XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0); + return AMD_XGBE_AN_EVENT; } -- cgit v1.2.3 From b668a3aefd48ea4cc3fdcb730989e362f13ed431 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 29 Jul 2014 08:57:49 -0500 Subject: amd-xgbe-phy: Print out the auto-negotiation method used Add a netdev_info statement detailing whether auto-negotiation was completed through parallel detection or through the auto-negotiation protocol. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/phy/amd-xgbe-phy.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index 39428e5a1700..388e3029165a 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -857,6 +857,7 @@ static void amd_xgbe_an_state_machine(struct work_struct *work) struct phy_device *phydev = priv->phydev; enum amd_xgbe_phy_an cur_state; int sleep; + unsigned int an_supported = 0; while (1) { mutex_lock(&priv->an_mutex); @@ -866,6 +867,7 @@ static void amd_xgbe_an_state_machine(struct work_struct *work) switch (priv->an_state) { case AMD_XGBE_AN_START: priv->an_state = amd_xgbe_an_start(phydev); + an_supported = 0; break; case AMD_XGBE_AN_EVENT: @@ -874,6 +876,7 @@ static void amd_xgbe_an_state_machine(struct work_struct *work) case AMD_XGBE_AN_PAGE_RECEIVED: priv->an_state = amd_xgbe_an_page_received(phydev); + an_supported++; break; case AMD_XGBE_AN_INCOMPAT_LINK: @@ -881,6 +884,11 @@ static void amd_xgbe_an_state_machine(struct work_struct *work) break; case AMD_XGBE_AN_COMPLETE: + netdev_info(phydev->attached_dev, "%s successful\n", + an_supported ? "Auto negotiation" + : "Parallel detection"); + /* fall through */ + case AMD_XGBE_AN_NO_LINK: case AMD_XGBE_AN_EXIT: goto exit_unlock; -- cgit v1.2.3 From fca2d99428473884e67ef8ea1586e58151ed6ac3 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 29 Jul 2014 08:57:55 -0500 Subject: amd-xgbe: Add traffic class support This patch adds support for traffic classes as well as support for Data Center Bridging interfaces related to traffic classes and priority flow control. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/Kconfig | 10 ++ drivers/net/ethernet/amd/xgbe/Makefile | 1 + drivers/net/ethernet/amd/xgbe/xgbe-common.h | 22 ++- drivers/net/ethernet/amd/xgbe/xgbe-dcb.c | 270 ++++++++++++++++++++++++++++ drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 180 ++++++++++++++++--- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 29 +++ drivers/net/ethernet/amd/xgbe/xgbe-main.c | 5 +- drivers/net/ethernet/amd/xgbe/xgbe.h | 18 +- 8 files changed, 508 insertions(+), 27 deletions(-) create mode 100644 drivers/net/ethernet/amd/xgbe/xgbe-dcb.c diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 98ef8ff8fa08..8319c99331b0 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -192,4 +192,14 @@ config AMD_XGBE To compile this driver as a module, choose M here: the module will be called amd-xgbe. +config AMD_XGBE_DCB + bool "Data Center Bridging (DCB) support" + default n + depends on AMD_XGBE && DCB + ---help--- + Say Y here to enable Data Center Bridging (DCB) support in the + driver. + + If unsure, say N. + endif # NET_VENDOR_AMD diff --git a/drivers/net/ethernet/amd/xgbe/Makefile b/drivers/net/ethernet/amd/xgbe/Makefile index 66c49b43e5f2..171a7e68048d 100644 --- a/drivers/net/ethernet/amd/xgbe/Makefile +++ b/drivers/net/ethernet/amd/xgbe/Makefile @@ -4,4 +4,5 @@ amd-xgbe-objs := xgbe-main.o xgbe-drv.o xgbe-dev.o \ xgbe-desc.o xgbe-ethtool.o xgbe-mdio.o \ xgbe-ptp.o +amd-xgbe-$(CONFIG_AMD_XGBE_DCB) += xgbe-dcb.o amd-xgbe-$(CONFIG_DEBUG_FS) += xgbe-debugfs.o diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index 646702cd75fb..cc25a3a9e7cf 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -322,6 +322,9 @@ #define MAC_MACA_INC 4 #define MAC_HTR_INC 4 +#define MAC_RQC2_INC 4 +#define MAC_RQC2_Q_PER_REG 4 + /* MAC register entry bit positions and sizes */ #define MAC_HWF0R_ADDMACADRSEL_INDEX 18 #define MAC_HWF0R_ADDMACADRSEL_WIDTH 5 @@ -361,6 +364,8 @@ #define MAC_HWF1R_HASHTBLSZ_WIDTH 3 #define MAC_HWF1R_L3L4FNUM_INDEX 27 #define MAC_HWF1R_L3L4FNUM_WIDTH 4 +#define MAC_HWF1R_NUMTC_INDEX 21 +#define MAC_HWF1R_NUMTC_WIDTH 3 #define MAC_HWF1R_RSSEN_INDEX 20 #define MAC_HWF1R_RSSEN_WIDTH 1 #define MAC_HWF1R_RXFIFOSIZE_INDEX 0 @@ -433,8 +438,12 @@ #define MAC_RCR_LM_WIDTH 1 #define MAC_RCR_RE_INDEX 0 #define MAC_RCR_RE_WIDTH 1 +#define MAC_RFCR_PFCE_INDEX 8 +#define MAC_RFCR_PFCE_WIDTH 1 #define MAC_RFCR_RFE_INDEX 0 #define MAC_RFCR_RFE_WIDTH 1 +#define MAC_RFCR_UP_INDEX 1 +#define MAC_RFCR_UP_WIDTH 1 #define MAC_RQC0R_RXQ0EN_INDEX 0 #define MAC_RQC0R_RXQ0EN_WIDTH 2 #define MAC_SSIR_SNSINC_INDEX 8 @@ -704,6 +713,8 @@ #define MTL_RQDCM_INC 4 #define MTL_RQDCM_Q_PER_REG 4 +#define MTL_TCPM_INC 4 +#define MTL_TCPM_TC_PER_REG 4 /* MTL register entry bit positions and sizes */ #define MTL_OMR_ETSALG_INDEX 5 @@ -722,9 +733,6 @@ #define MTL_Q_TQOMR 0x00 #define MTL_Q_TQUR 0x04 #define MTL_Q_TQDR 0x08 -#define MTL_Q_TCECR 0x10 -#define MTL_Q_TCESR 0x14 -#define MTL_Q_TCQWR 0x18 #define MTL_Q_RQOMR 0x40 #define MTL_Q_RQMPOCR 0x44 #define MTL_Q_RQDR 0x4c @@ -732,8 +740,6 @@ #define MTL_Q_ISR 0x74 /* MTL queue register entry bit positions and sizes */ -#define MTL_Q_TCQWR_QW_INDEX 0 -#define MTL_Q_TCQWR_QW_WIDTH 21 #define MTL_Q_RQOMR_EHFC_INDEX 7 #define MTL_Q_RQOMR_EHFC_WIDTH 1 #define MTL_Q_RQOMR_RFA_INDEX 8 @@ -748,6 +754,8 @@ #define MTL_Q_RQOMR_RTC_WIDTH 2 #define MTL_Q_TQOMR_FTQ_INDEX 0 #define MTL_Q_TQOMR_FTQ_WIDTH 1 +#define MTL_Q_TQOMR_Q2TCMAP_INDEX 8 +#define MTL_Q_TQOMR_Q2TCMAP_WIDTH 3 #define MTL_Q_TQOMR_TQS_INDEX 16 #define MTL_Q_TQOMR_TQS_WIDTH 10 #define MTL_Q_TQOMR_TSF_INDEX 1 @@ -794,10 +802,14 @@ #define MTL_TC_INC MTL_Q_INC #define MTL_TC_ETSCR 0x10 +#define MTL_TC_ETSSR 0x14 +#define MTL_TC_QWR 0x18 /* MTL traffic class register entry bit positions and sizes */ #define MTL_TC_ETSCR_TSA_INDEX 0 #define MTL_TC_ETSCR_TSA_WIDTH 2 +#define MTL_TC_QWR_QW_INDEX 0 +#define MTL_TC_QWR_QW_WIDTH 21 /* MTL traffic class register value */ #define MTL_TSA_SP 0x00 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c b/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c new file mode 100644 index 000000000000..7d6a49b24321 --- /dev/null +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c @@ -0,0 +1,270 @@ +/* + * AMD 10Gb Ethernet driver + * + * This file is available to you under your choice of the following two + * licenses: + * + * License 1: GPLv2 + * + * Copyright (c) 2014 Advanced Micro Devices, Inc. + * + * This file is free software; you may copy, redistribute 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 file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * The Synopsys DWC ETHER XGMAC Software Driver and documentation + * (hereinafter "Software") is an unsupported proprietary work of Synopsys, + * Inc. unless otherwise expressly agreed to in writing between Synopsys + * and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product + * under any End User Software License Agreement or Agreement for Licensed + * Product with Synopsys or any supplement thereto. Permission is hereby + * granted, free of charge, to any person obtaining a copy of this software + * annotated with this license and the Software, to deal in the Software + * without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * + * License 2: Modified BSD + * + * Copyright (c) 2014 Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Advanced Micro Devices, Inc. nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * The Synopsys DWC ETHER XGMAC Software Driver and documentation + * (hereinafter "Software") is an unsupported proprietary work of Synopsys, + * Inc. unless otherwise expressly agreed to in writing between Synopsys + * and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product + * under any End User Software License Agreement or Agreement for Licensed + * Product with Synopsys or any supplement thereto. Permission is hereby + * granted, free of charge, to any person obtaining a copy of this software + * annotated with this license and the Software, to deal in the Software + * without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "xgbe.h" +#include "xgbe-common.h" + + +static int xgbe_dcb_ieee_getets(struct net_device *netdev, + struct ieee_ets *ets) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + + /* Set number of supported traffic classes */ + ets->ets_cap = pdata->hw_feat.tc_cnt; + + if (pdata->ets) { + ets->cbs = pdata->ets->cbs; + memcpy(ets->tc_tx_bw, pdata->ets->tc_tx_bw, + sizeof(ets->tc_tx_bw)); + memcpy(ets->tc_tsa, pdata->ets->tc_tsa, + sizeof(ets->tc_tsa)); + memcpy(ets->prio_tc, pdata->ets->prio_tc, + sizeof(ets->prio_tc)); + } + + return 0; +} + +static int xgbe_dcb_ieee_setets(struct net_device *netdev, + struct ieee_ets *ets) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + unsigned int i, tc_ets, tc_ets_weight; + + tc_ets = 0; + tc_ets_weight = 0; + for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { + DBGPR(" TC%u: tx_bw=%hhu, rx_bw=%hhu, tsa=%hhu\n", i, + ets->tc_tx_bw[i], ets->tc_rx_bw[i], ets->tc_tsa[i]); + DBGPR(" PRIO%u: TC=%hhu\n", i, ets->prio_tc[i]); + + if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) && + (i >= pdata->hw_feat.tc_cnt)) + return -EINVAL; + + if (ets->prio_tc[i] >= pdata->hw_feat.tc_cnt) + return -EINVAL; + + switch (ets->tc_tsa[i]) { + case IEEE_8021QAZ_TSA_STRICT: + break; + case IEEE_8021QAZ_TSA_ETS: + tc_ets = 1; + tc_ets_weight += ets->tc_tx_bw[i]; + break; + + default: + return -EINVAL; + } + } + + /* Weights must add up to 100% */ + if (tc_ets && (tc_ets_weight != 100)) + return -EINVAL; + + if (!pdata->ets) { + pdata->ets = devm_kzalloc(pdata->dev, sizeof(*pdata->ets), + GFP_KERNEL); + if (!pdata->ets) + return -ENOMEM; + } + + memcpy(pdata->ets, ets, sizeof(*pdata->ets)); + + pdata->hw_if.config_dcb_tc(pdata); + + return 0; +} + +static int xgbe_dcb_ieee_getpfc(struct net_device *netdev, + struct ieee_pfc *pfc) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + + /* Set number of supported PFC traffic classes */ + pfc->pfc_cap = pdata->hw_feat.tc_cnt; + + if (pdata->pfc) { + pfc->pfc_en = pdata->pfc->pfc_en; + pfc->mbc = pdata->pfc->mbc; + pfc->delay = pdata->pfc->delay; + } + + return 0; +} + +static int xgbe_dcb_ieee_setpfc(struct net_device *netdev, + struct ieee_pfc *pfc) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + + DBGPR(" cap=%hhu, en=%hhx, mbc=%hhu, delay=%hhu\n", + pfc->pfc_cap, pfc->pfc_en, pfc->mbc, pfc->delay); + + if (!pdata->pfc) { + pdata->pfc = devm_kzalloc(pdata->dev, sizeof(*pdata->pfc), + GFP_KERNEL); + if (!pdata->pfc) + return -ENOMEM; + } + + memcpy(pdata->pfc, pfc, sizeof(*pdata->pfc)); + + pdata->hw_if.config_dcb_pfc(pdata); + + return 0; +} + +static u8 xgbe_dcb_getdcbx(struct net_device *netdev) +{ + return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE; +} + +static u8 xgbe_dcb_setdcbx(struct net_device *netdev, u8 dcbx) +{ + u8 support = xgbe_dcb_getdcbx(netdev); + + DBGPR(" DCBX=%#hhx\n", dcbx); + + if (dcbx & ~support) + return 1; + + if ((dcbx & support) != support) + return 1; + + return 0; +} + +static const struct dcbnl_rtnl_ops xgbe_dcbnl_ops = { + /* IEEE 802.1Qaz std */ + .ieee_getets = xgbe_dcb_ieee_getets, + .ieee_setets = xgbe_dcb_ieee_setets, + .ieee_getpfc = xgbe_dcb_ieee_getpfc, + .ieee_setpfc = xgbe_dcb_ieee_setpfc, + + /* DCBX configuration */ + .getdcbx = xgbe_dcb_getdcbx, + .setdcbx = xgbe_dcb_setdcbx, +}; + +const struct dcbnl_rtnl_ops *xgbe_get_dcbnl_ops(void) +{ + return &xgbe_dcbnl_ops; +} diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 2cdf34f6139f..edaca4496264 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -407,7 +407,9 @@ static int xgbe_enable_rx_flow_control(struct xgbe_prv_data *pdata) static int xgbe_config_tx_flow_control(struct xgbe_prv_data *pdata) { - if (pdata->tx_pause) + struct ieee_pfc *pfc = pdata->pfc; + + if (pdata->tx_pause || (pfc && pfc->pfc_en)) xgbe_enable_tx_flow_control(pdata); else xgbe_disable_tx_flow_control(pdata); @@ -417,7 +419,9 @@ static int xgbe_config_tx_flow_control(struct xgbe_prv_data *pdata) static int xgbe_config_rx_flow_control(struct xgbe_prv_data *pdata) { - if (pdata->rx_pause) + struct ieee_pfc *pfc = pdata->pfc; + + if (pdata->rx_pause || (pfc && pfc->pfc_en)) xgbe_enable_rx_flow_control(pdata); else xgbe_disable_rx_flow_control(pdata); @@ -427,8 +431,13 @@ static int xgbe_config_rx_flow_control(struct xgbe_prv_data *pdata) static void xgbe_config_flow_control(struct xgbe_prv_data *pdata) { + struct ieee_pfc *pfc = pdata->pfc; + xgbe_config_tx_flow_control(pdata); xgbe_config_rx_flow_control(pdata); + + XGMAC_IOWRITE_BITS(pdata, MAC_RFCR, PFCE, + (pfc && pfc->pfc_en) ? 1 : 0); } static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata) @@ -1117,6 +1126,79 @@ static int xgbe_config_tstamp(struct xgbe_prv_data *pdata, return 0; } +static void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata) +{ + struct ieee_ets *ets = pdata->ets; + unsigned int total_weight, min_weight, weight; + unsigned int i; + + if (!ets) + return; + + /* Set Tx to deficit weighted round robin scheduling algorithm (when + * traffic class is using ETS algorithm) + */ + XGMAC_IOWRITE_BITS(pdata, MTL_OMR, ETSALG, MTL_ETSALG_DWRR); + + /* Set Traffic Class algorithms */ + total_weight = pdata->netdev->mtu * pdata->hw_feat.tc_cnt; + min_weight = total_weight / 100; + if (!min_weight) + min_weight = 1; + + for (i = 0; i < pdata->hw_feat.tc_cnt; i++) { + switch (ets->tc_tsa[i]) { + case IEEE_8021QAZ_TSA_STRICT: + DBGPR(" TC%u using SP\n", i); + XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA, + MTL_TSA_SP); + break; + case IEEE_8021QAZ_TSA_ETS: + weight = total_weight * ets->tc_tx_bw[i] / 100; + weight = clamp(weight, min_weight, total_weight); + + DBGPR(" TC%u using DWRR (weight %u)\n", i, weight); + XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA, + MTL_TSA_ETS); + XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_QWR, QW, + weight); + break; + } + } +} + +static void xgbe_config_dcb_pfc(struct xgbe_prv_data *pdata) +{ + struct ieee_pfc *pfc = pdata->pfc; + struct ieee_ets *ets = pdata->ets; + unsigned int mask, reg, reg_val; + unsigned int tc, prio; + + if (!pfc || !ets) + return; + + for (tc = 0; tc < pdata->hw_feat.tc_cnt; tc++) { + mask = 0; + for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) { + if ((pfc->pfc_en & (1 << prio)) && + (ets->prio_tc[prio] == tc)) + mask |= (1 << prio); + } + mask &= 0xff; + + DBGPR(" TC%u PFC mask=%#x\n", tc, mask); + reg = MTL_TCPM0R + (MTL_TCPM_INC * (tc / MTL_TCPM_TC_PER_REG)); + reg_val = XGMAC_IOREAD(pdata, reg); + + reg_val &= ~(0xff << ((tc % MTL_TCPM_TC_PER_REG) << 3)); + reg_val |= (mask << ((tc % MTL_TCPM_TC_PER_REG) << 3)); + + XGMAC_IOWRITE(pdata, reg, reg_val); + } + + xgbe_config_flow_control(pdata); +} + static void xgbe_pre_xmit(struct xgbe_channel *channel) { struct xgbe_prv_data *pdata = channel->pdata; @@ -1607,14 +1689,15 @@ static void xgbe_config_mtl_mode(struct xgbe_prv_data *pdata) { unsigned int i; - /* Set Tx to weighted round robin scheduling algorithm (when - * traffic class is using ETS algorithm) - */ + /* Set Tx to weighted round robin scheduling algorithm */ XGMAC_IOWRITE_BITS(pdata, MTL_OMR, ETSALG, MTL_ETSALG_WRR); - /* Set Tx traffic classes to strict priority algorithm */ - for (i = 0; i < XGBE_TC_CNT; i++) - XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA, MTL_TSA_SP); + /* Set Tx traffic classes to use WRR algorithm with equal weights */ + for (i = 0; i < pdata->hw_feat.tc_cnt; i++) { + XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA, + MTL_TSA_ETS); + XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_QWR, QW, 1); + } /* Set Rx to strict priority algorithm */ XGMAC_IOWRITE_BITS(pdata, MTL_OMR, RAA, MTL_RAA_SP); @@ -1724,18 +1807,75 @@ static void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata) pdata->rx_q_count, ((fifo_size + 1) * 256)); } -static void xgbe_config_rx_queue_mapping(struct xgbe_prv_data *pdata) +static void xgbe_config_queue_mapping(struct xgbe_prv_data *pdata) { - unsigned int i, reg, reg_val; - unsigned int q_count = pdata->rx_q_count; + unsigned int qptc, qptc_extra, queue; + unsigned int prio_queues; + unsigned int ppq, ppq_extra, prio; + unsigned int mask; + unsigned int i, j, reg, reg_val; + + /* Map the MTL Tx Queues to Traffic Classes + * Note: Tx Queues >= Traffic Classes + */ + qptc = pdata->tx_q_count / pdata->hw_feat.tc_cnt; + qptc_extra = pdata->tx_q_count % pdata->hw_feat.tc_cnt; + + for (i = 0, queue = 0; i < pdata->hw_feat.tc_cnt; i++) { + for (j = 0; j < qptc; j++) { + DBGPR(" TXq%u mapped to TC%u\n", queue, i); + XGMAC_MTL_IOWRITE_BITS(pdata, queue, MTL_Q_TQOMR, + Q2TCMAP, i); + pdata->q2tc_map[queue++] = i; + } + + if (i < qptc_extra) { + DBGPR(" TXq%u mapped to TC%u\n", queue, i); + XGMAC_MTL_IOWRITE_BITS(pdata, queue, MTL_Q_TQOMR, + Q2TCMAP, i); + pdata->q2tc_map[queue++] = i; + } + } + + /* Map the 8 VLAN priority values to available MTL Rx queues */ + prio_queues = min_t(unsigned int, IEEE_8021QAZ_MAX_TCS, + pdata->rx_q_count); + ppq = IEEE_8021QAZ_MAX_TCS / prio_queues; + ppq_extra = IEEE_8021QAZ_MAX_TCS % prio_queues; + + reg = MAC_RQC2R; + reg_val = 0; + for (i = 0, prio = 0; i < prio_queues;) { + mask = 0; + for (j = 0; j < ppq; j++) { + DBGPR(" PRIO%u mapped to RXq%u\n", prio, i); + mask |= (1 << prio); + pdata->prio2q_map[prio++] = i; + } + + if (i < ppq_extra) { + DBGPR(" PRIO%u mapped to RXq%u\n", prio, i); + mask |= (1 << prio); + pdata->prio2q_map[prio++] = i; + } + + reg_val |= (mask << ((i++ % MAC_RQC2_Q_PER_REG) << 3)); + + if ((i % MAC_RQC2_Q_PER_REG) && (i != prio_queues)) + continue; + + XGMAC_IOWRITE(pdata, reg, reg_val); + reg += MAC_RQC2_INC; + reg_val = 0; + } /* Select dynamic mapping of MTL Rx queue to DMA Rx channel */ reg = MTL_RQDCM0R; reg_val = 0; - for (i = 0; i < q_count;) { + for (i = 0; i < pdata->rx_q_count;) { reg_val |= (0x80 << ((i++ % MTL_RQDCM_Q_PER_REG) << 3)); - if ((i % MTL_RQDCM_Q_PER_REG) && (i != q_count)) + if ((i % MTL_RQDCM_Q_PER_REG) && (i != pdata->rx_q_count)) continue; XGMAC_IOWRITE(pdata, reg, reg_val); @@ -2321,9 +2461,7 @@ static int xgbe_init(struct xgbe_prv_data *pdata) * Initialize MTL related features */ xgbe_config_mtl_mode(pdata); - xgbe_config_rx_queue_mapping(pdata); - /*TODO: Program the priorities mapped to the Selected Traffic Classes - in MTL_TC_Prty_Map0-3 registers */ + xgbe_config_queue_mapping(pdata); xgbe_config_tsf_mode(pdata, pdata->tx_sf_mode); xgbe_config_rsf_mode(pdata, pdata->rx_sf_mode); xgbe_config_tx_threshold(pdata, pdata->tx_threshold); @@ -2331,15 +2469,13 @@ static int xgbe_init(struct xgbe_prv_data *pdata) xgbe_config_tx_fifo_size(pdata); xgbe_config_rx_fifo_size(pdata); xgbe_config_flow_control_threshold(pdata); - /*TODO: Queue to Traffic Class Mapping (Q2TCMAP) */ /*TODO: Error Packet and undersized good Packet forwarding enable (FEP and FUP) */ + xgbe_config_dcb_tc(pdata); + xgbe_config_dcb_pfc(pdata); xgbe_enable_mtl_interrupts(pdata); - /* Transmit Class Weight */ - XGMAC_IOWRITE_BITS(pdata, MTL_Q_TCQWR, QW, 0x10); - /* * Initialize MAC related features */ @@ -2448,5 +2584,9 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) hw_if->get_tstamp_time = xgbe_get_tstamp_time; hw_if->get_tx_tstamp = xgbe_get_tx_tstamp; + /* For Data Center Bridging config */ + hw_if->config_dcb_tc = xgbe_config_dcb_tc; + hw_if->config_dcb_pfc = xgbe_config_dcb_pfc; + DBGPR("<--xgbe_init_function_ptrs\n"); } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 47a1e25b5609..3bf3c0194ad3 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -387,6 +387,7 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) hw_feat->sph = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, SPHEN); hw_feat->tso = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, TSOEN); hw_feat->dma_debug = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, DBGMEMA); + hw_feat->tc_cnt = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, NUMTC); hw_feat->hash_table_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, HASHTBLSZ); hw_feat->l3l4_filter_num = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, @@ -1312,6 +1313,33 @@ static void xgbe_poll_controller(struct net_device *netdev) } #endif /* End CONFIG_NET_POLL_CONTROLLER */ +static int xgbe_setup_tc(struct net_device *netdev, u8 tc) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + unsigned int offset, queue; + u8 i; + + if (tc && (tc != pdata->hw_feat.tc_cnt)) + return -EINVAL; + + if (tc) { + netdev_set_num_tc(netdev, tc); + for (i = 0, queue = 0, offset = 0; i < tc; i++) { + while ((queue < pdata->tx_q_count) && + (pdata->q2tc_map[queue] == i)) + queue++; + + DBGPR(" TC%u using TXq%u-%u\n", i, offset, queue - 1); + netdev_set_tc_queue(netdev, i, queue - offset, offset); + offset = queue; + } + } else { + netdev_reset_tc(netdev); + } + + return 0; +} + static int xgbe_set_features(struct net_device *netdev, netdev_features_t features) { @@ -1360,6 +1388,7 @@ static const struct net_device_ops xgbe_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = xgbe_poll_controller, #endif + .ndo_setup_tc = xgbe_setup_tc, .ndo_set_features = xgbe_set_features, }; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index 04e6c72eb3c8..ec977d36063f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -400,9 +400,12 @@ static int xgbe_probe(struct platform_device *pdev) if (ret) goto err_bus_id; - /* Set network and ethtool operations */ + /* Set device operations */ netdev->netdev_ops = xgbe_get_netdev_ops(); netdev->ethtool_ops = xgbe_get_ethtool_ops(); +#ifdef CONFIG_AMD_XGBE_DCB + netdev->dcbnl_ops = xgbe_get_dcbnl_ops(); +#endif /* Set device features */ netdev->hw_features = NETIF_F_SG | diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index f011d88d2211..07bf70a82908 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -126,6 +126,7 @@ #include #include #include +#include #define XGBE_DRV_NAME "amd-xgbe" @@ -144,6 +145,7 @@ #define XGBE_RX_BUF_ALIGN 64 #define XGBE_MAX_DMA_CHANNELS 16 +#define XGBE_MAX_QUEUES 16 /* DMA cache settings - Outer sharable, write-back, write-allocate */ #define XGBE_DMA_OS_AXDOMAIN 0x2 @@ -184,7 +186,7 @@ #define XGBE_FIFO_SIZE_B(x) (x) #define XGBE_FIFO_SIZE_KB(x) (x * 1024) -#define XGBE_TC_CNT 2 +#define XGBE_TC_MIN_QUANTUM 10 /* Helper macro for descriptor handling * Always use XGBE_GET_DESC_DATA to access the descriptor data @@ -504,6 +506,10 @@ struct xgbe_hw_if { unsigned int nsec); u64 (*get_tstamp_time)(struct xgbe_prv_data *); u64 (*get_tx_tstamp)(struct xgbe_prv_data *); + + /* For Data Center Bridging config */ + void (*config_dcb_tc)(struct xgbe_prv_data *); + void (*config_dcb_pfc)(struct xgbe_prv_data *); }; struct xgbe_desc_if { @@ -545,6 +551,7 @@ struct xgbe_hw_features { unsigned int tso; /* TCP Segmentation Offload */ unsigned int dma_debug; /* DMA Debug Registers */ unsigned int rss; /* Receive Side Scaling */ + unsigned int tc_cnt; /* Number of Traffic Classes */ unsigned int hash_table_size; /* Hash Table Size */ unsigned int l3l4_filter_num; /* Number of L3-L4 Filters */ @@ -663,6 +670,12 @@ struct xgbe_prv_data { struct sk_buff *tx_tstamp_skb; u64 tx_tstamp; + /* DCB support */ + struct ieee_ets *ets; + struct ieee_pfc *pfc; + unsigned int q2tc_map[XGBE_MAX_QUEUES]; + unsigned int prio2q_map[IEEE_8021QAZ_MAX_TCS]; + /* Hardware features of the device */ struct xgbe_hw_features hw_feat; @@ -688,6 +701,9 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *); void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *); struct net_device_ops *xgbe_get_netdev_ops(void); struct ethtool_ops *xgbe_get_ethtool_ops(void); +#ifdef CONFIG_AMD_XGBE_DCB +const struct dcbnl_rtnl_ops *xgbe_get_dcbnl_ops(void); +#endif int xgbe_mdio_register(struct xgbe_prv_data *); void xgbe_mdio_unregister(struct xgbe_prv_data *); -- cgit v1.2.3 From c36c9d50cc6af5c5bfcc195f21b73f55520c15f9 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Tue, 29 Jul 2014 16:29:30 +0200 Subject: bna: fix performance regression The recent commit "e29aa33 bna: Enable Multi Buffer RX" is causing a performance regression. It does not properly update 'cmpl' pointer at the end of the loop in NAPI handler bnad_cq_process(). The result is only one packet / per NAPI-schedule is processed. Signed-off-by: Ivan Vecera Signed-off-by: David S. Miller --- drivers/net/ethernet/brocade/bna/bnad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index 3a77f9ead004..556aab75f490 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -600,9 +600,9 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget) prefetch(bnad->netdev); cq = ccb->sw_q; - cmpl = &cq[ccb->producer_index]; while (packets < budget) { + cmpl = &cq[ccb->producer_index]; if (!cmpl->valid) break; /* The 'valid' field is set by the adapter, only after writing -- cgit v1.2.3 From 5160ee93005e4c22dbf45e24448ea7d3cb375fdb Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Jul 2014 17:16:44 +0200 Subject: CAPI: use correct structure type name in sizeof Correct typo in the name of the type given to sizeof. Because it is the size of a pointer that is wanted, the typo has no impact on compilation or execution. This problem was found using Coccinelle (http://coccinelle.lip6.fr/). The semantic patch used can be found in message 0 of this patch series. Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/isdn/capi/capi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index f9a87ed2392b..6a2df3297e77 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1260,7 +1260,7 @@ static int __init capinc_tty_init(void) if (capi_ttyminors <= 0) capi_ttyminors = CAPINC_NR_PORTS; - capiminors = kzalloc(sizeof(struct capi_minor *) * capi_ttyminors, + capiminors = kzalloc(sizeof(struct capiminor *) * capi_ttyminors, GFP_KERNEL); if (!capiminors) return -ENOMEM; -- cgit v1.2.3 From e10038a8ec06ac819b7552bb67aaa6d2d6f850c1 Mon Sep 17 00:00:00 2001 From: Pablo Neira Date: Tue, 29 Jul 2014 18:12:15 +0200 Subject: netfilter: xt_bpf: add mising opaque struct sk_filter definition This structure is not exposed to userspace, so fix this by defining struct sk_filter; so we skip the casting in kernelspace. This is safe since userspace has no way to lurk with that internal pointer. Fixes: e6f30c7 ("netfilter: x_tables: add xt_bpf match") Signed-off-by: Pablo Neira Ayuso Acked-by: Willem de Bruijn Signed-off-by: David S. Miller --- include/uapi/linux/netfilter/xt_bpf.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uapi/linux/netfilter/xt_bpf.h b/include/uapi/linux/netfilter/xt_bpf.h index 5dda450eb55b..2ec9fbcd06f9 100644 --- a/include/uapi/linux/netfilter/xt_bpf.h +++ b/include/uapi/linux/netfilter/xt_bpf.h @@ -6,6 +6,8 @@ #define XT_BPF_MAX_NUM_INSTR 64 +struct sk_filter; + struct xt_bpf_info { __u16 bpf_program_num_elem; struct sock_filter bpf_program[XT_BPF_MAX_NUM_INSTR]; -- cgit v1.2.3 From 34c5bd66e5ed2268bcb917b4cbdd6317023eada4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Date: Tue, 29 Jul 2014 17:36:28 +0200 Subject: net: filter: don't release unattached filter through call_rcu() sk_unattached_filter_destroy() does not always need to release the filter object via rcu. Since this filter is never attached to the socket, the caller should be responsible for releasing the filter in a safe way, which may not necessarily imply rcu. This is a short summary of clients of this function: 1) xt_bpf.c and cls_bpf.c use the bpf matchers from rules, these rules are removed from the packet path before the filter is released. Thus, the framework makes sure the filter is safely removed. 2) In the ppp driver, the ppp_lock ensures serialization between the xmit and filter attachment/detachment path. This doesn't use rcu so deferred release via rcu makes no sense. 3) In the isdn/ppp driver, it is called from isdn_ppp_release() the isdn_ppp_ioctl(). This driver uses mutex and spinlocks, no rcu. Thus, deferred rcu makes no sense to me either, the deferred releases may be just masking the effects of wrong locking strategy, which should be fixed in the driver itself. 4) In the team driver, this is the only place where the rcu synchronization with unattached filter is used. Therefore, this patch introduces synchronize_rcu() which is called from the genetlink path to make sure the filter doesn't go away while packets are still walking over it. I think we can revisit this once struct bpf_prog (that only wraps specific bpf code bits) is in place, then add some specific struct rcu_head in the scope of the team driver if Jiri thinks this is needed. Deferred rcu release for unattached filters was originally introduced in 302d663 ("filter: Allow to create sk-unattached filters"). Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- drivers/net/team/team_mode_loadbalance.c | 6 +++++- net/core/filter.c | 11 ++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c index a58dfebb5512..7106f3456439 100644 --- a/drivers/net/team/team_mode_loadbalance.c +++ b/drivers/net/team/team_mode_loadbalance.c @@ -293,11 +293,15 @@ static int lb_bpf_func_set(struct team *team, struct team_gsetter_ctx *ctx) __fprog_destroy(lb_priv->ex->orig_fprog); orig_fp = rcu_dereference_protected(lb_priv->fp, lockdep_is_held(&team->lock)); - sk_unattached_filter_destroy(orig_fp); } rcu_assign_pointer(lb_priv->fp, fp); lb_priv->ex->orig_fprog = fprog; + + if (orig_fp) { + synchronize_rcu(); + sk_unattached_filter_destroy(orig_fp); + } return 0; } diff --git a/net/core/filter.c b/net/core/filter.c index f3b2d5e9fe5f..42c1944b0c63 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -841,6 +841,12 @@ static void sk_release_orig_filter(struct sk_filter *fp) } } +static void __sk_filter_release(struct sk_filter *fp) +{ + sk_release_orig_filter(fp); + sk_filter_free(fp); +} + /** * sk_filter_release_rcu - Release a socket filter by rcu_head * @rcu: rcu_head that contains the sk_filter to free @@ -849,8 +855,7 @@ static void sk_filter_release_rcu(struct rcu_head *rcu) { struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); - sk_release_orig_filter(fp); - sk_filter_free(fp); + __sk_filter_release(fp); } /** @@ -1050,7 +1055,7 @@ EXPORT_SYMBOL_GPL(sk_unattached_filter_create); void sk_unattached_filter_destroy(struct sk_filter *fp) { - sk_filter_release(fp); + __sk_filter_release(fp); } EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy); -- cgit v1.2.3 From c1543d37ff22800c06c1ac1c1587bb3891474506 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Tue, 29 Jul 2014 14:47:25 -0500 Subject: net/fsl: fix misspelled word Fix one misspelled word reported by codespell. Signed-off-by: Madalin Bucur Signed-off-by: Shruti Kanetkar Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/xgmac_mdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index 0c9d55c862ae..81734075e0aa 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -46,7 +46,7 @@ struct tgec_mdio_controller { #define MDIO_DATA_BSY (1 << 31) /* - * Wait untill the MDIO bus is free + * Wait until the MDIO bus is free */ static int xgmac_wait_until_free(struct device *dev, struct tgec_mdio_controller __iomem *regs) -- cgit v1.2.3 From 9e6492ec99c24b88a7c57623e5664d389261bf4e Mon Sep 17 00:00:00 2001 From: Shruti Kanetkar Date: Tue, 29 Jul 2014 14:53:03 -0500 Subject: net/fsl: Add format length modifier to avoid negative values Signed-off-by: Shruti Kanetkar Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/xgmac_mdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index 81734075e0aa..6e7db66069aa 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -163,7 +163,7 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) /* Return all Fs if nothing was there */ if (in_be32(®s->mdio_stat) & MDIO_STAT_RD_ER) { dev_err(&bus->dev, - "Error while reading PHY%d reg at %d.%d\n", + "Error while reading PHY%d reg at %d.%hhu\n", phy_id, dev_addr, regnum); return 0xffff; } -- cgit v1.2.3 From 0c1d77dfb56660329d639090352bf690d3c33466 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Tue, 29 Jul 2014 15:19:57 -0500 Subject: net: libphy: Add phy specific function to access mmd phy registers libphy was originally written assuming all phy devices support clause 45 access extensions to the mmd registers through the indirection registers located within the first 16 phy registers. This assumption is not true in all cases, and one specific example is the Micrel ksz9021 10/100/1000 Mbps phy. Using the stmmac driver, accessing the mmd registers to query and configure energy efficient Ethernet (EEE) features yielded unexpected behavior. This patch adds mmd access functions to the phy driver that can be overriden by the phy specific driver if the phy does not support this mechanism or uses it's own non-standard access mechanism. By default, the IEEE Compatible clause 45 access mechanism described in clause 22 is used. With this patch, EEE query/configure functions as expected using the stmmac and the Micrel ksz9021 phy. Signed-off-by: Vince Bridgers Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 61 ++++++++++++++++++++++++++++++++------------------- include/linux/phy.h | 18 +++++++++++++++ 2 files changed, 56 insertions(+), 23 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e56e269a6eb3..c94e2a27446a 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -942,7 +942,7 @@ static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad, /** * phy_read_mmd_indirect - reads data from the MMD registers - * @bus: the target MII bus + * @phydev: The PHY device bus * @prtad: MMD Address * @devad: MMD DEVAD * @addr: PHY address on the MII bus @@ -955,18 +955,26 @@ static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad, * 3) Write reg 13 // MMD Data Command for MMD DEVAD * 3) Read reg 14 // Read MMD data */ -static int phy_read_mmd_indirect(struct mii_bus *bus, int prtad, int devad, - int addr) +static int phy_read_mmd_indirect(struct phy_device *phydev, int prtad, + int devad, int addr) { - mmd_phy_indirect(bus, prtad, devad, addr); + struct phy_driver *phydrv = phydev->drv; + int value = -1; - /* Read the content of the MMD's selected register */ - return bus->read(bus, addr, MII_MMD_DATA); + if (phydrv->read_mmd_indirect == NULL) { + mmd_phy_indirect(phydev->bus, prtad, devad, addr); + + /* Read the content of the MMD's selected register */ + value = phydev->bus->read(phydev->bus, addr, MII_MMD_DATA); + } else { + value = phydrv->read_mmd_indirect(phydev, prtad, devad, addr); + } + return value; } /** * phy_write_mmd_indirect - writes data to the MMD registers - * @bus: the target MII bus + * @phydev: The PHY device * @prtad: MMD Address * @devad: MMD DEVAD * @addr: PHY address on the MII bus @@ -980,13 +988,19 @@ static int phy_read_mmd_indirect(struct mii_bus *bus, int prtad, int devad, * 3) Write reg 13 // MMD Data Command for MMD DEVAD * 3) Write reg 14 // Write MMD data */ -static void phy_write_mmd_indirect(struct mii_bus *bus, int prtad, int devad, - int addr, u32 data) +static void phy_write_mmd_indirect(struct phy_device *phydev, int prtad, + int devad, int addr, u32 data) { - mmd_phy_indirect(bus, prtad, devad, addr); + struct phy_driver *phydrv = phydev->drv; - /* Write the data into MMD's selected register */ - bus->write(bus, addr, MII_MMD_DATA, data); + if (phydrv->write_mmd_indirect == NULL) { + mmd_phy_indirect(phydev->bus, prtad, devad, addr); + + /* Write the data into MMD's selected register */ + phydev->bus->write(phydev->bus, addr, MII_MMD_DATA, data); + } else { + phydrv->write_mmd_indirect(phydev, prtad, devad, addr, data); + } } /** @@ -1020,7 +1034,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) return status; /* First check if the EEE ability is supported */ - eee_cap = phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_ABLE, + eee_cap = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE, MDIO_MMD_PCS, phydev->addr); if (eee_cap < 0) return eee_cap; @@ -1032,12 +1046,12 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) /* Check which link settings negotiated and verify it in * the EEE advertising registers. */ - eee_lp = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_LPABLE, + eee_lp = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_LPABLE, MDIO_MMD_AN, phydev->addr); if (eee_lp < 0) return eee_lp; - eee_adv = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, + eee_adv = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV, MDIO_MMD_AN, phydev->addr); if (eee_adv < 0) return eee_adv; @@ -1052,15 +1066,16 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) /* Configure the PHY to stop receiving xMII * clock while it is signaling LPI. */ - int val = phy_read_mmd_indirect(phydev->bus, MDIO_CTRL1, + int val = phy_read_mmd_indirect(phydev, MDIO_CTRL1, MDIO_MMD_PCS, phydev->addr); if (val < 0) return val; val |= MDIO_PCS_CTRL1_CLKSTOP_EN; - phy_write_mmd_indirect(phydev->bus, MDIO_CTRL1, - MDIO_MMD_PCS, phydev->addr, val); + phy_write_mmd_indirect(phydev, MDIO_CTRL1, + MDIO_MMD_PCS, phydev->addr, + val); } return 0; /* EEE supported */ @@ -1079,7 +1094,7 @@ EXPORT_SYMBOL(phy_init_eee); */ int phy_get_eee_err(struct phy_device *phydev) { - return phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_WK_ERR, + return phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_WK_ERR, MDIO_MMD_PCS, phydev->addr); } EXPORT_SYMBOL(phy_get_eee_err); @@ -1097,21 +1112,21 @@ int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data) int val; /* Get Supported EEE */ - val = phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_ABLE, + val = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE, MDIO_MMD_PCS, phydev->addr); if (val < 0) return val; data->supported = mmd_eee_cap_to_ethtool_sup_t(val); /* Get advertisement EEE */ - val = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, + val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV, MDIO_MMD_AN, phydev->addr); if (val < 0) return val; data->advertised = mmd_eee_adv_to_ethtool_adv_t(val); /* Get LP advertisement EEE */ - val = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_LPABLE, + val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_LPABLE, MDIO_MMD_AN, phydev->addr); if (val < 0) return val; @@ -1132,7 +1147,7 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data) { int val = ethtool_adv_to_mmd_eee_adv_t(data->advertised); - phy_write_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, MDIO_MMD_AN, + phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV, MDIO_MMD_AN, phydev->addr, val); return 0; diff --git a/include/linux/phy.h b/include/linux/phy.h index 68041446c450..ed39956b5613 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -545,6 +545,24 @@ struct phy_driver { */ void (*link_change_notify)(struct phy_device *dev); + /* A function provided by a phy specific driver to override the + * the PHY driver framework support for reading a MMD register + * from the PHY. If not supported, return -1. This function is + * optional for PHY specific drivers, if not provided then the + * default MMD read function is used by the PHY framework. + */ + int (*read_mmd_indirect)(struct phy_device *dev, int ptrad, + int devnum, int regnum); + + /* A function provided by a phy specific driver to override the + * the PHY driver framework support for writing a MMD register + * from the PHY. This function is optional for PHY specific drivers, + * if not provided then the default MMD read function is used by + * the PHY framework. + */ + void (*write_mmd_indirect)(struct phy_device *dev, int ptrad, + int devnum, int regnum, u32 val); + struct device_driver driver; }; #define to_phy_driver(d) container_of(d, struct phy_driver, driver) -- cgit v1.2.3 From 19936942a1a30ce387ea3782b508ac72957b2293 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Tue, 29 Jul 2014 15:19:58 -0500 Subject: net: libphy: Add stubs to hook IEEE MMD Register reads and writes The Micrel ksz9021 PHY does not support standard IEEE standard MMD extended register access, therefore requires stubs to fail the read register method and do nothing for the write register method when libphy attempts to read and/or configure Energy Efficient Ethernet features in PHYS that do support those features. This problem was observed on an Altera Cyclone V SOC development kit that uses the Synopsys EMAC and the Micrel ksz9021 PHY. This patch was tested on the same board, and Energy Efficient Ethernet is now disabled as expected since the Micrel PHY does not support that feature. Signed-off-by: Vince Bridgers Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/micrel.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index bc7c7d2f75f2..fd0ea7c50ee6 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -420,6 +420,26 @@ static int ksz8873mll_config_aneg(struct phy_device *phydev) return 0; } +/* This routine returns -1 as an indication to the caller that the + * Micrel ksz9021 10/100/1000 PHY does not support standard IEEE + * MMD extended PHY registers. + */ +static int +ksz9021_rd_mmd_phyreg(struct phy_device *phydev, int ptrad, int devnum, + int regnum) +{ + return -1; +} + +/* This routine does nothing since the Micrel ksz9021 does not support + * standard IEEE MMD extended PHY registers. + */ +static void +ksz9021_wr_mmd_phyreg(struct phy_device *phydev, int ptrad, int devnum, + int regnum, u32 val) +{ +} + static struct phy_driver ksphy_driver[] = { { .phy_id = PHY_ID_KS8737, @@ -565,6 +585,8 @@ static struct phy_driver ksphy_driver[] = { .config_intr = ksz9021_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .read_mmd_indirect = ksz9021_rd_mmd_phyreg, + .write_mmd_indirect = ksz9021_wr_mmd_phyreg, .driver = { .owner = THIS_MODULE, }, }, { .phy_id = PHY_ID_KSZ9031, -- cgit v1.2.3 From 49193a66f00148443288a83c6ac377a641b10bd5 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Tue, 29 Jul 2014 15:19:59 -0500 Subject: Documentation: networking: phy.txt: Update text for indirect MMD access Update the PHY library documentation to describe how a specific PHY driver can use the PAL MMD register access routines or override those routines with it's own in the event the PHY does not support the IEEE standard for reading and writing MMD phy registers. Signed-off-by: Vince Bridgers Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/networking/phy.txt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt index 3544c98401fd..e839e7efc835 100644 --- a/Documentation/networking/phy.txt +++ b/Documentation/networking/phy.txt @@ -272,6 +272,8 @@ Writing a PHY driver txtsamp: Requests a transmit timestamp at the PHY level for a 'skb' set_wol: Enable Wake-on-LAN at the PHY level get_wol: Get the Wake-on-LAN status at the PHY level + read_mmd_indirect: Read PHY MMD indirect register + write_mmd_indirect: Write PHY MMD indirect register Of these, only config_aneg and read_status are required to be assigned by the driver code. The rest are optional. Also, it is @@ -284,7 +286,21 @@ Writing a PHY driver Feel free to look at the Marvell, Cicada, and Davicom drivers in drivers/net/phy/ for examples (the lxt and qsemi drivers have - not been tested as of this writing) + not been tested as of this writing). + + The PHY's MMD register accesses are handled by the PAL framework + by default, but can be overridden by a specific PHY driver if + required. This could be the case if a PHY was released for + manufacturing before the MMD PHY register definitions were + standardized by the IEEE. Most modern PHYs will be able to use + the generic PAL framework for accessing the PHY's MMD registers. + An example of such usage is for Energy Efficient Ethernet support, + implemented in the PAL. This support uses the PAL to access MMD + registers for EEE query and configuration if the PHY supports + the IEEE standard access mechanisms, or can use the PHY's specific + access interfaces if overridden by the specific PHY driver. See + the Micrel driver in drivers/net/phy/ for an example of how this + can be implemented. Board Fixups -- cgit v1.2.3 From 7fc527f96bc57a5cb87bf78e8535bb85ad372995 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 29 Jul 2014 14:34:14 -0700 Subject: net: bcmgenet: correct spelling Signed-off-by: Brian Norris Cc: Florian Fainelli Cc: David S. Miller Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 417ce68449a4..ce455aed5a2f 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -89,7 +89,7 @@ static inline void dmadesc_set_addr(struct bcmgenet_priv *priv, /* Register writes to GISB bus can take couple hundred nanoseconds * and are done for each packet, save these expensive writes unless - * the platform is explicitely configured for 64-bits/LPAE. + * the platform is explicitly configured for 64-bits/LPAE. */ #ifdef CONFIG_PHYS_ADDR_T_64BIT if (priv->hw_params->flags & GENET_HAS_40BITS) @@ -114,7 +114,7 @@ static inline dma_addr_t dmadesc_get_addr(struct bcmgenet_priv *priv, /* Register writes to GISB bus can take couple hundred nanoseconds * and are done for each packet, save these expensive writes unless - * the platform is explicitely configured for 64-bits/LPAE. + * the platform is explicitly configured for 64-bits/LPAE. */ #ifdef CONFIG_PHYS_ADDR_T_64BIT if (priv->hw_params->flags & GENET_HAS_40BITS) @@ -876,7 +876,7 @@ static void __bcmgenet_tx_reclaim(struct net_device *dev, struct netdev_queue *txq; unsigned int c_index; - /* Compute how many buffers are transmited since last xmit call */ + /* Compute how many buffers are transmitted since last xmit call */ c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX); txq = netdev_get_tx_queue(dev, ring->queue); @@ -1005,7 +1005,7 @@ static int bcmgenet_xmit_single(struct net_device *dev, return 0; } -/* Transmit a SKB fragement */ +/* Transmit a SKB fragment */ static int bcmgenet_xmit_frag(struct net_device *dev, skb_frag_t *frag, u16 dma_desc_flags, @@ -1481,7 +1481,7 @@ static int reset_umac(struct bcmgenet_priv *priv) if (timeout == 1000) { dev_err(kdev, - "timeout waiting for MAC to come out of resetn\n"); + "timeout waiting for MAC to come out of reset\n"); return -ETIMEDOUT; } @@ -1534,7 +1534,7 @@ static int init_umac(struct bcmgenet_priv *priv) dev_dbg(kdev, "%s:Enabling RXDMA_BDONE interrupt\n", __func__); - /* Monitor cable plug/unpluged event for internal PHY */ + /* Monitor cable plug/unplugged event for internal PHY */ if (phy_is_internal(priv->phydev)) { cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP); } else if (priv->ext_phy) { @@ -1709,7 +1709,7 @@ static void bcmgenet_init_multiq(struct net_device *dev) i * priv->hw_params->bds_cnt, (i + 1) * priv->hw_params->bds_cnt); - /* Configure ring as decriptor ring and setup priority */ + /* Configure ring as descriptor ring and setup priority */ ring_cfg |= 1 << i; dma_priority |= ((GENET_Q0_PRIORITY + i) << (GENET_MAX_MQ_CNT + 1) * i); @@ -1775,7 +1775,7 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv) /* Init tDma */ bcmgenet_tdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE); - /* Initialize commont TX ring structures */ + /* Initialize common TX ring structures */ priv->tx_bds = priv->base + priv->hw_params->tdma_offset; priv->num_tx_bds = TOTAL_DESC; priv->tx_cbs = kcalloc(priv->num_tx_bds, sizeof(struct enet_cb), @@ -1857,7 +1857,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) priv->irq1_stat = bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) & ~priv->int1_mask; - /* clear inerrupts*/ + /* clear interrupts */ bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR); netif_dbg(priv, intr, priv->dev, @@ -1885,7 +1885,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) priv->irq0_stat = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) & ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); - /* clear inerrupts*/ + /* clear interrupts */ bcmgenet_intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR); netif_dbg(priv, intr, priv->dev, @@ -2244,7 +2244,7 @@ static void bcmgenet_set_rx_mode(struct net_device *dev) netif_dbg(priv, hw, dev, "%s: %08X\n", __func__, dev->flags); - /* Promiscous mode */ + /* Promiscuous mode */ reg = bcmgenet_umac_readl(priv, UMAC_CMD); if (dev->flags & IFF_PROMISC) { reg |= CMD_PROMISC; -- cgit v1.2.3 From 9f0b4cbdee09e635906611ed8dcc5c51116cbd75 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Jul 2014 17:16:50 +0200 Subject: iwlegacy: use correct structure type name in sizeof Correct typo in the name of the type given to sizeof. Because it is the size of a pointer that is wanted, the typo has no impact on compilation or execution. This problem was found using Coccinelle (http://coccinelle.lip6.fr/). The semantic patch used can be found in message 0 of this patch series. Signed-off-by: Julia Lawall Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 03de7467aecf..2c4fa49686ef 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -2980,7 +2980,8 @@ il_tx_queue_alloc(struct il_priv *il, struct il_tx_queue *txq, u32 id) /* Driver ilate data, only for Tx (not command) queues, * not shared with device. */ if (id != il->cmd_queue) { - txq->skbs = kcalloc(TFD_QUEUE_SIZE_MAX, sizeof(struct skb *), + txq->skbs = kcalloc(TFD_QUEUE_SIZE_MAX, + sizeof(struct sk_buff *), GFP_KERNEL); if (!txq->skbs) { IL_ERR("Fail to alloc skbs\n"); -- cgit v1.2.3 From 46de06839b4936cc5fd4e6638b8fbf8437bce29e Mon Sep 17 00:00:00 2001 From: Daniel Kim Date: Wed, 30 Jul 2014 13:20:00 +0200 Subject: brcmfmac: Do not use strcpy and strcat Commit "c1b2053 brcmfmac: Make firmware path a module parameter" introduced use of strcpy and strcat. The strcpy and strcat require using null terminated strings and can cause out-of-bounds memory access and subsequent corruption. This patch replaces these by strncpy and strncat respectively to assure array boundaries are not crossed. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend Van Spriel Signed-off-by: Daniel Kim Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 25 ++++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 67d91d5cc13d..f55f625fd06b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -670,6 +670,8 @@ static int brcmf_sdio_get_fwnames(struct brcmf_chip *ci, struct brcmf_sdio_dev *sdiodev) { int i; + uint fw_len, nv_len; + char end; for (i = 0; i < ARRAY_SIZE(brcmf_fwname_data); i++) { if (brcmf_fwname_data[i].chipid == ci->chip && @@ -682,16 +684,25 @@ static int brcmf_sdio_get_fwnames(struct brcmf_chip *ci, return -ENODEV; } + fw_len = sizeof(sdiodev->fw_name) - 1; + nv_len = sizeof(sdiodev->nvram_name) - 1; /* check if firmware path is provided by module parameter */ if (brcmf_firmware_path[0] != '\0') { - if (brcmf_firmware_path[strlen(brcmf_firmware_path) - 1] != '/') - strcat(brcmf_firmware_path, "/"); - - strcpy(sdiodev->fw_name, brcmf_firmware_path); - strcpy(sdiodev->nvram_name, brcmf_firmware_path); + strncpy(sdiodev->fw_name, brcmf_firmware_path, fw_len); + strncpy(sdiodev->nvram_name, brcmf_firmware_path, nv_len); + fw_len -= strlen(sdiodev->fw_name); + nv_len -= strlen(sdiodev->nvram_name); + + end = brcmf_firmware_path[strlen(brcmf_firmware_path) - 1]; + if (end != '/') { + strncat(sdiodev->fw_name, "/", fw_len); + strncat(sdiodev->nvram_name, "/", nv_len); + fw_len--; + nv_len--; + } } - strcat(sdiodev->fw_name, brcmf_fwname_data[i].bin); - strcat(sdiodev->nvram_name, brcmf_fwname_data[i].nv); + strncat(sdiodev->fw_name, brcmf_fwname_data[i].bin, fw_len); + strncat(sdiodev->nvram_name, brcmf_fwname_data[i].nv, nv_len); return 0; } -- cgit v1.2.3 From 9374a2b514194acd4865f0183acd7c48c3b36b05 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 30 Jul 2014 13:20:01 +0200 Subject: brcmfmac: Export brcmf_netif_rx for new protocol msgbuf. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 1 + drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 7da6441bcfa8..1825f736fd45 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -181,6 +181,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp, enum brcmf_netif_stop_reason reason, bool state); void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx, bool success); +void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb); /* Sets dongle media info (drv_version, mac address). */ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index bf448081d6fb..7e14e5fa4744 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -288,7 +288,7 @@ void brcmf_txflowblock(struct device *dev, bool state) brcmf_fws_bus_blocked(drvr, state); } -static void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb) +void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb) { skb->dev = ifp->ndev; skb->protocol = eth_type_trans(skb, skb->dev); -- cgit v1.2.3 From 8851cce085dce026f14e9fc525acc71e4c9d305b Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 30 Jul 2014 13:20:02 +0200 Subject: brcmfmac: Add protocol addressing mode and peer deletion API. The soon to be added protocol msgbuf requires information about interface addressing mode and peer deletion. This patch adds the necessary APIs to proto, implements dummy functions in BCDC and adds calls to proto wherever necessary by wl_cfg80211. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcdc.c | 13 +++++++++ drivers/net/wireless/brcm80211/brcmfmac/proto.c | 8 +++++- drivers/net/wireless/brcm80211/brcmfmac/proto.h | 24 +++++++++++++++- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 33 +++++++++++++++++++++- 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c index c229210d50ba..10b48c2c4b36 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c @@ -337,6 +337,17 @@ brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset, return brcmf_bus_txdata(drvr->bus_if, pktbuf); } +static void +brcmf_proto_bcdc_configure_addr_mode(struct brcmf_pub *drvr, int ifidx, + enum proto_addr_mode addr_mode) +{ +} + +static void +brcmf_proto_bcdc_delete_peer(struct brcmf_pub *drvr, int ifidx, + u8 peer[ETH_ALEN]) +{ +} int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) { @@ -356,6 +367,8 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd; drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd; drvr->proto->txdata = brcmf_proto_bcdc_txdata; + drvr->proto->configure_addr_mode = brcmf_proto_bcdc_configure_addr_mode; + drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer; drvr->proto->pd = bcdc; drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/brcm80211/brcmfmac/proto.c index b6b464184946..d333ff8fcfff 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/proto.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.c @@ -30,6 +30,8 @@ int brcmf_proto_attach(struct brcmf_pub *drvr) { struct brcmf_proto *proto; + brcmf_dbg(TRACE, "Enter\n"); + proto = kzalloc(sizeof(*proto), GFP_ATOMIC); if (!proto) goto fail; @@ -40,7 +42,9 @@ int brcmf_proto_attach(struct brcmf_pub *drvr) goto fail; if ((proto->txdata == NULL) || (proto->hdrpull == NULL) || - (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL)) { + (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL) || + (proto->configure_addr_mode == NULL) || + (proto->delete_peer == NULL)) { brcmf_err("Not all proto handlers have been installed\n"); goto fail; } @@ -54,6 +58,8 @@ fail: void brcmf_proto_detach(struct brcmf_pub *drvr) { + brcmf_dbg(TRACE, "Enter\n"); + if (drvr->proto) { brcmf_proto_bcdc_detach(drvr); kfree(drvr->proto); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/brcm80211/brcmfmac/proto.h index 482fb0ba4a30..55942e3561a3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/proto.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.h @@ -16,6 +16,13 @@ #ifndef BRCMFMAC_PROTO_H #define BRCMFMAC_PROTO_H + +enum proto_addr_mode { + ADDR_INDIRECT = 0, + ADDR_DIRECT +}; + + struct brcmf_proto { int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, struct sk_buff *skb); @@ -25,6 +32,10 @@ struct brcmf_proto { uint len); int (*txdata)(struct brcmf_pub *drvr, int ifidx, u8 offset, struct sk_buff *skb); + void (*configure_addr_mode)(struct brcmf_pub *drvr, int ifidx, + enum proto_addr_mode addr_mode); + void (*delete_peer)(struct brcmf_pub *drvr, int ifidx, + u8 peer[ETH_ALEN]); void *pd; }; @@ -48,10 +59,21 @@ static inline int brcmf_proto_set_dcmd(struct brcmf_pub *drvr, int ifidx, return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len); } static inline int brcmf_proto_txdata(struct brcmf_pub *drvr, int ifidx, - u8 offset, struct sk_buff *skb) + u8 offset, struct sk_buff *skb) { return drvr->proto->txdata(drvr, ifidx, offset, skb); } +static inline void +brcmf_proto_configure_addr_mode(struct brcmf_pub *drvr, int ifidx, + enum proto_addr_mode addr_mode) +{ + drvr->proto->configure_addr_mode(drvr, ifidx, addr_mode); +} +static inline void +brcmf_proto_delete_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN]) +{ + drvr->proto->delete_peer(drvr, ifidx, peer); +} #endif /* BRCMFMAC_PROTO_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 48078a321716..a0e555a9f5f7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -35,6 +35,7 @@ #include "wl_cfg80211.h" #include "feature.h" #include "fwil.h" +#include "proto.h" #include "vendor.h" #define BRCMF_SCAN_IE_LEN_MAX 2048 @@ -493,6 +494,22 @@ brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable) return err; } +static void +brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev) +{ + struct net_device *ndev = wdev->netdev; + struct brcmf_if *ifp = netdev_priv(ndev); + + if ((wdev->iftype == NL80211_IFTYPE_ADHOC) || + (wdev->iftype == NL80211_IFTYPE_AP) || + (wdev->iftype == NL80211_IFTYPE_P2P_GO)) + brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx, + ADDR_DIRECT); + else + brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx, + ADDR_INDIRECT); +} + static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif) { enum nl80211_iftype iftype; @@ -512,6 +529,8 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, u32 *flags, struct vif_params *params) { + struct wireless_dev *wdev; + brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); switch (type) { case NL80211_IFTYPE_ADHOC: @@ -525,7 +544,10 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_DEVICE: - return brcmf_p2p_add_vif(wiphy, name, type, flags, params); + wdev = brcmf_p2p_add_vif(wiphy, name, type, flags, params); + if (!IS_ERR(wdev)) + brcmf_cfg80211_update_proto_addr_mode(wdev); + return wdev; case NL80211_IFTYPE_UNSPECIFIED: default: return ERR_PTR(-EINVAL); @@ -720,6 +742,8 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, } ndev->ieee80211_ptr->iftype = type; + brcmf_cfg80211_update_proto_addr_mode(&vif->wdev); + done: brcmf_dbg(TRACE, "Exit\n"); @@ -4525,6 +4549,13 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, struct ieee80211_channel *chan; s32 err = 0; + if ((e->event_code == BRCMF_E_DEAUTH) || + (e->event_code == BRCMF_E_DEAUTH_IND) || + (e->event_code == BRCMF_E_DISASSOC_IND) || + ((e->event_code == BRCMF_E_LINK) && (!e->flags))) { + brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr); + } + if (brcmf_is_apmode(ifp->vif)) { err = brcmf_notify_connect_status_ap(cfg, ndev, e, data); } else if (brcmf_is_linkup(e)) { -- cgit v1.2.3 From 9a1bb60250d2b6b546a62e5b73f55c4f1d22016b Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 30 Jul 2014 13:20:03 +0200 Subject: brcmfmac: Adding msgbuf protocol. This patch will add the msgbuf protocol. This protocol is used by the soon to be added new bus interface PCIe. Msgbuf is a protocol where most data is and remains located on the host (driver) side and transferred by DMA from and to device. Msgbuf is the protocol which takes care of the signalling of the buffers between host and device which identifies this DMA-able data. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/Makefile | 3 + .../net/wireless/brcm80211/brcmfmac/commonring.c | 273 ++++ .../net/wireless/brcm80211/brcmfmac/commonring.h | 69 + drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h | 32 + drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h | 35 +- drivers/net/wireless/brcm80211/brcmfmac/flowring.c | 362 +++++ drivers/net/wireless/brcm80211/brcmfmac/flowring.h | 74 ++ drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c | 1387 ++++++++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h | 40 + drivers/net/wireless/brcm80211/brcmfmac/proto.c | 21 +- 10 files changed, 2275 insertions(+), 21 deletions(-) create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/commonring.c create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/commonring.h create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/flowring.c create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/flowring.h create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 14e8a8d33520..0447a47fe237 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -31,6 +31,9 @@ brcmfmac-objs += \ p2p.o \ proto.o \ bcdc.o \ + commonring.o \ + flowring.o \ + msgbuf.o \ dhd_common.o \ dhd_linux.o \ firmware.o \ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.c b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c new file mode 100644 index 000000000000..c6d65b8e1e15 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.c @@ -0,0 +1,273 @@ +/* Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include + +#include "dhd.h" +#include "commonring.h" + + +/* dma flushing needs implementation for mips and arm platforms. Should + * be put in util. Note, this is not real flushing. It is virtual non + * cached memory. Only write buffers should have to be drained. Though + * this may be different depending on platform...... + * SEE ALSO msgbuf.c + */ +#define brcmf_dma_flush(addr, len) +#define brcmf_dma_invalidate_cache(addr, len) + + +void brcmf_commonring_register_cb(struct brcmf_commonring *commonring, + int (*cr_ring_bell)(void *ctx), + int (*cr_update_rptr)(void *ctx), + int (*cr_update_wptr)(void *ctx), + int (*cr_write_rptr)(void *ctx), + int (*cr_write_wptr)(void *ctx), void *ctx) +{ + commonring->cr_ring_bell = cr_ring_bell; + commonring->cr_update_rptr = cr_update_rptr; + commonring->cr_update_wptr = cr_update_wptr; + commonring->cr_write_rptr = cr_write_rptr; + commonring->cr_write_wptr = cr_write_wptr; + commonring->cr_ctx = ctx; +} + + +void brcmf_commonring_config(struct brcmf_commonring *commonring, u16 depth, + u16 item_len, void *buf_addr) +{ + commonring->depth = depth; + commonring->item_len = item_len; + commonring->buf_addr = buf_addr; + if (!commonring->inited) { + spin_lock_init(&commonring->lock); + commonring->inited = true; + } + commonring->r_ptr = 0; + if (commonring->cr_write_rptr) + commonring->cr_write_rptr(commonring->cr_ctx); + commonring->w_ptr = 0; + if (commonring->cr_write_wptr) + commonring->cr_write_wptr(commonring->cr_ctx); + commonring->f_ptr = 0; +} + + +void brcmf_commonring_lock(struct brcmf_commonring *commonring) + __acquires(&commonring->lock) +{ + unsigned long flags; + + spin_lock_irqsave(&commonring->lock, flags); + commonring->flags = flags; +} + + +void brcmf_commonring_unlock(struct brcmf_commonring *commonring) + __releases(&commonring->lock) +{ + spin_unlock_irqrestore(&commonring->lock, commonring->flags); +} + + +bool brcmf_commonring_write_available(struct brcmf_commonring *commonring) +{ + u16 available; + bool retry = true; + +again: + if (commonring->r_ptr <= commonring->w_ptr) + available = commonring->depth - commonring->w_ptr + + commonring->r_ptr; + else + available = commonring->r_ptr - commonring->w_ptr; + + if (available > 1) { + if (!commonring->was_full) + return true; + if (available > commonring->depth / 8) { + commonring->was_full = false; + return true; + } + if (retry) { + if (commonring->cr_update_rptr) + commonring->cr_update_rptr(commonring->cr_ctx); + retry = false; + goto again; + } + return false; + } + + if (retry) { + if (commonring->cr_update_rptr) + commonring->cr_update_rptr(commonring->cr_ctx); + retry = false; + goto again; + } + + commonring->was_full = true; + return false; +} + + +void *brcmf_commonring_reserve_for_write(struct brcmf_commonring *commonring) +{ + void *ret_ptr; + u16 available; + bool retry = true; + +again: + if (commonring->r_ptr <= commonring->w_ptr) + available = commonring->depth - commonring->w_ptr + + commonring->r_ptr; + else + available = commonring->r_ptr - commonring->w_ptr; + + if (available > 1) { + ret_ptr = commonring->buf_addr + + (commonring->w_ptr * commonring->item_len); + commonring->w_ptr++; + if (commonring->w_ptr == commonring->depth) + commonring->w_ptr = 0; + return ret_ptr; + } + + if (retry) { + if (commonring->cr_update_rptr) + commonring->cr_update_rptr(commonring->cr_ctx); + retry = false; + goto again; + } + + commonring->was_full = true; + return NULL; +} + + +void * +brcmf_commonring_reserve_for_write_multiple(struct brcmf_commonring *commonring, + u16 n_items, u16 *alloced) +{ + void *ret_ptr; + u16 available; + bool retry = true; + +again: + if (commonring->r_ptr <= commonring->w_ptr) + available = commonring->depth - commonring->w_ptr + + commonring->r_ptr; + else + available = commonring->r_ptr - commonring->w_ptr; + + if (available > 1) { + ret_ptr = commonring->buf_addr + + (commonring->w_ptr * commonring->item_len); + *alloced = min_t(u16, n_items, available - 1); + if (*alloced + commonring->w_ptr > commonring->depth) + *alloced = commonring->depth - commonring->w_ptr; + commonring->w_ptr += *alloced; + if (commonring->w_ptr == commonring->depth) + commonring->w_ptr = 0; + return ret_ptr; + } + + if (retry) { + if (commonring->cr_update_rptr) + commonring->cr_update_rptr(commonring->cr_ctx); + retry = false; + goto again; + } + + commonring->was_full = true; + return NULL; +} + + +int brcmf_commonring_write_complete(struct brcmf_commonring *commonring) +{ + void *address; + + address = commonring->buf_addr; + address += (commonring->f_ptr * commonring->item_len); + if (commonring->f_ptr > commonring->w_ptr) { + brcmf_dma_flush(address, + (commonring->depth - commonring->f_ptr) * + commonring->item_len); + address = commonring->buf_addr; + commonring->f_ptr = 0; + } + brcmf_dma_flush(address, (commonring->w_ptr - commonring->f_ptr) * + commonring->item_len); + + commonring->f_ptr = commonring->w_ptr; + + if (commonring->cr_write_wptr) + commonring->cr_write_wptr(commonring->cr_ctx); + if (commonring->cr_ring_bell) + return commonring->cr_ring_bell(commonring->cr_ctx); + + return -EIO; +} + + +void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring, + u16 n_items) +{ + if (commonring->w_ptr == 0) + commonring->w_ptr = commonring->depth - n_items; + else + commonring->w_ptr -= n_items; +} + + +void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring, + u16 *n_items) +{ + void *ret_addr; + + if (commonring->cr_update_wptr) + commonring->cr_update_wptr(commonring->cr_ctx); + + *n_items = (commonring->w_ptr >= commonring->r_ptr) ? + (commonring->w_ptr - commonring->r_ptr) : + (commonring->depth - commonring->r_ptr); + + if (*n_items == 0) + return NULL; + + ret_addr = commonring->buf_addr + + (commonring->r_ptr * commonring->item_len); + + commonring->r_ptr += *n_items; + if (commonring->r_ptr == commonring->depth) + commonring->r_ptr = 0; + + brcmf_dma_invalidate_cache(ret_addr, *n_ items * commonring->item_len); + + return ret_addr; +} + + +int brcmf_commonring_read_complete(struct brcmf_commonring *commonring) +{ + if (commonring->cr_write_rptr) + return commonring->cr_write_rptr(commonring->cr_ctx); + + return -EIO; +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h new file mode 100644 index 000000000000..002336e35764 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef BRCMFMAC_COMMONRING_H +#define BRCMFMAC_COMMONRING_H + + +struct brcmf_commonring { + u16 r_ptr; + u16 w_ptr; + u16 f_ptr; + u16 depth; + u16 item_len; + + void *buf_addr; + + int (*cr_ring_bell)(void *ctx); + int (*cr_update_rptr)(void *ctx); + int (*cr_update_wptr)(void *ctx); + int (*cr_write_rptr)(void *ctx); + int (*cr_write_wptr)(void *ctx); + + void *cr_ctx; + + spinlock_t lock; + unsigned long flags; + bool inited; + bool was_full; +}; + + +void brcmf_commonring_register_cb(struct brcmf_commonring *commonring, + int (*cr_ring_bell)(void *ctx), + int (*cr_update_rptr)(void *ctx), + int (*cr_update_wptr)(void *ctx), + int (*cr_write_rptr)(void *ctx), + int (*cr_write_wptr)(void *ctx), void *ctx); +void brcmf_commonring_config(struct brcmf_commonring *commonring, u16 depth, + u16 item_len, void *buf_addr); +void brcmf_commonring_lock(struct brcmf_commonring *commonring); +void brcmf_commonring_unlock(struct brcmf_commonring *commonring); +bool brcmf_commonring_write_available(struct brcmf_commonring *commonring); +void *brcmf_commonring_reserve_for_write(struct brcmf_commonring *commonring); +void * +brcmf_commonring_reserve_for_write_multiple(struct brcmf_commonring *commonring, + u16 n_items, u16 *alloced); +int brcmf_commonring_write_complete(struct brcmf_commonring *commonring); +void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring, + u16 n_items); +void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring, + u16 *n_items); +int brcmf_commonring_read_complete(struct brcmf_commonring *commonring); + +#define brcmf_commonring_n_items(commonring) (commonring->depth) +#define brcmf_commonring_len_item(commonring) (commonring->item_len) + + +#endif /* BRCMFMAC_COMMONRING_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index 7735328fff21..4053368eb743 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -19,6 +19,18 @@ #include "dhd_dbg.h" +/* IDs of the 6 default common rings of msgbuf protocol */ +#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT 0 +#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT 1 +#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE 2 +#define BRCMF_D2H_MSGRING_TX_COMPLETE 3 +#define BRCMF_D2H_MSGRING_RX_COMPLETE 4 + +#define BRCMF_NROF_H2D_COMMON_MSGRINGS 2 +#define BRCMF_NROF_D2H_COMMON_MSGRINGS 3 +#define BRCMF_NROF_COMMON_MSGRINGS (BRCMF_NROF_H2D_COMMON_MSGRINGS + \ + BRCMF_NROF_D2H_COMMON_MSGRINGS) + /* The level of bus communication with the dongle */ enum brcmf_bus_state { BRCMF_BUS_UNKNOWN, /* Not determined yet */ @@ -70,6 +82,25 @@ struct brcmf_bus_ops { struct pktq * (*gettxq)(struct device *dev); }; + +/** + * struct brcmf_bus_msgbuf - bus ringbuf if in case of msgbuf. + * + * @commonrings: commonrings which are always there. + * @flowrings: commonrings which are dynamically created and destroyed for data. + * @rx_dataoffset: if set then all rx data has this this offset. + * @max_rxbufpost: maximum number of buffers to post for rx. + * @nrof_flowrings: number of flowrings. + */ +struct brcmf_bus_msgbuf { + struct brcmf_commonring *commonrings[BRCMF_NROF_COMMON_MSGRINGS]; + struct brcmf_commonring **flowrings; + u32 rx_dataoffset; + u32 max_rxbufpost; + u32 nrof_flowrings; +}; + + /** * struct brcmf_bus - interface structure between common and bus layer * @@ -101,6 +132,7 @@ struct brcmf_bus { bool always_use_fws_queue; struct brcmf_bus_ops *ops; + struct brcmf_bus_msgbuf *msgbuf; }; /* diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index 6eade7c60c63..6804eeca7688 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h @@ -18,23 +18,24 @@ #define _BRCMF_DBG_H_ /* message levels */ -#define BRCMF_TRACE_VAL 0x00000002 -#define BRCMF_INFO_VAL 0x00000004 -#define BRCMF_DATA_VAL 0x00000008 -#define BRCMF_CTL_VAL 0x00000010 -#define BRCMF_TIMER_VAL 0x00000020 -#define BRCMF_HDRS_VAL 0x00000040 -#define BRCMF_BYTES_VAL 0x00000080 -#define BRCMF_INTR_VAL 0x00000100 -#define BRCMF_GLOM_VAL 0x00000200 -#define BRCMF_EVENT_VAL 0x00000400 -#define BRCMF_BTA_VAL 0x00000800 -#define BRCMF_FIL_VAL 0x00001000 -#define BRCMF_USB_VAL 0x00002000 -#define BRCMF_SCAN_VAL 0x00004000 -#define BRCMF_CONN_VAL 0x00008000 -#define BRCMF_BCDC_VAL 0x00010000 -#define BRCMF_SDIO_VAL 0x00020000 +#define BRCMF_TRACE_VAL 0x00000002 +#define BRCMF_INFO_VAL 0x00000004 +#define BRCMF_DATA_VAL 0x00000008 +#define BRCMF_CTL_VAL 0x00000010 +#define BRCMF_TIMER_VAL 0x00000020 +#define BRCMF_HDRS_VAL 0x00000040 +#define BRCMF_BYTES_VAL 0x00000080 +#define BRCMF_INTR_VAL 0x00000100 +#define BRCMF_GLOM_VAL 0x00000200 +#define BRCMF_EVENT_VAL 0x00000400 +#define BRCMF_BTA_VAL 0x00000800 +#define BRCMF_FIL_VAL 0x00001000 +#define BRCMF_USB_VAL 0x00002000 +#define BRCMF_SCAN_VAL 0x00004000 +#define BRCMF_CONN_VAL 0x00008000 +#define BRCMF_BCDC_VAL 0x00010000 +#define BRCMF_SDIO_VAL 0x00020000 +#define BRCMF_MSGBUF_VAL 0x00040000 /* set default print format */ #undef pr_fmt diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c new file mode 100644 index 000000000000..26cbb7c4ec4c --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c @@ -0,0 +1,362 @@ +/* Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#include +#include +#include +#include + +#include "dhd.h" +#include "dhd_dbg.h" +#include "dhd_bus.h" +#include "proto.h" +#include "flowring.h" +#include "msgbuf.h" + + +#define BRCMF_FLOWRING_HIGH 1024 +#define BRCMF_FLOWRING_LOW (BRCMF_FLOWRING_HIGH - 256) +#define BRCMF_FLOWRING_INVALID_IFIDX 0xff + +#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16) +#define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16) + +static const u8 ALLZEROMAC[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; +static const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +static const u8 brcmf_flowring_prio2fifo[] = { + 1, + 0, + 0, + 1, + 2, + 2, + 3, + 3 +}; + + +u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN], + u8 prio, u8 ifidx) +{ + struct brcmf_flowring_hash *hash; + u8 hash_idx; + u32 i; + bool found; + bool sta; + u8 fifo; + u8 *mac; + + fifo = brcmf_flowring_prio2fifo[prio]; + sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT); + mac = da; + if ((!sta) && (is_multicast_ether_addr(da))) { + mac = (u8 *)ALLFFMAC; + fifo = 0; + } + hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) : + BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx); + found = false; + hash = flow->hash; + for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { + if ((sta || (memcmp(hash[hash_idx].mac, mac, ETH_ALEN) == 0)) && + (hash[hash_idx].fifo == fifo) && + (hash[hash_idx].ifidx == ifidx)) { + found = true; + break; + } + hash_idx++; + } + if (found) + return hash[hash_idx].flowid; + + return BRCMF_FLOWRING_INVALID_ID; +} + + +u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], + u8 prio, u8 ifidx) +{ + struct brcmf_flowring_ring *ring; + struct brcmf_flowring_hash *hash; + u8 hash_idx; + u32 i; + bool found; + u8 fifo; + bool sta; + u8 *mac; + + fifo = brcmf_flowring_prio2fifo[prio]; + sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT); + mac = da; + if ((!sta) && (is_multicast_ether_addr(da))) { + mac = (u8 *)ALLFFMAC; + fifo = 0; + } + hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) : + BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx); + found = false; + hash = flow->hash; + for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { + if (((sta) && + (hash[hash_idx].ifidx == BRCMF_FLOWRING_INVALID_IFIDX)) || + ((!sta) && + (memcmp(hash[hash_idx].mac, ALLZEROMAC, ETH_ALEN) == 0))) { + found = true; + break; + } + hash_idx++; + } + if (found) { + for (i = 0; i < flow->nrofrings; i++) { + if (flow->rings[i] == NULL) + break; + } + if (i == flow->nrofrings) + return -ENOMEM; + + ring = kzalloc(sizeof(*ring), GFP_ATOMIC); + if (!ring) + return -ENOMEM; + + memcpy(hash[hash_idx].mac, mac, ETH_ALEN); + hash[hash_idx].fifo = fifo; + hash[hash_idx].ifidx = ifidx; + hash[hash_idx].flowid = i; + + ring->hash_id = hash_idx; + ring->status = RING_CLOSED; + skb_queue_head_init(&ring->skblist); + flow->rings[i] = ring; + + return i; + } + return BRCMF_FLOWRING_INVALID_ID; +} + + +u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid) +{ + struct brcmf_flowring_ring *ring; + + ring = flow->rings[flowid]; + + return flow->hash[ring->hash_id].fifo; +} + + +void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid) +{ + struct brcmf_flowring_ring *ring; + u8 hash_idx; + struct sk_buff *skb; + + ring = flow->rings[flowid]; + if (!ring) + return; + hash_idx = ring->hash_id; + flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX; + memset(flow->hash[hash_idx].mac, 0, ETH_ALEN); + flow->rings[flowid] = NULL; + + skb = skb_dequeue(&ring->skblist); + while (skb) { + brcmu_pkt_buf_free_skb(skb); + skb = skb_dequeue(&ring->skblist); + } + + kfree(ring); +} + + +void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, + struct sk_buff *skb) +{ + struct brcmf_flowring_ring *ring; + + ring = flow->rings[flowid]; + + skb_queue_tail(&ring->skblist, skb); + + if (!ring->blocked && + (skb_queue_len(&ring->skblist) > BRCMF_FLOWRING_HIGH)) { + brcmf_txflowblock(flow->dev, true); + brcmf_dbg(MSGBUF, "Flowcontrol: BLOCK for ring %d\n", flowid); + ring->blocked = 1; + } +} + + +struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid) +{ + struct brcmf_flowring_ring *ring; + struct sk_buff *skb; + + ring = flow->rings[flowid]; + if (ring->status != RING_OPEN) + return NULL; + + skb = skb_dequeue(&ring->skblist); + + if (ring->blocked && + (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)) { + brcmf_txflowblock(flow->dev, false); + brcmf_dbg(MSGBUF, "Flowcontrol: OPEN for ring %d\n", flowid); + ring->blocked = 0; + } + + return skb; +} + + +void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid, + struct sk_buff *skb) +{ + struct brcmf_flowring_ring *ring; + + ring = flow->rings[flowid]; + + skb_queue_head(&ring->skblist, skb); +} + + +u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid) +{ + struct brcmf_flowring_ring *ring; + + ring = flow->rings[flowid]; + if (!ring) + return 0; + + if (ring->status != RING_OPEN) + return 0; + + return skb_queue_len(&ring->skblist); +} + + +void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid) +{ + struct brcmf_flowring_ring *ring; + + ring = flow->rings[flowid]; + if (!ring) { + brcmf_err("Ring NULL, for flowid %d\n", flowid); + return; + } + + ring->status = RING_OPEN; +} + + +u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid) +{ + struct brcmf_flowring_ring *ring; + u8 hash_idx; + + ring = flow->rings[flowid]; + hash_idx = ring->hash_id; + + return flow->hash[hash_idx].ifidx; +} + + +struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings) +{ + struct brcmf_flowring *flow; + u32 i; + + flow = kzalloc(sizeof(*flow), GFP_ATOMIC); + if (flow) { + flow->dev = dev; + flow->nrofrings = nrofrings; + for (i = 0; i < ARRAY_SIZE(flow->addr_mode); i++) + flow->addr_mode[i] = ADDR_INDIRECT; + for (i = 0; i < ARRAY_SIZE(flow->hash); i++) + flow->hash[i].ifidx = BRCMF_FLOWRING_INVALID_IFIDX; + flow->rings = kcalloc(nrofrings, sizeof(*flow->rings), + GFP_ATOMIC); + if (!flow->rings) { + kfree(flow); + flow = NULL; + } + } + + return flow; +} + + +void brcmf_flowring_detach(struct brcmf_flowring *flow) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev); + struct brcmf_pub *drvr = bus_if->drvr; + u8 flowid; + + for (flowid = 0; flowid < flow->nrofrings; flowid++) { + if (flow->rings[flowid]) + brcmf_msgbuf_delete_flowring(drvr, flowid); + } + kfree(flow->rings); + kfree(flow); +} + + +void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx, + enum proto_addr_mode addr_mode) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev); + struct brcmf_pub *drvr = bus_if->drvr; + u32 i; + u8 flowid; + + if (flow->addr_mode[ifidx] != addr_mode) { + for (i = 0; i < ARRAY_SIZE(flow->hash); i++) { + if (flow->hash[i].ifidx == ifidx) { + flowid = flow->hash[i].flowid; + if (flow->rings[flowid]->status != RING_OPEN) + continue; + flow->rings[flowid]->status = RING_CLOSING; + brcmf_msgbuf_delete_flowring(drvr, flowid); + } + } + flow->addr_mode[ifidx] = addr_mode; + } +} + + +void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx, + u8 peer[ETH_ALEN]) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev); + struct brcmf_pub *drvr = bus_if->drvr; + struct brcmf_flowring_hash *hash; + u32 i; + u8 flowid; + bool sta; + + sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT); + hash = flow->hash; + for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { + if ((sta || (memcmp(hash[i].mac, peer, ETH_ALEN) == 0)) && + (hash[i].ifidx == ifidx)) { + flowid = flow->hash[i].flowid; + if (flow->rings[flowid]->status == RING_OPEN) { + flow->rings[flowid]->status = RING_CLOSING; + brcmf_msgbuf_delete_flowring(drvr, flowid); + } + } + } +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h new file mode 100644 index 000000000000..677f4b8065f6 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef BRCMFMAC_FLOWRING_H +#define BRCMFMAC_FLOWRING_H + + +#define BRCMF_FLOWRING_HASHSIZE 256 +#define BRCMF_FLOWRING_INVALID_ID 0xFFFFFFFF + + +struct brcmf_flowring_hash { + u8 mac[ETH_ALEN]; + u8 fifo; + u8 ifidx; + u8 flowid; +}; + +enum ring_status { + RING_CLOSED, + RING_CLOSING, + RING_OPEN +}; + +struct brcmf_flowring_ring { + u8 hash_id; + u8 blocked; + enum ring_status status; + struct sk_buff_head skblist; +}; + +struct brcmf_flowring { + struct device *dev; + struct brcmf_flowring_hash hash[BRCMF_FLOWRING_HASHSIZE]; + struct brcmf_flowring_ring **rings; + enum proto_addr_mode addr_mode[BRCMF_MAX_IFS]; + u16 nrofrings; +}; + + +u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN], + u8 prio, u8 ifidx); +u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], + u8 prio, u8 ifidx); +void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid); +void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid); +u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid); +void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, + struct sk_buff *skb); +struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid); +void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid, + struct sk_buff *skb); +u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid); +u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid); +struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings); +void brcmf_flowring_detach(struct brcmf_flowring *flow); +void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx, + enum proto_addr_mode addr_mode); +void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx, + u8 peer[ETH_ALEN]); + + +#endif /* BRCMFMAC_FLOWRING_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c new file mode 100644 index 000000000000..c7a1c59ba6c3 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c @@ -0,0 +1,1387 @@ +/* Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/******************************************************************************* + * Communicates with the dongle by using dcmd codes. + * For certain dcmd codes, the dongle interprets string data from the host. + ******************************************************************************/ + +#include +#include + +#include +#include + +#include "dhd.h" +#include "dhd_dbg.h" +#include "proto.h" +#include "msgbuf.h" +#include "commonring.h" +#include "flowring.h" +#include "dhd_bus.h" +#include "tracepoint.h" + + +#define MSGBUF_IOCTL_RESP_TIMEOUT 2000 + +#define MSGBUF_TYPE_GEN_STATUS 0x1 +#define MSGBUF_TYPE_RING_STATUS 0x2 +#define MSGBUF_TYPE_FLOW_RING_CREATE 0x3 +#define MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT 0x4 +#define MSGBUF_TYPE_FLOW_RING_DELETE 0x5 +#define MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT 0x6 +#define MSGBUF_TYPE_FLOW_RING_FLUSH 0x7 +#define MSGBUF_TYPE_FLOW_RING_FLUSH_CMPLT 0x8 +#define MSGBUF_TYPE_IOCTLPTR_REQ 0x9 +#define MSGBUF_TYPE_IOCTLPTR_REQ_ACK 0xA +#define MSGBUF_TYPE_IOCTLRESP_BUF_POST 0xB +#define MSGBUF_TYPE_IOCTL_CMPLT 0xC +#define MSGBUF_TYPE_EVENT_BUF_POST 0xD +#define MSGBUF_TYPE_WL_EVENT 0xE +#define MSGBUF_TYPE_TX_POST 0xF +#define MSGBUF_TYPE_TX_STATUS 0x10 +#define MSGBUF_TYPE_RXBUF_POST 0x11 +#define MSGBUF_TYPE_RX_CMPLT 0x12 +#define MSGBUF_TYPE_LPBK_DMAXFER 0x13 +#define MSGBUF_TYPE_LPBK_DMAXFER_CMPLT 0x14 + +#define NR_TX_PKTIDS 2048 +#define NR_RX_PKTIDS 1024 + +#define BRCMF_IOCTL_REQ_PKTID 0xFFFE + +#define BRCMF_MSGBUF_MAX_PKT_SIZE 2048 +#define BRCMF_MSGBUF_RXBUFPOST_THRESHOLD 32 +#define BRCMF_MSGBUF_MAX_IOCTLRESPBUF_POST 8 +#define BRCMF_MSGBUF_MAX_EVENTBUF_POST 8 + +#define BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3 0x01 +#define BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT 5 + +#define BRCMF_MSGBUF_TX_FLUSH_CNT1 32 +#define BRCMF_MSGBUF_TX_FLUSH_CNT2 96 + + +struct msgbuf_common_hdr { + u8 msgtype; + u8 ifidx; + u8 flags; + u8 rsvd0; + __le32 request_id; +}; + +struct msgbuf_buf_addr { + __le32 low_addr; + __le32 high_addr; +}; + +struct msgbuf_ioctl_req_hdr { + struct msgbuf_common_hdr msg; + __le32 cmd; + __le16 trans_id; + __le16 input_buf_len; + __le16 output_buf_len; + __le16 rsvd0[3]; + struct msgbuf_buf_addr req_buf_addr; + __le32 rsvd1[2]; +}; + +struct msgbuf_tx_msghdr { + struct msgbuf_common_hdr msg; + u8 txhdr[ETH_HLEN]; + u8 flags; + u8 seg_cnt; + struct msgbuf_buf_addr metadata_buf_addr; + struct msgbuf_buf_addr data_buf_addr; + __le16 metadata_buf_len; + __le16 data_len; + __le32 rsvd0; +}; + +struct msgbuf_rx_bufpost { + struct msgbuf_common_hdr msg; + __le16 metadata_buf_len; + __le16 data_buf_len; + __le32 rsvd0; + struct msgbuf_buf_addr metadata_buf_addr; + struct msgbuf_buf_addr data_buf_addr; +}; + +struct msgbuf_rx_ioctl_resp_or_event { + struct msgbuf_common_hdr msg; + __le16 host_buf_len; + __le16 rsvd0[3]; + struct msgbuf_buf_addr host_buf_addr; + __le32 rsvd1[4]; +}; + +struct msgbuf_completion_hdr { + __le16 status; + __le16 flow_ring_id; +}; + +struct msgbuf_rx_event { + struct msgbuf_common_hdr msg; + struct msgbuf_completion_hdr compl_hdr; + __le16 event_data_len; + __le16 seqnum; + __le16 rsvd0[4]; +}; + +struct msgbuf_ioctl_resp_hdr { + struct msgbuf_common_hdr msg; + struct msgbuf_completion_hdr compl_hdr; + __le16 resp_len; + __le16 trans_id; + __le32 cmd; + __le32 rsvd0; +}; + +struct msgbuf_tx_status { + struct msgbuf_common_hdr msg; + struct msgbuf_completion_hdr compl_hdr; + __le16 metadata_len; + __le16 tx_status; +}; + +struct msgbuf_rx_complete { + struct msgbuf_common_hdr msg; + struct msgbuf_completion_hdr compl_hdr; + __le16 metadata_len; + __le16 data_len; + __le16 data_offset; + __le16 flags; + __le32 rx_status_0; + __le32 rx_status_1; + __le32 rsvd0; +}; + +struct msgbuf_tx_flowring_create_req { + struct msgbuf_common_hdr msg; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u8 tid; + u8 if_flags; + __le16 flow_ring_id; + u8 tc; + u8 priority; + __le16 int_vector; + __le16 max_items; + __le16 len_item; + struct msgbuf_buf_addr flow_ring_addr; +}; + +struct msgbuf_tx_flowring_delete_req { + struct msgbuf_common_hdr msg; + __le16 flow_ring_id; + __le16 reason; + __le32 rsvd0[7]; +}; + +struct msgbuf_flowring_create_resp { + struct msgbuf_common_hdr msg; + struct msgbuf_completion_hdr compl_hdr; + __le32 rsvd0[3]; +}; + +struct msgbuf_flowring_delete_resp { + struct msgbuf_common_hdr msg; + struct msgbuf_completion_hdr compl_hdr; + __le32 rsvd0[3]; +}; + +struct msgbuf_flowring_flush_resp { + struct msgbuf_common_hdr msg; + struct msgbuf_completion_hdr compl_hdr; + __le32 rsvd0[3]; +}; + +struct brcmf_msgbuf { + struct brcmf_pub *drvr; + + struct brcmf_commonring **commonrings; + struct brcmf_commonring **flowrings; + dma_addr_t *flowring_dma_handle; + u16 nrof_flowrings; + + u16 rx_dataoffset; + u32 max_rxbufpost; + u16 rx_metadata_offset; + u32 rxbufpost; + + u32 max_ioctlrespbuf; + u32 cur_ioctlrespbuf; + u32 max_eventbuf; + u32 cur_eventbuf; + + void *ioctbuf; + dma_addr_t ioctbuf_handle; + u32 ioctbuf_phys_hi; + u32 ioctbuf_phys_lo; + u32 ioctl_resp_status; + u32 ioctl_resp_ret_len; + u32 ioctl_resp_pktid; + + u16 data_seq_no; + u16 ioctl_seq_no; + u32 reqid; + wait_queue_head_t ioctl_resp_wait; + bool ctl_completed; + + struct brcmf_msgbuf_pktids *tx_pktids; + struct brcmf_msgbuf_pktids *rx_pktids; + struct brcmf_flowring *flow; + + struct workqueue_struct *txflow_wq; + struct work_struct txflow_work; + unsigned long *flow_map; + unsigned long *txstatus_done_map; +}; + +struct brcmf_msgbuf_pktid { + atomic_t allocated; + u16 data_offset; + struct sk_buff *skb; + dma_addr_t physaddr; +}; + +struct brcmf_msgbuf_pktids { + u32 array_size; + u32 last_allocated_idx; + enum dma_data_direction direction; + struct brcmf_msgbuf_pktid *array; +}; + + +/* dma flushing needs implementation for mips and arm platforms. Should + * be put in util. Note, this is not real flushing. It is virtual non + * cached memory. Only write buffers should have to be drained. Though + * this may be different depending on platform...... + */ +#define brcmf_dma_flush(addr, len) +#define brcmf_dma_invalidate_cache(addr, len) + + +static void brcmf_msgbuf_rxbuf_ioctlresp_post(struct brcmf_msgbuf *msgbuf); + + +static struct brcmf_msgbuf_pktids * +brcmf_msgbuf_init_pktids(u32 nr_array_entries, + enum dma_data_direction direction) +{ + struct brcmf_msgbuf_pktid *array; + struct brcmf_msgbuf_pktids *pktids; + + array = kcalloc(nr_array_entries, sizeof(*array), GFP_ATOMIC); + if (!array) + return NULL; + + pktids = kzalloc(sizeof(*pktids), GFP_ATOMIC); + if (!pktids) { + kfree(array); + return NULL; + } + pktids->array = array; + pktids->array_size = nr_array_entries; + + return pktids; +} + + +static int +brcmf_msgbuf_alloc_pktid(struct device *dev, + struct brcmf_msgbuf_pktids *pktids, + struct sk_buff *skb, u16 data_offset, + dma_addr_t *physaddr, u32 *idx) +{ + struct brcmf_msgbuf_pktid *array; + u32 count; + + array = pktids->array; + + *physaddr = dma_map_single(dev, skb->data + data_offset, + skb->len - data_offset, pktids->direction); + + if (dma_mapping_error(dev, *physaddr)) { + brcmf_err("dma_map_single failed !!\n"); + return -ENOMEM; + } + + *idx = pktids->last_allocated_idx; + + count = 0; + do { + (*idx)++; + if (*idx == pktids->array_size) + *idx = 0; + if (array[*idx].allocated.counter == 0) + if (atomic_cmpxchg(&array[*idx].allocated, 0, 1) == 0) + break; + count++; + } while (count < pktids->array_size); + + if (count == pktids->array_size) + return -ENOMEM; + + array[*idx].data_offset = data_offset; + array[*idx].physaddr = *physaddr; + array[*idx].skb = skb; + + pktids->last_allocated_idx = *idx; + + return 0; +} + + +static struct sk_buff * +brcmf_msgbuf_get_pktid(struct device *dev, struct brcmf_msgbuf_pktids *pktids, + u32 idx) +{ + struct brcmf_msgbuf_pktid *pktid; + struct sk_buff *skb; + + if (idx >= pktids->array_size) { + brcmf_err("Invalid packet id %d (max %d)\n", idx, + pktids->array_size); + return NULL; + } + if (pktids->array[idx].allocated.counter) { + pktid = &pktids->array[idx]; + dma_unmap_single(dev, pktid->physaddr, + pktid->skb->len - pktid->data_offset, + pktids->direction); + skb = pktid->skb; + pktid->allocated.counter = 0; + return skb; + } else { + brcmf_err("Invalid packet id %d (not in use)\n", idx); + } + + return NULL; +} + + +static void +brcmf_msgbuf_release_array(struct device *dev, + struct brcmf_msgbuf_pktids *pktids) +{ + struct brcmf_msgbuf_pktid *array; + struct brcmf_msgbuf_pktid *pktid; + u32 count; + + array = pktids->array; + count = 0; + do { + if (array[count].allocated.counter) { + pktid = &array[count]; + dma_unmap_single(dev, pktid->physaddr, + pktid->skb->len - pktid->data_offset, + pktids->direction); + brcmu_pkt_buf_free_skb(pktid->skb); + } + count++; + } while (count < pktids->array_size); + + kfree(array); + kfree(pktids); +} + + +static void brcmf_msgbuf_release_pktids(struct brcmf_msgbuf *msgbuf) +{ + if (msgbuf->rx_pktids) + brcmf_msgbuf_release_array(msgbuf->drvr->bus_if->dev, + msgbuf->rx_pktids); + if (msgbuf->tx_pktids) + brcmf_msgbuf_release_array(msgbuf->drvr->bus_if->dev, + msgbuf->tx_pktids); +} + + +static int brcmf_msgbuf_tx_ioctl(struct brcmf_pub *drvr, int ifidx, + uint cmd, void *buf, uint len) +{ + struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + struct brcmf_commonring *commonring; + struct msgbuf_ioctl_req_hdr *request; + u16 buf_len; + void *ret_ptr; + int err; + + commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT]; + brcmf_commonring_lock(commonring); + ret_ptr = brcmf_commonring_reserve_for_write(commonring); + if (!ret_ptr) { + brcmf_err("Failed to reserve space in commonring\n"); + brcmf_commonring_unlock(commonring); + return -ENOMEM; + } + + msgbuf->reqid++; + + request = (struct msgbuf_ioctl_req_hdr *)ret_ptr; + request->msg.msgtype = MSGBUF_TYPE_IOCTLPTR_REQ; + request->msg.ifidx = (u8)ifidx; + request->msg.flags = 0; + request->msg.request_id = cpu_to_le32(BRCMF_IOCTL_REQ_PKTID); + request->cmd = cpu_to_le32(cmd); + request->output_buf_len = cpu_to_le16(len); + request->trans_id = cpu_to_le16(msgbuf->reqid); + + buf_len = min_t(u16, len, BRCMF_TX_IOCTL_MAX_MSG_SIZE); + request->input_buf_len = cpu_to_le16(buf_len); + request->req_buf_addr.high_addr = cpu_to_le32(msgbuf->ioctbuf_phys_hi); + request->req_buf_addr.low_addr = cpu_to_le32(msgbuf->ioctbuf_phys_lo); + if (buf) + memcpy(msgbuf->ioctbuf, buf, buf_len); + else + memset(msgbuf->ioctbuf, 0, buf_len); + brcmf_dma_flush(ioctl_buf, buf_len); + + err = brcmf_commonring_write_complete(commonring); + brcmf_commonring_unlock(commonring); + + return err; +} + + +static int brcmf_msgbuf_ioctl_resp_wait(struct brcmf_msgbuf *msgbuf) +{ + return wait_event_timeout(msgbuf->ioctl_resp_wait, + msgbuf->ctl_completed, + msecs_to_jiffies(MSGBUF_IOCTL_RESP_TIMEOUT)); +} + + +static void brcmf_msgbuf_ioctl_resp_wake(struct brcmf_msgbuf *msgbuf) +{ + if (waitqueue_active(&msgbuf->ioctl_resp_wait)) { + msgbuf->ctl_completed = true; + wake_up(&msgbuf->ioctl_resp_wait); + } +} + + +static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx, + uint cmd, void *buf, uint len) +{ + struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + struct sk_buff *skb = NULL; + int timeout; + int err; + + brcmf_dbg(MSGBUF, "ifidx=%d, cmd=%d, len=%d\n", ifidx, cmd, len); + msgbuf->ctl_completed = false; + err = brcmf_msgbuf_tx_ioctl(drvr, ifidx, cmd, buf, len); + if (err) + return err; + + timeout = brcmf_msgbuf_ioctl_resp_wait(msgbuf); + if (!timeout) { + brcmf_err("Timeout on response for query command\n"); + return -EIO; + } + + skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, + msgbuf->rx_pktids, + msgbuf->ioctl_resp_pktid); + if (msgbuf->ioctl_resp_ret_len != 0) { + if (!skb) { + brcmf_err("Invalid packet id idx recv'd %d\n", + msgbuf->ioctl_resp_pktid); + return -EBADF; + } + memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ? + len : msgbuf->ioctl_resp_ret_len); + } + if (skb) + brcmu_pkt_buf_free_skb(skb); + + return msgbuf->ioctl_resp_status; +} + + +static int brcmf_msgbuf_set_dcmd(struct brcmf_pub *drvr, int ifidx, + uint cmd, void *buf, uint len) +{ + return brcmf_msgbuf_query_dcmd(drvr, ifidx, cmd, buf, len); +} + + +static int brcmf_msgbuf_hdrpull(struct brcmf_pub *drvr, bool do_fws, + u8 *ifidx, struct sk_buff *skb) +{ + return -ENODEV; +} + + +static void +brcmf_msgbuf_remove_flowring(struct brcmf_msgbuf *msgbuf, u16 flowid) +{ + u32 dma_sz; + void *dma_buf; + + brcmf_dbg(MSGBUF, "Removing flowring %d\n", flowid); + + dma_sz = BRCMF_H2D_TXFLOWRING_MAX_ITEM * BRCMF_H2D_TXFLOWRING_ITEMSIZE; + dma_buf = msgbuf->flowrings[flowid]->buf_addr; + dma_free_coherent(msgbuf->drvr->bus_if->dev, dma_sz, dma_buf, + msgbuf->flowring_dma_handle[flowid]); + + brcmf_flowring_delete(msgbuf->flow, flowid); +} + + +static u32 brcmf_msgbuf_flowring_create(struct brcmf_msgbuf *msgbuf, int ifidx, + struct sk_buff *skb) +{ + struct msgbuf_tx_flowring_create_req *create; + struct ethhdr *eh = (struct ethhdr *)(skb->data); + struct brcmf_commonring *commonring; + void *ret_ptr; + u32 flowid; + void *dma_buf; + u32 dma_sz; + long long address; + int err; + + flowid = brcmf_flowring_create(msgbuf->flow, eh->h_dest, + skb->priority, ifidx); + if (flowid == BRCMF_FLOWRING_INVALID_ID) + return flowid; + + dma_sz = BRCMF_H2D_TXFLOWRING_MAX_ITEM * BRCMF_H2D_TXFLOWRING_ITEMSIZE; + + dma_buf = dma_alloc_coherent(msgbuf->drvr->bus_if->dev, dma_sz, + &msgbuf->flowring_dma_handle[flowid], + GFP_ATOMIC); + if (!dma_buf) { + brcmf_err("dma_alloc_coherent failed\n"); + brcmf_flowring_delete(msgbuf->flow, flowid); + return BRCMF_FLOWRING_INVALID_ID; + } + + brcmf_commonring_config(msgbuf->flowrings[flowid], + BRCMF_H2D_TXFLOWRING_MAX_ITEM, + BRCMF_H2D_TXFLOWRING_ITEMSIZE, dma_buf); + + commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT]; + brcmf_commonring_lock(commonring); + ret_ptr = brcmf_commonring_reserve_for_write(commonring); + if (!ret_ptr) { + brcmf_err("Failed to reserve space in commonring\n"); + brcmf_commonring_unlock(commonring); + brcmf_msgbuf_remove_flowring(msgbuf, flowid); + return BRCMF_FLOWRING_INVALID_ID; + } + + create = (struct msgbuf_tx_flowring_create_req *)ret_ptr; + create->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE; + create->msg.ifidx = ifidx; + create->msg.request_id = 0; + create->tid = brcmf_flowring_tid(msgbuf->flow, flowid); + create->flow_ring_id = cpu_to_le16(flowid + + BRCMF_NROF_H2D_COMMON_MSGRINGS); + memcpy(create->sa, eh->h_source, ETH_ALEN); + memcpy(create->da, eh->h_dest, ETH_ALEN); + address = (long long)(long)msgbuf->flowring_dma_handle[flowid]; + create->flow_ring_addr.high_addr = cpu_to_le32(address >> 32); + create->flow_ring_addr.low_addr = cpu_to_le32(address & 0xffffffff); + create->max_items = cpu_to_le16(BRCMF_H2D_TXFLOWRING_MAX_ITEM); + create->len_item = cpu_to_le16(BRCMF_H2D_TXFLOWRING_ITEMSIZE); + + brcmf_dbg(MSGBUF, "Send Flow Create Req flow ID %d for peer %pM prio %d ifindex %d\n", + flowid, eh->h_dest, create->tid, ifidx); + + err = brcmf_commonring_write_complete(commonring); + brcmf_commonring_unlock(commonring); + if (err) { + brcmf_err("Failed to write commonring\n"); + brcmf_msgbuf_remove_flowring(msgbuf, flowid); + return BRCMF_FLOWRING_INVALID_ID; + } + + return flowid; +} + + +static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid) +{ + struct brcmf_flowring *flow = msgbuf->flow; + struct brcmf_commonring *commonring; + void *ret_ptr; + u32 count; + struct sk_buff *skb; + dma_addr_t physaddr; + u32 pktid; + struct msgbuf_tx_msghdr *tx_msghdr; + long long address; + + commonring = msgbuf->flowrings[flowid]; + if (!brcmf_commonring_write_available(commonring)) + return; + + brcmf_commonring_lock(commonring); + + count = BRCMF_MSGBUF_TX_FLUSH_CNT2 - BRCMF_MSGBUF_TX_FLUSH_CNT1; + while (brcmf_flowring_qlen(flow, flowid)) { + skb = brcmf_flowring_dequeue(flow, flowid); + if (skb == NULL) { + brcmf_err("No SKB, but qlen %d\n", + brcmf_flowring_qlen(flow, flowid)); + break; + } + skb_orphan(skb); + if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev, + msgbuf->tx_pktids, skb, ETH_HLEN, + &physaddr, &pktid)) { + brcmf_flowring_reinsert(flow, flowid, skb); + brcmf_err("No PKTID available !!\n"); + break; + } + ret_ptr = brcmf_commonring_reserve_for_write(commonring); + if (!ret_ptr) { + brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, + msgbuf->tx_pktids, pktid); + brcmf_flowring_reinsert(flow, flowid, skb); + break; + } + count++; + + tx_msghdr = (struct msgbuf_tx_msghdr *)ret_ptr; + + tx_msghdr->msg.msgtype = MSGBUF_TYPE_TX_POST; + tx_msghdr->msg.request_id = cpu_to_le32(pktid); + tx_msghdr->msg.ifidx = brcmf_flowring_ifidx_get(flow, flowid); + tx_msghdr->flags = BRCMF_MSGBUF_PKT_FLAGS_FRAME_802_3; + tx_msghdr->flags |= (skb->priority & 0x07) << + BRCMF_MSGBUF_PKT_FLAGS_PRIO_SHIFT; + tx_msghdr->seg_cnt = 1; + memcpy(tx_msghdr->txhdr, skb->data, ETH_HLEN); + tx_msghdr->data_len = cpu_to_le16(skb->len - ETH_HLEN); + address = (long long)(long)physaddr; + tx_msghdr->data_buf_addr.high_addr = cpu_to_le32(address >> 32); + tx_msghdr->data_buf_addr.low_addr = + cpu_to_le32(address & 0xffffffff); + tx_msghdr->metadata_buf_len = 0; + tx_msghdr->metadata_buf_addr.high_addr = 0; + tx_msghdr->metadata_buf_addr.low_addr = 0; + if (count >= BRCMF_MSGBUF_TX_FLUSH_CNT2) { + brcmf_commonring_write_complete(commonring); + count = 0; + } + } + if (count) + brcmf_commonring_write_complete(commonring); + brcmf_commonring_unlock(commonring); +} + + +static void brcmf_msgbuf_txflow_worker(struct work_struct *worker) +{ + struct brcmf_msgbuf *msgbuf; + u32 flowid; + + msgbuf = container_of(worker, struct brcmf_msgbuf, txflow_work); + for_each_set_bit(flowid, msgbuf->flow_map, msgbuf->nrof_flowrings) { + clear_bit(flowid, msgbuf->flow_map); + brcmf_msgbuf_txflow(msgbuf, flowid); + } +} + + +static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid) +{ + set_bit(flowid, msgbuf->flow_map); + queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work); + + return 0; +} + + +static int brcmf_msgbuf_txdata(struct brcmf_pub *drvr, int ifidx, + u8 offset, struct sk_buff *skb) +{ + struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + struct brcmf_flowring *flow = msgbuf->flow; + struct ethhdr *eh = (struct ethhdr *)(skb->data); + u32 flowid; + + flowid = brcmf_flowring_lookup(flow, eh->h_dest, skb->priority, ifidx); + if (flowid == BRCMF_FLOWRING_INVALID_ID) { + flowid = brcmf_msgbuf_flowring_create(msgbuf, ifidx, skb); + if (flowid == BRCMF_FLOWRING_INVALID_ID) + return -ENOMEM; + } + brcmf_flowring_enqueue(flow, flowid, skb); + brcmf_msgbuf_schedule_txdata(msgbuf, flowid); + + return 0; +} + + +static void +brcmf_msgbuf_configure_addr_mode(struct brcmf_pub *drvr, int ifidx, + enum proto_addr_mode addr_mode) +{ + struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + + brcmf_flowring_configure_addr_mode(msgbuf->flow, ifidx, addr_mode); +} + + +static void +brcmf_msgbuf_delete_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN]) +{ + struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + + brcmf_flowring_delete_peer(msgbuf->flow, ifidx, peer); +} + + +static void +brcmf_msgbuf_process_ioctl_complete(struct brcmf_msgbuf *msgbuf, void *buf) +{ + struct msgbuf_ioctl_resp_hdr *ioctl_resp; + + ioctl_resp = (struct msgbuf_ioctl_resp_hdr *)buf; + + msgbuf->ioctl_resp_status = le16_to_cpu(ioctl_resp->compl_hdr.status); + msgbuf->ioctl_resp_ret_len = le16_to_cpu(ioctl_resp->resp_len); + msgbuf->ioctl_resp_pktid = le32_to_cpu(ioctl_resp->msg.request_id); + + brcmf_msgbuf_ioctl_resp_wake(msgbuf); + + if (msgbuf->cur_ioctlrespbuf) + msgbuf->cur_ioctlrespbuf--; + brcmf_msgbuf_rxbuf_ioctlresp_post(msgbuf); +} + + +static void +brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf) +{ + struct msgbuf_tx_status *tx_status; + u32 idx; + struct sk_buff *skb; + u16 flowid; + + tx_status = (struct msgbuf_tx_status *)buf; + idx = le32_to_cpu(tx_status->msg.request_id); + flowid = le16_to_cpu(tx_status->compl_hdr.flow_ring_id); + flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS; + skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, + msgbuf->tx_pktids, idx); + if (!skb) { + brcmf_err("Invalid packet id idx recv'd %d\n", idx); + return; + } + + set_bit(flowid, msgbuf->txstatus_done_map); + + brcmf_txfinalize(msgbuf->drvr, skb, tx_status->msg.ifidx, true); +} + + +static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count) +{ + struct brcmf_commonring *commonring; + void *ret_ptr; + struct sk_buff *skb; + u16 alloced; + u32 pktlen; + dma_addr_t physaddr; + struct msgbuf_rx_bufpost *rx_bufpost; + long long address; + u32 pktid; + u32 i; + + commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_RXPOST_SUBMIT]; + ret_ptr = brcmf_commonring_reserve_for_write_multiple(commonring, + count, + &alloced); + if (!ret_ptr) { + brcmf_err("Failed to reserve space in commonring\n"); + return 0; + } + + for (i = 0; i < alloced; i++) { + rx_bufpost = (struct msgbuf_rx_bufpost *)ret_ptr; + memset(rx_bufpost, 0, sizeof(*rx_bufpost)); + + skb = brcmu_pkt_buf_get_skb(BRCMF_MSGBUF_MAX_PKT_SIZE); + + if (skb == NULL) { + brcmf_err("Failed to alloc SKB\n"); + brcmf_commonring_write_cancel(commonring, alloced - i); + break; + } + + pktlen = skb->len; + if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev, + msgbuf->rx_pktids, skb, 0, + &physaddr, &pktid)) { + dev_kfree_skb_any(skb); + brcmf_err("No PKTID available !!\n"); + brcmf_commonring_write_cancel(commonring, alloced - i); + break; + } + + if (msgbuf->rx_metadata_offset) { + address = (long long)(long)physaddr; + rx_bufpost->metadata_buf_len = + cpu_to_le16(msgbuf->rx_metadata_offset); + rx_bufpost->metadata_buf_addr.high_addr = + cpu_to_le32(address >> 32); + rx_bufpost->metadata_buf_addr.low_addr = + cpu_to_le32(address & 0xffffffff); + + skb_pull(skb, msgbuf->rx_metadata_offset); + pktlen = skb->len; + physaddr += msgbuf->rx_metadata_offset; + } + rx_bufpost->msg.msgtype = MSGBUF_TYPE_RXBUF_POST; + rx_bufpost->msg.request_id = cpu_to_le32(pktid); + + address = (long long)(long)physaddr; + rx_bufpost->data_buf_len = cpu_to_le16((u16)pktlen); + rx_bufpost->data_buf_addr.high_addr = + cpu_to_le32(address >> 32); + rx_bufpost->data_buf_addr.low_addr = + cpu_to_le32(address & 0xffffffff); + + ret_ptr += brcmf_commonring_len_item(commonring); + } + + if (i) + brcmf_commonring_write_complete(commonring); + + return i; +} + + +static void +brcmf_msgbuf_rxbuf_data_fill(struct brcmf_msgbuf *msgbuf) +{ + u32 fillbufs; + u32 retcount; + + fillbufs = msgbuf->max_rxbufpost - msgbuf->rxbufpost; + + while (fillbufs) { + retcount = brcmf_msgbuf_rxbuf_data_post(msgbuf, fillbufs); + if (!retcount) + break; + msgbuf->rxbufpost += retcount; + fillbufs -= retcount; + } +} + + +static void +brcmf_msgbuf_update_rxbufpost_count(struct brcmf_msgbuf *msgbuf, u16 rxcnt) +{ + msgbuf->rxbufpost -= rxcnt; + if (msgbuf->rxbufpost <= (msgbuf->max_rxbufpost - + BRCMF_MSGBUF_RXBUFPOST_THRESHOLD)) + brcmf_msgbuf_rxbuf_data_fill(msgbuf); +} + + +static u32 +brcmf_msgbuf_rxbuf_ctrl_post(struct brcmf_msgbuf *msgbuf, bool event_buf, + u32 count) +{ + struct brcmf_commonring *commonring; + void *ret_ptr; + struct sk_buff *skb; + u16 alloced; + u32 pktlen; + dma_addr_t physaddr; + struct msgbuf_rx_ioctl_resp_or_event *rx_bufpost; + long long address; + u32 pktid; + u32 i; + + commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT]; + brcmf_commonring_lock(commonring); + ret_ptr = brcmf_commonring_reserve_for_write_multiple(commonring, + count, + &alloced); + if (!ret_ptr) { + brcmf_err("Failed to reserve space in commonring\n"); + brcmf_commonring_unlock(commonring); + return 0; + } + + for (i = 0; i < alloced; i++) { + rx_bufpost = (struct msgbuf_rx_ioctl_resp_or_event *)ret_ptr; + memset(rx_bufpost, 0, sizeof(*rx_bufpost)); + + skb = brcmu_pkt_buf_get_skb(BRCMF_MSGBUF_MAX_PKT_SIZE); + + if (skb == NULL) { + brcmf_err("Failed to alloc SKB\n"); + brcmf_commonring_write_cancel(commonring, alloced - i); + break; + } + + pktlen = skb->len; + if (brcmf_msgbuf_alloc_pktid(msgbuf->drvr->bus_if->dev, + msgbuf->rx_pktids, skb, 0, + &physaddr, &pktid)) { + dev_kfree_skb_any(skb); + brcmf_err("No PKTID available !!\n"); + brcmf_commonring_write_cancel(commonring, alloced - i); + break; + } + if (event_buf) + rx_bufpost->msg.msgtype = MSGBUF_TYPE_EVENT_BUF_POST; + else + rx_bufpost->msg.msgtype = + MSGBUF_TYPE_IOCTLRESP_BUF_POST; + rx_bufpost->msg.request_id = cpu_to_le32(pktid); + + address = (long long)(long)physaddr; + rx_bufpost->host_buf_len = cpu_to_le16((u16)pktlen); + rx_bufpost->host_buf_addr.high_addr = + cpu_to_le32(address >> 32); + rx_bufpost->host_buf_addr.low_addr = + cpu_to_le32(address & 0xffffffff); + + ret_ptr += brcmf_commonring_len_item(commonring); + } + + if (i) + brcmf_commonring_write_complete(commonring); + + brcmf_commonring_unlock(commonring); + + return i; +} + + +static void brcmf_msgbuf_rxbuf_ioctlresp_post(struct brcmf_msgbuf *msgbuf) +{ + u32 count; + + count = msgbuf->max_ioctlrespbuf - msgbuf->cur_ioctlrespbuf; + count = brcmf_msgbuf_rxbuf_ctrl_post(msgbuf, false, count); + msgbuf->cur_ioctlrespbuf += count; +} + + +static void brcmf_msgbuf_rxbuf_event_post(struct brcmf_msgbuf *msgbuf) +{ + u32 count; + + count = msgbuf->max_eventbuf - msgbuf->cur_eventbuf; + count = brcmf_msgbuf_rxbuf_ctrl_post(msgbuf, true, count); + msgbuf->cur_eventbuf += count; +} + + +static void +brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb, + u8 ifidx) +{ + struct brcmf_if *ifp; + + ifp = msgbuf->drvr->iflist[ifidx]; + if (!ifp || !ifp->ndev) { + brcmu_pkt_buf_free_skb(skb); + return; + } + brcmf_netif_rx(ifp, skb); +} + + +static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf) +{ + struct msgbuf_rx_event *event; + u32 idx; + u16 buflen; + struct sk_buff *skb; + + event = (struct msgbuf_rx_event *)buf; + idx = le32_to_cpu(event->msg.request_id); + buflen = le16_to_cpu(event->event_data_len); + + if (msgbuf->cur_eventbuf) + msgbuf->cur_eventbuf--; + brcmf_msgbuf_rxbuf_event_post(msgbuf); + + skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, + msgbuf->rx_pktids, idx); + if (!skb) + return; + + if (msgbuf->rx_dataoffset) + skb_pull(skb, msgbuf->rx_dataoffset); + + skb_trim(skb, buflen); + + brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx); +} + + +static void +brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf) +{ + struct msgbuf_rx_complete *rx_complete; + struct sk_buff *skb; + u16 data_offset; + u16 buflen; + u32 idx; + + brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1); + + rx_complete = (struct msgbuf_rx_complete *)buf; + data_offset = le16_to_cpu(rx_complete->data_offset); + buflen = le16_to_cpu(rx_complete->data_len); + idx = le32_to_cpu(rx_complete->msg.request_id); + + skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, + msgbuf->rx_pktids, idx); + + if (data_offset) + skb_pull(skb, data_offset); + else if (msgbuf->rx_dataoffset) + skb_pull(skb, msgbuf->rx_dataoffset); + + skb_trim(skb, buflen); + + brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx); +} + + +static void +brcmf_msgbuf_process_flow_ring_create_response(struct brcmf_msgbuf *msgbuf, + void *buf) +{ + struct msgbuf_flowring_create_resp *flowring_create_resp; + u16 status; + u16 flowid; + + flowring_create_resp = (struct msgbuf_flowring_create_resp *)buf; + + flowid = le16_to_cpu(flowring_create_resp->compl_hdr.flow_ring_id); + flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS; + status = le16_to_cpu(flowring_create_resp->compl_hdr.status); + + if (status) { + brcmf_err("Flowring creation failed, code %d\n", status); + brcmf_msgbuf_remove_flowring(msgbuf, flowid); + return; + } + brcmf_dbg(MSGBUF, "Flowring %d Create response status %d\n", flowid, + status); + + brcmf_flowring_open(msgbuf->flow, flowid); + + brcmf_msgbuf_schedule_txdata(msgbuf, flowid); +} + + +static void +brcmf_msgbuf_process_flow_ring_delete_response(struct brcmf_msgbuf *msgbuf, + void *buf) +{ + struct msgbuf_flowring_delete_resp *flowring_delete_resp; + u16 status; + u16 flowid; + + flowring_delete_resp = (struct msgbuf_flowring_delete_resp *)buf; + + flowid = le16_to_cpu(flowring_delete_resp->compl_hdr.flow_ring_id); + flowid -= BRCMF_NROF_H2D_COMMON_MSGRINGS; + status = le16_to_cpu(flowring_delete_resp->compl_hdr.status); + + if (status) { + brcmf_err("Flowring deletion failed, code %d\n", status); + brcmf_flowring_delete(msgbuf->flow, flowid); + return; + } + brcmf_dbg(MSGBUF, "Flowring %d Delete response status %d\n", flowid, + status); + + brcmf_msgbuf_remove_flowring(msgbuf, flowid); +} + + +static void brcmf_msgbuf_process_msgtype(struct brcmf_msgbuf *msgbuf, void *buf) +{ + struct msgbuf_common_hdr *msg; + + msg = (struct msgbuf_common_hdr *)buf; + switch (msg->msgtype) { + case MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT: + brcmf_dbg(MSGBUF, "MSGBUF_TYPE_FLOW_RING_CREATE_CMPLT\n"); + brcmf_msgbuf_process_flow_ring_create_response(msgbuf, buf); + break; + case MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT: + brcmf_dbg(MSGBUF, "MSGBUF_TYPE_FLOW_RING_DELETE_CMPLT\n"); + brcmf_msgbuf_process_flow_ring_delete_response(msgbuf, buf); + break; + case MSGBUF_TYPE_IOCTLPTR_REQ_ACK: + brcmf_dbg(MSGBUF, "MSGBUF_TYPE_IOCTLPTR_REQ_ACK\n"); + break; + case MSGBUF_TYPE_IOCTL_CMPLT: + brcmf_dbg(MSGBUF, "MSGBUF_TYPE_IOCTL_CMPLT\n"); + brcmf_msgbuf_process_ioctl_complete(msgbuf, buf); + break; + case MSGBUF_TYPE_WL_EVENT: + brcmf_dbg(MSGBUF, "MSGBUF_TYPE_WL_EVENT\n"); + brcmf_msgbuf_process_event(msgbuf, buf); + break; + case MSGBUF_TYPE_TX_STATUS: + brcmf_dbg(MSGBUF, "MSGBUF_TYPE_TX_STATUS\n"); + brcmf_msgbuf_process_txstatus(msgbuf, buf); + break; + case MSGBUF_TYPE_RX_CMPLT: + brcmf_dbg(MSGBUF, "MSGBUF_TYPE_RX_CMPLT\n"); + brcmf_msgbuf_process_rx_complete(msgbuf, buf); + break; + default: + brcmf_err("Unsupported msgtype %d\n", msg->msgtype); + break; + } +} + + +static void brcmf_msgbuf_process_rx(struct brcmf_msgbuf *msgbuf, + struct brcmf_commonring *commonring) +{ + void *buf; + u16 count; + +again: + buf = brcmf_commonring_get_read_ptr(commonring, &count); + if (buf == NULL) + return; + + while (count) { + brcmf_msgbuf_process_msgtype(msgbuf, + buf + msgbuf->rx_dataoffset); + buf += brcmf_commonring_len_item(commonring); + count--; + } + brcmf_commonring_read_complete(commonring); + + if (commonring->r_ptr == 0) + goto again; +} + + +int brcmf_proto_msgbuf_rx_trigger(struct device *dev) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; + struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + void *buf; + u32 flowid; + + buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE]; + brcmf_msgbuf_process_rx(msgbuf, buf); + buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE]; + brcmf_msgbuf_process_rx(msgbuf, buf); + buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE]; + brcmf_msgbuf_process_rx(msgbuf, buf); + + for_each_set_bit(flowid, msgbuf->txstatus_done_map, + msgbuf->nrof_flowrings) { + clear_bit(flowid, msgbuf->txstatus_done_map); + if (brcmf_flowring_qlen(msgbuf->flow, flowid)) + brcmf_msgbuf_schedule_txdata(msgbuf, flowid); + } + + return 0; +} + + +void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid) +{ + struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + struct msgbuf_tx_flowring_delete_req *delete; + struct brcmf_commonring *commonring; + void *ret_ptr; + u8 ifidx; + int err; + + commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT]; + brcmf_commonring_lock(commonring); + ret_ptr = brcmf_commonring_reserve_for_write(commonring); + if (!ret_ptr) { + brcmf_err("FW unaware, flowring will be removed !!\n"); + brcmf_commonring_unlock(commonring); + brcmf_msgbuf_remove_flowring(msgbuf, flowid); + return; + } + + delete = (struct msgbuf_tx_flowring_delete_req *)ret_ptr; + + ifidx = brcmf_flowring_ifidx_get(msgbuf->flow, flowid); + + delete->msg.msgtype = MSGBUF_TYPE_FLOW_RING_DELETE; + delete->msg.ifidx = ifidx; + delete->msg.request_id = 0; + + delete->flow_ring_id = cpu_to_le16(flowid + + BRCMF_NROF_H2D_COMMON_MSGRINGS); + delete->reason = 0; + + brcmf_dbg(MSGBUF, "Send Flow Delete Req flow ID %d, ifindex %d\n", + flowid, ifidx); + + err = brcmf_commonring_write_complete(commonring); + brcmf_commonring_unlock(commonring); + if (err) { + brcmf_err("Failed to submit RING_DELETE, flowring will be removed\n"); + brcmf_msgbuf_remove_flowring(msgbuf, flowid); + } +} + + +int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) +{ + struct brcmf_bus_msgbuf *if_msgbuf; + struct brcmf_msgbuf *msgbuf; + long long address; + u32 count; + + if_msgbuf = drvr->bus_if->msgbuf; + msgbuf = kzalloc(sizeof(*msgbuf), GFP_ATOMIC); + if (!msgbuf) + goto fail; + + msgbuf->txflow_wq = create_singlethread_workqueue("msgbuf_txflow"); + if (msgbuf->txflow_wq == NULL) { + brcmf_err("workqueue creation failed\n"); + goto fail; + } + INIT_WORK(&msgbuf->txflow_work, brcmf_msgbuf_txflow_worker); + count = BITS_TO_LONGS(if_msgbuf->nrof_flowrings); + msgbuf->flow_map = kzalloc(count, GFP_ATOMIC); + if (!msgbuf->flow_map) + goto fail; + + msgbuf->txstatus_done_map = kzalloc(count, GFP_ATOMIC); + if (!msgbuf->txstatus_done_map) + goto fail; + + msgbuf->drvr = drvr; + msgbuf->ioctbuf = dma_alloc_coherent(drvr->bus_if->dev, + BRCMF_TX_IOCTL_MAX_MSG_SIZE, + &msgbuf->ioctbuf_handle, + GFP_ATOMIC); + if (!msgbuf->ioctbuf) + goto fail; + address = (long long)(long)msgbuf->ioctbuf_handle; + msgbuf->ioctbuf_phys_hi = address >> 32; + msgbuf->ioctbuf_phys_lo = address & 0xffffffff; + + drvr->proto->hdrpull = brcmf_msgbuf_hdrpull; + drvr->proto->query_dcmd = brcmf_msgbuf_query_dcmd; + drvr->proto->set_dcmd = brcmf_msgbuf_set_dcmd; + drvr->proto->txdata = brcmf_msgbuf_txdata; + drvr->proto->configure_addr_mode = brcmf_msgbuf_configure_addr_mode; + drvr->proto->delete_peer = brcmf_msgbuf_delete_peer; + drvr->proto->pd = msgbuf; + + init_waitqueue_head(&msgbuf->ioctl_resp_wait); + + msgbuf->commonrings = + (struct brcmf_commonring **)if_msgbuf->commonrings; + msgbuf->flowrings = (struct brcmf_commonring **)if_msgbuf->flowrings; + msgbuf->nrof_flowrings = if_msgbuf->nrof_flowrings; + msgbuf->flowring_dma_handle = kzalloc(msgbuf->nrof_flowrings * + sizeof(*msgbuf->flowring_dma_handle), GFP_ATOMIC); + + msgbuf->rx_dataoffset = if_msgbuf->rx_dataoffset; + msgbuf->max_rxbufpost = if_msgbuf->max_rxbufpost; + + msgbuf->max_ioctlrespbuf = BRCMF_MSGBUF_MAX_IOCTLRESPBUF_POST; + msgbuf->max_eventbuf = BRCMF_MSGBUF_MAX_EVENTBUF_POST; + + msgbuf->tx_pktids = brcmf_msgbuf_init_pktids(NR_TX_PKTIDS, + DMA_TO_DEVICE); + if (!msgbuf->tx_pktids) + goto fail; + msgbuf->rx_pktids = brcmf_msgbuf_init_pktids(NR_RX_PKTIDS, + DMA_FROM_DEVICE); + if (!msgbuf->rx_pktids) + goto fail; + + msgbuf->flow = brcmf_flowring_attach(drvr->bus_if->dev, + if_msgbuf->nrof_flowrings); + if (!msgbuf->flow) + goto fail; + + + brcmf_dbg(MSGBUF, "Feeding buffers, rx data %d, rx event %d, rx ioctl resp %d\n", + msgbuf->max_rxbufpost, msgbuf->max_eventbuf, + msgbuf->max_ioctlrespbuf); + count = 0; + do { + brcmf_msgbuf_rxbuf_data_fill(msgbuf); + if (msgbuf->max_rxbufpost != msgbuf->rxbufpost) + msleep(10); + else + break; + count++; + } while (count < 10); + brcmf_msgbuf_rxbuf_event_post(msgbuf); + brcmf_msgbuf_rxbuf_ioctlresp_post(msgbuf); + + return 0; + +fail: + if (msgbuf) { + kfree(msgbuf->flow_map); + kfree(msgbuf->txstatus_done_map); + brcmf_msgbuf_release_pktids(msgbuf); + if (msgbuf->ioctbuf) + dma_free_coherent(drvr->bus_if->dev, + BRCMF_TX_IOCTL_MAX_MSG_SIZE, + msgbuf->ioctbuf, + msgbuf->ioctbuf_handle); + kfree(msgbuf); + } + return -ENOMEM; +} + + +void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr) +{ + struct brcmf_msgbuf *msgbuf; + + brcmf_dbg(TRACE, "Enter\n"); + if (drvr->proto->pd) { + msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + + kfree(msgbuf->flow_map); + kfree(msgbuf->txstatus_done_map); + if (msgbuf->txflow_wq) + destroy_workqueue(msgbuf->txflow_wq); + + brcmf_flowring_detach(msgbuf->flow); + dma_free_coherent(drvr->bus_if->dev, + BRCMF_TX_IOCTL_MAX_MSG_SIZE, + msgbuf->ioctbuf, msgbuf->ioctbuf_handle); + brcmf_msgbuf_release_pktids(msgbuf); + kfree(msgbuf); + drvr->proto->pd = NULL; + } +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h new file mode 100644 index 000000000000..f901ae52bf2b --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef BRCMFMAC_MSGBUF_H +#define BRCMFMAC_MSGBUF_H + + +#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM 20 +#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 256 +#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_MAX_ITEM 20 +#define BRCMF_D2H_MSGRING_TX_COMPLETE_MAX_ITEM 1024 +#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 256 +#define BRCMF_H2D_TXFLOWRING_MAX_ITEM 512 + +#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_ITEMSIZE 40 +#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_ITEMSIZE 32 +#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_ITEMSIZE 24 +#define BRCMF_D2H_MSGRING_TX_COMPLETE_ITEMSIZE 16 +#define BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE 32 +#define BRCMF_H2D_TXFLOWRING_ITEMSIZE 48 + + +int brcmf_proto_msgbuf_rx_trigger(struct device *dev); +int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr); +void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr); +void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid); + + +#endif /* BRCMFMAC_MSGBUF_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/brcm80211/brcmfmac/proto.c index d333ff8fcfff..44b1cb466d4e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/proto.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.c @@ -21,9 +21,11 @@ #include #include "dhd.h" +#include "dhd_bus.h" #include "dhd_dbg.h" #include "proto.h" #include "bcdc.h" +#include "msgbuf.h" int brcmf_proto_attach(struct brcmf_pub *drvr) @@ -37,10 +39,18 @@ int brcmf_proto_attach(struct brcmf_pub *drvr) goto fail; drvr->proto = proto; - /* BCDC protocol is only protocol supported for the moment */ - if (brcmf_proto_bcdc_attach(drvr)) - goto fail; + if (drvr->bus_if->proto_type == BRCMF_PROTO_BCDC) { + if (brcmf_proto_bcdc_attach(drvr)) + goto fail; + } else if (drvr->bus_if->proto_type == BRCMF_PROTO_MSGBUF) { + if (brcmf_proto_msgbuf_attach(drvr)) + goto fail; + } else { + brcmf_err("Unsupported proto type %d\n", + drvr->bus_if->proto_type); + goto fail; + } if ((proto->txdata == NULL) || (proto->hdrpull == NULL) || (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL) || (proto->configure_addr_mode == NULL) || @@ -61,7 +71,10 @@ void brcmf_proto_detach(struct brcmf_pub *drvr) brcmf_dbg(TRACE, "Enter\n"); if (drvr->proto) { - brcmf_proto_bcdc_detach(drvr); + if (drvr->bus_if->proto_type == BRCMF_PROTO_BCDC) + brcmf_proto_bcdc_detach(drvr); + else if (drvr->bus_if->proto_type == BRCMF_PROTO_MSGBUF) + brcmf_proto_msgbuf_detach(drvr); kfree(drvr->proto); drvr->proto = NULL; } -- cgit v1.2.3 From 9e37f045d5e7f33450515f237c2f6f6bfee137dd Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 30 Jul 2014 13:20:04 +0200 Subject: brcmfmac: Adding PCIe bus layer support. This patch will add PCIe support. With this patch the PCIe chipsets 43602, 4354, 4356, 43567, and 43570 will be supported. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/Kconfig | 10 + drivers/net/wireless/brcm80211/brcmfmac/Makefile | 2 + drivers/net/wireless/brcm80211/brcmfmac/chip.c | 8 + drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h | 1 + drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h | 1 + .../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 7 + drivers/net/wireless/brcm80211/brcmfmac/pcie.c | 1811 ++++++++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/pcie.h | 29 + .../net/wireless/brcm80211/include/brcm_hw_ids.h | 11 + 9 files changed, 1880 insertions(+) create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/pcie.c create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/pcie.h diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig index fcfed6b99a62..b8e2561ea645 100644 --- a/drivers/net/wireless/brcm80211/Kconfig +++ b/drivers/net/wireless/brcm80211/Kconfig @@ -48,6 +48,16 @@ config BRCMFMAC_USB IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to use the driver for an USB wireless card. +config BRCMFMAC_PCIE + bool "PCIE bus interface support for FullMAC driver" + depends on BRCMFMAC + depends on PCI + select FW_LOADER + ---help--- + This option enables the PCIE bus interface support for Broadcom + IEEE802.11ac embedded FullMAC WLAN driver. Say Y if you want to + use the driver for an PCIE wireless card. + config BRCM_TRACING bool "Broadcom device tracing" depends on BRCMSMAC || BRCMFMAC diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 0447a47fe237..c35adf4bc70b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -45,6 +45,8 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ bcmsdh.o brcmfmac-$(CONFIG_BRCMFMAC_USB) += \ usb.o +brcmfmac-$(CONFIG_BRCMFMAC_PCIE) += \ + pcie.o brcmfmac-$(CONFIG_BRCMDBG) += \ dhd_dbg.o brcmfmac-$(CONFIG_BRCM_TRACING) += \ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index 96800db0536b..95efde868db8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -506,9 +506,17 @@ static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci) break; case BRCM_CC_4339_CHIP_ID: case BRCM_CC_4354_CHIP_ID: + case BRCM_CC_4356_CHIP_ID: + case BRCM_CC_43567_CHIP_ID: + case BRCM_CC_43569_CHIP_ID: + case BRCM_CC_43570_CHIP_ID: ci->pub.ramsize = 0xc0000; ci->pub.rambase = 0x180000; break; + case BRCM_CC_43602_CHIP_ID: + ci->pub.ramsize = 0xf0000; + ci->pub.rambase = 0x180000; + break; default: brcmf_err("unknown chip: %s\n", ci->pub.name); break; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index 4053368eb743..3122b86050a1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -120,6 +120,7 @@ struct brcmf_bus { union { struct brcmf_sdio_dev *sdio; struct brcmf_usbdev *usb; + struct brcmf_pciedev *pcie; } bus_priv; enum brcmf_bus_protocol_type proto_type; struct device *dev; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index 6804eeca7688..dec40d316c82 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h @@ -36,6 +36,7 @@ #define BRCMF_BCDC_VAL 0x00010000 #define BRCMF_SDIO_VAL 0x00020000 #define BRCMF_MSGBUF_VAL 0x00040000 +#define BRCMF_PCIE_VAL 0x00080000 /* set default print format */ #undef pr_fmt diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 7e14e5fa4744..b456bcb7f916 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -32,6 +32,7 @@ #include "fwsignal.h" #include "feature.h" #include "proto.h" +#include "pcie.h" MODULE_AUTHOR("Broadcom Corporation"); MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); @@ -1084,6 +1085,9 @@ static void brcmf_driver_register(struct work_struct *work) #ifdef CONFIG_BRCMFMAC_USB brcmf_usb_register(); #endif +#ifdef CONFIG_BRCMFMAC_PCIE + brcmf_pcie_register(); +#endif } static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register); @@ -1108,6 +1112,9 @@ static void __exit brcmfmac_module_exit(void) #endif #ifdef CONFIG_BRCMFMAC_USB brcmf_usb_exit(); +#endif +#ifdef CONFIG_BRCMFMAC_PCIE + brcmf_pcie_exit(); #endif brcmf_debugfs_exit(); } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c new file mode 100644 index 000000000000..89be96d3b6e9 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c @@ -0,0 +1,1811 @@ +/* Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "dhd_dbg.h" +#include "dhd_bus.h" +#include "commonring.h" +#include "msgbuf.h" +#include "pcie.h" +#include "firmware.h" +#include "chip.h" + + +enum brcmf_pcie_state { + BRCMFMAC_PCIE_STATE_DOWN, + BRCMFMAC_PCIE_STATE_UP +}; + + +#define BRCMF_PCIE_43602_FW_NAME "brcm/brcmfmac43602-pcie.bin" +#define BRCMF_PCIE_43602_NVRAM_NAME "brcm/brcmfmac43602-pcie.txt" +#define BRCMF_PCIE_4354_FW_NAME "brcm/brcmfmac4354-pcie.bin" +#define BRCMF_PCIE_4354_NVRAM_NAME "brcm/brcmfmac4354-pcie.txt" +#define BRCMF_PCIE_4356_FW_NAME "brcm/brcmfmac4356-pcie.bin" +#define BRCMF_PCIE_4356_NVRAM_NAME "brcm/brcmfmac4356-pcie.txt" +#define BRCMF_PCIE_43570_FW_NAME "brcm/brcmfmac43570-pcie.bin" +#define BRCMF_PCIE_43570_NVRAM_NAME "brcm/brcmfmac43570-pcie.txt" + +#define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */ + +#define BRCMF_PCIE_TCM_MAP_SIZE (4096 * 1024) +#define BRCMF_PCIE_REG_MAP_SIZE (32 * 1024) + +/* backplane addres space accessed by BAR0 */ +#define BRCMF_PCIE_BAR0_WINDOW 0x80 +#define BRCMF_PCIE_BAR0_REG_SIZE 0x1000 +#define BRCMF_PCIE_BAR0_WRAPPERBASE 0x70 + +#define BRCMF_PCIE_BAR0_WRAPBASE_DMP_OFFSET 0x1000 +#define BRCMF_PCIE_BARO_PCIE_ENUM_OFFSET 0x2000 + +#define BRCMF_PCIE_ARMCR4REG_BANKIDX 0x40 +#define BRCMF_PCIE_ARMCR4REG_BANKPDA 0x4C + +#define BRCMF_PCIE_REG_INTSTATUS 0x90 +#define BRCMF_PCIE_REG_INTMASK 0x94 +#define BRCMF_PCIE_REG_SBMBX 0x98 + +#define BRCMF_PCIE_PCIE2REG_INTMASK 0x24 +#define BRCMF_PCIE_PCIE2REG_MAILBOXINT 0x48 +#define BRCMF_PCIE_PCIE2REG_MAILBOXMASK 0x4C +#define BRCMF_PCIE_PCIE2REG_CONFIGADDR 0x120 +#define BRCMF_PCIE_PCIE2REG_CONFIGDATA 0x124 +#define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX 0x140 + +#define BRCMF_PCIE_GENREV1 1 +#define BRCMF_PCIE_GENREV2 2 + +#define BRCMF_PCIE2_INTA 0x01 +#define BRCMF_PCIE2_INTB 0x02 + +#define BRCMF_PCIE_INT_0 0x01 +#define BRCMF_PCIE_INT_1 0x02 +#define BRCMF_PCIE_INT_DEF (BRCMF_PCIE_INT_0 | \ + BRCMF_PCIE_INT_1) + +#define BRCMF_PCIE_MB_INT_FN0_0 0x0100 +#define BRCMF_PCIE_MB_INT_FN0_1 0x0200 +#define BRCMF_PCIE_MB_INT_D2H0_DB0 0x10000 +#define BRCMF_PCIE_MB_INT_D2H0_DB1 0x20000 +#define BRCMF_PCIE_MB_INT_D2H1_DB0 0x40000 +#define BRCMF_PCIE_MB_INT_D2H1_DB1 0x80000 +#define BRCMF_PCIE_MB_INT_D2H2_DB0 0x100000 +#define BRCMF_PCIE_MB_INT_D2H2_DB1 0x200000 +#define BRCMF_PCIE_MB_INT_D2H3_DB0 0x400000 +#define BRCMF_PCIE_MB_INT_D2H3_DB1 0x800000 + +#define BRCMF_PCIE_MB_INT_D2H_DB (BRCMF_PCIE_MB_INT_D2H0_DB0 | \ + BRCMF_PCIE_MB_INT_D2H0_DB1 | \ + BRCMF_PCIE_MB_INT_D2H1_DB0 | \ + BRCMF_PCIE_MB_INT_D2H1_DB1 | \ + BRCMF_PCIE_MB_INT_D2H2_DB0 | \ + BRCMF_PCIE_MB_INT_D2H2_DB1 | \ + BRCMF_PCIE_MB_INT_D2H3_DB0 | \ + BRCMF_PCIE_MB_INT_D2H3_DB1) + +#define BRCMF_PCIE_MIN_SHARED_VERSION 4 +#define BRCMF_PCIE_MAX_SHARED_VERSION 5 +#define BRCMF_PCIE_SHARED_VERSION_MASK 0x00FF +#define BRCMF_PCIE_SHARED_TXPUSH_SUPPORT 0x4000 + +#define BRCMF_PCIE_FLAGS_HTOD_SPLIT 0x4000 +#define BRCMF_PCIE_FLAGS_DTOH_SPLIT 0x8000 + +#define BRCMF_SHARED_MAX_RXBUFPOST_OFFSET 34 +#define BRCMF_SHARED_RING_BASE_OFFSET 52 +#define BRCMF_SHARED_RX_DATAOFFSET_OFFSET 36 +#define BRCMF_SHARED_CONSOLE_ADDR_OFFSET 20 +#define BRCMF_SHARED_HTOD_MB_DATA_ADDR_OFFSET 40 +#define BRCMF_SHARED_DTOH_MB_DATA_ADDR_OFFSET 44 +#define BRCMF_SHARED_RING_INFO_ADDR_OFFSET 48 +#define BRCMF_SHARED_DMA_SCRATCH_LEN_OFFSET 52 +#define BRCMF_SHARED_DMA_SCRATCH_ADDR_OFFSET 56 +#define BRCMF_SHARED_DMA_RINGUPD_LEN_OFFSET 64 +#define BRCMF_SHARED_DMA_RINGUPD_ADDR_OFFSET 68 + +#define BRCMF_RING_H2D_RING_COUNT_OFFSET 0 +#define BRCMF_RING_D2H_RING_COUNT_OFFSET 1 +#define BRCMF_RING_H2D_RING_MEM_OFFSET 4 +#define BRCMF_RING_H2D_RING_STATE_OFFSET 8 + +#define BRCMF_RING_MEM_BASE_ADDR_OFFSET 8 +#define BRCMF_RING_MAX_ITEM_OFFSET 4 +#define BRCMF_RING_LEN_ITEMS_OFFSET 6 +#define BRCMF_RING_MEM_SZ 16 +#define BRCMF_RING_STATE_SZ 8 + +#define BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET 4 +#define BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET 8 +#define BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET 12 +#define BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET 16 +#define BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET 0 +#define BRCMF_SHARED_RING_MAX_SUB_QUEUES 52 + +#define BRCMF_DEF_MAX_RXBUFPOST 255 + +#define BRCMF_CONSOLE_BUFADDR_OFFSET 8 +#define BRCMF_CONSOLE_BUFSIZE_OFFSET 12 +#define BRCMF_CONSOLE_WRITEIDX_OFFSET 16 + +#define BRCMF_DMA_D2H_SCRATCH_BUF_LEN 8 +#define BRCMF_DMA_D2H_RINGUPD_BUF_LEN 1024 + +#define BRCMF_D2H_DEV_D3_ACK 0x00000001 +#define BRCMF_D2H_DEV_DS_ENTER_REQ 0x00000002 +#define BRCMF_D2H_DEV_DS_EXIT_NOTE 0x00000004 + +#define BRCMF_H2D_HOST_D3_INFORM 0x00000001 +#define BRCMF_H2D_HOST_DS_ACK 0x00000002 + +#define BRCMF_PCIE_MBDATA_TIMEOUT 2000 + + +MODULE_FIRMWARE(BRCMF_PCIE_43602_FW_NAME); +MODULE_FIRMWARE(BRCMF_PCIE_43602_NVRAM_NAME); +MODULE_FIRMWARE(BRCMF_PCIE_4354_FW_NAME); +MODULE_FIRMWARE(BRCMF_PCIE_4354_NVRAM_NAME); +MODULE_FIRMWARE(BRCMF_PCIE_43570_FW_NAME); +MODULE_FIRMWARE(BRCMF_PCIE_43570_NVRAM_NAME); + + +struct brcmf_pcie_console { + u32 base_addr; + u32 buf_addr; + u32 bufsize; + u32 read_idx; + u8 log_str[256]; + u8 log_idx; +}; + +struct brcmf_pcie_shared_info { + u32 tcm_base_address; + u32 flags; + struct brcmf_pcie_ringbuf *commonrings[BRCMF_NROF_COMMON_MSGRINGS]; + struct brcmf_pcie_ringbuf *flowrings; + u16 max_rxbufpost; + u32 nrof_flowrings; + u32 rx_dataoffset; + u32 htod_mb_data_addr; + u32 dtoh_mb_data_addr; + u32 ring_info_addr; + struct brcmf_pcie_console console; + void *scratch; + dma_addr_t scratch_dmahandle; + void *ringupd; + dma_addr_t ringupd_dmahandle; +}; + +struct brcmf_pcie_core_info { + u32 base; + u32 wrapbase; +}; + +struct brcmf_pciedev_info { + enum brcmf_pcie_state state; + bool in_irq; + bool irq_requested; + struct pci_dev *pdev; + char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN]; + char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN]; + void __iomem *regs; + void __iomem *tcm; + u32 tcm_size; + u32 ram_base; + u32 ram_size; + struct brcmf_chip *ci; + u32 coreid; + u32 generic_corerev; + struct brcmf_pcie_shared_info shared; + void (*ringbell)(struct brcmf_pciedev_info *devinfo); + wait_queue_head_t mbdata_resp_wait; + bool mbdata_completed; + bool irq_allocated; +}; + +struct brcmf_pcie_ringbuf { + struct brcmf_commonring commonring; + dma_addr_t dma_handle; + u32 w_idx_addr; + u32 r_idx_addr; + struct brcmf_pciedev_info *devinfo; + u8 id; +}; + + +static const u32 brcmf_ring_max_item[BRCMF_NROF_COMMON_MSGRINGS] = { + BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM, + BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM, + BRCMF_D2H_MSGRING_CONTROL_COMPLETE_MAX_ITEM, + BRCMF_D2H_MSGRING_TX_COMPLETE_MAX_ITEM, + BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM +}; + +static const u32 brcmf_ring_itemsize[BRCMF_NROF_COMMON_MSGRINGS] = { + BRCMF_H2D_MSGRING_CONTROL_SUBMIT_ITEMSIZE, + BRCMF_H2D_MSGRING_RXPOST_SUBMIT_ITEMSIZE, + BRCMF_D2H_MSGRING_CONTROL_COMPLETE_ITEMSIZE, + BRCMF_D2H_MSGRING_TX_COMPLETE_ITEMSIZE, + BRCMF_D2H_MSGRING_RX_COMPLETE_ITEMSIZE +}; + + +/* dma flushing needs implementation for mips and arm platforms. Should + * be put in util. Note, this is not real flushing. It is virtual non + * cached memory. Only write buffers should have to be drained. Though + * this may be different depending on platform...... + */ +#define brcmf_dma_flush(addr, len) +#define brcmf_dma_invalidate_cache(addr, len) + + +static u32 +brcmf_pcie_read_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset) +{ + void __iomem *address = devinfo->regs + reg_offset; + + return (ioread32(address)); +} + + +static void +brcmf_pcie_write_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset, + u32 value) +{ + void __iomem *address = devinfo->regs + reg_offset; + + iowrite32(value, address); +} + + +static u8 +brcmf_pcie_read_tcm8(struct brcmf_pciedev_info *devinfo, u32 mem_offset) +{ + void __iomem *address = devinfo->tcm + mem_offset; + + return (ioread8(address)); +} + + +static u16 +brcmf_pcie_read_tcm16(struct brcmf_pciedev_info *devinfo, u32 mem_offset) +{ + void __iomem *address = devinfo->tcm + mem_offset; + + return (ioread16(address)); +} + + +static void +brcmf_pcie_write_tcm16(struct brcmf_pciedev_info *devinfo, u32 mem_offset, + u16 value) +{ + void __iomem *address = devinfo->tcm + mem_offset; + + iowrite16(value, address); +} + + +static u32 +brcmf_pcie_read_tcm32(struct brcmf_pciedev_info *devinfo, u32 mem_offset) +{ + void __iomem *address = devinfo->tcm + mem_offset; + + return (ioread32(address)); +} + + +static void +brcmf_pcie_write_tcm32(struct brcmf_pciedev_info *devinfo, u32 mem_offset, + u32 value) +{ + void __iomem *address = devinfo->tcm + mem_offset; + + iowrite32(value, address); +} + + +static u32 +brcmf_pcie_read_ram32(struct brcmf_pciedev_info *devinfo, u32 mem_offset) +{ + void __iomem *addr = devinfo->tcm + devinfo->ci->rambase + mem_offset; + + return (ioread32(addr)); +} + + +static void +brcmf_pcie_write_ram32(struct brcmf_pciedev_info *devinfo, u32 mem_offset, + u32 value) +{ + void __iomem *addr = devinfo->tcm + devinfo->ci->rambase + mem_offset; + + iowrite32(value, addr); +} + + +static void +brcmf_pcie_copy_mem_todev(struct brcmf_pciedev_info *devinfo, u32 mem_offset, + void *srcaddr, u32 len) +{ + void __iomem *address = devinfo->tcm + mem_offset; + __le32 *src32; + __le16 *src16; + u8 *src8; + + if (((ulong)address & 4) || ((ulong)srcaddr & 4) || (len & 4)) { + if (((ulong)address & 2) || ((ulong)srcaddr & 2) || (len & 2)) { + src8 = (u8 *)srcaddr; + while (len) { + iowrite8(*src8, address); + address++; + src8++; + len--; + } + } else { + len = len / 2; + src16 = (__le16 *)srcaddr; + while (len) { + iowrite16(le16_to_cpu(*src16), address); + address += 2; + src16++; + len--; + } + } + } else { + len = len / 4; + src32 = (__le32 *)srcaddr; + while (len) { + iowrite32(le32_to_cpu(*src32), address); + address += 4; + src32++; + len--; + } + } +} + + +#define WRITECC32(devinfo, reg, value) brcmf_pcie_write_reg32(devinfo, \ + CHIPCREGOFFS(reg), value) + + +static void +brcmf_pcie_select_core(struct brcmf_pciedev_info *devinfo, u16 coreid) +{ + const struct pci_dev *pdev = devinfo->pdev; + struct brcmf_core *core; + u32 bar0_win; + + core = brcmf_chip_get_core(devinfo->ci, coreid); + if (core) { + bar0_win = core->base; + pci_write_config_dword(pdev, BRCMF_PCIE_BAR0_WINDOW, bar0_win); + if (pci_read_config_dword(pdev, BRCMF_PCIE_BAR0_WINDOW, + &bar0_win) == 0) { + if (bar0_win != core->base) { + bar0_win = core->base; + pci_write_config_dword(pdev, + BRCMF_PCIE_BAR0_WINDOW, + bar0_win); + } + } + } else { + brcmf_err("Unsupported core selected %x\n", coreid); + } +} + + +static void brcmf_pcie_detach(struct brcmf_pciedev_info *devinfo) +{ + u16 cfg_offset[] = { 0x4, 0x4C, 0x58, 0x5C, 0x60, 0x64, 0xDC, 0x228, + 0x248, 0x4e0, 0x4f4 }; + u32 i; + u32 val; + + if (!devinfo->ci) + return; + + brcmf_pcie_select_core(devinfo, BCMA_CORE_CHIPCOMMON); + WRITECC32(devinfo, watchdog, 0x4e0); + + msleep(100); + + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); + for (i = 0; i < ARRAY_SIZE(cfg_offset); i++) { + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, + cfg_offset[i]); + val = brcmf_pcie_read_reg32(devinfo, + BRCMF_PCIE_PCIE2REG_CONFIGDATA); + brcmf_dbg(PCIE, "config offset 0x%04x, value 0x%04x\n", + cfg_offset[i], val); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA, + val); + } +} + + +static void brcmf_pcie_attach(struct brcmf_pciedev_info *devinfo) +{ + u32 config; + + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); + if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_INTMASK) != 0) + brcmf_pcie_detach(devinfo); + /* BAR1 window may not be sized properly */ + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, 0x4e0); + config = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA, config); + + device_wakeup_enable(&devinfo->pdev->dev); +} + + +static int brcmf_pcie_enter_download_state(struct brcmf_pciedev_info *devinfo) +{ + brcmf_chip_enter_download(devinfo->ci); + + if (devinfo->ci->chip == BRCM_CC_43602_CHIP_ID) { + brcmf_pcie_select_core(devinfo, BCMA_CORE_ARM_CR4); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_ARMCR4REG_BANKIDX, + 5); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_ARMCR4REG_BANKPDA, + 0); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_ARMCR4REG_BANKIDX, + 7); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_ARMCR4REG_BANKPDA, + 0); + } + return 0; +} + + +static int brcmf_pcie_exit_download_state(struct brcmf_pciedev_info *devinfo, + u32 resetintr) +{ + struct brcmf_core *core; + + if (devinfo->ci->chip == BRCM_CC_43602_CHIP_ID) { + core = brcmf_chip_get_core(devinfo->ci, BCMA_CORE_INTERNAL_MEM); + brcmf_chip_resetcore(core, 0, 0, 0); + } + + return !brcmf_chip_exit_download(devinfo->ci, resetintr); +} + + +static void +brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data) +{ + struct brcmf_pcie_shared_info *shared; + u32 addr; + u32 cur_htod_mb_data; + u32 i; + + shared = &devinfo->shared; + addr = shared->htod_mb_data_addr; + cur_htod_mb_data = brcmf_pcie_read_tcm32(devinfo, addr); + + if (cur_htod_mb_data != 0) + brcmf_dbg(PCIE, "MB transaction is already pending 0x%04x\n", + cur_htod_mb_data); + + i = 0; + while (cur_htod_mb_data != 0) { + msleep(10); + i++; + if (i > 100) + break; + cur_htod_mb_data = brcmf_pcie_read_tcm32(devinfo, addr); + } + + brcmf_pcie_write_tcm32(devinfo, addr, htod_mb_data); + pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_SBMBX, 1); + pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_SBMBX, 1); +} + + +static void brcmf_pcie_handle_mb_data(struct brcmf_pciedev_info *devinfo) +{ + struct brcmf_pcie_shared_info *shared; + u32 addr; + u32 dtoh_mb_data; + + shared = &devinfo->shared; + addr = shared->dtoh_mb_data_addr; + dtoh_mb_data = brcmf_pcie_read_tcm32(devinfo, addr); + + if (!dtoh_mb_data) + return; + + brcmf_pcie_write_tcm32(devinfo, addr, 0); + + brcmf_dbg(PCIE, "D2H_MB_DATA: 0x%04x\n", dtoh_mb_data); + if (dtoh_mb_data & BRCMF_D2H_DEV_DS_ENTER_REQ) { + brcmf_dbg(PCIE, "D2H_MB_DATA: DEEP SLEEP REQ\n"); + brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_DS_ACK); + brcmf_dbg(PCIE, "D2H_MB_DATA: sent DEEP SLEEP ACK\n"); + } + if (dtoh_mb_data & BRCMF_D2H_DEV_DS_EXIT_NOTE) + brcmf_dbg(PCIE, "D2H_MB_DATA: DEEP SLEEP EXIT\n"); + if (dtoh_mb_data & BRCMF_D2H_DEV_D3_ACK) + brcmf_dbg(PCIE, "D2H_MB_DATA: D3 ACK\n"); + if (waitqueue_active(&devinfo->mbdata_resp_wait)) { + devinfo->mbdata_completed = true; + wake_up(&devinfo->mbdata_resp_wait); + } +} + + +static void brcmf_pcie_bus_console_init(struct brcmf_pciedev_info *devinfo) +{ + struct brcmf_pcie_shared_info *shared; + struct brcmf_pcie_console *console; + u32 addr; + + shared = &devinfo->shared; + console = &shared->console; + addr = shared->tcm_base_address + BRCMF_SHARED_CONSOLE_ADDR_OFFSET; + console->base_addr = brcmf_pcie_read_tcm32(devinfo, addr); + + addr = console->base_addr + BRCMF_CONSOLE_BUFADDR_OFFSET; + console->buf_addr = brcmf_pcie_read_tcm32(devinfo, addr); + addr = console->base_addr + BRCMF_CONSOLE_BUFSIZE_OFFSET; + console->bufsize = brcmf_pcie_read_tcm32(devinfo, addr); + + brcmf_dbg(PCIE, "Console: base %x, buf %x, size %d\n", + console->base_addr, console->buf_addr, console->bufsize); +} + + +static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo) +{ + struct brcmf_pcie_console *console; + u32 addr; + u8 ch; + u32 newidx; + + console = &devinfo->shared.console; + addr = console->base_addr + BRCMF_CONSOLE_WRITEIDX_OFFSET; + newidx = brcmf_pcie_read_tcm32(devinfo, addr); + while (newidx != console->read_idx) { + addr = console->buf_addr + console->read_idx; + ch = brcmf_pcie_read_tcm8(devinfo, addr); + console->read_idx++; + if (console->read_idx == console->bufsize) + console->read_idx = 0; + if (ch == '\r') + continue; + console->log_str[console->log_idx] = ch; + console->log_idx++; + if ((ch != '\n') && + (console->log_idx == (sizeof(console->log_str) - 2))) { + ch = '\n'; + console->log_str[console->log_idx] = ch; + console->log_idx++; + } + + if (ch == '\n') { + console->log_str[console->log_idx] = 0; + brcmf_dbg(PCIE, "CONSOLE: %s\n", console->log_str); + console->log_idx = 0; + } + } +} + + +static __used void brcmf_pcie_ringbell_v1(struct brcmf_pciedev_info *devinfo) +{ + u32 reg_value; + + brcmf_dbg(PCIE, "RING !\n"); + reg_value = brcmf_pcie_read_reg32(devinfo, + BRCMF_PCIE_PCIE2REG_MAILBOXINT); + reg_value |= BRCMF_PCIE2_INTB; + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, + reg_value); +} + + +static void brcmf_pcie_ringbell_v2(struct brcmf_pciedev_info *devinfo) +{ + brcmf_dbg(PCIE, "RING !\n"); + /* Any arbitrary value will do, lets use 1 */ + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX, 1); +} + + +static void brcmf_pcie_intr_disable(struct brcmf_pciedev_info *devinfo) +{ + if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) + pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTMASK, + 0); + else + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, + 0); +} + + +static void brcmf_pcie_intr_enable(struct brcmf_pciedev_info *devinfo) +{ + if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) + pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTMASK, + BRCMF_PCIE_INT_DEF); + else + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, + BRCMF_PCIE_MB_INT_D2H_DB | + BRCMF_PCIE_MB_INT_FN0_0 | + BRCMF_PCIE_MB_INT_FN0_1); +} + + +static irqreturn_t brcmf_pcie_quick_check_isr_v1(int irq, void *arg) +{ + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; + u32 status; + + status = 0; + pci_read_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTSTATUS, &status); + if (status) { + brcmf_pcie_intr_disable(devinfo); + brcmf_dbg(PCIE, "Enter\n"); + return IRQ_WAKE_THREAD; + } + return IRQ_NONE; +} + + +static irqreturn_t brcmf_pcie_quick_check_isr_v2(int irq, void *arg) +{ + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; + + if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT)) { + brcmf_pcie_intr_disable(devinfo); + brcmf_dbg(PCIE, "Enter\n"); + return IRQ_WAKE_THREAD; + } + return IRQ_NONE; +} + + +static irqreturn_t brcmf_pcie_isr_thread_v1(int irq, void *arg) +{ + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; + const struct pci_dev *pdev = devinfo->pdev; + u32 status; + + devinfo->in_irq = true; + status = 0; + pci_read_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, &status); + brcmf_dbg(PCIE, "Enter %x\n", status); + if (status) { + pci_write_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, status); + if (devinfo->state == BRCMFMAC_PCIE_STATE_UP) + brcmf_proto_msgbuf_rx_trigger(&devinfo->pdev->dev); + } + if (devinfo->state == BRCMFMAC_PCIE_STATE_UP) + brcmf_pcie_intr_enable(devinfo); + devinfo->in_irq = false; + return IRQ_HANDLED; +} + + +static irqreturn_t brcmf_pcie_isr_thread_v2(int irq, void *arg) +{ + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg; + u32 status; + + devinfo->in_irq = true; + status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT); + brcmf_dbg(PCIE, "Enter %x\n", status); + if (status) { + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, + status); + if (status & (BRCMF_PCIE_MB_INT_FN0_0 | + BRCMF_PCIE_MB_INT_FN0_1)) + brcmf_pcie_handle_mb_data(devinfo); + if (status & BRCMF_PCIE_MB_INT_D2H_DB) { + if (devinfo->state == BRCMFMAC_PCIE_STATE_UP) + brcmf_proto_msgbuf_rx_trigger( + &devinfo->pdev->dev); + } + } + brcmf_pcie_bus_console_read(devinfo); + if (devinfo->state == BRCMFMAC_PCIE_STATE_UP) + brcmf_pcie_intr_enable(devinfo); + devinfo->in_irq = false; + return IRQ_HANDLED; +} + + +static int brcmf_pcie_request_irq(struct brcmf_pciedev_info *devinfo) +{ + struct pci_dev *pdev; + + pdev = devinfo->pdev; + + brcmf_pcie_intr_disable(devinfo); + + brcmf_dbg(PCIE, "Enter\n"); + /* is it a v1 or v2 implementation */ + devinfo->irq_requested = false; + if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) { + if (request_threaded_irq(pdev->irq, + brcmf_pcie_quick_check_isr_v1, + brcmf_pcie_isr_thread_v1, + IRQF_SHARED, "brcmf_pcie_intr", + devinfo)) { + brcmf_err("Failed to request IRQ %d\n", pdev->irq); + return -EIO; + } + } else { + if (request_threaded_irq(pdev->irq, + brcmf_pcie_quick_check_isr_v2, + brcmf_pcie_isr_thread_v2, + IRQF_SHARED, "brcmf_pcie_intr", + devinfo)) { + brcmf_err("Failed to request IRQ %d\n", pdev->irq); + return -EIO; + } + } + devinfo->irq_requested = true; + devinfo->irq_allocated = true; + return 0; +} + + +static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo) +{ + struct pci_dev *pdev; + u32 status; + u32 count; + + if (!devinfo->irq_allocated) + return; + + pdev = devinfo->pdev; + + brcmf_pcie_intr_disable(devinfo); + if (!devinfo->irq_requested) + return; + devinfo->irq_requested = false; + free_irq(pdev->irq, devinfo); + + msleep(50); + count = 0; + while ((devinfo->in_irq) && (count < 20)) { + msleep(50); + count++; + } + if (devinfo->in_irq) + brcmf_err("Still in IRQ (processing) !!!\n"); + + if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) { + status = 0; + pci_read_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, &status); + pci_write_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, status); + } else { + status = brcmf_pcie_read_reg32(devinfo, + BRCMF_PCIE_PCIE2REG_MAILBOXINT); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, + status); + } + devinfo->irq_allocated = false; +} + + +static int brcmf_pcie_ring_mb_write_rptr(void *ctx) +{ + struct brcmf_pcie_ringbuf *ring = (struct brcmf_pcie_ringbuf *)ctx; + struct brcmf_pciedev_info *devinfo = ring->devinfo; + struct brcmf_commonring *commonring = &ring->commonring; + + if (devinfo->state != BRCMFMAC_PCIE_STATE_UP) + return -EIO; + + brcmf_dbg(PCIE, "W r_ptr %d (%d), ring %d\n", commonring->r_ptr, + commonring->w_ptr, ring->id); + + brcmf_pcie_write_tcm16(devinfo, ring->r_idx_addr, commonring->r_ptr); + + return 0; +} + + +static int brcmf_pcie_ring_mb_write_wptr(void *ctx) +{ + struct brcmf_pcie_ringbuf *ring = (struct brcmf_pcie_ringbuf *)ctx; + struct brcmf_pciedev_info *devinfo = ring->devinfo; + struct brcmf_commonring *commonring = &ring->commonring; + + if (devinfo->state != BRCMFMAC_PCIE_STATE_UP) + return -EIO; + + brcmf_dbg(PCIE, "W w_ptr %d (%d), ring %d\n", commonring->w_ptr, + commonring->r_ptr, ring->id); + + brcmf_pcie_write_tcm16(devinfo, ring->w_idx_addr, commonring->w_ptr); + + return 0; +} + + +static int brcmf_pcie_ring_mb_ring_bell(void *ctx) +{ + struct brcmf_pcie_ringbuf *ring = (struct brcmf_pcie_ringbuf *)ctx; + struct brcmf_pciedev_info *devinfo = ring->devinfo; + + if (devinfo->state != BRCMFMAC_PCIE_STATE_UP) + return -EIO; + + devinfo->ringbell(devinfo); + + return 0; +} + + +static int brcmf_pcie_ring_mb_update_rptr(void *ctx) +{ + struct brcmf_pcie_ringbuf *ring = (struct brcmf_pcie_ringbuf *)ctx; + struct brcmf_pciedev_info *devinfo = ring->devinfo; + struct brcmf_commonring *commonring = &ring->commonring; + + if (devinfo->state != BRCMFMAC_PCIE_STATE_UP) + return -EIO; + + commonring->r_ptr = brcmf_pcie_read_tcm16(devinfo, ring->r_idx_addr); + + brcmf_dbg(PCIE, "R r_ptr %d (%d), ring %d\n", commonring->r_ptr, + commonring->w_ptr, ring->id); + + return 0; +} + + +static int brcmf_pcie_ring_mb_update_wptr(void *ctx) +{ + struct brcmf_pcie_ringbuf *ring = (struct brcmf_pcie_ringbuf *)ctx; + struct brcmf_pciedev_info *devinfo = ring->devinfo; + struct brcmf_commonring *commonring = &ring->commonring; + + if (devinfo->state != BRCMFMAC_PCIE_STATE_UP) + return -EIO; + + commonring->w_ptr = brcmf_pcie_read_tcm16(devinfo, ring->w_idx_addr); + + brcmf_dbg(PCIE, "R w_ptr %d (%d), ring %d\n", commonring->w_ptr, + commonring->r_ptr, ring->id); + + return 0; +} + + +static void * +brcmf_pcie_init_dmabuffer_for_device(struct brcmf_pciedev_info *devinfo, + u32 size, u32 tcm_dma_phys_addr, + dma_addr_t *dma_handle) +{ + void *ring; + long long address; + + ring = dma_alloc_coherent(&devinfo->pdev->dev, size, dma_handle, + GFP_KERNEL); + if (!ring) + return NULL; + + address = (long long)(long)*dma_handle; + brcmf_pcie_write_tcm32(devinfo, tcm_dma_phys_addr, + address & 0xffffffff); + brcmf_pcie_write_tcm32(devinfo, tcm_dma_phys_addr + 4, address >> 32); + + memset(ring, 0, size); + + return (ring); +} + + +static struct brcmf_pcie_ringbuf * +brcmf_pcie_alloc_dma_and_ring(struct brcmf_pciedev_info *devinfo, u32 ring_id, + u32 tcm_ring_phys_addr) +{ + void *dma_buf; + dma_addr_t dma_handle; + struct brcmf_pcie_ringbuf *ring; + u32 size; + u32 addr; + + size = brcmf_ring_max_item[ring_id] * brcmf_ring_itemsize[ring_id]; + dma_buf = brcmf_pcie_init_dmabuffer_for_device(devinfo, size, + tcm_ring_phys_addr + BRCMF_RING_MEM_BASE_ADDR_OFFSET, + &dma_handle); + if (!dma_buf) + return NULL; + + addr = tcm_ring_phys_addr + BRCMF_RING_MAX_ITEM_OFFSET; + brcmf_pcie_write_tcm16(devinfo, addr, brcmf_ring_max_item[ring_id]); + addr = tcm_ring_phys_addr + BRCMF_RING_LEN_ITEMS_OFFSET; + brcmf_pcie_write_tcm16(devinfo, addr, brcmf_ring_itemsize[ring_id]); + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + if (!ring) { + dma_free_coherent(&devinfo->pdev->dev, size, dma_buf, + dma_handle); + return NULL; + } + brcmf_commonring_config(&ring->commonring, brcmf_ring_max_item[ring_id], + brcmf_ring_itemsize[ring_id], dma_buf); + ring->dma_handle = dma_handle; + ring->devinfo = devinfo; + brcmf_commonring_register_cb(&ring->commonring, + brcmf_pcie_ring_mb_ring_bell, + brcmf_pcie_ring_mb_update_rptr, + brcmf_pcie_ring_mb_update_wptr, + brcmf_pcie_ring_mb_write_rptr, + brcmf_pcie_ring_mb_write_wptr, ring); + + return (ring); +} + + +static void brcmf_pcie_release_ringbuffer(struct device *dev, + struct brcmf_pcie_ringbuf *ring) +{ + void *dma_buf; + u32 size; + + if (!ring) + return; + + dma_buf = ring->commonring.buf_addr; + if (dma_buf) { + size = ring->commonring.depth * ring->commonring.item_len; + dma_free_coherent(dev, size, dma_buf, ring->dma_handle); + } + kfree(ring); +} + + +static void brcmf_pcie_release_ringbuffers(struct brcmf_pciedev_info *devinfo) +{ + u32 i; + + for (i = 0; i < BRCMF_NROF_COMMON_MSGRINGS; i++) { + brcmf_pcie_release_ringbuffer(&devinfo->pdev->dev, + devinfo->shared.commonrings[i]); + devinfo->shared.commonrings[i] = NULL; + } + kfree(devinfo->shared.flowrings); + devinfo->shared.flowrings = NULL; +} + + +static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo) +{ + struct brcmf_pcie_ringbuf *ring; + struct brcmf_pcie_ringbuf *rings; + u32 ring_addr; + u32 d2h_w_idx_ptr; + u32 d2h_r_idx_ptr; + u32 h2d_w_idx_ptr; + u32 h2d_r_idx_ptr; + u32 addr; + u32 ring_mem_ptr; + u32 i; + u16 max_sub_queues; + + ring_addr = devinfo->shared.ring_info_addr; + brcmf_dbg(PCIE, "Base ring addr = 0x%08x\n", ring_addr); + + addr = ring_addr + BRCMF_SHARED_RING_D2H_W_IDX_PTR_OFFSET; + d2h_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); + addr = ring_addr + BRCMF_SHARED_RING_D2H_R_IDX_PTR_OFFSET; + d2h_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); + addr = ring_addr + BRCMF_SHARED_RING_H2D_W_IDX_PTR_OFFSET; + h2d_w_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); + addr = ring_addr + BRCMF_SHARED_RING_H2D_R_IDX_PTR_OFFSET; + h2d_r_idx_ptr = brcmf_pcie_read_tcm32(devinfo, addr); + + addr = ring_addr + BRCMF_SHARED_RING_TCM_MEMLOC_OFFSET; + ring_mem_ptr = brcmf_pcie_read_tcm32(devinfo, addr); + + for (i = 0; i < BRCMF_NROF_H2D_COMMON_MSGRINGS; i++) { + ring = brcmf_pcie_alloc_dma_and_ring(devinfo, i, ring_mem_ptr); + if (!ring) + goto fail; + ring->w_idx_addr = h2d_w_idx_ptr; + ring->r_idx_addr = h2d_r_idx_ptr; + ring->id = i; + devinfo->shared.commonrings[i] = ring; + + h2d_w_idx_ptr += sizeof(u32); + h2d_r_idx_ptr += sizeof(u32); + ring_mem_ptr += BRCMF_RING_MEM_SZ; + } + + for (i = BRCMF_NROF_H2D_COMMON_MSGRINGS; + i < BRCMF_NROF_COMMON_MSGRINGS; i++) { + ring = brcmf_pcie_alloc_dma_and_ring(devinfo, i, ring_mem_ptr); + if (!ring) + goto fail; + ring->w_idx_addr = d2h_w_idx_ptr; + ring->r_idx_addr = d2h_r_idx_ptr; + ring->id = i; + devinfo->shared.commonrings[i] = ring; + + d2h_w_idx_ptr += sizeof(u32); + d2h_r_idx_ptr += sizeof(u32); + ring_mem_ptr += BRCMF_RING_MEM_SZ; + } + + addr = ring_addr + BRCMF_SHARED_RING_MAX_SUB_QUEUES; + max_sub_queues = brcmf_pcie_read_tcm16(devinfo, addr); + devinfo->shared.nrof_flowrings = + max_sub_queues - BRCMF_NROF_H2D_COMMON_MSGRINGS; + rings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(*ring), + GFP_KERNEL); + if (!rings) + goto fail; + + brcmf_dbg(PCIE, "Nr of flowrings is %d\n", + devinfo->shared.nrof_flowrings); + + for (i = 0; i < devinfo->shared.nrof_flowrings; i++) { + ring = &rings[i]; + ring->devinfo = devinfo; + ring->id = i + BRCMF_NROF_COMMON_MSGRINGS; + brcmf_commonring_register_cb(&ring->commonring, + brcmf_pcie_ring_mb_ring_bell, + brcmf_pcie_ring_mb_update_rptr, + brcmf_pcie_ring_mb_update_wptr, + brcmf_pcie_ring_mb_write_rptr, + brcmf_pcie_ring_mb_write_wptr, + ring); + ring->w_idx_addr = h2d_w_idx_ptr; + ring->r_idx_addr = h2d_r_idx_ptr; + h2d_w_idx_ptr += sizeof(u32); + h2d_r_idx_ptr += sizeof(u32); + } + devinfo->shared.flowrings = rings; + + return 0; + +fail: + brcmf_err("Allocating commonring buffers failed\n"); + brcmf_pcie_release_ringbuffers(devinfo); + return -ENOMEM; +} + + +static void +brcmf_pcie_release_scratchbuffers(struct brcmf_pciedev_info *devinfo) +{ + if (devinfo->shared.scratch) + dma_free_coherent(&devinfo->pdev->dev, + BRCMF_DMA_D2H_SCRATCH_BUF_LEN, + devinfo->shared.scratch, + devinfo->shared.scratch_dmahandle); + if (devinfo->shared.ringupd) + dma_free_coherent(&devinfo->pdev->dev, + BRCMF_DMA_D2H_RINGUPD_BUF_LEN, + devinfo->shared.ringupd, + devinfo->shared.ringupd_dmahandle); +} + +static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo) +{ + long long address; + u32 addr; + + devinfo->shared.scratch = dma_alloc_coherent(&devinfo->pdev->dev, + BRCMF_DMA_D2H_SCRATCH_BUF_LEN, + &devinfo->shared.scratch_dmahandle, GFP_KERNEL); + if (!devinfo->shared.scratch) + goto fail; + + memset(devinfo->shared.scratch, 0, BRCMF_DMA_D2H_SCRATCH_BUF_LEN); + brcmf_dma_flush(devinfo->shared.scratch, BRCMF_DMA_D2H_SCRATCH_BUF_LEN); + + addr = devinfo->shared.tcm_base_address + + BRCMF_SHARED_DMA_SCRATCH_ADDR_OFFSET; + address = (long long)(long)devinfo->shared.scratch_dmahandle; + brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); + brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); + addr = devinfo->shared.tcm_base_address + + BRCMF_SHARED_DMA_SCRATCH_LEN_OFFSET; + brcmf_pcie_write_tcm32(devinfo, addr, BRCMF_DMA_D2H_SCRATCH_BUF_LEN); + + devinfo->shared.ringupd = dma_alloc_coherent(&devinfo->pdev->dev, + BRCMF_DMA_D2H_RINGUPD_BUF_LEN, + &devinfo->shared.ringupd_dmahandle, GFP_KERNEL); + if (!devinfo->shared.ringupd) + goto fail; + + memset(devinfo->shared.ringupd, 0, BRCMF_DMA_D2H_RINGUPD_BUF_LEN); + brcmf_dma_flush(devinfo->shared.ringupd, BRCMF_DMA_D2H_RINGUPD_BUF_LEN); + + addr = devinfo->shared.tcm_base_address + + BRCMF_SHARED_DMA_RINGUPD_ADDR_OFFSET; + address = (long long)(long)devinfo->shared.ringupd_dmahandle; + brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); + brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); + addr = devinfo->shared.tcm_base_address + + BRCMF_SHARED_DMA_RINGUPD_LEN_OFFSET; + brcmf_pcie_write_tcm32(devinfo, addr, BRCMF_DMA_D2H_RINGUPD_BUF_LEN); + return 0; + +fail: + brcmf_err("Allocating scratch buffers failed\n"); + brcmf_pcie_release_scratchbuffers(devinfo); + return -ENOMEM; +} + + +static void brcmf_pcie_down(struct device *dev) +{ +} + + +static int brcmf_pcie_tx(struct device *dev, struct sk_buff *skb) +{ + return 0; +} + + +static int brcmf_pcie_tx_ctlpkt(struct device *dev, unsigned char *msg, + uint len) +{ + return 0; +} + + +static int brcmf_pcie_rx_ctlpkt(struct device *dev, unsigned char *msg, + uint len) +{ + return 0; +} + + +static struct brcmf_bus_ops brcmf_pcie_bus_ops = { + .txdata = brcmf_pcie_tx, + .stop = brcmf_pcie_down, + .txctl = brcmf_pcie_tx_ctlpkt, + .rxctl = brcmf_pcie_rx_ctlpkt, +}; + + +static int +brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo, + u32 sharedram_addr) +{ + struct brcmf_pcie_shared_info *shared; + u32 addr; + u32 version; + + shared = &devinfo->shared; + shared->tcm_base_address = sharedram_addr; + + shared->flags = brcmf_pcie_read_tcm32(devinfo, sharedram_addr); + version = shared->flags & BRCMF_PCIE_SHARED_VERSION_MASK; + brcmf_dbg(PCIE, "PCIe protocol version %d\n", version); + if ((version > BRCMF_PCIE_MAX_SHARED_VERSION) || + (version < BRCMF_PCIE_MIN_SHARED_VERSION)) { + brcmf_err("Unsupported PCIE version %d\n", version); + return -EINVAL; + } + if (shared->flags & BRCMF_PCIE_SHARED_TXPUSH_SUPPORT) { + brcmf_err("Unsupported legacy TX mode 0x%x\n", + shared->flags & BRCMF_PCIE_SHARED_TXPUSH_SUPPORT); + return -EINVAL; + } + + addr = sharedram_addr + BRCMF_SHARED_MAX_RXBUFPOST_OFFSET; + shared->max_rxbufpost = brcmf_pcie_read_tcm16(devinfo, addr); + if (shared->max_rxbufpost == 0) + shared->max_rxbufpost = BRCMF_DEF_MAX_RXBUFPOST; + + addr = sharedram_addr + BRCMF_SHARED_RX_DATAOFFSET_OFFSET; + shared->rx_dataoffset = brcmf_pcie_read_tcm32(devinfo, addr); + + addr = sharedram_addr + BRCMF_SHARED_HTOD_MB_DATA_ADDR_OFFSET; + shared->htod_mb_data_addr = brcmf_pcie_read_tcm32(devinfo, addr); + + addr = sharedram_addr + BRCMF_SHARED_DTOH_MB_DATA_ADDR_OFFSET; + shared->dtoh_mb_data_addr = brcmf_pcie_read_tcm32(devinfo, addr); + + addr = sharedram_addr + BRCMF_SHARED_RING_INFO_ADDR_OFFSET; + shared->ring_info_addr = brcmf_pcie_read_tcm32(devinfo, addr); + + brcmf_dbg(PCIE, "max rx buf post %d, rx dataoffset %d\n", + shared->max_rxbufpost, shared->rx_dataoffset); + + brcmf_pcie_bus_console_init(devinfo); + + return 0; +} + + +static int brcmf_pcie_get_fwnames(struct brcmf_pciedev_info *devinfo) +{ + char *fw_name; + char *nvram_name; + uint fw_len, nv_len; + char end; + + brcmf_dbg(PCIE, "Enter, chip 0x%04x chiprev %d\n", devinfo->ci->chip, + devinfo->ci->chiprev); + + switch (devinfo->ci->chip) { + case BRCM_CC_43602_CHIP_ID: + fw_name = BRCMF_PCIE_43602_FW_NAME; + nvram_name = BRCMF_PCIE_43602_NVRAM_NAME; + break; + case BRCM_CC_4354_CHIP_ID: + fw_name = BRCMF_PCIE_4354_FW_NAME; + nvram_name = BRCMF_PCIE_4354_NVRAM_NAME; + break; + case BRCM_CC_4356_CHIP_ID: + fw_name = BRCMF_PCIE_4356_FW_NAME; + nvram_name = BRCMF_PCIE_4356_NVRAM_NAME; + break; + case BRCM_CC_43567_CHIP_ID: + case BRCM_CC_43569_CHIP_ID: + case BRCM_CC_43570_CHIP_ID: + fw_name = BRCMF_PCIE_43570_FW_NAME; + nvram_name = BRCMF_PCIE_43570_NVRAM_NAME; + break; + default: + brcmf_err("Unsupported chip 0x%04x\n", devinfo->ci->chip); + return -ENODEV; + } + + fw_len = sizeof(devinfo->fw_name) - 1; + nv_len = sizeof(devinfo->nvram_name) - 1; + /* check if firmware path is provided by module parameter */ + if (brcmf_firmware_path[0] != '\0') { + strncpy(devinfo->fw_name, brcmf_firmware_path, fw_len); + strncpy(devinfo->nvram_name, brcmf_firmware_path, nv_len); + fw_len -= strlen(devinfo->fw_name); + nv_len -= strlen(devinfo->nvram_name); + + end = brcmf_firmware_path[strlen(brcmf_firmware_path) - 1]; + if (end != '/') { + strncat(devinfo->fw_name, "/", fw_len); + strncat(devinfo->nvram_name, "/", nv_len); + fw_len--; + nv_len--; + } + } + strncat(devinfo->fw_name, fw_name, fw_len); + strncat(devinfo->nvram_name, nvram_name, nv_len); + + return 0; +} + + +static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, + const struct firmware *fw, void *nvram, + u32 nvram_len) +{ + u32 sharedram_addr; + u32 sharedram_addr_written; + u32 loop_counter; + int err; + u32 address; + u32 resetintr; + + devinfo->ringbell = brcmf_pcie_ringbell_v2; + devinfo->generic_corerev = BRCMF_PCIE_GENREV2; + + brcmf_dbg(PCIE, "Halt ARM.\n"); + err = brcmf_pcie_enter_download_state(devinfo); + if (err) + return err; + + brcmf_dbg(PCIE, "Download FW %s\n", devinfo->fw_name); + brcmf_pcie_copy_mem_todev(devinfo, devinfo->ci->rambase, + (void *)fw->data, fw->size); + + resetintr = get_unaligned_le32(fw->data); + release_firmware(fw); + + /* reset last 4 bytes of RAM address. to be used for shared + * area. This identifies when FW is running + */ + brcmf_pcie_write_ram32(devinfo, devinfo->ci->ramsize - 4, 0); + + if (nvram) { + brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name); + address = devinfo->ci->rambase + devinfo->ci->ramsize - + nvram_len; + brcmf_pcie_copy_mem_todev(devinfo, address, nvram, nvram_len); + brcmf_fw_nvram_free(nvram); + } else { + brcmf_dbg(PCIE, "No matching NVRAM file found %s\n", + devinfo->nvram_name); + } + + sharedram_addr_written = brcmf_pcie_read_ram32(devinfo, + devinfo->ci->ramsize - + 4); + brcmf_dbg(PCIE, "Bring ARM in running state\n"); + err = brcmf_pcie_exit_download_state(devinfo, resetintr); + if (err) + return err; + + brcmf_dbg(PCIE, "Wait for FW init\n"); + sharedram_addr = sharedram_addr_written; + loop_counter = BRCMF_PCIE_FW_UP_TIMEOUT / 50; + while ((sharedram_addr == sharedram_addr_written) && (loop_counter)) { + msleep(50); + sharedram_addr = brcmf_pcie_read_ram32(devinfo, + devinfo->ci->ramsize - + 4); + loop_counter--; + } + if (sharedram_addr == sharedram_addr_written) { + brcmf_err("FW failed to initialize\n"); + return -ENODEV; + } + brcmf_dbg(PCIE, "Shared RAM addr: 0x%08x\n", sharedram_addr); + + return (brcmf_pcie_init_share_ram_info(devinfo, sharedram_addr)); +} + + +static int brcmf_pcie_get_resource(struct brcmf_pciedev_info *devinfo) +{ + struct pci_dev *pdev; + int err; + phys_addr_t bar0_addr, bar1_addr; + ulong bar1_size; + + pdev = devinfo->pdev; + + err = pci_enable_device(pdev); + if (err) { + brcmf_err("pci_enable_device failed err=%d\n", err); + return err; + } + + pci_set_master(pdev); + + /* Bar-0 mapped address */ + bar0_addr = pci_resource_start(pdev, 0); + /* Bar-1 mapped address */ + bar1_addr = pci_resource_start(pdev, 2); + /* read Bar-1 mapped memory range */ + bar1_size = pci_resource_len(pdev, 2); + if ((bar1_size == 0) || (bar1_addr == 0)) { + brcmf_err("BAR1 Not enabled, device size=%ld, addr=%#016llx\n", + bar1_size, (unsigned long long)bar1_addr); + return -EINVAL; + } + + devinfo->regs = ioremap_nocache(bar0_addr, BRCMF_PCIE_REG_MAP_SIZE); + devinfo->tcm = ioremap_nocache(bar1_addr, BRCMF_PCIE_TCM_MAP_SIZE); + devinfo->tcm_size = BRCMF_PCIE_TCM_MAP_SIZE; + + if (!devinfo->regs || !devinfo->tcm) { + brcmf_err("ioremap() failed (%p,%p)\n", devinfo->regs, + devinfo->tcm); + return -EINVAL; + } + brcmf_dbg(PCIE, "Phys addr : reg space = %p base addr %#016llx\n", + devinfo->regs, (unsigned long long)bar0_addr); + brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx\n", + devinfo->tcm, (unsigned long long)bar1_addr); + + return 0; +} + + +static void brcmf_pcie_release_resource(struct brcmf_pciedev_info *devinfo) +{ + if (devinfo->tcm) + iounmap(devinfo->tcm); + if (devinfo->regs) + iounmap(devinfo->regs); + + pci_disable_device(devinfo->pdev); +} + + +static int brcmf_pcie_attach_bus(struct device *dev) +{ + int ret; + + /* Attach to the common driver interface */ + ret = brcmf_attach(dev); + if (ret) { + brcmf_err("brcmf_attach failed\n"); + } else { + ret = brcmf_bus_start(dev); + if (ret) + brcmf_err("dongle is not responding\n"); + } + + return ret; +} + + +static u32 brcmf_pcie_buscore_prep_addr(const struct pci_dev *pdev, u32 addr) +{ + u32 ret_addr; + + ret_addr = addr & (BRCMF_PCIE_BAR0_REG_SIZE - 1); + addr &= ~(BRCMF_PCIE_BAR0_REG_SIZE - 1); + pci_write_config_dword(pdev, BRCMF_PCIE_BAR0_WINDOW, addr); + + return ret_addr; +} + + +static u32 brcmf_pcie_buscore_read32(void *ctx, u32 addr) +{ + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; + + addr = brcmf_pcie_buscore_prep_addr(devinfo->pdev, addr); + return brcmf_pcie_read_reg32(devinfo, addr); +} + + +static void brcmf_pcie_buscore_write32(void *ctx, u32 addr, u32 value) +{ + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; + + addr = brcmf_pcie_buscore_prep_addr(devinfo->pdev, addr); + brcmf_pcie_write_reg32(devinfo, addr, value); +} + + +static int brcmf_pcie_buscoreprep(void *ctx) +{ + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; + int err; + + err = brcmf_pcie_get_resource(devinfo); + if (err == 0) { + /* Set CC watchdog to reset all the cores on the chip to bring + * back dongle to a sane state. + */ + brcmf_pcie_buscore_write32(ctx, CORE_CC_REG(SI_ENUM_BASE, + watchdog), 4); + msleep(100); + } + + return err; +} + + +static void brcmf_pcie_buscore_exitdl(void *ctx, struct brcmf_chip *chip, + u32 rstvec) +{ + struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; + + brcmf_pcie_write_tcm32(devinfo, 0, rstvec); +} + + +static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = { + .prepare = brcmf_pcie_buscoreprep, + .exit_dl = brcmf_pcie_buscore_exitdl, + .read32 = brcmf_pcie_buscore_read32, + .write32 = brcmf_pcie_buscore_write32, +}; + +static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw, + void *nvram, u32 nvram_len) +{ + struct brcmf_bus *bus = dev_get_drvdata(dev); + struct brcmf_pciedev *pcie_bus_dev = bus->bus_priv.pcie; + struct brcmf_pciedev_info *devinfo = pcie_bus_dev->devinfo; + struct brcmf_commonring **flowrings; + int ret; + u32 i; + + brcmf_pcie_attach(devinfo); + + ret = brcmf_pcie_download_fw_nvram(devinfo, fw, nvram, nvram_len); + if (ret) + goto fail; + + devinfo->state = BRCMFMAC_PCIE_STATE_UP; + + ret = brcmf_pcie_init_ringbuffers(devinfo); + if (ret) + goto fail; + + ret = brcmf_pcie_init_scratchbuffers(devinfo); + if (ret) + goto fail; + + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); + ret = brcmf_pcie_request_irq(devinfo); + if (ret) + goto fail; + + /* hook the commonrings in the bus structure. */ + for (i = 0; i < BRCMF_NROF_COMMON_MSGRINGS; i++) + bus->msgbuf->commonrings[i] = + &devinfo->shared.commonrings[i]->commonring; + + flowrings = kcalloc(devinfo->shared.nrof_flowrings, sizeof(flowrings), + GFP_KERNEL); + if (!flowrings) + goto fail; + + for (i = 0; i < devinfo->shared.nrof_flowrings; i++) + flowrings[i] = &devinfo->shared.flowrings[i].commonring; + bus->msgbuf->flowrings = flowrings; + + bus->msgbuf->rx_dataoffset = devinfo->shared.rx_dataoffset; + bus->msgbuf->max_rxbufpost = devinfo->shared.max_rxbufpost; + bus->msgbuf->nrof_flowrings = devinfo->shared.nrof_flowrings; + + init_waitqueue_head(&devinfo->mbdata_resp_wait); + + brcmf_pcie_intr_enable(devinfo); + if (brcmf_pcie_attach_bus(bus->dev) == 0) + return; + + brcmf_pcie_bus_console_read(devinfo); + +fail: + device_release_driver(dev); +} + +static int +brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int ret; + struct brcmf_pciedev_info *devinfo; + struct brcmf_pciedev *pcie_bus_dev; + struct brcmf_bus *bus; + + brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device); + + ret = -ENOMEM; + devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); + if (devinfo == NULL) + return ret; + + devinfo->pdev = pdev; + pcie_bus_dev = NULL; + devinfo->ci = brcmf_chip_attach(devinfo, &brcmf_pcie_buscore_ops); + if (IS_ERR(devinfo->ci)) { + ret = PTR_ERR(devinfo->ci); + devinfo->ci = NULL; + goto fail; + } + + pcie_bus_dev = kzalloc(sizeof(*pcie_bus_dev), GFP_KERNEL); + if (pcie_bus_dev == NULL) { + ret = -ENOMEM; + goto fail; + } + + bus = kzalloc(sizeof(*bus), GFP_KERNEL); + if (!bus) { + ret = -ENOMEM; + goto fail; + } + bus->msgbuf = kzalloc(sizeof(*bus->msgbuf), GFP_KERNEL); + if (!bus->msgbuf) { + ret = -ENOMEM; + kfree(bus); + goto fail; + } + + /* hook it all together. */ + pcie_bus_dev->devinfo = devinfo; + pcie_bus_dev->bus = bus; + bus->dev = &pdev->dev; + bus->bus_priv.pcie = pcie_bus_dev; + bus->ops = &brcmf_pcie_bus_ops; + bus->proto_type = BRCMF_PROTO_MSGBUF; + bus->chip = devinfo->coreid; + dev_set_drvdata(&pdev->dev, bus); + + ret = brcmf_pcie_get_fwnames(devinfo); + if (ret) + goto fail_bus; + + ret = brcmf_fw_get_firmwares(bus->dev, BRCMF_FW_REQUEST_NVRAM | + BRCMF_FW_REQ_NV_OPTIONAL, + devinfo->fw_name, devinfo->nvram_name, + brcmf_pcie_setup); + if (ret == 0) + return 0; +fail_bus: + kfree(bus->msgbuf); + kfree(bus); +fail: + brcmf_err("failed %x:%x\n", pdev->vendor, pdev->device); + brcmf_pcie_release_resource(devinfo); + if (devinfo->ci) + brcmf_chip_detach(devinfo->ci); + kfree(pcie_bus_dev); + kfree(devinfo); + return ret; +} + + +static void +brcmf_pcie_remove(struct pci_dev *pdev) +{ + struct brcmf_pciedev_info *devinfo; + struct brcmf_bus *bus; + + brcmf_dbg(PCIE, "Enter\n"); + + bus = dev_get_drvdata(&pdev->dev); + if (bus == NULL) + return; + + devinfo = bus->bus_priv.pcie->devinfo; + + devinfo->state = BRCMFMAC_PCIE_STATE_DOWN; + if (devinfo->ci) + brcmf_pcie_intr_disable(devinfo); + + brcmf_detach(&pdev->dev); + + kfree(bus->bus_priv.pcie); + kfree(bus->msgbuf->flowrings); + kfree(bus->msgbuf); + kfree(bus); + + brcmf_pcie_release_irq(devinfo); + brcmf_pcie_release_scratchbuffers(devinfo); + brcmf_pcie_release_ringbuffers(devinfo); + brcmf_pcie_detach(devinfo); + brcmf_pcie_release_resource(devinfo); + + if (devinfo->ci) + brcmf_chip_detach(devinfo->ci); + + kfree(devinfo); + dev_set_drvdata(&pdev->dev, NULL); +} + + +#ifdef CONFIG_PM + + +static int brcmf_pcie_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct brcmf_pciedev_info *devinfo; + struct brcmf_bus *bus; + int err; + + brcmf_dbg(PCIE, "Enter, state=%d, pdev=%p\n", state.event, pdev); + + bus = dev_get_drvdata(&pdev->dev); + devinfo = bus->bus_priv.pcie->devinfo; + + brcmf_bus_change_state(bus, BRCMF_BUS_DOWN); + + devinfo->mbdata_completed = false; + brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D3_INFORM); + + wait_event_timeout(devinfo->mbdata_resp_wait, + devinfo->mbdata_completed, + msecs_to_jiffies(BRCMF_PCIE_MBDATA_TIMEOUT)); + if (!devinfo->mbdata_completed) { + brcmf_err("Timeout on response for entering D3 substate\n"); + return -EIO; + } + brcmf_pcie_release_irq(devinfo); + + err = pci_save_state(pdev); + if (err) { + brcmf_err("pci_save_state failed, err=%d\n", err); + return err; + } + + brcmf_chip_detach(devinfo->ci); + devinfo->ci = NULL; + + brcmf_pcie_remove(pdev); + + return pci_prepare_to_sleep(pdev); +} + + +static int brcmf_pcie_resume(struct pci_dev *pdev) +{ + int err; + + brcmf_dbg(PCIE, "Enter, pdev=%p\n", pdev); + + err = pci_set_power_state(pdev, PCI_D0); + if (err) { + brcmf_err("pci_set_power_state failed, err=%d\n", err); + return err; + } + pci_restore_state(pdev); + + err = brcmf_pcie_probe(pdev, NULL); + if (err) + brcmf_err("probe after resume failed, err=%d\n", err); + + return err; +} + + +#endif /* CONFIG_PM */ + + +#define BRCMF_PCIE_DEVICE(dev_id) { BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\ + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } + +static struct pci_device_id brcmf_pcie_devid_table[] = { + BRCMF_PCIE_DEVICE(BRCM_PCIE_4354_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43602_DEVICE_ID), + { /* end: all zeroes */ } +}; + + +MODULE_DEVICE_TABLE(pci, brcmf_pcie_devid_table); + + +static struct pci_driver brcmf_pciedrvr = { + .node = {}, + .name = KBUILD_MODNAME, + .id_table = brcmf_pcie_devid_table, + .probe = brcmf_pcie_probe, + .remove = brcmf_pcie_remove, +#ifdef CONFIG_PM + .suspend = brcmf_pcie_suspend, + .resume = brcmf_pcie_resume +#endif /* CONFIG_PM */ +}; + + +void brcmf_pcie_register(void) +{ + int err; + + brcmf_dbg(PCIE, "Enter\n"); + err = pci_register_driver(&brcmf_pciedrvr); + if (err) + brcmf_err("PCIE driver registration failed, err=%d\n", err); +} + + +void brcmf_pcie_exit(void) +{ + brcmf_dbg(PCIE, "Enter\n"); + pci_unregister_driver(&brcmf_pciedrvr); +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.h b/drivers/net/wireless/brcm80211/brcmfmac/pcie.h new file mode 100644 index 000000000000..6edaaf8ef5ce --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef BRCMFMAC_PCIE_H +#define BRCMFMAC_PCIE_H + + +struct brcmf_pciedev { + struct brcmf_bus *bus; + struct brcmf_pciedev_info *devinfo; +}; + + +void brcmf_pcie_exit(void); +void brcmf_pcie_register(void); + + +#endif /* BRCMFMAC_PCIE_H */ diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index 64d1a7ba040c..af26e0de1e5c 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -38,8 +38,12 @@ #define BRCM_CC_4335_CHIP_ID 0x4335 #define BRCM_CC_4339_CHIP_ID 0x4339 #define BRCM_CC_4354_CHIP_ID 0x4354 +#define BRCM_CC_4356_CHIP_ID 0x4356 #define BRCM_CC_43566_CHIP_ID 43566 +#define BRCM_CC_43567_CHIP_ID 43567 #define BRCM_CC_43569_CHIP_ID 43569 +#define BRCM_CC_43570_CHIP_ID 43570 +#define BRCM_CC_43602_CHIP_ID 43602 /* SDIO Device IDs */ #define BRCM_SDIO_43143_DEVICE_ID BRCM_CC_43143_CHIP_ID @@ -58,6 +62,13 @@ #define BRCM_USB_43569_DEVICE_ID 0xbd27 #define BRCM_USB_BCMFW_DEVICE_ID 0x0bdc +/* PCIE Device IDs */ +#define BRCM_PCIE_4354_DEVICE_ID 0x43df +#define BRCM_PCIE_4356_DEVICE_ID 0x43ec +#define BRCM_PCIE_43567_DEVICE_ID 0x43d3 +#define BRCM_PCIE_43570_DEVICE_ID 0x43d9 +#define BRCM_PCIE_43602_DEVICE_ID 0x43ba + /* brcmsmac IDs */ #define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ #define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */ -- cgit v1.2.3 From bd4f82e3b2899829c7f87dde0d20daeb780ad014 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 30 Jul 2014 13:20:05 +0200 Subject: brcmfmac: Update pcie reset device routine. When a pcie device gets reset then the low power modes l1 and l2 should be temporarily disabled. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/pcie.c | 49 ++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c index 89be96d3b6e9..bc972c0ba5f8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c @@ -168,6 +168,20 @@ enum brcmf_pcie_state { #define BRCMF_PCIE_MBDATA_TIMEOUT 2000 +#define BRCMF_PCIE_CFGREG_STATUS_CMD 0x4 +#define BRCMF_PCIE_CFGREG_PM_CSR 0x4C +#define BRCMF_PCIE_CFGREG_MSI_CAP 0x58 +#define BRCMF_PCIE_CFGREG_MSI_ADDR_L 0x5C +#define BRCMF_PCIE_CFGREG_MSI_ADDR_H 0x60 +#define BRCMF_PCIE_CFGREG_MSI_DATA 0x64 +#define BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL 0xBC +#define BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL2 0xDC +#define BRCMF_PCIE_CFGREG_RBAR_CTRL 0x228 +#define BRCMF_PCIE_CFGREG_PML1_SUB_CTRL1 0x248 +#define BRCMF_PCIE_CFGREG_REG_BAR2_CONFIG 0x4E0 +#define BRCMF_PCIE_CFGREG_REG_BAR3_CONFIG 0x4F4 +#define BRCMF_PCIE_LINK_STATUS_CTRL_ASPM_ENAB 3 + MODULE_FIRMWARE(BRCMF_PCIE_43602_FW_NAME); MODULE_FIRMWARE(BRCMF_PCIE_43602_NVRAM_NAME); @@ -423,21 +437,42 @@ brcmf_pcie_select_core(struct brcmf_pciedev_info *devinfo, u16 coreid) } -static void brcmf_pcie_detach(struct brcmf_pciedev_info *devinfo) +static void brcmf_pcie_reset_device(struct brcmf_pciedev_info *devinfo) { - u16 cfg_offset[] = { 0x4, 0x4C, 0x58, 0x5C, 0x60, 0x64, 0xDC, 0x228, - 0x248, 0x4e0, 0x4f4 }; + u16 cfg_offset[] = { BRCMF_PCIE_CFGREG_STATUS_CMD, + BRCMF_PCIE_CFGREG_PM_CSR, + BRCMF_PCIE_CFGREG_MSI_CAP, + BRCMF_PCIE_CFGREG_MSI_ADDR_L, + BRCMF_PCIE_CFGREG_MSI_ADDR_H, + BRCMF_PCIE_CFGREG_MSI_DATA, + BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL2, + BRCMF_PCIE_CFGREG_RBAR_CTRL, + BRCMF_PCIE_CFGREG_PML1_SUB_CTRL1, + BRCMF_PCIE_CFGREG_REG_BAR2_CONFIG, + BRCMF_PCIE_CFGREG_REG_BAR3_CONFIG }; u32 i; u32 val; + u32 lsc; if (!devinfo->ci) return; - brcmf_pcie_select_core(devinfo, BCMA_CORE_CHIPCOMMON); - WRITECC32(devinfo, watchdog, 0x4e0); + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, + BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL); + lsc = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA); + val = lsc & (~BRCMF_PCIE_LINK_STATUS_CTRL_ASPM_ENAB); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA, val); + brcmf_pcie_select_core(devinfo, BCMA_CORE_CHIPCOMMON); + WRITECC32(devinfo, watchdog, 4); msleep(100); + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, + BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL); + brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGDATA, lsc); + brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); for (i = 0; i < ARRAY_SIZE(cfg_offset); i++) { brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, @@ -458,7 +493,7 @@ static void brcmf_pcie_attach(struct brcmf_pciedev_info *devinfo) brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); if (brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_INTMASK) != 0) - brcmf_pcie_detach(devinfo); + brcmf_pcie_reset_device(devinfo); /* BAR1 window may not be sized properly */ brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, 0x4e0); @@ -1686,7 +1721,7 @@ brcmf_pcie_remove(struct pci_dev *pdev) brcmf_pcie_release_irq(devinfo); brcmf_pcie_release_scratchbuffers(devinfo); brcmf_pcie_release_ringbuffers(devinfo); - brcmf_pcie_detach(devinfo); + brcmf_pcie_reset_device(devinfo); brcmf_pcie_release_resource(devinfo); if (devinfo->ci) -- cgit v1.2.3 From 17ca5c718414d605f0060336e071fb77359be790 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 30 Jul 2014 13:20:06 +0200 Subject: brcmfmac: Fix msgbuf flow control. Msgbuf flow control was using a function to flow off and on which was not supported without proptx enabled. Also flow control needs to be handled per ifidx. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 6 +-- drivers/net/wireless/brcm80211/brcmfmac/flowring.c | 61 ++++++++++++++++++++-- drivers/net/wireless/brcm80211/brcmfmac/flowring.h | 3 +- 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 1825f736fd45..5e4317dbc2b0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -121,12 +121,12 @@ struct brcmf_fws_mac_descriptor; * * @BRCMF_NETIF_STOP_REASON_FWS_FC: * netif stopped due to firmware signalling flow control. - * @BRCMF_NETIF_STOP_REASON_BLOCK_BUS: - * netif stopped due to bus blocking. + * @BRCMF_NETIF_STOP_REASON_FLOW: + * netif stopped due to flowring full. */ enum brcmf_netif_stop_reason { BRCMF_NETIF_STOP_REASON_FWS_FC = 1, - BRCMF_NETIF_STOP_REASON_BLOCK_BUS = 2 + BRCMF_NETIF_STOP_REASON_FLOW = 2 }; /** diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c index 26cbb7c4ec4c..07009046fda5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c @@ -158,6 +158,51 @@ u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid) } +static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid, + bool blocked) +{ + struct brcmf_flowring_ring *ring; + struct brcmf_bus *bus_if; + struct brcmf_pub *drvr; + struct brcmf_if *ifp; + bool currently_blocked; + int i; + u8 ifidx; + unsigned long flags; + + spin_lock_irqsave(&flow->block_lock, flags); + + ring = flow->rings[flowid]; + ifidx = brcmf_flowring_ifidx_get(flow, flowid); + + currently_blocked = false; + for (i = 0; i < flow->nrofrings; i++) { + if (flow->rings[i]) { + ring = flow->rings[i]; + if ((ring->status == RING_OPEN) && + (brcmf_flowring_ifidx_get(flow, i) == ifidx)) { + if (ring->blocked) { + currently_blocked = true; + break; + } + } + } + } + ring->blocked = blocked; + if (currently_blocked == blocked) { + spin_unlock_irqrestore(&flow->block_lock, flags); + return; + } + + bus_if = dev_get_drvdata(flow->dev); + drvr = bus_if->drvr; + ifp = drvr->iflist[ifidx]; + brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked); + + spin_unlock_irqrestore(&flow->block_lock, flags); +} + + void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid) { struct brcmf_flowring_ring *ring; @@ -167,6 +212,7 @@ void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid) ring = flow->rings[flowid]; if (!ring) return; + brcmf_flowring_block(flow, flowid, false); hash_idx = ring->hash_id; flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX; memset(flow->hash[hash_idx].mac, 0, ETH_ALEN); @@ -193,9 +239,16 @@ void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, if (!ring->blocked && (skb_queue_len(&ring->skblist) > BRCMF_FLOWRING_HIGH)) { - brcmf_txflowblock(flow->dev, true); + brcmf_flowring_block(flow, flowid, true); brcmf_dbg(MSGBUF, "Flowcontrol: BLOCK for ring %d\n", flowid); - ring->blocked = 1; + /* To prevent (work around) possible race condition, check + * queue len again. It is also possible to use locking to + * protect, but that is undesirable for every enqueue and + * dequeue. This simple check will solve a possible race + * condition if it occurs. + */ + if (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW) + brcmf_flowring_block(flow, flowid, false); } } @@ -213,9 +266,8 @@ struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid) if (ring->blocked && (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)) { - brcmf_txflowblock(flow->dev, false); + brcmf_flowring_block(flow, flowid, false); brcmf_dbg(MSGBUF, "Flowcontrol: OPEN for ring %d\n", flowid); - ring->blocked = 0; } return skb; @@ -283,6 +335,7 @@ struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings) if (flow) { flow->dev = dev; flow->nrofrings = nrofrings; + spin_lock_init(&flow->block_lock); for (i = 0; i < ARRAY_SIZE(flow->addr_mode); i++) flow->addr_mode[i] = ADDR_INDIRECT; for (i = 0; i < ARRAY_SIZE(flow->hash); i++) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h index 677f4b8065f6..cb9644ca6ece 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h @@ -35,7 +35,7 @@ enum ring_status { struct brcmf_flowring_ring { u8 hash_id; - u8 blocked; + bool blocked; enum ring_status status; struct sk_buff_head skblist; }; @@ -44,6 +44,7 @@ struct brcmf_flowring { struct device *dev; struct brcmf_flowring_hash hash[BRCMF_FLOWRING_HASHSIZE]; struct brcmf_flowring_ring **rings; + spinlock_t block_lock; enum proto_addr_mode addr_mode[BRCMF_MAX_IFS]; u16 nrofrings; }; -- cgit v1.2.3 From 70b7d94bcc1266fb91686bcd539ef81dff40eb3a Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 30 Jul 2014 13:20:07 +0200 Subject: brcmfmac: Add TDLS support to msgbuf. TDLS connections require dedicated flowrings. This patches adds TDLS event handling and flowring creation/deletion based on these events. Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/net/wireless/brcm80211/brcmfmac/bcdc.c | 7 ++ drivers/net/wireless/brcm80211/brcmfmac/flowring.c | 94 +++++++++++++++++++++- drivers/net/wireless/brcm80211/brcmfmac/flowring.h | 9 +++ drivers/net/wireless/brcm80211/brcmfmac/fweh.c | 6 +- drivers/net/wireless/brcm80211/brcmfmac/fweh.h | 5 ++ drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c | 10 +++ drivers/net/wireless/brcm80211/brcmfmac/proto.c | 2 +- drivers/net/wireless/brcm80211/brcmfmac/proto.h | 7 ++ .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 24 ++++++ 9 files changed, 158 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c index 10b48c2c4b36..a159ff3427de 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c @@ -349,6 +349,12 @@ brcmf_proto_bcdc_delete_peer(struct brcmf_pub *drvr, int ifidx, { } +static void +brcmf_proto_bcdc_add_tdls_peer(struct brcmf_pub *drvr, int ifidx, + u8 peer[ETH_ALEN]) +{ +} + int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) { struct brcmf_bcdc *bcdc; @@ -369,6 +375,7 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) drvr->proto->txdata = brcmf_proto_bcdc_txdata; drvr->proto->configure_addr_mode = brcmf_proto_bcdc_configure_addr_mode; drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer; + drvr->proto->add_tdls_peer = brcmf_proto_bcdc_add_tdls_peer; drvr->proto->pd = bcdc; drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c index 07009046fda5..a1016b811284 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c @@ -49,6 +49,23 @@ static const u8 brcmf_flowring_prio2fifo[] = { }; +static bool +brcmf_flowring_is_tdls_mac(struct brcmf_flowring *flow, u8 mac[ETH_ALEN]) +{ + struct brcmf_flowring_tdls_entry *search; + + search = flow->tdls_entry; + + while (search) { + if (memcmp(search->mac, mac, ETH_ALEN) == 0) + return true; + search = search->next; + } + + return false; +} + + u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN], u8 prio, u8 ifidx) { @@ -67,6 +84,10 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN], mac = (u8 *)ALLFFMAC; fifo = 0; } + if ((sta) && (flow->tdls_active) && + (brcmf_flowring_is_tdls_mac(flow, da))) { + sta = false; + } hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) : BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx); found = false; @@ -106,15 +127,17 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], mac = (u8 *)ALLFFMAC; fifo = 0; } + if ((sta) && (flow->tdls_active) && + (brcmf_flowring_is_tdls_mac(flow, da))) { + sta = false; + } hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) : BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx); found = false; hash = flow->hash; for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { - if (((sta) && - (hash[hash_idx].ifidx == BRCMF_FLOWRING_INVALID_IFIDX)) || - ((!sta) && - (memcmp(hash[hash_idx].mac, ALLZEROMAC, ETH_ALEN) == 0))) { + if ((hash[hash_idx].ifidx == BRCMF_FLOWRING_INVALID_IFIDX) && + (memcmp(hash[hash_idx].mac, ALLZEROMAC, ETH_ALEN) == 0)) { found = true; break; } @@ -356,12 +379,21 @@ void brcmf_flowring_detach(struct brcmf_flowring *flow) { struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev); struct brcmf_pub *drvr = bus_if->drvr; + struct brcmf_flowring_tdls_entry *search; + struct brcmf_flowring_tdls_entry *remove; u8 flowid; for (flowid = 0; flowid < flow->nrofrings; flowid++) { if (flow->rings[flowid]) brcmf_msgbuf_delete_flowring(drvr, flowid); } + + search = flow->tdls_entry; + while (search) { + remove = search; + search = search->next; + kfree(remove); + } kfree(flow->rings); kfree(flow); } @@ -396,11 +428,25 @@ void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx, struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev); struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_flowring_hash *hash; + struct brcmf_flowring_tdls_entry *prev; + struct brcmf_flowring_tdls_entry *search; u32 i; u8 flowid; bool sta; sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT); + + search = flow->tdls_entry; + prev = NULL; + while (search) { + if (memcmp(search->mac, peer, ETH_ALEN) == 0) { + sta = false; + break; + } + prev = search; + search = search->next; + } + hash = flow->hash; for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { if ((sta || (memcmp(hash[i].mac, peer, ETH_ALEN) == 0)) && @@ -412,4 +458,44 @@ void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx, } } } + + if (search) { + if (prev) + prev->next = search->next; + else + flow->tdls_entry = search->next; + kfree(search); + if (flow->tdls_entry == NULL) + flow->tdls_active = false; + } +} + + +void brcmf_flowring_add_tdls_peer(struct brcmf_flowring *flow, int ifidx, + u8 peer[ETH_ALEN]) +{ + struct brcmf_flowring_tdls_entry *tdls_entry; + struct brcmf_flowring_tdls_entry *search; + + tdls_entry = kzalloc(sizeof(*tdls_entry), GFP_ATOMIC); + if (tdls_entry == NULL) + return; + + memcpy(tdls_entry->mac, peer, ETH_ALEN); + tdls_entry->next = NULL; + if (flow->tdls_entry == NULL) { + flow->tdls_entry = tdls_entry; + } else { + search = flow->tdls_entry; + if (memcmp(search->mac, peer, ETH_ALEN) == 0) + return; + while (search->next) { + search = search->next; + if (memcmp(search->mac, peer, ETH_ALEN) == 0) + return; + } + search->next = tdls_entry; + } + + flow->tdls_active = true; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h index cb9644ca6ece..a34cd394c616 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h @@ -40,6 +40,11 @@ struct brcmf_flowring_ring { struct sk_buff_head skblist; }; +struct brcmf_flowring_tdls_entry { + u8 mac[ETH_ALEN]; + struct brcmf_flowring_tdls_entry *next; +}; + struct brcmf_flowring { struct device *dev; struct brcmf_flowring_hash hash[BRCMF_FLOWRING_HASHSIZE]; @@ -47,6 +52,8 @@ struct brcmf_flowring { spinlock_t block_lock; enum proto_addr_mode addr_mode[BRCMF_MAX_IFS]; u16 nrofrings; + bool tdls_active; + struct brcmf_flowring_tdls_entry *tdls_entry; }; @@ -70,6 +77,8 @@ void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx, enum proto_addr_mode addr_mode); void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx, u8 peer[ETH_ALEN]); +void brcmf_flowring_add_tdls_peer(struct brcmf_flowring *flow, int ifidx, + u8 peer[ETH_ALEN]); #endif /* BRCMFMAC_FLOWRING_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c index fad77dd2a3a5..4f1daabc551b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c @@ -293,7 +293,11 @@ static void brcmf_fweh_event_worker(struct work_struct *work) goto event_free; } - ifp = drvr->iflist[emsg.bsscfgidx]; + if ((event->code == BRCMF_E_TDLS_PEER_EVENT) && + (emsg.bsscfgidx == 1)) + ifp = drvr->iflist[0]; + else + ifp = drvr->iflist[emsg.bsscfgidx]; err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg, event->data); if (err) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h index 51b53a73d074..dd20b1862d44 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h @@ -102,6 +102,7 @@ struct brcmf_event; BRCMF_ENUM_DEF(DCS_REQUEST, 73) \ BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \ BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \ + BRCMF_ENUM_DEF(TDLS_PEER_EVENT, 92) \ BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \ BRCMF_ENUM_DEF(PSTA_PRIMARY_INTF_IND, 128) @@ -155,6 +156,10 @@ enum brcmf_fweh_event_code { #define BRCMF_E_REASON_TSPEC_REJECTED 7 #define BRCMF_E_REASON_BETTER_AP 8 +#define BRCMF_E_REASON_TDLS_PEER_DISCOVERED 0 +#define BRCMF_E_REASON_TDLS_PEER_CONNECTED 1 +#define BRCMF_E_REASON_TDLS_PEER_DISCONNECTED 2 + /* action field values for brcmf_ifevent */ #define BRCMF_E_IF_ADD 1 #define BRCMF_E_IF_DEL 2 diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c index c7a1c59ba6c3..535c7eb01b3a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c @@ -751,6 +751,15 @@ brcmf_msgbuf_delete_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN]) } +static void +brcmf_msgbuf_add_tdls_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN]) +{ + struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + + brcmf_flowring_add_tdls_peer(msgbuf->flow, ifidx, peer); +} + + static void brcmf_msgbuf_process_ioctl_complete(struct brcmf_msgbuf *msgbuf, void *buf) { @@ -1298,6 +1307,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) drvr->proto->txdata = brcmf_msgbuf_txdata; drvr->proto->configure_addr_mode = brcmf_msgbuf_configure_addr_mode; drvr->proto->delete_peer = brcmf_msgbuf_delete_peer; + drvr->proto->add_tdls_peer = brcmf_msgbuf_add_tdls_peer; drvr->proto->pd = msgbuf; init_waitqueue_head(&msgbuf->ioctl_resp_wait); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/brcm80211/brcmfmac/proto.c index 44b1cb466d4e..62b940723339 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/proto.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.c @@ -54,7 +54,7 @@ int brcmf_proto_attach(struct brcmf_pub *drvr) if ((proto->txdata == NULL) || (proto->hdrpull == NULL) || (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL) || (proto->configure_addr_mode == NULL) || - (proto->delete_peer == NULL)) { + (proto->delete_peer == NULL) || (proto->add_tdls_peer == NULL)) { brcmf_err("Not all proto handlers have been installed\n"); goto fail; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/brcm80211/brcmfmac/proto.h index 55942e3561a3..971172ff686c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/proto.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.h @@ -36,6 +36,8 @@ struct brcmf_proto { enum proto_addr_mode addr_mode); void (*delete_peer)(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN]); + void (*add_tdls_peer)(struct brcmf_pub *drvr, int ifidx, + u8 peer[ETH_ALEN]); void *pd; }; @@ -74,6 +76,11 @@ brcmf_proto_delete_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN]) { drvr->proto->delete_peer(drvr, ifidx, peer); } +static inline void +brcmf_proto_add_tdls_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN]) +{ + drvr->proto->add_tdls_peer(drvr, ifidx, peer); +} #endif /* BRCMFMAC_PROTO_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index a0e555a9f5f7..02fe706fc9ec 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4155,6 +4155,27 @@ static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy, clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status); } +static s32 +brcmf_notify_tdls_peer_event(struct brcmf_if *ifp, + const struct brcmf_event_msg *e, void *data) +{ + switch (e->reason) { + case BRCMF_E_REASON_TDLS_PEER_DISCOVERED: + brcmf_dbg(TRACE, "TDLS Peer Discovered\n"); + break; + case BRCMF_E_REASON_TDLS_PEER_CONNECTED: + brcmf_dbg(TRACE, "TDLS Peer Connected\n"); + brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr); + break; + case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED: + brcmf_dbg(TRACE, "TDLS Peer Disconnected\n"); + brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr); + break; + } + + return 0; +} + static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper) { int ret; @@ -5691,6 +5712,9 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, if (err) { brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err); wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS; + } else { + brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT, + brcmf_notify_tdls_peer_event); } return cfg; -- cgit v1.2.3 From ed7f75b4f058495332e107efa1b533fcc8720420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 30 Jul 2014 15:38:00 +0200 Subject: b43: update PHY descriptions in Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add lists of chipsets, so people can enable support for their device easier (at least after checking lspci). Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/Kconfig | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index d4c6ae3a9210..64a5b672e30a 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -132,35 +132,31 @@ config B43_PHY_G SoC: BCM4712, BCM5352E config B43_PHY_N - bool "Support for 802.11n (N-PHY) devices" + bool "Support for N-PHY (the main 802.11n series) devices" depends on B43 default y ---help--- - Support for the N-PHY. - - This enables support for devices with N-PHY. - - Say N if you expect high stability and performance. Saying Y will not - affect other devices support and may provide support for basic needs. + This PHY type can be found in the following chipsets: + PCI: BCM4321, BCM4322, + BCM43222, BCM43224, BCM43225, + BCM43131, BCM43217, BCM43227, BCM43228 + SoC: BCM4716, BCM4717, BCM4718, BCM5356, BCM5357, BCM5358 config B43_PHY_LP - bool "Support for low-power (LP-PHY) devices" + bool "Support for LP-PHY (low-power 802.11g) devices" depends on B43 && B43_SSB default y ---help--- - Support for the LP-PHY. The LP-PHY is a low-power PHY built into some notebooks and embedded devices. It supports 802.11a/b/g (802.11a support is optional, and currently disabled). config B43_PHY_HT - bool "Support for HT-PHY (high throughput) devices" + bool "Support for HT-PHY (high throughput 802.11n) devices" depends on B43 && B43_BCMA default y ---help--- - Support for the HT-PHY. - - Enables support for BCM4331 and possibly other chipsets with that PHY. + This PHY type with 3x3:3 MIMO can be found in the BCM4331 PCI chipset. config B43_PHY_LCN bool "Support for LCN-PHY devices (BROKEN)" -- cgit v1.2.3 From b9d317040a0a86104d0db0f02821a06fe4afc1cf Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Wed, 30 Jul 2014 13:57:16 -0700 Subject: MAINTAINERS: update for mwifiex driver maintainers Amitkumar and Avinash are taking care of mwifiex driver as the maintainers now due to organizational change. Signed-off-by: Bing Zhao Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: John W. Linville --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1859c2d0f9fc..1b9bef7a06c9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5681,7 +5681,8 @@ S: Maintained F: drivers/net/ethernet/marvell/mvneta.* MARVELL MWIFIEX WIRELESS DRIVER -M: Bing Zhao +M: Amitkumar Karwar +M: Avinash Patil L: linux-wireless@vger.kernel.org S: Maintained F: drivers/net/wireless/mwifiex/ -- cgit v1.2.3 From 11d14c7921715bf74fe3b43ba82cdade6f6dc476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 30 Jul 2014 23:02:30 +0200 Subject: b43: N-PHY: fix "Data bus error" while working in 5 GHz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When switching from one 5 GHz channel to another 5 GHz channel we need to make sure BPHY is still in a reset. However to access BPHY register we have to switch to 2 GHz mode for a moment. Otherwise this may result in "Data bus error" (noticed by Hauke with BCM43224 connected to the SoC). Reported-by: Hauke Mehrtens Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 1eead7af6899..e2a3f0d5bcc2 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -6217,6 +6217,9 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, u16 tmp16; if (new_channel->band == IEEE80211_BAND_5GHZ) { + /* Switch to 2 GHz for a moment to access B43_PHY_B_BBCFG */ + b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ); + tmp16 = b43_read16(dev, B43_MMIO_PSM_PHY_HDR); b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp16 | 4); /* Put BPHY in the reset */ -- cgit v1.2.3 From dc6be9f54a4ecb0a09765d1f515ed947d86b7528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 30 Jul 2014 23:21:06 +0200 Subject: bcma: use NS prefix for names of Northstar specific cores MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's cleaner and we don't have quite identical names like BCMA_CORE_PCIEG2 and BCMA_CORE_PCIE2. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/bcma/scan.c | 22 +++++++++++----------- include/linux/bcma/bcma.h | 22 +++++++++++----------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index 37768401d113..b4764c6bcf17 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -32,17 +32,17 @@ static const struct bcma_device_id_name bcma_bcm_device_names[] = { { BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" }, { BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" }, { BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" }, - { BCMA_CORE_PCIEG2, "PCIe Gen 2" }, - { BCMA_CORE_DMA, "DMA" }, - { BCMA_CORE_SDIO3, "SDIO3" }, - { BCMA_CORE_USB20, "USB 2.0" }, - { BCMA_CORE_USB30, "USB 3.0" }, - { BCMA_CORE_A9JTAG, "ARM Cortex A9 JTAG" }, - { BCMA_CORE_DDR23, "Denali DDR2/DDR3 memory controller" }, - { BCMA_CORE_ROM, "ROM" }, - { BCMA_CORE_NAND, "NAND flash controller" }, - { BCMA_CORE_QSPI, "SPI flash controller" }, - { BCMA_CORE_CHIPCOMMON_B, "Chipcommon B" }, + { BCMA_CORE_NS_PCIEG2, "PCIe Gen 2" }, + { BCMA_CORE_NS_DMA, "DMA" }, + { BCMA_CORE_NS_SDIO3, "SDIO3" }, + { BCMA_CORE_NS_USB20, "USB 2.0" }, + { BCMA_CORE_NS_USB30, "USB 3.0" }, + { BCMA_CORE_NS_A9JTAG, "ARM Cortex A9 JTAG" }, + { BCMA_CORE_NS_DDR23, "Denali DDR2/DDR3 memory controller" }, + { BCMA_CORE_NS_ROM, "ROM" }, + { BCMA_CORE_NS_NAND, "NAND flash controller" }, + { BCMA_CORE_NS_QSPI, "SPI flash controller" }, + { BCMA_CORE_NS_CHIPCOMMON_B, "Chipcommon B" }, { BCMA_CORE_ARMCA9, "ARM Cortex A9 core (ihost)" }, { BCMA_CORE_AMEMC, "AMEMC (DDR)" }, { BCMA_CORE_ALTA, "ALTA (I2S)" }, diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 70b8d88b3982..0272e49135d0 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -73,17 +73,17 @@ struct bcma_host_ops { /* Core-ID values. */ #define BCMA_CORE_OOB_ROUTER 0x367 /* Out of band */ #define BCMA_CORE_4706_CHIPCOMMON 0x500 -#define BCMA_CORE_PCIEG2 0x501 -#define BCMA_CORE_DMA 0x502 -#define BCMA_CORE_SDIO3 0x503 -#define BCMA_CORE_USB20 0x504 -#define BCMA_CORE_USB30 0x505 -#define BCMA_CORE_A9JTAG 0x506 -#define BCMA_CORE_DDR23 0x507 -#define BCMA_CORE_ROM 0x508 -#define BCMA_CORE_NAND 0x509 -#define BCMA_CORE_QSPI 0x50A -#define BCMA_CORE_CHIPCOMMON_B 0x50B +#define BCMA_CORE_NS_PCIEG2 0x501 +#define BCMA_CORE_NS_DMA 0x502 +#define BCMA_CORE_NS_SDIO3 0x503 +#define BCMA_CORE_NS_USB20 0x504 +#define BCMA_CORE_NS_USB30 0x505 +#define BCMA_CORE_NS_A9JTAG 0x506 +#define BCMA_CORE_NS_DDR23 0x507 +#define BCMA_CORE_NS_ROM 0x508 +#define BCMA_CORE_NS_NAND 0x509 +#define BCMA_CORE_NS_QSPI 0x50A +#define BCMA_CORE_NS_CHIPCOMMON_B 0x50B #define BCMA_CORE_4706_SOC_RAM 0x50E #define BCMA_CORE_ARMCA9 0x510 #define BCMA_CORE_4706_MAC_GBIT 0x52D -- cgit v1.2.3 From b6d04688040218d66edd8b221e43c67240b83119 Mon Sep 17 00:00:00 2001 From: Alexey Perevalov Date: Thu, 31 Jul 2014 17:14:05 +0400 Subject: netfilter: nfnetlink_acct: avoid using NFACCT_F_OVERQUOTA with bit helper functions Bit helper functions were used for manipulation with NFACCT_F_OVERQUOTA, but they are accepting pit position, but not a bit mask. As a result not a third bit for NFACCT_F_OVERQUOTA was set, but forth. Such behaviour was dangarous and could lead to unexpected overquota report result. Signed-off-by: Alexey Perevalov Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nfnetlink_acct.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c index 11d863c8b11f..3ea0eacbd970 100644 --- a/net/netfilter/nfnetlink_acct.c +++ b/net/netfilter/nfnetlink_acct.c @@ -41,6 +41,7 @@ struct nf_acct { }; #define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES) +#define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */ static int nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb, @@ -77,7 +78,8 @@ nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb, smp_mb__before_atomic(); /* reset overquota flag if quota is enabled. */ if ((matching->flags & NFACCT_F_QUOTA)) - clear_bit(NFACCT_F_OVERQUOTA, &matching->flags); + clear_bit(NFACCT_OVERQUOTA_BIT, + &matching->flags); return 0; } return -EBUSY; @@ -150,7 +152,7 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, bytes = atomic64_xchg(&acct->bytes, 0); smp_mb__before_atomic(); if (acct->flags & NFACCT_F_QUOTA) - clear_bit(NFACCT_F_OVERQUOTA, &acct->flags); + clear_bit(NFACCT_OVERQUOTA_BIT, &acct->flags); } else { pkts = atomic64_read(&acct->pkts); bytes = atomic64_read(&acct->bytes); @@ -414,7 +416,7 @@ int nfnl_acct_overquota(const struct sk_buff *skb, struct nf_acct *nfacct) ret = now > *quota; if (now >= *quota && - !test_and_set_bit(NFACCT_F_OVERQUOTA, &nfacct->flags)) { + !test_and_set_bit(NFACCT_OVERQUOTA_BIT, &nfacct->flags)) { nfnl_overquota_report(nfacct); } -- cgit v1.2.3 From 7afcaec4969652e177cf0b247a1530ac927a20f8 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Tue, 29 Jul 2014 13:27:43 +0200 Subject: bonding: use kobject_put instead of _del after kobject_add Otherwise the name of the kobject isn't getting freed and other stuff from kobject_cleanup() isn't getting called. kobject_put() will call kobject_del() on its own in kobject_cleanup(). CC: Jay Vosburgh CC: Andy Gospodarek Signed-off-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_sysfs_slave.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_sysfs_slave.c b/drivers/net/bonding/bond_sysfs_slave.c index 198677f58ce0..5cd532ca1cfe 100644 --- a/drivers/net/bonding/bond_sysfs_slave.c +++ b/drivers/net/bonding/bond_sysfs_slave.c @@ -125,7 +125,7 @@ int bond_sysfs_slave_add(struct slave *slave) for (a = slave_attrs; *a; ++a) { err = sysfs_create_file(&slave->kobj, &((*a)->attr)); if (err) { - kobject_del(&slave->kobj); + kobject_put(&slave->kobj); return err; } } @@ -140,5 +140,5 @@ void bond_sysfs_slave_del(struct slave *slave) for (a = slave_attrs; *a; ++a) sysfs_remove_file(&slave->kobj, &((*a)->attr)); - kobject_del(&slave->kobj); + kobject_put(&slave->kobj); } -- cgit v1.2.3 From 7d5570ca8972aad58de0b4ad03a5e991c41d4ce2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 25 Jul 2014 13:15:36 +0200 Subject: netfilter: nf_tables: check for unset NFTA_SET_ELEM_LIST_ELEMENTS attribute Otherwise, the kernel oopses in nla_for_each_nested when iterating over the unset attribute NFTA_SET_ELEM_LIST_ELEMENTS in the nf_tables_{new,del}setelem() path. netlink: 65524 bytes leftover after parsing attributes in process `nft'. [...] Oops: 0000 [#1] SMP [...] CPU: 2 PID: 6287 Comm: nft Not tainted 3.16.0-rc2+ #169 RIP: 0010:[] [] nf_tables_newsetelem+0x82/0xec [nf_tables] [...] Call Trace: [] nfnetlink_rcv+0x2e7/0x3d7 [nfnetlink] [] ? nfnetlink_rcv+0x35c/0x3d7 [nfnetlink] [] netlink_unicast+0xf8/0x17a [] netlink_sendmsg+0x323/0x351 [...] Fix this by returning -EINVAL if this attribute is not set, which doesn't make sense at all since those commands are there to add and to delete elements from the set. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index ecffb26e2f20..93692d692ebc 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -3073,6 +3073,9 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb, struct nft_ctx ctx; int rem, err = 0; + if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) + return -EINVAL; + err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, true); if (err < 0) return err; @@ -3156,6 +3159,9 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb, struct nft_ctx ctx; int rem, err = 0; + if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) + return -EINVAL; + err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, false); if (err < 0) return err; -- cgit v1.2.3 From 47fab41ab51a18a2e5fc4ec63f16b4c6702809b6 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Wed, 30 Jul 2014 13:31:51 +0900 Subject: bridge: Don't include NDA_VLAN for FDB entries with vid 0 An FDB entry with vlan_id 0 doesn't mean it is used in vlan 0, but used when vlan_filtering is disabled. There is inconsistency around NDA_VLAN whose payload is 0 - even if we add an entry by RTM_NEWNEIGH without any NDA_VLAN, and even though adding an entry with NDA_VLAN 0 is prohibited, we get an entry with NDA_VLAN 0 by RTM_GETNEIGH. Dumping an FDB entry with vlan_id 0 shouldn't include NDA_VLAN. Signed-off-by: Toshiaki Makita Signed-off-by: David S. Miller --- net/bridge/br_fdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index b524c36c1273..02359e81f86e 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -631,7 +631,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br, if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) goto nla_put_failure; - if (nla_put(skb, NDA_VLAN, sizeof(u16), &fdb->vlan_id)) + if (fdb->vlan_id && nla_put(skb, NDA_VLAN, sizeof(u16), &fdb->vlan_id)) goto nla_put_failure; return nlmsg_end(skb, nlh); -- cgit v1.2.3 From 2b391ee2cae3945832011970bede35dab885879d Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 31 Jul 2014 21:48:59 +0200 Subject: team: fix releasing uninitialized pointer to BPF prog Commit 34c5bd66e5ed introduced the possibility that an uninitialized pointer on the stack (orig_fp) can call into sk_unattached_filter_destroy() when its value is non NULL. Before that commit orig_fp was only destroyed in the same block where it was assigned a valid BPF prog before. Fix it up by initializing it to NULL. Fixes: 34c5bd66e5ed ("net: filter: don't release unattached filter through call_rcu()") Signed-off-by: Daniel Borkmann Cc: Pablo Neira Cc: Alexei Starovoitov Cc: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/team/team_mode_loadbalance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c index 7106f3456439..d7be9b36bce6 100644 --- a/drivers/net/team/team_mode_loadbalance.c +++ b/drivers/net/team/team_mode_loadbalance.c @@ -272,7 +272,7 @@ static int lb_bpf_func_set(struct team *team, struct team_gsetter_ctx *ctx) { struct lb_priv *lb_priv = get_lb_priv(team); struct sk_filter *fp = NULL; - struct sk_filter *orig_fp; + struct sk_filter *orig_fp = NULL; struct sock_fprog_kern *fprog = NULL; int err; -- cgit v1.2.3 From 388070faa1e1f6138c1ea0e82271c7ecb3f36477 Mon Sep 17 00:00:00 2001 From: "Banerjee, Debabrata" Date: Wed, 30 Jul 2014 13:50:17 -0400 Subject: tcp: don't require root to read tcp_metrics commit d23ff7016 (tcp: add generic netlink support for tcp_metrics) introduced netlink support for the new tcp_metrics, however it restricted getting of tcp_metrics to root user only. This is a change from how these values could have been fetched when in the old route cache. Unless there's a legitimate reason to restrict the reading of these values it would be better if normal users could fetch them. Cc: Julian Anastasov Cc: linux-kernel@vger.kernel.org Signed-off-by: Debabrata Banerjee Signed-off-by: David S. Miller --- net/ipv4/tcp_metrics.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 4fe041805989..0d54e59b9ea8 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -1093,7 +1093,6 @@ static const struct genl_ops tcp_metrics_nl_ops[] = { .doit = tcp_metrics_nl_cmd_get, .dumpit = tcp_metrics_nl_dump, .policy = tcp_metrics_nl_policy, - .flags = GENL_ADMIN_PERM, }, { .cmd = TCP_METRICS_CMD_DEL, -- cgit v1.2.3 From 7ed24bbe188e9e910274969e65b91342e7642dbf Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Thu, 31 Jul 2014 15:49:13 -0500 Subject: net: stmmac: Change MAC interface to support multiple filter configurations The synopsys EMAC can be configured for different numbers of multicast hash bins and perfect filter entries at device creation time and there's no way to query this configuration information at runtime. As a result, a devicetree parameter is required in order for the driver to program these filters correctly for a particular device instance. This patch modifies the 10/100/1000 MAC software interface such that these configuration parameters can be set at initialization time. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/common.h | 41 ++++++++++-------- .../net/ethernet/stmicro/stmmac/dwmac1000_core.c | 50 +++++++++++++++------- .../net/ethernet/stmicro/stmmac/dwmac100_core.c | 24 +++++++---- .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 6 +-- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 32 +++++++------- 5 files changed, 91 insertions(+), 62 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 74610f3aca9e..96f1f14310a6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -368,34 +368,36 @@ struct stmmac_dma_ops { void (*rx_watchdog) (void __iomem *ioaddr, u32 riwt); }; +struct mac_device_info; + struct stmmac_ops { /* MAC core initialization */ - void (*core_init) (void __iomem *ioaddr, int mtu); + void (*core_init)(struct mac_device_info *hw, int mtu); /* Enable and verify that the IPC module is supported */ - int (*rx_ipc) (void __iomem *ioaddr); + int (*rx_ipc)(struct mac_device_info *hw); /* Dump MAC registers */ - void (*dump_regs) (void __iomem *ioaddr); + void (*dump_regs)(struct mac_device_info *hw); /* Handle extra events on specific interrupts hw dependent */ - int (*host_irq_status) (void __iomem *ioaddr, - struct stmmac_extra_stats *x); + int (*host_irq_status)(struct mac_device_info *hw, + struct stmmac_extra_stats *x); /* Multicast filter setting */ - void (*set_filter) (struct net_device *dev, int id); + void (*set_filter)(struct net_device *dev, int id); /* Flow control setting */ - void (*flow_ctrl) (void __iomem *ioaddr, unsigned int duplex, - unsigned int fc, unsigned int pause_time); + void (*flow_ctrl)(struct mac_device_info *hw, unsigned int duplex, + unsigned int fc, unsigned int pause_time); /* Set power management mode (e.g. magic frame) */ - void (*pmt) (void __iomem *ioaddr, unsigned long mode); + void (*pmt)(struct mac_device_info *hw, unsigned long mode); /* Set/Get Unicast MAC addresses */ - void (*set_umac_addr) (void __iomem *ioaddr, unsigned char *addr, - unsigned int reg_n); - void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr, - unsigned int reg_n); - void (*set_eee_mode) (void __iomem *ioaddr); - void (*reset_eee_mode) (void __iomem *ioaddr); - void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw); - void (*set_eee_pls) (void __iomem *ioaddr, int link); - void (*ctrl_ane) (void __iomem *ioaddr, bool restart); - void (*get_adv) (void __iomem *ioaddr, struct rgmii_adv *adv); + void (*set_umac_addr)(struct mac_device_info *hw, unsigned char *addr, + unsigned int reg_n); + void (*get_umac_addr)(struct mac_device_info *hw, unsigned char *addr, + unsigned int reg_n); + void (*set_eee_mode)(struct mac_device_info *hw); + void (*reset_eee_mode)(struct mac_device_info *hw); + void (*set_eee_timer)(struct mac_device_info *hw, int ls, int tw); + void (*set_eee_pls)(struct mac_device_info *hw, int link); + void (*ctrl_ane)(struct mac_device_info *hw, bool restart); + void (*get_adv)(struct mac_device_info *hw, struct rgmii_adv *adv); }; struct stmmac_hwtimestamp { @@ -439,6 +441,7 @@ struct mac_device_info { struct mii_regs mii; /* MII register Addresses */ struct mac_link link; unsigned int synopsys_uid; + void __iomem *pcsr; /* vpointer to device CSRs */ }; struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index 9d3748361a1e..b6081ff29c91 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -32,8 +32,9 @@ #include #include "dwmac1000.h" -static void dwmac1000_core_init(void __iomem *ioaddr, int mtu) +static void dwmac1000_core_init(struct mac_device_info *hw, int mtu) { + void __iomem *ioaddr = hw->pcsr; u32 value = readl(ioaddr + GMAC_CONTROL); value |= GMAC_CORE_INIT; if (mtu > 1500) @@ -52,8 +53,9 @@ static void dwmac1000_core_init(void __iomem *ioaddr, int mtu) #endif } -static int dwmac1000_rx_ipc_enable(void __iomem *ioaddr) +static int dwmac1000_rx_ipc_enable(struct mac_device_info *hw) { + void __iomem *ioaddr = hw->pcsr; u32 value = readl(ioaddr + GMAC_CONTROL); value |= GMAC_CONTROL_IPC; @@ -64,8 +66,9 @@ static int dwmac1000_rx_ipc_enable(void __iomem *ioaddr) return !!(value & GMAC_CONTROL_IPC); } -static void dwmac1000_dump_regs(void __iomem *ioaddr) +static void dwmac1000_dump_regs(struct mac_device_info *hw) { + void __iomem *ioaddr = hw->pcsr; int i; pr_info("\tDWMAC1000 regs (base addr = 0x%p)\n", ioaddr); @@ -76,16 +79,20 @@ static void dwmac1000_dump_regs(void __iomem *ioaddr) } } -static void dwmac1000_set_umac_addr(void __iomem *ioaddr, unsigned char *addr, +static void dwmac1000_set_umac_addr(struct mac_device_info *hw, + unsigned char *addr, unsigned int reg_n) { + void __iomem *ioaddr = hw->pcsr; stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), GMAC_ADDR_LOW(reg_n)); } -static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr, +static void dwmac1000_get_umac_addr(struct mac_device_info *hw, + unsigned char *addr, unsigned int reg_n) { + void __iomem *ioaddr = hw->pcsr; stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), GMAC_ADDR_LOW(reg_n)); } @@ -146,7 +153,9 @@ static void dwmac1000_set_filter(struct net_device *dev, int id) struct netdev_hw_addr *ha; netdev_for_each_uc_addr(ha, dev) { - dwmac1000_set_umac_addr(ioaddr, ha->addr, reg); + stmmac_get_mac_addr(ioaddr, ha->addr, + GMAC_ADDR_HIGH(reg), + GMAC_ADDR_LOW(reg)); reg++; } } @@ -162,9 +171,11 @@ static void dwmac1000_set_filter(struct net_device *dev, int id) readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW)); } -static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, + +static void dwmac1000_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, unsigned int fc, unsigned int pause_time) { + void __iomem *ioaddr = hw->pcsr; unsigned int flow = 0; pr_debug("GMAC Flow-Control:\n"); @@ -185,8 +196,9 @@ static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, writel(flow, ioaddr + GMAC_FLOW_CTRL); } -static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode) +static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode) { + void __iomem *ioaddr = hw->pcsr; unsigned int pmt = 0; if (mode & WAKE_MAGIC) { @@ -201,9 +213,10 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode) writel(pmt, ioaddr + GMAC_PMT); } -static int dwmac1000_irq_status(void __iomem *ioaddr, +static int dwmac1000_irq_status(struct mac_device_info *hw, struct stmmac_extra_stats *x) { + void __iomem *ioaddr = hw->pcsr; u32 intr_status = readl(ioaddr + GMAC_INT_STATUS); int ret = 0; @@ -268,8 +281,9 @@ static int dwmac1000_irq_status(void __iomem *ioaddr, return ret; } -static void dwmac1000_set_eee_mode(void __iomem *ioaddr) +static void dwmac1000_set_eee_mode(struct mac_device_info *hw) { + void __iomem *ioaddr = hw->pcsr; u32 value; /* Enable the link status receive on RGMII, SGMII ore SMII @@ -281,8 +295,9 @@ static void dwmac1000_set_eee_mode(void __iomem *ioaddr) writel(value, ioaddr + LPI_CTRL_STATUS); } -static void dwmac1000_reset_eee_mode(void __iomem *ioaddr) +static void dwmac1000_reset_eee_mode(struct mac_device_info *hw) { + void __iomem *ioaddr = hw->pcsr; u32 value; value = readl(ioaddr + LPI_CTRL_STATUS); @@ -290,8 +305,9 @@ static void dwmac1000_reset_eee_mode(void __iomem *ioaddr) writel(value, ioaddr + LPI_CTRL_STATUS); } -static void dwmac1000_set_eee_pls(void __iomem *ioaddr, int link) +static void dwmac1000_set_eee_pls(struct mac_device_info *hw, int link) { + void __iomem *ioaddr = hw->pcsr; u32 value; value = readl(ioaddr + LPI_CTRL_STATUS); @@ -304,8 +320,9 @@ static void dwmac1000_set_eee_pls(void __iomem *ioaddr, int link) writel(value, ioaddr + LPI_CTRL_STATUS); } -static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw) +static void dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw) { + void __iomem *ioaddr = hw->pcsr; int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16); /* Program the timers in the LPI timer control register: @@ -318,8 +335,9 @@ static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw) writel(value, ioaddr + LPI_TIMER_CTRL); } -static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool restart) +static void dwmac1000_ctrl_ane(struct mac_device_info *hw, bool restart) { + void __iomem *ioaddr = hw->pcsr; /* auto negotiation enable and External Loopback enable */ u32 value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE; @@ -329,8 +347,9 @@ static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool restart) writel(value, ioaddr + GMAC_AN_CTRL); } -static void dwmac1000_get_adv(void __iomem *ioaddr, struct rgmii_adv *adv) +static void dwmac1000_get_adv(struct mac_device_info *hw, struct rgmii_adv *adv) { + void __iomem *ioaddr = hw->pcsr; u32 value = readl(ioaddr + GMAC_ANE_ADV); if (value & GMAC_ANE_FD) @@ -377,6 +396,7 @@ struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr) if (!mac) return NULL; + mac->pcsr = ioaddr; mac->mac = &dwmac1000_ops; mac->dma = &dwmac1000_dma_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c index 2ff767bcfdd0..8bb201aeb686 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c @@ -32,8 +32,9 @@ #include #include "dwmac100.h" -static void dwmac100_core_init(void __iomem *ioaddr, int mtu) +static void dwmac100_core_init(struct mac_device_info *hw, int mtu) { + void __iomem *ioaddr = hw->pcsr; u32 value = readl(ioaddr + MAC_CONTROL); writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL); @@ -43,8 +44,9 @@ static void dwmac100_core_init(void __iomem *ioaddr, int mtu) #endif } -static void dwmac100_dump_mac_regs(void __iomem *ioaddr) +static void dwmac100_dump_mac_regs(struct mac_device_info *hw) { + void __iomem *ioaddr = hw->pcsr; pr_info("\t----------------------------------------------\n" "\t DWMAC 100 CSR (base addr = 0x%p)\n" "\t----------------------------------------------\n", ioaddr); @@ -66,26 +68,30 @@ static void dwmac100_dump_mac_regs(void __iomem *ioaddr) readl(ioaddr + MAC_VLAN2)); } -static int dwmac100_rx_ipc_enable(void __iomem *ioaddr) +static int dwmac100_rx_ipc_enable(struct mac_device_info *hw) { return 0; } -static int dwmac100_irq_status(void __iomem *ioaddr, +static int dwmac100_irq_status(struct mac_device_info *hw, struct stmmac_extra_stats *x) { return 0; } -static void dwmac100_set_umac_addr(void __iomem *ioaddr, unsigned char *addr, +static void dwmac100_set_umac_addr(struct mac_device_info *hw, + unsigned char *addr, unsigned int reg_n) { + void __iomem *ioaddr = hw->pcsr; stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); } -static void dwmac100_get_umac_addr(void __iomem *ioaddr, unsigned char *addr, +static void dwmac100_get_umac_addr(struct mac_device_info *hw, + unsigned char *addr, unsigned int reg_n) { + void __iomem *ioaddr = hw->pcsr; stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); } @@ -137,9 +143,10 @@ static void dwmac100_set_filter(struct net_device *dev, int id) writel(value, ioaddr + MAC_CONTROL); } -static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, +static void dwmac100_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, unsigned int fc, unsigned int pause_time) { + void __iomem *ioaddr = hw->pcsr; unsigned int flow = MAC_FLOW_CTRL_ENABLE; if (duplex) @@ -148,7 +155,7 @@ static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, } /* No PMT module supported on ST boards with this Eth chip. */ -static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode) +static void dwmac100_pmt(struct mac_device_info *hw, unsigned long mode) { return; } @@ -175,6 +182,7 @@ struct mac_device_info *dwmac100_setup(void __iomem *ioaddr) pr_info("\tDWMAC100\n"); + mac->pcsr = ioaddr; mac->mac = &dwmac100_ops; mac->dma = &dwmac100_dma_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index c62e67f3c2f0..9af50bae4dde 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -262,7 +262,7 @@ static int stmmac_ethtool_getsettings(struct net_device *dev, /* Get and convert ADV/LP_ADV from the HW AN registers */ if (priv->hw->mac->get_adv) - priv->hw->mac->get_adv(priv->ioaddr, &adv); + priv->hw->mac->get_adv(priv->hw, &adv); else return -EOPNOTSUPP; /* should never happen indeed */ @@ -350,7 +350,7 @@ static int stmmac_ethtool_setsettings(struct net_device *dev, spin_lock(&priv->lock); if (priv->hw->mac->ctrl_ane) - priv->hw->mac->ctrl_ane(priv->ioaddr, 1); + priv->hw->mac->ctrl_ane(priv->hw, 1); spin_unlock(&priv->lock); } @@ -464,7 +464,7 @@ stmmac_set_pauseparam(struct net_device *netdev, if (netif_running(netdev)) ret = phy_start_aneg(phy); } else - priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex, + priv->hw->mac->flow_ctrl(priv->hw, phy->duplex, priv->flow_ctrl, priv->pause); return ret; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 18315f34938b..814ff4599205 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -233,7 +233,7 @@ static void stmmac_enable_eee_mode(struct stmmac_priv *priv) /* Check and enter in LPI mode */ if ((priv->dirty_tx == priv->cur_tx) && (priv->tx_path_in_lpi_mode == false)) - priv->hw->mac->set_eee_mode(priv->ioaddr); + priv->hw->mac->set_eee_mode(priv->hw); } /** @@ -244,7 +244,7 @@ static void stmmac_enable_eee_mode(struct stmmac_priv *priv) */ void stmmac_disable_eee_mode(struct stmmac_priv *priv) { - priv->hw->mac->reset_eee_mode(priv->ioaddr); + priv->hw->mac->reset_eee_mode(priv->hw); del_timer_sync(&priv->eee_ctrl_timer); priv->tx_path_in_lpi_mode = false; } @@ -298,7 +298,7 @@ bool stmmac_eee_init(struct stmmac_priv *priv) if (priv->eee_active) { pr_debug("stmmac: disable EEE\n"); del_timer_sync(&priv->eee_ctrl_timer); - priv->hw->mac->set_eee_timer(priv->ioaddr, 0, + priv->hw->mac->set_eee_timer(priv->hw, 0, tx_lpi_timer); } priv->eee_active = 0; @@ -313,12 +313,12 @@ bool stmmac_eee_init(struct stmmac_priv *priv) priv->eee_ctrl_timer.expires = STMMAC_LPI_T(eee_timer); add_timer(&priv->eee_ctrl_timer); - priv->hw->mac->set_eee_timer(priv->ioaddr, + priv->hw->mac->set_eee_timer(priv->hw, STMMAC_DEFAULT_LIT_LS, tx_lpi_timer); } else /* Set HW EEE according to the speed */ - priv->hw->mac->set_eee_pls(priv->ioaddr, + priv->hw->mac->set_eee_pls(priv->hw, priv->phydev->link); pr_debug("stmmac: Energy-Efficient Ethernet initialized\n"); @@ -693,7 +693,7 @@ static void stmmac_adjust_link(struct net_device *dev) } /* Flow Control operation */ if (phydev->pause) - priv->hw->mac->flow_ctrl(priv->ioaddr, phydev->duplex, + priv->hw->mac->flow_ctrl(priv->hw, phydev->duplex, fc, pause_time); if (phydev->speed != priv->speed) { @@ -1531,8 +1531,7 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv) static void stmmac_check_ether_addr(struct stmmac_priv *priv) { if (!is_valid_ether_addr(priv->dev->dev_addr)) { - priv->hw->mac->get_umac_addr((void __iomem *) - priv->dev->base_addr, + priv->hw->mac->get_umac_addr(priv->hw, priv->dev->dev_addr, 0); if (!is_valid_ether_addr(priv->dev->dev_addr)) eth_hw_addr_random(priv->dev); @@ -1629,14 +1628,14 @@ static int stmmac_hw_setup(struct net_device *dev) } /* Copy the MAC addr into the HW */ - priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0); + priv->hw->mac->set_umac_addr(priv->hw, dev->dev_addr, 0); /* If required, perform hw setup of the bus. */ if (priv->plat->bus_setup) priv->plat->bus_setup(priv->ioaddr); /* Initialize the MAC Core */ - priv->hw->mac->core_init(priv->ioaddr, dev->mtu); + priv->hw->mac->core_init(priv->hw, dev->mtu); /* Enable the MAC Rx/Tx */ stmmac_set_mac(priv->ioaddr, true); @@ -1662,7 +1661,7 @@ static int stmmac_hw_setup(struct net_device *dev) /* Dump DMA/MAC registers */ if (netif_msg_hw(priv)) { - priv->hw->mac->dump_regs(priv->ioaddr); + priv->hw->mac->dump_regs(priv->hw); priv->hw->dma->dump_regs(priv->ioaddr); } priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS; @@ -1677,7 +1676,7 @@ static int stmmac_hw_setup(struct net_device *dev) } if (priv->pcs && priv->hw->mac->ctrl_ane) - priv->hw->mac->ctrl_ane(priv->ioaddr, 0); + priv->hw->mac->ctrl_ane(priv->hw, 0); return 0; } @@ -2316,8 +2315,7 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) /* To handle GMAC own interrupts */ if (priv->plat->has_gmac) { - int status = priv->hw->mac->host_irq_status((void __iomem *) - dev->base_addr, + int status = priv->hw->mac->host_irq_status(priv->hw, &priv->xstats); if (unlikely(status)) { /* For LPI we need to save the tx status */ @@ -2649,7 +2647,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv) /* To use alternate (extended) or normal descriptor structures */ stmmac_selec_desc_mode(priv); - ret = priv->hw->mac->rx_ipc(priv->ioaddr); + ret = priv->hw->mac->rx_ipc(priv->hw); if (!ret) { pr_warn(" RX IPC Checksum Offload not configured.\n"); priv->plat->rx_coe = STMMAC_RX_COE_NONE; @@ -2869,7 +2867,7 @@ int stmmac_suspend(struct net_device *ndev) /* Enable Power down mode by programming the PMT regs */ if (device_may_wakeup(priv->device)) { - priv->hw->mac->pmt(priv->ioaddr, priv->wolopts); + priv->hw->mac->pmt(priv->hw, priv->wolopts); priv->irq_wake = 1; } else { stmmac_set_mac(priv->ioaddr, false); @@ -2902,7 +2900,7 @@ int stmmac_resume(struct net_device *ndev) * from another devices (e.g. serial console). */ if (device_may_wakeup(priv->device)) { - priv->hw->mac->pmt(priv->ioaddr, 0); + priv->hw->mac->pmt(priv->hw, 0); priv->irq_wake = 0; } else { pinctrl_pm_select_default_state(priv->device); -- cgit v1.2.3 From aefef4c15a1f696ed6c676698d26741024d98f36 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Thu, 31 Jul 2014 15:49:14 -0500 Subject: net: stmmac: Correct set_filter for multicast and unicast cases This patch removes the check for the number of mulitcast addresses when using hash based filtering since it's not necessary. If the number of multicast addresses in the list exceeds the number of multicast hash bins, the bins will "fold" over into one of the bins configured and enabled for the particular component instance. The default number of maximum unicast addresses was changed from 32 to 1 since this number is not dependent on the component revision. The maximum number of multicast and unicast addresses is dependent on the configuration of the Synopsys EMAC configured by the SOC architect at the time the features were selected and configured for a particular component. Sadly, Synopsys does not provide a way to query the precise number supported by a particular component, so we must fall back on a devicetree entry. This configuration could vary from vendor to vendor (such as STMicro, Altera, etc). The multicast bins are set for every possible filtering case (including no entries) - previously the bits were set only if multicast filter entries were present. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/common.h | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 2 +- .../net/ethernet/stmicro/stmmac/dwmac1000_core.c | 25 +++++++++------------- .../net/ethernet/stmicro/stmmac/dwmac100_core.c | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 96f1f14310a6..49f72e1ffbef 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -381,7 +381,7 @@ struct stmmac_ops { int (*host_irq_status)(struct mac_device_info *hw, struct stmmac_extra_stats *x); /* Multicast filter setting */ - void (*set_filter)(struct net_device *dev, int id); + void (*set_filter)(struct net_device *dev); /* Flow control setting */ void (*flow_ctrl)(struct mac_device_info *hw, unsigned int duplex, unsigned int fc, unsigned int pause_time); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h index f37d90f114f5..285e3056f362 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h @@ -87,7 +87,7 @@ enum power_event { (reg * 8)) #define GMAC_ADDR_LOW(reg) (((reg > 15) ? 0x00000804 : 0x00000044) + \ (reg * 8)) -#define GMAC_MAX_PERFECT_ADDRESSES 32 +#define GMAC_MAX_PERFECT_ADDRESSES 1 /* PCS registers (AN/TBI/SGMII/RGMII) offset */ #define GMAC_AN_CTRL 0x000000c0 /* AN control */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index b6081ff29c91..cdcbad1f1ac0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -97,30 +97,28 @@ static void dwmac1000_get_umac_addr(struct mac_device_info *hw, GMAC_ADDR_LOW(reg_n)); } -static void dwmac1000_set_filter(struct net_device *dev, int id) +static void dwmac1000_set_filter(struct net_device *dev) { void __iomem *ioaddr = (void __iomem *)dev->base_addr; unsigned int value = 0; unsigned int perfect_addr_number; + u32 mc_filter[2]; pr_debug("%s: # mcasts %d, # unicast %d\n", __func__, netdev_mc_count(dev), netdev_uc_count(dev)); - if (dev->flags & IFF_PROMISC) + memset(mc_filter, 0, sizeof(mc_filter)); + + if (dev->flags & IFF_PROMISC) { value = GMAC_FRAME_FILTER_PR; - else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE) - || (dev->flags & IFF_ALLMULTI)) { + } else if (dev->flags & IFF_ALLMULTI) { value = GMAC_FRAME_FILTER_PM; /* pass all multi */ - writel(0xffffffff, ioaddr + GMAC_HASH_HIGH); - writel(0xffffffff, ioaddr + GMAC_HASH_LOW); } else if (!netdev_mc_empty(dev)) { - u32 mc_filter[2]; struct netdev_hw_addr *ha; /* Hash filter for multicast */ value = GMAC_FRAME_FILTER_HMC; - memset(mc_filter, 0, sizeof(mc_filter)); netdev_for_each_mc_addr(ha, dev) { /* The upper 6 bits of the calculated CRC are used to * index the contens of the hash table @@ -132,15 +130,12 @@ static void dwmac1000_set_filter(struct net_device *dev, int id) */ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); } - writel(mc_filter[0], ioaddr + GMAC_HASH_LOW); - writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH); } - /* Extra 16 regs are available in cores newer than the 3.40. */ - if (id > DWMAC_CORE_3_40) - perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES; - else - perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES / 2; + writel(mc_filter[0], ioaddr + GMAC_HASH_LOW); + writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH); + + perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES; /* Handle multiple unicast addresses (perfect filtering) */ if (netdev_uc_count(dev) > perfect_addr_number) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c index 8bb201aeb686..3a2d63388f8d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c @@ -95,7 +95,7 @@ static void dwmac100_get_umac_addr(struct mac_device_info *hw, stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); } -static void dwmac100_set_filter(struct net_device *dev, int id) +static void dwmac100_set_filter(struct net_device *dev) { void __iomem *ioaddr = (void __iomem *)dev->base_addr; u32 value = readl(ioaddr + MAC_CONTROL); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 814ff4599205..cff2b69e62ee 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2225,7 +2225,7 @@ static void stmmac_set_rx_mode(struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); spin_lock(&priv->lock); - priv->hw->mac->set_filter(dev, priv->synopsys_id); + priv->hw->mac->set_filter(dev); spin_unlock(&priv->lock); } -- cgit v1.2.3 From 94ceaa26320fc48c16ea299ee7b546a0203d95b5 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Thu, 31 Jul 2014 15:49:15 -0500 Subject: dts: Add bindings for multicast hash bins and perfect filter entries This change adds bindings for the number of multicast hash bins and perfect filter entries supported by the Synopsys EMAC. The Synopsys EMAC core is configurable at device creation time, and can be configured for a different number of multicast hash bins and a different number of perfect filter entries. The device does not provide a way to query these parameters, therefore parameters are required. The Altera Cyclone V SOC has support for 256 multicast hash bins and 128 perfect filter entries, and is different than what's currently provided in the stmmac driver. Signed-off-by: Vince Bridgers Acked-by: Rob Herring Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/stmmac.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/net/stmmac.txt b/Documentation/devicetree/bindings/net/stmmac.txt index a2acd2b26baf..9b03c57563a4 100644 --- a/Documentation/devicetree/bindings/net/stmmac.txt +++ b/Documentation/devicetree/bindings/net/stmmac.txt @@ -25,6 +25,10 @@ Required properties: - snps,force_sf_dma_mode Force DMA to use the Store and Forward mode for both tx and rx. This flag is ignored if force_thresh_dma_mode is set. +- snps,multicast-filter-bins: Number of multicast filter hash bins + supported by this device instance +- snps,perfect-filter-entries: Number of perfect filter entries supported + by this device instance Optional properties: - resets: Should contain a phandle to the STMMAC reset signal, if any @@ -47,6 +51,8 @@ Examples: mac-address = [000000000000]; /* Filled in by U-Boot */ max-frame-size = <3800>; phy-mode = "gmii"; + snps,multicast-filter-bins = <256>; + snps,perfect-filter-entries = <128>; clocks = <&clock>; clock-names = "stmmaceth">; }; -- cgit v1.2.3 From ea6856e35240c5accf0936de920f2d8c9afee444 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Thu, 31 Jul 2014 15:49:16 -0500 Subject: ARM: socfpga: Add socfpga Ethernet filter attributes entries This patch adds socfpga Ethernet filter attributes for multicast and unicast filters per Synopsys Ethernet IP configuration chosen by Altera for the Cyclone 5 and Arria SOC FPGAs. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- arch/arm/boot/dts/socfpga.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 4676f25e87a7..70fdd2064811 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -486,6 +486,8 @@ clock-names = "stmmaceth"; resets = <&rst EMAC0_RESET>; reset-names = "stmmaceth"; + snps,multicast-filter-bins = <256>; + snps,perfect-filter-entries = <128>; status = "disabled"; }; @@ -500,6 +502,8 @@ clock-names = "stmmaceth"; resets = <&rst EMAC1_RESET>; reset-names = "stmmaceth"; + snps,multicast-filter-bins = <256>; + snps,perfect-filter-entries = <128>; status = "disabled"; }; -- cgit v1.2.3 From 3b57de958e2aa39abe020eb31bf19000d5899389 Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Thu, 31 Jul 2014 15:49:17 -0500 Subject: net: stmmac: Support devicetree configs for mcast and ucast filter entries This patch adds and modifies code to support multiple Multicast and Unicast Synopsys MAC filter configurations. The default configuration is defined to support legacy driver behavior, which is 64 Multicast bins. The Unicast filter code previously assumed all controllers support 32 or 16 Unicast addresses based on controller version number, but this has been corrected to support a default of 1 Unicast address. The filter configuration may be specified through the devicetree using a Synopsys specific device tree entry. This information was verified with Synopsys through Synopsys Support Case #8000684337 and shared with the maintainer. Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/common.h | 8 ++- drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 1 + .../net/ethernet/stmicro/stmmac/dwmac1000_core.c | 66 +++++++++++++++------ .../net/ethernet/stmicro/stmmac/dwmac100_core.c | 3 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 +- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 67 ++++++++++++++++++++++ include/linux/stmmac.h | 2 + 7 files changed, 132 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 49f72e1ffbef..de507c32036c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -381,7 +381,7 @@ struct stmmac_ops { int (*host_irq_status)(struct mac_device_info *hw, struct stmmac_extra_stats *x); /* Multicast filter setting */ - void (*set_filter)(struct net_device *dev); + void (*set_filter)(struct mac_device_info *hw, struct net_device *dev); /* Flow control setting */ void (*flow_ctrl)(struct mac_device_info *hw, unsigned int duplex, unsigned int fc, unsigned int pause_time); @@ -442,9 +442,13 @@ struct mac_device_info { struct mac_link link; unsigned int synopsys_uid; void __iomem *pcsr; /* vpointer to device CSRs */ + int multicast_filter_bins; + int unicast_filter_entries; + int mcast_bits_log2; }; -struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr); +struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins, + int perfect_uc_entries); struct mac_device_info *dwmac100_setup(void __iomem *ioaddr); void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h index 285e3056f362..71b5419256c1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h @@ -261,6 +261,7 @@ enum rtc_control { #define GMAC_MMC_RX_INTR 0x104 #define GMAC_MMC_TX_INTR 0x108 #define GMAC_MMC_RX_CSUM_OFFLOAD 0x208 +#define GMAC_EXTHASH_BASE 0x500 extern const struct stmmac_dma_ops dwmac1000_dma_ops; #endif /* __DWMAC1000_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index cdcbad1f1ac0..d8ef18786a1c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -97,12 +97,41 @@ static void dwmac1000_get_umac_addr(struct mac_device_info *hw, GMAC_ADDR_LOW(reg_n)); } -static void dwmac1000_set_filter(struct net_device *dev) +static void dwmac1000_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits, + int mcbitslog2) +{ + int numhashregs, regs; + + switch (mcbitslog2) { + case 6: + writel(mcfilterbits[0], ioaddr + GMAC_HASH_LOW); + writel(mcfilterbits[1], ioaddr + GMAC_HASH_HIGH); + return; + break; + case 7: + numhashregs = 4; + break; + case 8: + numhashregs = 8; + break; + default: + pr_debug("STMMAC: err in setting mulitcast filter\n"); + return; + break; + } + for (regs = 0; regs < numhashregs; regs++) + writel(mcfilterbits[regs], + ioaddr + GMAC_EXTHASH_BASE + regs * 4); +} + +static void dwmac1000_set_filter(struct mac_device_info *hw, + struct net_device *dev) { void __iomem *ioaddr = (void __iomem *)dev->base_addr; unsigned int value = 0; - unsigned int perfect_addr_number; + unsigned int perfect_addr_number = hw->unicast_filter_entries; u32 mc_filter[2]; + int mcbitslog2 = hw->mcast_bits_log2; pr_debug("%s: # mcasts %d, # unicast %d\n", __func__, netdev_mc_count(dev), netdev_uc_count(dev)); @@ -120,10 +149,14 @@ static void dwmac1000_set_filter(struct net_device *dev) value = GMAC_FRAME_FILTER_HMC; netdev_for_each_mc_addr(ha, dev) { - /* The upper 6 bits of the calculated CRC are used to - * index the contens of the hash table + /* The upper n bits of the calculated CRC are used to + * index the contents of the hash table. The number of + * bits used depends on the hardware configuration + * selected at core configuration time. */ - int bit_nr = bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26; + int bit_nr = bitrev32(~crc32_le(~0, ha->addr, + ETH_ALEN)) >> + (32 - mcbitslog2); /* The most significant bit determines the register to * use (H/L) while the other 5 bits determine the bit * within the register. @@ -132,15 +165,12 @@ static void dwmac1000_set_filter(struct net_device *dev) } } - writel(mc_filter[0], ioaddr + GMAC_HASH_LOW); - writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH); - - perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES; + dwmac1000_set_mchash(ioaddr, mc_filter, mcbitslog2); /* Handle multiple unicast addresses (perfect filtering) */ if (netdev_uc_count(dev) > perfect_addr_number) - /* Switch to promiscuous mode if more than 16 addrs - * are required + /* Switch to promiscuous mode if more than unicast + * addresses are requested than supported by hardware. */ value |= GMAC_FRAME_FILTER_PR; else { @@ -160,10 +190,6 @@ static void dwmac1000_set_filter(struct net_device *dev) value |= GMAC_FRAME_FILTER_RA; #endif writel(value, ioaddr + GMAC_FRAME_FILTER); - - pr_debug("\tFilter: 0x%08x\n\tHash: HI 0x%08x, LO 0x%08x\n", - readl(ioaddr + GMAC_FRAME_FILTER), - readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW)); } @@ -382,7 +408,8 @@ static const struct stmmac_ops dwmac1000_ops = { .get_adv = dwmac1000_get_adv, }; -struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr) +struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins, + int perfect_uc_entries) { struct mac_device_info *mac; u32 hwid = readl(ioaddr + GMAC_VERSION); @@ -392,6 +419,13 @@ struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr) return NULL; mac->pcsr = ioaddr; + mac->multicast_filter_bins = mcbins; + mac->unicast_filter_entries = perfect_uc_entries; + mac->mcast_bits_log2 = 0; + + if (mac->multicast_filter_bins) + mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins); + mac->mac = &dwmac1000_ops; mac->dma = &dwmac1000_dma_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c index 3a2d63388f8d..f8dd773f246c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c @@ -95,7 +95,8 @@ static void dwmac100_get_umac_addr(struct mac_device_info *hw, stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); } -static void dwmac100_set_filter(struct net_device *dev) +static void dwmac100_set_filter(struct mac_device_info *hw, + struct net_device *dev) { void __iomem *ioaddr = (void __iomem *)dev->base_addr; u32 value = readl(ioaddr + MAC_CONTROL); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index cff2b69e62ee..08addd653728 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2225,7 +2225,7 @@ static void stmmac_set_rx_mode(struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); spin_lock(&priv->lock); - priv->hw->mac->set_filter(dev); + priv->hw->mac->set_filter(priv->hw, dev); spin_unlock(&priv->lock); } @@ -2598,7 +2598,9 @@ static int stmmac_hw_init(struct stmmac_priv *priv) /* Identify the MAC HW device */ if (priv->plat->has_gmac) { priv->dev->priv_flags |= IFF_UNICAST_FLT; - mac = dwmac1000_setup(priv->ioaddr); + mac = dwmac1000_setup(priv->ioaddr, + priv->plat->multicast_filter_bins, + priv->plat->unicast_filter_entries); } else { mac = dwmac100_setup(priv->ioaddr); } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index ea7a65be1f9a..bb524a932be4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -52,6 +52,59 @@ static const struct of_device_id stmmac_dt_ids[] = { MODULE_DEVICE_TABLE(of, stmmac_dt_ids); #ifdef CONFIG_OF + +/* This function validates the number of Multicast filtering bins specified + * by the configuration through the device tree. The Synopsys GMAC supports + * 64 bins, 128 bins, or 256 bins. "bins" refer to the division of CRC + * number space. 64 bins correspond to 6 bits of the CRC, 128 corresponds + * to 7 bits, and 256 refers to 8 bits of the CRC. Any other setting is + * invalid and will cause the filtering algorithm to use Multicast + * promiscuous mode. + */ +static int dwmac1000_validate_mcast_bins(int mcast_bins) +{ + int x = mcast_bins; + + switch (x) { + case HASH_TABLE_SIZE: + case 128: + case 256: + break; + default: + x = 0; + pr_info("Hash table entries set to unexpected value %d", + mcast_bins); + break; + } + return x; +} + +/* This function validates the number of Unicast address entries supported + * by a particular Synopsys 10/100/1000 controller. The Synopsys controller + * supports 1, 32, 64, or 128 Unicast filter entries for it's Unicast filter + * logic. This function validates a valid, supported configuration is + * selected, and defaults to 1 Unicast address if an unsupported + * configuration is selected. + */ +static int dwmac1000_validate_ucast_entries(int ucast_entries) +{ + int x = ucast_entries; + + switch (x) { + case 1: + case 32: + case 64: + case 128: + break; + default: + x = 1; + pr_info("Unicast table entries set to unexpected value %d\n", + ucast_entries); + break; + } + return x; +} + static int stmmac_probe_config_dt(struct platform_device *pdev, struct plat_stmmacenet_data *plat, const char **mac) @@ -115,6 +168,12 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, */ plat->maxmtu = JUMBO_LEN; + /* Set default value for multicast hash bins */ + plat->multicast_filter_bins = HASH_TABLE_SIZE; + + /* Set default value for unicast filter entries */ + plat->unicast_filter_entries = 1; + /* * Currently only the properties needed on SPEAr600 * are provided. All other properties should be added @@ -131,6 +190,14 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, * are clearly MTUs */ of_property_read_u32(np, "max-frame-size", &plat->maxmtu); + of_property_read_u32(np, "snps,multicast-filter-bins", + &plat->multicast_filter_bins); + of_property_read_u32(np, "snps,perfect-filter-entries", + &plat->unicast_filter_entries); + plat->unicast_filter_entries = dwmac1000_validate_ucast_entries( + plat->unicast_filter_entries); + plat->multicast_filter_bins = dwmac1000_validate_mcast_bins( + plat->multicast_filter_bins); plat->has_gmac = 1; plat->pmt = 1; } diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index 6f27d4f957bd..cd63851b57f2 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -112,6 +112,8 @@ struct plat_stmmacenet_data { int riwt_off; int max_speed; int maxmtu; + int multicast_filter_bins; + int unicast_filter_entries; void (*fix_mac_speed)(void *priv, unsigned int speed); void (*bus_setup)(void __iomem *ioaddr); void *(*setup)(struct platform_device *pdev); -- cgit v1.2.3 From 536721b1cb3fb50034bf6f6c7a7ea16166970e69 Mon Sep 17 00:00:00 2001 From: Karoly Kemeny Date: Wed, 30 Jul 2014 20:27:36 +0200 Subject: net: kernel-doc compliant documentation for net_device Net_device is a vast and important structure, but it has no kernel-doc compliant documentation. This patch extracts the comments from the structure to clean it up, and let the scripts extract documentation from it. I know that the patch is big, but it's just reordering of comments into the appropriate form, and adding a few more, for the missing members. Signed-off-by: Karoly Kemeny Acked-by: Randy Dunlap Signed-off-by: David S. Miller --- include/linux/netdevice.h | 381 ++++++++++++++++++++++++++++++---------------- 1 file changed, 250 insertions(+), 131 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8e8fb3ed574b..38377392d082 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1231,42 +1231,228 @@ enum netdev_priv_flags { #define IFF_LIVE_ADDR_CHANGE IFF_LIVE_ADDR_CHANGE #define IFF_MACVLAN IFF_MACVLAN -/* - * The DEVICE structure. - * Actually, this whole structure is a big mistake. It mixes I/O - * data with strictly "high-level" data, and it has to know about - * almost every data structure used in the INET module. +/** + * struct net_device - The DEVICE structure. + * Actually, this whole structure is a big mistake. It mixes I/O + * data with strictly "high-level" data, and it has to know about + * almost every data structure used in the INET module. + * + * @name: This is the first field of the "visible" part of this structure + * (i.e. as seen by users in the "Space.c" file). It is the name + * of the interface. + * + * @name_hlist: Device name hash chain, please keep it close to name[] + * @ifalias: SNMP alias + * @mem_end: Shared memory end + * @mem_start: Shared memory start + * @base_addr: Device I/O address + * @irq: Device IRQ number + * + * @state: Generic network queuing layer state, see netdev_state_t + * @dev_list: The global list of network devices + * @napi_list: List entry, that is used for polling napi devices + * @unreg_list: List entry, that is used, when we are unregistering the + * device, see the function unregister_netdev + * @close_list: List entry, that is used, when we are closing the device + * + * @adj_list: Directly linked devices, like slaves for bonding + * @all_adj_list: All linked devices, *including* neighbours + * @features: Currently active device features + * @hw_features: User-changeable features + * + * @wanted_features: User-requested features + * @vlan_features: Mask of features inheritable by VLAN devices + * + * @hw_enc_features: Mask of features inherited by encapsulating devices + * This field indicates what encapsulation + * offloads the hardware is capable of doing, + * and drivers will need to set them appropriately. + * + * @mpls_features: Mask of features inheritable by MPLS + * + * @ifindex: interface index + * @iflink: unique device identifier + * + * @stats: Statistics struct, which was left as a legacy, use + * rtnl_link_stats64 instead + * + * @rx_dropped: Dropped packets by core network, + * do not use this in drivers + * @tx_dropped: Dropped packets by core network, + * do not use this in drivers + * + * @carrier_changes: Stats to monitor carrier on<->off transitions + * + * @wireless_handlers: List of functions to handle Wireless Extensions, + * instead of ioctl, + * see for details. + * @wireless_data: Instance data managed by the core of wireless extensions + * + * @netdev_ops: Includes several pointers to callbacks, + * if one wants to override the ndo_*() functions + * @ethtool_ops: Management operations + * @fwd_ops: Management operations + * @header_ops: Includes callbacks for creating,parsing,rebuilding,etc + * of Layer 2 headers. + * + * @flags: Interface flags (a la BSD) + * @priv_flags: Like 'flags' but invisible to userspace, + * see if.h for the definitions + * @gflags: Global flags ( kept as legacy ) + * @padded: How much padding added by alloc_netdev() + * @operstate: RFC2863 operstate + * @link_mode: Mapping policy to operstate + * @if_port: Selectable AUI, TP, ... + * @dma: DMA channel + * @mtu: Interface MTU value + * @type: Interface hardware type + * @hard_header_len: Hardware header length + * + * @needed_headroom: Extra headroom the hardware may need, but not in all + * cases can this be guaranteed + * @needed_tailroom: Extra tailroom the hardware may need, but not in all + * cases can this be guaranteed. Some cases also use + * LL_MAX_HEADER instead to allocate the skb + * + * interface address info: + * + * @perm_addr: Permanent hw address + * @addr_assign_type: Hw address assignment type + * @addr_len: Hardware address length + * @neigh_priv_len; Used in neigh_alloc(), + * initialized only in atm/clip.c + * @dev_id: Used to differentiate devices that share + * the same link layer address + * @dev_port: Used to differentiate devices that share + * the same function + * @addr_list_lock: XXX: need comments on this one + * @uc: unicast mac addresses + * @mc: multicast mac addresses + * @dev_addrs: list of device hw addresses + * @queues_kset: Group of all Kobjects in the Tx and RX queues + * @uc_promisc: Counter, that indicates, that promiscuous mode + * has been enabled due to the need to listen to + * additional unicast addresses in a device that + * does not implement ndo_set_rx_mode() + * @promiscuity: Number of times, the NIC is told to work in + * Promiscuous mode, if it becomes 0 the NIC will + * exit from working in Promiscuous mode + * @allmulti: Counter, enables or disables allmulticast mode + * + * @vlan_info: VLAN info + * @dsa_ptr: dsa specific data + * @tipc_ptr: TIPC specific data + * @atalk_ptr: AppleTalk link + * @ip_ptr: IPv4 specific data + * @dn_ptr: DECnet specific data + * @ip6_ptr: IPv6 specific data + * @ax25_ptr: AX.25 specific data + * @ieee80211_ptr: IEEE 802.11 specific data, assign before registering + * + * @last_rx: Time of last Rx + * @dev_addr: Hw address (before bcast, + * because most packets are unicast) + * + * @_rx: Array of RX queues + * @num_rx_queues: Number of RX queues + * allocated at register_netdev() time + * @real_num_rx_queues: Number of RX queues currently active in device + * + * @rx_handler: handler for received packets + * @rx_handler_data: XXX: need comments on this one + * @ingress_queue: XXX: need comments on this one + * @broadcast: hw bcast address + * + * @_tx: Array of TX queues + * @num_tx_queues: Number of TX queues allocated at alloc_netdev_mq() time + * @real_num_tx_queues: Number of TX queues currently active in device + * @qdisc: Root qdisc from userspace point of view + * @tx_queue_len: Max frames per queue allowed + * @tx_global_lock: XXX: need comments on this one + * + * @xps_maps: XXX: need comments on this one + * + * @rx_cpu_rmap: CPU reverse-mapping for RX completion interrupts, + * indexed by RX queue number. Assigned by driver. + * This must only be set if the ndo_rx_flow_steer + * operation is defined + * + * @trans_start: Time (in jiffies) of last Tx + * @watchdog_timeo: Represents the timeout that is used by + * the watchdog ( see dev_watchdog() ) + * @watchdog_timer: List of timers + * + * @pcpu_refcnt: Number of references to this device + * @todo_list: Delayed register/unregister + * @index_hlist: Device index hash chain + * @link_watch_list: XXX: need comments on this one + * + * @reg_state: Register/unregister state machine + * @dismantle: Device is going to be freed + * @rtnl_link_state: This enum represents the phases of creating + * a new link + * + * @destructor: Called from unregister, + * can be used to call free_netdev + * @npinfo: XXX: need comments on this one + * @nd_net: Network namespace this network device is inside + * + * @ml_priv: Mid-layer private + * @lstats: Loopback statistics + * @tstats: Tunnel statistics + * @dstats: Dummy statistics + * @vstats: Virtual ethernet statistics + * + * @garp_port: GARP + * @mrp_port: MRP + * + * @dev: Class/net/name entry + * @sysfs_groups: Space for optional device, statistics and wireless + * sysfs groups + * + * @sysfs_rx_queue_group: Space for optional per-rx queue attributes + * @rtnl_link_ops: Rtnl_link_ops + * + * @gso_max_size: Maximum size of generic segmentation offload + * @gso_max_segs: Maximum number of segments that can be passed to the + * NIC for GSO + * + * @dcbnl_ops: Data Center Bridging netlink ops + * @num_tc: Number of traffic classes in the net device + * @tc_to_txq: XXX: need comments on this one + * @prio_tc_map XXX: need comments on this one + * + * @fcoe_ddp_xid: Max exchange id for FCoE LRO by ddp + * + * @priomap: XXX: need comments on this one + * @phydev: Physical device may attach itself + * for hardware timestamping + * + * @qdisc_tx_busylock: XXX: need comments on this one + * + * @group: The group, that the device belongs to + * @pm_qos_req: Power Management QoS object * * FIXME: cleanup struct net_device such that network protocol info * moves out. */ struct net_device { - - /* - * This is the first field of the "visible" part of this structure - * (i.e. as seen by users in the "Space.c" file). It is the name - * of the interface. - */ char name[IFNAMSIZ]; - - /* device name hash chain, please keep it close to name[] */ struct hlist_node name_hlist; - - /* snmp alias */ char *ifalias; - /* * I/O specific fields * FIXME: Merge these and struct ifmap into one */ - unsigned long mem_end; /* shared mem end */ - unsigned long mem_start; /* shared mem start */ - unsigned long base_addr; /* device I/O address */ - int irq; /* device IRQ number */ + unsigned long mem_end; + unsigned long mem_start; + unsigned long base_addr; + int irq; /* - * Some hardware also needs these fields, but they are not + * Some hardware also needs these fields (state,dev_list, + * napi_list,unreg_list,close_list) but they are not * part of the usual set specified in Space.c. */ @@ -1277,106 +1463,74 @@ struct net_device { struct list_head unreg_list; struct list_head close_list; - /* directly linked devices, like slaves for bonding */ struct { struct list_head upper; struct list_head lower; } adj_list; - /* all linked devices, *including* neighbours */ struct { struct list_head upper; struct list_head lower; } all_adj_list; - - /* currently active device features */ netdev_features_t features; - /* user-changeable features */ netdev_features_t hw_features; - /* user-requested features */ netdev_features_t wanted_features; - /* mask of features inheritable by VLAN devices */ netdev_features_t vlan_features; - /* mask of features inherited by encapsulating devices - * This field indicates what encapsulation offloads - * the hardware is capable of doing, and drivers will - * need to set them appropriately. - */ netdev_features_t hw_enc_features; - /* mask of fetures inheritable by MPLS */ netdev_features_t mpls_features; - /* Interface index. Unique device identifier */ int ifindex; int iflink; struct net_device_stats stats; - /* dropped packets by core network, Do not use this in drivers */ atomic_long_t rx_dropped; atomic_long_t tx_dropped; - /* Stats to monitor carrier on<->off transitions */ atomic_t carrier_changes; #ifdef CONFIG_WIRELESS_EXT - /* List of functions to handle Wireless Extensions (instead of ioctl). - * See for details. Jean II */ const struct iw_handler_def * wireless_handlers; - /* Instance data managed by the core of Wireless Extensions. */ struct iw_public_data * wireless_data; #endif - /* Management operations */ const struct net_device_ops *netdev_ops; const struct ethtool_ops *ethtool_ops; const struct forwarding_accel_ops *fwd_ops; - /* Hardware header description */ const struct header_ops *header_ops; - unsigned int flags; /* interface flags (a la BSD) */ - unsigned int priv_flags; /* Like 'flags' but invisible to userspace. - * See if.h for definitions. */ + unsigned int flags; + unsigned int priv_flags; + unsigned short gflags; - unsigned short padded; /* How much padding added by alloc_netdev() */ + unsigned short padded; - unsigned char operstate; /* RFC2863 operstate */ - unsigned char link_mode; /* mapping policy to operstate */ + unsigned char operstate; + unsigned char link_mode; - unsigned char if_port; /* Selectable AUI, TP,..*/ - unsigned char dma; /* DMA channel */ + unsigned char if_port; + unsigned char dma; - unsigned int mtu; /* interface MTU value */ - unsigned short type; /* interface hardware type */ - unsigned short hard_header_len; /* hardware hdr length */ + unsigned int mtu; + unsigned short type; + unsigned short hard_header_len; - /* extra head- and tailroom the hardware may need, but not in all cases - * can this be guaranteed, especially tailroom. Some cases also use - * LL_MAX_HEADER instead to allocate the skb. - */ unsigned short needed_headroom; unsigned short needed_tailroom; /* Interface address info. */ - unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */ - unsigned char addr_assign_type; /* hw address assignment type */ - unsigned char addr_len; /* hardware address length */ + unsigned char perm_addr[MAX_ADDR_LEN]; + unsigned char addr_assign_type; + unsigned char addr_len; unsigned short neigh_priv_len; - unsigned short dev_id; /* Used to differentiate devices - * that share the same link - * layer address - */ - unsigned short dev_port; /* Used to differentiate - * devices that share the same - * function - */ + unsigned short dev_id; + unsigned short dev_port; spinlock_t addr_list_lock; - struct netdev_hw_addr_list uc; /* Unicast mac addresses */ - struct netdev_hw_addr_list mc; /* Multicast mac addresses */ - struct netdev_hw_addr_list dev_addrs; /* list of device - * hw addresses - */ + struct netdev_hw_addr_list uc; + struct netdev_hw_addr_list mc; + struct netdev_hw_addr_list dev_addrs; + #ifdef CONFIG_SYSFS struct kset *queues_kset; #endif @@ -1391,40 +1545,34 @@ struct net_device { /* Protocol specific pointers */ #if IS_ENABLED(CONFIG_VLAN_8021Q) - struct vlan_info __rcu *vlan_info; /* VLAN info */ + struct vlan_info __rcu *vlan_info; #endif #if IS_ENABLED(CONFIG_NET_DSA) - struct dsa_switch_tree *dsa_ptr; /* dsa specific data */ + struct dsa_switch_tree *dsa_ptr; #endif #if IS_ENABLED(CONFIG_TIPC) - struct tipc_bearer __rcu *tipc_ptr; /* TIPC specific data */ + struct tipc_bearer __rcu *tipc_ptr; #endif - void *atalk_ptr; /* AppleTalk link */ - struct in_device __rcu *ip_ptr; /* IPv4 specific data */ - struct dn_dev __rcu *dn_ptr; /* DECnet specific data */ - struct inet6_dev __rcu *ip6_ptr; /* IPv6 specific data */ - void *ax25_ptr; /* AX.25 specific data */ - struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data, - assign before registering */ + void *atalk_ptr; + struct in_device __rcu *ip_ptr; + struct dn_dev __rcu *dn_ptr; + struct inet6_dev __rcu *ip6_ptr; + void *ax25_ptr; + struct wireless_dev *ieee80211_ptr; /* * Cache lines mostly used on receive path (including eth_type_trans()) */ - unsigned long last_rx; /* Time of last Rx */ + unsigned long last_rx; /* Interface address info used in eth_type_trans() */ - unsigned char *dev_addr; /* hw address, (before bcast - because most packets are - unicast) */ + unsigned char *dev_addr; #ifdef CONFIG_SYSFS struct netdev_rx_queue *_rx; - /* Number of RX queues allocated at register_netdev() time */ unsigned int num_rx_queues; - - /* Number of RX queues currently active in device */ unsigned int real_num_rx_queues; #endif @@ -1433,33 +1581,23 @@ struct net_device { void __rcu *rx_handler_data; struct netdev_queue __rcu *ingress_queue; - unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ + unsigned char broadcast[MAX_ADDR_LEN]; /* * Cache lines mostly used on transmit path */ struct netdev_queue *_tx ____cacheline_aligned_in_smp; - - /* Number of TX queues allocated at alloc_netdev_mq() time */ unsigned int num_tx_queues; - - /* Number of TX queues currently active in device */ unsigned int real_num_tx_queues; - - /* root qdisc from userspace point of view */ struct Qdisc *qdisc; - - unsigned long tx_queue_len; /* Max frames per queue allowed */ + unsigned long tx_queue_len; spinlock_t tx_global_lock; #ifdef CONFIG_XPS struct xps_dev_maps __rcu *xps_maps; #endif #ifdef CONFIG_RFS_ACCEL - /* CPU reverse-mapping for RX completion interrupts, indexed - * by RX queue number. Assigned by driver. This must only be - * set if the ndo_rx_flow_steer operation is defined. */ struct cpu_rmap *rx_cpu_rmap; #endif @@ -1469,22 +1607,17 @@ struct net_device { * trans_start here is expensive for high speed devices on SMP, * please use netdev_queue->trans_start instead. */ - unsigned long trans_start; /* Time (in jiffies) of last Tx */ + unsigned long trans_start; - int watchdog_timeo; /* used by dev_watchdog() */ + int watchdog_timeo; struct timer_list watchdog_timer; - /* Number of references to this device */ int __percpu *pcpu_refcnt; - - /* delayed register/unregister */ struct list_head todo_list; - /* device index hash chain */ - struct hlist_node index_hlist; + struct hlist_node index_hlist; struct list_head link_watch_list; - /* register/unregister state machine */ enum { NETREG_UNINITIALIZED=0, NETREG_REGISTERED, /* completed register_netdevice */ NETREG_UNREGISTERING, /* called unregister_netdevice */ @@ -1493,14 +1626,13 @@ struct net_device { NETREG_DUMMY, /* dummy device for NAPI poll */ } reg_state:8; - bool dismantle; /* device is going do be freed */ + bool dismantle; enum { RTNL_LINK_INITIALIZED, RTNL_LINK_INITIALIZING, } rtnl_link_state:16; - /* Called from unregister, can be used to call free_netdev */ void (*destructor)(struct net_device *dev); #ifdef CONFIG_NETPOLL @@ -1508,31 +1640,25 @@ struct net_device { #endif #ifdef CONFIG_NET_NS - /* Network namespace this network device is inside */ struct net *nd_net; #endif /* mid-layer private */ union { - void *ml_priv; - struct pcpu_lstats __percpu *lstats; /* loopback stats */ + void *ml_priv; + struct pcpu_lstats __percpu *lstats; struct pcpu_sw_netstats __percpu *tstats; - struct pcpu_dstats __percpu *dstats; /* dummy stats */ - struct pcpu_vstats __percpu *vstats; /* veth stats */ + struct pcpu_dstats __percpu *dstats; + struct pcpu_vstats __percpu *vstats; }; - /* GARP */ + struct garp_port __rcu *garp_port; - /* MRP */ struct mrp_port __rcu *mrp_port; - /* class/net/name entry */ - struct device dev; - /* space for optional device, statistics, and wireless sysfs groups */ + struct device dev; const struct attribute_group *sysfs_groups[4]; - /* space for optional per-rx queue attributes */ const struct attribute_group *sysfs_rx_queue_group; - /* rtnetlink link ops */ const struct rtnl_link_ops *rtnl_link_ops; /* for setting kernel sock attribute on TCP connection setup */ @@ -1542,7 +1668,6 @@ struct net_device { u16 gso_max_segs; #ifdef CONFIG_DCB - /* Data Center Bridging netlink ops */ const struct dcbnl_rtnl_ops *dcbnl_ops; #endif u8 num_tc; @@ -1550,20 +1675,14 @@ struct net_device { u8 prio_tc_map[TC_BITMASK + 1]; #if IS_ENABLED(CONFIG_FCOE) - /* max exchange id for FCoE LRO by ddp */ unsigned int fcoe_ddp_xid; #endif #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) struct netprio_map __rcu *priomap; #endif - /* phy device may attach itself for hardware timestamping */ struct phy_device *phydev; - struct lock_class_key *qdisc_tx_busylock; - - /* group the device belongs to */ int group; - struct pm_qos_request pm_qos_req; }; #define to_net_dev(d) container_of(d, struct net_device, dev) -- cgit v1.2.3 From 299ee123e19889d511092347f5fc14db0f10e3a6 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 30 Jul 2014 12:40:53 -0600 Subject: sctp: Fixup v4mapped behaviour to comply with Sock API The SCTP socket extensions API document describes the v4mapping option as follows: 8.1.15. Set/Clear IPv4 Mapped Addresses (SCTP_I_WANT_MAPPED_V4_ADDR) This socket option is a Boolean flag which turns on or off the mapping of IPv4 addresses. If this option is turned on, then IPv4 addresses will be mapped to V6 representation. If this option is turned off, then no mapping will be done of V4 addresses and a user will receive both PF_INET6 and PF_INET type addresses on the socket. See [RFC3542] for more details on mapped V6 addresses. This description isn't really in line with what the code does though. Introduce addr_to_user (renamed addr_v4map), which should be called before any sockaddr is passed back to user space. The new function places the sockaddr into the correct format depending on the SCTP_I_WANT_MAPPED_V4_ADDR option. Audit all places that touched v4mapped and either sanely construct a v4 or v6 address then call addr_to_user, or drop the unnecessary v4mapped check entirely. Audit all places that call addr_to_user and verify they are on a sycall return path. Add a custom getname that formats the address properly. Several bugs are addressed: - SCTP_I_WANT_MAPPED_V4_ADDR=0 often returned garbage for addresses to user space - The addr_len returned from recvmsg was not correct when returning AF_INET on a v6 socket - flowlabel and scope_id were not zerod when promoting a v4 to v6 - Some syscalls like bind and connect behaved differently depending on v4mapped Tested bind, getpeername, getsockname, connect, and recvmsg for proper behaviour in v4mapped = 1 and 0 cases. Signed-off-by: Neil Horman Tested-by: Jason Gunthorpe Signed-off-by: Jason Gunthorpe Signed-off-by: David S. Miller --- include/net/sctp/sctp.h | 2 + include/net/sctp/structs.h | 8 +-- net/sctp/ipv6.c | 156 ++++++++++++++++++++++++--------------------- net/sctp/protocol.c | 12 ++-- net/sctp/socket.c | 33 +++++----- net/sctp/transport.c | 4 +- net/sctp/ulpevent.c | 2 +- 7 files changed, 112 insertions(+), 105 deletions(-) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 90c1cccd164d..f6e7397e799d 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -554,6 +554,8 @@ static inline void sctp_v6_map_v4(union sctp_addr *addr) static inline void sctp_v4_map_v6(union sctp_addr *addr) { addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_flowinfo = 0; + addr->v6.sin6_scope_id = 0; addr->v6.sin6_port = addr->v4.sin_port; addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr; addr->v6.sin6_addr.s6_addr32[0] = 0; diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 7741d1b66967..4ff3f67be62c 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -465,10 +465,6 @@ struct sctp_af { int saddr); void (*from_sk) (union sctp_addr *, struct sock *sk); - void (*to_sk_saddr) (union sctp_addr *, - struct sock *sk); - void (*to_sk_daddr) (union sctp_addr *, - struct sock *sk); void (*from_addr_param) (union sctp_addr *, union sctp_addr_param *, __be16 port, int iif); @@ -509,7 +505,9 @@ struct sctp_pf { int (*supported_addrs)(const struct sctp_sock *, __be16 *); struct sock *(*create_accept_sk) (struct sock *sk, struct sctp_association *asoc); - void (*addr_v4map) (struct sctp_sock *, union sctp_addr *); + int (*addr_to_user)(struct sctp_sock *sk, union sctp_addr *addr); + void (*to_sk_saddr)(union sctp_addr *, struct sock *sk); + void (*to_sk_daddr)(union sctp_addr *, struct sock *sk); struct sctp_af *af; }; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 1999592ba88c..0e4198ee2370 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -434,7 +434,7 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk) /* Initialize sk->sk_rcv_saddr from sctp_addr. */ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { - if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) { + if (addr->sa.sa_family == AF_INET) { sk->sk_v6_rcv_saddr.s6_addr32[0] = 0; sk->sk_v6_rcv_saddr.s6_addr32[1] = 0; sk->sk_v6_rcv_saddr.s6_addr32[2] = htonl(0x0000ffff); @@ -448,7 +448,7 @@ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) /* Initialize sk->sk_daddr from sctp_addr. */ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) { - if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) { + if (addr->sa.sa_family == AF_INET) { sk->sk_v6_daddr.s6_addr32[0] = 0; sk->sk_v6_daddr.s6_addr32[1] = 0; sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff); @@ -556,8 +556,6 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) if (IPV6_ADDR_ANY == type) return 1; if (type == IPV6_ADDR_MAPPED) { - if (sp && !sp->v4mapped) - return 0; if (sp && ipv6_only_sock(sctp_opt2sk(sp))) return 0; sctp_v6_map_v4(addr); @@ -587,8 +585,6 @@ static int sctp_v6_addr_valid(union sctp_addr *addr, /* Note: This routine is used in input, so v4-mapped-v6 * are disallowed here when there is no sctp_sock. */ - if (!sp || !sp->v4mapped) - return 0; if (sp && ipv6_only_sock(sctp_opt2sk(sp))) return 0; sctp_v6_map_v4(addr); @@ -675,11 +671,23 @@ out: return newsk; } -/* Map v4 address to mapped v6 address */ -static void sctp_v6_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr) +/* Format a sockaddr for return to user space. This makes sure the return is + * AF_INET or AF_INET6 depending on the SCTP_I_WANT_MAPPED_V4_ADDR option. + */ +static int sctp_v6_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr) { - if (sp->v4mapped && AF_INET == addr->sa.sa_family) - sctp_v4_map_v6(addr); + if (sp->v4mapped) { + if (addr->sa.sa_family == AF_INET) + sctp_v4_map_v6(addr); + } else { + if (addr->sa.sa_family == AF_INET6 && + ipv6_addr_v4mapped(&addr->v6.sin6_addr)) + sctp_v6_map_v4(addr); + } + + if (addr->sa.sa_family == AF_INET) + return sizeof(struct sockaddr_in); + return sizeof(struct sockaddr_in6); } /* Where did this skb come from? */ @@ -706,82 +714,68 @@ static void sctp_v6_ecn_capable(struct sock *sk) inet6_sk(sk)->tclass |= INET_ECN_ECT_0; } -/* Initialize a PF_INET6 socket msg_name. */ -static void sctp_inet6_msgname(char *msgname, int *addr_len) -{ - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)msgname; - sin6->sin6_family = AF_INET6; - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = 0; /*FIXME */ - *addr_len = sizeof(struct sockaddr_in6); -} - /* Initialize a PF_INET msgname from a ulpevent. */ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, char *msgname, int *addrlen) { - struct sockaddr_in6 *sin6, *sin6from; - - if (msgname) { - union sctp_addr *addr; - struct sctp_association *asoc; - - asoc = event->asoc; - sctp_inet6_msgname(msgname, addrlen); - sin6 = (struct sockaddr_in6 *)msgname; - sin6->sin6_port = htons(asoc->peer.port); - addr = &asoc->peer.primary_addr; + union sctp_addr *addr; + struct sctp_association *asoc; + union sctp_addr *paddr; - /* Note: If we go to a common v6 format, this code - * will change. - */ + if (!msgname) + return; - /* Map ipv4 address into v4-mapped-on-v6 address. */ - if (sctp_sk(asoc->base.sk)->v4mapped && - AF_INET == addr->sa.sa_family) { - sctp_v4_map_v6((union sctp_addr *)sin6); - sin6->sin6_addr.s6_addr32[3] = - addr->v4.sin_addr.s_addr; - return; - } + addr = (union sctp_addr *)msgname; + asoc = event->asoc; + paddr = &asoc->peer.primary_addr; - sin6from = &asoc->peer.primary_addr.v6; - sin6->sin6_addr = sin6from->sin6_addr; - if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) - sin6->sin6_scope_id = sin6from->sin6_scope_id; + if (paddr->sa.sa_family == AF_INET) { + addr->v4.sin_family = AF_INET; + addr->v4.sin_port = htons(asoc->peer.port); + addr->v4.sin_addr = paddr->v4.sin_addr; + } else { + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_flowinfo = 0; + if (ipv6_addr_type(&paddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) + addr->v6.sin6_scope_id = paddr->v6.sin6_scope_id; + else + addr->v6.sin6_scope_id = 0; + addr->v6.sin6_port = htons(asoc->peer.port); + addr->v6.sin6_addr = paddr->v6.sin6_addr; } + + *addrlen = sctp_v6_addr_to_user(sctp_sk(asoc->base.sk), addr); } /* Initialize a msg_name from an inbound skb. */ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, int *addr_len) { + union sctp_addr *addr; struct sctphdr *sh; - struct sockaddr_in6 *sin6; - - if (msgname) { - sctp_inet6_msgname(msgname, addr_len); - sin6 = (struct sockaddr_in6 *)msgname; - sh = sctp_hdr(skb); - sin6->sin6_port = sh->source; - - /* Map ipv4 address into v4-mapped-on-v6 address. */ - if (sctp_sk(skb->sk)->v4mapped && - ip_hdr(skb)->version == 4) { - sctp_v4_map_v6((union sctp_addr *)sin6); - sin6->sin6_addr.s6_addr32[3] = ip_hdr(skb)->saddr; - return; - } - /* Otherwise, just copy the v6 address. */ - sin6->sin6_addr = ipv6_hdr(skb)->saddr; - if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) { + if (!msgname) + return; + + addr = (union sctp_addr *)msgname; + sh = sctp_hdr(skb); + + if (ip_hdr(skb)->version == 4) { + addr->v4.sin_family = AF_INET; + addr->v4.sin_port = sh->source; + addr->v4.sin_addr.s_addr = ip_hdr(skb)->saddr; + } else { + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_flowinfo = 0; + addr->v6.sin6_port = sh->source; + addr->v6.sin6_addr = ipv6_hdr(skb)->saddr; + if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) { struct sctp_ulpevent *ev = sctp_skb2event(skb); - sin6->sin6_scope_id = ev->iif; + addr->v6.sin6_scope_id = ev->iif; } } + + *addr_len = sctp_v6_addr_to_user(sctp_sk(skb->sk), addr); } /* Do we support this AF? */ @@ -857,9 +851,6 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr) return 0; } rcu_read_unlock(); - } else if (type == IPV6_ADDR_MAPPED) { - if (!opt->v4mapped) - return 0; } af = opt->pf->af; @@ -914,6 +905,23 @@ static int sctp_inet6_supported_addrs(const struct sctp_sock *opt, return 1; } +/* Handle SCTP_I_WANT_MAPPED_V4_ADDR for getpeername() and getsockname() */ +static int sctp_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer) +{ + int rc; + + rc = inet6_getname(sock, uaddr, uaddr_len, peer); + + if (rc != 0) + return rc; + + *uaddr_len = sctp_v6_addr_to_user(sctp_sk(sock->sk), + (union sctp_addr *)uaddr); + + return rc; +} + static const struct proto_ops inet6_seqpacket_ops = { .family = PF_INET6, .owner = THIS_MODULE, @@ -922,7 +930,7 @@ static const struct proto_ops inet6_seqpacket_ops = { .connect = inet_dgram_connect, .socketpair = sock_no_socketpair, .accept = inet_accept, - .getname = inet6_getname, + .getname = sctp_getname, .poll = sctp_poll, .ioctl = inet6_ioctl, .listen = sctp_inet_listen, @@ -974,8 +982,6 @@ static struct sctp_af sctp_af_inet6 = { .copy_addrlist = sctp_v6_copy_addrlist, .from_skb = sctp_v6_from_skb, .from_sk = sctp_v6_from_sk, - .to_sk_saddr = sctp_v6_to_sk_saddr, - .to_sk_daddr = sctp_v6_to_sk_daddr, .from_addr_param = sctp_v6_from_addr_param, .to_addr_param = sctp_v6_to_addr_param, .cmp_addr = sctp_v6_cmp_addr, @@ -1005,7 +1011,9 @@ static struct sctp_pf sctp_pf_inet6 = { .send_verify = sctp_inet6_send_verify, .supported_addrs = sctp_inet6_supported_addrs, .create_accept_sk = sctp_v6_create_accept_sk, - .addr_v4map = sctp_v6_addr_v4map, + .addr_to_user = sctp_v6_addr_to_user, + .to_sk_saddr = sctp_v6_to_sk_saddr, + .to_sk_daddr = sctp_v6_to_sk_daddr, .af = &sctp_af_inet6, }; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 6789d785e698..6240834f4b95 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -576,10 +576,10 @@ out: return newsk; } -/* Map address, empty for v4 family */ -static void sctp_v4_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr) +static int sctp_v4_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr) { - /* Empty */ + /* No address mapping for V4 sockets */ + return sizeof(struct sockaddr_in); } /* Dump the v4 addr to the seq file. */ @@ -976,7 +976,9 @@ static struct sctp_pf sctp_pf_inet = { .send_verify = sctp_inet_send_verify, .supported_addrs = sctp_inet_supported_addrs, .create_accept_sk = sctp_v4_create_accept_sk, - .addr_v4map = sctp_v4_addr_v4map, + .addr_to_user = sctp_v4_addr_to_user, + .to_sk_saddr = sctp_v4_to_sk_saddr, + .to_sk_daddr = sctp_v4_to_sk_daddr, .af = &sctp_af_inet }; @@ -1047,8 +1049,6 @@ static struct sctp_af sctp_af_inet = { .copy_addrlist = sctp_v4_copy_addrlist, .from_skb = sctp_v4_from_skb, .from_sk = sctp_v4_from_sk, - .to_sk_saddr = sctp_v4_to_sk_saddr, - .to_sk_daddr = sctp_v4_to_sk_daddr, .from_addr_param = sctp_v4_from_addr_param, .to_addr_param = sctp_v4_to_addr_param, .cmp_addr = sctp_v4_cmp_addr, diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 743308f40544..eb71d49e7653 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -254,7 +254,7 @@ static struct sctp_transport *sctp_addr_id2transport(struct sock *sk, if (id_asoc && (id_asoc != addr_asoc)) return NULL; - sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), + sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), (union sctp_addr *)addr); return transport; @@ -396,7 +396,7 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) /* Copy back into socket for getsockname() use. */ if (!ret) { inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num); - af->to_sk_saddr(addr, sk); + sp->pf->to_sk_saddr(addr, sk); } return ret; @@ -1053,7 +1053,6 @@ static int __sctp_connect(struct sock *sk, struct sctp_association *asoc2; struct sctp_transport *transport; union sctp_addr to; - struct sctp_af *af; sctp_scope_t scope; long timeo; int err = 0; @@ -1081,6 +1080,8 @@ static int __sctp_connect(struct sock *sk, /* Walk through the addrs buffer and count the number of addresses. */ addr_buf = kaddrs; while (walk_size < addrs_size) { + struct sctp_af *af; + if (walk_size + sizeof(sa_family_t) > addrs_size) { err = -EINVAL; goto out_free; @@ -1205,8 +1206,7 @@ static int __sctp_connect(struct sock *sk, /* Initialize sk's dport and daddr for getpeername() */ inet_sk(sk)->inet_dport = htons(asoc->peer.port); - af = sctp_get_af_specific(sa_addr->sa.sa_family); - af->to_sk_daddr(sa_addr, sk); + sp->pf->to_sk_daddr(sa_addr, sk); sk->sk_err = 0; /* in-kernel sockets don't generally have a file allocated to them @@ -4255,7 +4255,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, transport->af_specific->sockaddr_len); /* Map ipv4 address into v4-mapped-on-v6 address. */ - sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), + sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk), (union sctp_addr *)&status.sstat_primary.spinfo_address); status.sstat_primary.spinfo_state = transport->state; status.sstat_primary.spinfo_cwnd = transport->cwnd; @@ -4413,8 +4413,8 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optv int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) { struct sctp_association *asoc = sctp_id2assoc(sk, id); + struct sctp_sock *sp = sctp_sk(sk); struct socket *sock; - struct sctp_af *af; int err = 0; if (!asoc) @@ -4436,8 +4436,7 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) /* Make peeled-off sockets more like 1-1 accepted sockets. * Set the daddr and initialize id to something more random */ - af = sctp_get_af_specific(asoc->peer.primary_addr.sa.sa_family); - af->to_sk_daddr(&asoc->peer.primary_addr, sk); + sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sk); /* Populate the fields of the newsk from the oldsk and migrate the * asoc to the newsk. @@ -4821,8 +4820,8 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, list_for_each_entry(from, &asoc->peer.transport_addr_list, transports) { memcpy(&temp, &from->ipaddr, sizeof(temp)); - sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); - addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; + addrlen = sctp_get_pf_specific(sk->sk_family) + ->addr_to_user(sp, &temp); if (space_left < addrlen) return -ENOMEM; if (copy_to_user(to, &temp, addrlen)) @@ -4866,9 +4865,9 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, if (!temp.v4.sin_port) temp.v4.sin_port = htons(port); - sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), - &temp); - addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; + addrlen = sctp_get_pf_specific(sk->sk_family) + ->addr_to_user(sctp_sk(sk), &temp); + if (space_left < addrlen) { cnt = -ENOMEM; break; @@ -4956,8 +4955,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, */ list_for_each_entry(addr, &bp->address_list, list) { memcpy(&temp, &addr->a, sizeof(temp)); - sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); - addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; + addrlen = sctp_get_pf_specific(sk->sk_family) + ->addr_to_user(sp, &temp); if (space_left < addrlen) { err = -ENOMEM; /*fixme: right error?*/ goto out; @@ -5016,7 +5015,7 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, asoc->peer.primary_path->af_specific->sockaddr_len); - sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, + sctp_get_pf_specific(sk->sk_family)->addr_to_user(sp, (union sctp_addr *)&prim.ssp_addr); if (put_user(len, optlen)) diff --git a/net/sctp/transport.c b/net/sctp/transport.c index b10e047bbd15..a0a431824f63 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -289,8 +289,8 @@ void sctp_transport_route(struct sctp_transport *transport, */ if (asoc && (!asoc->peer.primary_path || (transport == asoc->peer.active_path))) - opt->pf->af->to_sk_saddr(&transport->saddr, - asoc->base.sk); + opt->pf->to_sk_saddr(&transport->saddr, + asoc->base.sk); } else transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; } diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index e049298ecfa0..d1e38308f615 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -341,7 +341,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage)); /* Map ipv4 address into v4-mapped-on-v6 address. */ - sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_v4map( + sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_to_user( sctp_sk(asoc->base.sk), (union sctp_addr *)&spc->spc_aaddr); -- cgit v1.2.3 From 7304fe4681634a8e0511a5922c972aa132ffb43d Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Thu, 31 Jul 2014 17:54:32 +0800 Subject: net: fix the counter ICMP_MIB_INERRORS/ICMP6_MIB_INERRORS When dealing with ICMPv[46] Error Message, function icmp_socket_deliver() and icmpv6_notify() do some valid checks on packet's length, but then some protocols check packet's length redaudantly. So remove those duplicated statements, and increase counter ICMP_MIB_INERRORS/ICMP6_MIB_INERRORS in function icmp_socket_deliver() and icmpv6_notify() respectively. In addition, add missed counter in udp6/udplite6 when socket is NULL. Signed-off-by: Duan Jiong Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 4 +++- net/ipv4/tcp_ipv4.c | 5 ----- net/ipv6/icmp.c | 13 ++++++++----- net/ipv6/udp.c | 8 ++++++-- net/sctp/input.c | 5 ----- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 42b7bcf8045b..092400ef88d0 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -663,8 +663,10 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info) /* Checkin full IP header plus 8 bytes of protocol to * avoid additional coding at protocol handlers. */ - if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) + if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) { + ICMP_INC_STATS_BH(dev_net(skb->dev), ICMP_MIB_INERRORS); return; + } raw_icmp_error(skb, protocol, info); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1edc739b9da5..d0ba39537d5c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -344,11 +344,6 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) int err; struct net *net = dev_net(icmp_skb->dev); - if (icmp_skb->len < (iph->ihl << 2) + 8) { - ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); - return; - } - sk = inet_lookup(net, &tcp_hashinfo, iph->daddr, th->dest, iph->saddr, th->source, inet_iif(icmp_skb)); if (!sk) { diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index f6c84a6eb238..06ba3e58320b 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -626,9 +626,10 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info) int inner_offset; __be16 frag_off; u8 nexthdr; + struct net *net = dev_net(skb->dev); if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) - return; + goto out; nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr; if (ipv6_ext_hdr(nexthdr)) { @@ -636,14 +637,14 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info) inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, &frag_off); if (inner_offset<0) - return; + goto out; } else { inner_offset = sizeof(struct ipv6hdr); } /* Checkin header including 8 bytes of inner protocol header. */ if (!pskb_may_pull(skb, inner_offset+8)) - return; + goto out; /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. Without this we will not able f.e. to make source routed @@ -652,13 +653,15 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info) --ANK (980726) */ - rcu_read_lock(); ipprot = rcu_dereference(inet6_protos[nexthdr]); if (ipprot && ipprot->err_handler) ipprot->err_handler(skb, NULL, type, code, inner_offset, info); - rcu_read_unlock(); raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info); + return; + +out: + ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS); } /* diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 5b6091de5868..c6941a1ac977 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -533,11 +533,15 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct udphdr *uh = (struct udphdr*)(skb->data+offset); struct sock *sk; int err; + struct net *net = dev_net(skb->dev); - sk = __udp6_lib_lookup(dev_net(skb->dev), daddr, uh->dest, + sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source, inet6_iif(skb), udptable); - if (sk == NULL) + if (sk == NULL) { + ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev), + ICMP6_MIB_INERRORS); return; + } if (type == ICMPV6_PKT_TOOBIG) { if (!ip6_sk_accept_pmtu(sk)) diff --git a/net/sctp/input.c b/net/sctp/input.c index f2e2cbd2d750..c1b991294516 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -575,11 +575,6 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) int err; struct net *net = dev_net(skb->dev); - if (skb->len < ihlen + 8) { - ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); - return; - } - /* Fix up skb to look at the embedded net header. */ saveip = skb->network_header; savesctp = skb->transport_header; -- cgit v1.2.3 From 74e83b23f2619db057c9e3c3ec4b7090f883bc5e Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 31 Jul 2014 12:17:08 +0200 Subject: netlink: Use PAGE_ALIGNED macro Use PAGE_ALIGNED(...) instead of IS_ALIGNED(..., PAGE_SIZE). Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 1b38f7fe12f1..ce82722a7265 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -374,7 +374,7 @@ static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, if ((int)req->nm_block_size <= 0) return -EINVAL; - if (!IS_ALIGNED(req->nm_block_size, PAGE_SIZE)) + if (!PAGE_ALIGNED(req->nm_block_size)) return -EINVAL; if (req->nm_frame_size < NL_MMAP_HDRLEN) return -EINVAL; -- cgit v1.2.3 From e98d69ba464868a5d6b0b43730658810a29ff825 Mon Sep 17 00:00:00 2001 From: Freddy Xin Date: Thu, 31 Jul 2014 19:06:35 +0800 Subject: AX88179_178A: Add ethtool ops for EEE support Add functions to support ethtool EEE manipulating, and the EEE is disabled in default setting to enhance the compatibility with certain switch. Signed-off-by: Freddy Xin Signed-off-by: David S. Miller --- drivers/net/usb/ax88179_178a.c | 264 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 054e59ca6946..be4275721039 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #define AX88179_PHY_ID 0x03 #define AX_EEPROM_LEN 0x100 @@ -170,8 +172,12 @@ #define GMII_PHY_PAGE_SELECT 0x1f #define GMII_PHY_PGSEL_EXT 0x0007 #define GMII_PHY_PGSEL_PAGE0 0x0000 + #define GMII_PHY_PGSEL_PAGE3 0x0003 + #define GMII_PHY_PGSEL_PAGE5 0x0005 struct ax88179_data { + u8 eee_enabled; + u8 eee_active; u16 rxctl; u16 reserved; }; @@ -373,6 +379,60 @@ static void ax88179_mdio_write(struct net_device *netdev, int phy_id, int loc, ax88179_write_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res); } +static inline int ax88179_phy_mmd_indirect(struct usbnet *dev, u16 prtad, + u16 devad) +{ + u16 tmp16; + int ret; + + tmp16 = devad; + ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_MMD_CTRL, 2, &tmp16); + + tmp16 = prtad; + ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_MMD_DATA, 2, &tmp16); + + tmp16 = devad | MII_MMD_CTRL_NOINCR; + ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_MMD_CTRL, 2, &tmp16); + + return ret; +} + +static int +ax88179_phy_read_mmd_indirect(struct usbnet *dev, u16 prtad, u16 devad) +{ + int ret; + u16 tmp16; + + ax88179_phy_mmd_indirect(dev, prtad, devad); + + ret = ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_MMD_DATA, 2, &tmp16); + if (ret < 0) + return ret; + + return tmp16; +} + +static int +ax88179_phy_write_mmd_indirect(struct usbnet *dev, u16 prtad, u16 devad, + u16 data) +{ + int ret; + + ax88179_phy_mmd_indirect(dev, prtad, devad); + + ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_MMD_DATA, 2, &data); + + if (ret < 0) + return ret; + + return 0; +} + static int ax88179_suspend(struct usb_interface *intf, pm_message_t message) { struct usbnet *dev = usb_get_intfdata(intf); @@ -572,6 +632,185 @@ static int ax88179_set_settings(struct net_device *net, struct ethtool_cmd *cmd) return mii_ethtool_sset(&dev->mii, cmd); } +static int +ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_eee *data) +{ + int val; + + /* Get Supported EEE */ + val = ax88179_phy_read_mmd_indirect(dev, MDIO_PCS_EEE_ABLE, + MDIO_MMD_PCS); + if (val < 0) + return val; + data->supported = mmd_eee_cap_to_ethtool_sup_t(val); + + /* Get advertisement EEE */ + val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_ADV, + MDIO_MMD_AN); + if (val < 0) + return val; + data->advertised = mmd_eee_adv_to_ethtool_adv_t(val); + + /* Get LP advertisement EEE */ + val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_LPABLE, + MDIO_MMD_AN); + if (val < 0) + return val; + data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val); + + return 0; +} + +static int +ax88179_ethtool_set_eee(struct usbnet *dev, struct ethtool_eee *data) +{ + u16 tmp16 = ethtool_adv_to_mmd_eee_adv_t(data->advertised); + + return ax88179_phy_write_mmd_indirect(dev, MDIO_AN_EEE_ADV, + MDIO_MMD_AN, tmp16); +} + +static int ax88179_chk_eee(struct usbnet *dev) +{ + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; + struct ax88179_data *priv = (struct ax88179_data *)dev->data; + + mii_ethtool_gset(&dev->mii, &ecmd); + + if (ecmd.duplex & DUPLEX_FULL) { + int eee_lp, eee_cap, eee_adv; + u32 lp, cap, adv, supported = 0; + + eee_cap = ax88179_phy_read_mmd_indirect(dev, + MDIO_PCS_EEE_ABLE, + MDIO_MMD_PCS); + if (eee_cap < 0) { + priv->eee_active = 0; + return false; + } + + cap = mmd_eee_cap_to_ethtool_sup_t(eee_cap); + if (!cap) { + priv->eee_active = 0; + return false; + } + + eee_lp = ax88179_phy_read_mmd_indirect(dev, + MDIO_AN_EEE_LPABLE, + MDIO_MMD_AN); + if (eee_lp < 0) { + priv->eee_active = 0; + return false; + } + + eee_adv = ax88179_phy_read_mmd_indirect(dev, + MDIO_AN_EEE_ADV, + MDIO_MMD_AN); + + if (eee_adv < 0) { + priv->eee_active = 0; + return false; + } + + adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv); + lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp); + supported = (ecmd.speed == SPEED_1000) ? + SUPPORTED_1000baseT_Full : + SUPPORTED_100baseT_Full; + + if (!(lp & adv & supported)) { + priv->eee_active = 0; + return false; + } + + priv->eee_active = 1; + return true; + } + + priv->eee_active = 0; + return false; +} + +static void ax88179_disable_eee(struct usbnet *dev) +{ + u16 tmp16; + + tmp16 = GMII_PHY_PGSEL_PAGE3; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PAGE_SELECT, 2, &tmp16); + + tmp16 = 0x3246; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_PHYADDR, 2, &tmp16); + + tmp16 = GMII_PHY_PGSEL_PAGE0; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PAGE_SELECT, 2, &tmp16); +} + +static void ax88179_enable_eee(struct usbnet *dev) +{ + u16 tmp16; + + tmp16 = GMII_PHY_PGSEL_PAGE3; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PAGE_SELECT, 2, &tmp16); + + tmp16 = 0x3247; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_PHYADDR, 2, &tmp16); + + tmp16 = GMII_PHY_PGSEL_PAGE5; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PAGE_SELECT, 2, &tmp16); + + tmp16 = 0x0680; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_BMSR, 2, &tmp16); + + tmp16 = GMII_PHY_PGSEL_PAGE0; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PAGE_SELECT, 2, &tmp16); +} + +static int ax88179_get_eee(struct net_device *net, struct ethtool_eee *edata) +{ + struct usbnet *dev = netdev_priv(net); + struct ax88179_data *priv = (struct ax88179_data *)dev->data; + + edata->eee_enabled = priv->eee_enabled; + edata->eee_active = priv->eee_active; + + return ax88179_ethtool_get_eee(dev, edata); +} + +static int ax88179_set_eee(struct net_device *net, struct ethtool_eee *edata) +{ + struct usbnet *dev = netdev_priv(net); + struct ax88179_data *priv = (struct ax88179_data *)dev->data; + int ret = -EOPNOTSUPP; + + priv->eee_enabled = edata->eee_enabled; + if (!priv->eee_enabled) { + ax88179_disable_eee(dev); + } else { + priv->eee_enabled = ax88179_chk_eee(dev); + if (!priv->eee_enabled) + return -EOPNOTSUPP; + + ax88179_enable_eee(dev); + } + + ret = ax88179_ethtool_set_eee(dev, edata); + if (ret) + return ret; + + mii_nway_restart(&dev->mii); + + usbnet_link_change(dev, 0, 0); + + return ret; +} static int ax88179_ioctl(struct net_device *net, struct ifreq *rq, int cmd) { @@ -589,6 +828,8 @@ static const struct ethtool_ops ax88179_ethtool_ops = { .get_eeprom = ax88179_get_eeprom, .get_settings = ax88179_get_settings, .set_settings = ax88179_set_settings, + .get_eee = ax88179_get_eee, + .set_eee = ax88179_set_eee, .nway_reset = usbnet_nway_reset, }; @@ -980,6 +1221,7 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) u16 *tmp16; u8 *tmp; struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data; + struct ethtool_eee eee_data; usbnet_get_endpoints(dev, intf); @@ -1062,6 +1304,15 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) ax88179_led_setting(dev); + ax179_data->eee_enabled = 0; + ax179_data->eee_active = 0; + + ax88179_disable_eee(dev); + + ax88179_ethtool_get_eee(dev, &eee_data); + eee_data.advertised = 0; + ax88179_ethtool_set_eee(dev, &eee_data); + /* Restart autoneg */ mii_nway_restart(&dev->mii); @@ -1261,6 +1512,8 @@ static int ax88179_link_reset(struct usbnet *dev) ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, 2, 2, &mode); + ax179_data->eee_enabled = ax88179_chk_eee(dev); + netif_carrier_on(dev->net); return 0; @@ -1271,6 +1524,8 @@ static int ax88179_reset(struct usbnet *dev) u8 buf[5]; u16 *tmp16; u8 *tmp; + struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data; + struct ethtool_eee eee_data; tmp16 = (u16 *)buf; tmp = (u8 *)buf; @@ -1340,6 +1595,15 @@ static int ax88179_reset(struct usbnet *dev) ax88179_led_setting(dev); + ax179_data->eee_enabled = 0; + ax179_data->eee_active = 0; + + ax88179_disable_eee(dev); + + ax88179_ethtool_get_eee(dev, &eee_data); + eee_data.advertised = 0; + ax88179_ethtool_set_eee(dev, &eee_data); + /* Restart autoneg */ mii_nway_restart(&dev->mii); -- cgit v1.2.3 From 081e83a78db9b0ae1f5eabc2dedecc865f509b98 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Thu, 31 Jul 2014 10:30:25 -0400 Subject: macvlan: Initialize vlan_features to turn on offload support. Macvlan devices do not initialize vlan_features. As a result, any vlan devices configured on top of macvlans perform very poorly. Initialize vlan_features based on the vlan features of the lower-level device. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 958df383068a..ef8a5c20236a 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -646,6 +646,7 @@ static int macvlan_init(struct net_device *dev) (lowerdev->state & MACVLAN_STATE_MASK); dev->features = lowerdev->features & MACVLAN_FEATURES; dev->features |= ALWAYS_ON_FEATURES; + dev->vlan_features = lowerdev->vlan_features & MACVLAN_FEATURES; dev->gso_max_size = lowerdev->gso_max_size; dev->iflink = lowerdev->ifindex; dev->hard_header_len = lowerdev->hard_header_len; -- cgit v1.2.3 From 7bcc6738eef36e7139c4293c321bc43f716e8d85 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 31 Jul 2014 18:30:11 +0300 Subject: ISDN: pcbit: off by one bugs in pcbit_set_msn() 1) We don't allocate enough space for the NUL terminator so we end up corrupting one character beyond the end of the buffer. 2) The "len - 1" should just be "len". The code is trying to copy a word from a buffer up to a comma or the last word in the buffer. Say you have the buffer, "foo,bar,baz", then this code truncates the last letter off each word so you get "fo", "ba", and "ba". You would hope this kind of bug would get noticed in testing... I'm not very familiar with this code and I can't test it, but I think we should copy the final character. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/isdn/pcbit/drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index f02cc506fbfa..4172e22ae7ed 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -1035,14 +1035,14 @@ static void pcbit_set_msn(struct pcbit_dev *dev, char *list) } ptr->next = NULL; - ptr->msn = kmalloc(len, GFP_ATOMIC); + ptr->msn = kmalloc(len + 1, GFP_ATOMIC); if (!ptr->msn) { printk(KERN_WARNING "kmalloc failed\n"); kfree(ptr); return; } - memcpy(ptr->msn, sp, len - 1); + memcpy(ptr->msn, sp, len); ptr->msn[len] = 0; #ifdef DEBUG -- cgit v1.2.3 From db8c8ab61a28d7e3eb86d247b342a853263262c3 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 31 Jul 2014 17:38:22 +0100 Subject: xen-netfront: fix locking in connect error path If no queues could be created when connecting to the backend, one of the error paths would deadlock. Signed-off-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 055222bae6e4..1cc46d00d20a 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -2001,7 +2001,7 @@ abort_transaction_no_dev_fatal: info->queues = NULL; rtnl_lock(); netif_set_real_num_tx_queues(info->netdev, 0); - rtnl_lock(); + rtnl_unlock(); out: return err; } -- cgit v1.2.3 From a5b5dc3ce4df4f05f4d81c7d3c56a7604b242093 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 31 Jul 2014 17:38:23 +0100 Subject: xen-netfront: release per-queue Tx and Rx resource when disconnecting Since netfront may reconnect to a backend with a different number of queues, all per-queue Rx and Tx resources (skbs and grant references) should be freed when disconnecting. Without this fix, the Tx and Rx grant refs are not released and netfront will exhaust them after only a few reconnections. netfront will fail to connect when no free grant references are available. Since all Rx bufs are freed and reallocated instead of reused this will add some additional delay to the reconnection but this is expected to be small compared to the time taken by any backend hotplug scripts etc. Signed-off-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 68 +++++----------------------------------------- 1 file changed, 7 insertions(+), 61 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 1cc46d00d20a..0b133a3d4312 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1196,22 +1196,6 @@ static void xennet_release_rx_bufs(struct netfront_queue *queue) spin_unlock_bh(&queue->rx_lock); } -static void xennet_uninit(struct net_device *dev) -{ - struct netfront_info *np = netdev_priv(dev); - unsigned int num_queues = dev->real_num_tx_queues; - struct netfront_queue *queue; - unsigned int i; - - for (i = 0; i < num_queues; ++i) { - queue = &np->queues[i]; - xennet_release_tx_bufs(queue); - xennet_release_rx_bufs(queue); - gnttab_free_grant_references(queue->gref_tx_head); - gnttab_free_grant_references(queue->gref_rx_head); - } -} - static netdev_features_t xennet_fix_features(struct net_device *dev, netdev_features_t features) { @@ -1313,7 +1297,6 @@ static void xennet_poll_controller(struct net_device *dev) static const struct net_device_ops xennet_netdev_ops = { .ndo_open = xennet_open, - .ndo_uninit = xennet_uninit, .ndo_stop = xennet_close, .ndo_start_xmit = xennet_start_xmit, .ndo_change_mtu = xennet_change_mtu, @@ -1455,6 +1438,11 @@ static void xennet_disconnect_backend(struct netfront_info *info) napi_synchronize(&queue->napi); + xennet_release_tx_bufs(queue); + xennet_release_rx_bufs(queue); + gnttab_free_grant_references(queue->gref_tx_head); + gnttab_free_grant_references(queue->gref_rx_head); + /* End access and free the pages */ xennet_end_access(queue->tx_ring_ref, queue->tx.sring); xennet_end_access(queue->rx_ring_ref, queue->rx.sring); @@ -2010,10 +1998,7 @@ static int xennet_connect(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); unsigned int num_queues = 0; - int i, requeue_idx, err; - struct sk_buff *skb; - grant_ref_t ref; - struct xen_netif_rx_request *req; + int err; unsigned int feature_rx_copy; unsigned int j = 0; struct netfront_queue *queue = NULL; @@ -2040,47 +2025,8 @@ static int xennet_connect(struct net_device *dev) netdev_update_features(dev); rtnl_unlock(); - /* By now, the queue structures have been set up */ - for (j = 0; j < num_queues; ++j) { - queue = &np->queues[j]; - - /* Step 1: Discard all pending TX packet fragments. */ - spin_lock_irq(&queue->tx_lock); - xennet_release_tx_bufs(queue); - spin_unlock_irq(&queue->tx_lock); - - /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ - spin_lock_bh(&queue->rx_lock); - - for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { - skb_frag_t *frag; - const struct page *page; - if (!queue->rx_skbs[i]) - continue; - - skb = queue->rx_skbs[requeue_idx] = xennet_get_rx_skb(queue, i); - ref = queue->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(queue, i); - req = RING_GET_REQUEST(&queue->rx, requeue_idx); - - frag = &skb_shinfo(skb)->frags[0]; - page = skb_frag_page(frag); - gnttab_grant_foreign_access_ref( - ref, queue->info->xbdev->otherend_id, - pfn_to_mfn(page_to_pfn(page)), - 0); - req->gref = ref; - req->id = requeue_idx; - - requeue_idx++; - } - - queue->rx.req_prod_pvt = requeue_idx; - - spin_unlock_bh(&queue->rx_lock); - } - /* - * Step 3: All public and private state should now be sane. Get + * All public and private state should now be sane. Get * ready to start sending and receiving packets and give the driver * domain a kick because we've probably just requeued some * packets. -- cgit v1.2.3 From 69cb85242f4ff1cbbac5a45c05223600084760e8 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 31 Jul 2014 17:38:24 +0100 Subject: xen-netfront: print correct number of queues When less than the requested number of queues could be created, include the actual number in the warning (instead of the requested number). Signed-off-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 0b133a3d4312..28204bc4f369 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1815,8 +1815,8 @@ static int xennet_create_queues(struct netfront_info *info, ret = xennet_init_queue(queue); if (ret < 0) { - dev_warn(&info->netdev->dev, "only created %d queues\n", - num_queues); + dev_warn(&info->netdev->dev, + "only created %d queues\n", i); num_queues = i; break; } -- cgit v1.2.3 From fcdfe3a7fa4cb74391d42b6a26dc07c20dab1d82 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Thu, 31 Jul 2014 10:33:06 -0400 Subject: net: Correctly set segment mac_len in skb_segment(). When performing segmentation, the mac_len value is copied right out of the original skb. However, this value is not always set correctly (like when the packet is VLAN-tagged) and we'll end up copying a bad value. One way to demonstrate this is to configure a VM which tags packets internally and turn off VLAN acceleration on the forwarding bridge port. The packets show up corrupt like this: 16:18:24.985548 52:54:00:ab:be:25 > 52:54:00:26:ce:a3, ethertype 802.1Q (0x8100), length 1518: vlan 100, p 0, ethertype 0x05e0, 0x0000: 8cdb 1c7c 8cdb 0064 4006 b59d 0a00 6402 ...|...d@.....d. 0x0010: 0a00 6401 9e0d b441 0a5e 64ec 0330 14fa ..d....A.^d..0.. 0x0020: 29e3 01c9 f871 0000 0101 080a 000a e833)....q.........3 0x0030: 000f 8c75 6e65 7470 6572 6600 6e65 7470 ...unetperf.netp 0x0040: 6572 6600 6e65 7470 6572 6600 6e65 7470 erf.netperf.netp 0x0050: 6572 6600 6e65 7470 6572 6600 6e65 7470 erf.netperf.netp 0x0060: 6572 6600 6e65 7470 6572 6600 6e65 7470 erf.netperf.netp ... This also leads to awful throughput as GSO packets are dropped and cause retransmissions. The solution is to set the mac_len using the values already available in then new skb. We've already adjusted all of the header offset, so we might as well correctly figure out the mac_len using skb_reset_mac_len(). After this change, packets are segmented correctly and performance is restored. CC: Eric Dumazet Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/core/skbuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c1a33033cbe2..58ff88edbefd 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2976,9 +2976,9 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, tail = nskb; __copy_skb_header(nskb, head_skb); - nskb->mac_len = head_skb->mac_len; skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom); + skb_reset_mac_len(nskb); skb_copy_from_linear_data_offset(head_skb, -tnl_hlen, nskb->data - tnl_hlen, -- cgit v1.2.3 From 4330487acfff0cf1d7b14d238583a182e0a444bb Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Fri, 1 Aug 2014 09:52:58 +0800 Subject: net: use inet6_iif instead of IP6CB()->iif Signed-off-by: Duan Jiong Signed-off-by: David S. Miller --- net/ipv4/ping.c | 2 +- net/ipv6/raw.c | 8 ++++---- net/ipv6/udp.c | 2 +- net/l2tp/l2tp_ip6.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 044a0ddf6a79..a3c59a077a5f 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -911,7 +911,7 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, sin6->sin6_flowinfo = ip6_flowinfo(ip6); sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, - IP6CB(skb)->iif); + inet6_iif(skb)); *addr_len = sizeof(*sin6); } diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index dee80fb1aa86..39d44226e402 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -176,7 +176,7 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) goto out; net = dev_net(skb->dev); - sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); + sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, inet6_iif(skb)); while (sk) { int filtered; @@ -220,7 +220,7 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) } } sk = __raw_v6_lookup(net, sk_next(sk), nexthdr, daddr, saddr, - IP6CB(skb)->iif); + inet6_iif(skb)); } out: read_unlock(&raw_v6_hashinfo.lock); @@ -375,7 +375,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, net = dev_net(skb->dev); while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr, - IP6CB(skb)->iif))) { + inet6_iif(skb)))) { rawv6_err(sk, skb, NULL, type, code, inner_offset, info); sk = sk_next(sk); @@ -506,7 +506,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, sin6->sin6_addr = ipv6_hdr(skb)->saddr; sin6->sin6_flowinfo = 0; sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, - IP6CB(skb)->iif); + inet6_iif(skb)); *addr_len = sizeof(*sin6); } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index c6941a1ac977..4836af8f582d 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -472,7 +472,7 @@ try_again: sin6->sin6_addr = ipv6_hdr(skb)->saddr; sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, - IP6CB(skb)->iif); + inet6_iif(skb)); } *addr_len = sizeof(*sin6); } diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index f3f98a156cee..0edb263cc002 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -687,7 +687,7 @@ static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk, lsa->l2tp_scope_id = 0; lsa->l2tp_conn_id = 0; if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL) - lsa->l2tp_scope_id = IP6CB(skb)->iif; + lsa->l2tp_scope_id = inet6_iif(skb); } if (np->rxopt.all) -- cgit v1.2.3 From 0dc1362562a2e8b82a6be8d3ae307a234f28f9bc Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Fri, 1 Aug 2014 17:25:38 +0200 Subject: netfilter: nf_tables: Avoid duplicate call to nft_data_uninit() for same key nft_del_setelem() currently calls nft_data_uninit() twice on the same key. Once to release the key which is guaranteed to be NFT_DATA_VALUE and a second time in the error path to which it falls through. The second call has been harmless so far though because the type passed is always NFT_DATA_VALUE which is currently a no-op. Signed-off-by: Thomas Graf Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 8746ff9a8357..b35ba833e13c 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -3218,6 +3218,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, if (set->flags & NFT_SET_MAP) nft_data_uninit(&elem.data, set->dtype); + return 0; err2: nft_data_uninit(&elem.key, desc.type); err1: -- cgit v1.2.3 From 278571baca2aecf5fb5cb5c8b002dbfa0a6c524c Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Wed, 30 Jul 2014 20:34:12 -0700 Subject: net: filter: simplify socket charging attaching bpf program to a socket involves multiple socket memory arithmetic, since size of 'sk_filter' is changing when classic BPF is converted to eBPF. Also common path of program creation has to deal with two ways of freeing the memory. Simplify the code by delaying socket charging until program is ready and its size is known Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/filter.h | 2 +- net/core/filter.c | 87 +++++++++++++++++++++----------------------------- net/core/sock.c | 9 ++++-- 3 files changed, 45 insertions(+), 53 deletions(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index 20dd50ef7271..00640edc166f 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -366,7 +366,7 @@ int sk_chk_filter(const struct sock_filter *filter, unsigned int flen); int sk_get_filter(struct sock *sk, struct sock_filter __user *filter, unsigned int len); -void sk_filter_charge(struct sock *sk, struct sk_filter *fp); +bool sk_filter_charge(struct sock *sk, struct sk_filter *fp); void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp); u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); diff --git a/net/core/filter.c b/net/core/filter.c index 42c1944b0c63..5a6aeb1d40b8 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -872,41 +872,30 @@ static void sk_filter_release(struct sk_filter *fp) void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp) { - atomic_sub(sk_filter_size(fp->len), &sk->sk_omem_alloc); - sk_filter_release(fp); -} + u32 filter_size = sk_filter_size(fp->len); -void sk_filter_charge(struct sock *sk, struct sk_filter *fp) -{ - atomic_inc(&fp->refcnt); - atomic_add(sk_filter_size(fp->len), &sk->sk_omem_alloc); + atomic_sub(filter_size, &sk->sk_omem_alloc); + sk_filter_release(fp); } -static struct sk_filter *__sk_migrate_realloc(struct sk_filter *fp, - struct sock *sk, - unsigned int len) +/* try to charge the socket memory if there is space available + * return true on success + */ +bool sk_filter_charge(struct sock *sk, struct sk_filter *fp) { - struct sk_filter *fp_new; - - if (sk == NULL) - return krealloc(fp, len, GFP_KERNEL); - - fp_new = sock_kmalloc(sk, len, GFP_KERNEL); - if (fp_new) { - *fp_new = *fp; - /* As we're keeping orig_prog in fp_new along, - * we need to make sure we're not evicting it - * from the old fp. - */ - fp->orig_prog = NULL; - sk_filter_uncharge(sk, fp); + u32 filter_size = sk_filter_size(fp->len); + + /* same check as in sock_kmalloc() */ + if (filter_size <= sysctl_optmem_max && + atomic_read(&sk->sk_omem_alloc) + filter_size < sysctl_optmem_max) { + atomic_inc(&fp->refcnt); + atomic_add(filter_size, &sk->sk_omem_alloc); + return true; } - - return fp_new; + return false; } -static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp, - struct sock *sk) +static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp) { struct sock_filter *old_prog; struct sk_filter *old_fp; @@ -938,7 +927,7 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp, /* Expand fp for appending the new filter representation. */ old_fp = fp; - fp = __sk_migrate_realloc(old_fp, sk, sk_filter_size(new_len)); + fp = krealloc(old_fp, sk_filter_size(new_len), GFP_KERNEL); if (!fp) { /* The old_fp is still around in case we couldn't * allocate new memory, so uncharge on that one. @@ -956,7 +945,7 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp, /* 2nd sk_convert_filter() can fail only if it fails * to allocate memory, remapping must succeed. Note, * that at this time old_fp has already been released - * by __sk_migrate_realloc(). + * by krealloc(). */ goto out_err_free; @@ -968,16 +957,11 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp, out_err_free: kfree(old_prog); out_err: - /* Rollback filter setup. */ - if (sk != NULL) - sk_filter_uncharge(sk, fp); - else - kfree(fp); + __sk_filter_release(fp); return ERR_PTR(err); } -static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp, - struct sock *sk) +static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp) { int err; @@ -986,10 +970,7 @@ static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp, err = sk_chk_filter(fp->insns, fp->len); if (err) { - if (sk != NULL) - sk_filter_uncharge(sk, fp); - else - kfree(fp); + __sk_filter_release(fp); return ERR_PTR(err); } @@ -1002,7 +983,7 @@ static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp, * internal BPF translation for the optimized interpreter. */ if (!fp->jited) - fp = __sk_migrate_filter(fp, sk); + fp = __sk_migrate_filter(fp); return fp; } @@ -1041,10 +1022,10 @@ int sk_unattached_filter_create(struct sk_filter **pfp, */ fp->orig_prog = NULL; - /* __sk_prepare_filter() already takes care of uncharging + /* __sk_prepare_filter() already takes care of freeing * memory in case something goes wrong. */ - fp = __sk_prepare_filter(fp, NULL); + fp = __sk_prepare_filter(fp); if (IS_ERR(fp)) return PTR_ERR(fp); @@ -1083,31 +1064,37 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) if (fprog->filter == NULL) return -EINVAL; - fp = sock_kmalloc(sk, sk_fsize, GFP_KERNEL); + fp = kmalloc(sk_fsize, GFP_KERNEL); if (!fp) return -ENOMEM; if (copy_from_user(fp->insns, fprog->filter, fsize)) { - sock_kfree_s(sk, fp, sk_fsize); + kfree(fp); return -EFAULT; } - atomic_set(&fp->refcnt, 1); fp->len = fprog->len; err = sk_store_orig_filter(fp, fprog); if (err) { - sk_filter_uncharge(sk, fp); + kfree(fp); return -ENOMEM; } - /* __sk_prepare_filter() already takes care of uncharging + /* __sk_prepare_filter() already takes care of freeing * memory in case something goes wrong. */ - fp = __sk_prepare_filter(fp, sk); + fp = __sk_prepare_filter(fp); if (IS_ERR(fp)) return PTR_ERR(fp); + atomic_set(&fp->refcnt, 0); + + if (!sk_filter_charge(sk, fp)) { + __sk_filter_release(fp); + return -ENOMEM; + } + old_fp = rcu_dereference_protected(sk->sk_filter, sock_owned_by_user(sk)); rcu_assign_pointer(sk->sk_filter, fp); diff --git a/net/core/sock.c b/net/core/sock.c index 134291d73fcd..a741163568fa 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1474,6 +1474,7 @@ static void sk_update_clone(const struct sock *sk, struct sock *newsk) struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) { struct sock *newsk; + bool is_charged = true; newsk = sk_prot_alloc(sk->sk_prot, priority, sk->sk_family); if (newsk != NULL) { @@ -1518,9 +1519,13 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) filter = rcu_dereference_protected(newsk->sk_filter, 1); if (filter != NULL) - sk_filter_charge(newsk, filter); + /* though it's an empty new sock, the charging may fail + * if sysctl_optmem_max was changed between creation of + * original socket and cloning + */ + is_charged = sk_filter_charge(newsk, filter); - if (unlikely(xfrm_sk_clone_policy(newsk))) { + if (unlikely(!is_charged || xfrm_sk_clone_policy(newsk))) { /* It is still raw copy of parent, so invalidate * destructor and make plain sk_free() */ newsk->sk_destruct = NULL; -- cgit v1.2.3 From 009937e78a45553a86d26654f192b2fd9ebe289d Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Wed, 30 Jul 2014 20:34:13 -0700 Subject: net: filter: rename sk_filter_proglen -> bpf_classic_proglen trivial rename to better match semantics of macro Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/filter.h | 3 +-- net/core/filter.c | 8 ++++---- net/core/sock_diag.c | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index 00640edc166f..3769341a745d 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -344,8 +344,7 @@ static inline unsigned int sk_filter_size(unsigned int proglen) offsetof(struct sk_filter, insns[proglen])); } -#define sk_filter_proglen(fprog) \ - (fprog->len * sizeof(fprog->filter[0])) +#define bpf_classic_proglen(fprog) (fprog->len * sizeof(fprog->filter[0])) int sk_filter(struct sock *sk, struct sk_buff *skb); diff --git a/net/core/filter.c b/net/core/filter.c index 5a6aeb1d40b8..d6cb287e4f59 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -813,7 +813,7 @@ EXPORT_SYMBOL(sk_chk_filter); static int sk_store_orig_filter(struct sk_filter *fp, const struct sock_fprog *fprog) { - unsigned int fsize = sk_filter_proglen(fprog); + unsigned int fsize = bpf_classic_proglen(fprog); struct sock_fprog_kern *fkprog; fp->orig_prog = kmalloc(sizeof(*fkprog), GFP_KERNEL); @@ -1001,7 +1001,7 @@ static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp) int sk_unattached_filter_create(struct sk_filter **pfp, struct sock_fprog_kern *fprog) { - unsigned int fsize = sk_filter_proglen(fprog); + unsigned int fsize = bpf_classic_proglen(fprog); struct sk_filter *fp; /* Make sure new filter is there and in the right amounts. */ @@ -1053,7 +1053,7 @@ EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy); int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) { struct sk_filter *fp, *old_fp; - unsigned int fsize = sk_filter_proglen(fprog); + unsigned int fsize = bpf_classic_proglen(fprog); unsigned int sk_fsize = sk_filter_size(fprog->len); int err; @@ -1154,7 +1154,7 @@ int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, goto out; ret = -EFAULT; - if (copy_to_user(ubuf, fprog->filter, sk_filter_proglen(fprog))) + if (copy_to_user(ubuf, fprog->filter, bpf_classic_proglen(fprog))) goto out; /* Instead of bytes, the API requests to return the number diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index a4216a4c9572..57d922320c59 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -69,7 +69,7 @@ int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk, goto out; fprog = filter->orig_prog; - flen = sk_filter_proglen(fprog); + flen = bpf_classic_proglen(fprog); attr = nla_reserve(skb, attrtype, flen); if (attr == NULL) { -- cgit v1.2.3 From 4df95ff488eb796aab9566652c250330179def17 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Wed, 30 Jul 2014 20:34:14 -0700 Subject: net: filter: rename sk_chk_filter() -> bpf_check_classic() trivial rename to indicate that this functions performs classic BPF checking Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- Documentation/networking/filter.txt | 2 +- include/linux/filter.h | 2 +- kernel/bpf/core.c | 2 +- kernel/seccomp.c | 4 ++-- net/core/filter.c | 10 +++++----- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt index ee78eba78a9d..712068be8171 100644 --- a/Documentation/networking/filter.txt +++ b/Documentation/networking/filter.txt @@ -591,7 +591,7 @@ sk_unattached_filter_destroy() for destroying it. The macro SK_RUN_FILTER(filter, ctx) transparently invokes eBPF interpreter or JITed code to run the filter. 'filter' is a pointer to struct sk_filter that we got from sk_unattached_filter_create(), and 'ctx' the given context (e.g. -skb pointer). All constraints and restrictions from sk_chk_filter() apply +skb pointer). All constraints and restrictions from bpf_check_classic() apply before a conversion to the new layout is being done behind the scenes! Currently, the classic BPF format is being used for JITing on most of the diff --git a/include/linux/filter.h b/include/linux/filter.h index 3769341a745d..c4d0be4c5e75 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -361,7 +361,7 @@ void sk_unattached_filter_destroy(struct sk_filter *fp); int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); int sk_detach_filter(struct sock *sk); -int sk_chk_filter(const struct sock_filter *filter, unsigned int flen); +int bpf_check_classic(const struct sock_filter *filter, unsigned int flen); int sk_get_filter(struct sock *sk, struct sock_filter __user *filter, unsigned int len); diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 265a02cc822d..b479807ec383 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -18,7 +18,7 @@ * 2 of the License, or (at your option) any later version. * * Andi Kleen - Fix a few bad bugs and races. - * Kris Katterjohn - Added many additional checks in sk_chk_filter() + * Kris Katterjohn - Added many additional checks in bpf_check_classic() */ #include #include diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 565743db5384..f4a77d23f209 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -87,7 +87,7 @@ static void populate_seccomp_data(struct seccomp_data *sd) * @filter: filter to verify * @flen: length of filter * - * Takes a previously checked filter (by sk_chk_filter) and + * Takes a previously checked filter (by bpf_check_classic) and * redirects all filter code that loads struct sk_buff data * and related data through seccomp_bpf_load. It also * enforces length and alignment checking of those loads. @@ -239,7 +239,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) goto free_prog; /* Check and rewrite the fprog via the skb checker */ - ret = sk_chk_filter(fp, fprog->len); + ret = bpf_check_classic(fp, fprog->len); if (ret) goto free_prog; diff --git a/net/core/filter.c b/net/core/filter.c index d6cb287e4f59..5740ea08a3ad 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -18,7 +18,7 @@ * 2 of the License, or (at your option) any later version. * * Andi Kleen - Fix a few bad bugs and races. - * Kris Katterjohn - Added many additional checks in sk_chk_filter() + * Kris Katterjohn - Added many additional checks in bpf_check_classic() */ #include @@ -721,7 +721,7 @@ static bool chk_code_allowed(u16 code_to_probe) } /** - * sk_chk_filter - verify socket filter code + * bpf_check_classic - verify socket filter code * @filter: filter to verify * @flen: length of filter * @@ -734,7 +734,7 @@ static bool chk_code_allowed(u16 code_to_probe) * * Returns 0 if the rule set is legal or -EINVAL if not. */ -int sk_chk_filter(const struct sock_filter *filter, unsigned int flen) +int bpf_check_classic(const struct sock_filter *filter, unsigned int flen) { bool anc_found; int pc; @@ -808,7 +808,7 @@ int sk_chk_filter(const struct sock_filter *filter, unsigned int flen) return -EINVAL; } -EXPORT_SYMBOL(sk_chk_filter); +EXPORT_SYMBOL(bpf_check_classic); static int sk_store_orig_filter(struct sk_filter *fp, const struct sock_fprog *fprog) @@ -968,7 +968,7 @@ static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp) fp->bpf_func = NULL; fp->jited = 0; - err = sk_chk_filter(fp->insns, fp->len); + err = bpf_check_classic(fp->insns, fp->len); if (err) { __sk_filter_release(fp); return ERR_PTR(err); -- cgit v1.2.3 From 8fb575ca396bc31d9fa99c26336e2432b41d1bfc Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Wed, 30 Jul 2014 20:34:15 -0700 Subject: net: filter: rename sk_convert_filter() -> bpf_convert_filter() to indicate that this function is converting classic BPF into eBPF and not related to sockets Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- arch/x86/net/bpf_jit_comp.c | 2 +- include/linux/filter.h | 4 ++-- kernel/bpf/core.c | 2 +- kernel/seccomp.c | 4 ++-- net/core/filter.c | 16 ++++++++-------- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 71737a83f022..e2ecc1380b3d 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -235,7 +235,7 @@ static int do_jit(struct sk_filter *bpf_prog, int *addrs, u8 *image, /* mov qword ptr [rbp-X],rbx */ EMIT3_off32(0x48, 0x89, 0x9D, -stacksize); - /* sk_convert_filter() maps classic BPF register X to R7 and uses R8 + /* bpf_convert_filter() maps classic BPF register X to R7 and uses R8 * as temporary, so all tcpdump filters need to spill/fill R7(r13) and * R8(r14). R9(r15) spill could be made conditional, but there is only * one 'bpf_error' return path out of helper functions inside bpf_jit.S diff --git a/include/linux/filter.h b/include/linux/filter.h index c4d0be4c5e75..7cb9b40e9a2f 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -351,8 +351,8 @@ int sk_filter(struct sock *sk, struct sk_buff *skb); void sk_filter_select_runtime(struct sk_filter *fp); void sk_filter_free(struct sk_filter *fp); -int sk_convert_filter(struct sock_filter *prog, int len, - struct bpf_insn *new_prog, int *new_len); +int bpf_convert_filter(struct sock_filter *prog, int len, + struct bpf_insn *new_prog, int *new_len); int sk_unattached_filter_create(struct sk_filter **pfp, struct sock_fprog_kern *fprog); diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index b479807ec383..188ac5ba3900 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -446,7 +446,7 @@ load_word: /* BPF_LD + BPD_ABS and BPF_LD + BPF_IND insns are * only appearing in the programs where ctx == * skb. All programs keep 'ctx' in regs[BPF_REG_CTX] - * == BPF_R6, sk_convert_filter() saves it in BPF_R6, + * == BPF_R6, bpf_convert_filter() saves it in BPF_R6, * internal BPF verifier will check that BPF_R6 == * ctx. * diff --git a/kernel/seccomp.c b/kernel/seccomp.c index f4a77d23f209..33a3a97e2b58 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -249,7 +249,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) goto free_prog; /* Convert 'sock_filter' insns to 'bpf_insn' insns */ - ret = sk_convert_filter(fp, fprog->len, NULL, &new_len); + ret = bpf_convert_filter(fp, fprog->len, NULL, &new_len); if (ret) goto free_prog; @@ -265,7 +265,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) if (!filter->prog) goto free_filter; - ret = sk_convert_filter(fp, fprog->len, filter->prog->insnsi, &new_len); + ret = bpf_convert_filter(fp, fprog->len, filter->prog->insnsi, &new_len); if (ret) goto free_filter_prog; kfree(fp); diff --git a/net/core/filter.c b/net/core/filter.c index 5740ea08a3ad..6ac901613bee 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -312,7 +312,7 @@ static bool convert_bpf_extensions(struct sock_filter *fp, } /** - * sk_convert_filter - convert filter program + * bpf_convert_filter - convert filter program * @prog: the user passed filter program * @len: the length of the user passed filter program * @new_prog: buffer where converted program will be stored @@ -322,12 +322,12 @@ static bool convert_bpf_extensions(struct sock_filter *fp, * Conversion workflow: * * 1) First pass for calculating the new program length: - * sk_convert_filter(old_prog, old_len, NULL, &new_len) + * bpf_convert_filter(old_prog, old_len, NULL, &new_len) * * 2) 2nd pass to remap in two passes: 1st pass finds new * jump offsets, 2nd pass remapping: * new_prog = kmalloc(sizeof(struct bpf_insn) * new_len); - * sk_convert_filter(old_prog, old_len, new_prog, &new_len); + * bpf_convert_filter(old_prog, old_len, new_prog, &new_len); * * User BPF's register A is mapped to our BPF register 6, user BPF * register X is mapped to BPF register 7; frame pointer is always @@ -335,8 +335,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp, * for socket filters: ctx == 'struct sk_buff *', for seccomp: * ctx == 'struct seccomp_data *'. */ -int sk_convert_filter(struct sock_filter *prog, int len, - struct bpf_insn *new_prog, int *new_len) +int bpf_convert_filter(struct sock_filter *prog, int len, + struct bpf_insn *new_prog, int *new_len) { int new_flen = 0, pass = 0, target, i; struct bpf_insn *new_insn; @@ -921,7 +921,7 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp) } /* 1st pass: calculate the new program length. */ - err = sk_convert_filter(old_prog, old_len, NULL, &new_len); + err = bpf_convert_filter(old_prog, old_len, NULL, &new_len); if (err) goto out_err_free; @@ -940,9 +940,9 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp) fp->len = new_len; /* 2nd pass: remap sock_filter insns into bpf_insn insns. */ - err = sk_convert_filter(old_prog, old_len, fp->insnsi, &new_len); + err = bpf_convert_filter(old_prog, old_len, fp->insnsi, &new_len); if (err) - /* 2nd sk_convert_filter() can fail only if it fails + /* 2nd bpf_convert_filter() can fail only if it fails * to allocate memory, remapping must succeed. Note, * that at this time old_fp has already been released * by krealloc(). -- cgit v1.2.3 From 7ae457c1e5b45a1b826fad9d62b32191d2bdcfdb Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Wed, 30 Jul 2014 20:34:16 -0700 Subject: net: filter: split 'struct sk_filter' into socket and bpf parts clean up names related to socket filtering and bpf in the following way: - everything that deals with sockets keeps 'sk_*' prefix - everything that is pure BPF is changed to 'bpf_*' prefix split 'struct sk_filter' into struct sk_filter { atomic_t refcnt; struct rcu_head rcu; struct bpf_prog *prog; }; and struct bpf_prog { u32 jited:1, len:31; struct sock_fprog_kern *orig_prog; unsigned int (*bpf_func)(const struct sk_buff *skb, const struct bpf_insn *filter); union { struct sock_filter insns[0]; struct bpf_insn insnsi[0]; struct work_struct work; }; }; so that 'struct bpf_prog' can be used independent of sockets and cleans up 'unattached' bpf use cases split SK_RUN_FILTER macro into: SK_RUN_FILTER to be used with 'struct sk_filter *' and BPF_PROG_RUN to be used with 'struct bpf_prog *' __sk_filter_release(struct sk_filter *) gains __bpf_prog_release(struct bpf_prog *) helper function also perform related renames for the functions that work with 'struct bpf_prog *', since they're on the same lines: sk_filter_size -> bpf_prog_size sk_filter_select_runtime -> bpf_prog_select_runtime sk_filter_free -> bpf_prog_free sk_unattached_filter_create -> bpf_prog_create sk_unattached_filter_destroy -> bpf_prog_destroy sk_store_orig_filter -> bpf_prog_store_orig_filter sk_release_orig_filter -> bpf_release_orig_filter __sk_migrate_filter -> bpf_migrate_filter __sk_prepare_filter -> bpf_prepare_filter API for attaching classic BPF to a socket stays the same: sk_attach_filter(prog, struct sock *)/sk_detach_filter(struct sock *) and SK_RUN_FILTER(struct sk_filter *, ctx) to execute a program which is used by sockets, tun, af_packet API for 'unattached' BPF programs becomes: bpf_prog_create(struct bpf_prog **)/bpf_prog_destroy(struct bpf_prog *) and BPF_PROG_RUN(struct bpf_prog *, ctx) to execute a program which is used by isdn, ppp, team, seccomp, ptp, xt_bpf, cls_bpf, test_bpf Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- Documentation/networking/filter.txt | 10 ++-- arch/arm/net/bpf_jit_32.c | 8 +-- arch/mips/net/bpf_jit.c | 8 +-- arch/powerpc/net/bpf_jit_comp.c | 8 +-- arch/s390/net/bpf_jit_comp.c | 4 +- arch/sparc/net/bpf_jit_comp.c | 4 +- arch/x86/net/bpf_jit_comp.c | 12 ++--- drivers/isdn/i4l/isdn_ppp.c | 26 +++++---- drivers/net/ppp/ppp_generic.c | 28 +++++----- drivers/net/team/team_mode_loadbalance.c | 14 ++--- include/linux/filter.h | 40 ++++++++------ include/linux/isdn_ppp.h | 4 +- include/uapi/linux/netfilter/xt_bpf.h | 4 +- kernel/bpf/core.c | 30 +++++------ kernel/seccomp.c | 10 ++-- lib/test_bpf.c | 24 ++++----- net/core/filter.c | 92 ++++++++++++++++++-------------- net/core/ptp_classifier.c | 6 +-- net/core/sock_diag.c | 2 +- net/netfilter/xt_bpf.c | 6 +-- net/sched/cls_bpf.c | 12 ++--- 21 files changed, 183 insertions(+), 169 deletions(-) diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt index 712068be8171..c48a9704bda8 100644 --- a/Documentation/networking/filter.txt +++ b/Documentation/networking/filter.txt @@ -586,11 +586,11 @@ team driver's classifier for its load-balancing mode, netfilter's xt_bpf extension, PTP dissector/classifier, and much more. They are all internally converted by the kernel into the new instruction set representation and run in the eBPF interpreter. For in-kernel handlers, this all works transparently -by using sk_unattached_filter_create() for setting up the filter, resp. -sk_unattached_filter_destroy() for destroying it. The macro -SK_RUN_FILTER(filter, ctx) transparently invokes eBPF interpreter or JITed -code to run the filter. 'filter' is a pointer to struct sk_filter that we -got from sk_unattached_filter_create(), and 'ctx' the given context (e.g. +by using bpf_prog_create() for setting up the filter, resp. +bpf_prog_destroy() for destroying it. The macro +BPF_PROG_RUN(filter, ctx) transparently invokes eBPF interpreter or JITed +code to run the filter. 'filter' is a pointer to struct bpf_prog that we +got from bpf_prog_create(), and 'ctx' the given context (e.g. skb pointer). All constraints and restrictions from bpf_check_classic() apply before a conversion to the new layout is being done behind the scenes! diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index fb5503ce016f..a37b989a2f91 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -56,7 +56,7 @@ #define FLAG_NEED_X_RESET (1 << 0) struct jit_ctx { - const struct sk_filter *skf; + const struct bpf_prog *skf; unsigned idx; unsigned prologue_bytes; int ret0_fp_idx; @@ -465,7 +465,7 @@ static inline void update_on_xread(struct jit_ctx *ctx) static int build_body(struct jit_ctx *ctx) { void *load_func[] = {jit_get_skb_b, jit_get_skb_h, jit_get_skb_w}; - const struct sk_filter *prog = ctx->skf; + const struct bpf_prog *prog = ctx->skf; const struct sock_filter *inst; unsigned i, load_order, off, condt; int imm12; @@ -857,7 +857,7 @@ b_epilogue: } -void bpf_jit_compile(struct sk_filter *fp) +void bpf_jit_compile(struct bpf_prog *fp) { struct jit_ctx ctx; unsigned tmp_idx; @@ -926,7 +926,7 @@ out: return; } -void bpf_jit_free(struct sk_filter *fp) +void bpf_jit_free(struct bpf_prog *fp) { if (fp->jited) module_free(NULL, fp->bpf_func); diff --git a/arch/mips/net/bpf_jit.c b/arch/mips/net/bpf_jit.c index b87390a56a2f..05a56619ece2 100644 --- a/arch/mips/net/bpf_jit.c +++ b/arch/mips/net/bpf_jit.c @@ -131,7 +131,7 @@ * @target: Memory location for the compiled filter */ struct jit_ctx { - const struct sk_filter *skf; + const struct bpf_prog *skf; unsigned int prologue_bytes; u32 idx; u32 flags; @@ -789,7 +789,7 @@ static int pkt_type_offset(void) static int build_body(struct jit_ctx *ctx) { void *load_func[] = {jit_get_skb_b, jit_get_skb_h, jit_get_skb_w}; - const struct sk_filter *prog = ctx->skf; + const struct bpf_prog *prog = ctx->skf; const struct sock_filter *inst; unsigned int i, off, load_order, condt; u32 k, b_off __maybe_unused; @@ -1369,7 +1369,7 @@ jmp_cmp: int bpf_jit_enable __read_mostly; -void bpf_jit_compile(struct sk_filter *fp) +void bpf_jit_compile(struct bpf_prog *fp) { struct jit_ctx ctx; unsigned int alloc_size, tmp_idx; @@ -1423,7 +1423,7 @@ out: kfree(ctx.offsets); } -void bpf_jit_free(struct sk_filter *fp) +void bpf_jit_free(struct bpf_prog *fp) { if (fp->jited) module_free(NULL, fp->bpf_func); diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c index 82e82cadcde5..3afa6f4c1957 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c @@ -25,7 +25,7 @@ static inline void bpf_flush_icache(void *start, void *end) flush_icache_range((unsigned long)start, (unsigned long)end); } -static void bpf_jit_build_prologue(struct sk_filter *fp, u32 *image, +static void bpf_jit_build_prologue(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx) { int i; @@ -121,7 +121,7 @@ static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) ((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset) /* Assemble the body code between the prologue & epilogue. */ -static int bpf_jit_build_body(struct sk_filter *fp, u32 *image, +static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx, unsigned int *addrs) { @@ -569,7 +569,7 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image, return 0; } -void bpf_jit_compile(struct sk_filter *fp) +void bpf_jit_compile(struct bpf_prog *fp) { unsigned int proglen; unsigned int alloclen; @@ -693,7 +693,7 @@ out: return; } -void bpf_jit_free(struct sk_filter *fp) +void bpf_jit_free(struct bpf_prog *fp) { if (fp->jited) module_free(NULL, fp->bpf_func); diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index a2cbd875543a..61e45b7c04d7 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -812,7 +812,7 @@ static struct bpf_binary_header *bpf_alloc_binary(unsigned int bpfsize, return header; } -void bpf_jit_compile(struct sk_filter *fp) +void bpf_jit_compile(struct bpf_prog *fp) { struct bpf_binary_header *header = NULL; unsigned long size, prg_len, lit_len; @@ -875,7 +875,7 @@ out: kfree(addrs); } -void bpf_jit_free(struct sk_filter *fp) +void bpf_jit_free(struct bpf_prog *fp) { unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK; struct bpf_binary_header *header = (void *)addr; diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c index 892a102671ad..1f76c22a6a75 100644 --- a/arch/sparc/net/bpf_jit_comp.c +++ b/arch/sparc/net/bpf_jit_comp.c @@ -354,7 +354,7 @@ do { *prog++ = BR_OPC | WDISP22(OFF); \ * emit_jump() calls with adjusted offsets. */ -void bpf_jit_compile(struct sk_filter *fp) +void bpf_jit_compile(struct bpf_prog *fp) { unsigned int cleanup_addr, proglen, oldproglen = 0; u32 temp[8], *prog, *func, seen = 0, pass; @@ -808,7 +808,7 @@ out: return; } -void bpf_jit_free(struct sk_filter *fp) +void bpf_jit_free(struct bpf_prog *fp) { if (fp->jited) module_free(NULL, fp->bpf_func); diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index e2ecc1380b3d..5c8cb8043c5a 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -211,7 +211,7 @@ struct jit_context { bool seen_ld_abs; }; -static int do_jit(struct sk_filter *bpf_prog, int *addrs, u8 *image, +static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, int oldproglen, struct jit_context *ctx) { struct bpf_insn *insn = bpf_prog->insnsi; @@ -841,7 +841,7 @@ common_load: ctx->seen_ld_abs = true; /* By design x64 JIT should support all BPF instructions * This error will be seen if new instruction was added * to interpreter, but not to JIT - * or if there is junk in sk_filter + * or if there is junk in bpf_prog */ pr_err("bpf_jit: unknown opcode %02x\n", insn->code); return -EINVAL; @@ -862,11 +862,11 @@ common_load: ctx->seen_ld_abs = true; return proglen; } -void bpf_jit_compile(struct sk_filter *prog) +void bpf_jit_compile(struct bpf_prog *prog) { } -void bpf_int_jit_compile(struct sk_filter *prog) +void bpf_int_jit_compile(struct bpf_prog *prog) { struct bpf_binary_header *header = NULL; int proglen, oldproglen = 0; @@ -932,7 +932,7 @@ out: static void bpf_jit_free_deferred(struct work_struct *work) { - struct sk_filter *fp = container_of(work, struct sk_filter, work); + struct bpf_prog *fp = container_of(work, struct bpf_prog, work); unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK; struct bpf_binary_header *header = (void *)addr; @@ -941,7 +941,7 @@ static void bpf_jit_free_deferred(struct work_struct *work) kfree(fp); } -void bpf_jit_free(struct sk_filter *fp) +void bpf_jit_free(struct bpf_prog *fp) { if (fp->jited) { INIT_WORK(&fp->work, bpf_jit_free_deferred); diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 62f0688d45a5..c4198fa490bf 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -379,12 +379,12 @@ isdn_ppp_release(int min, struct file *file) #endif #ifdef CONFIG_IPPP_FILTER if (is->pass_filter) { - sk_unattached_filter_destroy(is->pass_filter); + bpf_prog_destroy(is->pass_filter); is->pass_filter = NULL; } if (is->active_filter) { - sk_unattached_filter_destroy(is->active_filter); + bpf_prog_destroy(is->active_filter); is->active_filter = NULL; } #endif @@ -639,12 +639,11 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) fprog.filter = code; if (is->pass_filter) { - sk_unattached_filter_destroy(is->pass_filter); + bpf_prog_destroy(is->pass_filter); is->pass_filter = NULL; } if (fprog.filter != NULL) - err = sk_unattached_filter_create(&is->pass_filter, - &fprog); + err = bpf_prog_create(&is->pass_filter, &fprog); else err = 0; kfree(code); @@ -664,12 +663,11 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) fprog.filter = code; if (is->active_filter) { - sk_unattached_filter_destroy(is->active_filter); + bpf_prog_destroy(is->active_filter); is->active_filter = NULL; } if (fprog.filter != NULL) - err = sk_unattached_filter_create(&is->active_filter, - &fprog); + err = bpf_prog_create(&is->active_filter, &fprog); else err = 0; kfree(code); @@ -1174,14 +1172,14 @@ isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff * } if (is->pass_filter - && SK_RUN_FILTER(is->pass_filter, skb) == 0) { + && BPF_PROG_RUN(is->pass_filter, skb) == 0) { if (is->debug & 0x2) printk(KERN_DEBUG "IPPP: inbound frame filtered.\n"); kfree_skb(skb); return; } if (!(is->active_filter - && SK_RUN_FILTER(is->active_filter, skb) == 0)) { + && BPF_PROG_RUN(is->active_filter, skb) == 0)) { if (is->debug & 0x2) printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n"); lp->huptimer = 0; @@ -1320,14 +1318,14 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) } if (ipt->pass_filter - && SK_RUN_FILTER(ipt->pass_filter, skb) == 0) { + && BPF_PROG_RUN(ipt->pass_filter, skb) == 0) { if (ipt->debug & 0x4) printk(KERN_DEBUG "IPPP: outbound frame filtered.\n"); kfree_skb(skb); goto unlock; } if (!(ipt->active_filter - && SK_RUN_FILTER(ipt->active_filter, skb) == 0)) { + && BPF_PROG_RUN(ipt->active_filter, skb) == 0)) { if (ipt->debug & 0x4) printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n"); lp->huptimer = 0; @@ -1517,9 +1515,9 @@ int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp) } drop |= is->pass_filter - && SK_RUN_FILTER(is->pass_filter, skb) == 0; + && BPF_PROG_RUN(is->pass_filter, skb) == 0; drop |= is->active_filter - && SK_RUN_FILTER(is->active_filter, skb) == 0; + && BPF_PROG_RUN(is->active_filter, skb) == 0; skb_push(skb, IPPP_MAX_HEADER - 4); return drop; diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 765248b42a0a..fa0d71727894 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -143,8 +143,8 @@ struct ppp { struct sk_buff_head mrq; /* MP: receive reconstruction queue */ #endif /* CONFIG_PPP_MULTILINK */ #ifdef CONFIG_PPP_FILTER - struct sk_filter *pass_filter; /* filter for packets to pass */ - struct sk_filter *active_filter;/* filter for pkts to reset idle */ + struct bpf_prog *pass_filter; /* filter for packets to pass */ + struct bpf_prog *active_filter; /* filter for pkts to reset idle */ #endif /* CONFIG_PPP_FILTER */ struct net *ppp_net; /* the net we belong to */ struct ppp_link_stats stats64; /* 64 bit network stats */ @@ -762,12 +762,12 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ppp_lock(ppp); if (ppp->pass_filter) { - sk_unattached_filter_destroy(ppp->pass_filter); + bpf_prog_destroy(ppp->pass_filter); ppp->pass_filter = NULL; } if (fprog.filter != NULL) - err = sk_unattached_filter_create(&ppp->pass_filter, - &fprog); + err = bpf_prog_create(&ppp->pass_filter, + &fprog); else err = 0; kfree(code); @@ -788,12 +788,12 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ppp_lock(ppp); if (ppp->active_filter) { - sk_unattached_filter_destroy(ppp->active_filter); + bpf_prog_destroy(ppp->active_filter); ppp->active_filter = NULL; } if (fprog.filter != NULL) - err = sk_unattached_filter_create(&ppp->active_filter, - &fprog); + err = bpf_prog_create(&ppp->active_filter, + &fprog); else err = 0; kfree(code); @@ -1205,7 +1205,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) a four-byte PPP header on each packet */ *skb_push(skb, 2) = 1; if (ppp->pass_filter && - SK_RUN_FILTER(ppp->pass_filter, skb) == 0) { + BPF_PROG_RUN(ppp->pass_filter, skb) == 0) { if (ppp->debug & 1) netdev_printk(KERN_DEBUG, ppp->dev, "PPP: outbound frame " @@ -1215,7 +1215,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) } /* if this packet passes the active filter, record the time */ if (!(ppp->active_filter && - SK_RUN_FILTER(ppp->active_filter, skb) == 0)) + BPF_PROG_RUN(ppp->active_filter, skb) == 0)) ppp->last_xmit = jiffies; skb_pull(skb, 2); #else @@ -1839,7 +1839,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) *skb_push(skb, 2) = 0; if (ppp->pass_filter && - SK_RUN_FILTER(ppp->pass_filter, skb) == 0) { + BPF_PROG_RUN(ppp->pass_filter, skb) == 0) { if (ppp->debug & 1) netdev_printk(KERN_DEBUG, ppp->dev, "PPP: inbound frame " @@ -1848,7 +1848,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) return; } if (!(ppp->active_filter && - SK_RUN_FILTER(ppp->active_filter, skb) == 0)) + BPF_PROG_RUN(ppp->active_filter, skb) == 0)) ppp->last_recv = jiffies; __skb_pull(skb, 2); } else @@ -2829,12 +2829,12 @@ static void ppp_destroy_interface(struct ppp *ppp) #endif /* CONFIG_PPP_MULTILINK */ #ifdef CONFIG_PPP_FILTER if (ppp->pass_filter) { - sk_unattached_filter_destroy(ppp->pass_filter); + bpf_prog_destroy(ppp->pass_filter); ppp->pass_filter = NULL; } if (ppp->active_filter) { - sk_unattached_filter_destroy(ppp->active_filter); + bpf_prog_destroy(ppp->active_filter); ppp->active_filter = NULL; } #endif /* CONFIG_PPP_FILTER */ diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c index d7be9b36bce6..a1536d0d83a9 100644 --- a/drivers/net/team/team_mode_loadbalance.c +++ b/drivers/net/team/team_mode_loadbalance.c @@ -58,7 +58,7 @@ struct lb_priv_ex { }; struct lb_priv { - struct sk_filter __rcu *fp; + struct bpf_prog __rcu *fp; lb_select_tx_port_func_t __rcu *select_tx_port_func; struct lb_pcpu_stats __percpu *pcpu_stats; struct lb_priv_ex *ex; /* priv extension */ @@ -174,14 +174,14 @@ static lb_select_tx_port_func_t *lb_select_tx_port_get_func(const char *name) static unsigned int lb_get_skb_hash(struct lb_priv *lb_priv, struct sk_buff *skb) { - struct sk_filter *fp; + struct bpf_prog *fp; uint32_t lhash; unsigned char *c; fp = rcu_dereference_bh(lb_priv->fp); if (unlikely(!fp)) return 0; - lhash = SK_RUN_FILTER(fp, skb); + lhash = BPF_PROG_RUN(fp, skb); c = (char *) &lhash; return c[0] ^ c[1] ^ c[2] ^ c[3]; } @@ -271,8 +271,8 @@ static void __fprog_destroy(struct sock_fprog_kern *fprog) static int lb_bpf_func_set(struct team *team, struct team_gsetter_ctx *ctx) { struct lb_priv *lb_priv = get_lb_priv(team); - struct sk_filter *fp = NULL; - struct sk_filter *orig_fp = NULL; + struct bpf_prog *fp = NULL; + struct bpf_prog *orig_fp = NULL; struct sock_fprog_kern *fprog = NULL; int err; @@ -281,7 +281,7 @@ static int lb_bpf_func_set(struct team *team, struct team_gsetter_ctx *ctx) ctx->data.bin_val.ptr); if (err) return err; - err = sk_unattached_filter_create(&fp, fprog); + err = bpf_prog_create(&fp, fprog); if (err) { __fprog_destroy(fprog); return err; @@ -300,7 +300,7 @@ static int lb_bpf_func_set(struct team *team, struct team_gsetter_ctx *ctx) if (orig_fp) { synchronize_rcu(); - sk_unattached_filter_destroy(orig_fp); + bpf_prog_destroy(orig_fp); } return 0; } diff --git a/include/linux/filter.h b/include/linux/filter.h index 7cb9b40e9a2f..a5227ab8ccb1 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -296,7 +296,8 @@ enum { }) /* Macro to invoke filter function. */ -#define SK_RUN_FILTER(filter, ctx) (*filter->bpf_func)(ctx, filter->insnsi) +#define SK_RUN_FILTER(filter, ctx) \ + (*filter->prog->bpf_func)(ctx, filter->prog->insnsi) struct bpf_insn { __u8 code; /* opcode */ @@ -323,12 +324,10 @@ struct sk_buff; struct sock; struct seccomp_data; -struct sk_filter { - atomic_t refcnt; +struct bpf_prog { u32 jited:1, /* Is our filter JIT'ed? */ len:31; /* Number of filter blocks */ struct sock_fprog_kern *orig_prog; /* Original BPF program */ - struct rcu_head rcu; unsigned int (*bpf_func)(const struct sk_buff *skb, const struct bpf_insn *filter); union { @@ -338,25 +337,32 @@ struct sk_filter { }; }; -static inline unsigned int sk_filter_size(unsigned int proglen) +struct sk_filter { + atomic_t refcnt; + struct rcu_head rcu; + struct bpf_prog *prog; +}; + +#define BPF_PROG_RUN(filter, ctx) (*filter->bpf_func)(ctx, filter->insnsi) + +static inline unsigned int bpf_prog_size(unsigned int proglen) { - return max(sizeof(struct sk_filter), - offsetof(struct sk_filter, insns[proglen])); + return max(sizeof(struct bpf_prog), + offsetof(struct bpf_prog, insns[proglen])); } #define bpf_classic_proglen(fprog) (fprog->len * sizeof(fprog->filter[0])) int sk_filter(struct sock *sk, struct sk_buff *skb); -void sk_filter_select_runtime(struct sk_filter *fp); -void sk_filter_free(struct sk_filter *fp); +void bpf_prog_select_runtime(struct bpf_prog *fp); +void bpf_prog_free(struct bpf_prog *fp); int bpf_convert_filter(struct sock_filter *prog, int len, struct bpf_insn *new_prog, int *new_len); -int sk_unattached_filter_create(struct sk_filter **pfp, - struct sock_fprog_kern *fprog); -void sk_unattached_filter_destroy(struct sk_filter *fp); +int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog); +void bpf_prog_destroy(struct bpf_prog *fp); int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); int sk_detach_filter(struct sock *sk); @@ -369,7 +375,7 @@ bool sk_filter_charge(struct sock *sk, struct sk_filter *fp); void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp); u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); -void bpf_int_jit_compile(struct sk_filter *fp); +void bpf_int_jit_compile(struct bpf_prog *fp); #define BPF_ANC BIT(15) @@ -423,8 +429,8 @@ static inline void *bpf_load_pointer(const struct sk_buff *skb, int k, #include #include -void bpf_jit_compile(struct sk_filter *fp); -void bpf_jit_free(struct sk_filter *fp); +void bpf_jit_compile(struct bpf_prog *fp); +void bpf_jit_free(struct bpf_prog *fp); static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen, u32 pass, void *image) @@ -438,11 +444,11 @@ static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen, #else #include -static inline void bpf_jit_compile(struct sk_filter *fp) +static inline void bpf_jit_compile(struct bpf_prog *fp) { } -static inline void bpf_jit_free(struct sk_filter *fp) +static inline void bpf_jit_free(struct bpf_prog *fp) { kfree(fp); } diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h index 8e10f57f109f..a0070c6dfaf8 100644 --- a/include/linux/isdn_ppp.h +++ b/include/linux/isdn_ppp.h @@ -180,8 +180,8 @@ struct ippp_struct { struct slcompress *slcomp; #endif #ifdef CONFIG_IPPP_FILTER - struct sk_filter *pass_filter; /* filter for packets to pass */ - struct sk_filter *active_filter; /* filter for pkts to reset idle */ + struct bpf_prog *pass_filter; /* filter for packets to pass */ + struct bpf_prog *active_filter; /* filter for pkts to reset idle */ #endif unsigned long debug; struct isdn_ppp_compressor *compressor,*decompressor; diff --git a/include/uapi/linux/netfilter/xt_bpf.h b/include/uapi/linux/netfilter/xt_bpf.h index 2ec9fbcd06f9..1fad2c27ac32 100644 --- a/include/uapi/linux/netfilter/xt_bpf.h +++ b/include/uapi/linux/netfilter/xt_bpf.h @@ -6,14 +6,14 @@ #define XT_BPF_MAX_NUM_INSTR 64 -struct sk_filter; +struct bpf_prog; struct xt_bpf_info { __u16 bpf_program_num_elem; struct sock_filter bpf_program[XT_BPF_MAX_NUM_INSTR]; /* only used in the kernel */ - struct sk_filter *filter __attribute__((aligned(8))); + struct bpf_prog *filter __attribute__((aligned(8))); }; #endif /*_XT_BPF_H */ diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 188ac5ba3900..7f0dbcbb34af 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -73,15 +73,13 @@ noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) } /** - * __sk_run_filter - run a filter on a given context - * @ctx: buffer to run the filter on - * @insn: filter to apply + * __bpf_prog_run - run eBPF program on a given context + * @ctx: is the data we are operating on + * @insn: is the array of eBPF instructions * - * Decode and apply filter instructions to the skb->data. Return length to - * keep, 0 for none. @ctx is the data we are operating on, @insn is the - * array of filter instructions. + * Decode and execute eBPF instructions. */ -static unsigned int __sk_run_filter(void *ctx, const struct bpf_insn *insn) +static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn) { u64 stack[MAX_BPF_STACK / sizeof(u64)]; u64 regs[MAX_BPF_REG], tmp; @@ -508,29 +506,29 @@ load_byte: return 0; } -void __weak bpf_int_jit_compile(struct sk_filter *prog) +void __weak bpf_int_jit_compile(struct bpf_prog *prog) { } /** - * sk_filter_select_runtime - select execution runtime for BPF program - * @fp: sk_filter populated with internal BPF program + * bpf_prog_select_runtime - select execution runtime for BPF program + * @fp: bpf_prog populated with internal BPF program * * try to JIT internal BPF program, if JIT is not available select interpreter - * BPF program will be executed via SK_RUN_FILTER() macro + * BPF program will be executed via BPF_PROG_RUN() macro */ -void sk_filter_select_runtime(struct sk_filter *fp) +void bpf_prog_select_runtime(struct bpf_prog *fp) { - fp->bpf_func = (void *) __sk_run_filter; + fp->bpf_func = (void *) __bpf_prog_run; /* Probe if internal BPF can be JITed */ bpf_int_jit_compile(fp); } -EXPORT_SYMBOL_GPL(sk_filter_select_runtime); +EXPORT_SYMBOL_GPL(bpf_prog_select_runtime); /* free internal BPF program */ -void sk_filter_free(struct sk_filter *fp) +void bpf_prog_free(struct bpf_prog *fp) { bpf_jit_free(fp); } -EXPORT_SYMBOL_GPL(sk_filter_free); +EXPORT_SYMBOL_GPL(bpf_prog_free); diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 33a3a97e2b58..2f3fa2cc2eac 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -54,7 +54,7 @@ struct seccomp_filter { atomic_t usage; struct seccomp_filter *prev; - struct sk_filter *prog; + struct bpf_prog *prog; }; /* Limit any path through the tree to 256KB worth of instructions. */ @@ -187,7 +187,7 @@ static u32 seccomp_run_filters(int syscall) * value always takes priority (ignoring the DATA). */ for (f = current->seccomp.filter; f; f = f->prev) { - u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd); + u32 cur_ret = BPF_PROG_RUN(f->prog, (void *)&sd); if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) ret = cur_ret; @@ -260,7 +260,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) if (!filter) goto free_prog; - filter->prog = kzalloc(sk_filter_size(new_len), + filter->prog = kzalloc(bpf_prog_size(new_len), GFP_KERNEL|__GFP_NOWARN); if (!filter->prog) goto free_filter; @@ -273,7 +273,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) atomic_set(&filter->usage, 1); filter->prog->len = new_len; - sk_filter_select_runtime(filter->prog); + bpf_prog_select_runtime(filter->prog); /* * If there is an existing filter, make it the prev and don't drop its @@ -337,7 +337,7 @@ void put_seccomp_filter(struct task_struct *tsk) while (orig && atomic_dec_and_test(&orig->usage)) { struct seccomp_filter *freeme = orig; orig = orig->prev; - sk_filter_free(freeme->prog); + bpf_prog_free(freeme->prog); kfree(freeme); } } diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 5f48623ee1a7..89e0345733bd 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -1761,9 +1761,9 @@ static int probe_filter_length(struct sock_filter *fp) return len + 1; } -static struct sk_filter *generate_filter(int which, int *err) +static struct bpf_prog *generate_filter(int which, int *err) { - struct sk_filter *fp; + struct bpf_prog *fp; struct sock_fprog_kern fprog; unsigned int flen = probe_filter_length(tests[which].u.insns); __u8 test_type = tests[which].aux & TEST_TYPE_MASK; @@ -1773,7 +1773,7 @@ static struct sk_filter *generate_filter(int which, int *err) fprog.filter = tests[which].u.insns; fprog.len = flen; - *err = sk_unattached_filter_create(&fp, &fprog); + *err = bpf_prog_create(&fp, &fprog); if (tests[which].aux & FLAG_EXPECTED_FAIL) { if (*err == -EINVAL) { pr_cont("PASS\n"); @@ -1798,7 +1798,7 @@ static struct sk_filter *generate_filter(int which, int *err) break; case INTERNAL: - fp = kzalloc(sk_filter_size(flen), GFP_KERNEL); + fp = kzalloc(bpf_prog_size(flen), GFP_KERNEL); if (fp == NULL) { pr_cont("UNEXPECTED_FAIL no memory left\n"); *err = -ENOMEM; @@ -1809,7 +1809,7 @@ static struct sk_filter *generate_filter(int which, int *err) memcpy(fp->insnsi, tests[which].u.insns_int, fp->len * sizeof(struct bpf_insn)); - sk_filter_select_runtime(fp); + bpf_prog_select_runtime(fp); break; } @@ -1817,21 +1817,21 @@ static struct sk_filter *generate_filter(int which, int *err) return fp; } -static void release_filter(struct sk_filter *fp, int which) +static void release_filter(struct bpf_prog *fp, int which) { __u8 test_type = tests[which].aux & TEST_TYPE_MASK; switch (test_type) { case CLASSIC: - sk_unattached_filter_destroy(fp); + bpf_prog_destroy(fp); break; case INTERNAL: - sk_filter_free(fp); + bpf_prog_free(fp); break; } } -static int __run_one(const struct sk_filter *fp, const void *data, +static int __run_one(const struct bpf_prog *fp, const void *data, int runs, u64 *duration) { u64 start, finish; @@ -1840,7 +1840,7 @@ static int __run_one(const struct sk_filter *fp, const void *data, start = ktime_to_us(ktime_get()); for (i = 0; i < runs; i++) - ret = SK_RUN_FILTER(fp, data); + ret = BPF_PROG_RUN(fp, data); finish = ktime_to_us(ktime_get()); @@ -1850,7 +1850,7 @@ static int __run_one(const struct sk_filter *fp, const void *data, return ret; } -static int run_one(const struct sk_filter *fp, struct bpf_test *test) +static int run_one(const struct bpf_prog *fp, struct bpf_test *test) { int err_cnt = 0, i, runs = MAX_TESTRUNS; @@ -1884,7 +1884,7 @@ static __init int test_bpf(void) int i, err_cnt = 0, pass_cnt = 0; for (i = 0; i < ARRAY_SIZE(tests); i++) { - struct sk_filter *fp; + struct bpf_prog *fp; int err; pr_info("#%d %s ", i, tests[i].descr); diff --git a/net/core/filter.c b/net/core/filter.c index 6ac901613bee..d814b8a89d0f 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -810,8 +810,8 @@ int bpf_check_classic(const struct sock_filter *filter, unsigned int flen) } EXPORT_SYMBOL(bpf_check_classic); -static int sk_store_orig_filter(struct sk_filter *fp, - const struct sock_fprog *fprog) +static int bpf_prog_store_orig_filter(struct bpf_prog *fp, + const struct sock_fprog *fprog) { unsigned int fsize = bpf_classic_proglen(fprog); struct sock_fprog_kern *fkprog; @@ -831,7 +831,7 @@ static int sk_store_orig_filter(struct sk_filter *fp, return 0; } -static void sk_release_orig_filter(struct sk_filter *fp) +static void bpf_release_orig_filter(struct bpf_prog *fp) { struct sock_fprog_kern *fprog = fp->orig_prog; @@ -841,10 +841,16 @@ static void sk_release_orig_filter(struct sk_filter *fp) } } +static void __bpf_prog_release(struct bpf_prog *prog) +{ + bpf_release_orig_filter(prog); + bpf_prog_free(prog); +} + static void __sk_filter_release(struct sk_filter *fp) { - sk_release_orig_filter(fp); - sk_filter_free(fp); + __bpf_prog_release(fp->prog); + kfree(fp); } /** @@ -872,7 +878,7 @@ static void sk_filter_release(struct sk_filter *fp) void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp) { - u32 filter_size = sk_filter_size(fp->len); + u32 filter_size = bpf_prog_size(fp->prog->len); atomic_sub(filter_size, &sk->sk_omem_alloc); sk_filter_release(fp); @@ -883,7 +889,7 @@ void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp) */ bool sk_filter_charge(struct sock *sk, struct sk_filter *fp) { - u32 filter_size = sk_filter_size(fp->len); + u32 filter_size = bpf_prog_size(fp->prog->len); /* same check as in sock_kmalloc() */ if (filter_size <= sysctl_optmem_max && @@ -895,10 +901,10 @@ bool sk_filter_charge(struct sock *sk, struct sk_filter *fp) return false; } -static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp) +static struct bpf_prog *bpf_migrate_filter(struct bpf_prog *fp) { struct sock_filter *old_prog; - struct sk_filter *old_fp; + struct bpf_prog *old_fp; int err, new_len, old_len = fp->len; /* We are free to overwrite insns et al right here as it @@ -927,7 +933,7 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp) /* Expand fp for appending the new filter representation. */ old_fp = fp; - fp = krealloc(old_fp, sk_filter_size(new_len), GFP_KERNEL); + fp = krealloc(old_fp, bpf_prog_size(new_len), GFP_KERNEL); if (!fp) { /* The old_fp is still around in case we couldn't * allocate new memory, so uncharge on that one. @@ -949,7 +955,7 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp) */ goto out_err_free; - sk_filter_select_runtime(fp); + bpf_prog_select_runtime(fp); kfree(old_prog); return fp; @@ -957,11 +963,11 @@ static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp) out_err_free: kfree(old_prog); out_err: - __sk_filter_release(fp); + __bpf_prog_release(fp); return ERR_PTR(err); } -static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp) +static struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp) { int err; @@ -970,7 +976,7 @@ static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp) err = bpf_check_classic(fp->insns, fp->len); if (err) { - __sk_filter_release(fp); + __bpf_prog_release(fp); return ERR_PTR(err); } @@ -983,13 +989,13 @@ static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp) * internal BPF translation for the optimized interpreter. */ if (!fp->jited) - fp = __sk_migrate_filter(fp); + fp = bpf_migrate_filter(fp); return fp; } /** - * sk_unattached_filter_create - create an unattached filter + * bpf_prog_create - create an unattached filter * @pfp: the unattached filter that is created * @fprog: the filter program * @@ -998,23 +1004,21 @@ static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp) * If an error occurs or there is insufficient memory for the filter * a negative errno code is returned. On success the return is zero. */ -int sk_unattached_filter_create(struct sk_filter **pfp, - struct sock_fprog_kern *fprog) +int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog) { unsigned int fsize = bpf_classic_proglen(fprog); - struct sk_filter *fp; + struct bpf_prog *fp; /* Make sure new filter is there and in the right amounts. */ if (fprog->filter == NULL) return -EINVAL; - fp = kmalloc(sk_filter_size(fprog->len), GFP_KERNEL); + fp = kmalloc(bpf_prog_size(fprog->len), GFP_KERNEL); if (!fp) return -ENOMEM; memcpy(fp->insns, fprog->filter, fsize); - atomic_set(&fp->refcnt, 1); fp->len = fprog->len; /* Since unattached filters are not copied back to user * space through sk_get_filter(), we do not need to hold @@ -1022,23 +1026,23 @@ int sk_unattached_filter_create(struct sk_filter **pfp, */ fp->orig_prog = NULL; - /* __sk_prepare_filter() already takes care of freeing + /* bpf_prepare_filter() already takes care of freeing * memory in case something goes wrong. */ - fp = __sk_prepare_filter(fp); + fp = bpf_prepare_filter(fp); if (IS_ERR(fp)) return PTR_ERR(fp); *pfp = fp; return 0; } -EXPORT_SYMBOL_GPL(sk_unattached_filter_create); +EXPORT_SYMBOL_GPL(bpf_prog_create); -void sk_unattached_filter_destroy(struct sk_filter *fp) +void bpf_prog_destroy(struct bpf_prog *fp) { - __sk_filter_release(fp); + __bpf_prog_release(fp); } -EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy); +EXPORT_SYMBOL_GPL(bpf_prog_destroy); /** * sk_attach_filter - attach a socket filter @@ -1054,7 +1058,8 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) { struct sk_filter *fp, *old_fp; unsigned int fsize = bpf_classic_proglen(fprog); - unsigned int sk_fsize = sk_filter_size(fprog->len); + unsigned int bpf_fsize = bpf_prog_size(fprog->len); + struct bpf_prog *prog; int err; if (sock_flag(sk, SOCK_FILTER_LOCKED)) @@ -1064,29 +1069,36 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) if (fprog->filter == NULL) return -EINVAL; - fp = kmalloc(sk_fsize, GFP_KERNEL); - if (!fp) + prog = kmalloc(bpf_fsize, GFP_KERNEL); + if (!prog) return -ENOMEM; - if (copy_from_user(fp->insns, fprog->filter, fsize)) { - kfree(fp); + if (copy_from_user(prog->insns, fprog->filter, fsize)) { + kfree(prog); return -EFAULT; } - fp->len = fprog->len; + prog->len = fprog->len; - err = sk_store_orig_filter(fp, fprog); + err = bpf_prog_store_orig_filter(prog, fprog); if (err) { - kfree(fp); + kfree(prog); return -ENOMEM; } - /* __sk_prepare_filter() already takes care of freeing + /* bpf_prepare_filter() already takes care of freeing * memory in case something goes wrong. */ - fp = __sk_prepare_filter(fp); - if (IS_ERR(fp)) - return PTR_ERR(fp); + prog = bpf_prepare_filter(prog); + if (IS_ERR(prog)) + return PTR_ERR(prog); + + fp = kmalloc(sizeof(*fp), GFP_KERNEL); + if (!fp) { + __bpf_prog_release(prog); + return -ENOMEM; + } + fp->prog = prog; atomic_set(&fp->refcnt, 0); @@ -1142,7 +1154,7 @@ int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, /* We're copying the filter that has been originally attached, * so no conversion/decode needed anymore. */ - fprog = filter->orig_prog; + fprog = filter->prog->orig_prog; ret = fprog->len; if (!len) diff --git a/net/core/ptp_classifier.c b/net/core/ptp_classifier.c index 12ab7b4be609..4eab4a94a59d 100644 --- a/net/core/ptp_classifier.c +++ b/net/core/ptp_classifier.c @@ -107,11 +107,11 @@ #include #include -static struct sk_filter *ptp_insns __read_mostly; +static struct bpf_prog *ptp_insns __read_mostly; unsigned int ptp_classify_raw(const struct sk_buff *skb) { - return SK_RUN_FILTER(ptp_insns, skb); + return BPF_PROG_RUN(ptp_insns, skb); } EXPORT_SYMBOL_GPL(ptp_classify_raw); @@ -189,5 +189,5 @@ void __init ptp_classifier_init(void) .len = ARRAY_SIZE(ptp_filter), .filter = ptp_filter, }; - BUG_ON(sk_unattached_filter_create(&ptp_insns, &ptp_prog)); + BUG_ON(bpf_prog_create(&ptp_insns, &ptp_prog)); } diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index 57d922320c59..ad704c757bb4 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -68,7 +68,7 @@ int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk, if (!filter) goto out; - fprog = filter->orig_prog; + fprog = filter->prog->orig_prog; flen = bpf_classic_proglen(fprog); attr = nla_reserve(skb, attrtype, flen); diff --git a/net/netfilter/xt_bpf.c b/net/netfilter/xt_bpf.c index bbffdbdaf603..dffee9d47ec4 100644 --- a/net/netfilter/xt_bpf.c +++ b/net/netfilter/xt_bpf.c @@ -28,7 +28,7 @@ static int bpf_mt_check(const struct xt_mtchk_param *par) program.len = info->bpf_program_num_elem; program.filter = info->bpf_program; - if (sk_unattached_filter_create(&info->filter, &program)) { + if (bpf_prog_create(&info->filter, &program)) { pr_info("bpf: check failed: parse error\n"); return -EINVAL; } @@ -40,13 +40,13 @@ static bool bpf_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_bpf_info *info = par->matchinfo; - return SK_RUN_FILTER(info->filter, skb); + return BPF_PROG_RUN(info->filter, skb); } static void bpf_mt_destroy(const struct xt_mtdtor_param *par) { const struct xt_bpf_info *info = par->matchinfo; - sk_unattached_filter_destroy(info->filter); + bpf_prog_destroy(info->filter); } static struct xt_match bpf_mt_reg __read_mostly = { diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c index 13f64df2c710..0e30d58149da 100644 --- a/net/sched/cls_bpf.c +++ b/net/sched/cls_bpf.c @@ -30,7 +30,7 @@ struct cls_bpf_head { }; struct cls_bpf_prog { - struct sk_filter *filter; + struct bpf_prog *filter; struct sock_filter *bpf_ops; struct tcf_exts exts; struct tcf_result res; @@ -54,7 +54,7 @@ static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp, int ret; list_for_each_entry(prog, &head->plist, link) { - int filter_res = SK_RUN_FILTER(prog->filter, skb); + int filter_res = BPF_PROG_RUN(prog->filter, skb); if (filter_res == 0) continue; @@ -92,7 +92,7 @@ static void cls_bpf_delete_prog(struct tcf_proto *tp, struct cls_bpf_prog *prog) tcf_unbind_filter(tp, &prog->res); tcf_exts_destroy(tp, &prog->exts); - sk_unattached_filter_destroy(prog->filter); + bpf_prog_destroy(prog->filter); kfree(prog->bpf_ops); kfree(prog); @@ -161,7 +161,7 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, struct sock_filter *bpf_ops, *bpf_old; struct tcf_exts exts; struct sock_fprog_kern tmp; - struct sk_filter *fp, *fp_old; + struct bpf_prog *fp, *fp_old; u16 bpf_size, bpf_len; u32 classid; int ret; @@ -193,7 +193,7 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, tmp.len = bpf_len; tmp.filter = bpf_ops; - ret = sk_unattached_filter_create(&fp, &tmp); + ret = bpf_prog_create(&fp, &tmp); if (ret) goto errout_free; @@ -211,7 +211,7 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, tcf_exts_change(tp, &prog->exts, &exts); if (fp_old) - sk_unattached_filter_destroy(fp_old); + bpf_prog_destroy(fp_old); if (bpf_old) kfree(bpf_old); -- cgit v1.2.3 From 06ebb06d49486676272a3c030bfeef4bd969a8e6 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 31 Jul 2014 23:00:35 -0400 Subject: iovec: make sure the caller actually wants anything in memcpy_fromiovecend Check for cases when the caller requests 0 bytes instead of running off and dereferencing potentially invalid iovecs. Signed-off-by: Sasha Levin Signed-off-by: David S. Miller --- lib/iovec.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/iovec.c b/lib/iovec.c index 7a7c2da4cddf..df3abd1eaa4a 100644 --- a/lib/iovec.c +++ b/lib/iovec.c @@ -85,6 +85,10 @@ EXPORT_SYMBOL(memcpy_toiovecend); int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, int offset, int len) { + /* No data? Done! */ + if (len == 0) + return 0; + /* Skip over the finished iovecs */ while (offset >= iov->iov_len) { offset -= iov->iov_len; -- cgit v1.2.3 From 188b1210f3d633e27dc97309c97315ce484122ec Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Fri, 1 Aug 2014 14:00:36 +0800 Subject: ipv4: remove nested rcu_read_lock/unlock ip_local_deliver_finish() already have a rcu_read_lock/unlock, so the rcu_read_lock/unlock is unnecessary. See the stack below: ip_local_deliver_finish | | ->icmp_rcv | | ->icmp_socket_deliver Suggested-by: Hannes Frederic Sowa Signed-off-by: Duan Jiong Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 092400ef88d0..ea7d4afe8205 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -670,11 +670,9 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info) raw_icmp_error(skb, protocol, info); - rcu_read_lock(); ipprot = rcu_dereference(inet_protos[protocol]); if (ipprot && ipprot->err_handler) ipprot->err_handler(skb, info); - rcu_read_unlock(); } static bool icmp_tag_validation(int proto) -- cgit v1.2.3 From a5536e109453bc625461d287619f4bffe233ade9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 1 Aug 2014 11:23:57 +0300 Subject: dm9000: NULL dereferences on error in probe() The dm9000_release_board() function is called with NULL ->data_req and ->addr_req pointers if dm9000_probe() fails. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ethernet/davicom/dm9000.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 13723c96d1a2..23084fb2090e 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -817,10 +817,12 @@ dm9000_release_board(struct platform_device *pdev, struct board_info *db) /* release the resources */ - release_resource(db->data_req); + if (db->data_req) + release_resource(db->data_req); kfree(db->data_req); - release_resource(db->addr_req); + if (db->addr_req) + release_resource(db->addr_req); kfree(db->addr_req); } -- cgit v1.2.3 From d2373862b3589260f0139a6e4969478f84154369 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 1 Aug 2014 12:29:43 +0200 Subject: inet: frags: use INC_STATS_BH in the ipv6 reassembly code Softirqs are already disabled so no need to do it again, thus let's be consistent and use the IP6_INC_STATS_BH variant. Signed-off-by: Nikolay Aleksandrov Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/ipv6/reassembly.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index f1709c4a289a..512ccc027ce3 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -355,8 +355,8 @@ found: discard_fq: inet_frag_kill(&fq->q, &ip6_frags); err: - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_REASMFAILS); + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), + IPSTATS_MIB_REASMFAILS); kfree_skb(skb); return -1; } @@ -566,7 +566,8 @@ static int ipv6_frag_rcv(struct sk_buff *skb) return -1; fail_hdr: - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); + IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), + IPSTATS_MIB_INHDRERRORS); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb_network_header_len(skb)); return -1; } -- cgit v1.2.3 From 06aa8b8a0345c78f4d9a1fb3f852952b12a0e40c Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 1 Aug 2014 12:29:44 +0200 Subject: inet: frags: rename last_in to flags The last_in field has been used to store various flags different from first/last frag in so give it a more descriptive name: flags. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- include/net/inet_frag.h | 2 +- net/ieee802154/reassembly.c | 14 +++++++------- net/ipv4/inet_fragment.c | 14 +++++++------- net/ipv4/ip_fragment.c | 20 ++++++++++---------- net/ipv6/netfilter/nf_conntrack_reasm.c | 12 ++++++------ net/ipv6/reassembly.c | 18 +++++++++--------- 6 files changed, 40 insertions(+), 40 deletions(-) diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 6f4930a0b660..5024d6c20407 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -25,7 +25,7 @@ struct inet_frag_queue { ktime_t stamp; int len; /* total length of orig datagram */ int meat; - __u8 last_in; /* first/last segment arrived? */ + __u8 flags; /* first/last segment arrived? */ #define INET_FRAG_EVICTED 8 #define INET_FRAG_COMPLETE 4 diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index f13d4f32e207..5607accd2fee 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -99,7 +99,7 @@ static void lowpan_frag_expire(unsigned long data) spin_lock(&fq->q.lock); - if (fq->q.last_in & INET_FRAG_COMPLETE) + if (fq->q.flags & INET_FRAG_COMPLETE) goto out; inet_frag_kill(&fq->q, &lowpan_frags); @@ -142,7 +142,7 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq, struct net_device *dev; int end, offset; - if (fq->q.last_in & INET_FRAG_COMPLETE) + if (fq->q.flags & INET_FRAG_COMPLETE) goto err; offset = lowpan_cb(skb)->d_offset << 3; @@ -154,14 +154,14 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq, * or have different end, the segment is corrupted. */ if (end < fq->q.len || - ((fq->q.last_in & INET_FRAG_LAST_IN) && end != fq->q.len)) + ((fq->q.flags & INET_FRAG_LAST_IN) && end != fq->q.len)) goto err; - fq->q.last_in |= INET_FRAG_LAST_IN; + fq->q.flags |= INET_FRAG_LAST_IN; fq->q.len = end; } else { if (end > fq->q.len) { /* Some bits beyond end -> corruption. */ - if (fq->q.last_in & INET_FRAG_LAST_IN) + if (fq->q.flags & INET_FRAG_LAST_IN) goto err; fq->q.len = end; } @@ -201,13 +201,13 @@ found: if (frag_type == LOWPAN_DISPATCH_FRAG1) { /* Calculate uncomp. 6lowpan header to estimate full size */ fq->q.meat += lowpan_uncompress_size(skb, NULL); - fq->q.last_in |= INET_FRAG_FIRST_IN; + fq->q.flags |= INET_FRAG_FIRST_IN; } else { fq->q.meat += skb->len; } add_frag_mem_limit(&fq->q, skb->truesize); - if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && + if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && fq->q.meat == fq->q.len) { int res; unsigned long orefdst = skb->_skb_refdst; diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 62b1f73749dc..e3ebc6608e5d 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -152,8 +152,8 @@ evict_again: } /* suppress xmit of (icmp) error packet */ - fq->last_in &= ~INET_FRAG_FIRST_IN; - fq->last_in |= INET_FRAG_EVICTED; + fq->flags &= ~INET_FRAG_FIRST_IN; + fq->flags |= INET_FRAG_EVICTED; hlist_del(&fq->list); hlist_add_head(&fq->list, &expired); ++evicted; @@ -289,16 +289,16 @@ void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f) if (del_timer(&fq->timer)) atomic_dec(&fq->refcnt); - if (!(fq->last_in & INET_FRAG_COMPLETE)) { + if (!(fq->flags & INET_FRAG_COMPLETE)) { fq_unlink(fq, f); atomic_dec(&fq->refcnt); - fq->last_in |= INET_FRAG_COMPLETE; + fq->flags |= INET_FRAG_COMPLETE; } } EXPORT_SYMBOL(inet_frag_kill); static inline void frag_kfree_skb(struct netns_frags *nf, struct inet_frags *f, - struct sk_buff *skb) + struct sk_buff *skb) { if (f->skb_free) f->skb_free(skb); @@ -311,7 +311,7 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f) struct netns_frags *nf; unsigned int sum, sum_truesize = 0; - WARN_ON(!(q->last_in & INET_FRAG_COMPLETE)); + WARN_ON(!(q->flags & INET_FRAG_COMPLETE)); WARN_ON(del_timer(&q->timer) != 0); /* Release all fragment data. */ @@ -349,7 +349,7 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, if (qp->net == nf && f->match(qp, arg)) { atomic_inc(&qp->refcnt); spin_unlock(&hb->chain_lock); - qp_in->last_in |= INET_FRAG_COMPLETE; + qp_in->flags |= INET_FRAG_COMPLETE; inet_frag_put(qp_in, f); return qp; } diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 634fc31aa243..6fce1ecc5bca 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -185,16 +185,16 @@ static void ip_expire(unsigned long arg) spin_lock(&qp->q.lock); - if (qp->q.last_in & INET_FRAG_COMPLETE) + if (qp->q.flags & INET_FRAG_COMPLETE) goto out; ipq_kill(qp); - if (!(qp->q.last_in & INET_FRAG_EVICTED)) + if (!(qp->q.flags & INET_FRAG_EVICTED)) IP_INC_STATS_BH(net, IPSTATS_MIB_REASMTIMEOUT); IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS); - if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { + if ((qp->q.flags & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { struct sk_buff *head = qp->q.fragments; const struct iphdr *iph; int err; @@ -302,7 +302,7 @@ static int ip_frag_reinit(struct ipq *qp) } while (fp); sub_frag_mem_limit(&qp->q, sum_truesize); - qp->q.last_in = 0; + qp->q.flags = 0; qp->q.len = 0; qp->q.meat = 0; qp->q.fragments = NULL; @@ -323,7 +323,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) int err = -ENOENT; u8 ecn; - if (qp->q.last_in & INET_FRAG_COMPLETE) + if (qp->q.flags & INET_FRAG_COMPLETE) goto err; if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) && @@ -350,9 +350,9 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) * or have different end, the segment is corrupted. */ if (end < qp->q.len || - ((qp->q.last_in & INET_FRAG_LAST_IN) && end != qp->q.len)) + ((qp->q.flags & INET_FRAG_LAST_IN) && end != qp->q.len)) goto err; - qp->q.last_in |= INET_FRAG_LAST_IN; + qp->q.flags |= INET_FRAG_LAST_IN; qp->q.len = end; } else { if (end&7) { @@ -362,7 +362,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) } if (end > qp->q.len) { /* Some bits beyond end -> corruption. */ - if (qp->q.last_in & INET_FRAG_LAST_IN) + if (qp->q.flags & INET_FRAG_LAST_IN) goto err; qp->q.len = end; } @@ -471,13 +471,13 @@ found: qp->ecn |= ecn; add_frag_mem_limit(&qp->q, skb->truesize); if (offset == 0) - qp->q.last_in |= INET_FRAG_FIRST_IN; + qp->q.flags |= INET_FRAG_FIRST_IN; if (ip_hdr(skb)->frag_off & htons(IP_DF) && skb->len + ihl > qp->q.max_size) qp->q.max_size = skb->len + ihl; - if (qp->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && + if (qp->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && qp->q.meat == qp->q.len) { unsigned long orefdst = skb->_skb_refdst; diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 3d4bccf6d67d..cca686e42b97 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -222,7 +222,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, int offset, end; u8 ecn; - if (fq->q.last_in & INET_FRAG_COMPLETE) { + if (fq->q.flags & INET_FRAG_COMPLETE) { pr_debug("Already completed\n"); goto err; } @@ -253,11 +253,11 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, * or have different end, the segment is corrupted. */ if (end < fq->q.len || - ((fq->q.last_in & INET_FRAG_LAST_IN) && end != fq->q.len)) { + ((fq->q.flags & INET_FRAG_LAST_IN) && end != fq->q.len)) { pr_debug("already received last fragment\n"); goto err; } - fq->q.last_in |= INET_FRAG_LAST_IN; + fq->q.flags |= INET_FRAG_LAST_IN; fq->q.len = end; } else { /* Check if the fragment is rounded to 8 bytes. @@ -272,7 +272,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, } if (end > fq->q.len) { /* Some bits beyond end -> corruption. */ - if (fq->q.last_in & INET_FRAG_LAST_IN) { + if (fq->q.flags & INET_FRAG_LAST_IN) { pr_debug("last packet already reached.\n"); goto err; } @@ -354,7 +354,7 @@ found: */ if (offset == 0) { fq->nhoffset = nhoff; - fq->q.last_in |= INET_FRAG_FIRST_IN; + fq->q.flags |= INET_FRAG_FIRST_IN; } return 0; @@ -617,7 +617,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) goto ret_orig; } - if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && + if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && fq->q.meat == fq->q.len) { ret_skb = nf_ct_frag6_reasm(fq, dev); if (ret_skb == NULL) diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 512ccc027ce3..b4baceed0d0d 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -131,7 +131,7 @@ void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq, spin_lock(&fq->q.lock); - if (fq->q.last_in & INET_FRAG_COMPLETE) + if (fq->q.flags & INET_FRAG_COMPLETE) goto out; inet_frag_kill(&fq->q, frags); @@ -141,13 +141,13 @@ void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq, if (!dev) goto out_rcu_unlock; - if (!(fq->q.last_in & INET_FRAG_EVICTED)) + if (!(fq->q.flags & INET_FRAG_EVICTED)) IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); /* Don't send error if the first segment did not arrive. */ - if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments) + if (!(fq->q.flags & INET_FRAG_FIRST_IN) || !fq->q.fragments) goto out_rcu_unlock; /* @@ -209,7 +209,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, struct net *net = dev_net(skb_dst(skb)->dev); u8 ecn; - if (fq->q.last_in & INET_FRAG_COMPLETE) + if (fq->q.flags & INET_FRAG_COMPLETE) goto err; offset = ntohs(fhdr->frag_off) & ~0x7; @@ -240,9 +240,9 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, * or have different end, the segment is corrupted. */ if (end < fq->q.len || - ((fq->q.last_in & INET_FRAG_LAST_IN) && end != fq->q.len)) + ((fq->q.flags & INET_FRAG_LAST_IN) && end != fq->q.len)) goto err; - fq->q.last_in |= INET_FRAG_LAST_IN; + fq->q.flags |= INET_FRAG_LAST_IN; fq->q.len = end; } else { /* Check if the fragment is rounded to 8 bytes. @@ -260,7 +260,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, } if (end > fq->q.len) { /* Some bits beyond end -> corruption. */ - if (fq->q.last_in & INET_FRAG_LAST_IN) + if (fq->q.flags & INET_FRAG_LAST_IN) goto err; fq->q.len = end; } @@ -335,10 +335,10 @@ found: */ if (offset == 0) { fq->nhoffset = nhoff; - fq->q.last_in |= INET_FRAG_FIRST_IN; + fq->q.flags |= INET_FRAG_FIRST_IN; } - if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && + if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && fq->q.meat == fq->q.len) { int res; unsigned long orefdst = skb->_skb_refdst; -- cgit v1.2.3 From 1ab1934ed80aa90b268a62a561f8fdc60812793c Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 1 Aug 2014 12:29:45 +0200 Subject: inet: frags: enum the flag definitions and add descriptions Move the flags to an enum definion, swap FIRST_IN/LAST_IN to be in increasing order and add comments explaining each flag and the inet_frag_queue struct members. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- include/net/inet_frag.h | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 5024d6c20407..90015c47b447 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -15,25 +15,49 @@ struct netns_frags { int low_thresh; }; +/** + * fragment queue flags + * + * @INET_FRAG_FIRST_IN: first fragment has arrived + * @INET_FRAG_LAST_IN: final fragment has arrived + * @INET_FRAG_COMPLETE: frag queue has been processed and is due for destruction + * @INET_FRAG_EVICTED: frag queue is being evicted + */ +enum { + INET_FRAG_FIRST_IN = BIT(0), + INET_FRAG_LAST_IN = BIT(1), + INET_FRAG_COMPLETE = BIT(2), + INET_FRAG_EVICTED = BIT(3) +}; + +/** + * struct inet_frag_queue - fragment queue + * + * @lock: spinlock protecting the queue + * @timer: queue expiration timer + * @list: hash bucket list + * @refcnt: reference count of the queue + * @fragments: received fragments head + * @fragments_tail: received fragments tail + * @stamp: timestamp of the last received fragment + * @len: total length of the original datagram + * @meat: length of received fragments so far + * @flags: fragment queue flags + * @max_size: (ipv4 only) maximum received fragment size with IP_DF set + * @net: namespace that this frag belongs to + */ struct inet_frag_queue { spinlock_t lock; - struct timer_list timer; /* when will this queue expire? */ + struct timer_list timer; struct hlist_node list; atomic_t refcnt; - struct sk_buff *fragments; /* list of received fragments */ + struct sk_buff *fragments; struct sk_buff *fragments_tail; ktime_t stamp; - int len; /* total length of orig datagram */ + int len; int meat; - __u8 flags; /* first/last segment arrived? */ - -#define INET_FRAG_EVICTED 8 -#define INET_FRAG_COMPLETE 4 -#define INET_FRAG_FIRST_IN 2 -#define INET_FRAG_LAST_IN 1 - + __u8 flags; u16 max_size; - struct netns_frags *net; }; -- cgit v1.2.3 From f926e23660d52601089222cb4755aabc693ca390 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 1 Aug 2014 12:29:46 +0200 Subject: inet: frags: fix function declaration alignments in inet_fragment Fix a couple of functions' declaration alignments. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/ipv4/inet_fragment.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index e3ebc6608e5d..fa49916c23a0 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -334,8 +334,9 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f) EXPORT_SYMBOL(inet_frag_destroy); static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, - struct inet_frag_queue *qp_in, struct inet_frags *f, - void *arg) + struct inet_frag_queue *qp_in, + struct inet_frags *f, + void *arg) { struct inet_frag_bucket *hb = get_frag_bucket_locked(qp_in, f); struct inet_frag_queue *qp; @@ -368,7 +369,8 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, } static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, - struct inet_frags *f, void *arg) + struct inet_frags *f, + void *arg) { struct inet_frag_queue *q; @@ -393,7 +395,8 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, } static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf, - struct inet_frags *f, void *arg) + struct inet_frags *f, + void *arg) { struct inet_frag_queue *q; @@ -405,7 +408,8 @@ static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf, } struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, - struct inet_frags *f, void *key, unsigned int hash) + struct inet_frags *f, void *key, + unsigned int hash) { struct inet_frag_bucket *hb; struct inet_frag_queue *q; -- cgit v1.2.3 From 2e404f632f44979ddf0ce0808a438249a72d7015 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 1 Aug 2014 12:29:47 +0200 Subject: inet: frags: use INET_FRAG_EVICTED to prevent icmp messages Now that we have INET_FRAG_EVICTED we might as well use it to stop sending icmp messages in the "frag_expire" functions instead of stripping INET_FRAG_FIRST_IN from their flags when evicting. Also fix the comment style in ip6_expire_frag_queue(). Signed-off-by: Nikolay Aleksandrov Reviewed-by: Florian Westphal Signed-off-by: David S. Miller --- net/ipv4/inet_fragment.c | 2 -- net/ipv4/ip_fragment.c | 14 +++++++------- net/ipv6/reassembly.c | 15 ++++++++------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index fa49916c23a0..4baa76c60398 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -151,8 +151,6 @@ evict_again: goto evict_again; } - /* suppress xmit of (icmp) error packet */ - fq->flags &= ~INET_FRAG_FIRST_IN; fq->flags |= INET_FRAG_EVICTED; hlist_del(&fq->list); hlist_add_head(&fq->list, &expired); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 6fce1ecc5bca..cb56bcc1eee2 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -189,16 +189,18 @@ static void ip_expire(unsigned long arg) goto out; ipq_kill(qp); - - if (!(qp->q.flags & INET_FRAG_EVICTED)) - IP_INC_STATS_BH(net, IPSTATS_MIB_REASMTIMEOUT); IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS); - if ((qp->q.flags & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { + if (!(qp->q.flags & INET_FRAG_EVICTED)) { struct sk_buff *head = qp->q.fragments; const struct iphdr *iph; int err; + IP_INC_STATS_BH(net, IPSTATS_MIB_REASMTIMEOUT); + + if (!(qp->q.flags & INET_FRAG_FIRST_IN) || !qp->q.fragments) + goto out; + rcu_read_lock(); head->dev = dev_get_by_index_rcu(net, qp->iif); if (!head->dev) @@ -211,8 +213,7 @@ static void ip_expire(unsigned long arg) if (err) goto out_rcu_unlock; - /* - * Only an end host needs to send an ICMP + /* Only an end host needs to send an ICMP * "Fragment Reassembly Timeout" message, per RFC792. */ if (qp->user == IP_DEFRAG_AF_PACKET || @@ -221,7 +222,6 @@ static void ip_expire(unsigned long arg) (skb_rtable(head)->rt_type != RTN_LOCAL))) goto out_rcu_unlock; - /* Send an ICMP "Fragment Reassembly Timeout" message. */ icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); out_rcu_unlock: diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index b4baceed0d0d..beb6872a8fa5 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -141,19 +141,20 @@ void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq, if (!dev) goto out_rcu_unlock; - if (!(fq->q.flags & INET_FRAG_EVICTED)) - IP6_INC_STATS_BH(net, __in6_dev_get(dev), - IPSTATS_MIB_REASMTIMEOUT); IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); + if (fq->q.flags & INET_FRAG_EVICTED) + goto out_rcu_unlock; + + IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); + /* Don't send error if the first segment did not arrive. */ if (!(fq->q.flags & INET_FRAG_FIRST_IN) || !fq->q.fragments) goto out_rcu_unlock; - /* - But use as source device on which LAST ARRIVED - segment was received. And do not use fq->dev - pointer directly, device might already disappeared. + /* But use as source device on which LAST ARRIVED + * segment was received. And do not use fq->dev + * pointer directly, device might already disappeared. */ fq->q.fragments->dev = dev; icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0); -- cgit v1.2.3 From d4ad4d22e7ac6b8711b35d7e86eb29f03f8ac153 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 1 Aug 2014 12:29:48 +0200 Subject: inet: frags: use kmem_cache for inet_frag_queue Use kmem_cache to allocate/free inet_frag_queue objects since they're all the same size per inet_frags user and are alloced/freed in high volumes thus making it a perfect case for kmem_cache. Signed-off-by: Nikolay Aleksandrov Acked-by: Florian Westphal Signed-off-by: David S. Miller --- include/net/inet_frag.h | 4 +++- net/ieee802154/reassembly.c | 7 ++++++- net/ipv4/inet_fragment.c | 13 ++++++++++--- net/ipv4/ip_fragment.c | 5 ++++- net/ipv6/netfilter/nf_conntrack_reasm.c | 8 ++++++-- net/ipv6/reassembly.c | 7 ++++++- 6 files changed, 35 insertions(+), 9 deletions(-) diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 90015c47b447..65a8855e99fe 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -101,9 +101,11 @@ struct inet_frags { void (*destructor)(struct inet_frag_queue *); void (*skb_free)(struct sk_buff *); void (*frag_expire)(unsigned long data); + struct kmem_cache *frags_cachep; + const char *frags_cache_name; }; -void inet_frags_init(struct inet_frags *); +int inet_frags_init(struct inet_frags *); void inet_frags_fini(struct inet_frags *); void inet_frags_init_net(struct netns_frags *nf); diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index 5607accd2fee..ffec6ce51005 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c @@ -30,6 +30,8 @@ #include "reassembly.h" +static const char lowpan_frags_cache_name[] = "lowpan-frags"; + struct lowpan_frag_info { __be16 d_tag; u16 d_size; @@ -571,7 +573,10 @@ int __init lowpan_net_frag_init(void) lowpan_frags.qsize = sizeof(struct frag_queue); lowpan_frags.match = lowpan_frag_match; lowpan_frags.frag_expire = lowpan_frag_expire; - inet_frags_init(&lowpan_frags); + lowpan_frags.frags_cache_name = lowpan_frags_cache_name; + ret = inet_frags_init(&lowpan_frags); + if (ret) + goto err_pernet; return ret; err_pernet: diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 4baa76c60398..9eb89f3f0ee4 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -198,7 +198,7 @@ static void inet_frag_schedule_worker(struct inet_frags *f) schedule_work(&f->frags_work); } -void inet_frags_init(struct inet_frags *f) +int inet_frags_init(struct inet_frags *f) { int i; @@ -213,6 +213,12 @@ void inet_frags_init(struct inet_frags *f) seqlock_init(&f->rnd_seqlock); f->last_rebuild_jiffies = 0; + f->frags_cachep = kmem_cache_create(f->frags_cache_name, f->qsize, 0, 0, + NULL); + if (!f->frags_cachep) + return -ENOMEM; + + return 0; } EXPORT_SYMBOL(inet_frags_init); @@ -225,6 +231,7 @@ EXPORT_SYMBOL(inet_frags_init_net); void inet_frags_fini(struct inet_frags *f) { cancel_work_sync(&f->frags_work); + kmem_cache_destroy(f->frags_cachep); } EXPORT_SYMBOL(inet_frags_fini); @@ -327,7 +334,7 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f) if (f->destructor) f->destructor(q); - kfree(q); + kmem_cache_free(f->frags_cachep, q); } EXPORT_SYMBOL(inet_frag_destroy); @@ -377,7 +384,7 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, return NULL; } - q = kzalloc(f->qsize, GFP_ATOMIC); + q = kmem_cache_zalloc(f->frags_cachep, GFP_ATOMIC); if (q == NULL) return NULL; diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index cb56bcc1eee2..15f0e2bad7ad 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -55,6 +55,7 @@ */ static int sysctl_ipfrag_max_dist __read_mostly = 64; +static const char ip_frag_cache_name[] = "ip4-frags"; struct ipfrag_skb_cb { @@ -860,5 +861,7 @@ void __init ipfrag_init(void) ip4_frags.qsize = sizeof(struct ipq); ip4_frags.match = ip4_frag_match; ip4_frags.frag_expire = ip_expire; - inet_frags_init(&ip4_frags); + ip4_frags.frags_cache_name = ip_frag_cache_name; + if (inet_frags_init(&ip4_frags)) + panic("IP: failed to allocate ip4_frags cache\n"); } diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index cca686e42b97..6f187c8d8a1b 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -50,6 +50,7 @@ #include #include +static const char nf_frags_cache_name[] = "nf-frags"; struct nf_ct_frag6_skb_cb { @@ -677,12 +678,15 @@ int nf_ct_frag6_init(void) nf_frags.qsize = sizeof(struct frag_queue); nf_frags.match = ip6_frag_match; nf_frags.frag_expire = nf_ct_frag6_expire; - inet_frags_init(&nf_frags); - + nf_frags.frags_cache_name = nf_frags_cache_name; + ret = inet_frags_init(&nf_frags); + if (ret) + goto out; ret = register_pernet_subsys(&nf_ct_net_ops); if (ret) inet_frags_fini(&nf_frags); +out: return ret; } diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index beb6872a8fa5..c6557d9f7808 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -60,6 +60,8 @@ #include #include +static const char ip6_frag_cache_name[] = "ip6-frags"; + struct ip6frag_skb_cb { struct inet6_skb_parm h; @@ -748,7 +750,10 @@ int __init ipv6_frag_init(void) ip6_frags.qsize = sizeof(struct frag_queue); ip6_frags.match = ip6_frag_match; ip6_frags.frag_expire = ip6_frag_expire; - inet_frags_init(&ip6_frags); + ip6_frags.frags_cache_name = ip6_frag_cache_name; + ret = inet_frags_init(&ip6_frags); + if (ret) + goto err_pernet; out: return ret; -- cgit v1.2.3 From dbcdd4d58c7230bea3157d56d6ef77c493b3865b Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 1 Aug 2014 14:01:51 +0200 Subject: cdc_subset: deal with a device that needs reset for timeout This device needs to be reset to recover from a timeout. Unfortunately this can be handled only at the level of the subdrivers. Signed-off-by: Oliver Neukum Signed-off-by: David S. Miller --- drivers/net/usb/cdc_subset.c | 27 ++++++++++++++++++++++++++- drivers/net/usb/usbnet.c | 8 ++++++-- include/linux/usb/usbnet.h | 3 +++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c index 91f0919fe278..6ea98cff2d3b 100644 --- a/drivers/net/usb/cdc_subset.c +++ b/drivers/net/usb/cdc_subset.c @@ -85,14 +85,28 @@ static int always_connected (struct usbnet *dev) * *-------------------------------------------------------------------------*/ +static void m5632_recover(struct usbnet *dev) +{ + struct usb_device *udev = dev->udev; + struct usb_interface *intf = dev->intf; + int r; + + r = usb_lock_device_for_reset(udev, intf); + if (r < 0) + return; + + usb_reset_device(udev); + usb_unlock_device(udev); +} + static const struct driver_info ali_m5632_info = { .description = "ALi M5632", .flags = FLAG_POINTTOPOINT, + .recover = m5632_recover, }; #endif - #ifdef CONFIG_USB_AN2720 #define HAVE_HARDWARE @@ -326,12 +340,23 @@ static const struct usb_device_id products [] = { MODULE_DEVICE_TABLE(usb, products); /*-------------------------------------------------------------------------*/ +static int dummy_prereset(struct usb_interface *intf) +{ + return 0; +} + +static int dummy_postreset(struct usb_interface *intf) +{ + return 0; +} static struct usb_driver cdc_subset_driver = { .name = "cdc_subset", .probe = usbnet_probe, .suspend = usbnet_suspend, .resume = usbnet_resume, + .pre_reset = dummy_prereset, + .post_reset = dummy_postreset, .disconnect = usbnet_disconnect, .id_table = products, .disable_hub_initiated_lpm = 1, diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index f9e96c427558..5173821a9575 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1218,8 +1218,12 @@ void usbnet_tx_timeout (struct net_device *net) unlink_urbs (dev, &dev->txq); tasklet_schedule (&dev->bh); - - // FIXME: device recovery -- reset? + /* this needs to be handled individually because the generic layer + * doesn't know what is sufficient and could not restore private + * information if a remedy of an unconditional reset were used. + */ + if (dev->driver_info->recover) + (dev->driver_info->recover)(dev); } EXPORT_SYMBOL_GPL(usbnet_tx_timeout); diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 0662e98fef72..26088feb6608 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -148,6 +148,9 @@ struct driver_info { struct sk_buff *(*tx_fixup)(struct usbnet *dev, struct sk_buff *skb, gfp_t flags); + /* recover from timeout */ + void (*recover)(struct usbnet *dev); + /* early initialization code, can sleep. This is for minidrivers * having 'subminidrivers' that need to do extra initialization * right after minidriver have initialized hardware. */ -- cgit v1.2.3 From d3d183126de8e100b003d09b64c6ec4b1c93abfc Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Fri, 1 Aug 2014 17:47:30 +0530 Subject: be2net: ignore get/set profile FW cmd failures Old versions of BE3 FW may not support cmds to re-provision (and hence optimize) resources/queues in SR-IOV config. Do not treat this FW cmd failure as fatal and fail the function initialization. Instead, just enable SR-IOV with the resources provided by the FW. Prior to the "create optimal number of queues on SR-IOV config" patch such failures were ignored. Fixes: bec84e6b2 ("create optimal number of queues on SR-IOV config") Reported-by: Eduardo Habkost Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 67 ++++++++++++++++------------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 9c50814f1e95..da4d3863bd18 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3342,22 +3342,17 @@ static int be_get_sriov_config(struct be_adapter *adapter) { struct device *dev = &adapter->pdev->dev; struct be_resources res = {0}; - int status, max_vfs, old_vfs; - - status = be_cmd_get_profile_config(adapter, &res, 0); - if (status) - return status; - - adapter->pool_res = res; + int max_vfs, old_vfs; /* Some old versions of BE3 FW don't report max_vfs value */ + be_cmd_get_profile_config(adapter, &res, 0); + if (BE3_chip(adapter) && !res.max_vfs) { max_vfs = pci_sriov_get_totalvfs(adapter->pdev); res.max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0; } - adapter->pool_res.max_vfs = res.max_vfs; - pci_sriov_set_totalvfs(adapter->pdev, be_max_vfs(adapter)); + adapter->pool_res = res; if (!be_max_vfs(adapter)) { if (num_vfs) @@ -3366,6 +3361,8 @@ static int be_get_sriov_config(struct be_adapter *adapter) return 0; } + pci_sriov_set_totalvfs(adapter->pdev, be_max_vfs(adapter)); + /* validate num_vfs module param */ old_vfs = pci_num_vf(adapter->pdev); if (old_vfs) { @@ -3423,6 +3420,35 @@ static int be_get_resources(struct be_adapter *adapter) return 0; } +static void be_sriov_config(struct be_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + int status; + + status = be_get_sriov_config(adapter); + if (status) { + dev_err(dev, "Failed to query SR-IOV configuration\n"); + dev_err(dev, "SR-IOV cannot be enabled\n"); + return; + } + + /* When the HW is in SRIOV capable configuration, the PF-pool + * resources are equally distributed across the max-number of + * VFs. The user may request only a subset of the max-vfs to be + * enabled. Based on num_vfs, redistribute the resources across + * num_vfs so that each VF will have access to more number of + * resources. This facility is not available in BE3 FW. + * Also, this is done by FW in Lancer chip. + */ + if (be_max_vfs(adapter) && !pci_num_vf(adapter->pdev)) { + status = be_cmd_set_sriov_config(adapter, + adapter->pool_res, + adapter->num_vfs); + if (status) + dev_err(dev, "Failed to optimize SR-IOV resources\n"); + } +} + static int be_get_config(struct be_adapter *adapter) { u16 profile_id; @@ -3439,27 +3465,8 @@ static int be_get_config(struct be_adapter *adapter) "Using profile 0x%x\n", profile_id); } - if (!BE2_chip(adapter) && be_physfn(adapter)) { - status = be_get_sriov_config(adapter); - if (status) - return status; - - /* When the HW is in SRIOV capable configuration, the PF-pool - * resources are equally distributed across the max-number of - * VFs. The user may request only a subset of the max-vfs to be - * enabled. Based on num_vfs, redistribute the resources across - * num_vfs so that each VF will have access to more number of - * resources. This facility is not available in BE3 FW. - * Also, this is done by FW in Lancer chip. - */ - if (!pci_num_vf(adapter->pdev)) { - status = be_cmd_set_sriov_config(adapter, - adapter->pool_res, - adapter->num_vfs); - if (status) - return status; - } - } + if (!BE2_chip(adapter) && be_physfn(adapter)) + be_sriov_config(adapter); status = be_get_resources(adapter); if (status) -- cgit v1.2.3 From 3c31aaf340387a209b6f7036adaa8522a1cd7f18 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Fri, 1 Aug 2014 17:47:31 +0530 Subject: be2net: ignore VF mac address setting for the same mac ndo_set_vf_mac() call may be issued for a mac-addr that is already active on a VF. If so, silently ignore the request. Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index da4d3863bd18..db4ff14ff18f 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1270,6 +1270,12 @@ static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) if (!is_valid_ether_addr(mac) || vf >= adapter->num_vfs) return -EINVAL; + /* Proceed further only if user provided MAC is different + * from active MAC + */ + if (ether_addr_equal(mac, vf_cfg->mac_addr)) + return 0; + if (BEx_chip(adapter)) { be_cmd_pmac_del(adapter, vf_cfg->if_handle, vf_cfg->pmac_id, vf + 1); -- cgit v1.2.3 From f0613380152a9290b68390ce60ba400ed25c780d Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Fri, 1 Aug 2014 17:47:32 +0530 Subject: be2net: support deleting FW dump via ethtool (only for Lancer) This patch adds support to delete an existing FW-dump in Lancer via ethtool. Initiating a new dump is not allowed if a FW dump is already present in the adapter. The existing dump has to be first explicitly deleted. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 2 ++ drivers/net/ethernet/emulex/benet/be_cmds.c | 48 ++++++++++++++++++++++++-- drivers/net/ethernet/emulex/benet/be_cmds.h | 10 ++++++ drivers/net/ethernet/emulex/benet/be_ethtool.c | 17 +++++---- 4 files changed, 65 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 0048ef8e5f35..811f1351db7a 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -383,8 +383,10 @@ enum vf_state { #define BE_UC_PMAC_COUNT 30 #define BE_VF_UC_PMAC_COUNT 2 + /* Ethtool set_dump flags */ #define LANCER_INITIATE_FW_DUMP 0x1 +#define LANCER_DELETE_FW_DUMP 0x2 struct phy_info { u8 transceiver; diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 791094c33535..4370ec1952ac 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2240,6 +2240,34 @@ err_unlock: return status; } +int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name) +{ + struct lancer_cmd_req_delete_object *req; + struct be_mcc_wrb *wrb; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = embedded_payload(wrb); + + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_DELETE_OBJECT, + sizeof(*req), wrb, NULL); + + strcpy(req->object_name, obj_name); + + status = be_mcc_notify_wait(adapter); +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 data_size, u32 data_offset, const char *obj_name, u32 *data_read, u32 *eof, u8 *addn_status) @@ -3805,13 +3833,19 @@ bool dump_present(struct be_adapter *adapter) int lancer_initiate_dump(struct be_adapter *adapter) { + struct device *dev = &adapter->pdev->dev; int status; + if (dump_present(adapter)) { + dev_info(dev, "Previous dump not cleared, not forcing dump\n"); + return -EEXIST; + } + /* give firmware reset and diagnostic dump */ status = lancer_physdev_ctrl(adapter, PHYSDEV_CONTROL_FW_RESET_MASK | PHYSDEV_CONTROL_DD_MASK); if (status < 0) { - dev_err(&adapter->pdev->dev, "Firmware reset failed\n"); + dev_err(dev, "FW reset failed\n"); return status; } @@ -3820,13 +3854,21 @@ int lancer_initiate_dump(struct be_adapter *adapter) return status; if (!dump_present(adapter)) { - dev_err(&adapter->pdev->dev, "Dump image not present\n"); - return -1; + dev_err(dev, "FW dump not generated\n"); + return -EIO; } return 0; } +int lancer_delete_dump(struct be_adapter *adapter) +{ + int status; + + status = lancer_cmd_delete_object(adapter, LANCER_FW_DUMP_FILE); + return be_cmd_status(status); +} + /* Uses sync mcc */ int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain) { diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 03e8a15c6922..5284b825bba2 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -231,6 +231,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_GET_FN_PRIVILEGES 170 #define OPCODE_COMMON_READ_OBJECT 171 #define OPCODE_COMMON_WRITE_OBJECT 172 +#define OPCODE_COMMON_DELETE_OBJECT 174 #define OPCODE_COMMON_MANAGE_IFACE_FILTERS 193 #define OPCODE_COMMON_GET_IFACE_LIST 194 #define OPCODE_COMMON_ENABLE_DISABLE_VF 196 @@ -1253,6 +1254,13 @@ struct lancer_cmd_resp_read_object { u32 eof; }; +struct lancer_cmd_req_delete_object { + struct be_cmd_req_hdr hdr; + u32 rsvd1; + u32 rsvd2; + u8 object_name[104]; +}; + /************************ WOL *******************************/ struct be_cmd_req_acpi_wol_magic_config{ struct be_cmd_req_hdr hdr; @@ -2067,6 +2075,7 @@ int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 data_size, u32 data_offset, const char *obj_name, u32 *data_read, u32 *eof, u8 *addn_status); +int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name); int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, u16 optype, int offset); int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, @@ -2120,6 +2129,7 @@ int be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter, struct be_fat_conf_params *cfgs); int lancer_physdev_ctrl(struct be_adapter *adapter, u32 mask); int lancer_initiate_dump(struct be_adapter *adapter); +int lancer_delete_dump(struct be_adapter *adapter); bool dump_present(struct be_adapter *adapter); int lancer_test_and_set_rdy_state(struct be_adapter *adapter); int be_cmd_query_port_name(struct be_adapter *adapter, u8 *port_name); diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 25f516d6eb9e..0cd3311409a8 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -681,22 +681,21 @@ static int be_set_dump(struct net_device *netdev, struct ethtool_dump *dump) struct device *dev = &adapter->pdev->dev; int status; - if (!lancer_chip(adapter)) { - dev_err(dev, "FW dump not supported\n"); + if (!lancer_chip(adapter) || + !check_privilege(adapter, MAX_PRIVILEGES)) return -EOPNOTSUPP; - } - - if (dump_present(adapter)) { - dev_err(dev, "Previous dump not cleared, not forcing dump\n"); - return 0; - } switch (dump->flag) { case LANCER_INITIATE_FW_DUMP: status = lancer_initiate_dump(adapter); if (!status) - dev_info(dev, "F/w dump initiated successfully\n"); + dev_info(dev, "FW dump initiated successfully\n"); break; + case LANCER_DELETE_FW_DUMP: + status = lancer_delete_dump(adapter); + if (!status) + dev_info(dev, "FW dump deleted successfully\n"); + break; default: dev_err(dev, "Invalid dump level: 0x%x\n", dump->flag); return -EINVAL; -- cgit v1.2.3 From 166bd890a3d851b7cfdf3e417917878bfe4671f1 Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Fri, 1 Aug 2014 14:41:10 +0200 Subject: ipv6: data of fwmark_reflect sysctl needs to be updated on netns construction Fixes: e110861f86094cd ("net: add a sysctl to reflect the fwmark on replies") Cc: Lorenzo Colitti Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/ipv6/sysctl_net_ipv6.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 058f3eca2e53..818334619abb 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -74,6 +74,7 @@ static int __net_init ipv6_sysctl_net_init(struct net *net) ipv6_table[0].data = &net->ipv6.sysctl.bindv6only; ipv6_table[1].data = &net->ipv6.sysctl.anycast_src_echo_reply; ipv6_table[2].data = &net->ipv6.sysctl.flowlabel_consistency; + ipv6_table[3].data = &net->ipv6.sysctl.fwmark_reflect; ipv6_route_table = ipv6_route_sysctl_init(net); if (!ipv6_route_table) -- cgit v1.2.3 From 0f76b9d83b2b010b63a094024b3cfd82e20af28d Mon Sep 17 00:00:00 2001 From: Hisashi Nakamura Date: Fri, 1 Aug 2014 17:03:00 +0200 Subject: net: sh_eth: Add r8a7794 support Signed-off-by: Hisashi Nakamura [uli: added bindings documentation] Signed-off-by: Ulrich Hecht Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/sh_eth.txt | 1 + drivers/net/ethernet/renesas/sh_eth.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/net/sh_eth.txt b/Documentation/devicetree/bindings/net/sh_eth.txt index e7106b50dbdc..34d4db1a4e25 100644 --- a/Documentation/devicetree/bindings/net/sh_eth.txt +++ b/Documentation/devicetree/bindings/net/sh_eth.txt @@ -9,6 +9,7 @@ Required properties: "renesas,ether-r8a7779" if the device is a part of R8A7779 SoC. "renesas,ether-r8a7790" if the device is a part of R8A7790 SoC. "renesas,ether-r8a7791" if the device is a part of R8A7791 SoC. + "renesas,ether-r8a7794" if the device is a part of R8A7794 SoC. "renesas,ether-r7s72100" if the device is a part of R7S72100 SoC. - reg: offset and length of (1) the E-DMAC/feLic register block (required), (2) the TSU register block (optional). diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 67b11c833870..60e9c2cd051e 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -2746,6 +2746,7 @@ static const struct of_device_id sh_eth_match_table[] = { { .compatible = "renesas,ether-r8a7779", .data = &r8a777x_data }, { .compatible = "renesas,ether-r8a7790", .data = &r8a779x_data }, { .compatible = "renesas,ether-r8a7791", .data = &r8a779x_data }, + { .compatible = "renesas,ether-r8a7794", .data = &r8a779x_data }, { .compatible = "renesas,ether-r7s72100", .data = &r7s72100_data }, { } }; @@ -2972,6 +2973,7 @@ static struct platform_device_id sh_eth_id_table[] = { { "r8a777x-ether", (kernel_ulong_t)&r8a777x_data }, { "r8a7790-ether", (kernel_ulong_t)&r8a779x_data }, { "r8a7791-ether", (kernel_ulong_t)&r8a779x_data }, + { "r8a7794-ether", (kernel_ulong_t)&r8a779x_data }, { } }; MODULE_DEVICE_TABLE(platform, sh_eth_id_table); -- cgit v1.2.3 From 6751edeb870034d95dc227716863c4e5572e35b6 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 1 Aug 2014 20:58:19 +0530 Subject: cirrus: cs89x0: Use managed interfaces This patch introduces the use of managed interfaces like devm_ioremap_resource and does away with the functions to free the allocated memory in the probe and remove functions. Also, many labels are done away with. The field size in no longer needed and is hence removed from the struct net_local. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/ethernet/cirrus/cs89x0.c | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c index fe84fbabc0d4..9823a0ea7937 100644 --- a/drivers/net/ethernet/cirrus/cs89x0.c +++ b/drivers/net/ethernet/cirrus/cs89x0.c @@ -145,7 +145,6 @@ struct net_local { int force; /* force various values; see FORCE* above. */ spinlock_t lock; void __iomem *virt_addr;/* CS89x0 virtual address. */ - unsigned long size; /* Length of CS89x0 memory region. */ #if ALLOW_DMA int use_dma; /* Flag: we're using dma */ int dma; /* DMA channel */ @@ -1854,41 +1853,29 @@ static int __init cs89x0_platform_probe(struct platform_device *pdev) lp = netdev_priv(dev); - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->irq = platform_get_irq(pdev, 0); - if (mem_res == NULL || dev->irq <= 0) { - dev_warn(&dev->dev, "memory/interrupt resource missing\n"); + if (dev->irq <= 0) { + dev_warn(&dev->dev, "interrupt resource missing\n"); err = -ENXIO; goto free; } - lp->size = resource_size(mem_res); - if (!request_mem_region(mem_res->start, lp->size, DRV_NAME)) { - dev_warn(&dev->dev, "request_mem_region() failed\n"); - err = -EBUSY; + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + virt_addr = devm_ioremap_resource(&pdev->dev, mem_res); + if (IS_ERR(virt_addr)) { + err = PTR_ERR(virt_addr); goto free; } - virt_addr = ioremap(mem_res->start, lp->size); - if (!virt_addr) { - dev_warn(&dev->dev, "ioremap() failed\n"); - err = -ENOMEM; - goto release; - } - err = cs89x0_probe1(dev, virt_addr, 0); if (err) { dev_warn(&dev->dev, "no cs8900 or cs8920 detected\n"); - goto unmap; + goto free; } platform_set_drvdata(pdev, dev); return 0; -unmap: - iounmap(virt_addr); -release: - release_mem_region(mem_res->start, lp->size); free: free_netdev(dev); return err; @@ -1897,17 +1884,12 @@ free: static int cs89x0_platform_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); - struct net_local *lp = netdev_priv(dev); - struct resource *mem_res; /* This platform_get_resource() call will not return NULL, because * the same call in cs89x0_platform_probe() has returned a non NULL * value. */ - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); unregister_netdev(dev); - iounmap(lp->virt_addr); - release_mem_region(mem_res->start, lp->size); free_netdev(dev); return 0; } -- cgit v1.2.3 From 54789983d14c00c80933beb782205df2a6c59afc Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 1 Aug 2014 20:59:13 +0530 Subject: net: ks8851-ml: Use devm_ioremap_resource This patch introduces the use of devm_ioremap_resource, devm_kmalloc and does away with the functions to free the allocated memory in the probe and remove functions. Also, some labels are done away with. A bug is fixed as two regions are allocated in the probe function, but only one is freed in the remove function. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/ethernet/micrel/ks8851_mll.c | 59 ++++++++++++-------------------- 1 file changed, 21 insertions(+), 38 deletions(-) diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c index c83d16dc7cd5..0eb47649191b 100644 --- a/drivers/net/ethernet/micrel/ks8851_mll.c +++ b/drivers/net/ethernet/micrel/ks8851_mll.c @@ -1519,7 +1519,8 @@ static int ks_hw_init(struct ks_net *ks) ks->all_mcast = 0; ks->mcast_lst_size = 0; - ks->frame_head_info = kmalloc(MHEADER_SIZE, GFP_KERNEL); + ks->frame_head_info = devm_kmalloc(&ks->pdev->dev, MHEADER_SIZE, + GFP_KERNEL); if (!ks->frame_head_info) return false; @@ -1537,44 +1538,41 @@ MODULE_DEVICE_TABLE(of, ks8851_ml_dt_ids); static int ks8851_probe(struct platform_device *pdev) { - int err = -ENOMEM; + int err; struct resource *io_d, *io_c; struct net_device *netdev; struct ks_net *ks; u16 id, data; const char *mac; - io_d = platform_get_resource(pdev, IORESOURCE_MEM, 0); - io_c = platform_get_resource(pdev, IORESOURCE_MEM, 1); - - if (!request_mem_region(io_d->start, resource_size(io_d), DRV_NAME)) - goto err_mem_region; - - if (!request_mem_region(io_c->start, resource_size(io_c), DRV_NAME)) - goto err_mem_region1; - netdev = alloc_etherdev(sizeof(struct ks_net)); if (!netdev) - goto err_alloc_etherdev; + return -ENOMEM; SET_NETDEV_DEV(netdev, &pdev->dev); ks = netdev_priv(netdev); ks->netdev = netdev; - ks->hw_addr = ioremap(io_d->start, resource_size(io_d)); - if (!ks->hw_addr) - goto err_ioremap; + io_d = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ks->hw_addr = devm_ioremap_resource(&pdev->dev, io_d); + if (IS_ERR(ks->hw_addr)) { + err = PTR_ERR(ks->hw_addr); + goto err_free; + } - ks->hw_addr_cmd = ioremap(io_c->start, resource_size(io_c)); - if (!ks->hw_addr_cmd) - goto err_ioremap1; + io_c = platform_get_resource(pdev, IORESOURCE_MEM, 1); + ks->hw_addr_cmd = devm_ioremap_resource(&pdev->dev, io_c); + if (IS_ERR(ks->hw_addr_cmd)) { + err = PTR_ERR(ks->hw_addr_cmd); + goto err_free; + } netdev->irq = platform_get_irq(pdev, 0); if ((int)netdev->irq < 0) { err = netdev->irq; - goto err_get_irq; + goto err_free; } ks->pdev = pdev; @@ -1604,18 +1602,18 @@ static int ks8851_probe(struct platform_device *pdev) if ((ks_rdreg16(ks, KS_CIDER) & ~CIDER_REV_MASK) != CIDER_ID) { netdev_err(netdev, "failed to read device ID\n"); err = -ENODEV; - goto err_register; + goto err_free; } if (ks_read_selftest(ks)) { netdev_err(netdev, "failed to read device ID\n"); err = -ENODEV; - goto err_register; + goto err_free; } err = register_netdev(netdev); if (err) - goto err_register; + goto err_free; platform_set_drvdata(pdev, netdev); @@ -1663,32 +1661,17 @@ static int ks8851_probe(struct platform_device *pdev) err_pdata: unregister_netdev(netdev); -err_register: -err_get_irq: - iounmap(ks->hw_addr_cmd); -err_ioremap1: - iounmap(ks->hw_addr); -err_ioremap: +err_free: free_netdev(netdev); -err_alloc_etherdev: - release_mem_region(io_c->start, resource_size(io_c)); -err_mem_region1: - release_mem_region(io_d->start, resource_size(io_d)); -err_mem_region: return err; } static int ks8851_remove(struct platform_device *pdev) { struct net_device *netdev = platform_get_drvdata(pdev); - struct ks_net *ks = netdev_priv(netdev); - struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - kfree(ks->frame_head_info); unregister_netdev(netdev); - iounmap(ks->hw_addr); free_netdev(netdev); - release_mem_region(iomem->start, resource_size(iomem)); return 0; } -- cgit v1.2.3 From ae29223eaf0ecf4c701457a6b40d7b8f19c90413 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 1 Aug 2014 21:00:03 +0530 Subject: net: dnet: Use managed interfaces This patch introduces the use of managed interfaces like devm_ioremap_resource and does away with the calls to free the allocated memory in the probe and remove functions. Also, some labels and variable are done away with. This fixes a bug as there was a missing release_mem_region in the remove function. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/ethernet/dnet.c | 46 ++++++++++++--------------------------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c index e9b0faba3078..a379c3e4b57f 100644 --- a/drivers/net/ethernet/dnet.c +++ b/drivers/net/ethernet/dnet.c @@ -323,7 +323,8 @@ static int dnet_mii_init(struct dnet *bp) bp->mii_bus->priv = bp; - bp->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + bp->mii_bus->irq = devm_kmalloc(&bp->pdev->dev, + sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); if (!bp->mii_bus->irq) { err = -ENOMEM; goto err_out; @@ -334,7 +335,7 @@ static int dnet_mii_init(struct dnet *bp) if (mdiobus_register(bp->mii_bus)) { err = -ENXIO; - goto err_out_free_mdio_irq; + goto err_out; } if (dnet_mii_probe(bp->dev) != 0) { @@ -346,8 +347,6 @@ static int dnet_mii_init(struct dnet *bp) err_out_unregister_bus: mdiobus_unregister(bp->mii_bus); -err_out_free_mdio_irq: - kfree(bp->mii_bus->irq); err_out: mdiobus_free(bp->mii_bus); return err; @@ -825,28 +824,14 @@ static int dnet_probe(struct platform_device *pdev) struct net_device *dev; struct dnet *bp; struct phy_device *phydev; - int err = -ENXIO; - unsigned int mem_base, mem_size, irq; + int err; + unsigned int irq; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "no mmio resource defined\n"); - goto err_out; - } - mem_base = res->start; - mem_size = resource_size(res); irq = platform_get_irq(pdev, 0); - if (!request_mem_region(mem_base, mem_size, DRV_NAME)) { - dev_err(&pdev->dev, "no memory region available\n"); - err = -EBUSY; - goto err_out; - } - - err = -ENOMEM; dev = alloc_etherdev(sizeof(*bp)); if (!dev) - goto err_out_release_mem; + return -ENOMEM; /* TODO: Actually, we have some interesting features... */ dev->features |= 0; @@ -859,10 +844,10 @@ static int dnet_probe(struct platform_device *pdev) spin_lock_init(&bp->lock); - bp->regs = ioremap(mem_base, mem_size); - if (!bp->regs) { - dev_err(&pdev->dev, "failed to map registers, aborting.\n"); - err = -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + bp->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(bp->regs)) { + err = PTR_ERR(bp->regs); goto err_out_free_dev; } @@ -871,7 +856,7 @@ static int dnet_probe(struct platform_device *pdev) if (err) { dev_err(&pdev->dev, "Unable to request IRQ %d (error %d)\n", irq, err); - goto err_out_iounmap; + goto err_out_free_dev; } dev->netdev_ops = &dnet_netdev_ops; @@ -908,7 +893,7 @@ static int dnet_probe(struct platform_device *pdev) goto err_out_unregister_netdev; dev_info(&pdev->dev, "Dave DNET at 0x%p (0x%08x) irq %d %pM\n", - bp->regs, mem_base, dev->irq, dev->dev_addr); + bp->regs, (unsigned int)res->start, dev->irq, dev->dev_addr); dev_info(&pdev->dev, "has %smdio, %sirq, %sgigabit, %sdma\n", (bp->capabilities & DNET_HAS_MDIO) ? "" : "no ", (bp->capabilities & DNET_HAS_IRQ) ? "" : "no ", @@ -925,13 +910,8 @@ err_out_unregister_netdev: unregister_netdev(dev); err_out_free_irq: free_irq(dev->irq, dev); -err_out_iounmap: - iounmap(bp->regs); err_out_free_dev: free_netdev(dev); -err_out_release_mem: - release_mem_region(mem_base, mem_size); -err_out: return err; } @@ -948,11 +928,9 @@ static int dnet_remove(struct platform_device *pdev) if (bp->phy_dev) phy_disconnect(bp->phy_dev); mdiobus_unregister(bp->mii_bus); - kfree(bp->mii_bus->irq); mdiobus_free(bp->mii_bus); unregister_netdev(dev); free_irq(dev->irq, dev); - iounmap(bp->regs); free_netdev(dev); } -- cgit v1.2.3 From 8c43a2cc75b3bf4f89ea439f4439a2a61f22c961 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 1 Aug 2014 11:56:29 -0500 Subject: amd-xgbe: Remove unnecessary spinlocks Remove the spinlocks around the ethtool get and set settings functions and within the link adjustment callback routine. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 20 +++++--------------- drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 5 ----- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index 6005b6021f78..a076aca138a1 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -290,13 +290,9 @@ static int xgbe_get_settings(struct net_device *netdev, if (!pdata->phydev) return -ENODEV; - spin_lock_irq(&pdata->lock); - ret = phy_ethtool_gset(pdata->phydev, cmd); cmd->transceiver = XCVR_EXTERNAL; - spin_unlock_irq(&pdata->lock); - DBGPR("<--xgbe_get_settings\n"); return ret; @@ -315,17 +311,14 @@ static int xgbe_set_settings(struct net_device *netdev, if (!pdata->phydev) return -ENODEV; - spin_lock_irq(&pdata->lock); - speed = ethtool_cmd_speed(cmd); - ret = -EINVAL; if (cmd->phy_address != phydev->addr) - goto unlock; + return -EINVAL; if ((cmd->autoneg != AUTONEG_ENABLE) && (cmd->autoneg != AUTONEG_DISABLE)) - goto unlock; + return -EINVAL; if (cmd->autoneg == AUTONEG_DISABLE) { switch (speed) { @@ -334,16 +327,16 @@ static int xgbe_set_settings(struct net_device *netdev, case SPEED_1000: break; default: - goto unlock; + return -EINVAL; } if (cmd->duplex != DUPLEX_FULL) - goto unlock; + return -EINVAL; } cmd->advertising &= phydev->supported; if ((cmd->autoneg == AUTONEG_ENABLE) && !cmd->advertising) - goto unlock; + return -EINVAL; ret = 0; phydev->autoneg = cmd->autoneg; @@ -359,9 +352,6 @@ static int xgbe_set_settings(struct net_device *netdev, if (netif_running(netdev)) ret = phy_start_aneg(phydev); -unlock: - spin_unlock_irq(&pdata->lock); - DBGPR("<--xgbe_set_settings\n"); return ret; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 225f22d5fe0a..eecd360430a4 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -163,7 +163,6 @@ static void xgbe_adjust_link(struct net_device *netdev) struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_hw_if *hw_if = &pdata->hw_if; struct phy_device *phydev = pdata->phydev; - unsigned long flags; int new_state = 0; if (phydev == NULL) @@ -172,8 +171,6 @@ static void xgbe_adjust_link(struct net_device *netdev) DBGPR_MDIO("-->xgbe_adjust_link: address=%d, newlink=%d, curlink=%d\n", phydev->addr, phydev->link, pdata->phy_link); - spin_lock_irqsave(&pdata->lock, flags); - if (phydev->link) { /* Flow control support */ if (pdata->pause_autoneg) { @@ -229,8 +226,6 @@ static void xgbe_adjust_link(struct net_device *netdev) if (new_state) phy_print_status(phydev); - spin_unlock_irqrestore(&pdata->lock, flags); - DBGPR_MDIO("<--xgbe_adjust_link\n"); } -- cgit v1.2.3 From 1fa1f2e09824abd39fa7e7bffe8769b7b0260b45 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Fri, 1 Aug 2014 11:56:36 -0500 Subject: amd-xgbe-phy: Allow more time for Rx/Tx to become ready The current time range waiting for Rx/Tx to become ready can sometimes be too short if a connection is not present. Increase the number of retries and the sleep to give a bit more time. Also, change level of the message issued from _err to _dbg if Rx/Tx do not become ready since the underlying logic will function as if no link is established and retry eventually. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/phy/amd-xgbe-phy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index 388e3029165a..f3230eef41fd 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -95,7 +95,7 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define XNP_MP_FORMATTED (1 << 13) #define XNP_NP_EXCHANGE (1 << 15) -#define XGBE_PHY_RATECHANGE_COUNT 100 +#define XGBE_PHY_RATECHANGE_COUNT 500 #ifndef MDIO_PMA_10GBR_PMD_CTRL #define MDIO_PMA_10GBR_PMD_CTRL 0x0096 @@ -411,7 +411,7 @@ static void amd_xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev) /* Wait for Rx and Tx ready */ wait = XGBE_PHY_RATECHANGE_COUNT; while (wait--) { - usleep_range(10, 20); + usleep_range(50, 75); status = XSIR0_IOREAD(priv, SIR0_STATUS); if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) && @@ -419,7 +419,7 @@ static void amd_xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev) return; } - netdev_err(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n", + netdev_dbg(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n", status); } -- cgit v1.2.3 From a1a693698d00b48d2d56fc1c887ab86375934a06 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Fri, 1 Aug 2014 13:27:02 -0700 Subject: i40e: adds FCoE code to the i40e driver This patch adds FCoE ( Fibre Channel Over Ethernet ) code for Intel XL710 adapters. This patch is limited to only new FCoE offloads code in newly added files by this patch and then following patches in the series modifies rest of the existing driver to enable FCoE with i40e driver. Signed-off-by: Vasu Dev Tested-by: Jack Morgan Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 1568 +++++++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_fcoe.h | 128 +++ 2 files changed, 1696 insertions(+) create mode 100644 drivers/net/ethernet/intel/i40e/i40e_fcoe.c create mode 100644 drivers/net/ethernet/intel/i40e/i40e_fcoe.h diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c new file mode 100644 index 000000000000..8574eeefefc7 --- /dev/null +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c @@ -0,0 +1,1568 @@ +/******************************************************************************* + * + * Intel Ethernet Controller XL710 Family Linux Driver + * Copyright(c) 2013 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + ******************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i40e.h" +#include "i40e_fcoe.h" + +/** + * i40e_rx_is_fip - returns true if the rx packet type is FIP + * @ptype: the packet type field from rx descriptor write-back + **/ +static inline bool i40e_rx_is_fip(u16 ptype) +{ + return ptype == I40E_RX_PTYPE_L2_FIP_PAY2; +} + +/** + * i40e_rx_is_fcoe - returns true if the rx packet type is FCoE + * @ptype: the packet type field from rx descriptor write-back + **/ +static inline bool i40e_rx_is_fcoe(u16 ptype) +{ + return (ptype >= I40E_RX_PTYPE_L2_FCOE_PAY3) && + (ptype <= I40E_RX_PTYPE_L2_FCOE_VFT_FCOTHER); +} + +/** + * i40e_fcoe_sof_is_class2 - returns true if this is a FC Class 2 SOF + * @sof: the FCoE start of frame delimiter + **/ +static inline bool i40e_fcoe_sof_is_class2(u8 sof) +{ + return (sof == FC_SOF_I2) || (sof == FC_SOF_N2); +} + +/** + * i40e_fcoe_sof_is_class3 - returns true if this is a FC Class 3 SOF + * @sof: the FCoE start of frame delimiter + **/ +static inline bool i40e_fcoe_sof_is_class3(u8 sof) +{ + return (sof == FC_SOF_I3) || (sof == FC_SOF_N3); +} + +/** + * i40e_fcoe_sof_is_supported - returns true if the FC SOF is supported by HW + * @sof: the input SOF value from the frame + **/ +static inline bool i40e_fcoe_sof_is_supported(u8 sof) +{ + return i40e_fcoe_sof_is_class2(sof) || + i40e_fcoe_sof_is_class3(sof); +} + +/** + * i40e_fcoe_fc_sof - pull the SOF from FCoE header in the frame + * @skb: the frame whose EOF is to be pulled from + **/ +static inline int i40e_fcoe_fc_sof(struct sk_buff *skb, u8 *sof) +{ + *sof = ((struct fcoe_hdr *)skb_network_header(skb))->fcoe_sof; + + if (!i40e_fcoe_sof_is_supported(*sof)) + return -EINVAL; + return 0; +} + +/** + * i40e_fcoe_eof_is_supported - returns true if the EOF is supported by HW + * @eof: the input EOF value from the frame + **/ +static inline bool i40e_fcoe_eof_is_supported(u8 eof) +{ + return (eof == FC_EOF_N) || (eof == FC_EOF_T) || + (eof == FC_EOF_NI) || (eof == FC_EOF_A); +} + +/** + * i40e_fcoe_fc_eof - pull EOF from FCoE trailer in the frame + * @skb: the frame whose EOF is to be pulled from + **/ +static inline int i40e_fcoe_fc_eof(struct sk_buff *skb, u8 *eof) +{ + /* the first byte of the last dword is EOF */ + skb_copy_bits(skb, skb->len - 4, eof, 1); + + if (!i40e_fcoe_eof_is_supported(*eof)) + return -EINVAL; + return 0; +} + +/** + * i40e_fcoe_ctxt_eof - convert input FC EOF for descriptor programming + * @eof: the input eof value from the frame + * + * The FC EOF is converted to the value understood by HW for descriptor + * programming. Never call this w/o calling i40e_fcoe_eof_is_supported() + * first. + **/ +static inline u32 i40e_fcoe_ctxt_eof(u8 eof) +{ + switch (eof) { + case FC_EOF_N: + return I40E_TX_DESC_CMD_L4T_EOFT_EOF_N; + case FC_EOF_T: + return I40E_TX_DESC_CMD_L4T_EOFT_EOF_T; + case FC_EOF_NI: + return I40E_TX_DESC_CMD_L4T_EOFT_EOF_NI; + case FC_EOF_A: + return I40E_TX_DESC_CMD_L4T_EOFT_EOF_A; + default: + /* FIXME: still returns 0 */ + pr_err("Unrecognized EOF %x\n", eof); + return 0; + } +} + +/** + * i40e_fcoe_xid_is_valid - returns true if the exchange id is valid + * @xid: the exchange id + **/ +static inline bool i40e_fcoe_xid_is_valid(u16 xid) +{ + return (xid != FC_XID_UNKNOWN) && (xid < I40E_FCOE_DDP_MAX); +} + +/** + * i40e_fcoe_ddp_unmap - unmap the mapped sglist associated + * @pf: pointer to pf + * @ddp: sw DDP context + * + * Unmap the scatter-gather list associated with the given SW DDP context + * + * Returns: data length already ddp-ed in bytes + * + **/ +static inline void i40e_fcoe_ddp_unmap(struct i40e_pf *pf, + struct i40e_fcoe_ddp *ddp) +{ + if (test_and_set_bit(__I40E_FCOE_DDP_UNMAPPED, &ddp->flags)) + return; + + if (ddp->sgl) { + dma_unmap_sg(&pf->pdev->dev, ddp->sgl, ddp->sgc, + DMA_FROM_DEVICE); + ddp->sgl = NULL; + ddp->sgc = 0; + } + + if (ddp->pool) { + dma_pool_free(ddp->pool, ddp->udl, ddp->udp); + ddp->pool = NULL; + } +} + +/** + * i40e_fcoe_ddp_clear - clear the given SW DDP context + * @ddp - SW DDP context + **/ +static inline void i40e_fcoe_ddp_clear(struct i40e_fcoe_ddp *ddp) +{ + memset(ddp, 0, sizeof(struct i40e_fcoe_ddp)); + ddp->xid = FC_XID_UNKNOWN; + ddp->flags = __I40E_FCOE_DDP_NONE; +} + +/** + * i40e_fcoe_progid_is_fcoe - check if the prog_id is for FCoE + * @id: the prog id for the programming status Rx descriptor write-back + **/ +static inline bool i40e_fcoe_progid_is_fcoe(u8 id) +{ + return (id == I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_PROG_STATUS) || + (id == I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_INVL_STATUS); +} + +/** + * i40e_fcoe_fc_get_xid - get xid from the frame header + * @fh: the fc frame header + * + * In case the incoming frame's exchange is originated from + * the initiator, then received frame's exchange id is ANDed + * with fc_cpu_mask bits to get the same cpu on which exchange + * was originated, otherwise just use the current cpu. + * + * Returns ox_id if exchange originator, rx_id if responder + **/ +static inline u16 i40e_fcoe_fc_get_xid(struct fc_frame_header *fh) +{ + u32 f_ctl = ntoh24(fh->fh_f_ctl); + + return (f_ctl & FC_FC_EX_CTX) ? + be16_to_cpu(fh->fh_ox_id) : + be16_to_cpu(fh->fh_rx_id); +} + +/** + * i40e_fcoe_fc_frame_header - get fc frame header from skb + * @skb: packet + * + * This checks if there is a VLAN header and returns the data + * pointer to the start of the fc_frame_header. + * + * Returns pointer to the fc_frame_header + **/ +static inline struct fc_frame_header *i40e_fcoe_fc_frame_header( + struct sk_buff *skb) +{ + void *fh = skb->data + sizeof(struct fcoe_hdr); + + if (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q)) + fh += sizeof(struct vlan_hdr); + + return (struct fc_frame_header *)fh; +} + +/** + * i40e_fcoe_ddp_put - release the DDP context for a given exchange id + * @netdev: the corresponding net_device + * @xid: the exchange id that corresponding DDP context will be released + * + * This is the implementation of net_device_ops.ndo_fcoe_ddp_done + * and it is expected to be called by ULD, i.e., FCP layer of libfc + * to release the corresponding ddp context when the I/O is done. + * + * Returns : data length already ddp-ed in bytes + **/ +static int i40e_fcoe_ddp_put(struct net_device *netdev, u16 xid) +{ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + struct i40e_fcoe *fcoe = &pf->fcoe; + int len = 0; + struct i40e_fcoe_ddp *ddp = &fcoe->ddp[xid]; + + if (!fcoe || !ddp) + goto out; + + if (test_bit(__I40E_FCOE_DDP_DONE, &ddp->flags)) + len = ddp->len; + i40e_fcoe_ddp_unmap(pf, ddp); +out: + return len; +} + +/** + * i40e_fcoe_sw_init - sets up the HW for FCoE + * @pf: pointer to pf + * + * Returns 0 if FCoE is supported otherwise the error code + **/ +int i40e_init_pf_fcoe(struct i40e_pf *pf) +{ + struct i40e_hw *hw = &pf->hw; + u32 val; + + pf->flags &= ~I40E_FLAG_FCOE_ENABLED; + pf->num_fcoe_qps = 0; + pf->fcoe_hmc_cntx_num = 0; + pf->fcoe_hmc_filt_num = 0; + + if (!pf->hw.func_caps.fcoe) { + dev_info(&pf->pdev->dev, "FCoE capability is disabled\n"); + return 0; + } + + if (!pf->hw.func_caps.dcb) { + dev_warn(&pf->pdev->dev, + "Hardware is not DCB capable not enabling FCoE.\n"); + return 0; + } + + /* enable FCoE hash filter */ + val = rd32(hw, I40E_PFQF_HENA(1)); + val |= 1 << (I40E_FILTER_PCTYPE_FCOE_OX - 32); + val |= 1 << (I40E_FILTER_PCTYPE_FCOE_RX - 32); + val &= I40E_PFQF_HENA_PTYPE_ENA_MASK; + wr32(hw, I40E_PFQF_HENA(1), val); + + /* enable flag */ + pf->flags |= I40E_FLAG_FCOE_ENABLED; + pf->num_fcoe_qps = I40E_DEFAULT_FCOE; + + /* Reserve 4K DDP contexts and 20K filter size for FCoE */ + pf->fcoe_hmc_cntx_num = (1 << I40E_DMA_CNTX_SIZE_4K) * + I40E_DMA_CNTX_BASE_SIZE; + pf->fcoe_hmc_filt_num = pf->fcoe_hmc_cntx_num + + (1 << I40E_HASH_FILTER_SIZE_16K) * + I40E_HASH_FILTER_BASE_SIZE; + + /* FCoE object: max 16K filter buckets and 4K DMA contexts */ + pf->filter_settings.fcoe_filt_num = I40E_HASH_FILTER_SIZE_16K; + pf->filter_settings.fcoe_cntx_num = I40E_DMA_CNTX_SIZE_4K; + + /* Setup max frame with FCoE_MTU plus L2 overheads */ + val = rd32(hw, I40E_GLFCOE_RCTL); + val &= ~I40E_GLFCOE_RCTL_MAX_SIZE_MASK; + val |= ((FCOE_MTU + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN) + << I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT); + wr32(hw, I40E_GLFCOE_RCTL, val); + + dev_info(&pf->pdev->dev, "FCoE is supported.\n"); + return 0; +} + +/** + * i40e_get_fcoe_tc_map - Return TC map for FCoE APP + * @pf: pointer to pf + * + **/ +u8 i40e_get_fcoe_tc_map(struct i40e_pf *pf) +{ + struct i40e_ieee_app_priority_table app; + struct i40e_hw *hw = &pf->hw; + u8 enabled_tc = 0; + u8 tc, i; + /* Get the FCoE APP TLV */ + struct i40e_dcbx_config *dcbcfg = &hw->local_dcbx_config; + + for (i = 0; i < dcbcfg->numapps; i++) { + app = dcbcfg->app[i]; + if (app.selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && + app.protocolid == ETH_P_FCOE) { + tc = dcbcfg->etscfg.prioritytable[app.priority]; + enabled_tc |= (1 << tc); + break; + } + } + + /* TC0 if there is no TC defined for FCoE APP TLV */ + enabled_tc = enabled_tc ? enabled_tc : 0x1; + + return enabled_tc; +} + +/** + * i40e_fcoe_vsi_init - prepares the VSI context for creating a FCoE VSI + * @vsi: pointer to the associated VSI struct + * @ctxt: pointer to the associated VSI context to be passed to HW + * + * Returns 0 on success or < 0 on error + **/ +int i40e_fcoe_vsi_init(struct i40e_vsi *vsi, struct i40e_vsi_context *ctxt) +{ + struct i40e_aqc_vsi_properties_data *info = &ctxt->info; + struct i40e_pf *pf = vsi->back; + struct i40e_hw *hw = &pf->hw; + u8 enabled_tc = 0; + + if (!(pf->flags & I40E_FLAG_FCOE_ENABLED)) { + dev_err(&pf->pdev->dev, + "FCoE is not enabled for this device\n"); + return -EPERM; + } + + /* initialize the hardware for FCoE */ + ctxt->pf_num = hw->pf_id; + ctxt->vf_num = 0; + ctxt->uplink_seid = vsi->uplink_seid; + ctxt->connection_type = 0x1; + ctxt->flags = I40E_AQ_VSI_TYPE_PF; + + /* FCoE VSI would need the following sections */ + info->valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID | + I40E_AQ_VSI_PROP_QUEUE_OPT_VALID); + + /* FCoE VSI does not need these sections */ + info->valid_sections &= cpu_to_le16(~(I40E_AQ_VSI_PROP_SECURITY_VALID | + I40E_AQ_VSI_PROP_VLAN_VALID | + I40E_AQ_VSI_PROP_CAS_PV_VALID | + I40E_AQ_VSI_PROP_INGRESS_UP_VALID | + I40E_AQ_VSI_PROP_EGRESS_UP_VALID)); + + enabled_tc = i40e_get_fcoe_tc_map(pf); + i40e_vsi_setup_queue_map(vsi, ctxt, enabled_tc, true); + + /* set up queue option section: only enable FCoE */ + info->queueing_opt_flags = I40E_AQ_VSI_QUE_OPT_FCOE_ENA; + + return 0; +} + +/** + * i40e_fcoe_enable - this is the implementation of ndo_fcoe_enable, + * indicating the upper FCoE protocol stack is ready to use FCoE + * offload features. + * + * @netdev: pointer to the netdev that FCoE is created on + * + * Returns 0 on success + * + * in RTNL + * + **/ +int i40e_fcoe_enable(struct net_device *netdev) +{ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_vsi *vsi = np->vsi; + struct i40e_pf *pf = vsi->back; + struct i40e_fcoe *fcoe = &pf->fcoe; + + if (!(pf->flags & I40E_FLAG_FCOE_ENABLED)) { + netdev_err(netdev, "HW does not support FCoE.\n"); + return -ENODEV; + } + + if (vsi->type != I40E_VSI_FCOE) { + netdev_err(netdev, "interface does not support FCoE.\n"); + return -EBUSY; + } + + atomic_inc(&fcoe->refcnt); + + return 0; +} + +/** + * i40e_fcoe_disable- disables FCoE for upper FCoE protocol stack. + * @dev: pointer to the netdev that FCoE is created on + * + * Returns 0 on success + * + **/ +int i40e_fcoe_disable(struct net_device *netdev) +{ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_vsi *vsi = np->vsi; + struct i40e_pf *pf = vsi->back; + struct i40e_fcoe *fcoe = &pf->fcoe; + + if (!(pf->flags & I40E_FLAG_FCOE_ENABLED)) { + netdev_err(netdev, "device does not support FCoE\n"); + return -ENODEV; + } + if (vsi->type != I40E_VSI_FCOE) + return -EBUSY; + + if (!atomic_dec_and_test(&fcoe->refcnt)) + return -EINVAL; + + netdev_info(netdev, "FCoE disabled\n"); + + return 0; +} + +/** + * i40e_fcoe_dma_pool_free - free the per cpu pool for FCoE DDP + * @fcoe: the FCoE sw object + * @dev: the device that the pool is associated with + * @cpu: the cpu for this pool + * + **/ +static void i40e_fcoe_dma_pool_free(struct i40e_fcoe *fcoe, + struct device *dev, + unsigned int cpu) +{ + struct i40e_fcoe_ddp_pool *ddp_pool; + + ddp_pool = per_cpu_ptr(fcoe->ddp_pool, cpu); + if (!ddp_pool->pool) { + dev_warn(dev, "DDP pool already freed for cpu %d\n", cpu); + return; + } + dma_pool_destroy(ddp_pool->pool); + ddp_pool->pool = NULL; +} + +/** + * i40e_fcoe_dma_pool_create - per cpu pool for FCoE DDP + * @fcoe: the FCoE sw object + * @dev: the device that the pool is associated with + * @cpu: the cpu for this pool + * + * Returns 0 on successful or non zero on failure + * + **/ +static int i40e_fcoe_dma_pool_create(struct i40e_fcoe *fcoe, + struct device *dev, + unsigned int cpu) +{ + struct i40e_fcoe_ddp_pool *ddp_pool; + struct dma_pool *pool; + char pool_name[32]; + + ddp_pool = per_cpu_ptr(fcoe->ddp_pool, cpu); + if (ddp_pool && ddp_pool->pool) { + dev_warn(dev, "DDP pool already allocated for cpu %d\n", cpu); + return 0; + } + snprintf(pool_name, sizeof(pool_name), "i40e_fcoe_ddp_%d", cpu); + pool = dma_pool_create(pool_name, dev, I40E_FCOE_DDP_PTR_MAX, + I40E_FCOE_DDP_PTR_ALIGN, PAGE_SIZE); + if (!pool) { + dev_err(dev, "dma_pool_create %s failed\n", pool_name); + return -ENOMEM; + } + ddp_pool->pool = pool; + return 0; +} + +/** + * i40e_fcoe_free_ddp_resources - release FCoE DDP resources + * @vsi: the vsi FCoE is associated with + * + **/ +void i40e_fcoe_free_ddp_resources(struct i40e_vsi *vsi) +{ + struct i40e_pf *pf = vsi->back; + struct i40e_fcoe *fcoe = &pf->fcoe; + int cpu, i; + + /* do nothing if not FCoE VSI */ + if (vsi->type != I40E_VSI_FCOE) + return; + + /* do nothing if no DDP pools were allocated */ + if (!fcoe->ddp_pool) + return; + + for (i = 0; i < I40E_FCOE_DDP_MAX; i++) + i40e_fcoe_ddp_put(vsi->netdev, i); + + for_each_possible_cpu(cpu) + i40e_fcoe_dma_pool_free(fcoe, &pf->pdev->dev, cpu); + + free_percpu(fcoe->ddp_pool); + fcoe->ddp_pool = NULL; + + netdev_info(vsi->netdev, "VSI %d,%d FCoE DDP resources released\n", + vsi->id, vsi->seid); +} + +/** + * i40e_fcoe_setup_ddp_resources - allocate per cpu DDP resources + * @vsi: the VSI FCoE is associated with + * + * Returns 0 on successful or non zero on failure + * + **/ +int i40e_fcoe_setup_ddp_resources(struct i40e_vsi *vsi) +{ + struct i40e_pf *pf = vsi->back; + struct device *dev = &pf->pdev->dev; + struct i40e_fcoe *fcoe = &pf->fcoe; + unsigned int cpu; + int i; + + if (vsi->type != I40E_VSI_FCOE) + return -ENODEV; + + /* do nothing if no DDP pools were allocated */ + if (fcoe->ddp_pool) + return -EEXIST; + + /* allocate per CPU memory to track DDP pools */ + fcoe->ddp_pool = alloc_percpu(struct i40e_fcoe_ddp_pool); + if (!fcoe->ddp_pool) { + dev_err(&pf->pdev->dev, "failed to allocate percpu DDP\n"); + return -ENOMEM; + } + + /* allocate pci pool for each cpu */ + for_each_possible_cpu(cpu) { + if (!i40e_fcoe_dma_pool_create(fcoe, dev, cpu)) + continue; + + dev_err(dev, "failed to alloc DDP pool on cpu:%d\n", cpu); + i40e_fcoe_free_ddp_resources(vsi); + return -ENOMEM; + } + + /* initialize the sw context */ + for (i = 0; i < I40E_FCOE_DDP_MAX; i++) + i40e_fcoe_ddp_clear(&fcoe->ddp[i]); + + netdev_info(vsi->netdev, "VSI %d,%d FCoE DDP resources allocated\n", + vsi->id, vsi->seid); + + return 0; +} + +/** + * i40e_fcoe_handle_status - check the Programming Status for FCoE + * @rx_ring: the Rx ring for this descriptor + * @rx_desc: the Rx descriptor for Programming Status, not a packet descriptor. + * + * Check if this is the Rx Programming Status descriptor write-back for FCoE. + * This is used to verify if the context/filter programming or invalidation + * requested by SW to the HW is successful or not and take actions accordingly. + **/ +void i40e_fcoe_handle_status(struct i40e_ring *rx_ring, + union i40e_rx_desc *rx_desc, u8 prog_id) +{ + struct i40e_pf *pf = rx_ring->vsi->back; + struct i40e_fcoe *fcoe = &pf->fcoe; + struct i40e_fcoe_ddp *ddp; + u32 error; + u16 xid; + u64 qw; + + /* we only care for FCoE here */ + if (!i40e_fcoe_progid_is_fcoe(prog_id)) + return; + + xid = le32_to_cpu(rx_desc->wb.qword0.hi_dword.fcoe_param) & + (I40E_FCOE_DDP_MAX - 1); + + if (!i40e_fcoe_xid_is_valid(xid)) + return; + + ddp = &fcoe->ddp[xid]; + WARN_ON(xid != ddp->xid); + + qw = le64_to_cpu(rx_desc->wb.qword1.status_error_len); + error = (qw & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >> + I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT; + + /* DDP context programming status: failure or success */ + if (prog_id == I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_PROG_STATUS) { + if (I40E_RX_PROG_FCOE_ERROR_TBL_FULL(error)) { + dev_err(&pf->pdev->dev, "xid %x ddp->xid %x TABLE FULL\n", + xid, ddp->xid); + ddp->prerr |= I40E_RX_PROG_FCOE_ERROR_TBL_FULL_BIT; + } + if (I40E_RX_PROG_FCOE_ERROR_CONFLICT(error)) { + dev_err(&pf->pdev->dev, "xid %x ddp->xid %x CONFLICT\n", + xid, ddp->xid); + ddp->prerr |= I40E_RX_PROG_FCOE_ERROR_CONFLICT_BIT; + } + } + + /* DDP context invalidation status: failure or success */ + if (prog_id == I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_INVL_STATUS) { + if (I40E_RX_PROG_FCOE_ERROR_INVLFAIL(error)) { + dev_err(&pf->pdev->dev, "xid %x ddp->xid %x INVALIDATION FAILURE\n", + xid, ddp->xid); + ddp->prerr |= I40E_RX_PROG_FCOE_ERROR_INVLFAIL_BIT; + } + /* clear the flag so we can retry invalidation */ + clear_bit(__I40E_FCOE_DDP_ABORTED, &ddp->flags); + } + + /* unmap DMA */ + i40e_fcoe_ddp_unmap(pf, ddp); + i40e_fcoe_ddp_clear(ddp); +} + +/** + * i40e_fcoe_handle_offload - check ddp status and mark it done + * @adapter: i40e adapter + * @rx_desc: advanced rx descriptor + * @skb: the skb holding the received data + * + * This checks ddp status. + * + * Returns : < 0 indicates an error or not a FCOE ddp, 0 indicates + * not passing the skb to ULD, > 0 indicates is the length of data + * being ddped. + * + **/ +int i40e_fcoe_handle_offload(struct i40e_ring *rx_ring, + union i40e_rx_desc *rx_desc, + struct sk_buff *skb) +{ + struct i40e_pf *pf = rx_ring->vsi->back; + struct i40e_fcoe *fcoe = &pf->fcoe; + struct fc_frame_header *fh = NULL; + struct i40e_fcoe_ddp *ddp = NULL; + u32 status, fltstat; + u32 error, fcerr; + int rc = -EINVAL; + u16 ptype; + u16 xid; + u64 qw; + + /* check this rxd is for programming status */ + qw = le64_to_cpu(rx_desc->wb.qword1.status_error_len); + /* packet descriptor, check packet type */ + ptype = (qw & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; + if (!i40e_rx_is_fcoe(ptype)) + goto out_no_ddp; + + error = (qw & I40E_RXD_QW1_ERROR_MASK) >> I40E_RXD_QW1_ERROR_SHIFT; + fcerr = (error >> I40E_RX_DESC_ERROR_L3L4E_SHIFT) & + I40E_RX_DESC_FCOE_ERROR_MASK; + + /* check stateless offload error */ + if (unlikely(fcerr == I40E_RX_DESC_ERROR_L3L4E_PROT)) { + dev_err(&pf->pdev->dev, "Protocol Error\n"); + skb->ip_summed = CHECKSUM_NONE; + } else { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + + /* check hw status on ddp */ + status = (qw & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; + fltstat = (status >> I40E_RX_DESC_STATUS_FLTSTAT_SHIFT) & + I40E_RX_DESC_FLTSTAT_FCMASK; + + /* now we are ready to check DDP */ + fh = i40e_fcoe_fc_frame_header(skb); + xid = i40e_fcoe_fc_get_xid(fh); + if (!i40e_fcoe_xid_is_valid(xid)) + goto out_no_ddp; + + /* non DDP normal receive, return to the protocol stack */ + if (fltstat == I40E_RX_DESC_FLTSTAT_NOMTCH) + goto out_no_ddp; + + /* do we have a sw ddp context setup ? */ + ddp = &fcoe->ddp[xid]; + if (!ddp->sgl) + goto out_no_ddp; + + /* fetch xid from hw rxd wb, which should match up the sw ctxt */ + xid = le16_to_cpu(rx_desc->wb.qword0.lo_dword.mirr_fcoe.fcoe_ctx_id); + if (ddp->xid != xid) { + dev_err(&pf->pdev->dev, "xid 0x%x does not match ctx_xid 0x%x\n", + ddp->xid, xid); + goto out_put_ddp; + } + + /* the same exchange has already errored out */ + if (ddp->fcerr) { + dev_err(&pf->pdev->dev, "xid 0x%x fcerr 0x%x reported fcer 0x%x\n", + xid, ddp->fcerr, fcerr); + goto out_put_ddp; + } + + /* fcoe param is valid by now with correct DDPed length */ + ddp->len = le32_to_cpu(rx_desc->wb.qword0.hi_dword.fcoe_param); + ddp->fcerr = fcerr; + /* header posting only, useful only for target mode and debugging */ + if (fltstat == I40E_RX_DESC_FLTSTAT_DDP) { + /* For target mode, we get header of the last packet but it + * does not have the FCoE trailer field, i.e., CRC and EOF + * Ordered Set since they are offloaded by the HW, so fill + * it up correspondingly to allow the packet to pass through + * to the upper protocol stack. + */ + u32 f_ctl = ntoh24(fh->fh_f_ctl); + + if ((f_ctl & FC_FC_END_SEQ) && + (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA)) { + struct fcoe_crc_eof *crc = NULL; + + crc = (struct fcoe_crc_eof *)skb_put(skb, sizeof(*crc)); + crc->fcoe_eof = FC_EOF_T; + } else { + /* otherwise, drop the header only frame */ + rc = 0; + goto out_no_ddp; + } + } + +out_put_ddp: + /* either we got RSP or we have an error, unmap DMA in both cases */ + i40e_fcoe_ddp_unmap(pf, ddp); + if (ddp->len && !ddp->fcerr) { + int pkts; + + rc = ddp->len; + i40e_fcoe_ddp_clear(ddp); + ddp->len = rc; + pkts = DIV_ROUND_UP(rc, 2048); + rx_ring->stats.bytes += rc; + rx_ring->stats.packets += pkts; + rx_ring->q_vector->rx.total_bytes += rc; + rx_ring->q_vector->rx.total_packets += pkts; + set_bit(__I40E_FCOE_DDP_DONE, &ddp->flags); + } + +out_no_ddp: + return rc; +} + +/** + * i40e_fcoe_ddp_setup - called to set up ddp context + * @netdev: the corresponding net_device + * @xid: the exchange id requesting ddp + * @sgl: the scatter-gather list for this request + * @sgc: the number of scatter-gather items + * @target_mode: indicates this is a DDP request for target + * + * Returns : 1 for success and 0 for no DDP on this I/O + **/ +static int i40e_fcoe_ddp_setup(struct net_device *netdev, u16 xid, + struct scatterlist *sgl, unsigned int sgc, + int target_mode) +{ + static const unsigned int bufflen = I40E_FCOE_DDP_BUF_MIN; + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_fcoe_ddp_pool *ddp_pool; + struct i40e_pf *pf = np->vsi->back; + struct i40e_fcoe *fcoe = &pf->fcoe; + unsigned int i, j, dmacount; + struct i40e_fcoe_ddp *ddp; + unsigned int firstoff = 0; + unsigned int thisoff = 0; + unsigned int thislen = 0; + struct scatterlist *sg; + dma_addr_t addr = 0; + unsigned int len; + + if (xid >= I40E_FCOE_DDP_MAX) { + dev_warn(&pf->pdev->dev, "xid=0x%x out-of-range\n", xid); + return 0; + } + + /* no DDP if we are already down or resetting */ + if (test_bit(__I40E_DOWN, &pf->state) || + test_bit(__I40E_NEEDS_RESTART, &pf->state)) { + dev_info(&pf->pdev->dev, "xid=0x%x device in reset/down\n", + xid); + return 0; + } + + ddp = &fcoe->ddp[xid]; + if (ddp->sgl) { + dev_info(&pf->pdev->dev, "xid 0x%x w/ non-null sgl=%p nents=%d\n", + xid, ddp->sgl, ddp->sgc); + return 0; + } + i40e_fcoe_ddp_clear(ddp); + + if (!fcoe->ddp_pool) { + dev_info(&pf->pdev->dev, "No DDP pool, xid 0x%x\n", xid); + return 0; + } + + ddp_pool = per_cpu_ptr(fcoe->ddp_pool, get_cpu()); + if (!ddp_pool->pool) { + dev_info(&pf->pdev->dev, "No percpu ddp pool, xid 0x%x\n", xid); + goto out_noddp; + } + + /* setup dma from scsi command sgl */ + dmacount = dma_map_sg(&pf->pdev->dev, sgl, sgc, DMA_FROM_DEVICE); + if (dmacount == 0) { + dev_info(&pf->pdev->dev, "dma_map_sg for sgl %p, sgc %d failed\n", + sgl, sgc); + goto out_noddp_unmap; + } + + /* alloc the udl from our ddp pool */ + ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_ATOMIC, &ddp->udp); + if (!ddp->udl) { + dev_info(&pf->pdev->dev, + "Failed allocated ddp context, xid 0x%x\n", xid); + goto out_noddp_unmap; + } + + j = 0; + ddp->len = 0; + for_each_sg(sgl, sg, dmacount, i) { + addr = sg_dma_address(sg); + len = sg_dma_len(sg); + ddp->len += len; + while (len) { + /* max number of buffers allowed in one DDP context */ + if (j >= I40E_FCOE_DDP_BUFFCNT_MAX) { + dev_info(&pf->pdev->dev, + "xid=%x:%d,%d,%d:addr=%llx not enough descriptors\n", + xid, i, j, dmacount, (u64)addr); + goto out_noddp_free; + } + + /* get the offset of length of current buffer */ + thisoff = addr & ((dma_addr_t)bufflen - 1); + thislen = min_t(unsigned int, (bufflen - thisoff), len); + /* all but the 1st buffer (j == 0) + * must be aligned on bufflen + */ + if ((j != 0) && (thisoff)) + goto out_noddp_free; + + /* all but the last buffer + * ((i == (dmacount - 1)) && (thislen == len)) + * must end at bufflen + */ + if (((i != (dmacount - 1)) || (thislen != len)) && + ((thislen + thisoff) != bufflen)) + goto out_noddp_free; + + ddp->udl[j] = (u64)(addr - thisoff); + /* only the first buffer may have none-zero offset */ + if (j == 0) + firstoff = thisoff; + len -= thislen; + addr += thislen; + j++; + } + } + /* only the last buffer may have non-full bufflen */ + ddp->lastsize = thisoff + thislen; + ddp->firstoff = firstoff; + ddp->list_len = j; + ddp->pool = ddp_pool->pool; + ddp->sgl = sgl; + ddp->sgc = sgc; + ddp->xid = xid; + if (target_mode) + set_bit(__I40E_FCOE_DDP_TARGET, &ddp->flags); + set_bit(__I40E_FCOE_DDP_INITALIZED, &ddp->flags); + + put_cpu(); + return 1; /* Success */ + +out_noddp_free: + dma_pool_free(ddp->pool, ddp->udl, ddp->udp); + i40e_fcoe_ddp_clear(ddp); + +out_noddp_unmap: + dma_unmap_sg(&pf->pdev->dev, sgl, sgc, DMA_FROM_DEVICE); +out_noddp: + put_cpu(); + return 0; +} + +/** + * i40e_fcoe_ddp_get - called to set up ddp context in initiator mode + * @netdev: the corresponding net_device + * @xid: the exchange id requesting ddp + * @sgl: the scatter-gather list for this request + * @sgc: the number of scatter-gather items + * + * This is the implementation of net_device_ops.ndo_fcoe_ddp_setup + * and is expected to be called from ULD, e.g., FCP layer of libfc + * to set up ddp for the corresponding xid of the given sglist for + * the corresponding I/O. + * + * Returns : 1 for success and 0 for no ddp + **/ +static int i40e_fcoe_ddp_get(struct net_device *netdev, u16 xid, + struct scatterlist *sgl, unsigned int sgc) +{ + return i40e_fcoe_ddp_setup(netdev, xid, sgl, sgc, 0); +} + +/** + * i40e_fcoe_ddp_target - called to set up ddp context in target mode + * @netdev: the corresponding net_device + * @xid: the exchange id requesting ddp + * @sgl: the scatter-gather list for this request + * @sgc: the number of scatter-gather items + * + * This is the implementation of net_device_ops.ndo_fcoe_ddp_target + * and is expected to be called from ULD, e.g., FCP layer of libfc + * to set up ddp for the corresponding xid of the given sglist for + * the corresponding I/O. The DDP in target mode is a write I/O request + * from the initiator. + * + * Returns : 1 for success and 0 for no ddp + **/ +static int i40e_fcoe_ddp_target(struct net_device *netdev, u16 xid, + struct scatterlist *sgl, unsigned int sgc) +{ + return i40e_fcoe_ddp_setup(netdev, xid, sgl, sgc, 1); +} + +/** + * i40e_fcoe_program_ddp - programs the HW DDP related descriptors + * @tx_ring: transmit ring for this packet + * @skb: the packet to be sent out + * @sof: the SOF to indicate class of service + * + * Determine if it is READ/WRITE command, and finds out if there is + * a matching SW DDP context for this command. DDP is applicable + * only in case of READ if initiator or WRITE in case of + * responder (via checking XFER_RDY). + * + * Note: caller checks sof and ddp sw context + * + * Returns : none + * + **/ +static void i40e_fcoe_program_ddp(struct i40e_ring *tx_ring, + struct sk_buff *skb, + struct i40e_fcoe_ddp *ddp, u8 sof) +{ + struct i40e_fcoe_filter_context_desc *filter_desc = NULL; + struct i40e_fcoe_queue_context_desc *queue_desc = NULL; + struct i40e_fcoe_ddp_context_desc *ddp_desc = NULL; + struct i40e_pf *pf = tx_ring->vsi->back; + u16 i = tx_ring->next_to_use; + struct fc_frame_header *fh; + u64 flags_rsvd_lanq = 0; + bool target_mode; + + /* check if abort is still pending */ + if (test_bit(__I40E_FCOE_DDP_ABORTED, &ddp->flags)) { + dev_warn(&pf->pdev->dev, + "DDP abort is still pending xid:%hx and ddp->flags:%lx:\n", + ddp->xid, ddp->flags); + return; + } + + /* set the flag to indicate this is programmed */ + if (test_and_set_bit(__I40E_FCOE_DDP_PROGRAMMED, &ddp->flags)) { + dev_warn(&pf->pdev->dev, + "DDP is already programmed for xid:%hx and ddp->flags:%lx:\n", + ddp->xid, ddp->flags); + return; + } + + /* Prepare the DDP context descriptor */ + ddp_desc = I40E_DDP_CONTEXT_DESC(tx_ring, i); + i++; + if (i == tx_ring->count) + i = 0; + + ddp_desc->type_cmd_foff_lsize = + cpu_to_le64(I40E_TX_DESC_DTYPE_DDP_CTX | + ((u64)I40E_FCOE_DDP_CTX_DESC_BSIZE_4K << + I40E_FCOE_DDP_CTX_QW1_CMD_SHIFT) | + ((u64)ddp->firstoff << + I40E_FCOE_DDP_CTX_QW1_FOFF_SHIFT) | + ((u64)ddp->lastsize << + I40E_FCOE_DDP_CTX_QW1_LSIZE_SHIFT)); + ddp_desc->rsvd = cpu_to_le64(0); + + /* target mode needs last packet in the sequence */ + target_mode = test_bit(__I40E_FCOE_DDP_TARGET, &ddp->flags); + if (target_mode) + ddp_desc->type_cmd_foff_lsize |= + cpu_to_le64(I40E_FCOE_DDP_CTX_DESC_LASTSEQH); + + /* Prepare queue_context descriptor */ + queue_desc = I40E_QUEUE_CONTEXT_DESC(tx_ring, i++); + if (i == tx_ring->count) + i = 0; + queue_desc->dmaindx_fbase = cpu_to_le64(ddp->xid | ((u64)ddp->udp)); + queue_desc->flen_tph = cpu_to_le64(ddp->list_len | + ((u64)(I40E_FCOE_QUEUE_CTX_DESC_TPHRDESC | + I40E_FCOE_QUEUE_CTX_DESC_TPHDATA) << + I40E_FCOE_QUEUE_CTX_QW1_TPH_SHIFT)); + + /* Prepare filter_context_desc */ + filter_desc = I40E_FILTER_CONTEXT_DESC(tx_ring, i); + i++; + if (i == tx_ring->count) + i = 0; + + fh = (struct fc_frame_header *)skb_transport_header(skb); + filter_desc->param = cpu_to_le32(ntohl(fh->fh_parm_offset)); + filter_desc->seqn = cpu_to_le16(ntohs(fh->fh_seq_cnt)); + filter_desc->rsvd_dmaindx = cpu_to_le16(ddp->xid << + I40E_FCOE_FILTER_CTX_QW0_DMAINDX_SHIFT); + + flags_rsvd_lanq = I40E_FCOE_FILTER_CTX_DESC_CTYP_DDP; + flags_rsvd_lanq |= (u64)(target_mode ? + I40E_FCOE_FILTER_CTX_DESC_ENODE_RSP : + I40E_FCOE_FILTER_CTX_DESC_ENODE_INIT); + + flags_rsvd_lanq |= (u64)((sof == FC_SOF_I2 || sof == FC_SOF_N2) ? + I40E_FCOE_FILTER_CTX_DESC_FC_CLASS2 : + I40E_FCOE_FILTER_CTX_DESC_FC_CLASS3); + + flags_rsvd_lanq |= ((u64)skb->queue_mapping << + I40E_FCOE_FILTER_CTX_QW1_LANQINDX_SHIFT); + filter_desc->flags_rsvd_lanq = cpu_to_le64(flags_rsvd_lanq); + + /* By this time, all offload related descriptors has been programmed */ + tx_ring->next_to_use = i; +} + +/** + * i40e_fcoe_invalidate_ddp - invalidates DDP in case of abort + * @tx_ring: transmit ring for this packet + * @skb: the packet associated w/ this DDP invalidation, i.e., ABTS + * @ddp: the SW DDP context for this DDP + * + * Programs the Tx context descriptor to do DDP invalidation. + **/ +static void i40e_fcoe_invalidate_ddp(struct i40e_ring *tx_ring, + struct sk_buff *skb, + struct i40e_fcoe_ddp *ddp) +{ + struct i40e_tx_context_desc *context_desc; + int i; + + if (test_and_set_bit(__I40E_FCOE_DDP_ABORTED, &ddp->flags)) + return; + + i = tx_ring->next_to_use; + context_desc = I40E_TX_CTXTDESC(tx_ring, i); + i++; + if (i == tx_ring->count) + i = 0; + + context_desc->tunneling_params = cpu_to_le32(0); + context_desc->l2tag2 = cpu_to_le16(0); + context_desc->rsvd = cpu_to_le16(0); + context_desc->type_cmd_tso_mss = cpu_to_le64( + I40E_TX_DESC_DTYPE_FCOE_CTX | + (I40E_FCOE_TX_CTX_DESC_OPCODE_DDP_CTX_INVL << + I40E_TXD_CTX_QW1_CMD_SHIFT) | + (I40E_FCOE_TX_CTX_DESC_OPCODE_SINGLE_SEND << + I40E_TXD_CTX_QW1_CMD_SHIFT)); + tx_ring->next_to_use = i; +} + +/** + * i40e_fcoe_handle_ddp - check we should setup or invalidate DDP + * @tx_ring: transmit ring for this packet + * @skb: the packet to be sent out + * @sof: the SOF to indicate class of service + * + * Determine if it is ABTS/READ/XFER_RDY, and finds out if there is + * a matching SW DDP context for this command. DDP is applicable + * only in case of READ if initiator or WRITE in case of + * responder (via checking XFER_RDY). In case this is an ABTS, send + * just invalidate the context. + **/ +static void i40e_fcoe_handle_ddp(struct i40e_ring *tx_ring, + struct sk_buff *skb, u8 sof) +{ + struct i40e_pf *pf = tx_ring->vsi->back; + struct i40e_fcoe *fcoe = &pf->fcoe; + struct fc_frame_header *fh; + struct i40e_fcoe_ddp *ddp; + u32 f_ctl; + u8 r_ctl; + u16 xid; + + fh = (struct fc_frame_header *)skb_transport_header(skb); + f_ctl = ntoh24(fh->fh_f_ctl); + r_ctl = fh->fh_r_ctl; + ddp = NULL; + + if ((r_ctl == FC_RCTL_DD_DATA_DESC) && (f_ctl & FC_FC_EX_CTX)) { + /* exchange responder? if so, XFER_RDY for write */ + xid = ntohs(fh->fh_rx_id); + if (i40e_fcoe_xid_is_valid(xid)) { + ddp = &fcoe->ddp[xid]; + if ((ddp->xid == xid) && + (test_bit(__I40E_FCOE_DDP_TARGET, &ddp->flags))) + i40e_fcoe_program_ddp(tx_ring, skb, ddp, sof); + } + } else if (r_ctl == FC_RCTL_DD_UNSOL_CMD) { + /* exchange originator, check READ cmd */ + xid = ntohs(fh->fh_ox_id); + if (i40e_fcoe_xid_is_valid(xid)) { + ddp = &fcoe->ddp[xid]; + if ((ddp->xid == xid) && + (!test_bit(__I40E_FCOE_DDP_TARGET, &ddp->flags))) + i40e_fcoe_program_ddp(tx_ring, skb, ddp, sof); + } + } else if (r_ctl == FC_RCTL_BA_ABTS) { + /* exchange originator, check ABTS */ + xid = ntohs(fh->fh_ox_id); + if (i40e_fcoe_xid_is_valid(xid)) { + ddp = &fcoe->ddp[xid]; + if ((ddp->xid == xid) && + (!test_bit(__I40E_FCOE_DDP_TARGET, &ddp->flags))) + i40e_fcoe_invalidate_ddp(tx_ring, skb, ddp); + } + } +} + +/** + * i40e_fcoe_tso - set up FCoE TSO + * @tx_ring: ring to send buffer on + * @skb: send buffer + * @tx_flags: collected send information + * @hdr_len: the tso header length + * @sof: the SOF to indicate class of service + * + * Note must already have sof checked to be either class 2 or class 3 before + * calling this function. + * + * Returns 1 to indicate sequence segmentation offload is properly setup + * or returns 0 to indicate no tso is needed, otherwise returns error + * code to drop the frame. + **/ +static int i40e_fcoe_tso(struct i40e_ring *tx_ring, + struct sk_buff *skb, + u32 tx_flags, u8 *hdr_len, u8 sof) +{ + struct i40e_tx_context_desc *context_desc; + u32 cd_type, cd_cmd, cd_tso_len, cd_mss; + struct fc_frame_header *fh; + u64 cd_type_cmd_tso_mss; + + /* must match gso type as FCoE */ + if (!skb_is_gso(skb)) + return 0; + + /* is it the expected gso type for FCoE ?*/ + if (skb_shinfo(skb)->gso_type != SKB_GSO_FCOE) { + netdev_err(skb->dev, + "wrong gso type %d:expecting SKB_GSO_FCOE\n", + skb_shinfo(skb)->gso_type); + return -EINVAL; + } + + /* header and trailer are inserted by hw */ + *hdr_len = skb_transport_offset(skb) + sizeof(struct fc_frame_header) + + sizeof(struct fcoe_crc_eof); + + /* check sof to decide a class 2 or 3 TSO */ + if (likely(i40e_fcoe_sof_is_class3(sof))) + cd_cmd = I40E_FCOE_TX_CTX_DESC_OPCODE_TSO_FC_CLASS3; + else + cd_cmd = I40E_FCOE_TX_CTX_DESC_OPCODE_TSO_FC_CLASS2; + + /* param field valid? */ + fh = (struct fc_frame_header *)skb_transport_header(skb); + if (fh->fh_f_ctl[2] & FC_FC_REL_OFF) + cd_cmd |= I40E_FCOE_TX_CTX_DESC_RELOFF; + + /* fill the field values */ + cd_type = I40E_TX_DESC_DTYPE_FCOE_CTX; + cd_tso_len = skb->len - *hdr_len; + cd_mss = skb_shinfo(skb)->gso_size; + cd_type_cmd_tso_mss = + ((u64)cd_type << I40E_TXD_CTX_QW1_DTYPE_SHIFT) | + ((u64)cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) | + ((u64)cd_tso_len << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) | + ((u64)cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT); + + /* grab the next descriptor */ + context_desc = I40E_TX_CTXTDESC(tx_ring, tx_ring->next_to_use); + tx_ring->next_to_use++; + if (tx_ring->next_to_use == tx_ring->count) + tx_ring->next_to_use = 0; + + context_desc->tunneling_params = 0; + context_desc->l2tag2 = cpu_to_le16((tx_flags & I40E_TX_FLAGS_VLAN_MASK) + >> I40E_TX_FLAGS_VLAN_SHIFT); + context_desc->type_cmd_tso_mss = cpu_to_le64(cd_type_cmd_tso_mss); + + return 1; +} + +/** + * i40e_fcoe_tx_map - build the tx descriptor + * @tx_ring: ring to send buffer on + * @skb: send buffer + * @first: first buffer info buffer to use + * @tx_flags: collected send information + * @hdr_len: ptr to the size of the packet header + * @eof: the frame eof value + * + * Note, for FCoE, sof and eof are already checked + **/ +static void i40e_fcoe_tx_map(struct i40e_ring *tx_ring, + struct sk_buff *skb, + struct i40e_tx_buffer *first, + u32 tx_flags, u8 hdr_len, u8 eof) +{ + u32 td_offset = 0; + u32 td_cmd = 0; + u32 maclen; + + /* insert CRC */ + td_cmd = I40E_TX_DESC_CMD_ICRC; + + /* setup MACLEN */ + maclen = skb_network_offset(skb); + if (tx_flags & I40E_TX_FLAGS_SW_VLAN) + maclen += sizeof(struct vlan_hdr); + + if (skb->protocol == htons(ETH_P_FCOE)) { + /* for FCoE, maclen should exclude ether type */ + maclen -= 2; + /* setup type as FCoE and EOF insertion */ + td_cmd |= (I40E_TX_DESC_CMD_FCOET | i40e_fcoe_ctxt_eof(eof)); + /* setup FCoELEN and FCLEN */ + td_offset |= ((((sizeof(struct fcoe_hdr) + 2) >> 2) << + I40E_TX_DESC_LENGTH_IPLEN_SHIFT) | + ((sizeof(struct fc_frame_header) >> 2) << + I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT)); + /* trim to exclude trailer */ + pskb_trim(skb, skb->len - sizeof(struct fcoe_crc_eof)); + } + + /* MACLEN is ether header length in words not bytes */ + td_offset |= (maclen >> 1) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT; + + return i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len, + td_cmd, td_offset); +} + +/** + * i40e_fcoe_set_skb_header - adjust skb header point for FIP/FCoE/FC + * @skb: the skb to be adjusted + * + * Returns true if this skb is a FCoE/FIP or VLAN carried FCoE/FIP and then + * adjusts the skb header pointers correspondingly. Otherwise, returns false. + **/ +static inline int i40e_fcoe_set_skb_header(struct sk_buff *skb) +{ + __be16 protocol = skb->protocol; + + skb_reset_mac_header(skb); + skb->mac_len = sizeof(struct ethhdr); + if (protocol == htons(ETH_P_8021Q)) { + struct vlan_ethhdr *veth = (struct vlan_ethhdr *)eth_hdr(skb); + + protocol = veth->h_vlan_encapsulated_proto; + skb->mac_len += sizeof(struct vlan_hdr); + } + + /* FCoE or FIP only */ + if ((protocol != htons(ETH_P_FIP)) && + (protocol != htons(ETH_P_FCOE))) + return -EINVAL; + + /* set header to L2 of FCoE/FIP */ + skb_set_network_header(skb, skb->mac_len); + if (protocol == htons(ETH_P_FIP)) + return 0; + + /* set header to L3 of FC */ + skb_set_transport_header(skb, skb->mac_len + sizeof(struct fcoe_hdr)); + return 0; +} + +/** + * i40e_fcoe_xmit_frame - transmit buffer + * @skb: send buffer + * @netdev: the fcoe netdev + * + * Returns 0 if sent, else an error code + **/ +static netdev_tx_t i40e_fcoe_xmit_frame(struct sk_buff *skb, + struct net_device *netdev) +{ + struct i40e_netdev_priv *np = netdev_priv(skb->dev); + struct i40e_vsi *vsi = np->vsi; + struct i40e_ring *tx_ring = vsi->tx_rings[skb->queue_mapping]; + struct i40e_tx_buffer *first; + __be16 protocol = skb->protocol; + + u32 tx_flags = 0; + u8 hdr_len = 0; + u8 sof = 0; + u8 eof = 0; + int fso; + + if (i40e_fcoe_set_skb_header(skb)) + goto out_drop; + + if (!i40e_xmit_descriptor_count(skb, tx_ring)) + return NETDEV_TX_BUSY; + + /* prepare the xmit flags */ + if (i40e_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags)) + goto out_drop; + + /* record the location of the first descriptor for this packet */ + first = &tx_ring->tx_bi[tx_ring->next_to_use]; + + if (protocol == htons(ETH_P_8021Q)) { + struct vlan_ethhdr *veth = (struct vlan_ethhdr *)eth_hdr(skb); + + protocol = veth->h_vlan_encapsulated_proto; + } + /* FIP is a regular L2 traffic w/o offload */ + if (protocol == htons(ETH_P_FIP)) + goto out_send; + + /* check sof and eof, only supports FC Class 2 or 3 */ + if (i40e_fcoe_fc_sof(skb, &sof) || i40e_fcoe_fc_eof(skb, &eof)) { + netdev_err(netdev, "SOF/EOF error:%02x - %02x\n", sof, eof); + goto out_drop; + } + + /* always do FCCRC for FCoE */ + tx_flags |= I40E_TX_FLAGS_FCCRC; + + /* check we should do sequence offload */ + fso = i40e_fcoe_tso(tx_ring, skb, tx_flags, &hdr_len, sof); + if (fso < 0) + goto out_drop; + else if (fso) + tx_flags |= I40E_TX_FLAGS_FSO; + else + i40e_fcoe_handle_ddp(tx_ring, skb, sof); + +out_send: + /* send out the packet */ + i40e_fcoe_tx_map(tx_ring, skb, first, tx_flags, hdr_len, eof); + + i40e_maybe_stop_tx(tx_ring, DESC_NEEDED); + return NETDEV_TX_OK; + +out_drop: + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +/** + * i40e_fcoe_change_mtu - NDO callback to change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns error as operation not permitted + * + **/ +static int i40e_fcoe_change_mtu(struct net_device *netdev, int new_mtu) +{ + netdev_warn(netdev, "MTU change is not supported on FCoE interfaces\n"); + return -EPERM; +} + +/** + * i40e_fcoe_set_features - set the netdev feature flags + * @netdev: ptr to the netdev being adjusted + * @features: the feature set that the stack is suggesting + * + **/ +static int i40e_fcoe_set_features(struct net_device *netdev, + netdev_features_t features) +{ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_vsi *vsi = np->vsi; + + if (features & NETIF_F_HW_VLAN_CTAG_RX) + i40e_vlan_stripping_enable(vsi); + else + i40e_vlan_stripping_disable(vsi); + + return 0; +} + + +static const struct net_device_ops i40e_fcoe_netdev_ops = { + .ndo_open = i40e_open, + .ndo_stop = i40e_close, + .ndo_get_stats64 = i40e_get_netdev_stats_struct, + .ndo_set_rx_mode = i40e_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = i40e_set_mac, + .ndo_change_mtu = i40e_fcoe_change_mtu, + .ndo_do_ioctl = i40e_ioctl, + .ndo_tx_timeout = i40e_tx_timeout, + .ndo_vlan_rx_add_vid = i40e_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = i40e_vlan_rx_kill_vid, + .ndo_setup_tc = i40e_setup_tc, + +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = i40e_netpoll, +#endif + .ndo_start_xmit = i40e_fcoe_xmit_frame, + .ndo_fcoe_enable = i40e_fcoe_enable, + .ndo_fcoe_disable = i40e_fcoe_disable, + .ndo_fcoe_ddp_setup = i40e_fcoe_ddp_get, + .ndo_fcoe_ddp_done = i40e_fcoe_ddp_put, + .ndo_fcoe_ddp_target = i40e_fcoe_ddp_target, + .ndo_set_features = i40e_fcoe_set_features, +}; + +/** + * i40e_fcoe_config_netdev - prepares the VSI context for creating a FCoE VSI + * @vsi: pointer to the associated VSI struct + * @ctxt: pointer to the associated VSI context to be passed to HW + * + * Returns 0 on success or < 0 on error + **/ +void i40e_fcoe_config_netdev(struct net_device *netdev, struct i40e_vsi *vsi) +{ + struct i40e_hw *hw = &vsi->back->hw; + struct i40e_pf *pf = vsi->back; + + if (vsi->type != I40E_VSI_FCOE) + return; + + netdev->features = (NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_HW_VLAN_CTAG_FILTER); + + netdev->vlan_features = netdev->features; + netdev->vlan_features &= ~(NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_HW_VLAN_CTAG_FILTER); + netdev->fcoe_ddp_xid = I40E_FCOE_DDP_MAX - 1; + netdev->features |= NETIF_F_ALL_FCOE; + netdev->vlan_features |= NETIF_F_ALL_FCOE; + netdev->hw_features |= netdev->features; + netdev->priv_flags |= IFF_UNICAST_FLT; + netdev->priv_flags |= IFF_SUPP_NOFCS; + + strlcpy(netdev->name, "fcoe%d", IFNAMSIZ-1); + netdev->mtu = FCOE_MTU; + SET_NETDEV_DEV(netdev, &pf->pdev->dev); + i40e_add_filter(vsi, hw->mac.san_addr, 0, false, false); + i40e_add_filter(vsi, (u8[6]) FC_FCOE_FLOGI_MAC, 0, false, false); + i40e_add_filter(vsi, FIP_ALL_FCOE_MACS, 0, false, false); + i40e_add_filter(vsi, FIP_ALL_ENODE_MACS, 0, false, false); + i40e_add_filter(vsi, FIP_ALL_VN2VN_MACS, 0, false, false); + i40e_add_filter(vsi, FIP_ALL_P2P_MACS, 0, false, false); + + /* use san mac */ + ether_addr_copy(netdev->dev_addr, hw->mac.san_addr); + ether_addr_copy(netdev->perm_addr, hw->mac.san_addr); + /* fcoe netdev ops */ + netdev->netdev_ops = &i40e_fcoe_netdev_ops; +} + +/** + * i40e_fcoe_vsi_setup - allocate and set up FCoE VSI + * @pf: the pf that VSI is associated with + * + **/ +void i40e_fcoe_vsi_setup(struct i40e_pf *pf) +{ + struct i40e_vsi *vsi; + u16 seid; + int i; + + if (!(pf->flags & I40E_FLAG_FCOE_ENABLED)) + return; + + BUG_ON(!pf->vsi[pf->lan_vsi]); + + for (i = 0; i < pf->num_alloc_vsi; i++) { + vsi = pf->vsi[i]; + if (vsi && vsi->type == I40E_VSI_FCOE) { + dev_warn(&pf->pdev->dev, + "FCoE VSI already created\n"); + return; + } + } + + seid = pf->vsi[pf->lan_vsi]->seid; + vsi = i40e_vsi_setup(pf, I40E_VSI_FCOE, seid, 0); + if (vsi) { + dev_dbg(&pf->pdev->dev, + "Successfully created FCoE VSI seid %d id %d uplink_seid %d pf seid %d\n", + vsi->seid, vsi->id, vsi->uplink_seid, seid); + } else { + dev_info(&pf->pdev->dev, "Failed to create FCoE VSI\n"); + } +} diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.h b/drivers/net/ethernet/intel/i40e/i40e_fcoe.h new file mode 100644 index 000000000000..21e0f582031c --- /dev/null +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.h @@ -0,0 +1,128 @@ +/******************************************************************************* + * + * Intel Ethernet Controller XL710 Family Linux Driver + * Copyright(c) 2013 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + ******************************************************************************/ + +#ifndef _I40E_FCOE_H_ +#define _I40E_FCOE_H_ + +/* FCoE HW context helper macros */ +#define I40E_DDP_CONTEXT_DESC(R, i) \ + (&(((struct i40e_fcoe_ddp_context_desc *)((R)->desc))[i])) + +#define I40E_QUEUE_CONTEXT_DESC(R, i) \ + (&(((struct i40e_fcoe_queue_context_desc *)((R)->desc))[i])) + +#define I40E_FILTER_CONTEXT_DESC(R, i) \ + (&(((struct i40e_fcoe_filter_context_desc *)((R)->desc))[i])) + + +/* receive queue descriptor filter status for FCoE */ +#define I40E_RX_DESC_FLTSTAT_FCMASK 0x3 +#define I40E_RX_DESC_FLTSTAT_NOMTCH 0x0 /* no ddp context match */ +#define I40E_RX_DESC_FLTSTAT_NODDP 0x1 /* no ddp due to error */ +#define I40E_RX_DESC_FLTSTAT_DDP 0x2 /* DDPed payload, post header */ +#define I40E_RX_DESC_FLTSTAT_FCPRSP 0x3 /* FCP_RSP */ + +/* receive queue descriptor error codes for FCoE */ +#define I40E_RX_DESC_FCOE_ERROR_MASK \ + (I40E_RX_DESC_ERROR_L3L4E_PROT | \ + I40E_RX_DESC_ERROR_L3L4E_FC | \ + I40E_RX_DESC_ERROR_L3L4E_DMAC_ERR | \ + I40E_RX_DESC_ERROR_L3L4E_DMAC_WARN) + +/* receive queue descriptor programming error */ +#define I40E_RX_PROG_FCOE_ERROR_TBL_FULL(e) \ + (((e) >> I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT) & 0x1) + +#define I40E_RX_PROG_FCOE_ERROR_CONFLICT(e) \ + (((e) >> I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT) & 0x1) + +#define I40E_RX_PROG_FCOE_ERROR_TBL_FULL_BIT \ + (1 << I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT) +#define I40E_RX_PROG_FCOE_ERROR_CONFLICT_BIT \ + (1 << I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT) + +#define I40E_RX_PROG_FCOE_ERROR_INVLFAIL(e) \ + I40E_RX_PROG_FCOE_ERROR_CONFLICT(e) +#define I40E_RX_PROG_FCOE_ERROR_INVLFAIL_BIT \ + I40E_RX_PROG_FCOE_ERROR_CONFLICT_BIT + +/* FCoE DDP related definitions */ +#define I40E_FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */ +#define I40E_FCOE_MAX_XID 0x0FFF /* the max xid supported by fcoe_sw */ +#define I40E_FCOE_DDP_BUFFCNT_MAX 512 /* 9 bits bufcnt */ +#define I40E_FCOE_DDP_PTR_ALIGN 16 +#define I40E_FCOE_DDP_PTR_MAX (I40E_FCOE_DDP_BUFFCNT_MAX * sizeof(dma_addr_t)) +#define I40E_FCOE_DDP_BUF_MIN 4096 +#define I40E_FCOE_DDP_MAX 2048 +#define I40E_FCOE_FILTER_CTX_QW1_PCTYPE_SHIFT 8 + +/* supported netdev features for FCoE */ +#define I40E_FCOE_NETIF_FEATURES (NETIF_F_ALL_FCOE | \ + NETIF_F_HW_VLAN_CTAG_TX | \ + NETIF_F_HW_VLAN_CTAG_RX | \ + NETIF_F_HW_VLAN_CTAG_FILTER) + +/* DDP context flags */ +enum i40e_fcoe_ddp_flags { + __I40E_FCOE_DDP_NONE = 1, + __I40E_FCOE_DDP_TARGET, + __I40E_FCOE_DDP_INITALIZED, + __I40E_FCOE_DDP_PROGRAMMED, + __I40E_FCOE_DDP_DONE, + __I40E_FCOE_DDP_ABORTED, + __I40E_FCOE_DDP_UNMAPPED, +}; + +/* DDP SW context struct */ +struct i40e_fcoe_ddp { + int len; + u16 xid; + u16 firstoff; + u16 lastsize; + u16 list_len; + u8 fcerr; + u8 prerr; + unsigned long flags; + unsigned int sgc; + struct scatterlist *sgl; + dma_addr_t udp; + u64 *udl; + struct dma_pool *pool; + +}; + +struct i40e_fcoe_ddp_pool { + struct dma_pool *pool; +}; + +struct i40e_fcoe { + unsigned long mode; + atomic_t refcnt; + struct i40e_fcoe_ddp_pool __percpu *ddp_pool; + struct i40e_fcoe_ddp ddp[I40E_FCOE_DDP_MAX]; +}; + +#endif /* _I40E_FCOE_H_ */ -- cgit v1.2.3 From 38e004388692f049908636a7944f6cd57d28bd77 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Fri, 1 Aug 2014 13:27:03 -0700 Subject: i40e: Adds FCoE related code to i40e core driver Adds FCoE specific code to existing i40e core driver to:- 1. have separate FCoE VSI with additional FCoE queues pairs. 2. have FCoE related hash defines. 3. have additional FCoE related stats code. 4. export and then re-use existing functions required by FCoE build. Signed-off-by: Vasu Dev Tested-by: Jack Morgan Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e.h | 62 ++++++ drivers/net/ethernet/intel/i40e/i40e_common.c | 27 +++ drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 19 ++ drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 35 +++ drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 9 +- drivers/net/ethernet/intel/i40e/i40e_main.c | 268 +++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_osdep.h | 3 + drivers/net/ethernet/intel/i40e/i40e_prototype.h | 3 + drivers/net/ethernet/intel/i40e/i40e_txrx.c | 37 +++- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 9 + drivers/net/ethernet/intel/i40e/i40e_type.h | 138 ++++++++++++ 11 files changed, 599 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 29cd81ae29f4..801da392a20e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -54,6 +54,9 @@ #include #include "i40e_type.h" #include "i40e_prototype.h" +#ifdef I40E_FCOE +#include "i40e_fcoe.h" +#endif #include "i40e_virtchnl.h" #include "i40e_virtchnl_pf.h" #include "i40e_txrx.h" @@ -79,6 +82,10 @@ #define I40E_MAX_QUEUES_PER_TC 64 /* should be a power of 2 */ #define I40E_FDIR_RING 0 #define I40E_FDIR_RING_COUNT 32 +#ifdef I40E_FCOE +#define I40E_DEFAULT_FCOE 8 /* default number of QPs for FCoE */ +#define I40E_MINIMUM_FCOE 1 /* minimum number of QPs for FCoE */ +#endif /* I40E_FCOE */ #define I40E_MAX_AQ_BUF_SIZE 4096 #define I40E_AQ_LEN 32 #define I40E_AQ_WORK_LIMIT 16 @@ -225,6 +232,10 @@ struct i40e_pf { u16 num_vmdq_msix; /* num queue vectors per vmdq pool */ u16 num_req_vfs; /* num vfs requested for this vf */ u16 num_vf_qps; /* num queue pairs per vf */ +#ifdef I40E_FCOE + u16 num_fcoe_qps; /* num fcoe queues this pf has set up */ + u16 num_fcoe_msix; /* num queue vectors per fcoe pool */ +#endif /* I40E_FCOE */ u16 num_lan_qps; /* num lan queues this pf has set up */ u16 num_lan_msix; /* num queue vectors for the base pf vsi */ int queues_left; /* queues left unclaimed */ @@ -265,6 +276,9 @@ struct i40e_pf { #define I40E_FLAG_VMDQ_ENABLED (u64)(1 << 7) #define I40E_FLAG_FDIR_REQUIRES_REINIT (u64)(1 << 8) #define I40E_FLAG_NEED_LINK_UPDATE (u64)(1 << 9) +#ifdef I40E_FCOE +#define I40E_FLAG_FCOE_ENABLED (u64)(1 << 11) +#endif /* I40E_FCOE */ #define I40E_FLAG_IN_NETPOLL (u64)(1 << 12) #define I40E_FLAG_16BYTE_RX_DESC_ENABLED (u64)(1 << 13) #define I40E_FLAG_CLEAN_ADMINQ (u64)(1 << 14) @@ -286,6 +300,10 @@ struct i40e_pf { /* tracks features that get auto disabled by errors */ u64 auto_disable_flags; +#ifdef I40E_FCOE + struct i40e_fcoe fcoe; + +#endif /* I40E_FCOE */ bool stat_offsets_loaded; struct i40e_hw_port_stats stats; struct i40e_hw_port_stats stats_offsets; @@ -408,6 +426,11 @@ struct i40e_vsi { struct rtnl_link_stats64 net_stats_offsets; struct i40e_eth_stats eth_stats; struct i40e_eth_stats eth_stats_offsets; +#ifdef I40E_FCOE + struct i40e_fcoe_stats fcoe_stats; + struct i40e_fcoe_stats fcoe_stats_offsets; + bool fcoe_stat_offsets_loaded; +#endif u32 tx_restart; u32 tx_busy; u32 rx_buf_failed; @@ -598,6 +621,11 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, int i40e_vsi_release(struct i40e_vsi *vsi); struct i40e_vsi *i40e_vsi_lookup(struct i40e_pf *pf, enum i40e_vsi_type type, struct i40e_vsi *start_vsi); +#ifdef I40E_FCOE +void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, + struct i40e_vsi_context *ctxt, + u8 enabled_tc, bool is_add); +#endif int i40e_vsi_control_rings(struct i40e_vsi *vsi, bool enable); int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count); struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, u16 uplink_seid, @@ -624,7 +652,21 @@ void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector); void i40e_irq_dynamic_disable(struct i40e_vsi *vsi, int vector); void i40e_irq_dynamic_disable_icr0(struct i40e_pf *pf); void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf); +#ifdef I40E_FCOE +struct rtnl_link_stats64 *i40e_get_netdev_stats_struct( + struct net_device *netdev, + struct rtnl_link_stats64 *storage); +int i40e_set_mac(struct net_device *netdev, void *p); +void i40e_set_rx_mode(struct net_device *netdev); +#endif int i40e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); +#ifdef I40E_FCOE +void i40e_tx_timeout(struct net_device *netdev); +int i40e_vlan_rx_add_vid(struct net_device *netdev, + __always_unused __be16 proto, u16 vid); +int i40e_vlan_rx_kill_vid(struct net_device *netdev, + __always_unused __be16 proto, u16 vid); +#endif int i40e_vsi_open(struct i40e_vsi *vsi); void i40e_vlan_stripping_disable(struct i40e_vsi *vsi); int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid); @@ -634,6 +676,26 @@ struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, u8 *macaddr, bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi); struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr, bool is_vf, bool is_netdev); +#ifdef I40E_FCOE +int i40e_open(struct net_device *netdev); +int i40e_close(struct net_device *netdev); +int i40e_setup_tc(struct net_device *netdev, u8 tc); +void i40e_netpoll(struct net_device *netdev); +int i40e_fcoe_enable(struct net_device *netdev); +int i40e_fcoe_disable(struct net_device *netdev); +int i40e_fcoe_vsi_init(struct i40e_vsi *vsi, struct i40e_vsi_context *ctxt); +u8 i40e_get_fcoe_tc_map(struct i40e_pf *pf); +void i40e_fcoe_config_netdev(struct net_device *netdev, struct i40e_vsi *vsi); +void i40e_fcoe_vsi_setup(struct i40e_pf *pf); +int i40e_init_pf_fcoe(struct i40e_pf *pf); +int i40e_fcoe_setup_ddp_resources(struct i40e_vsi *vsi); +void i40e_fcoe_free_ddp_resources(struct i40e_vsi *vsi); +int i40e_fcoe_handle_offload(struct i40e_ring *rx_ring, + union i40e_rx_desc *rx_desc, + struct sk_buff *skb); +void i40e_fcoe_handle_status(struct i40e_ring *rx_ring, + union i40e_rx_desc *rx_desc, u8 prog_id); +#endif /* I40E_FCOE */ void i40e_vlan_stripping_enable(struct i40e_vsi *vsi); #ifdef CONFIG_I40E_DCB void i40e_dcbnl_flush_apps(struct i40e_pf *pf, diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index f4e502a305ff..a010584d8962 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -709,6 +709,33 @@ void i40e_pre_tx_queue_cfg(struct i40e_hw *hw, u32 queue, bool enable) wr32(hw, I40E_GLLAN_TXPRE_QDIS(reg_block), reg_val); } +#ifdef I40E_FCOE + +/** + * i40e_get_san_mac_addr - get SAN MAC address + * @hw: pointer to the HW structure + * @mac_addr: pointer to SAN MAC address + * + * Reads the adapter's SAN MAC address from NVM + **/ +i40e_status i40e_get_san_mac_addr(struct i40e_hw *hw, u8 *mac_addr) +{ + struct i40e_aqc_mac_address_read_data addrs; + i40e_status status; + u16 flags = 0; + + status = i40e_aq_mac_address_read(hw, &flags, &addrs, NULL); + if (status) + return status; + + if (flags & I40E_AQC_SAN_ADDR_VALID) + memcpy(mac_addr, &addrs.pf_san_mac, sizeof(addrs.pf_san_mac)); + else + status = I40E_ERR_INVALID_MAC_ADDR; + + return status; +} +#endif /** * i40e_get_media_type - Gets media type diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 9eaed04618a3..5a0cabeb35ed 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -697,6 +697,25 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid) vsi->bw_ets_limit_credits[i], vsi->bw_ets_max_quanta[i]); } +#ifdef I40E_FCOE + if (vsi->type == I40E_VSI_FCOE) { + dev_info(&pf->pdev->dev, + " fcoe_stats: rx_packets = %llu, rx_dwords = %llu, rx_dropped = %llu\n", + vsi->fcoe_stats.rx_fcoe_packets, + vsi->fcoe_stats.rx_fcoe_dwords, + vsi->fcoe_stats.rx_fcoe_dropped); + dev_info(&pf->pdev->dev, + " fcoe_stats: tx_packets = %llu, tx_dwords = %llu\n", + vsi->fcoe_stats.tx_fcoe_packets, + vsi->fcoe_stats.tx_fcoe_dwords); + dev_info(&pf->pdev->dev, + " fcoe_stats: bad_crc = %llu, last_error = %llu\n", + vsi->fcoe_stats.fcoe_bad_fccrc, + vsi->fcoe_stats.fcoe_last_error); + dev_info(&pf->pdev->dev, " fcoe_stats: ddp_count = %llu\n", + vsi->fcoe_stats.fcoe_ddp_count); + } +#endif } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 9c93ff28d4aa..681a9e81ff51 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -155,6 +155,19 @@ static struct i40e_stats i40e_gstrings_stats[] = { I40E_PF_STAT("rx_lpi_count", stats.rx_lpi_count), }; +#ifdef I40E_FCOE +static const struct i40e_stats i40e_gstrings_fcoe_stats[] = { + I40E_VSI_STAT("fcoe_bad_fccrc", fcoe_stats.fcoe_bad_fccrc), + I40E_VSI_STAT("rx_fcoe_dropped", fcoe_stats.rx_fcoe_dropped), + I40E_VSI_STAT("rx_fcoe_packets", fcoe_stats.rx_fcoe_packets), + I40E_VSI_STAT("rx_fcoe_dwords", fcoe_stats.rx_fcoe_dwords), + I40E_VSI_STAT("fcoe_ddp_count", fcoe_stats.fcoe_ddp_count), + I40E_VSI_STAT("fcoe_last_error", fcoe_stats.fcoe_last_error), + I40E_VSI_STAT("tx_fcoe_packets", fcoe_stats.tx_fcoe_packets), + I40E_VSI_STAT("tx_fcoe_dwords", fcoe_stats.tx_fcoe_dwords), +}; + +#endif /* I40E_FCOE */ #define I40E_QUEUE_STATS_LEN(n) \ (((struct i40e_netdev_priv *)netdev_priv((n)))->vsi->num_queue_pairs \ * 2 /* Tx and Rx together */ \ @@ -162,9 +175,17 @@ static struct i40e_stats i40e_gstrings_stats[] = { #define I40E_GLOBAL_STATS_LEN ARRAY_SIZE(i40e_gstrings_stats) #define I40E_NETDEV_STATS_LEN ARRAY_SIZE(i40e_gstrings_net_stats) #define I40E_MISC_STATS_LEN ARRAY_SIZE(i40e_gstrings_misc_stats) +#ifdef I40E_FCOE +#define I40E_FCOE_STATS_LEN ARRAY_SIZE(i40e_gstrings_fcoe_stats) +#define I40E_VSI_STATS_LEN(n) (I40E_NETDEV_STATS_LEN + \ + I40E_FCOE_STATS_LEN + \ + I40E_MISC_STATS_LEN + \ + I40E_QUEUE_STATS_LEN((n))) +#else #define I40E_VSI_STATS_LEN(n) (I40E_NETDEV_STATS_LEN + \ I40E_MISC_STATS_LEN + \ I40E_QUEUE_STATS_LEN((n))) +#endif /* I40E_FCOE */ #define I40E_PFC_STATS_LEN ( \ (FIELD_SIZEOF(struct i40e_pf, stats.priority_xoff_rx) + \ FIELD_SIZEOF(struct i40e_pf, stats.priority_xon_rx) + \ @@ -1112,6 +1133,13 @@ static void i40e_get_ethtool_stats(struct net_device *netdev, data[i++] = (i40e_gstrings_misc_stats[j].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } +#ifdef I40E_FCOE + for (j = 0; j < I40E_FCOE_STATS_LEN; j++) { + p = (char *)vsi + i40e_gstrings_fcoe_stats[j].stat_offset; + data[i++] = (i40e_gstrings_fcoe_stats[j].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } +#endif rcu_read_lock(); for (j = 0; j < vsi->num_queue_pairs; j++) { tx_ring = ACCESS_ONCE(vsi->tx_rings[j]); @@ -1193,6 +1221,13 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset, i40e_gstrings_misc_stats[i].stat_string); p += ETH_GSTRING_LEN; } +#ifdef I40E_FCOE + for (i = 0; i < I40E_FCOE_STATS_LEN; i++) { + snprintf(p, ETH_GSTRING_LEN, "%s", + i40e_gstrings_fcoe_stats[i].stat_string); + p += ETH_GSTRING_LEN; + } +#endif for (i = 0; i < vsi->num_queue_pairs; i++) { snprintf(p, ETH_GSTRING_LEN, "tx-%u.tx_packets", i); p += ETH_GSTRING_LEN; diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c index 8574eeefefc7..6938fc1ad877 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c @@ -1363,8 +1363,6 @@ static netdev_tx_t i40e_fcoe_xmit_frame(struct sk_buff *skb, struct i40e_vsi *vsi = np->vsi; struct i40e_ring *tx_ring = vsi->tx_rings[skb->queue_mapping]; struct i40e_tx_buffer *first; - __be16 protocol = skb->protocol; - u32 tx_flags = 0; u8 hdr_len = 0; u8 sof = 0; @@ -1384,13 +1382,8 @@ static netdev_tx_t i40e_fcoe_xmit_frame(struct sk_buff *skb, /* record the location of the first descriptor for this packet */ first = &tx_ring->tx_bi[tx_ring->next_to_use]; - if (protocol == htons(ETH_P_8021Q)) { - struct vlan_ethhdr *veth = (struct vlan_ethhdr *)eth_hdr(skb); - - protocol = veth->h_vlan_encapsulated_proto; - } /* FIP is a regular L2 traffic w/o offload */ - if (protocol == htons(ETH_P_FIP)) + if (skb->protocol == htons(ETH_P_FIP)) goto out_send; /* check sof and eof, only supports FC Class 2 or 3 */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 821fcc1adb85..6ac8487f9a51 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -269,7 +269,11 @@ static void i40e_service_event_schedule(struct i40e_pf *pf) * device is munged, not just the one netdev port, so go for the full * reset. **/ +#ifdef I40E_FCOE +void i40e_tx_timeout(struct net_device *netdev) +#else static void i40e_tx_timeout(struct net_device *netdev) +#endif { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; @@ -349,9 +353,15 @@ struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi) * Returns the address of the device statistics structure. * The statistics are actually updated from the service task. **/ +#ifdef I40E_FCOE +struct rtnl_link_stats64 *i40e_get_netdev_stats_struct( + struct net_device *netdev, + struct rtnl_link_stats64 *stats) +#else static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct( struct net_device *netdev, struct rtnl_link_stats64 *stats) +#endif { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_ring *tx_ring, *rx_ring; @@ -636,6 +646,55 @@ static void i40e_update_veb_stats(struct i40e_veb *veb) veb->stat_offsets_loaded = true; } +#ifdef I40E_FCOE +/** + * i40e_update_fcoe_stats - Update FCoE-specific ethernet statistics counters. + * @vsi: the VSI that is capable of doing FCoE + **/ +static void i40e_update_fcoe_stats(struct i40e_vsi *vsi) +{ + struct i40e_pf *pf = vsi->back; + struct i40e_hw *hw = &pf->hw; + struct i40e_fcoe_stats *ofs; + struct i40e_fcoe_stats *fs; /* device's eth stats */ + int idx; + + if (vsi->type != I40E_VSI_FCOE) + return; + + idx = (pf->pf_seid - I40E_BASE_PF_SEID) + I40E_FCOE_PF_STAT_OFFSET; + fs = &vsi->fcoe_stats; + ofs = &vsi->fcoe_stats_offsets; + + i40e_stat_update32(hw, I40E_GL_FCOEPRC(idx), + vsi->fcoe_stat_offsets_loaded, + &ofs->rx_fcoe_packets, &fs->rx_fcoe_packets); + i40e_stat_update48(hw, I40E_GL_FCOEDWRCH(idx), I40E_GL_FCOEDWRCL(idx), + vsi->fcoe_stat_offsets_loaded, + &ofs->rx_fcoe_dwords, &fs->rx_fcoe_dwords); + i40e_stat_update32(hw, I40E_GL_FCOERPDC(idx), + vsi->fcoe_stat_offsets_loaded, + &ofs->rx_fcoe_dropped, &fs->rx_fcoe_dropped); + i40e_stat_update32(hw, I40E_GL_FCOEPTC(idx), + vsi->fcoe_stat_offsets_loaded, + &ofs->tx_fcoe_packets, &fs->tx_fcoe_packets); + i40e_stat_update48(hw, I40E_GL_FCOEDWTCH(idx), I40E_GL_FCOEDWTCL(idx), + vsi->fcoe_stat_offsets_loaded, + &ofs->tx_fcoe_dwords, &fs->tx_fcoe_dwords); + i40e_stat_update32(hw, I40E_GL_FCOECRC(idx), + vsi->fcoe_stat_offsets_loaded, + &ofs->fcoe_bad_fccrc, &fs->fcoe_bad_fccrc); + i40e_stat_update32(hw, I40E_GL_FCOELAST(idx), + vsi->fcoe_stat_offsets_loaded, + &ofs->fcoe_last_error, &fs->fcoe_last_error); + i40e_stat_update32(hw, I40E_GL_FCOEDDPC(idx), + vsi->fcoe_stat_offsets_loaded, + &ofs->fcoe_ddp_count, &fs->fcoe_ddp_count); + + vsi->fcoe_stat_offsets_loaded = true; +} + +#endif /** * i40e_update_link_xoff_rx - Update XOFF received in link flow control mode * @pf: the corresponding PF @@ -1064,6 +1123,9 @@ void i40e_update_stats(struct i40e_vsi *vsi) i40e_update_pf_stats(pf); i40e_update_vsi_stats(vsi); +#ifdef I40E_FCOE + i40e_update_fcoe_stats(vsi); +#endif } /** @@ -1315,7 +1377,11 @@ void i40e_del_filter(struct i40e_vsi *vsi, * * Returns 0 on success, negative on failure **/ +#ifdef I40E_FCOE +int i40e_set_mac(struct net_device *netdev, void *p) +#else static int i40e_set_mac(struct net_device *netdev, void *p) +#endif { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; @@ -1376,10 +1442,17 @@ static int i40e_set_mac(struct net_device *netdev, void *p) * * Setup VSI queue mapping for enabled traffic classes. **/ +#ifdef I40E_FCOE +void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, + struct i40e_vsi_context *ctxt, + u8 enabled_tc, + bool is_add) +#else static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, struct i40e_vsi_context *ctxt, u8 enabled_tc, bool is_add) +#endif { struct i40e_pf *pf = vsi->back; u16 sections = 0; @@ -1425,6 +1498,11 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, case I40E_VSI_MAIN: qcount = min_t(int, pf->rss_size, num_tc_qps); break; +#ifdef I40E_FCOE + case I40E_VSI_FCOE: + qcount = num_tc_qps; + break; +#endif case I40E_VSI_FDIR: case I40E_VSI_SRIOV: case I40E_VSI_VMDQ2: @@ -1491,7 +1569,11 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, * i40e_set_rx_mode - NDO callback to set the netdev filters * @netdev: network interface device structure **/ +#ifdef I40E_FCOE +void i40e_set_rx_mode(struct net_device *netdev) +#else static void i40e_set_rx_mode(struct net_device *netdev) +#endif { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_mac_filter *f, *ftmp; @@ -2069,8 +2151,13 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid) * * net_device_ops implementation for adding vlan ids **/ +#ifdef I40E_FCOE +int i40e_vlan_rx_add_vid(struct net_device *netdev, + __always_unused __be16 proto, u16 vid) +#else static int i40e_vlan_rx_add_vid(struct net_device *netdev, __always_unused __be16 proto, u16 vid) +#endif { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; @@ -2103,8 +2190,13 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev, * * net_device_ops implementation for removing vlan ids **/ +#ifdef I40E_FCOE +int i40e_vlan_rx_kill_vid(struct net_device *netdev, + __always_unused __be16 proto, u16 vid) +#else static int i40e_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto, u16 vid) +#endif { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; @@ -2236,6 +2328,9 @@ static int i40e_vsi_setup_rx_resources(struct i40e_vsi *vsi) for (i = 0; i < vsi->num_queue_pairs && !err; i++) err = i40e_setup_rx_descriptors(vsi->rx_rings[i]); +#ifdef I40E_FCOE + i40e_fcoe_setup_ddp_resources(vsi); +#endif return err; } @@ -2255,6 +2350,9 @@ static void i40e_vsi_free_rx_resources(struct i40e_vsi *vsi) for (i = 0; i < vsi->num_queue_pairs; i++) if (vsi->rx_rings[i] && vsi->rx_rings[i]->desc) i40e_free_rx_resources(vsi->rx_rings[i]); +#ifdef I40E_FCOE + i40e_fcoe_free_ddp_resources(vsi); +#endif } /** @@ -2296,6 +2394,9 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring) tx_ctx.qlen = ring->count; tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FD_SB_ENABLED | I40E_FLAG_FD_ATR_ENABLED)); +#ifdef I40E_FCOE + tx_ctx.fc_ena = (vsi->type == I40E_VSI_FCOE); +#endif tx_ctx.timesync_ena = !!(vsi->back->flags & I40E_FLAG_PTP); /* FDIR VSI tx ring can still use RS bit and writebacks */ if (vsi->type != I40E_VSI_FDIR) @@ -2408,6 +2509,9 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) rx_ctx.crcstrip = 1; rx_ctx.l2tsel = 1; rx_ctx.showiv = 1; +#ifdef I40E_FCOE + rx_ctx.fc_ena = (vsi->type == I40E_VSI_FCOE); +#endif /* set the prefena field to 1 because the manual says to */ rx_ctx.prefena = 1; @@ -2492,6 +2596,17 @@ static int i40e_vsi_configure_rx(struct i40e_vsi *vsi) break; } +#ifdef I40E_FCOE + /* setup rx buffer for FCoE */ + if ((vsi->type == I40E_VSI_FCOE) && + (vsi->back->flags & I40E_FLAG_FCOE_ENABLED)) { + vsi->rx_hdr_len = 0; + vsi->rx_buf_len = I40E_RXBUFFER_3072; + vsi->max_frame = I40E_RXBUFFER_3072; + vsi->dtype = I40E_RX_DTYPE_NO_SPLIT; + } + +#endif /* I40E_FCOE */ /* round up for the chip's needs */ vsi->rx_hdr_len = ALIGN(vsi->rx_hdr_len, (1 << I40E_RXQ_CTX_HBUFF_SHIFT)); @@ -3252,7 +3367,11 @@ static int i40e_vsi_request_irq(struct i40e_vsi *vsi, char *basename) * This is used by netconsole to send skbs without having to re-enable * interrupts. It's not called while the normal interrupt routine is executing. **/ +#ifdef I40E_FCOE +void i40e_netpoll(struct net_device *netdev) +#else static void i40e_netpoll(struct net_device *netdev) +#endif { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; @@ -4202,12 +4321,20 @@ static void i40e_dcb_reconfigure(struct i40e_pf *pf) continue; /* - Enable all TCs for the LAN VSI +#ifdef I40E_FCOE + * - For FCoE VSI only enable the TC configured + * as per the APP TLV +#endif * - For all others keep them at TC0 for now */ if (v == pf->lan_vsi) tc_map = i40e_pf_get_tc_map(pf); else tc_map = i40e_pf_get_default_tc(pf); +#ifdef I40E_FCOE + if (pf->vsi[v]->type == I40E_VSI_FCOE) + tc_map = i40e_get_fcoe_tc_map(pf); +#endif /* #ifdef I40E_FCOE */ ret = i40e_vsi_config_tc(pf->vsi[v], tc_map); if (ret) { @@ -4434,7 +4561,11 @@ void i40e_down(struct i40e_vsi *vsi) * @netdev: net device to configure * @tc: number of traffic classes to enable **/ +#ifdef I40E_FCOE +int i40e_setup_tc(struct net_device *netdev, u8 tc) +#else static int i40e_setup_tc(struct net_device *netdev, u8 tc) +#endif { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; @@ -4499,7 +4630,11 @@ exit: * * Returns 0 on success, negative value on failure **/ +#ifdef I40E_FCOE +int i40e_open(struct net_device *netdev) +#else static int i40e_open(struct net_device *netdev) +#endif { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; @@ -4635,7 +4770,11 @@ static void i40e_fdir_filter_exit(struct i40e_pf *pf) * * Returns 0, this is not allowed to fail **/ +#ifdef I40E_FCOE +int i40e_close(struct net_device *netdev) +#else static int i40e_close(struct net_device *netdev) +#endif { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; @@ -5050,6 +5189,9 @@ static void i40e_vsi_link_event(struct i40e_vsi *vsi, bool link_up) switch (vsi->type) { case I40E_VSI_MAIN: +#ifdef I40E_FCOE + case I40E_VSI_FCOE: +#endif if (!vsi->netdev || !vsi->netdev_registered) break; @@ -5768,7 +5910,12 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) goto end_core_reset; } #endif /* CONFIG_I40E_DCB */ +#ifdef I40E_FCOE + ret = i40e_init_pf_fcoe(pf); + if (ret) + dev_info(&pf->pdev->dev, "init_pf_fcoe failed: %d\n", ret); +#endif /* do basic switch setup */ ret = i40e_setup_pf_switch(pf, reinit); if (ret) @@ -6107,6 +6254,15 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi) I40E_REQ_DESCRIPTOR_MULTIPLE); break; +#ifdef I40E_FCOE + case I40E_VSI_FCOE: + vsi->alloc_queue_pairs = pf->num_fcoe_qps; + vsi->num_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS, + I40E_REQ_DESCRIPTOR_MULTIPLE); + vsi->num_q_vectors = pf->num_fcoe_msix; + break; + +#endif /* I40E_FCOE */ default: WARN_ON(1); return -ENODATA; @@ -6418,6 +6574,9 @@ static int i40e_init_msix(struct i40e_pf *pf) * is governed by number of cpus in the system. * - assumes symmetric Tx/Rx pairing * - The number of VMDq pairs +#ifdef I40E_FCOE + * - The number of FCOE qps. +#endif * Once we count this up, try the request. * * If we can't get what we want, we'll simplify to nearly nothing @@ -6430,6 +6589,13 @@ static int i40e_init_msix(struct i40e_pf *pf) if (pf->flags & I40E_FLAG_FD_SB_ENABLED) v_budget++; +#ifdef I40E_FCOE + if (pf->flags & I40E_FLAG_FCOE_ENABLED) { + pf->num_fcoe_msix = pf->num_fcoe_qps; + v_budget += pf->num_fcoe_msix; + } + +#endif /* Scale down if necessary, and the rings will share vectors */ v_budget = min_t(int, v_budget, hw->func_caps.num_msix_vectors); @@ -6448,6 +6614,10 @@ static int i40e_init_msix(struct i40e_pf *pf) * of these features based on the policy and at the end disable * the features that did not get any vectors. */ +#ifdef I40E_FCOE + pf->num_fcoe_qps = 0; + pf->num_fcoe_msix = 0; +#endif pf->num_vmdq_msix = 0; } @@ -6478,9 +6648,24 @@ static int i40e_init_msix(struct i40e_pf *pf) pf->num_lan_msix = 1; break; case 3: +#ifdef I40E_FCOE + /* give one vector to FCoE */ + if (pf->flags & I40E_FLAG_FCOE_ENABLED) { + pf->num_lan_msix = 1; + pf->num_fcoe_msix = 1; + } +#else pf->num_lan_msix = 2; +#endif break; default: +#ifdef I40E_FCOE + /* give one vector to FCoE */ + if (pf->flags & I40E_FLAG_FCOE_ENABLED) { + pf->num_fcoe_msix = 1; + vec--; + } +#endif pf->num_lan_msix = min_t(int, (vec / 2), pf->num_lan_qps); pf->num_vmdq_vsis = min_t(int, (vec - pf->num_lan_msix), @@ -6494,6 +6679,13 @@ static int i40e_init_msix(struct i40e_pf *pf) dev_info(&pf->pdev->dev, "VMDq disabled, not enough MSI-X vectors\n"); pf->flags &= ~I40E_FLAG_VMDQ_ENABLED; } +#ifdef I40E_FCOE + + if ((pf->flags & I40E_FLAG_FCOE_ENABLED) && (pf->num_fcoe_msix == 0)) { + dev_info(&pf->pdev->dev, "FCOE disabled, not enough MSI-X vectors\n"); + pf->flags &= ~I40E_FLAG_FCOE_ENABLED; + } +#endif return err; } @@ -6577,6 +6769,9 @@ static void i40e_init_interrupt_scheme(struct i40e_pf *pf) err = i40e_init_msix(pf); if (err) { pf->flags &= ~(I40E_FLAG_MSIX_ENABLED | +#ifdef I40E_FCOE + I40E_FLAG_FCOE_ENABLED | +#endif I40E_FLAG_RSS_ENABLED | I40E_FLAG_DCB_CAPABLE | I40E_FLAG_SRIOV_ENABLED | @@ -6814,6 +7009,12 @@ static int i40e_sw_init(struct i40e_pf *pf) pf->num_vmdq_qps = I40E_DEFAULT_QUEUES_PER_VMDQ; } +#ifdef I40E_FCOE + err = i40e_init_pf_fcoe(pf); + if (err) + dev_info(&pf->pdev->dev, "init_pf_fcoe failed: %d\n", err); + +#endif /* I40E_FCOE */ #ifdef CONFIG_PCI_IOV if (pf->hw.func_caps.num_vfs) { pf->num_vf_qps = I40E_DEFAULT_QUEUES_PER_VF; @@ -7141,6 +7342,10 @@ static const struct net_device_ops i40e_netdev_ops = { .ndo_poll_controller = i40e_netpoll, #endif .ndo_setup_tc = i40e_setup_tc, +#ifdef I40E_FCOE + .ndo_fcoe_enable = i40e_fcoe_enable, + .ndo_fcoe_disable = i40e_fcoe_disable, +#endif .ndo_set_features = i40e_set_features, .ndo_set_vf_mac = i40e_ndo_set_vf_mac, .ndo_set_vf_vlan = i40e_ndo_set_vf_port_vlan, @@ -7249,6 +7454,9 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) netdev->netdev_ops = &i40e_netdev_ops; netdev->watchdog_timeo = 5 * HZ; i40e_set_ethtool_ops(netdev); +#ifdef I40E_FCOE + i40e_fcoe_config_netdev(netdev, vsi); +#endif return 0; } @@ -7402,6 +7610,16 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, true); break; +#ifdef I40E_FCOE + case I40E_VSI_FCOE: + ret = i40e_fcoe_vsi_init(vsi, &ctxt); + if (ret) { + dev_info(&pf->pdev->dev, "failed to initialize FCoE VSI\n"); + return ret; + } + break; + +#endif /* I40E_FCOE */ default: return -ENODEV; } @@ -7760,6 +7978,7 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, /* setup the netdev if needed */ case I40E_VSI_MAIN: case I40E_VSI_VMDQ2: + case I40E_VSI_FCOE: ret = i40e_config_netdev(vsi); if (ret) goto err_netdev; @@ -8378,6 +8597,9 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) int queues_left; pf->num_lan_qps = 0; +#ifdef I40E_FCOE + pf->num_fcoe_qps = 0; +#endif /* Find the max queues to be put into basic use. We'll always be * using TC0, whether or not DCB is running, and TC0 will get the @@ -8393,6 +8615,9 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) /* make sure all the fancies are disabled */ pf->flags &= ~(I40E_FLAG_RSS_ENABLED | +#ifdef I40E_FCOE + I40E_FLAG_FCOE_ENABLED | +#endif I40E_FLAG_FD_SB_ENABLED | I40E_FLAG_FD_ATR_ENABLED | I40E_FLAG_DCB_CAPABLE | @@ -8407,6 +8632,9 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) queues_left -= pf->num_lan_qps; pf->flags &= ~(I40E_FLAG_RSS_ENABLED | +#ifdef I40E_FCOE + I40E_FLAG_FCOE_ENABLED | +#endif I40E_FLAG_FD_SB_ENABLED | I40E_FLAG_FD_ATR_ENABLED | I40E_FLAG_DCB_ENABLED | @@ -8422,6 +8650,22 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) queues_left -= pf->num_lan_qps; } +#ifdef I40E_FCOE + if (pf->flags & I40E_FLAG_FCOE_ENABLED) { + if (I40E_DEFAULT_FCOE <= queues_left) { + pf->num_fcoe_qps = I40E_DEFAULT_FCOE; + } else if (I40E_MINIMUM_FCOE <= queues_left) { + pf->num_fcoe_qps = I40E_MINIMUM_FCOE; + } else { + pf->num_fcoe_qps = 0; + pf->flags &= ~I40E_FLAG_FCOE_ENABLED; + dev_info(&pf->pdev->dev, "not enough queues for FCoE. FCoE feature will be disabled\n"); + } + + queues_left -= pf->num_fcoe_qps; + } + +#endif if (pf->flags & I40E_FLAG_FD_SB_ENABLED) { if (queues_left > 1) { queues_left -= 1; /* save 1 queue for FD */ @@ -8446,6 +8690,9 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) } pf->queues_left = queues_left; +#ifdef I40E_FCOE + dev_info(&pf->pdev->dev, "fcoe queues = %d\n", pf->num_fcoe_qps); +#endif } /** @@ -8512,6 +8759,10 @@ static void i40e_print_features(struct i40e_pf *pf) buf += sprintf(buf, "DCB "); if (pf->flags & I40E_FLAG_PTP) buf += sprintf(buf, "PTP "); +#ifdef I40E_FCOE + if (pf->flags & I40E_FLAG_FCOE_ENABLED) + buf += sprintf(buf, "FCOE "); +#endif BUG_ON(buf > (string + INFO_STRING_LEN)); dev_info(&pf->pdev->dev, "%s\n", string); @@ -8699,6 +8950,18 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) i40e_get_port_mac_addr(hw, hw->mac.port_addr); if (is_valid_ether_addr(hw->mac.port_addr)) pf->flags |= I40E_FLAG_PORT_ID_VALID; +#ifdef I40E_FCOE + err = i40e_get_san_mac_addr(hw, hw->mac.san_addr); + if (err) + dev_info(&pdev->dev, + "(non-fatal) SAN MAC retrieval failed: %d\n", err); + if (!is_valid_ether_addr(hw->mac.san_addr)) { + dev_warn(&pdev->dev, "invalid SAN MAC address %pM, falling back to LAN MAC\n", + hw->mac.san_addr); + ether_addr_copy(hw->mac.san_addr, hw->mac.addr); + } + dev_info(&pf->pdev->dev, "SAN MAC: %pM\n", hw->mac.san_addr); +#endif /* I40E_FCOE */ pci_set_drvdata(pdev, pf); pci_save_state(pdev); @@ -8815,6 +9078,11 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mod_timer(&pf->service_timer, round_jiffies(jiffies + pf->service_timer_period)); +#ifdef I40E_FCOE + /* create FCoE interface */ + i40e_fcoe_vsi_setup(pf); + +#endif /* Get the negotiated link width and speed from PCI config space */ pcie_capability_read_word(pf->pdev, PCI_EXP_LNKSTA, &link_status); diff --git a/drivers/net/ethernet/intel/i40e/i40e_osdep.h b/drivers/net/ethernet/intel/i40e/i40e_osdep.h index ecd0f0b663c9..045b5c4b98b3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_osdep.h +++ b/drivers/net/ethernet/intel/i40e/i40e_osdep.h @@ -78,4 +78,7 @@ do { \ } while (0) typedef enum i40e_status_code i40e_status; +#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) +#define I40E_FCOE +#endif /* CONFIG_FCOE or CONFIG_FCOE_MODULE */ #endif /* _I40E_OSDEP_H_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index a91d7e1a5b5b..8cd4390a2842 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -237,6 +237,9 @@ i40e_status i40e_get_mac_addr(struct i40e_hw *hw, u8 *mac_addr); i40e_status i40e_get_port_mac_addr(struct i40e_hw *hw, u8 *mac_addr); i40e_status i40e_validate_mac_addr(u8 *mac_addr); void i40e_pre_tx_queue_cfg(struct i40e_hw *hw, u32 queue, bool enable); +#ifdef I40E_FCOE +i40e_status i40e_get_san_mac_addr(struct i40e_hw *hw, u8 *mac_addr); +#endif /* prototype for functions used for NVM access */ i40e_status i40e_init_nvm(struct i40e_hw *hw); i40e_status i40e_acquire_nvm(struct i40e_hw *hw, diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index d26d6836689d..a51aa37b7b5a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -896,6 +896,11 @@ static void i40e_clean_programming_status(struct i40e_ring *rx_ring, if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS) i40e_fd_handle_status(rx_ring, rx_desc, id); +#ifdef I40E_FCOE + else if ((id == I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_PROG_STATUS) || + (id == I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_INVL_STATUS)) + i40e_fcoe_handle_status(rx_ring, rx_desc, id); +#endif } /** @@ -1489,6 +1494,12 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) vlan_tag = rx_status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; +#ifdef I40E_FCOE + if (!i40e_fcoe_handle_offload(rx_ring, rx_desc, skb)) { + dev_kfree_skb_any(skb); + goto next_desc; + } +#endif i40e_receive_skb(rx_ring, skb, vlan_tag); rx_ring->netdev->last_rx = jiffies; @@ -1719,9 +1730,15 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, * Returns error code indicate the frame should be dropped upon error and the * otherwise returns 0 to indicate the flags has been set properly. **/ +#ifdef I40E_FCOE +int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, + struct i40e_ring *tx_ring, + u32 *flags) +#else static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, struct i40e_ring *tx_ring, u32 *flags) +#endif { __be16 protocol = skb->protocol; u32 tx_flags = 0; @@ -1743,9 +1760,8 @@ static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, } /* Insert 802.1p priority into VLAN header */ - if ((tx_ring->vsi->back->flags & I40E_FLAG_DCB_ENABLED) && - ((tx_flags & (I40E_TX_FLAGS_HW_VLAN | I40E_TX_FLAGS_SW_VLAN)) || - (skb->priority != TC_PRIO_CONTROL))) { + if ((tx_flags & (I40E_TX_FLAGS_HW_VLAN | I40E_TX_FLAGS_SW_VLAN)) || + (skb->priority != TC_PRIO_CONTROL)) { tx_flags &= ~I40E_TX_FLAGS_VLAN_PRIO_MASK; tx_flags |= (skb->priority & 0x7) << I40E_TX_FLAGS_VLAN_PRIO_SHIFT; @@ -2018,9 +2034,15 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring, * @td_cmd: the command field in the descriptor * @td_offset: offset for checksum or crc **/ +#ifdef I40E_FCOE +void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, + struct i40e_tx_buffer *first, u32 tx_flags, + const u8 hdr_len, u32 td_cmd, u32 td_offset) +#else static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, struct i40e_tx_buffer *first, u32 tx_flags, const u8 hdr_len, u32 td_cmd, u32 td_offset) +#endif { unsigned int data_len = skb->data_len; unsigned int size = skb_headlen(skb); @@ -2197,7 +2219,11 @@ static inline int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size) * * Returns 0 if stop is not needed **/ +#ifdef I40E_FCOE +int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size) +#else static int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size) +#endif { if (likely(I40E_DESC_UNUSED(tx_ring) >= size)) return 0; @@ -2213,8 +2239,13 @@ static int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size) * there is not enough descriptors available in this ring since we need at least * one descriptor. **/ +#ifdef I40E_FCOE +int i40e_xmit_descriptor_count(struct sk_buff *skb, + struct i40e_ring *tx_ring) +#else static int i40e_xmit_descriptor_count(struct sk_buff *skb, struct i40e_ring *tx_ring) +#endif { unsigned int f; int count = 0; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index c1c356984b17..73f4fa425697 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -290,4 +290,13 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring); void i40e_free_tx_resources(struct i40e_ring *tx_ring); void i40e_free_rx_resources(struct i40e_ring *rx_ring); int i40e_napi_poll(struct napi_struct *napi, int budget); +#ifdef I40E_FCOE +void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, + struct i40e_tx_buffer *first, u32 tx_flags, + const u8 hdr_len, u32 td_cmd, u32 td_offset); +int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size); +int i40e_xmit_descriptor_count(struct sk_buff *skb, struct i40e_ring *tx_ring); +int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, + struct i40e_ring *tx_ring, u32 *flags); +#endif #endif /* _I40E_TXRX_H_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 8bb9049191cb..ce04d9093db6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -1051,6 +1051,25 @@ struct i40e_eth_stats { u64 tx_errors; /* tepc */ }; +#ifdef I40E_FCOE +/* Statistics collected per function for FCoE */ +struct i40e_fcoe_stats { + u64 rx_fcoe_packets; /* fcoeprc */ + u64 rx_fcoe_dwords; /* focedwrc */ + u64 rx_fcoe_dropped; /* fcoerpdc */ + u64 tx_fcoe_packets; /* fcoeptc */ + u64 tx_fcoe_dwords; /* focedwtc */ + u64 fcoe_bad_fccrc; /* fcoecrc */ + u64 fcoe_last_error; /* fcoelast */ + u64 fcoe_ddp_count; /* fcoeddpc */ +}; + +/* offset to per function FCoE statistics block */ +#define I40E_FCOE_VF_STAT_OFFSET 0 +#define I40E_FCOE_PF_STAT_OFFSET 128 +#define I40E_FCOE_STAT_MAX (I40E_FCOE_PF_STAT_OFFSET + I40E_MAX_PF) + +#endif /* Statistics collected by the MAC */ struct i40e_hw_port_stats { /* eth stats collected by the port */ @@ -1131,6 +1150,125 @@ struct i40e_hw_port_stats { #define I40E_SRRD_SRCTL_ATTEMPTS 100000 +#ifdef I40E_FCOE +/* FCoE Tx context descriptor - Use the i40e_tx_context_desc struct */ + +enum i40E_fcoe_tx_ctx_desc_cmd_bits { + I40E_FCOE_TX_CTX_DESC_OPCODE_SINGLE_SEND = 0x00, /* 4 BITS */ + I40E_FCOE_TX_CTX_DESC_OPCODE_TSO_FC_CLASS2 = 0x01, /* 4 BITS */ + I40E_FCOE_TX_CTX_DESC_OPCODE_TSO_FC_CLASS3 = 0x05, /* 4 BITS */ + I40E_FCOE_TX_CTX_DESC_OPCODE_ETSO_FC_CLASS2 = 0x02, /* 4 BITS */ + I40E_FCOE_TX_CTX_DESC_OPCODE_ETSO_FC_CLASS3 = 0x06, /* 4 BITS */ + I40E_FCOE_TX_CTX_DESC_OPCODE_DWO_FC_CLASS2 = 0x03, /* 4 BITS */ + I40E_FCOE_TX_CTX_DESC_OPCODE_DWO_FC_CLASS3 = 0x07, /* 4 BITS */ + I40E_FCOE_TX_CTX_DESC_OPCODE_DDP_CTX_INVL = 0x08, /* 4 BITS */ + I40E_FCOE_TX_CTX_DESC_OPCODE_DWO_CTX_INVL = 0x09, /* 4 BITS */ + I40E_FCOE_TX_CTX_DESC_RELOFF = 0x10, + I40E_FCOE_TX_CTX_DESC_CLRSEQ = 0x20, + I40E_FCOE_TX_CTX_DESC_DIFENA = 0x40, + I40E_FCOE_TX_CTX_DESC_IL2TAG2 = 0x80 +}; + +/* FCoE DDP Context descriptor */ +struct i40e_fcoe_ddp_context_desc { + __le64 rsvd; + __le64 type_cmd_foff_lsize; +}; + +#define I40E_FCOE_DDP_CTX_QW1_DTYPE_SHIFT 0 +#define I40E_FCOE_DDP_CTX_QW1_DTYPE_MASK (0xFULL << \ + I40E_FCOE_DDP_CTX_QW1_DTYPE_SHIFT) + +#define I40E_FCOE_DDP_CTX_QW1_CMD_SHIFT 4 +#define I40E_FCOE_DDP_CTX_QW1_CMD_MASK (0xFULL << \ + I40E_FCOE_DDP_CTX_QW1_CMD_SHIFT) + +enum i40e_fcoe_ddp_ctx_desc_cmd_bits { + I40E_FCOE_DDP_CTX_DESC_BSIZE_512B = 0x00, /* 2 BITS */ + I40E_FCOE_DDP_CTX_DESC_BSIZE_4K = 0x01, /* 2 BITS */ + I40E_FCOE_DDP_CTX_DESC_BSIZE_8K = 0x02, /* 2 BITS */ + I40E_FCOE_DDP_CTX_DESC_BSIZE_16K = 0x03, /* 2 BITS */ + I40E_FCOE_DDP_CTX_DESC_DIFENA = 0x04, /* 1 BIT */ + I40E_FCOE_DDP_CTX_DESC_LASTSEQH = 0x08, /* 1 BIT */ +}; + +#define I40E_FCOE_DDP_CTX_QW1_FOFF_SHIFT 16 +#define I40E_FCOE_DDP_CTX_QW1_FOFF_MASK (0x3FFFULL << \ + I40E_FCOE_DDP_CTX_QW1_FOFF_SHIFT) + +#define I40E_FCOE_DDP_CTX_QW1_LSIZE_SHIFT 32 +#define I40E_FCOE_DDP_CTX_QW1_LSIZE_MASK (0x3FFFULL << \ + I40E_FCOE_DDP_CTX_QW1_LSIZE_SHIFT) + +/* FCoE DDP/DWO Queue Context descriptor */ +struct i40e_fcoe_queue_context_desc { + __le64 dmaindx_fbase; /* 0:11 DMAINDX, 12:63 FBASE */ + __le64 flen_tph; /* 0:12 FLEN, 13:15 TPH */ +}; + +#define I40E_FCOE_QUEUE_CTX_QW0_DMAINDX_SHIFT 0 +#define I40E_FCOE_QUEUE_CTX_QW0_DMAINDX_MASK (0xFFFULL << \ + I40E_FCOE_QUEUE_CTX_QW0_DMAINDX_SHIFT) + +#define I40E_FCOE_QUEUE_CTX_QW0_FBASE_SHIFT 12 +#define I40E_FCOE_QUEUE_CTX_QW0_FBASE_MASK (0xFFFFFFFFFFFFFULL << \ + I40E_FCOE_QUEUE_CTX_QW0_FBASE_SHIFT) + +#define I40E_FCOE_QUEUE_CTX_QW1_FLEN_SHIFT 0 +#define I40E_FCOE_QUEUE_CTX_QW1_FLEN_MASK (0x1FFFULL << \ + I40E_FCOE_QUEUE_CTX_QW1_FLEN_SHIFT) + +#define I40E_FCOE_QUEUE_CTX_QW1_TPH_SHIFT 13 +#define I40E_FCOE_QUEUE_CTX_QW1_TPH_MASK (0x7ULL << \ + I40E_FCOE_QUEUE_CTX_QW1_FLEN_SHIFT) + +enum i40e_fcoe_queue_ctx_desc_tph_bits { + I40E_FCOE_QUEUE_CTX_DESC_TPHRDESC = 0x1, + I40E_FCOE_QUEUE_CTX_DESC_TPHDATA = 0x2 +}; + +#define I40E_FCOE_QUEUE_CTX_QW1_RECIPE_SHIFT 30 +#define I40E_FCOE_QUEUE_CTX_QW1_RECIPE_MASK (0x3ULL << \ + I40E_FCOE_QUEUE_CTX_QW1_RECIPE_SHIFT) + +/* FCoE DDP/DWO Filter Context descriptor */ +struct i40e_fcoe_filter_context_desc { + __le32 param; + __le16 seqn; + + /* 48:51(0:3) RSVD, 52:63(4:15) DMAINDX */ + __le16 rsvd_dmaindx; + + /* 0:7 FLAGS, 8:52 RSVD, 53:63 LANQ */ + __le64 flags_rsvd_lanq; +}; + +#define I40E_FCOE_FILTER_CTX_QW0_DMAINDX_SHIFT 4 +#define I40E_FCOE_FILTER_CTX_QW0_DMAINDX_MASK (0xFFF << \ + I40E_FCOE_FILTER_CTX_QW0_DMAINDX_SHIFT) + +enum i40e_fcoe_filter_ctx_desc_flags_bits { + I40E_FCOE_FILTER_CTX_DESC_CTYP_DDP = 0x00, + I40E_FCOE_FILTER_CTX_DESC_CTYP_DWO = 0x01, + I40E_FCOE_FILTER_CTX_DESC_ENODE_INIT = 0x00, + I40E_FCOE_FILTER_CTX_DESC_ENODE_RSP = 0x02, + I40E_FCOE_FILTER_CTX_DESC_FC_CLASS2 = 0x00, + I40E_FCOE_FILTER_CTX_DESC_FC_CLASS3 = 0x04 +}; + +#define I40E_FCOE_FILTER_CTX_QW1_FLAGS_SHIFT 0 +#define I40E_FCOE_FILTER_CTX_QW1_FLAGS_MASK (0xFFULL << \ + I40E_FCOE_FILTER_CTX_QW1_FLAGS_SHIFT) + +#define I40E_FCOE_FILTER_CTX_QW1_PCTYPE_SHIFT 8 +#define I40E_FCOE_FILTER_CTX_QW1_PCTYPE_MASK (0x3FULL << \ + I40E_FCOE_FILTER_CTX_QW1_PCTYPE_SHIFT) + +#define I40E_FCOE_FILTER_CTX_QW1_LANQINDX_SHIFT 53 +#define I40E_FCOE_FILTER_CTX_QW1_LANQINDX_MASK (0x7FFULL << \ + I40E_FCOE_FILTER_CTX_QW1_LANQINDX_SHIFT) + +#endif /* I40E_FCOE */ enum i40e_switch_element_types { I40E_SWITCH_ELEMENT_TYPE_MAC = 1, I40E_SWITCH_ELEMENT_TYPE_PF = 2, -- cgit v1.2.3 From 38758f552dc31e7f79671635ee0979b6e5e3bbed Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Fri, 1 Aug 2014 13:27:04 -0700 Subject: i40e: adds FCoE to build and updates its documentation Adds newly added FCoE files to the build but only if FCoE module is configured. Also, updates i40e document for added FCoE support. Signed-off-by: Vasu Dev Tested-by: Jack Morgan Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- Documentation/networking/i40e.txt | 7 +++++-- drivers/net/ethernet/intel/i40e/Makefile | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/i40e.txt b/Documentation/networking/i40e.txt index f737273c6dc1..a251bf4fe9c9 100644 --- a/Documentation/networking/i40e.txt +++ b/Documentation/networking/i40e.txt @@ -69,8 +69,11 @@ Additional Configurations FCoE ---- - Fiber Channel over Ethernet (FCoE) hardware offload is not currently - supported. + The driver supports Fiber Channel over Ethernet (FCoE) and Data Center + Bridging (DCB) functionality. Configuring DCB and FCoE is outside the scope + of this driver doc. Refer to http://www.open-fcoe.org/ for FCoE project + information and http://www.open-lldp.org/ or email list + e1000-eedc@lists.sourceforge.net for DCB information. MAC and VLAN anti-spoofing feature ---------------------------------- diff --git a/drivers/net/ethernet/intel/i40e/Makefile b/drivers/net/ethernet/intel/i40e/Makefile index d9eb80acac4f..4b94ddb29c24 100644 --- a/drivers/net/ethernet/intel/i40e/Makefile +++ b/drivers/net/ethernet/intel/i40e/Makefile @@ -44,3 +44,4 @@ i40e-objs := i40e_main.o \ i40e_virtchnl_pf.o i40e-$(CONFIG_I40E_DCB) += i40e_dcb.o i40e_dcb_nl.o +i40e-$(CONFIG_FCOE:m=y) += i40e_fcoe.o -- cgit v1.2.3 From 53db45cd9ae5f39163054d55051a5a9ad0f5b821 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Fri, 1 Aug 2014 13:27:05 -0700 Subject: i40e: expose debug_write_register request Now that the HW registers are no longer in debug mode and many are locked down for writes, we need to expose the Firmware API request used to do writes on the driver's behalf. Change-ID: I09a05c4dc9ea0b24c00193faac34d7799eaa8496 Signed-off-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_common.c | 29 ++++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_prototype.h | 3 +++ 2 files changed, 32 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index a010584d8962..df43e7c6777c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -2001,6 +2001,35 @@ i40e_status i40e_aq_send_msg_to_vf(struct i40e_hw *hw, u16 vfid, return status; } +/** + * i40e_aq_debug_write_register + * @hw: pointer to the hw struct + * @reg_addr: register address + * @reg_val: register value + * @cmd_details: pointer to command details structure or NULL + * + * Write to a register using the admin queue commands + **/ +i40e_status i40e_aq_debug_write_register(struct i40e_hw *hw, + u32 reg_addr, u64 reg_val, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aqc_debug_reg_read_write *cmd = + (struct i40e_aqc_debug_reg_read_write *)&desc.params.raw; + i40e_status status; + + i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_debug_write_reg); + + cmd->address = cpu_to_le32(reg_addr); + cmd->value_high = cpu_to_le32((u32)(reg_val >> 32)); + cmd->value_low = cpu_to_le32((u32)(reg_val & 0xFFFFFFFF)); + + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + + return status; +} + /** * i40e_aq_set_hmc_resource_profile * @hw: pointer to the hw struct diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 8cd4390a2842..949a9a01778b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -70,6 +70,9 @@ i40e_status i40e_aq_get_firmware_version(struct i40e_hw *hw, u16 *fw_major_version, u16 *fw_minor_version, u16 *api_major_version, u16 *api_minor_version, struct i40e_asq_cmd_details *cmd_details); +i40e_status i40e_aq_debug_write_register(struct i40e_hw *hw, + u32 reg_addr, u64 reg_val, + struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_phy_debug(struct i40e_hw *hw, u8 cmd_flags, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_default_vsi(struct i40e_hw *hw, u16 vsi_id, -- cgit v1.2.3 From f19efbb5eff0ed718f8e213d256e3291ed4e43a9 Mon Sep 17 00:00:00 2001 From: Ashish Shah Date: Fri, 1 Aug 2014 13:27:06 -0700 Subject: i40e: use correct vf_id offset for virtchnl message The vf_id needs to be offset by the vf_base_id from hw function capabilities for the case of multiple PFs. Change-ID: I20ca8621f98e9cdf98649380b8eeaa35db52677c Signed-off-by: Ashish Shah Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index cafda0cfc1a9..504bdf5939b5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1005,7 +1005,7 @@ static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode, { struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; - int true_vf_id = vf->vf_id + hw->func_caps.vf_base_id; + int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; i40e_status aq_ret; /* single place to detect unsuccessful return values */ @@ -1025,7 +1025,7 @@ static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode, vf->num_valid_msgs++; } - aq_ret = i40e_aq_send_msg_to_vf(hw, true_vf_id, v_opcode, v_retval, + aq_ret = i40e_aq_send_msg_to_vf(hw, abs_vf_id, v_opcode, v_retval, msg, msglen, NULL); if (aq_ret) { dev_err(&pf->pdev->dev, @@ -1935,15 +1935,17 @@ static void i40e_vc_vf_broadcast(struct i40e_pf *pf, { struct i40e_hw *hw = &pf->hw; struct i40e_vf *vf = pf->vf; + int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; int i; for (i = 0; i < pf->num_alloc_vfs; i++) { /* Ignore return value on purpose - a given VF may fail, but * we need to keep going and send to all of them */ - i40e_aq_send_msg_to_vf(hw, vf->vf_id, v_opcode, v_retval, + i40e_aq_send_msg_to_vf(hw, abs_vf_id, v_opcode, v_retval, msg, msglen, NULL); vf++; + abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; } } @@ -1959,6 +1961,7 @@ void i40e_vc_notify_link_state(struct i40e_pf *pf) struct i40e_hw *hw = &pf->hw; struct i40e_vf *vf = pf->vf; struct i40e_link_status *ls = &pf->hw.phy.link_info; + int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; int i; pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE; @@ -1973,10 +1976,11 @@ void i40e_vc_notify_link_state(struct i40e_pf *pf) ls->link_info & I40E_AQ_LINK_UP; pfe.event_data.link_event.link_speed = ls->link_speed; } - i40e_aq_send_msg_to_vf(hw, vf->vf_id, I40E_VIRTCHNL_OP_EVENT, + i40e_aq_send_msg_to_vf(hw, abs_vf_id, I40E_VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, sizeof(pfe), NULL); vf++; + abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; } } @@ -2005,10 +2009,11 @@ void i40e_vc_notify_reset(struct i40e_pf *pf) void i40e_vc_notify_vf_reset(struct i40e_vf *vf) { struct i40e_virtchnl_pf_event pfe; + int abs_vf_id = vf->vf_id + vf->pf->hw.func_caps.vf_base_id; pfe.event = I40E_VIRTCHNL_EVENT_RESET_IMPENDING; pfe.severity = I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM; - i40e_aq_send_msg_to_vf(&vf->pf->hw, vf->vf_id, I40E_VIRTCHNL_OP_EVENT, + i40e_aq_send_msg_to_vf(&vf->pf->hw, abs_vf_id, I40E_VIRTCHNL_OP_EVENT, I40E_SUCCESS, (u8 *)&pfe, sizeof(struct i40e_virtchnl_pf_event), NULL); } @@ -2345,6 +2350,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) struct i40e_virtchnl_pf_event pfe; struct i40e_hw *hw = &pf->hw; struct i40e_vf *vf; + int abs_vf_id; int ret = 0; /* validate the request */ @@ -2355,6 +2361,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) } vf = &pf->vf[vf_id]; + abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE; pfe.severity = I40E_PF_EVENT_SEVERITY_INFO; @@ -2384,7 +2391,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) goto error_out; } /* Notify the VF of its new link state */ - i40e_aq_send_msg_to_vf(hw, vf->vf_id, I40E_VIRTCHNL_OP_EVENT, + i40e_aq_send_msg_to_vf(hw, abs_vf_id, I40E_VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, sizeof(pfe), NULL); error_out: -- cgit v1.2.3 From 738abbac9b8bf11a7cc3955b691cca8d7589127a Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Fri, 1 Aug 2014 13:27:07 -0700 Subject: i40e: disable local loopback on vmdq vsi The local loopback should only be enabled for VSIs that are supporting cascaded VEBs or VEPA setups. This is not the case here, and we need to stop the VEB from echoing the VMDQ VSI packets back at the VSI. Change-ID: I9dfb6ac79db24d04360d7efde62d81e20abc5090 Signed-off-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 6ac8487f9a51..51bc03072ed3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7576,7 +7576,6 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) * should be set to zero by default. */ ctxt.info.switch_id = 0; - ctxt.info.switch_id |= cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB); ctxt.info.switch_id |= cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB); /* Setup the VSI tx/rx queue map for TC0 only for now */ -- cgit v1.2.3 From b39c1e2c581fac29a63e322667cbd39a8661ca2a Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 1 Aug 2014 13:27:08 -0700 Subject: i40evf: fix scan warning on sprintf The driver was converted to use snprintf everywhere but this one function. Just use snprintf, instead of sprintf. Also a small spelling correction in a comment. Change-ID: I59d45f94a52754c7b4cd6034df9a61d8132b7f77 Signed-off-by: Jesse Brandeburg Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c | 2 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c index e70e4cdb0eb2..efee6b290c0f 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c @@ -193,7 +193,7 @@ static void i40evf_set_msglevel(struct net_device *netdev, u32 data) } /** - * i40evf_get_drvinto - Get driver info + * i40evf_get_drvinfo - Get driver info * @netdev: network interface device structure * @drvinfo: ethool driver info structure * diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index a53e81bb0960..937785db7dff 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -527,7 +527,8 @@ static int i40evf_request_misc_irq(struct i40evf_adapter *adapter) struct net_device *netdev = adapter->netdev; int err; - sprintf(adapter->misc_vector_name, "i40evf:mbx"); + snprintf(adapter->misc_vector_name, + sizeof(adapter->misc_vector_name) - 1, "i40evf:mbx"); err = request_irq(adapter->msix_entries[0].vector, &i40evf_msix_aq, 0, adapter->misc_vector_name, netdev); -- cgit v1.2.3 From 84a9208d9ee025945dc9ab79f89f9d36cc60f287 Mon Sep 17 00:00:00 2001 From: Akeem G Abodunrin Date: Fri, 1 Aug 2014 13:27:09 -0700 Subject: i40e: Minor comment changes Fixes comment for reset reason Change-ID: I6fda4fa292255e6eb0f874502b4d38d722149b10 Signed-off-by: Akeem G Abodunrin Tested-by: Jim Young Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 504bdf5939b5..033d85323d6e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -669,7 +669,7 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr) */ for (i = 0; i < 100; i++) { /* vf reset requires driver to first reset the - * vf & than poll the status register to make sure + * vf and then poll the status register to make sure * that the requested op was completed * successfully */ -- cgit v1.2.3 From 89cb86c3b2a7ec3326dc7ffe5cfb850818f78ea0 Mon Sep 17 00:00:00 2001 From: Ashish Shah Date: Fri, 1 Aug 2014 13:27:10 -0700 Subject: i40e: remove support for vf unicast promiscuous mode Remove the ability of a VF to set unicast promiscuous mode. Considered to be a security risk to allow VFs to receive traffic intended for other VFs so don't allow it, simply ignore the flag. Also fix it to send the correct seid to aq for multicast promiscuous set. Change-ID: Icb9c49a281a8e9d3aeebf991ef1533ac82b84b14 Signed-off-by: Ashish Shah Tested-by: Jim Young Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 033d85323d6e..89672551dce9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1163,8 +1163,8 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, (struct i40e_virtchnl_promisc_info *)msg; struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; + struct i40e_vsi *vsi; bool allmulti = false; - bool promisc = false; i40e_status aq_ret; if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) || @@ -1174,17 +1174,10 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, aq_ret = I40E_ERR_PARAM; goto error_param; } - - if (info->flags & I40E_FLAG_VF_UNICAST_PROMISC) - promisc = true; - aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, info->vsi_id, - promisc, NULL); - if (aq_ret) - goto error_param; - + vsi = pf->vsi[info->vsi_id]; if (info->flags & I40E_FLAG_VF_MULTICAST_PROMISC) allmulti = true; - aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, info->vsi_id, + aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid, allmulti, NULL); error_param: -- cgit v1.2.3 From fd35886ad38a5b7c71a2105a7d0cac079c735111 Mon Sep 17 00:00:00 2001 From: Ashish Shah Date: Fri, 1 Aug 2014 13:27:11 -0700 Subject: i40evf: future-proof vfr_stat state check Previously defined state I40E_VFR_VFACTIVE uses bit 1 which is now set to "reserved." Update the state checks to also include I40E_VFR_COMPLETED. This change will allow the VF to work with both existing and future PFs. Change-ID: Ifd1d34f79f3b0ffd6d2550ee4dadc55825ff52f8 Signed-off-by: Ashish Shah Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 937785db7dff..4c01079fc2ff 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1298,12 +1298,16 @@ static void i40evf_watchdog_task(struct work_struct *work) struct i40evf_adapter, watchdog_task); struct i40e_hw *hw = &adapter->hw; + uint32_t rstat_val; if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) goto restart_watchdog; if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { - if ((rd32(hw, I40E_VFGEN_RSTAT) & 0x3) == I40E_VFR_VFACTIVE) { + rstat_val = rd32(hw, I40E_VFGEN_RSTAT) & + I40E_VFGEN_RSTAT_VFR_STATE_MASK; + if ((rstat_val == I40E_VFR_VFACTIVE) || + (rstat_val == I40E_VFR_COMPLETED)) { /* A chance for redemption! */ dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n"); adapter->state = __I40EVF_STARTUP; @@ -1329,8 +1333,11 @@ static void i40evf_watchdog_task(struct work_struct *work) goto watchdog_done; /* check for reset */ + rstat_val = rd32(hw, I40E_VFGEN_RSTAT) & + I40E_VFGEN_RSTAT_VFR_STATE_MASK; if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING) && - (rd32(hw, I40E_VFGEN_RSTAT) & 0x3) != I40E_VFR_VFACTIVE) { + (rstat_val != I40E_VFR_VFACTIVE) && + (rstat_val != I40E_VFR_COMPLETED)) { adapter->state = __I40EVF_RESETTING; adapter->flags |= I40EVF_FLAG_RESET_PENDING; dev_err(&adapter->pdev->dev, "Hardware reset detected\n"); @@ -1496,7 +1503,8 @@ static void i40evf_reset_task(struct work_struct *work) for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) { rstat_val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; - if (rstat_val != I40E_VFR_VFACTIVE) + if ((rstat_val != I40E_VFR_VFACTIVE) && + (rstat_val != I40E_VFR_COMPLETED)) break; else msleep(I40EVF_RESET_WAIT_MS); @@ -1510,7 +1518,8 @@ static void i40evf_reset_task(struct work_struct *work) for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) { rstat_val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; - if (rstat_val == I40E_VFR_VFACTIVE) + if ((rstat_val == I40E_VFR_VFACTIVE) || + (rstat_val == I40E_VFR_COMPLETED)) break; else msleep(I40EVF_RESET_WAIT_MS); @@ -1947,8 +1956,10 @@ static int i40evf_check_reset_complete(struct i40e_hw *hw) int i; for (i = 0; i < 100; i++) { - rstat = rd32(hw, I40E_VFGEN_RSTAT); - if (rstat == I40E_VFR_VFACTIVE) + rstat = rd32(hw, I40E_VFGEN_RSTAT) & + I40E_VFGEN_RSTAT_VFR_STATE_MASK; + if ((rstat == I40E_VFR_VFACTIVE) || + (rstat == I40E_VFR_COMPLETED)) return 0; udelay(10); } -- cgit v1.2.3 From d3e2edb70ecf877b4e5f42314449fc648b18627b Mon Sep 17 00:00:00 2001 From: Ashish Shah Date: Fri, 1 Aug 2014 13:27:12 -0700 Subject: i40evf: do not re-arm watchdog after remove Add in an adapter state check to prevent re-arming watchdog timer after i40evf_remove has been called and timer has been deleted. Change-ID: I636ba7c6322be8cbf053231959f90c0a2d8d803a Signed-off-by: Ashish Shah Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 4c01079fc2ff..2aca9cf45119 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1403,6 +1403,8 @@ static void i40evf_watchdog_task(struct work_struct *work) watchdog_done: clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); restart_watchdog: + if (adapter->state == __I40EVF_REMOVE) + return; if (adapter->aq_required) mod_timer(&adapter->watchdog_timer, jiffies + msecs_to_jiffies(20)); -- cgit v1.2.3 From d31944d6f0872ba9536501c4850dfb20dea5bf64 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 1 Aug 2014 13:27:13 -0700 Subject: i40evf: don't leak queue vectors Fix a memory leak. Driver was allocating memory for queue vectors on init but not freeing them on shutdown. These need to be freed at two different times: during module unload, and during reset recovery when the driver cannot contact the PF driver and needs to give up. Change-ID: I7c1d0157a776e960d4da432dfe309035aad7c670 Signed-off-by: Mitch Williams Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 2aca9cf45119..0c4f7baffad6 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1542,6 +1542,7 @@ static void i40evf_reset_task(struct work_struct *work) i40evf_free_misc_irq(adapter); i40evf_reset_interrupt_capability(adapter); i40evf_free_queues(adapter); + i40evf_free_q_vectors(adapter); kfree(adapter->vf_res); i40evf_shutdown_adminq(hw); adapter->netdev->flags &= ~IFF_UP; @@ -2429,6 +2430,7 @@ static void i40evf_remove(struct pci_dev *pdev) i40evf_misc_irq_disable(adapter); i40evf_free_misc_irq(adapter); i40evf_reset_interrupt_capability(adapter); + i40evf_free_q_vectors(adapter); } if (adapter->watchdog_timer.function) -- cgit v1.2.3 From 6ba36a246ef58100ff3f31b0738e317cfab1f240 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 1 Aug 2014 13:27:14 -0700 Subject: i40evf: fix memory leak on unused interfaces If the driver is loaded and then unloaded before the interface is brought up, then it will allocate a MAC filter entry and never free it. To fix this, on unload, run through the mac filter list and free all the entries. We also do this during reset recovery when the driver cannot contact the PF and needs to shut down completely. Change-ID: I15fabd67eb4a1bfc57605a7db60d0b5d819839db Signed-off-by: Mitch Williams Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 0c4f7baffad6..e5679d82e0c0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1527,6 +1527,9 @@ static void i40evf_reset_task(struct work_struct *work) msleep(I40EVF_RESET_WAIT_MS); } if (i == I40EVF_RESET_WAIT_COUNT) { + struct i40evf_mac_filter *f, *ftmp; + struct i40evf_vlan_filter *fv, *fvtmp; + /* reset never finished */ dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n", rstat_val); @@ -1539,6 +1542,19 @@ static void i40evf_reset_task(struct work_struct *work) i40evf_free_all_tx_resources(adapter); i40evf_free_all_rx_resources(adapter); } + + /* Delete all of the filters, both MAC and VLAN. */ + list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, + list) { + list_del(&f->list); + kfree(f); + } + list_for_each_entry_safe(fv, fvtmp, &adapter->vlan_filter_list, + list) { + list_del(&fv->list); + kfree(fv); + } + i40evf_free_misc_irq(adapter); i40evf_reset_interrupt_capability(adapter); i40evf_free_queues(adapter); @@ -2415,6 +2431,7 @@ static void i40evf_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct i40evf_adapter *adapter = netdev_priv(netdev); + struct i40evf_mac_filter *f, *ftmp; struct i40e_hw *hw = &adapter->hw; cancel_delayed_work_sync(&adapter->init_task); @@ -2446,6 +2463,13 @@ static void i40evf_remove(struct pci_dev *pdev) i40evf_free_queues(adapter); kfree(adapter->vf_res); + /* If we got removed before an up/down sequence, we've got a filter + * hanging out there that we need to get rid of. + */ + list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { + list_del(&f->list); + kfree(f); + } free_netdev(netdev); -- cgit v1.2.3 From 8bb1a540450c3dbd075491ea43772ac8a7ddec46 Mon Sep 17 00:00:00 2001 From: Serey Kong Date: Fri, 1 Aug 2014 13:27:15 -0700 Subject: i40evf: Fixed guest OS panic when removing vf driver Removing VF driver during device still in reset caused guest OS panic. in the i40evf_remove(), we're trying to clean mac_filter_list which has not been initialized since the device is still stuck at the reset. The change is to initialize the filter_list before setting any task. Change-ID: I8b59df7384416c7e6f2d264b598f447e1c2c92b0 Signed-off-by: Serey Kong Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index e5679d82e0c0..ab15f4d07e41 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2137,8 +2137,6 @@ static void i40evf_init_task(struct work_struct *work) ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr); ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr); - INIT_LIST_HEAD(&adapter->mac_filter_list); - INIT_LIST_HEAD(&adapter->vlan_filter_list); f = kzalloc(sizeof(*f), GFP_ATOMIC); if (NULL == f) goto err_sw_init; @@ -2320,6 +2318,9 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->bus.device = PCI_SLOT(pdev->devfn); hw->bus.func = PCI_FUNC(pdev->devfn); + INIT_LIST_HEAD(&adapter->mac_filter_list); + INIT_LIST_HEAD(&adapter->vlan_filter_list); + INIT_WORK(&adapter->reset_task, i40evf_reset_task); INIT_WORK(&adapter->adminq_task, i40evf_adminq_task); INIT_WORK(&adapter->watchdog_task, i40evf_watchdog_task); -- cgit v1.2.3 From 7e1e77636e36075ebf118298855268468f1028e8 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Sat, 2 Aug 2014 11:47:44 +0200 Subject: lib: Resizable, Scalable, Concurrent Hash Table Generic implementation of a resizable, scalable, concurrent hash table based on [0]. The implementation supports both, fixed size keys specified via an offset and length, or arbitrary keys via own hash and compare functions. Lookups are lockless and protected as RCU read side critical sections. Automatic growing/shrinking based on user configurable watermarks is available while allowing concurrent lookups to take place. Objects to be hashed must include a struct rhash_head. The reason for not using the existing struct hlist_head is that the expansion and shrinking will have two buckets point to a single entry which would lead in obscure reverse chaining behaviour. Code includes a boot selftest if CONFIG_TEST_RHASHTABLE is defined. [0] https://www.usenix.org/legacy/event/atc11/tech/final_files/Triplett.pdf Signed-off-by: Thomas Graf Reviewed-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- include/linux/rhashtable.h | 213 ++++++++++++ lib/Kconfig.debug | 8 + lib/Makefile | 2 +- lib/rhashtable.c | 797 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1019 insertions(+), 1 deletion(-) create mode 100644 include/linux/rhashtable.h create mode 100644 lib/rhashtable.c diff --git a/include/linux/rhashtable.h b/include/linux/rhashtable.h new file mode 100644 index 000000000000..9cda293c867d --- /dev/null +++ b/include/linux/rhashtable.h @@ -0,0 +1,213 @@ +/* + * Resizable, Scalable, Concurrent Hash Table + * + * Copyright (c) 2014 Thomas Graf + * Copyright (c) 2008-2014 Patrick McHardy + * + * Based on the following paper by Josh Triplett, Paul E. McKenney + * and Jonathan Walpole: + * https://www.usenix.org/legacy/event/atc11/tech/final_files/Triplett.pdf + * + * Code partially derived from nft_hash + * + * 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. + */ + +#ifndef _LINUX_RHASHTABLE_H +#define _LINUX_RHASHTABLE_H + +#include + +struct rhash_head { + struct rhash_head *next; +}; + +#define INIT_HASH_HEAD(ptr) ((ptr)->next = NULL) + +struct bucket_table { + size_t size; + struct rhash_head __rcu *buckets[]; +}; + +typedef u32 (*rht_hashfn_t)(const void *data, u32 len, u32 seed); +typedef u32 (*rht_obj_hashfn_t)(const void *data, u32 seed); + +struct rhashtable; + +/** + * struct rhashtable_params - Hash table construction parameters + * @nelem_hint: Hint on number of elements, should be 75% of desired size + * @key_len: Length of key + * @key_offset: Offset of key in struct to be hashed + * @head_offset: Offset of rhash_head in struct to be hashed + * @hash_rnd: Seed to use while hashing + * @max_shift: Maximum number of shifts while expanding + * @hashfn: Function to hash key + * @obj_hashfn: Function to hash object + * @grow_decision: If defined, may return true if table should expand + * @shrink_decision: If defined, may return true if table should shrink + * @mutex_is_held: Must return true if protecting mutex is held + */ +struct rhashtable_params { + size_t nelem_hint; + size_t key_len; + size_t key_offset; + size_t head_offset; + u32 hash_rnd; + size_t max_shift; + rht_hashfn_t hashfn; + rht_obj_hashfn_t obj_hashfn; + bool (*grow_decision)(const struct rhashtable *ht, + size_t new_size); + bool (*shrink_decision)(const struct rhashtable *ht, + size_t new_size); + int (*mutex_is_held)(void); +}; + +/** + * struct rhashtable - Hash table handle + * @tbl: Bucket table + * @nelems: Number of elements in table + * @shift: Current size (1 << shift) + * @p: Configuration parameters + */ +struct rhashtable { + struct bucket_table __rcu *tbl; + size_t nelems; + size_t shift; + struct rhashtable_params p; +}; + +#ifdef CONFIG_PROVE_LOCKING +int lockdep_rht_mutex_is_held(const struct rhashtable *ht); +#else +static inline int lockdep_rht_mutex_is_held(const struct rhashtable *ht) +{ + return 1; +} +#endif /* CONFIG_PROVE_LOCKING */ + +int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params); + +u32 rhashtable_hashfn(const struct rhashtable *ht, const void *key, u32 len); +u32 rhashtable_obj_hashfn(const struct rhashtable *ht, void *ptr); + +void rhashtable_insert(struct rhashtable *ht, struct rhash_head *node, gfp_t); +bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *node, gfp_t); +void rhashtable_remove_pprev(struct rhashtable *ht, struct rhash_head *obj, + struct rhash_head **pprev, gfp_t flags); + +bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size); +bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size); + +int rhashtable_expand(struct rhashtable *ht, gfp_t flags); +int rhashtable_shrink(struct rhashtable *ht, gfp_t flags); + +void *rhashtable_lookup(const struct rhashtable *ht, const void *key); +void *rhashtable_lookup_compare(const struct rhashtable *ht, u32 hash, + bool (*compare)(void *, void *), void *arg); + +void rhashtable_destroy(const struct rhashtable *ht); + +#define rht_dereference(p, ht) \ + rcu_dereference_protected(p, lockdep_rht_mutex_is_held(ht)) + +#define rht_dereference_rcu(p, ht) \ + rcu_dereference_check(p, lockdep_rht_mutex_is_held(ht)) + +/* Internal, use rht_obj() instead */ +#define rht_entry(ptr, type, member) container_of(ptr, type, member) +#define rht_entry_safe(ptr, type, member) \ +({ \ + typeof(ptr) __ptr = (ptr); \ + __ptr ? rht_entry(__ptr, type, member) : NULL; \ +}) +#define rht_entry_safe_rcu(ptr, type, member) \ +({ \ + typeof(*ptr) __rcu *__ptr = (typeof(*ptr) __rcu __force *)ptr; \ + __ptr ? container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member) : NULL; \ +}) + +#define rht_next_entry_safe(pos, ht, member) \ +({ \ + pos ? rht_entry_safe(rht_dereference((pos)->member.next, ht), \ + typeof(*(pos)), member) : NULL; \ +}) + +/** + * rht_for_each - iterate over hash chain + * @pos: &struct rhash_head to use as a loop cursor. + * @head: head of the hash chain (struct rhash_head *) + * @ht: pointer to your struct rhashtable + */ +#define rht_for_each(pos, head, ht) \ + for (pos = rht_dereference(head, ht); \ + pos; \ + pos = rht_dereference((pos)->next, ht)) + +/** + * rht_for_each_entry - iterate over hash chain of given type + * @pos: type * to use as a loop cursor. + * @head: head of the hash chain (struct rhash_head *) + * @ht: pointer to your struct rhashtable + * @member: name of the rhash_head within the hashable struct. + */ +#define rht_for_each_entry(pos, head, ht, member) \ + for (pos = rht_entry_safe(rht_dereference(head, ht), \ + typeof(*(pos)), member); \ + pos; \ + pos = rht_next_entry_safe(pos, ht, member)) + +/** + * rht_for_each_entry_safe - safely iterate over hash chain of given type + * @pos: type * to use as a loop cursor. + * @n: type * to use for temporary next object storage + * @head: head of the hash chain (struct rhash_head *) + * @ht: pointer to your struct rhashtable + * @member: name of the rhash_head within the hashable struct. + * + * This hash chain list-traversal primitive allows for the looped code to + * remove the loop cursor from the list. + */ +#define rht_for_each_entry_safe(pos, n, head, ht, member) \ + for (pos = rht_entry_safe(rht_dereference(head, ht), \ + typeof(*(pos)), member), \ + n = rht_next_entry_safe(pos, ht, member); \ + pos; \ + pos = n, \ + n = rht_next_entry_safe(pos, ht, member)) + +/** + * rht_for_each_rcu - iterate over rcu hash chain + * @pos: &struct rhash_head to use as a loop cursor. + * @head: head of the hash chain (struct rhash_head *) + * @ht: pointer to your struct rhashtable + * + * This hash chain list-traversal primitive may safely run concurrently with + * the _rcu fkht mutation primitives such as rht_insert() as long as the + * traversal is guarded by rcu_read_lock(). + */ +#define rht_for_each_rcu(pos, head, ht) \ + for (pos = rht_dereference_rcu(head, ht); \ + pos; \ + pos = rht_dereference_rcu((pos)->next, ht)) + +/** + * rht_for_each_entry_rcu - iterate over rcu hash chain of given type + * @pos: type * to use as a loop cursor. + * @head: head of the hash chain (struct rhash_head *) + * @member: name of the rhash_head within the hashable struct. + * + * This hash chain list-traversal primitive may safely run concurrently with + * the _rcu fkht mutation primitives such as rht_insert() as long as the + * traversal is guarded by rcu_read_lock(). + */ +#define rht_for_each_entry_rcu(pos, head, member) \ + for (pos = rht_entry_safe_rcu(head, typeof(*(pos)), member); \ + pos; \ + pos = rht_entry_safe_rcu((pos)->member.next, \ + typeof(*(pos)), member)) + +#endif /* _LINUX_RHASHTABLE_H */ diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 7a638aa3545b..f11a2e8f6157 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1550,6 +1550,14 @@ config TEST_STRING_HELPERS config TEST_KSTRTOX tristate "Test kstrto*() family of functions at runtime" +config TEST_RHASHTABLE + bool "Perform selftest on resizable hash table" + default n + help + Enable this option to test the rhashtable functions at boot. + + If unsure, say N. + endmenu # runtime tests config PROVIDE_OHCI1394_DMA_INIT diff --git a/lib/Makefile b/lib/Makefile index ba967a19edba..fd248e4c05ad 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -26,7 +26,7 @@ obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \ bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \ - percpu-refcount.o percpu_ida.o hash.o + percpu-refcount.o percpu_ida.o hash.o rhashtable.o obj-y += string_helpers.o obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o obj-y += kstrtox.o diff --git a/lib/rhashtable.c b/lib/rhashtable.c new file mode 100644 index 000000000000..e6940cf16628 --- /dev/null +++ b/lib/rhashtable.c @@ -0,0 +1,797 @@ +/* + * Resizable, Scalable, Concurrent Hash Table + * + * Copyright (c) 2014 Thomas Graf + * Copyright (c) 2008-2014 Patrick McHardy + * + * Based on the following paper: + * https://www.usenix.org/legacy/event/atc11/tech/final_files/Triplett.pdf + * + * Code partially derived from nft_hash + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HASH_DEFAULT_SIZE 64UL +#define HASH_MIN_SIZE 4UL + +#define ASSERT_RHT_MUTEX(HT) BUG_ON(!lockdep_rht_mutex_is_held(HT)) + +#ifdef CONFIG_PROVE_LOCKING +int lockdep_rht_mutex_is_held(const struct rhashtable *ht) +{ + return ht->p.mutex_is_held(); +} +EXPORT_SYMBOL_GPL(lockdep_rht_mutex_is_held); +#endif + +/** + * rht_obj - cast hash head to outer object + * @ht: hash table + * @he: hashed node + */ +void *rht_obj(const struct rhashtable *ht, const struct rhash_head *he) +{ + return (void *) he - ht->p.head_offset; +} +EXPORT_SYMBOL_GPL(rht_obj); + +static u32 __hashfn(const struct rhashtable *ht, const void *key, + u32 len, u32 hsize) +{ + u32 h; + + h = ht->p.hashfn(key, len, ht->p.hash_rnd); + + return h & (hsize - 1); +} + +/** + * rhashtable_hashfn - compute hash for key of given length + * @ht: hash table to compuate for + * @key: pointer to key + * @len: length of key + * + * Computes the hash value using the hash function provided in the 'hashfn' + * of struct rhashtable_params. The returned value is guaranteed to be + * smaller than the number of buckets in the hash table. + */ +u32 rhashtable_hashfn(const struct rhashtable *ht, const void *key, u32 len) +{ + struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); + + return __hashfn(ht, key, len, tbl->size); +} +EXPORT_SYMBOL_GPL(rhashtable_hashfn); + +static u32 obj_hashfn(const struct rhashtable *ht, const void *ptr, u32 hsize) +{ + if (unlikely(!ht->p.key_len)) { + u32 h; + + h = ht->p.obj_hashfn(ptr, ht->p.hash_rnd); + + return h & (hsize - 1); + } + + return __hashfn(ht, ptr + ht->p.key_offset, ht->p.key_len, hsize); +} + +/** + * rhashtable_obj_hashfn - compute hash for hashed object + * @ht: hash table to compuate for + * @ptr: pointer to hashed object + * + * Computes the hash value using the hash function `hashfn` respectively + * 'obj_hashfn' depending on whether the hash table is set up to work with + * a fixed length key. The returned value is guaranteed to be smaller than + * the number of buckets in the hash table. + */ +u32 rhashtable_obj_hashfn(const struct rhashtable *ht, void *ptr) +{ + struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); + + return obj_hashfn(ht, ptr, tbl->size); +} +EXPORT_SYMBOL_GPL(rhashtable_obj_hashfn); + +static u32 head_hashfn(const struct rhashtable *ht, + const struct rhash_head *he, u32 hsize) +{ + return obj_hashfn(ht, rht_obj(ht, he), hsize); +} + +static struct bucket_table *bucket_table_alloc(size_t nbuckets, gfp_t flags) +{ + struct bucket_table *tbl; + size_t size; + + size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]); + tbl = kzalloc(size, flags); + if (tbl == NULL) + tbl = vzalloc(size); + + if (tbl == NULL) + return NULL; + + tbl->size = nbuckets; + + return tbl; +} + +static void bucket_table_free(const struct bucket_table *tbl) +{ + kvfree(tbl); +} + +/** + * rht_grow_above_75 - returns true if nelems > 0.75 * table-size + * @ht: hash table + * @new_size: new table size + */ +bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size) +{ + /* Expand table when exceeding 75% load */ + return ht->nelems > (new_size / 4 * 3); +} +EXPORT_SYMBOL_GPL(rht_grow_above_75); + +/** + * rht_shrink_below_30 - returns true if nelems < 0.3 * table-size + * @ht: hash table + * @new_size: new table size + */ +bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size) +{ + /* Shrink table beneath 30% load */ + return ht->nelems < (new_size * 3 / 10); +} +EXPORT_SYMBOL_GPL(rht_shrink_below_30); + +static void hashtable_chain_unzip(const struct rhashtable *ht, + const struct bucket_table *new_tbl, + struct bucket_table *old_tbl, size_t n) +{ + struct rhash_head *he, *p, *next; + unsigned int h; + + /* Old bucket empty, no work needed. */ + p = rht_dereference(old_tbl->buckets[n], ht); + if (!p) + return; + + /* Advance the old bucket pointer one or more times until it + * reaches a node that doesn't hash to the same bucket as the + * previous node p. Call the previous node p; + */ + h = head_hashfn(ht, p, new_tbl->size); + rht_for_each(he, p->next, ht) { + if (head_hashfn(ht, he, new_tbl->size) != h) + break; + p = he; + } + RCU_INIT_POINTER(old_tbl->buckets[n], p->next); + + /* Find the subsequent node which does hash to the same + * bucket as node P, or NULL if no such node exists. + */ + next = NULL; + if (he) { + rht_for_each(he, he->next, ht) { + if (head_hashfn(ht, he, new_tbl->size) == h) { + next = he; + break; + } + } + } + + /* Set p's next pointer to that subsequent node pointer, + * bypassing the nodes which do not hash to p's bucket + */ + RCU_INIT_POINTER(p->next, next); +} + +/** + * rhashtable_expand - Expand hash table while allowing concurrent lookups + * @ht: the hash table to expand + * @flags: allocation flags + * + * A secondary bucket array is allocated and the hash entries are migrated + * while keeping them on both lists until the end of the RCU grace period. + * + * This function may only be called in a context where it is safe to call + * synchronize_rcu(), e.g. not within a rcu_read_lock() section. + * + * The caller must ensure that no concurrent table mutations take place. + * It is however valid to have concurrent lookups if they are RCU protected. + */ +int rhashtable_expand(struct rhashtable *ht, gfp_t flags) +{ + struct bucket_table *new_tbl, *old_tbl = rht_dereference(ht->tbl, ht); + struct rhash_head *he; + unsigned int i, h; + bool complete; + + ASSERT_RHT_MUTEX(ht); + + if (ht->p.max_shift && ht->shift >= ht->p.max_shift) + return 0; + + new_tbl = bucket_table_alloc(old_tbl->size * 2, flags); + if (new_tbl == NULL) + return -ENOMEM; + + ht->shift++; + + /* For each new bucket, search the corresponding old bucket + * for the first entry that hashes to the new bucket, and + * link the new bucket to that entry. Since all the entries + * which will end up in the new bucket appear in the same + * old bucket, this constructs an entirely valid new hash + * table, but with multiple buckets "zipped" together into a + * single imprecise chain. + */ + for (i = 0; i < new_tbl->size; i++) { + h = i & (old_tbl->size - 1); + rht_for_each(he, old_tbl->buckets[h], ht) { + if (head_hashfn(ht, he, new_tbl->size) == i) { + RCU_INIT_POINTER(new_tbl->buckets[i], he); + break; + } + } + } + + /* Publish the new table pointer. Lookups may now traverse + * the new table, but they will not benefit from any + * additional efficiency until later steps unzip the buckets. + */ + rcu_assign_pointer(ht->tbl, new_tbl); + + /* Unzip interleaved hash chains */ + do { + /* Wait for readers. All new readers will see the new + * table, and thus no references to the old table will + * remain. + */ + synchronize_rcu(); + + /* For each bucket in the old table (each of which + * contains items from multiple buckets of the new + * table): ... + */ + complete = true; + for (i = 0; i < old_tbl->size; i++) { + hashtable_chain_unzip(ht, new_tbl, old_tbl, i); + if (old_tbl->buckets[i] != NULL) + complete = false; + } + } while (!complete); + + bucket_table_free(old_tbl); + return 0; +} +EXPORT_SYMBOL_GPL(rhashtable_expand); + +/** + * rhashtable_shrink - Shrink hash table while allowing concurrent lookups + * @ht: the hash table to shrink + * @flags: allocation flags + * + * This function may only be called in a context where it is safe to call + * synchronize_rcu(), e.g. not within a rcu_read_lock() section. + * + * The caller must ensure that no concurrent table mutations take place. + * It is however valid to have concurrent lookups if they are RCU protected. + */ +int rhashtable_shrink(struct rhashtable *ht, gfp_t flags) +{ + struct bucket_table *ntbl, *tbl = rht_dereference(ht->tbl, ht); + struct rhash_head __rcu **pprev; + unsigned int i; + + ASSERT_RHT_MUTEX(ht); + + if (tbl->size <= HASH_MIN_SIZE) + return 0; + + ntbl = bucket_table_alloc(tbl->size / 2, flags); + if (ntbl == NULL) + return -ENOMEM; + + ht->shift--; + + /* Link each bucket in the new table to the first bucket + * in the old table that contains entries which will hash + * to the new bucket. + */ + for (i = 0; i < ntbl->size; i++) { + ntbl->buckets[i] = tbl->buckets[i]; + + /* Link each bucket in the new table to the first bucket + * in the old table that contains entries which will hash + * to the new bucket. + */ + for (pprev = &ntbl->buckets[i]; *pprev != NULL; + pprev = &rht_dereference(*pprev, ht)->next) + ; + RCU_INIT_POINTER(*pprev, tbl->buckets[i + ntbl->size]); + } + + /* Publish the new, valid hash table */ + rcu_assign_pointer(ht->tbl, ntbl); + + /* Wait for readers. No new readers will have references to the + * old hash table. + */ + synchronize_rcu(); + + bucket_table_free(tbl); + + return 0; +} +EXPORT_SYMBOL_GPL(rhashtable_shrink); + +/** + * rhashtable_insert - insert object into hash hash table + * @ht: hash table + * @obj: pointer to hash head inside object + * @flags: allocation flags (table expansion) + * + * Will automatically grow the table via rhashtable_expand() if the the + * grow_decision function specified at rhashtable_init() returns true. + * + * The caller must ensure that no concurrent table mutations occur. It is + * however valid to have concurrent lookups if they are RCU protected. + */ +void rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj, + gfp_t flags) +{ + struct bucket_table *tbl = rht_dereference(ht->tbl, ht); + u32 hash; + + ASSERT_RHT_MUTEX(ht); + + hash = head_hashfn(ht, obj, tbl->size); + RCU_INIT_POINTER(obj->next, tbl->buckets[hash]); + rcu_assign_pointer(tbl->buckets[hash], obj); + ht->nelems++; + + if (ht->p.grow_decision && ht->p.grow_decision(ht, tbl->size)) + rhashtable_expand(ht, flags); +} +EXPORT_SYMBOL_GPL(rhashtable_insert); + +/** + * rhashtable_remove_pprev - remove object from hash table given previous element + * @ht: hash table + * @obj: pointer to hash head inside object + * @pprev: pointer to previous element + * @flags: allocation flags (table expansion) + * + * Identical to rhashtable_remove() but caller is alreayd aware of the element + * in front of the element to be deleted. This is in particular useful for + * deletion when combined with walking or lookup. + */ +void rhashtable_remove_pprev(struct rhashtable *ht, struct rhash_head *obj, + struct rhash_head **pprev, gfp_t flags) +{ + struct bucket_table *tbl = rht_dereference(ht->tbl, ht); + + ASSERT_RHT_MUTEX(ht); + + RCU_INIT_POINTER(*pprev, obj->next); + ht->nelems--; + + if (ht->p.shrink_decision && + ht->p.shrink_decision(ht, tbl->size)) + rhashtable_shrink(ht, flags); +} +EXPORT_SYMBOL_GPL(rhashtable_remove_pprev); + +/** + * rhashtable_remove - remove object from hash table + * @ht: hash table + * @obj: pointer to hash head inside object + * @flags: allocation flags (table expansion) + * + * Since the hash chain is single linked, the removal operation needs to + * walk the bucket chain upon removal. The removal operation is thus + * considerable slow if the hash table is not correctly sized. + * + * Will automatically shrink the table via rhashtable_expand() if the the + * shrink_decision function specified at rhashtable_init() returns true. + * + * The caller must ensure that no concurrent table mutations occur. It is + * however valid to have concurrent lookups if they are RCU protected. + */ +bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *obj, + gfp_t flags) +{ + struct bucket_table *tbl = rht_dereference(ht->tbl, ht); + struct rhash_head __rcu **pprev; + struct rhash_head *he; + u32 h; + + ASSERT_RHT_MUTEX(ht); + + h = head_hashfn(ht, obj, tbl->size); + + pprev = &tbl->buckets[h]; + rht_for_each(he, tbl->buckets[h], ht) { + if (he != obj) { + pprev = &he->next; + continue; + } + + rhashtable_remove_pprev(ht, he, pprev, flags); + return true; + } + + return false; +} +EXPORT_SYMBOL_GPL(rhashtable_remove); + +/** + * rhashtable_lookup - lookup key in hash table + * @ht: hash table + * @key: pointer to key + * + * Computes the hash value for the key and traverses the bucket chain looking + * for a entry with an identical key. The first matching entry is returned. + * + * This lookup function may only be used for fixed key hash table (key_len + * paramter set). It will BUG() if used inappropriately. + * + * Lookups may occur in parallel with hash mutations as long as the lookup is + * guarded by rcu_read_lock(). The caller must take care of this. + */ +void *rhashtable_lookup(const struct rhashtable *ht, const void *key) +{ + const struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); + struct rhash_head *he; + u32 h; + + BUG_ON(!ht->p.key_len); + + h = __hashfn(ht, key, ht->p.key_len, tbl->size); + rht_for_each_rcu(he, tbl->buckets[h], ht) { + if (memcmp(rht_obj(ht, he) + ht->p.key_offset, key, + ht->p.key_len)) + continue; + return (void *) he - ht->p.head_offset; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(rhashtable_lookup); + +/** + * rhashtable_lookup_compare - search hash table with compare function + * @ht: hash table + * @hash: hash value of desired entry + * @compare: compare function, must return true on match + * @arg: argument passed on to compare function + * + * Traverses the bucket chain behind the provided hash value and calls the + * specified compare function for each entry. + * + * Lookups may occur in parallel with hash mutations as long as the lookup is + * guarded by rcu_read_lock(). The caller must take care of this. + * + * Returns the first entry on which the compare function returned true. + */ +void *rhashtable_lookup_compare(const struct rhashtable *ht, u32 hash, + bool (*compare)(void *, void *), void *arg) +{ + const struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); + struct rhash_head *he; + + if (unlikely(hash >= tbl->size)) + return NULL; + + rht_for_each_rcu(he, tbl->buckets[hash], ht) { + if (!compare(rht_obj(ht, he), arg)) + continue; + return (void *) he - ht->p.head_offset; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(rhashtable_lookup_compare); + +static size_t rounded_hashtable_size(unsigned int nelem) +{ + return max(roundup_pow_of_two(nelem * 4 / 3), HASH_MIN_SIZE); +} + +/** + * rhashtable_init - initialize a new hash table + * @ht: hash table to be initialized + * @params: configuration parameters + * + * Initializes a new hash table based on the provided configuration + * parameters. A table can be configured either with a variable or + * fixed length key: + * + * Configuration Example 1: Fixed length keys + * struct test_obj { + * int key; + * void * my_member; + * struct rhash_head node; + * }; + * + * struct rhashtable_params params = { + * .head_offset = offsetof(struct test_obj, node), + * .key_offset = offsetof(struct test_obj, key), + * .key_len = sizeof(int), + * .hashfn = arch_fast_hash, + * .mutex_is_held = &my_mutex_is_held, + * }; + * + * Configuration Example 2: Variable length keys + * struct test_obj { + * [...] + * struct rhash_head node; + * }; + * + * u32 my_hash_fn(const void *data, u32 seed) + * { + * struct test_obj *obj = data; + * + * return [... hash ...]; + * } + * + * struct rhashtable_params params = { + * .head_offset = offsetof(struct test_obj, node), + * .hashfn = arch_fast_hash, + * .obj_hashfn = my_hash_fn, + * .mutex_is_held = &my_mutex_is_held, + * }; + */ +int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params) +{ + struct bucket_table *tbl; + size_t size; + + size = HASH_DEFAULT_SIZE; + + if ((params->key_len && !params->hashfn) || + (!params->key_len && !params->obj_hashfn)) + return -EINVAL; + + if (params->nelem_hint) + size = rounded_hashtable_size(params->nelem_hint); + + tbl = bucket_table_alloc(size, GFP_KERNEL); + if (tbl == NULL) + return -ENOMEM; + + memset(ht, 0, sizeof(*ht)); + ht->shift = ilog2(tbl->size); + memcpy(&ht->p, params, sizeof(*params)); + RCU_INIT_POINTER(ht->tbl, tbl); + + if (!ht->p.hash_rnd) + get_random_bytes(&ht->p.hash_rnd, sizeof(ht->p.hash_rnd)); + + return 0; +} +EXPORT_SYMBOL_GPL(rhashtable_init); + +/** + * rhashtable_destroy - destroy hash table + * @ht: the hash table to destroy + * + * Frees the bucket array. + */ +void rhashtable_destroy(const struct rhashtable *ht) +{ + const struct bucket_table *tbl = rht_dereference(ht->tbl, ht); + + bucket_table_free(tbl); +} +EXPORT_SYMBOL_GPL(rhashtable_destroy); + +/************************************************************************** + * Self Test + **************************************************************************/ + +#ifdef CONFIG_TEST_RHASHTABLE + +#define TEST_HT_SIZE 8 +#define TEST_ENTRIES 2048 +#define TEST_PTR ((void *) 0xdeadbeef) +#define TEST_NEXPANDS 4 + +static int test_mutex_is_held(void) +{ + return 1; +} + +struct test_obj { + void *ptr; + int value; + struct rhash_head node; +}; + +static int __init test_rht_lookup(struct rhashtable *ht) +{ + unsigned int i; + + for (i = 0; i < TEST_ENTRIES * 2; i++) { + struct test_obj *obj; + bool expected = !(i % 2); + u32 key = i; + + obj = rhashtable_lookup(ht, &key); + + if (expected && !obj) { + pr_warn("Test failed: Could not find key %u\n", key); + return -ENOENT; + } else if (!expected && obj) { + pr_warn("Test failed: Unexpected entry found for key %u\n", + key); + return -EEXIST; + } else if (expected && obj) { + if (obj->ptr != TEST_PTR || obj->value != i) { + pr_warn("Test failed: Lookup value mismatch %p!=%p, %u!=%u\n", + obj->ptr, TEST_PTR, obj->value, i); + return -EINVAL; + } + } + } + + return 0; +} + +static void test_bucket_stats(struct rhashtable *ht, + struct bucket_table *tbl, + bool quiet) +{ + unsigned int cnt, i, total = 0; + struct test_obj *obj; + + for (i = 0; i < tbl->size; i++) { + cnt = 0; + + if (!quiet) + pr_info(" [%#4x/%zu]", i, tbl->size); + + rht_for_each_entry_rcu(obj, tbl->buckets[i], node) { + cnt++; + total++; + if (!quiet) + pr_cont(" [%p],", obj); + } + + if (!quiet) + pr_cont("\n [%#x] first element: %p, chain length: %u\n", + i, tbl->buckets[i], cnt); + } + + pr_info(" Traversal complete: counted=%u, nelems=%zu, entries=%d\n", + total, ht->nelems, TEST_ENTRIES); +} + +static int __init test_rhashtable(struct rhashtable *ht) +{ + struct bucket_table *tbl; + struct test_obj *obj, *next; + int err; + unsigned int i; + + /* + * Insertion Test: + * Insert TEST_ENTRIES into table with all keys even numbers + */ + pr_info(" Adding %d keys\n", TEST_ENTRIES); + for (i = 0; i < TEST_ENTRIES; i++) { + struct test_obj *obj; + + obj = kzalloc(sizeof(*obj), GFP_KERNEL); + if (!obj) { + err = -ENOMEM; + goto error; + } + + obj->ptr = TEST_PTR; + obj->value = i * 2; + + rhashtable_insert(ht, &obj->node, GFP_KERNEL); + } + + rcu_read_lock(); + tbl = rht_dereference_rcu(ht->tbl, ht); + test_bucket_stats(ht, tbl, true); + test_rht_lookup(ht); + rcu_read_unlock(); + + for (i = 0; i < TEST_NEXPANDS; i++) { + pr_info(" Table expansion iteration %u...\n", i); + rhashtable_expand(ht, GFP_KERNEL); + + rcu_read_lock(); + pr_info(" Verifying lookups...\n"); + test_rht_lookup(ht); + rcu_read_unlock(); + } + + for (i = 0; i < TEST_NEXPANDS; i++) { + pr_info(" Table shrinkage iteration %u...\n", i); + rhashtable_shrink(ht, GFP_KERNEL); + + rcu_read_lock(); + pr_info(" Verifying lookups...\n"); + test_rht_lookup(ht); + rcu_read_unlock(); + } + + pr_info(" Deleting %d keys\n", TEST_ENTRIES); + for (i = 0; i < TEST_ENTRIES; i++) { + u32 key = i * 2; + + obj = rhashtable_lookup(ht, &key); + BUG_ON(!obj); + + rhashtable_remove(ht, &obj->node, GFP_KERNEL); + kfree(obj); + } + + return 0; + +error: + tbl = rht_dereference_rcu(ht->tbl, ht); + for (i = 0; i < tbl->size; i++) + rht_for_each_entry_safe(obj, next, tbl->buckets[i], ht, node) + kfree(obj); + + return err; +} + +static int __init test_rht_init(void) +{ + struct rhashtable ht; + struct rhashtable_params params = { + .nelem_hint = TEST_HT_SIZE, + .head_offset = offsetof(struct test_obj, node), + .key_offset = offsetof(struct test_obj, value), + .key_len = sizeof(int), + .hashfn = arch_fast_hash, + .mutex_is_held = &test_mutex_is_held, + .grow_decision = rht_grow_above_75, + .shrink_decision = rht_shrink_below_30, + }; + int err; + + pr_info("Running resizable hashtable tests...\n"); + + err = rhashtable_init(&ht, ¶ms); + if (err < 0) { + pr_warn("Test failed: Unable to initialize hashtable: %d\n", + err); + return err; + } + + err = test_rhashtable(&ht); + + rhashtable_destroy(&ht); + + return err; +} + +subsys_initcall(test_rht_init); + +#endif /* CONFIG_TEST_RHASHTABLE */ -- cgit v1.2.3 From e341694e3eb57fcda9f1adc7bfea42fe080d8d7a Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Sat, 2 Aug 2014 11:47:45 +0200 Subject: netlink: Convert netlink_lookup() to use RCU protected hash table Heavy Netlink users such as Open vSwitch spend a considerable amount of time in netlink_lookup() due to the read-lock on nl_table_lock. Use of RCU relieves the lock contention. Makes use of the new resizable hash table to avoid locking on the lookup. The hash table will grow if entries exceeds 75% of table size up to a total table size of 64K. It will automatically shrink if usage falls below 30%. Also splits nl_table_lock into a separate mutex to protect hash table mutations and allow synchronize_rcu() to sleep while waiting for readers during expansion and shrinking. Before: 9.16% kpktgend_0 [openvswitch] [k] masked_flow_lookup 6.42% kpktgend_0 [pktgen] [k] mod_cur_headers 6.26% kpktgend_0 [pktgen] [k] pktgen_thread_worker 6.23% kpktgend_0 [kernel.kallsyms] [k] memset 4.79% kpktgend_0 [kernel.kallsyms] [k] netlink_lookup 4.37% kpktgend_0 [kernel.kallsyms] [k] memcpy 3.60% kpktgend_0 [openvswitch] [k] ovs_flow_extract 2.69% kpktgend_0 [kernel.kallsyms] [k] jhash2 After: 15.26% kpktgend_0 [openvswitch] [k] masked_flow_lookup 8.12% kpktgend_0 [pktgen] [k] pktgen_thread_worker 7.92% kpktgend_0 [pktgen] [k] mod_cur_headers 5.11% kpktgend_0 [kernel.kallsyms] [k] memset 4.11% kpktgend_0 [openvswitch] [k] ovs_flow_extract 4.06% kpktgend_0 [kernel.kallsyms] [k] _raw_spin_lock 3.90% kpktgend_0 [kernel.kallsyms] [k] jhash2 [...] 0.67% kpktgend_0 [kernel.kallsyms] [k] netlink_lookup Signed-off-by: Thomas Graf Reviewed-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 285 ++++++++++++++++++----------------------------- net/netlink/af_netlink.h | 18 +-- net/netlink/diag.c | 11 +- 3 files changed, 119 insertions(+), 195 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index ce82722a7265..0b89ca51a3af 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -58,7 +58,9 @@ #include #include #include +#include #include +#include #include #include @@ -100,6 +102,18 @@ static atomic_t nl_table_users = ATOMIC_INIT(0); #define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock)); +/* Protects netlink socket hash table mutations */ +DEFINE_MUTEX(nl_sk_hash_lock); + +static int lockdep_nl_sk_hash_is_held(void) +{ +#ifdef CONFIG_LOCKDEP + return (debug_locks) ? lockdep_is_held(&nl_sk_hash_lock) : 1; +#else + return 1; +#endif +} + static ATOMIC_NOTIFIER_HEAD(netlink_chain); static DEFINE_SPINLOCK(netlink_tap_lock); @@ -110,11 +124,6 @@ static inline u32 netlink_group_mask(u32 group) return group ? 1 << (group - 1) : 0; } -static inline struct hlist_head *nl_portid_hashfn(struct nl_portid_hash *hash, u32 portid) -{ - return &hash->table[jhash_1word(portid, hash->rnd) & hash->mask]; -} - int netlink_add_tap(struct netlink_tap *nt) { if (unlikely(nt->dev->type != ARPHRD_NETLINK)) @@ -983,105 +992,48 @@ netlink_unlock_table(void) wake_up(&nl_table_wait); } -static bool netlink_compare(struct net *net, struct sock *sk) -{ - return net_eq(sock_net(sk), net); -} - -static struct sock *netlink_lookup(struct net *net, int protocol, u32 portid) +struct netlink_compare_arg { - struct netlink_table *table = &nl_table[protocol]; - struct nl_portid_hash *hash = &table->hash; - struct hlist_head *head; - struct sock *sk; - - read_lock(&nl_table_lock); - head = nl_portid_hashfn(hash, portid); - sk_for_each(sk, head) { - if (table->compare(net, sk) && - (nlk_sk(sk)->portid == portid)) { - sock_hold(sk); - goto found; - } - } - sk = NULL; -found: - read_unlock(&nl_table_lock); - return sk; -} + struct net *net; + u32 portid; +}; -static struct hlist_head *nl_portid_hash_zalloc(size_t size) +static bool netlink_compare(void *ptr, void *arg) { - if (size <= PAGE_SIZE) - return kzalloc(size, GFP_ATOMIC); - else - return (struct hlist_head *) - __get_free_pages(GFP_ATOMIC | __GFP_ZERO, - get_order(size)); -} + struct netlink_compare_arg *x = arg; + struct sock *sk = ptr; -static void nl_portid_hash_free(struct hlist_head *table, size_t size) -{ - if (size <= PAGE_SIZE) - kfree(table); - else - free_pages((unsigned long)table, get_order(size)); + return nlk_sk(sk)->portid == x->portid && + net_eq(sock_net(sk), x->net); } -static int nl_portid_hash_rehash(struct nl_portid_hash *hash, int grow) +static struct sock *__netlink_lookup(struct netlink_table *table, u32 portid, + struct net *net) { - unsigned int omask, mask, shift; - size_t osize, size; - struct hlist_head *otable, *table; - int i; - - omask = mask = hash->mask; - osize = size = (mask + 1) * sizeof(*table); - shift = hash->shift; - - if (grow) { - if (++shift > hash->max_shift) - return 0; - mask = mask * 2 + 1; - size *= 2; - } + struct netlink_compare_arg arg = { + .net = net, + .portid = portid, + }; + u32 hash; - table = nl_portid_hash_zalloc(size); - if (!table) - return 0; + hash = rhashtable_hashfn(&table->hash, &portid, sizeof(portid)); - otable = hash->table; - hash->table = table; - hash->mask = mask; - hash->shift = shift; - get_random_bytes(&hash->rnd, sizeof(hash->rnd)); - - for (i = 0; i <= omask; i++) { - struct sock *sk; - struct hlist_node *tmp; - - sk_for_each_safe(sk, tmp, &otable[i]) - __sk_add_node(sk, nl_portid_hashfn(hash, nlk_sk(sk)->portid)); - } - - nl_portid_hash_free(otable, osize); - hash->rehash_time = jiffies + 10 * 60 * HZ; - return 1; + return rhashtable_lookup_compare(&table->hash, hash, + &netlink_compare, &arg); } -static inline int nl_portid_hash_dilute(struct nl_portid_hash *hash, int len) +static struct sock *netlink_lookup(struct net *net, int protocol, u32 portid) { - int avg = hash->entries >> hash->shift; - - if (unlikely(avg > 1) && nl_portid_hash_rehash(hash, 1)) - return 1; + struct netlink_table *table = &nl_table[protocol]; + struct sock *sk; - if (unlikely(len > avg) && time_after(jiffies, hash->rehash_time)) { - nl_portid_hash_rehash(hash, 0); - return 1; - } + rcu_read_lock(); + sk = __netlink_lookup(table, portid, net); + if (sk) + sock_hold(sk); + rcu_read_unlock(); - return 0; + return sk; } static const struct proto_ops netlink_ops; @@ -1113,22 +1065,10 @@ netlink_update_listeners(struct sock *sk) static int netlink_insert(struct sock *sk, struct net *net, u32 portid) { struct netlink_table *table = &nl_table[sk->sk_protocol]; - struct nl_portid_hash *hash = &table->hash; - struct hlist_head *head; int err = -EADDRINUSE; - struct sock *osk; - int len; - netlink_table_grab(); - head = nl_portid_hashfn(hash, portid); - len = 0; - sk_for_each(osk, head) { - if (table->compare(net, osk) && - (nlk_sk(osk)->portid == portid)) - break; - len++; - } - if (osk) + mutex_lock(&nl_sk_hash_lock); + if (__netlink_lookup(table, portid, net)) goto err; err = -EBUSY; @@ -1136,26 +1076,31 @@ static int netlink_insert(struct sock *sk, struct net *net, u32 portid) goto err; err = -ENOMEM; - if (BITS_PER_LONG > 32 && unlikely(hash->entries >= UINT_MAX)) + if (BITS_PER_LONG > 32 && unlikely(table->hash.nelems >= UINT_MAX)) goto err; - if (len && nl_portid_hash_dilute(hash, len)) - head = nl_portid_hashfn(hash, portid); - hash->entries++; nlk_sk(sk)->portid = portid; - sk_add_node(sk, head); + sock_hold(sk); + rhashtable_insert(&table->hash, &nlk_sk(sk)->node, GFP_KERNEL); err = 0; - err: - netlink_table_ungrab(); + mutex_unlock(&nl_sk_hash_lock); return err; } static void netlink_remove(struct sock *sk) { + struct netlink_table *table; + + mutex_lock(&nl_sk_hash_lock); + table = &nl_table[sk->sk_protocol]; + if (rhashtable_remove(&table->hash, &nlk_sk(sk)->node, GFP_KERNEL)) { + WARN_ON(atomic_read(&sk->sk_refcnt) == 1); + __sock_put(sk); + } + mutex_unlock(&nl_sk_hash_lock); + netlink_table_grab(); - if (sk_del_node_init(sk)) - nl_table[sk->sk_protocol].hash.entries--; if (nlk_sk(sk)->subscriptions) __sk_del_bind_node(sk); netlink_table_ungrab(); @@ -1311,6 +1256,9 @@ static int netlink_release(struct socket *sock) } netlink_table_ungrab(); + /* Wait for readers to complete */ + synchronize_net(); + kfree(nlk->groups); nlk->groups = NULL; @@ -1326,30 +1274,22 @@ static int netlink_autobind(struct socket *sock) struct sock *sk = sock->sk; struct net *net = sock_net(sk); struct netlink_table *table = &nl_table[sk->sk_protocol]; - struct nl_portid_hash *hash = &table->hash; - struct hlist_head *head; - struct sock *osk; s32 portid = task_tgid_vnr(current); int err; static s32 rover = -4097; retry: cond_resched(); - netlink_table_grab(); - head = nl_portid_hashfn(hash, portid); - sk_for_each(osk, head) { - if (!table->compare(net, osk)) - continue; - if (nlk_sk(osk)->portid == portid) { - /* Bind collision, search negative portid values. */ - portid = rover--; - if (rover > -4097) - rover = -4097; - netlink_table_ungrab(); - goto retry; - } + rcu_read_lock(); + if (__netlink_lookup(table, portid, net)) { + /* Bind collision, search negative portid values. */ + portid = rover--; + if (rover > -4097) + rover = -4097; + rcu_read_unlock(); + goto retry; } - netlink_table_ungrab(); + rcu_read_unlock(); err = netlink_insert(sk, net, portid); if (err == -EADDRINUSE) @@ -2953,14 +2893,18 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) { struct nl_seq_iter *iter = seq->private; int i, j; + struct netlink_sock *nlk; struct sock *s; loff_t off = 0; for (i = 0; i < MAX_LINKS; i++) { - struct nl_portid_hash *hash = &nl_table[i].hash; + struct rhashtable *ht = &nl_table[i].hash; + const struct bucket_table *tbl = rht_dereference(ht->tbl, ht); + + for (j = 0; j < tbl->size; j++) { + rht_for_each_entry_rcu(nlk, tbl->buckets[j], node) { + s = (struct sock *)nlk; - for (j = 0; j <= hash->mask; j++) { - sk_for_each(s, &hash->table[j]) { if (sock_net(s) != seq_file_net(seq)) continue; if (off == pos) { @@ -2976,15 +2920,14 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) } static void *netlink_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(nl_table_lock) { - read_lock(&nl_table_lock); + rcu_read_lock(); return *pos ? netlink_seq_socket_idx(seq, *pos - 1) : SEQ_START_TOKEN; } static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - struct sock *s; + struct netlink_sock *nlk; struct nl_seq_iter *iter; struct net *net; int i, j; @@ -2996,28 +2939,26 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) net = seq_file_net(seq); iter = seq->private; - s = v; - do { - s = sk_next(s); - } while (s && !nl_table[s->sk_protocol].compare(net, s)); - if (s) - return s; + nlk = v; + + rht_for_each_entry_rcu(nlk, nlk->node.next, node) + if (net_eq(sock_net((struct sock *)nlk), net)) + return nlk; i = iter->link; j = iter->hash_idx + 1; do { - struct nl_portid_hash *hash = &nl_table[i].hash; - - for (; j <= hash->mask; j++) { - s = sk_head(&hash->table[j]); + struct rhashtable *ht = &nl_table[i].hash; + const struct bucket_table *tbl = rht_dereference(ht->tbl, ht); - while (s && !nl_table[s->sk_protocol].compare(net, s)) - s = sk_next(s); - if (s) { - iter->link = i; - iter->hash_idx = j; - return s; + for (; j < tbl->size; j++) { + rht_for_each_entry_rcu(nlk, tbl->buckets[j], node) { + if (net_eq(sock_net((struct sock *)nlk), net)) { + iter->link = i; + iter->hash_idx = j; + return nlk; + } } } @@ -3028,9 +2969,8 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void netlink_seq_stop(struct seq_file *seq, void *v) - __releases(nl_table_lock) { - read_unlock(&nl_table_lock); + rcu_read_unlock(); } @@ -3168,9 +3108,17 @@ static struct pernet_operations __net_initdata netlink_net_ops = { static int __init netlink_proto_init(void) { int i; - unsigned long limit; - unsigned int order; int err = proto_register(&netlink_proto, 0); + struct rhashtable_params ht_params = { + .head_offset = offsetof(struct netlink_sock, node), + .key_offset = offsetof(struct netlink_sock, portid), + .key_len = sizeof(u32), /* portid */ + .hashfn = arch_fast_hash, + .max_shift = 16, /* 64K */ + .grow_decision = rht_grow_above_75, + .shrink_decision = rht_shrink_below_30, + .mutex_is_held = lockdep_nl_sk_hash_is_held, + }; if (err != 0) goto out; @@ -3181,32 +3129,13 @@ static int __init netlink_proto_init(void) if (!nl_table) goto panic; - if (totalram_pages >= (128 * 1024)) - limit = totalram_pages >> (21 - PAGE_SHIFT); - else - limit = totalram_pages >> (23 - PAGE_SHIFT); - - order = get_bitmask_order(limit) - 1 + PAGE_SHIFT; - limit = (1UL << order) / sizeof(struct hlist_head); - order = get_bitmask_order(min(limit, (unsigned long)UINT_MAX)) - 1; - for (i = 0; i < MAX_LINKS; i++) { - struct nl_portid_hash *hash = &nl_table[i].hash; - - hash->table = nl_portid_hash_zalloc(1 * sizeof(*hash->table)); - if (!hash->table) { - while (i-- > 0) - nl_portid_hash_free(nl_table[i].hash.table, - 1 * sizeof(*hash->table)); + if (rhashtable_init(&nl_table[i].hash, &ht_params) < 0) { + while (--i > 0) + rhashtable_destroy(&nl_table[i].hash); kfree(nl_table); goto panic; } - hash->max_shift = order; - hash->shift = 0; - hash->mask = 0; - hash->rehash_time = jiffies; - - nl_table[i].compare = netlink_compare; } INIT_LIST_HEAD(&netlink_tap_all); diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index 0b59d441f5b6..60f631fb7087 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h @@ -1,6 +1,7 @@ #ifndef _AF_NETLINK_H #define _AF_NETLINK_H +#include #include #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) @@ -47,6 +48,8 @@ struct netlink_sock { struct netlink_ring tx_ring; atomic_t mapped; #endif /* CONFIG_NETLINK_MMAP */ + + struct rhash_head node; }; static inline struct netlink_sock *nlk_sk(struct sock *sk) @@ -54,21 +57,8 @@ static inline struct netlink_sock *nlk_sk(struct sock *sk) return container_of(sk, struct netlink_sock, sk); } -struct nl_portid_hash { - struct hlist_head *table; - unsigned long rehash_time; - - unsigned int mask; - unsigned int shift; - - unsigned int entries; - unsigned int max_shift; - - u32 rnd; -}; - struct netlink_table { - struct nl_portid_hash hash; + struct rhashtable hash; struct hlist_head mc_list; struct listeners __rcu *listeners; unsigned int flags; diff --git a/net/netlink/diag.c b/net/netlink/diag.c index 1af29624b92f..7301850eb56f 100644 --- a/net/netlink/diag.c +++ b/net/netlink/diag.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "af_netlink.h" @@ -101,16 +102,20 @@ static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, int protocol, int s_num) { struct netlink_table *tbl = &nl_table[protocol]; - struct nl_portid_hash *hash = &tbl->hash; + struct rhashtable *ht = &tbl->hash; + const struct bucket_table *htbl = rht_dereference(ht->tbl, ht); struct net *net = sock_net(skb->sk); struct netlink_diag_req *req; + struct netlink_sock *nlsk; struct sock *sk; int ret = 0, num = 0, i; req = nlmsg_data(cb->nlh); - for (i = 0; i <= hash->mask; i++) { - sk_for_each(sk, &hash->table[i]) { + for (i = 0; i < htbl->size; i++) { + rht_for_each_entry(nlsk, htbl->buckets[i], ht, node) { + sk = (struct sock *)nlsk; + if (!net_eq(sock_net(sk), net)) continue; if (num < s_num) { -- cgit v1.2.3 From cfe4a9dda034e2b5b6ba0b6313b65dfb89ee451c Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Sat, 2 Aug 2014 11:47:46 +0200 Subject: nftables: Convert nft_hash to use generic rhashtable The sizing of the hash table and the practice of requiring a lookup to retrieve the pprev to be stored in the element cookie before the deletion of an entry is left intact. Signed-off-by: Thomas Graf Acked-by: Patrick McHardy Reviewed-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/netfilter/nft_hash.c | 291 +++++++++-------------------------------------- 1 file changed, 55 insertions(+), 236 deletions(-) diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index 4080ed6a072b..28fb8f38e6ba 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c @@ -15,209 +15,40 @@ #include #include #include -#include +#include #include #include #include -#define NFT_HASH_MIN_SIZE 4UL - -struct nft_hash { - struct nft_hash_table __rcu *tbl; -}; - -struct nft_hash_table { - unsigned int size; - struct nft_hash_elem __rcu *buckets[]; -}; +/* We target a hash table size of 4, element hint is 75% of final size */ +#define NFT_HASH_ELEMENT_HINT 3 struct nft_hash_elem { - struct nft_hash_elem __rcu *next; + struct rhash_head node; struct nft_data key; struct nft_data data[]; }; -#define nft_hash_for_each_entry(i, head) \ - for (i = nft_dereference(head); i != NULL; i = nft_dereference(i->next)) -#define nft_hash_for_each_entry_rcu(i, head) \ - for (i = rcu_dereference(head); i != NULL; i = rcu_dereference(i->next)) - -static u32 nft_hash_rnd __read_mostly; -static bool nft_hash_rnd_initted __read_mostly; - -static unsigned int nft_hash_data(const struct nft_data *data, - unsigned int hsize, unsigned int len) -{ - unsigned int h; - - h = jhash(data->data, len, nft_hash_rnd); - return h & (hsize - 1); -} - static bool nft_hash_lookup(const struct nft_set *set, const struct nft_data *key, struct nft_data *data) { - const struct nft_hash *priv = nft_set_priv(set); - const struct nft_hash_table *tbl = rcu_dereference(priv->tbl); + const struct rhashtable *priv = nft_set_priv(set); const struct nft_hash_elem *he; - unsigned int h; - - h = nft_hash_data(key, tbl->size, set->klen); - nft_hash_for_each_entry_rcu(he, tbl->buckets[h]) { - if (nft_data_cmp(&he->key, key, set->klen)) - continue; - if (set->flags & NFT_SET_MAP) - nft_data_copy(data, he->data); - return true; - } - return false; -} - -static void nft_hash_tbl_free(const struct nft_hash_table *tbl) -{ - kvfree(tbl); -} - -static unsigned int nft_hash_tbl_size(unsigned int nelem) -{ - return max(roundup_pow_of_two(nelem * 4 / 3), NFT_HASH_MIN_SIZE); -} - -static struct nft_hash_table *nft_hash_tbl_alloc(unsigned int nbuckets) -{ - struct nft_hash_table *tbl; - size_t size; - - size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]); - tbl = kzalloc(size, GFP_KERNEL | __GFP_REPEAT | __GFP_NOWARN); - if (tbl == NULL) - tbl = vzalloc(size); - if (tbl == NULL) - return NULL; - tbl->size = nbuckets; - - return tbl; -} - -static void nft_hash_chain_unzip(const struct nft_set *set, - const struct nft_hash_table *ntbl, - struct nft_hash_table *tbl, unsigned int n) -{ - struct nft_hash_elem *he, *last, *next; - unsigned int h; - - he = nft_dereference(tbl->buckets[n]); - if (he == NULL) - return; - h = nft_hash_data(&he->key, ntbl->size, set->klen); - - /* Find last element of first chain hashing to bucket h */ - last = he; - nft_hash_for_each_entry(he, he->next) { - if (nft_hash_data(&he->key, ntbl->size, set->klen) != h) - break; - last = he; - } - - /* Unlink first chain from the old table */ - RCU_INIT_POINTER(tbl->buckets[n], last->next); - /* If end of chain reached, done */ - if (he == NULL) - return; + he = rhashtable_lookup(priv, key); + if (he && set->flags & NFT_SET_MAP) + nft_data_copy(data, he->data); - /* Find first element of second chain hashing to bucket h */ - next = NULL; - nft_hash_for_each_entry(he, he->next) { - if (nft_hash_data(&he->key, ntbl->size, set->klen) != h) - continue; - next = he; - break; - } - - /* Link the two chains */ - RCU_INIT_POINTER(last->next, next); -} - -static int nft_hash_tbl_expand(const struct nft_set *set, struct nft_hash *priv) -{ - struct nft_hash_table *tbl = nft_dereference(priv->tbl), *ntbl; - struct nft_hash_elem *he; - unsigned int i, h; - bool complete; - - ntbl = nft_hash_tbl_alloc(tbl->size * 2); - if (ntbl == NULL) - return -ENOMEM; - - /* Link new table's buckets to first element in the old table - * hashing to the new bucket. - */ - for (i = 0; i < ntbl->size; i++) { - h = i < tbl->size ? i : i - tbl->size; - nft_hash_for_each_entry(he, tbl->buckets[h]) { - if (nft_hash_data(&he->key, ntbl->size, set->klen) != i) - continue; - RCU_INIT_POINTER(ntbl->buckets[i], he); - break; - } - } - - /* Publish new table */ - rcu_assign_pointer(priv->tbl, ntbl); - - /* Unzip interleaved hash chains */ - do { - /* Wait for readers to use new table/unzipped chains */ - synchronize_rcu(); - - complete = true; - for (i = 0; i < tbl->size; i++) { - nft_hash_chain_unzip(set, ntbl, tbl, i); - if (tbl->buckets[i] != NULL) - complete = false; - } - } while (!complete); - - nft_hash_tbl_free(tbl); - return 0; -} - -static int nft_hash_tbl_shrink(const struct nft_set *set, struct nft_hash *priv) -{ - struct nft_hash_table *tbl = nft_dereference(priv->tbl), *ntbl; - struct nft_hash_elem __rcu **pprev; - unsigned int i; - - ntbl = nft_hash_tbl_alloc(tbl->size / 2); - if (ntbl == NULL) - return -ENOMEM; - - for (i = 0; i < ntbl->size; i++) { - ntbl->buckets[i] = tbl->buckets[i]; - - for (pprev = &ntbl->buckets[i]; *pprev != NULL; - pprev = &nft_dereference(*pprev)->next) - ; - RCU_INIT_POINTER(*pprev, tbl->buckets[i + ntbl->size]); - } - - /* Publish new table */ - rcu_assign_pointer(priv->tbl, ntbl); - synchronize_rcu(); - - nft_hash_tbl_free(tbl); - return 0; + return !!he; } static int nft_hash_insert(const struct nft_set *set, const struct nft_set_elem *elem) { - struct nft_hash *priv = nft_set_priv(set); - struct nft_hash_table *tbl = nft_dereference(priv->tbl); + struct rhashtable *priv = nft_set_priv(set); struct nft_hash_elem *he; - unsigned int size, h; + unsigned int size; if (elem->flags != 0) return -EINVAL; @@ -234,13 +65,7 @@ static int nft_hash_insert(const struct nft_set *set, if (set->flags & NFT_SET_MAP) nft_data_copy(he->data, &elem->data); - h = nft_hash_data(&he->key, tbl->size, set->klen); - RCU_INIT_POINTER(he->next, tbl->buckets[h]); - rcu_assign_pointer(tbl->buckets[h], he); - - /* Expand table when exceeding 75% load */ - if (set->nelems + 1 > tbl->size / 4 * 3) - nft_hash_tbl_expand(set, priv); + rhashtable_insert(priv, &he->node, GFP_KERNEL); return 0; } @@ -257,36 +82,31 @@ static void nft_hash_elem_destroy(const struct nft_set *set, static void nft_hash_remove(const struct nft_set *set, const struct nft_set_elem *elem) { - struct nft_hash *priv = nft_set_priv(set); - struct nft_hash_table *tbl = nft_dereference(priv->tbl); - struct nft_hash_elem *he, __rcu **pprev; + struct rhashtable *priv = nft_set_priv(set); + struct rhash_head *he, __rcu **pprev; pprev = elem->cookie; - he = nft_dereference((*pprev)); + he = rht_dereference((*pprev), priv); + + rhashtable_remove_pprev(priv, he, pprev, GFP_KERNEL); - RCU_INIT_POINTER(*pprev, he->next); synchronize_rcu(); kfree(he); - - /* Shrink table beneath 30% load */ - if (set->nelems - 1 < tbl->size * 3 / 10 && - tbl->size > NFT_HASH_MIN_SIZE) - nft_hash_tbl_shrink(set, priv); } static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem) { - const struct nft_hash *priv = nft_set_priv(set); - const struct nft_hash_table *tbl = nft_dereference(priv->tbl); - struct nft_hash_elem __rcu * const *pprev; + const struct rhashtable *priv = nft_set_priv(set); + const struct bucket_table *tbl = rht_dereference_rcu(priv->tbl, priv); + struct rhash_head __rcu * const *pprev; struct nft_hash_elem *he; - unsigned int h; + u32 h; - h = nft_hash_data(&elem->key, tbl->size, set->klen); + h = rhashtable_hashfn(priv, &elem->key, set->klen); pprev = &tbl->buckets[h]; - nft_hash_for_each_entry(he, tbl->buckets[h]) { + rht_for_each_entry_rcu(he, tbl->buckets[h], node) { if (nft_data_cmp(&he->key, &elem->key, set->klen)) { - pprev = &he->next; + pprev = &he->node.next; continue; } @@ -302,14 +122,15 @@ static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem) static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, struct nft_set_iter *iter) { - const struct nft_hash *priv = nft_set_priv(set); - const struct nft_hash_table *tbl = nft_dereference(priv->tbl); + const struct rhashtable *priv = nft_set_priv(set); + const struct bucket_table *tbl; const struct nft_hash_elem *he; struct nft_set_elem elem; unsigned int i; + tbl = rht_dereference_rcu(priv->tbl, priv); for (i = 0; i < tbl->size; i++) { - nft_hash_for_each_entry(he, tbl->buckets[i]) { + rht_for_each_entry_rcu(he, tbl->buckets[i], node) { if (iter->count < iter->skip) goto cont; @@ -329,48 +150,46 @@ cont: static unsigned int nft_hash_privsize(const struct nlattr * const nla[]) { - return sizeof(struct nft_hash); + return sizeof(struct rhashtable); +} + +static int lockdep_nfnl_lock_is_held(void) +{ + return lockdep_nfnl_is_held(NFNL_SUBSYS_NFTABLES); } static int nft_hash_init(const struct nft_set *set, const struct nft_set_desc *desc, const struct nlattr * const tb[]) { - struct nft_hash *priv = nft_set_priv(set); - struct nft_hash_table *tbl; - unsigned int size; + struct rhashtable *priv = nft_set_priv(set); + struct rhashtable_params params = { + .nelem_hint = desc->size ? : NFT_HASH_ELEMENT_HINT, + .head_offset = offsetof(struct nft_hash_elem, node), + .key_offset = offsetof(struct nft_hash_elem, key), + .key_len = set->klen, + .hashfn = jhash, + .grow_decision = rht_grow_above_75, + .shrink_decision = rht_shrink_below_30, + .mutex_is_held = lockdep_nfnl_lock_is_held, + }; - if (unlikely(!nft_hash_rnd_initted)) { - get_random_bytes(&nft_hash_rnd, 4); - nft_hash_rnd_initted = true; - } - - size = NFT_HASH_MIN_SIZE; - if (desc->size) - size = nft_hash_tbl_size(desc->size); - - tbl = nft_hash_tbl_alloc(size); - if (tbl == NULL) - return -ENOMEM; - RCU_INIT_POINTER(priv->tbl, tbl); - return 0; + return rhashtable_init(priv, ¶ms); } static void nft_hash_destroy(const struct nft_set *set) { - const struct nft_hash *priv = nft_set_priv(set); - const struct nft_hash_table *tbl = nft_dereference(priv->tbl); + const struct rhashtable *priv = nft_set_priv(set); + const struct bucket_table *tbl; struct nft_hash_elem *he, *next; unsigned int i; - for (i = 0; i < tbl->size; i++) { - for (he = nft_dereference(tbl->buckets[i]); he != NULL; - he = next) { - next = nft_dereference(he->next); + tbl = rht_dereference(priv->tbl, priv); + for (i = 0; i < tbl->size; i++) + rht_for_each_entry_safe(he, next, tbl->buckets[i], priv, node) nft_hash_elem_destroy(set, he); - } - } - kfree(tbl); + + rhashtable_destroy(priv); } static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features, @@ -383,8 +202,8 @@ static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features, esize += FIELD_SIZEOF(struct nft_hash_elem, data[0]); if (desc->size) { - est->size = sizeof(struct nft_hash) + - nft_hash_tbl_size(desc->size) * + est->size = sizeof(struct rhashtable) + + roundup_pow_of_two(desc->size * 4 / 3) * sizeof(struct nft_hash_elem *) + desc->size * esize; } else { -- cgit v1.2.3 From e6b92c25d20c64c271ef429bba8febeefb848b5b Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Sat, 2 Aug 2014 15:50:44 -0700 Subject: cxgb4i : remove spurious use of rcu As pointed out by the intel guys, there is no need to hold rcu read lock in cxgbi_inet6addr_handler(), this patch removes it. Fixes: 759a0cc5a3e1 ("cxgb4i: Add ipv6 code to driver, call into libcxgbi ipv6 api") Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index a4a4e98effdd..d31f9e600639 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -1646,25 +1646,22 @@ static int cxgbi_inet6addr_handler(struct notifier_block *this, struct cxgbi_device *cdev; int ret = NOTIFY_DONE; - rcu_read_lock(); - if (event_dev->priv_flags & IFF_802_1Q_VLAN) event_dev = vlan_dev_real_dev(event_dev); cdev = cxgbi_device_find_by_netdev(event_dev, NULL); - if (!cdev) { - rcu_read_unlock(); + + if (!cdev) return ret; - } + switch (event) { case NETDEV_UP: ret = cxgb4_clip_get(event_dev, (const struct in6_addr *) ((ifa)->addr.s6_addr)); - if (ret < 0) { - rcu_read_unlock(); + if (ret < 0) return ret; - } + ret = NOTIFY_OK; break; @@ -1679,7 +1676,6 @@ static int cxgbi_inet6addr_handler(struct notifier_block *this, break; } - rcu_read_unlock(); return ret; } -- cgit v1.2.3 From 4f933f414bf629852f361edf0fc5e765e3e78388 Mon Sep 17 00:00:00 2001 From: JF Le Fillatre Date: Sat, 2 Aug 2014 01:26:40 +0200 Subject: r8152: add missing Makefile rule Add missing Makefile rule for r8152 driver In the current kernel the r8152 driver is *never* built because of a missing rule in drivers/net/Makefile, despite being selected as built-in or module in the .config file. There is no error message or warning to indicate that the driver isn't built. This change adds the rule and lets the driver build. Tested as built-in and module for 3.15.8. Signed-off by: JF Le Fillatre Signed-off-by: David S. Miller --- drivers/net/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 3fef8a81c0f6..331d9cfa6193 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_USB_CATC) += usb/ obj-$(CONFIG_USB_KAWETH) += usb/ obj-$(CONFIG_USB_PEGASUS) += usb/ obj-$(CONFIG_USB_RTL8150) += usb/ +obj-$(CONFIG_USB_RTL8152) += usb/ obj-$(CONFIG_USB_HSO) += usb/ obj-$(CONFIG_USB_USBNET) += usb/ obj-$(CONFIG_USB_ZD1201) += usb/ -- cgit v1.2.3 From 0185dda640a704ce41ca1489c6775451c5ff3dcf Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Sat, 24 May 2014 06:43:47 +0200 Subject: batman-adv: prefer kmalloc_array to kmalloc when possible Reported by checkpatch with the following warning: WARNING: Prefer kmalloc_array over kmalloc with multiply Signed-off-by: Antonio Quartulli Signed-off-by: Marek Lindner --- net/batman-adv/bat_iv_ogm.c | 13 +++++++------ net/batman-adv/distributed-arp-table.c | 3 ++- net/batman-adv/hash.c | 6 +++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index f04224c32005..1e8053976e83 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -108,14 +108,15 @@ static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, int max_if_num) { void *data_ptr; - size_t data_size, old_size; + size_t old_size; int ret = -ENOMEM; spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); - data_size = max_if_num * sizeof(unsigned long) * BATADV_NUM_WORDS; old_size = (max_if_num - 1) * sizeof(unsigned long) * BATADV_NUM_WORDS; - data_ptr = kmalloc(data_size, GFP_ATOMIC); + data_ptr = kmalloc_array(max_if_num, + BATADV_NUM_WORDS * sizeof(unsigned long), + GFP_ATOMIC); if (!data_ptr) goto unlock; @@ -123,7 +124,7 @@ static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, kfree(orig_node->bat_iv.bcast_own); orig_node->bat_iv.bcast_own = data_ptr; - data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC); + data_ptr = kmalloc_array(max_if_num, sizeof(uint8_t), GFP_ATOMIC); if (!data_ptr) { kfree(orig_node->bat_iv.bcast_own); goto unlock; @@ -164,7 +165,7 @@ static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node, goto free_bcast_own; chunk_size = sizeof(unsigned long) * BATADV_NUM_WORDS; - data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC); + data_ptr = kmalloc_array(max_if_num, chunk_size, GFP_ATOMIC); if (!data_ptr) goto unlock; @@ -183,7 +184,7 @@ free_bcast_own: if (max_if_num == 0) goto free_own_sum; - data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC); + data_ptr = kmalloc_array(max_if_num, sizeof(uint8_t), GFP_ATOMIC); if (!data_ptr) { kfree(orig_node->bat_iv.bcast_own); goto unlock; diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index f2c066b21716..b5981113c9a7 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -537,7 +537,8 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst) if (!bat_priv->orig_hash) return NULL; - res = kmalloc(BATADV_DAT_CANDIDATES_NUM * sizeof(*res), GFP_ATOMIC); + res = kmalloc_array(BATADV_DAT_CANDIDATES_NUM, sizeof(*res), + GFP_ATOMIC); if (!res) return NULL; diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c index 63bdf7e94f1e..7c1c63080e20 100644 --- a/net/batman-adv/hash.c +++ b/net/batman-adv/hash.c @@ -46,12 +46,12 @@ struct batadv_hashtable *batadv_hash_new(uint32_t size) if (!hash) return NULL; - hash->table = kmalloc(sizeof(*hash->table) * size, GFP_ATOMIC); + hash->table = kmalloc_array(size, sizeof(*hash->table), GFP_ATOMIC); if (!hash->table) goto free_hash; - hash->list_locks = kmalloc(sizeof(*hash->list_locks) * size, - GFP_ATOMIC); + hash->list_locks = kmalloc_array(size, sizeof(*hash->list_locks), + GFP_ATOMIC); if (!hash->list_locks) goto free_table; -- cgit v1.2.3 From 4b7a9168e1f795368458cc4ca92224c4481bedf8 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 4 Aug 2014 15:22:40 +0200 Subject: bridge: remove a useless comment commit 6cbdceeb1cb12c7d620161925a8c3e81daadb2e4 bridge: Dump vlan information from a bridge port introduced a comment in an attempt to explain the code logic. The comment is unfinished so it confuses more than it explains, remove it. Signed-off-by: Michael S. Tsirkin Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_netlink.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 26edb518b839..cb5fcf62f663 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -208,7 +208,6 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, int err = 0; struct net_bridge_port *port = br_port_get_rtnl(dev); - /* not a bridge port and */ if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN)) goto out; -- cgit v1.2.3 From 5fa766946ba3ef88374445ec014f0e72481fd63a Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 4 Aug 2014 17:01:30 +0530 Subject: cxgb4: only free allocated fls Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + drivers/net/ethernet/chelsio/cxgb4/sge.c | 35 ++++++++++++++++++------------ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 46156210df34..c9b922cc3e67 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -866,6 +866,7 @@ void t4_os_link_changed(struct adapter *adap, int port_id, int link_stat); void *t4_alloc_mem(size_t size); void t4_free_sge_resources(struct adapter *adap); +void t4_free_ofld_rxqs(struct adapter *adap, int n, struct sge_ofld_rxq *q); irq_handler_t t4_intr_handler(struct adapter *adap); netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev); int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 8bae1aa744a7..b0bba32d69d5 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -2479,6 +2479,22 @@ static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, } } +/** + * t4_free_ofld_rxqs - free a block of consecutive Rx queues + * @adap: the adapter + * @n: number of queues + * @q: pointer to first queue + * + * Release the resources of a consecutive block of offload Rx queues. + */ +void t4_free_ofld_rxqs(struct adapter *adap, int n, struct sge_ofld_rxq *q) +{ + for ( ; n; n--, q++) + if (q->rspq.desc) + free_rspq_fl(adap, &q->rspq, + q->fl.size ? &q->fl : NULL); +} + /** * t4_free_sge_resources - free SGE resources * @adap: the adapter @@ -2490,12 +2506,12 @@ void t4_free_sge_resources(struct adapter *adap) int i; struct sge_eth_rxq *eq = adap->sge.ethrxq; struct sge_eth_txq *etq = adap->sge.ethtxq; - struct sge_ofld_rxq *oq = adap->sge.ofldrxq; /* clean up Ethernet Tx/Rx queues */ for (i = 0; i < adap->sge.ethqsets; i++, eq++, etq++) { if (eq->rspq.desc) - free_rspq_fl(adap, &eq->rspq, &eq->fl); + free_rspq_fl(adap, &eq->rspq, + eq->fl.size ? &eq->fl : NULL); if (etq->q.desc) { t4_eth_eq_free(adap, adap->fn, adap->fn, 0, etq->q.cntxt_id); @@ -2506,18 +2522,9 @@ void t4_free_sge_resources(struct adapter *adap) } /* clean up RDMA and iSCSI Rx queues */ - for (i = 0; i < adap->sge.ofldqsets; i++, oq++) { - if (oq->rspq.desc) - free_rspq_fl(adap, &oq->rspq, &oq->fl); - } - for (i = 0, oq = adap->sge.rdmarxq; i < adap->sge.rdmaqs; i++, oq++) { - if (oq->rspq.desc) - free_rspq_fl(adap, &oq->rspq, &oq->fl); - } - for (i = 0, oq = adap->sge.rdmaciq; i < adap->sge.rdmaciqs; i++, oq++) { - if (oq->rspq.desc) - free_rspq_fl(adap, &oq->rspq, &oq->fl); - } + t4_free_ofld_rxqs(adap, adap->sge.ofldqsets, adap->sge.ofldrxq); + t4_free_ofld_rxqs(adap, adap->sge.rdmaqs, adap->sge.rdmarxq); + t4_free_ofld_rxqs(adap, adap->sge.rdmaciqs, adap->sge.rdmaciq); /* clean up offload Tx queues */ for (i = 0; i < ARRAY_SIZE(adap->sge.ofldtxq); i++) { -- cgit v1.2.3 From b32a8b6410b9e718f3d47dbe7a266b7a0b70bb66 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sun, 3 Aug 2014 13:39:43 +0530 Subject: net: phy: spi_ks8995: Introduce the use of devm_kzalloc This patch introduces the use of devm_kzalloc and does away with the kfrees in the probe and remove functions. Also, a label is removed. Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/phy/spi_ks8995.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c index 22b047f1fcdc..eab57fc5b967 100644 --- a/drivers/net/phy/spi_ks8995.c +++ b/drivers/net/phy/spi_ks8995.c @@ -277,7 +277,7 @@ static int ks8995_probe(struct spi_device *spi) /* Chip description */ pdata = spi->dev.platform_data; - ks = kzalloc(sizeof(*ks), GFP_KERNEL); + ks = devm_kzalloc(&spi->dev, sizeof(*ks), GFP_KERNEL); if (!ks) return -ENOMEM; @@ -291,14 +291,14 @@ static int ks8995_probe(struct spi_device *spi) err = spi_setup(spi); if (err) { dev_err(&spi->dev, "spi_setup failed, err=%d\n", err); - goto err_drvdata; + return err; } err = ks8995_read(ks, ids, KS8995_REG_ID0, sizeof(ids)); if (err < 0) { dev_err(&spi->dev, "unable to read id registers, err=%d\n", err); - goto err_drvdata; + return err; } switch (ids[0]) { @@ -306,8 +306,7 @@ static int ks8995_probe(struct spi_device *spi) break; default: dev_err(&spi->dev, "unknown family id:%02x\n", ids[0]); - err = -ENODEV; - goto err_drvdata; + return -ENODEV; } memcpy(&ks->regs_attr, &ks8995_registers_attr, sizeof(ks->regs_attr)); @@ -320,24 +319,24 @@ static int ks8995_probe(struct spi_device *spi) dev_err(&spi->dev, "unable to read chip id register, err=%d\n", err); - goto err_drvdata; + return err; } if ((val & 0x80) == 0) { dev_err(&spi->dev, "unknown chip:%02x,0\n", ids[1]); - goto err_drvdata; + return err; } ks->regs_attr.size = KSZ8864_REGS_SIZE; } err = ks8995_reset(ks); if (err) - goto err_drvdata; + return err; err = sysfs_create_bin_file(&spi->dev.kobj, &ks->regs_attr); if (err) { dev_err(&spi->dev, "unable to create sysfs file, err=%d\n", err); - goto err_drvdata; + return err; } if (get_chip_id(ids[1]) == CHIPID_M) { @@ -350,21 +349,12 @@ static int ks8995_probe(struct spi_device *spi) } return 0; - -err_drvdata: - kfree(ks); - return err; } static int ks8995_remove(struct spi_device *spi) { - struct ks8995_data *ks8995; - - ks8995 = spi_get_drvdata(spi); sysfs_remove_bin_file(&spi->dev.kobj, &ks8995_registers_attr); - kfree(ks8995); - return 0; } -- cgit v1.2.3 From 9041263ca9128b9f54fce9c215b09850615ff810 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Mon, 4 Aug 2014 23:47:44 +0200 Subject: net: remove spurious zd1201 rule. Leftover from 5c601d0c942f5aaf7f3cff7e08f61047d70a964e ("wireless: move zd1201 where it belongs"). Signed-off-by: Francois Romieu Signed-off-by: David S. Miller --- drivers/net/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 3fef8a81c0f6..fa49d45f9ff6 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -67,7 +67,6 @@ obj-$(CONFIG_USB_PEGASUS) += usb/ obj-$(CONFIG_USB_RTL8150) += usb/ obj-$(CONFIG_USB_HSO) += usb/ obj-$(CONFIG_USB_USBNET) += usb/ -obj-$(CONFIG_USB_ZD1201) += usb/ obj-$(CONFIG_USB_IPHETH) += usb/ obj-$(CONFIG_USB_CDC_PHONET) += usb/ -- cgit v1.2.3 From 06b47aac4924180d63aad50727a11230d876c348 Mon Sep 17 00:00:00 2001 From: KY Srinivasan Date: Sat, 2 Aug 2014 10:42:02 -0700 Subject: Drivers: net-next: hyperv: Increase the size of the sendbuf region Intel did some benchmarking on our network throughput when Linux on Hyper-V is as used as a gateway. This fix gave us almost a 1 Gbps additional throughput on about 5Gbps base throughput we hadi, prior to increasing the sendbuf size. The sendbuf mechanism is a copy based transport that we have which is clearly more optimal than the copy-free page flipping mechanism (for small packets). In the forwarding scenario, we deal only with MTU sized packets, and increasing the size of the senbuf area gave us the additional performance. For what it is worth, Windows guests on Hyper-V, I am told use similar sendbuf size as well. The exact value of sendbuf I think is less important than the fact that it needs to be larger than what Linux can allocate as physically contiguous memory. Thus the change over to allocating via vmalloc(). We currently allocate 16MB receive buffer and we use vmalloc there for allocation. Also the low level channel code has already been modified to deal with physically dis-contiguous memory in the ringbuffer setup. Based on experimentation Intel did, they say there was some improvement in throughput as the sendbuf size was increased up to 16MB and there was no effect on throughput beyond 16MB. Thus I have chosen 16MB here. Increasing the sendbuf value makes a material difference in small packet handling In this version of the patch, based on David's feedback, I have added additional details in the commit log. Signed-off-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 2 +- drivers/net/hyperv/netvsc.c | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 24441ae832d1..02a3ee282eee 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -585,7 +585,7 @@ struct nvsp_message { #define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */ #define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY (1024*1024*15) /* 15MB */ -#define NETVSC_SEND_BUFFER_SIZE (1024 * 1024) /* 1MB */ +#define NETVSC_SEND_BUFFER_SIZE (1024 * 1024 * 16) /* 16MB */ #define NETVSC_INVALID_INDEX -1 diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 592977a6547c..66979cf7fca6 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -193,8 +193,7 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device) } if (net_device->send_buf) { /* Free up the receive buffer */ - free_pages((unsigned long)net_device->send_buf, - get_order(net_device->send_buf_size)); + vfree(net_device->send_buf); net_device->send_buf = NULL; } kfree(net_device->send_section_map); @@ -303,9 +302,7 @@ static int netvsc_init_buf(struct hv_device *device) /* Now setup the send buffer. */ - net_device->send_buf = - (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, - get_order(net_device->send_buf_size)); + net_device->send_buf = vzalloc(net_device->send_buf_size); if (!net_device->send_buf) { netdev_err(ndev, "unable to allocate send " "buffer of size %d\n", net_device->send_buf_size); -- cgit v1.2.3 From 64a124edcc94011ce459f0b9bdf51e1783146712 Mon Sep 17 00:00:00 2001 From: Dmitry Popov Date: Sun, 3 Aug 2014 22:45:19 +0400 Subject: tcp: md5: remove unneeded check in tcp_v4_parse_md5_keys tcpm_key is an array inside struct tcp_md5sig, there is no need to check it against NULL. Signed-off-by: Dmitry Popov Acked-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index d0ba39537d5c..992a1f926009 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1049,7 +1049,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, if (sin->sin_family != AF_INET) return -EINVAL; - if (!cmd.tcpm_key || !cmd.tcpm_keylen) + if (!cmd.tcpm_keylen) return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, AF_INET); -- cgit v1.2.3 From 67a24ac18b0262178ba9f05501b2c6e6731d449a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 5 Aug 2014 07:50:07 +0200 Subject: netlink: fix lockdep splats With netlink_lookup() conversion to RCU, we need to use appropriate rcu dereference in netlink_seq_socket_idx() & netlink_seq_next() Reported-by: Sasha Levin Signed-off-by: Eric Dumazet Fixes: e341694e3eb57fc ("netlink: Convert netlink_lookup() to use RCU protected hash table") Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 0b89ca51a3af..479a344563d8 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2899,7 +2899,7 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) for (i = 0; i < MAX_LINKS; i++) { struct rhashtable *ht = &nl_table[i].hash; - const struct bucket_table *tbl = rht_dereference(ht->tbl, ht); + const struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); for (j = 0; j < tbl->size; j++) { rht_for_each_entry_rcu(nlk, tbl->buckets[j], node) { @@ -2950,7 +2950,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) do { struct rhashtable *ht = &nl_table[i].hash; - const struct bucket_table *tbl = rht_dereference(ht->tbl, ht); + const struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); for (; j < tbl->size; j++) { rht_for_each_entry_rcu(nlk, tbl->buckets[j], node) { -- cgit v1.2.3 From d9124268d84a836f14a6ead54ff9d8eee4c43be5 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 26 May 2014 17:21:39 +0200 Subject: batman-adv: Fix out-of-order fragmentation support batadv_frag_insert_packet was unable to handle out-of-order packets because it dropped them directly. This is caused by the way the fragmentation lists is checked for the correct place to insert a fragmentation entry. The fragmentation code keeps the fragments in lists. The fragmentation entries are kept in descending order of sequence number. The list is traversed and each entry is compared with the new fragment. If the current entry has a smaller sequence number than the new fragment then the new one has to be inserted before the current entry. This ensures that the list is still in descending order. An out-of-order packet with a smaller sequence number than all entries in the list still has to be added to the end of the list. The used hlist has no information about the last entry in the list inside hlist_head and thus the last entry has to be calculated differently. Currently the code assumes that the iterator variable of hlist_for_each_entry can be used for this purpose after the hlist_for_each_entry finished. This is obviously wrong because the iterator variable is always NULL when the list was completely traversed. Instead the information about the last entry has to be stored in a different variable. This problem was introduced in 610bfc6bc99bc83680d190ebc69359a05fc7f605 ("batman-adv: Receive fragmented packets and merge"). Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/fragmentation.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index f14e54a05691..022d18ab27a6 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -128,6 +128,7 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node, { struct batadv_frag_table_entry *chain; struct batadv_frag_list_entry *frag_entry_new = NULL, *frag_entry_curr; + struct batadv_frag_list_entry *frag_entry_last = NULL; struct batadv_frag_packet *frag_packet; uint8_t bucket; uint16_t seqno, hdr_size = sizeof(struct batadv_frag_packet); @@ -180,11 +181,14 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node, ret = true; goto out; } + + /* store current entry because it could be the last in list */ + frag_entry_last = frag_entry_curr; } - /* Reached the end of the list, so insert after 'frag_entry_curr'. */ - if (likely(frag_entry_curr)) { - hlist_add_after(&frag_entry_curr->list, &frag_entry_new->list); + /* Reached the end of the list, so insert after 'frag_entry_last'. */ + if (likely(frag_entry_last)) { + hlist_add_after(&frag_entry_last->list, &frag_entry_new->list); chain->size += skb->len - hdr_size; chain->timestamp = jiffies; ret = true; -- cgit v1.2.3 From 23c4ec10f4ab926396b7925f13974eef58ef0cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Gaul?= Date: Tue, 10 Jun 2014 17:50:31 +0200 Subject: batman-adv: remove unnecessary logspam MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch removes unnecessary logspam which resulted from superfluous calls to net_ratelimit(). With the supplied patch, net_ratelimit() is called after the loglevel has been checked. Signed-off-by: André Gaul Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/main.h | 20 ++++++++++++++------ net/batman-adv/routing.c | 18 +++++++++--------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 118b990bae25..257840ef427c 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -238,21 +238,29 @@ enum batadv_dbg_level { int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...) __printf(2, 3); -#define batadv_dbg(type, bat_priv, fmt, arg...) \ +/* possibly ratelimited debug output */ +#define _batadv_dbg(type, bat_priv, ratelimited, fmt, arg...) \ do { \ - if (atomic_read(&bat_priv->log_level) & type) \ + if (atomic_read(&bat_priv->log_level) & type && \ + (!ratelimited || net_ratelimit())) \ batadv_debug_log(bat_priv, fmt, ## arg);\ } \ while (0) #else /* !CONFIG_BATMAN_ADV_DEBUG */ -__printf(3, 4) -static inline void batadv_dbg(int type __always_unused, - struct batadv_priv *bat_priv __always_unused, - const char *fmt __always_unused, ...) +__printf(4, 5) +static inline void _batadv_dbg(int type __always_unused, + struct batadv_priv *bat_priv __always_unused, + int ratelimited __always_unused, + const char *fmt __always_unused, ...) { } #endif +#define batadv_dbg(type, bat_priv, arg...) \ + _batadv_dbg(type, bat_priv, 0, ## arg) +#define batadv_dbg_ratelimited(type, bat_priv, arg...) \ + _batadv_dbg(type, bat_priv, 1, ## arg) + #define batadv_info(net_dev, fmt, arg...) \ do { \ struct net_device *_netdev = (net_dev); \ diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 35141534938e..35f76f2f7824 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -706,11 +706,11 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) { if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, ethhdr->h_dest, vid)) - net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, - bat_priv, - "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n", - unicast_packet->dest, - ethhdr->h_dest); + batadv_dbg_ratelimited(BATADV_DBG_TT, + bat_priv, + "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n", + unicast_packet->dest, + ethhdr->h_dest); /* at this point the mesh destination should have been * substituted with the originator address found in the global * table. If not, let the packet go untouched anyway because @@ -752,10 +752,10 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, */ if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, ethhdr->h_dest, vid)) { - net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, bat_priv, - "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", - unicast_packet->dest, ethhdr->h_dest, - old_ttvn, curr_ttvn); + batadv_dbg_ratelimited(BATADV_DBG_TT, bat_priv, + "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", + unicast_packet->dest, ethhdr->h_dest, + old_ttvn, curr_ttvn); return 1; } -- cgit v1.2.3 From e03366ea6b05c0ac7e53cecb292b6182419dc49c Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Tue, 17 Jun 2014 12:16:03 +0200 Subject: batman-adv: increase default hop penalty The default hop penalty is currently set to 15, which is applied like that for multi interface devices (e.g. dual band APs). Single band devices will still use an effective penalty of 30 (hop penalty + wifi penalty). After receiving reports of too long paths in mesh networks with dual band APs which were fixed by increasing the hop penalty, we'd like to suggest to increase that default value in the default setting as well. We've evaluated that increase in a handful of medium sized mesh networks (5-20 nodes) with single and dual band devices, with changes for the better (shorter routes, higher throughput) or no change at all. This patch changes the hop penalty to 30, which will give an effective penalty of 60 on single band devices (hop penalty + wifi penalty). Signed-off-by: Simon Wunderlich Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/soft-interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index e0a723991c54..5467955eb27c 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -751,7 +751,7 @@ static int batadv_softif_init_late(struct net_device *dev) atomic_set(&bat_priv->gw.bandwidth_down, 100); atomic_set(&bat_priv->gw.bandwidth_up, 20); atomic_set(&bat_priv->orig_interval, 1000); - atomic_set(&bat_priv->hop_penalty, 15); + atomic_set(&bat_priv->hop_penalty, 30); #ifdef CONFIG_BATMAN_ADV_DEBUG atomic_set(&bat_priv->log_level, 0); #endif -- cgit v1.2.3 From 71b75d0e95b7699394f1d7d76628df719e859ef1 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Mon, 21 Jul 2014 16:05:35 +0200 Subject: batman-adv: Start new development cycle Signed-off-by: Simon Wunderlich Signed-off-by: Antonio Quartulli --- net/batman-adv/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 257840ef427c..a1fcd884f0b1 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -24,7 +24,7 @@ #define BATADV_DRIVER_DEVICE "batman-adv" #ifndef BATADV_SOURCE_VERSION -#define BATADV_SOURCE_VERSION "2014.3.0" +#define BATADV_SOURCE_VERSION "2014.4.0" #endif /* B.A.T.M.A.N. parameters */ -- cgit v1.2.3 From 597aec3f93616c6aa73c3fb1d008f66f2ede9f4c Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Sun, 3 Aug 2014 17:18:20 -0700 Subject: drivers: atm: fix %d confusingly prefixed with 0x in format strings Signed-off-by: Hans Wennborg Acked-by: Chas Williams Signed-off-by: David S. Miller --- drivers/atm/eni.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index b1955ba40d63..d65975aba4ec 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -2155,7 +2155,7 @@ static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) if (!tx->send) continue; if (!--left) { - return sprintf(page,"tx[%d]: 0x%ld-0x%ld " + return sprintf(page, "tx[%d]: 0x%lx-0x%lx " "(%6ld bytes), rsv %d cps, shp %d cps%s\n",i, (unsigned long) (tx->send - eni_dev->ram), tx->send-eni_dev->ram+tx->words*4-1,tx->words*4, @@ -2181,7 +2181,7 @@ static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) if (--left) continue; length = sprintf(page,"vcc %4d: ",vcc->vci); if (eni_vcc->rx) { - length += sprintf(page+length,"0x%ld-0x%ld " + length += sprintf(page+length, "0x%lx-0x%lx " "(%6ld bytes)", (unsigned long) (eni_vcc->recv - eni_dev->ram), eni_vcc->recv-eni_dev->ram+eni_vcc->words*4-1, -- cgit v1.2.3 From 45dfab6894e43c70b24d1e3f63538e4ce7acc9dd Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Sun, 3 Aug 2014 17:19:46 -0700 Subject: net: smc911x: fix %d confusingly prefixed with 0x in format string Signed-off-by: Hans Wennborg Signed-off-by: David S. Miller --- drivers/net/ethernet/smsc/smc911x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c index 1c44e67c3067..9778cba9fc74 100644 --- a/drivers/net/ethernet/smsc/smc911x.c +++ b/drivers/net/ethernet/smsc/smc911x.c @@ -730,7 +730,7 @@ static void smc911x_phy_detect(struct net_device *dev) lp->phy_type = id1 << 16 | id2; } - DBG(SMC_DEBUG_MISC, dev, "phy_id1=0x%x, phy_id2=0x%x phyaddr=0x%d\n", + DBG(SMC_DEBUG_MISC, dev, "phy_id1=0x%x, phy_id2=0x%x phyaddr=0x%x\n", id1, id2, lp->mii.phy_id); } -- cgit v1.2.3 From 61ab9efddf51cbc0d57356a4d650785cf5721fbe Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Mon, 4 Aug 2014 11:11:49 +0200 Subject: net/usb/hso: Add support for Option GTM671WFS After this patch: [ 32.985530] hso: drivers/net/usb/hso.c: Option Wireless [ 33.000452] hso 2-1.4:1.7: Not our interface [ 33.001849] usbcore: registered new interface driver hso root@qt5022:~# ls /dev/ttyHS* /dev/ttyHS0 /dev/ttyHS1 /dev/ttyHS2 /dev/ttyHS3 /dev/ttyHS4 /dev/ttyHS5 root@qt5022:~# lsusb -d 0af0: -vvv Bus 002 Device 003: ID 0af0:9200 Option Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 255 Vendor Specific Class bDeviceSubClass 255 Vendor Specific Subclass bDeviceProtocol 255 Vendor Specific Protocol bMaxPacketSize0 64 idVendor 0x0af0 Option idProduct 0x9200 bcdDevice 0.00 iManufacturer 3 Option N.V. iProduct 2 Globetrotter HSUPA Modem iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 200 bNumInterfaces 8 bConfigurationValue 1 iConfiguration 1 Option Configuration bmAttributes 0xe0 Self Powered Remote Wakeup MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 4 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 5 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x06 EP 6 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 6 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x87 EP 7 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x88 EP 8 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x07 EP 7 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 32 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 7 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 8 Mass Storage bInterfaceSubClass 6 SCSI bInterfaceProtocol 80 Bulk-Only iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x08 EP 8 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x89 EP 9 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 1 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 255 Vendor Specific Class bDeviceSubClass 255 Vendor Specific Subclass bDeviceProtocol 255 Vendor Specific Protocol bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0001 Self Powered Signed-off-by: Ricardo Ribalda Delgado Acked-by: Dan Williams Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index a36401802cec..babda7d8693e 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -467,6 +467,7 @@ static const struct usb_device_id hso_ids[] = { {USB_DEVICE(0x0af0, 0x8800)}, {USB_DEVICE(0x0af0, 0x8900)}, {USB_DEVICE(0x0af0, 0x9000)}, + {USB_DEVICE(0x0af0, 0x9200)}, /* Option GTM671WFS */ {USB_DEVICE(0x0af0, 0xd035)}, {USB_DEVICE(0x0af0, 0xd055)}, {USB_DEVICE(0x0af0, 0xd155)}, -- cgit v1.2.3 From 3d1af1df9762e56e563e8fd088a1b4ce2bcfaf8b Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Mon, 4 Aug 2014 16:20:57 +0100 Subject: xen-netback: Using a new state bit instead of carrier This patch introduces a new state bit VIF_STATUS_CONNECTED to track whether the vif is in a connected state. Using carrier will not work with the next patch in this series, which aims to turn the carrier temporarily off if the guest doesn't seem to be able to receive packets. Signed-off-by: Zoltan Kiss Signed-off-by: David Vrabel Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: xen-devel@lists.xenproject.org v2: - rename the bitshift type to "enum state_bit_shift" here, not in the next patch Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 6 ++++++ drivers/net/xen-netback/interface.c | 19 +++++++++++-------- drivers/net/xen-netback/netback.c | 2 +- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 28c98229e95f..4a92fc19f410 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -198,6 +198,11 @@ struct xenvif_queue { /* Per-queue data for xenvif */ struct xenvif_stats stats; }; +enum state_bit_shift { + /* This bit marks that the vif is connected */ + VIF_STATUS_CONNECTED +}; + struct xenvif { /* Unique identifier for this interface. */ domid_t domid; @@ -220,6 +225,7 @@ struct xenvif { * frontend is rogue. */ bool disabled; + unsigned long status; /* Queues */ struct xenvif_queue *queues; diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index bd59d9dbf27b..fbdadb3d8220 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -55,7 +55,8 @@ static inline void xenvif_stop_queue(struct xenvif_queue *queue) int xenvif_schedulable(struct xenvif *vif) { - return netif_running(vif->dev) && netif_carrier_ok(vif->dev); + return netif_running(vif->dev) && + test_bit(VIF_STATUS_CONNECTED, &vif->status); } static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id) @@ -267,7 +268,7 @@ static void xenvif_down(struct xenvif *vif) static int xenvif_open(struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); - if (netif_carrier_ok(dev)) + if (test_bit(VIF_STATUS_CONNECTED, &vif->status)) xenvif_up(vif); netif_tx_start_all_queues(dev); return 0; @@ -276,7 +277,7 @@ static int xenvif_open(struct net_device *dev) static int xenvif_close(struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); - if (netif_carrier_ok(dev)) + if (test_bit(VIF_STATUS_CONNECTED, &vif->status)) xenvif_down(vif); netif_tx_stop_all_queues(dev); return 0; @@ -528,6 +529,7 @@ void xenvif_carrier_on(struct xenvif *vif) if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN) dev_set_mtu(vif->dev, ETH_DATA_LEN); netdev_update_features(vif->dev); + set_bit(VIF_STATUS_CONNECTED, &vif->status); netif_carrier_on(vif->dev); if (netif_running(vif->dev)) xenvif_up(vif); @@ -625,9 +627,11 @@ void xenvif_carrier_off(struct xenvif *vif) struct net_device *dev = vif->dev; rtnl_lock(); - netif_carrier_off(dev); /* discard queued packets */ - if (netif_running(dev)) - xenvif_down(vif); + if (test_and_clear_bit(VIF_STATUS_CONNECTED, &vif->status)) { + netif_carrier_off(dev); /* discard queued packets */ + if (netif_running(dev)) + xenvif_down(vif); + } rtnl_unlock(); } @@ -656,8 +660,7 @@ void xenvif_disconnect(struct xenvif *vif) unsigned int num_queues = vif->num_queues; unsigned int queue_index; - if (netif_carrier_ok(vif->dev)) - xenvif_carrier_off(vif); + xenvif_carrier_off(vif); for (queue_index = 0; queue_index < num_queues; ++queue_index) { queue = &vif->queues[queue_index]; diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 769e553d3f45..6c4cc0f44da5 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1953,7 +1953,7 @@ int xenvif_kthread_guest_rx(void *data) * context so we defer it here, if this thread is * associated with queue 0. */ - if (unlikely(queue->vif->disabled && netif_carrier_ok(queue->vif->dev) && queue->id == 0)) + if (unlikely(queue->vif->disabled && queue->id == 0)) xenvif_carrier_off(queue->vif); if (kthread_should_stop()) -- cgit v1.2.3 From f34a4cf9c9b4fd35ba7f9a596cedb011879a1a4d Mon Sep 17 00:00:00 2001 From: Zoltan Kiss Date: Mon, 4 Aug 2014 16:20:58 +0100 Subject: xen-netback: Turn off the carrier if the guest is not able to receive Currently when the guest is not able to receive more packets, qdisc layer starts a timer, and when it goes off, qdisc is started again to deliver a packet again. This is a very slow way to drain the queues, consumes unnecessary resources and slows down other guests shutdown. This patch change the behaviour by turning the carrier off when that timer fires, so all the packets are freed up which were stucked waiting for that vif. Instead of the rx_queue_purge bool it uses the VIF_STATUS_RX_PURGE_EVENT bit to signal the thread that either the timeout happened or an RX interrupt arrived, so the thread can check what it should do. It also disables NAPI, so the guest can't transmit, but leaves the interrupts on, so it can resurrect. Only the queues which brought down the interface can enable it again, the bit QUEUE_STATUS_RX_STALLED makes sure of that. Signed-off-by: Zoltan Kiss Signed-off-by: David Vrabel Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: xen-devel@lists.xenproject.org Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 15 ++++-- drivers/net/xen-netback/interface.c | 49 +++++++++++-------- drivers/net/xen-netback/netback.c | 97 +++++++++++++++++++++++++++++++------ 3 files changed, 123 insertions(+), 38 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 4a92fc19f410..ef3026f46a37 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -176,9 +176,9 @@ struct xenvif_queue { /* Per-queue data for xenvif */ struct xen_netif_rx_back_ring rx; struct sk_buff_head rx_queue; RING_IDX rx_last_skb_slots; - bool rx_queue_purge; + unsigned long status; - struct timer_list wake_queue; + struct timer_list rx_stalled; struct gnttab_copy grant_copy_op[MAX_GRANT_COPY_OPS]; @@ -200,7 +200,16 @@ struct xenvif_queue { /* Per-queue data for xenvif */ enum state_bit_shift { /* This bit marks that the vif is connected */ - VIF_STATUS_CONNECTED + VIF_STATUS_CONNECTED, + /* This bit signals the RX thread that queuing was stopped (in + * start_xmit), and either the timer fired or an RX interrupt came + */ + QUEUE_STATUS_RX_PURGE_EVENT, + /* This bit tells the interrupt handler that this queue was the reason + * for the carrier off, so it should kick the thread. Only queues which + * brought it down can turn on the carrier. + */ + QUEUE_STATUS_RX_STALLED }; struct xenvif { diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index fbdadb3d8220..48a55cda979b 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -78,8 +78,12 @@ int xenvif_poll(struct napi_struct *napi, int budget) /* This vif is rogue, we pretend we've there is nothing to do * for this vif to deschedule it from NAPI. But this interface * will be turned off in thread context later. + * Also, if a guest doesn't post enough slots to receive data on one of + * its queues, the carrier goes down and NAPI is descheduled here so + * the guest can't send more packets until it's ready to receive. */ - if (unlikely(queue->vif->disabled)) { + if (unlikely(queue->vif->disabled || + !netif_carrier_ok(queue->vif->dev))) { napi_complete(napi); return 0; } @@ -97,7 +101,16 @@ int xenvif_poll(struct napi_struct *napi, int budget) static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id) { struct xenvif_queue *queue = dev_id; + struct netdev_queue *net_queue = + netdev_get_tx_queue(queue->vif->dev, queue->id); + /* QUEUE_STATUS_RX_PURGE_EVENT is only set if either QDisc was off OR + * the carrier went down and this queue was previously blocked + */ + if (unlikely(netif_tx_queue_stopped(net_queue) || + (!netif_carrier_ok(queue->vif->dev) && + test_bit(QUEUE_STATUS_RX_STALLED, &queue->status)))) + set_bit(QUEUE_STATUS_RX_PURGE_EVENT, &queue->status); xenvif_kick_thread(queue); return IRQ_HANDLED; @@ -125,16 +138,14 @@ void xenvif_wake_queue(struct xenvif_queue *queue) netif_tx_wake_queue(netdev_get_tx_queue(dev, id)); } -/* Callback to wake the queue and drain it on timeout */ -static void xenvif_wake_queue_callback(unsigned long data) +/* Callback to wake the queue's thread and turn the carrier off on timeout */ +static void xenvif_rx_stalled(unsigned long data) { struct xenvif_queue *queue = (struct xenvif_queue *)data; if (xenvif_queue_stopped(queue)) { - netdev_err(queue->vif->dev, "draining TX queue\n"); - queue->rx_queue_purge = true; + set_bit(QUEUE_STATUS_RX_PURGE_EVENT, &queue->status); xenvif_kick_thread(queue); - xenvif_wake_queue(queue); } } @@ -183,11 +194,11 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) * drain. */ if (!xenvif_rx_ring_slots_available(queue, min_slots_needed)) { - queue->wake_queue.function = xenvif_wake_queue_callback; - queue->wake_queue.data = (unsigned long)queue; + queue->rx_stalled.function = xenvif_rx_stalled; + queue->rx_stalled.data = (unsigned long)queue; xenvif_stop_queue(queue); - mod_timer(&queue->wake_queue, - jiffies + rx_drain_timeout_jiffies); + mod_timer(&queue->rx_stalled, + jiffies + rx_drain_timeout_jiffies); } skb_queue_tail(&queue->rx_queue, skb); @@ -515,7 +526,7 @@ int xenvif_init_queue(struct xenvif_queue *queue) queue->grant_tx_handle[i] = NETBACK_INVALID_HANDLE; } - init_timer(&queue->wake_queue); + init_timer(&queue->rx_stalled); netif_napi_add(queue->vif->dev, &queue->napi, xenvif_poll, XENVIF_NAPI_WEIGHT); @@ -666,7 +677,7 @@ void xenvif_disconnect(struct xenvif *vif) queue = &vif->queues[queue_index]; if (queue->task) { - del_timer_sync(&queue->wake_queue); + del_timer_sync(&queue->rx_stalled); kthread_stop(queue->task); queue->task = NULL; } @@ -708,16 +719,12 @@ void xenvif_free(struct xenvif *vif) /* Here we want to avoid timeout messages if an skb can be legitimately * stuck somewhere else. Realistically this could be an another vif's * internal or QDisc queue. That another vif also has this - * rx_drain_timeout_msecs timeout, but the timer only ditches the - * internal queue. After that, the QDisc queue can put in worst case - * XEN_NETIF_RX_RING_SIZE / MAX_SKB_FRAGS skbs into that another vif's - * internal queue, so we need several rounds of such timeouts until we - * can be sure that no another vif should have skb's from us. We are - * not sending more skb's, so newly stuck packets are not interesting - * for us here. + * rx_drain_timeout_msecs timeout, so give it time to drain out. + * Although if that other guest wakes up just before its timeout happens + * and takes only one skb from QDisc, it can hold onto other skbs for a + * longer period. */ - unsigned int worst_case_skb_lifetime = (rx_drain_timeout_msecs/1000) * - DIV_ROUND_UP(XENVIF_QUEUE_LENGTH, (XEN_NETIF_RX_RING_SIZE / MAX_SKB_FRAGS)); + unsigned int worst_case_skb_lifetime = (rx_drain_timeout_msecs/1000); unregister_netdev(vif->dev); diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 6c4cc0f44da5..aa2093325be1 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1869,8 +1869,7 @@ void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx) static inline int rx_work_todo(struct xenvif_queue *queue) { return (!skb_queue_empty(&queue->rx_queue) && - xenvif_rx_ring_slots_available(queue, queue->rx_last_skb_slots)) || - queue->rx_queue_purge; + xenvif_rx_ring_slots_available(queue, queue->rx_last_skb_slots)); } static inline int tx_work_todo(struct xenvif_queue *queue) @@ -1935,6 +1934,75 @@ static void xenvif_start_queue(struct xenvif_queue *queue) xenvif_wake_queue(queue); } +/* Only called from the queue's thread, it handles the situation when the guest + * doesn't post enough requests on the receiving ring. + * First xenvif_start_xmit disables QDisc and start a timer, and then either the + * timer fires, or the guest send an interrupt after posting new request. If it + * is the timer, the carrier is turned off here. + * */ +static void xenvif_rx_purge_event(struct xenvif_queue *queue) +{ + /* Either the last unsuccesful skb or at least 1 slot should fit */ + int needed = queue->rx_last_skb_slots ? + queue->rx_last_skb_slots : 1; + + /* It is assumed that if the guest post new slots after this, the RX + * interrupt will set the QUEUE_STATUS_RX_PURGE_EVENT bit and wake up + * the thread again + */ + set_bit(QUEUE_STATUS_RX_STALLED, &queue->status); + if (!xenvif_rx_ring_slots_available(queue, needed)) { + rtnl_lock(); + if (netif_carrier_ok(queue->vif->dev)) { + /* Timer fired and there are still no slots. Turn off + * everything except the interrupts + */ + netif_carrier_off(queue->vif->dev); + skb_queue_purge(&queue->rx_queue); + queue->rx_last_skb_slots = 0; + if (net_ratelimit()) + netdev_err(queue->vif->dev, "Carrier off due to lack of guest response on queue %d\n", queue->id); + } else { + /* Probably an another queue already turned the carrier + * off, make sure nothing is stucked in the internal + * queue of this queue + */ + skb_queue_purge(&queue->rx_queue); + queue->rx_last_skb_slots = 0; + } + rtnl_unlock(); + } else if (!netif_carrier_ok(queue->vif->dev)) { + unsigned int num_queues = queue->vif->num_queues; + unsigned int i; + /* The carrier was down, but an interrupt kicked + * the thread again after new requests were + * posted + */ + clear_bit(QUEUE_STATUS_RX_STALLED, + &queue->status); + rtnl_lock(); + netif_carrier_on(queue->vif->dev); + netif_tx_wake_all_queues(queue->vif->dev); + rtnl_unlock(); + + for (i = 0; i < num_queues; i++) { + struct xenvif_queue *temp = &queue->vif->queues[i]; + + xenvif_napi_schedule_or_enable_events(temp); + } + if (net_ratelimit()) + netdev_err(queue->vif->dev, "Carrier on again\n"); + } else { + /* Queuing were stopped, but the guest posted + * new requests and sent an interrupt + */ + clear_bit(QUEUE_STATUS_RX_STALLED, + &queue->status); + del_timer_sync(&queue->rx_stalled); + xenvif_start_queue(queue); + } +} + int xenvif_kthread_guest_rx(void *data) { struct xenvif_queue *queue = data; @@ -1944,8 +2012,12 @@ int xenvif_kthread_guest_rx(void *data) wait_event_interruptible(queue->wq, rx_work_todo(queue) || queue->vif->disabled || + test_bit(QUEUE_STATUS_RX_PURGE_EVENT, &queue->status) || kthread_should_stop()); + if (kthread_should_stop()) + break; + /* This frontend is found to be rogue, disable it in * kthread context. Currently this is only set when * netback finds out frontend sends malformed packet, @@ -1955,24 +2027,21 @@ int xenvif_kthread_guest_rx(void *data) */ if (unlikely(queue->vif->disabled && queue->id == 0)) xenvif_carrier_off(queue->vif); - - if (kthread_should_stop()) - break; - - if (queue->rx_queue_purge) { + else if (unlikely(test_and_clear_bit(QUEUE_STATUS_RX_PURGE_EVENT, + &queue->status))) { + xenvif_rx_purge_event(queue); + } else if (!netif_carrier_ok(queue->vif->dev)) { + /* Another queue stalled and turned the carrier off, so + * purge the internal queue of queues which were not + * blocked + */ skb_queue_purge(&queue->rx_queue); - queue->rx_queue_purge = false; + queue->rx_last_skb_slots = 0; } if (!skb_queue_empty(&queue->rx_queue)) xenvif_rx_action(queue); - if (skb_queue_empty(&queue->rx_queue) && - xenvif_queue_stopped(queue)) { - del_timer_sync(&queue->wake_queue); - xenvif_start_queue(queue); - } - cond_resched(); } -- cgit v1.2.3 From a0eaf75c03712b491b7a840b5836c8f1e2a09277 Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Mon, 4 Aug 2014 11:51:16 -0400 Subject: qlcnic: Fix update of ethtool stats. o Aggregating tx stats in adapter variable was resulting in an increase in stats even after no traffic was run and user runs ifconfig/ethtool command. o qlcnic_update_stats used to accumulate stats in adapter struct at each function call, instead accumulate tx stats in local variable and then assign it to adapter structure. Reported-by: Holger Kiehl Signed-off-by: Rajesh Borundia Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 1b7f3dbae289..141f116eb868 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -1290,17 +1290,25 @@ static u64 *qlcnic_fill_stats(u64 *data, void *stats, int type) void qlcnic_update_stats(struct qlcnic_adapter *adapter) { + struct qlcnic_tx_queue_stats tx_stats; struct qlcnic_host_tx_ring *tx_ring; int ring; + memset(&tx_stats, 0, sizeof(tx_stats)); for (ring = 0; ring < adapter->drv_tx_rings; ring++) { tx_ring = &adapter->tx_ring[ring]; - adapter->stats.xmit_on += tx_ring->tx_stats.xmit_on; - adapter->stats.xmit_off += tx_ring->tx_stats.xmit_off; - adapter->stats.xmitcalled += tx_ring->tx_stats.xmit_called; - adapter->stats.xmitfinished += tx_ring->tx_stats.xmit_finished; - adapter->stats.txbytes += tx_ring->tx_stats.tx_bytes; + tx_stats.xmit_on += tx_ring->tx_stats.xmit_on; + tx_stats.xmit_off += tx_ring->tx_stats.xmit_off; + tx_stats.xmit_called += tx_ring->tx_stats.xmit_called; + tx_stats.xmit_finished += tx_ring->tx_stats.xmit_finished; + tx_stats.tx_bytes += tx_ring->tx_stats.tx_bytes; } + + adapter->stats.xmit_on = tx_stats.xmit_on; + adapter->stats.xmit_off = tx_stats.xmit_off; + adapter->stats.xmitcalled = tx_stats.xmit_called; + adapter->stats.xmitfinished = tx_stats.xmit_finished; + adapter->stats.txbytes = tx_stats.tx_bytes; } static u64 *qlcnic_fill_tx_queue_stats(u64 *data, void *stats) -- cgit v1.2.3 From bf63014f108aaff49e4382b7adc7d0a2b6365744 Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Mon, 4 Aug 2014 11:51:17 -0400 Subject: qlcnic: Set driver version before registering netdev o Earlier, set_drv_version was getting called after register_netdev. This was resulting in a race between set_drv_version and FLR called from open(). Moving set_drv_version before register_netdev avoids the race. o Log response code in error message on CDRP failure. Signed-off-by: Rajesh Borundia Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c | 2 +- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index 304e247bdf33..ffbae293cef5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -136,7 +136,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter, rsp = qlcnic_poll_rsp(adapter); if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) { - dev_err(&pdev->dev, "card response timeout.\n"); + dev_err(&pdev->dev, "command timeout, response = 0x%x\n", rsp); cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT; } else if (rsp == QLCNIC_CDRP_RSP_FAIL) { cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1), &err); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 4fc186713b66..158e1d9f255f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -2623,13 +2623,13 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_out_disable_mbx_intr; + if (adapter->portnum == 0) + qlcnic_set_drv_version(adapter); + err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac); if (err) goto err_out_disable_mbx_intr; - if (adapter->portnum == 0) - qlcnic_set_drv_version(adapter); - pci_set_drvdata(pdev, adapter); if (qlcnic_82xx_check(adapter)) -- cgit v1.2.3 From cd1560e2b60fc2fbfadb9200c366eb59fe04f10d Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Mon, 4 Aug 2014 11:51:18 -0400 Subject: qlcnic: Initialize dcbnl_ops before register_netdev o Initialization of dcbnl_ops after register netdev may result in dcbnl_ops not getting set before it is being accessed from open. So, moving it before register_netdev. Signed-off-by: Rajesh Borundia Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 158e1d9f255f..3187bc0c471b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -2323,14 +2323,14 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev, if (err) return err; + qlcnic_dcb_init_dcbnl_ops(adapter->dcb); + err = register_netdev(netdev); if (err) { dev_err(&pdev->dev, "failed to register net device\n"); return err; } - qlcnic_dcb_init_dcbnl_ops(adapter->dcb); - return 0; } -- cgit v1.2.3 From 5ae344c949e79b8545a11db149f0a85a6e59e1f3 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Mon, 4 Aug 2014 19:12:29 -0400 Subject: tcp: reduce spurious retransmits due to transient SACK reneging This commit reduces spurious retransmits due to apparent SACK reneging by only reacting to SACK reneging that persists for a short delay. When a sequence space hole at snd_una is filled, some TCP receivers send a series of ACKs as they apparently scan their out-of-order queue and cumulatively ACK all the packets that have now been consecutiveyly received. This is essentially misbehavior B in "Misbehaviors in TCP SACK generation" ACM SIGCOMM Computer Communication Review, April 2011, so we suspect that this is from several common OSes (Windows 2000, Windows Server 2003, Windows XP). However, this issue has also been seen in other cases, e.g. the netdev thread "TCP being hoodwinked into spurious retransmissions by lack of timestamps?" from March 2014, where the receiver was thought to be a BSD box. Since snd_una would temporarily be adjacent to a previously SACKed range in these scenarios, this receiver behavior triggered the Linux SACK reneging code path in the sender. This led the sender to clear the SACK scoreboard, enter CA_Loss, and spuriously retransmit (potentially) every packet from the entire write queue at line rate just a few milliseconds before the ACK for each packet arrives at the sender. To avoid such situations, now when a sender sees apparent reneging it does not yet retransmit, but rather adjusts the RTO timer to give the receiver a little time (max(RTT/2, 10ms)) to send us some more ACKs that will restore sanity to the SACK scoreboard. If the reneging persists until this RTO then, as before, we clear the SACK scoreboard and enter CA_Loss. A 10ms delay tolerates a receiver sending such a stream of ACKs at 56Kbit/sec. And to allow for receivers with slower or more congested paths, we wait for at least RTT/2. We validated the resulting max(RTT/2, 10ms) delay formula with a mix of North American and South American Google web server traffic, and found that for ACKs displaying transient reneging: (1) 90% of inter-ACK delays were less than 10ms (2) 99% of inter-ACK delays were less than RTT/2 In tests on Google web servers this commit reduced reneging events by 75%-90% (as measured by the TcpExtTCPSACKReneging counter), without any measurable impact on latency for user HTTP and SPDY requests. Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- net/ipv4/tcp_input.c | 29 ++++++++++++++++++----------- net/ipv4/tcp_timer.c | 4 ++-- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 0aeb2eb749dc..dafa1cbc149b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -411,7 +411,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, bool fastopen); int tcp_child_process(struct sock *parent, struct sock *child, struct sk_buff *skb); -void tcp_enter_loss(struct sock *sk, int how); +void tcp_enter_loss(struct sock *sk); void tcp_clear_retrans(struct tcp_sock *tp); void tcp_update_metrics(struct sock *sk); void tcp_init_metrics(struct sock *sk); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 7832d941dbcd..6a2984507755 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1904,16 +1904,17 @@ void tcp_clear_retrans(struct tcp_sock *tp) tp->sacked_out = 0; } -/* Enter Loss state. If "how" is not zero, forget all SACK information +/* Enter Loss state. If we detect SACK reneging, forget all SACK information * and reset tags completely, otherwise preserve SACKs. If receiver * dropped its ofo queue, we will know this due to reneging detection. */ -void tcp_enter_loss(struct sock *sk, int how) +void tcp_enter_loss(struct sock *sk) { const struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; bool new_recovery = false; + bool is_reneg; /* is receiver reneging on SACKs? */ /* Reduce ssthresh if it has not yet been made inside this window. */ if (icsk->icsk_ca_state <= TCP_CA_Disorder || @@ -1934,7 +1935,11 @@ void tcp_enter_loss(struct sock *sk, int how) tcp_reset_reno_sack(tp); tp->undo_marker = tp->snd_una; - if (how) { + + skb = tcp_write_queue_head(sk); + is_reneg = skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED); + if (is_reneg) { + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSACKRENEGING); tp->sacked_out = 0; tp->fackets_out = 0; } @@ -1948,7 +1953,7 @@ void tcp_enter_loss(struct sock *sk, int how) tp->undo_marker = 0; TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED; - if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || how) { + if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || is_reneg) { TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED; TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; tp->lost_out += tcp_skb_pcount(skb); @@ -1981,19 +1986,21 @@ void tcp_enter_loss(struct sock *sk, int how) * remembered SACKs do not reflect real state of receiver i.e. * receiver _host_ is heavily congested (or buggy). * - * Do processing similar to RTO timeout. + * To avoid big spurious retransmission bursts due to transient SACK + * scoreboard oddities that look like reneging, we give the receiver a + * little time (max(RTT/2, 10ms)) to send us some more ACKs that will + * restore sanity to the SACK scoreboard. If the apparent reneging + * persists until this RTO then we'll clear the SACK scoreboard. */ static bool tcp_check_sack_reneging(struct sock *sk, int flag) { if (flag & FLAG_SACK_RENEGING) { - struct inet_connection_sock *icsk = inet_csk(sk); - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSACKRENEGING); + struct tcp_sock *tp = tcp_sk(sk); + unsigned long delay = max(usecs_to_jiffies(tp->srtt_us >> 4), + msecs_to_jiffies(10)); - tcp_enter_loss(sk, 1); - icsk->icsk_retransmits++; - tcp_retransmit_skb(sk, tcp_write_queue_head(sk)); inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, - icsk->icsk_rto, TCP_RTO_MAX); + delay, TCP_RTO_MAX); return true; } return false; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 286227abed10..df90cd1ce37f 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -391,7 +391,7 @@ void tcp_retransmit_timer(struct sock *sk) tcp_write_err(sk); goto out; } - tcp_enter_loss(sk, 0); + tcp_enter_loss(sk); tcp_retransmit_skb(sk, tcp_write_queue_head(sk)); __sk_dst_reset(sk); goto out_reset_timer; @@ -422,7 +422,7 @@ void tcp_retransmit_timer(struct sock *sk) NET_INC_STATS_BH(sock_net(sk), mib_idx); } - tcp_enter_loss(sk, 0); + tcp_enter_loss(sk); if (tcp_retransmit_skb(sk, tcp_write_queue_head(sk)) > 0) { /* Retransmission failed because of local congestion, -- cgit v1.2.3 From a2b81b35f9e5ade210e4df2001f7a30ac390114d Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Mon, 4 Aug 2014 16:17:51 -0700 Subject: cxgb4i : Move stray CPL definitions to cxgb4 driver These belong to the t4 msg header, will ensure there is no accidental code duplication in the future Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 2 ++ drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index 0259feeab1b3..52e08103f221 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -75,6 +75,7 @@ enum { CPL_RX_DATA_DDP = 0x42, CPL_PASS_ACCEPT_REQ = 0x44, CPL_TRACE_PKT_T5 = 0x48, + CPL_RX_ISCSI_DDP = 0x49, CPL_RDMA_READ_REQ = 0x60, @@ -86,6 +87,7 @@ enum { CPL_SGE_EGR_UPDATE = 0xA5, CPL_TRACE_PKT = 0xB0, + CPL_ISCSI_DATA = 0xB2, CPL_FW4_MSG = 0xC0, CPL_FW4_PLD = 0xC1, diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index d31f9e600639..79788a12712d 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -1384,8 +1384,6 @@ rel_resource: return -EINVAL; } -#define CPL_ISCSI_DATA 0xB2 -#define CPL_RX_ISCSI_DDP 0x49 cxgb4i_cplhandler_func cxgb4i_cplhandlers[NUM_CPL_CMDS] = { [CPL_ACT_ESTABLISH] = do_act_establish, [CPL_ACT_OPEN_RPL] = do_act_open_rpl, -- cgit v1.2.3 From f24b9be5957b38bb420b838115040dc2031b7d0c Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 4 Aug 2014 22:11:45 -0400 Subject: net-timestamp: extend SCM_TIMESTAMPING ancillary data struct Applications that request kernel tx timestamps with SO_TIMESTAMPING read timestamps as recvmsg() ancillary data. The response is defined implicitly as timespec[3]. 1) define struct scm_timestamping explicitly and 2) add support for new tstamp types. On tx, scm_timestamping always accompanies a sock_extended_err. Define previously unused field ee_info to signal the type of ts[0]. Introduce SCM_TSTAMP_SND to define the existing behavior. The reception path is not modified. On rx, no struct similar to sock_extended_err is passed along with SCM_TIMESTAMPING. Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- include/linux/skbuff.h | 3 +++ include/net/sock.h | 4 +++- include/uapi/linux/errqueue.h | 18 ++++++++++++++++++ net/core/skbuff.c | 1 + net/socket.c | 20 +++++++++++--------- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 281deced7469..477f0f60db45 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -249,6 +249,9 @@ enum { SKBTX_SHARED_FRAG = 1 << 5, }; +#define SKBTX_ANY_SW_TSTAMP SKBTX_SW_TSTAMP +#define SKBTX_ANY_TSTAMP (SKBTX_HW_TSTAMP | SKBTX_ANY_SW_TSTAMP) + /* * The callback notifies userspace to release buffers when skb DMA is done in * lower device, the skb last reference should be 0 when calling this. diff --git a/include/net/sock.h b/include/net/sock.h index b91c8868ab8d..02f5b35e65f1 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2169,7 +2169,9 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) */ if (sock_flag(sk, SOCK_RCVTSTAMP) || sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE) || - (kt.tv64 && sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) || + (kt.tv64 && + (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) || + skb_shinfo(skb)->tx_flags & SKBTX_ANY_SW_TSTAMP)) || (hwtstamps->hwtstamp.tv64 && sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE))) __sock_recv_timestamp(msg, sk, skb); diff --git a/include/uapi/linux/errqueue.h b/include/uapi/linux/errqueue.h index aacd4fb7102a..accee72cae7c 100644 --- a/include/uapi/linux/errqueue.h +++ b/include/uapi/linux/errqueue.h @@ -22,5 +22,23 @@ struct sock_extended_err { #define SO_EE_OFFENDER(ee) ((struct sockaddr*)((ee)+1)) +/** + * struct scm_timestamping - timestamps exposed through cmsg + * + * The timestamping interfaces SO_TIMESTAMPING, MSG_TSTAMP_* + * communicate network timestamps by passing this struct in a cmsg with + * recvmsg(). See Documentation/networking/timestamping.txt for details. + */ +struct scm_timestamping { + struct timespec ts[3]; +}; + +/* The type of scm_timestamping, passed in sock_extended_err ee_info. + * This defines the type of ts[0]. For SCM_TSTAMP_SND only, if ts[0] + * is zero, then this is a hardware timestamp and recorded in ts[2]. + */ +enum { + SCM_TSTAMP_SND, /* driver passed skb to NIC, or HW */ +}; #endif /* _UAPI_LINUX_ERRQUEUE_H */ diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c1a33033cbe2..c9f68802e992 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3521,6 +3521,7 @@ void skb_tstamp_tx(struct sk_buff *orig_skb, memset(serr, 0, sizeof(*serr)); serr->ee.ee_errno = ENOMSG; serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; + serr->ee.ee_info = SCM_TSTAMP_SND; err = sock_queue_err_skb(sk, skb); diff --git a/net/socket.c b/net/socket.c index d8222c025061..dc0cc5d95ee5 100644 --- a/net/socket.c +++ b/net/socket.c @@ -106,6 +106,7 @@ #include #include #include +#include #ifdef CONFIG_NET_RX_BUSY_POLL unsigned int sysctl_net_busy_read __read_mostly; @@ -697,7 +698,7 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) { int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); - struct timespec ts[3]; + struct scm_timestamping tss; int empty = 1; struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); @@ -714,24 +715,25 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, sizeof(tv), &tv); } else { - skb_get_timestampns(skb, &ts[0]); + struct timespec ts; + skb_get_timestampns(skb, &ts); put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, - sizeof(ts[0]), &ts[0]); + sizeof(ts), &ts); } } - - memset(ts, 0, sizeof(ts)); - if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) && - ktime_to_timespec_cond(skb->tstamp, ts + 0)) + memset(&tss, 0, sizeof(tss)); + if ((sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) || + skb_shinfo(skb)->tx_flags & SKBTX_ANY_SW_TSTAMP) && + ktime_to_timespec_cond(skb->tstamp, tss.ts + 0)) empty = 0; if (shhwtstamps && sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) && - ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts + 2)) + ktime_to_timespec_cond(shhwtstamps->hwtstamp, tss.ts + 2)) empty = 0; if (!empty) put_cmsg(msg, SOL_SOCKET, - SCM_TIMESTAMPING, sizeof(ts), &ts); + SCM_TIMESTAMPING, sizeof(tss), &tss); } EXPORT_SYMBOL_GPL(__sock_recv_timestamp); -- cgit v1.2.3 From b9f40e21ef4298650ab33e35740fa85bd57706d5 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 4 Aug 2014 22:11:46 -0400 Subject: net-timestamp: move timestamp flags out of sk_flags sk_flags is reaching its limit. New timestamping options will not fit. Move all of them into a new field sk->sk_tsflags. Added benefit is that this removes boilerplate code to convert between SOF_TIMESTAMPING_.. and SOCK_TIMESTAMPING_.. in getsockopt/setsockopt. SOCK_TIMESTAMPING_RX_SOFTWARE is also used to toggle the receive timestamp logic (netstamp_needed). That can be simplified and this last key removed, but will leave that for a separate patch. Signed-off-by: Willem de Bruijn ---- The u16 in sock can be moved into a 16-bit hole below sk_gso_max_segs, though that scatters tstamp fields throughout the struct. Signed-off-by: David S. Miller --- include/net/sock.h | 29 +++++++++++------------------ net/core/sock.c | 25 ++----------------------- net/socket.c | 8 ++++---- 3 files changed, 17 insertions(+), 45 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 02f5b35e65f1..a21129716aae 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -67,6 +67,7 @@ #include #include #include +#include struct cgroup; struct cgroup_subsys; @@ -278,6 +279,7 @@ struct cg_proto; * @sk_protinfo: private area, net family specific, when not using slab * @sk_timer: sock cleanup timer * @sk_stamp: time stamp of last packet received + * @sk_tsflags: SO_TIMESTAMPING socket options * @sk_socket: Identd and reporting IO signals * @sk_user_data: RPC layer private data * @sk_frag: cached page frag @@ -411,6 +413,7 @@ struct sock { void *sk_protinfo; struct timer_list sk_timer; ktime_t sk_stamp; + u16 sk_tsflags; struct socket *sk_socket; void *sk_user_data; struct page_frag sk_frag; @@ -701,12 +704,7 @@ enum sock_flags { SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */ SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */ SOCK_MEMALLOC, /* VM depends on this socket for swapping */ - SOCK_TIMESTAMPING_TX_HARDWARE, /* %SOF_TIMESTAMPING_TX_HARDWARE */ - SOCK_TIMESTAMPING_TX_SOFTWARE, /* %SOF_TIMESTAMPING_TX_SOFTWARE */ - SOCK_TIMESTAMPING_RX_HARDWARE, /* %SOF_TIMESTAMPING_RX_HARDWARE */ SOCK_TIMESTAMPING_RX_SOFTWARE, /* %SOF_TIMESTAMPING_RX_SOFTWARE */ - SOCK_TIMESTAMPING_SOFTWARE, /* %SOF_TIMESTAMPING_SOFTWARE */ - SOCK_TIMESTAMPING_RAW_HARDWARE, /* %SOF_TIMESTAMPING_RAW_HARDWARE */ SOCK_FASYNC, /* fasync() active */ SOCK_RXQ_OVFL, SOCK_ZEROCOPY, /* buffers from userspace */ @@ -2160,20 +2158,17 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) /* * generate control messages if - * - receive time stamping in software requested (SOCK_RCVTSTAMP - * or SOCK_TIMESTAMPING_RX_SOFTWARE) + * - receive time stamping in software requested * - software time stamp available and wanted - * (SOCK_TIMESTAMPING_SOFTWARE) * - hardware time stamps available and wanted - * SOCK_TIMESTAMPING_RAW_HARDWARE */ if (sock_flag(sk, SOCK_RCVTSTAMP) || - sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE) || + (sk->sk_tsflags & SOF_TIMESTAMPING_RX_SOFTWARE) || (kt.tv64 && - (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) || + (sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE || skb_shinfo(skb)->tx_flags & SKBTX_ANY_SW_TSTAMP)) || (hwtstamps->hwtstamp.tv64 && - sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE))) + (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE))) __sock_recv_timestamp(msg, sk, skb); else sk->sk_stamp = kt; @@ -2189,11 +2184,11 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) { #define FLAGS_TS_OR_DROPS ((1UL << SOCK_RXQ_OVFL) | \ - (1UL << SOCK_RCVTSTAMP) | \ - (1UL << SOCK_TIMESTAMPING_SOFTWARE) | \ - (1UL << SOCK_TIMESTAMPING_RAW_HARDWARE)) + (1UL << SOCK_RCVTSTAMP)) +#define TSFLAGS_ANY (SOF_TIMESTAMPING_SOFTWARE | \ + SOF_TIMESTAMPING_RAW_HARDWARE) - if (sk->sk_flags & FLAGS_TS_OR_DROPS) + if (sk->sk_flags & FLAGS_TS_OR_DROPS || sk->sk_tsflags & TSFLAGS_ANY) __sock_recv_ts_and_drops(msg, sk, skb); else sk->sk_stamp = skb->tstamp; @@ -2203,8 +2198,6 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, * sock_tx_timestamp - checks whether the outgoing packet is to be time stamped * @sk: socket sending this packet * @tx_flags: filled with instructions for time stamping - * - * Currently only depends on SOCK_TIMESTAMPING* flags. */ void sock_tx_timestamp(struct sock *sk, __u8 *tx_flags); diff --git a/net/core/sock.c b/net/core/sock.c index a741163568fa..47c9377e14b9 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -848,22 +848,13 @@ set_rcvbuf: ret = -EINVAL; break; } - sock_valbool_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE, - val & SOF_TIMESTAMPING_TX_HARDWARE); - sock_valbool_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE, - val & SOF_TIMESTAMPING_TX_SOFTWARE); - sock_valbool_flag(sk, SOCK_TIMESTAMPING_RX_HARDWARE, - val & SOF_TIMESTAMPING_RX_HARDWARE); + sk->sk_tsflags = val; if (val & SOF_TIMESTAMPING_RX_SOFTWARE) sock_enable_timestamp(sk, SOCK_TIMESTAMPING_RX_SOFTWARE); else sock_disable_timestamp(sk, (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)); - sock_valbool_flag(sk, SOCK_TIMESTAMPING_SOFTWARE, - val & SOF_TIMESTAMPING_SOFTWARE); - sock_valbool_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE, - val & SOF_TIMESTAMPING_RAW_HARDWARE); break; case SO_RCVLOWAT: @@ -1089,19 +1080,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, break; case SO_TIMESTAMPING: - v.val = 0; - if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE)) - v.val |= SOF_TIMESTAMPING_TX_HARDWARE; - if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE)) - v.val |= SOF_TIMESTAMPING_TX_SOFTWARE; - if (sock_flag(sk, SOCK_TIMESTAMPING_RX_HARDWARE)) - v.val |= SOF_TIMESTAMPING_RX_HARDWARE; - if (sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE)) - v.val |= SOF_TIMESTAMPING_RX_SOFTWARE; - if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) - v.val |= SOF_TIMESTAMPING_SOFTWARE; - if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE)) - v.val |= SOF_TIMESTAMPING_RAW_HARDWARE; + v.val = sk->sk_tsflags; break; case SO_RCVTIMEO: diff --git a/net/socket.c b/net/socket.c index dc0cc5d95ee5..255d9b802723 100644 --- a/net/socket.c +++ b/net/socket.c @@ -613,9 +613,9 @@ EXPORT_SYMBOL(sock_release); void sock_tx_timestamp(struct sock *sk, __u8 *tx_flags) { *tx_flags = 0; - if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE)) + if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_HARDWARE) *tx_flags |= SKBTX_HW_TSTAMP; - if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE)) + if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_SOFTWARE) *tx_flags |= SKBTX_SW_TSTAMP; if (sock_flag(sk, SOCK_WIFI_STATUS)) *tx_flags |= SKBTX_WIFI_STATUS; @@ -723,12 +723,12 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, } memset(&tss, 0, sizeof(tss)); - if ((sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) || + if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE || skb_shinfo(skb)->tx_flags & SKBTX_ANY_SW_TSTAMP) && ktime_to_timespec_cond(skb->tstamp, tss.ts + 0)) empty = 0; if (shhwtstamps && - sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) && + (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) && ktime_to_timespec_cond(shhwtstamps->hwtstamp, tss.ts + 2)) empty = 0; if (!empty) -- cgit v1.2.3 From 09c2d251b70723650ba47e83571ff49281320f7c Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 4 Aug 2014 22:11:47 -0400 Subject: net-timestamp: add key to disambiguate concurrent datagrams Datagrams timestamped on transmission can coexist in the kernel stack and be reordered in packet scheduling. When reading looped datagrams from the socket error queue it is not always possible to unique correlate looped data with original send() call (for application level retransmits). Even if possible, it may be expensive and complex, requiring packet inspection. Introduce a data-independent ID mechanism to associate timestamps with send calls. Pass an ID alongside the timestamp in field ee_data of sock_extended_err. The ID is a simple 32 bit unsigned int that is associated with the socket and incremented on each send() call for which software tx timestamp generation is enabled. The feature is enabled only if SOF_TIMESTAMPING_OPT_ID is set, to avoid changing ee_data for existing applications that expect it 0. The counter is reset each time the flag is reenabled. Reenabling does not change the ID of already submitted data. It is possible to receive out of order IDs if the timestamp stream is not quiesced first. Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- include/linux/skbuff.h | 1 + include/net/sock.h | 2 ++ include/uapi/linux/net_tstamp.h | 8 +++++--- net/core/skbuff.c | 2 ++ net/core/sock.c | 3 +++ net/ipv4/ip_output.c | 6 ++++++ net/ipv6/ip6_output.c | 9 ++++++++- 7 files changed, 27 insertions(+), 4 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 477f0f60db45..0e35b3af7317 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -278,6 +278,7 @@ struct skb_shared_info { unsigned short gso_type; struct sk_buff *frag_list; struct skb_shared_hwtstamps hwtstamps; + u32 tskey; __be32 ip6_frag_id; /* diff --git a/include/net/sock.h b/include/net/sock.h index a21129716aae..52fe0bc5598a 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -280,6 +280,7 @@ struct cg_proto; * @sk_timer: sock cleanup timer * @sk_stamp: time stamp of last packet received * @sk_tsflags: SO_TIMESTAMPING socket options + * @sk_tskey: counter to disambiguate concurrent tstamp requests * @sk_socket: Identd and reporting IO signals * @sk_user_data: RPC layer private data * @sk_frag: cached page frag @@ -414,6 +415,7 @@ struct sock { struct timer_list sk_timer; ktime_t sk_stamp; u16 sk_tsflags; + u32 sk_tskey; struct socket *sk_socket; void *sk_user_data; struct page_frag sk_frag; diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h index f53879c0f590..1e861d2e1a31 100644 --- a/include/uapi/linux/net_tstamp.h +++ b/include/uapi/linux/net_tstamp.h @@ -20,9 +20,11 @@ enum { SOF_TIMESTAMPING_SOFTWARE = (1<<4), SOF_TIMESTAMPING_SYS_HARDWARE = (1<<5), SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6), - SOF_TIMESTAMPING_MASK = - (SOF_TIMESTAMPING_RAW_HARDWARE - 1) | - SOF_TIMESTAMPING_RAW_HARDWARE + SOF_TIMESTAMPING_OPT_ID = (1<<7), + + SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_ID, + SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | + SOF_TIMESTAMPING_LAST }; /** diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c9f68802e992..0df4f1d14c5a 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3522,6 +3522,8 @@ void skb_tstamp_tx(struct sk_buff *orig_skb, serr->ee.ee_errno = ENOMSG; serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; serr->ee.ee_info = SCM_TSTAMP_SND; + if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) + serr->ee.ee_data = skb_shinfo(skb)->tskey; err = sock_queue_err_skb(sk, skb); diff --git a/net/core/sock.c b/net/core/sock.c index 47c9377e14b9..1e0f1c63ad6b 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -848,6 +848,9 @@ set_rcvbuf: ret = -EINVAL; break; } + if (val & SOF_TIMESTAMPING_OPT_ID && + !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) + sk->sk_tskey = 0; sk->sk_tsflags = val; if (val & SOF_TIMESTAMPING_RX_SOFTWARE) sock_enable_timestamp(sk, diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index b16556836d66..215af2b155cb 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -855,11 +855,15 @@ static int __ip_append_data(struct sock *sk, unsigned int maxfraglen, fragheaderlen, maxnonfragsize; int csummode = CHECKSUM_NONE; struct rtable *rt = (struct rtable *)cork->dst; + u32 tskey = 0; skb = skb_peek_tail(queue); exthdrlen = !skb ? rt->dst.header_len : 0; mtu = cork->fragsize; + if (cork->tx_flags & SKBTX_ANY_SW_TSTAMP && + sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) + tskey = sk->sk_tskey++; hh_len = LL_RESERVED_SPACE(rt->dst.dev); @@ -976,6 +980,8 @@ alloc_new_skb: /* only the initial fragment is time stamped */ skb_shinfo(skb)->tx_flags = cork->tx_flags; cork->tx_flags = 0; + skb_shinfo(skb)->tskey = tskey; + tskey = 0; /* * Find where to start putting bytes. diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index f5dafe609f8b..315a55d66079 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1157,6 +1157,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int err; int offset = 0; __u8 tx_flags = 0; + u32 tskey = 0; if (flags&MSG_PROBE) return 0; @@ -1272,8 +1273,12 @@ emsgsize: } } - if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) + if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) { sock_tx_timestamp(sk, &tx_flags); + if (tx_flags & SKBTX_ANY_SW_TSTAMP && + sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) + tskey = sk->sk_tskey++; + } /* * Let's try using as much space as possible. @@ -1397,6 +1402,8 @@ alloc_new_skb: /* Only the initial fragment is time stamped */ skb_shinfo(skb)->tx_flags = tx_flags; tx_flags = 0; + skb_shinfo(skb)->tskey = tskey; + tskey = 0; /* * Find where to start putting bytes -- cgit v1.2.3 From e7fd2885385157d46c85f282fc6d7d297db43e1f Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 4 Aug 2014 22:11:48 -0400 Subject: net-timestamp: SCHED timestamp on entering packet scheduler Kernel transmit latency is often incurred in the packet scheduler. Introduce a new timestamp on transmission just before entering the scheduler. When data travels through multiple devices (bonding, tunneling, ...) each device will export an individual timestamp. Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- include/linux/skbuff.h | 11 +++++++++-- include/uapi/linux/errqueue.h | 1 + include/uapi/linux/net_tstamp.h | 3 ++- net/core/dev.c | 4 ++++ net/core/skbuff.c | 16 ++++++++++++---- net/socket.c | 3 +++ 6 files changed, 31 insertions(+), 7 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 0e35b3af7317..50e1e9b3a5a5 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -229,7 +229,7 @@ enum { /* generate hardware time stamp */ SKBTX_HW_TSTAMP = 1 << 0, - /* generate software time stamp */ + /* generate software time stamp when queueing packet to NIC */ SKBTX_SW_TSTAMP = 1 << 1, /* device driver is going to provide hardware time stamp */ @@ -247,9 +247,12 @@ enum { * all frags to avoid possible bad checksum */ SKBTX_SHARED_FRAG = 1 << 5, + + /* generate software time stamp when entering packet scheduling */ + SKBTX_SCHED_TSTAMP = 1 << 6, }; -#define SKBTX_ANY_SW_TSTAMP SKBTX_SW_TSTAMP +#define SKBTX_ANY_SW_TSTAMP (SKBTX_SW_TSTAMP | SKBTX_SCHED_TSTAMP) #define SKBTX_ANY_TSTAMP (SKBTX_HW_TSTAMP | SKBTX_ANY_SW_TSTAMP) /* @@ -2695,6 +2698,10 @@ static inline bool skb_defer_rx_timestamp(struct sk_buff *skb) void skb_complete_tx_timestamp(struct sk_buff *skb, struct skb_shared_hwtstamps *hwtstamps); +void __skb_tstamp_tx(struct sk_buff *orig_skb, + struct skb_shared_hwtstamps *hwtstamps, + struct sock *sk, int tstype); + /** * skb_tstamp_tx - queue clone of skb with send time stamps * @orig_skb: the original outgoing packet diff --git a/include/uapi/linux/errqueue.h b/include/uapi/linux/errqueue.h index accee72cae7c..17437cf297b7 100644 --- a/include/uapi/linux/errqueue.h +++ b/include/uapi/linux/errqueue.h @@ -39,6 +39,7 @@ struct scm_timestamping { */ enum { SCM_TSTAMP_SND, /* driver passed skb to NIC, or HW */ + SCM_TSTAMP_SCHED, /* data entered the packet scheduler */ }; #endif /* _UAPI_LINUX_ERRQUEUE_H */ diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h index 1e861d2e1a31..60733845fcdd 100644 --- a/include/uapi/linux/net_tstamp.h +++ b/include/uapi/linux/net_tstamp.h @@ -21,8 +21,9 @@ enum { SOF_TIMESTAMPING_SYS_HARDWARE = (1<<5), SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6), SOF_TIMESTAMPING_OPT_ID = (1<<7), + SOF_TIMESTAMPING_TX_SCHED = (1<<8), - SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_ID, + SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_TX_SCHED, SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | SOF_TIMESTAMPING_LAST }; diff --git a/net/core/dev.c b/net/core/dev.c index b370230fe1d3..1c15b189c52b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -132,6 +132,7 @@ #include #include #include +#include #include "net-sysfs.h" @@ -2876,6 +2877,9 @@ static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv) skb_reset_mac_header(skb); + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_SCHED_TSTAMP)) + __skb_tstamp_tx(skb, NULL, skb->sk, SCM_TSTAMP_SCHED); + /* Disable soft irqs for various locks below. Also * stops preemption for RCU. */ diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 0df4f1d14c5a..9705c0732aab 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3490,10 +3490,10 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) } EXPORT_SYMBOL(sock_queue_err_skb); -void skb_tstamp_tx(struct sk_buff *orig_skb, - struct skb_shared_hwtstamps *hwtstamps) +void __skb_tstamp_tx(struct sk_buff *orig_skb, + struct skb_shared_hwtstamps *hwtstamps, + struct sock *sk, int tstype) { - struct sock *sk = orig_skb->sk; struct sock_exterr_skb *serr; struct sk_buff *skb; int err; @@ -3521,7 +3521,7 @@ void skb_tstamp_tx(struct sk_buff *orig_skb, memset(serr, 0, sizeof(*serr)); serr->ee.ee_errno = ENOMSG; serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; - serr->ee.ee_info = SCM_TSTAMP_SND; + serr->ee.ee_info = tstype; if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) serr->ee.ee_data = skb_shinfo(skb)->tskey; @@ -3530,6 +3530,14 @@ void skb_tstamp_tx(struct sk_buff *orig_skb, if (err) kfree_skb(skb); } +EXPORT_SYMBOL_GPL(__skb_tstamp_tx); + +void skb_tstamp_tx(struct sk_buff *orig_skb, + struct skb_shared_hwtstamps *hwtstamps) +{ + return __skb_tstamp_tx(orig_skb, hwtstamps, orig_skb->sk, + SCM_TSTAMP_SND); +} EXPORT_SYMBOL_GPL(skb_tstamp_tx); void skb_complete_wifi_ack(struct sk_buff *skb, bool acked) diff --git a/net/socket.c b/net/socket.c index 255d9b802723..3a2778d71631 100644 --- a/net/socket.c +++ b/net/socket.c @@ -617,6 +617,9 @@ void sock_tx_timestamp(struct sock *sk, __u8 *tx_flags) *tx_flags |= SKBTX_HW_TSTAMP; if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_SOFTWARE) *tx_flags |= SKBTX_SW_TSTAMP; + if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED) + *tx_flags |= SKBTX_SCHED_TSTAMP; + if (sock_flag(sk, SOCK_WIFI_STATUS)) *tx_flags |= SKBTX_WIFI_STATUS; } -- cgit v1.2.3 From 4ed2d765dfaccff5ebdac68e2064b59125033a3b Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 4 Aug 2014 22:11:49 -0400 Subject: net-timestamp: TCP timestamping TCP timestamping extends SO_TIMESTAMPING to bytestreams. Bytestreams do not have a 1:1 relationship between send() buffers and network packets. The feature interprets a send call on a bytestream as a request for a timestamp for the last byte in that send() buffer. The choice corresponds to a request for a timestamp when all bytes in the buffer have been sent. That assumption depends on in-order kernel transmission. This is the common case. That said, it is possible to construct a traffic shaping tree that would result in reordering. The guarantee is strong, then, but not ironclad. This implementation supports send and sendpages (splice). GSO replaces one large packet with multiple smaller packets. This patch also copies the option into the correct smaller packet. This patch does not yet support timestamping on data in an initial TCP Fast Open SYN, because that takes a very different data path. If ID generation in ee_data is enabled, bytestream timestamps return a byte offset, instead of the packet counter for datagrams. The implementation supports a single timestamp per packet. It silenty replaces requests for previous timestamps. To avoid missing tstamps, flush the tcp queue by disabling Nagle, cork and autocork. Missing tstamps can be detected by offset when the ee_data ID is enabled. Implementation details: - On GSO, the timestamping code can be included in the main loop. I moved it into its own loop to reduce the impact on the common case to a single branch. - To avoid leaking the absolute seqno to userspace, the offset returned in ee_data must always be relative. It is an offset between an skb and sk field. The first is always set (also for GSO & ACK). The second must also never be uninitialized. Only allow the ID option on sockets in the ESTABLISHED state, for which the seqno is available. Never reset it to zero (instead, move it to the current seqno when reenabling the option). Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- net/core/skbuff.c | 5 ++++- net/core/sock.c | 13 +++++++++++-- net/ipv4/tcp.c | 22 +++++++++++++++++++--- net/ipv4/tcp_offload.c | 18 ++++++++++++++++++ 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 9705c0732aab..3dec0293a7c5 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3522,8 +3522,11 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb, serr->ee.ee_errno = ENOMSG; serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; serr->ee.ee_info = tstype; - if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) + if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) { serr->ee.ee_data = skb_shinfo(skb)->tskey; + if (sk->sk_protocol == IPPROTO_TCP) + serr->ee.ee_data -= sk->sk_tskey; + } err = sock_queue_err_skb(sk, skb); diff --git a/net/core/sock.c b/net/core/sock.c index 1e0f1c63ad6b..2714811afbd8 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -849,8 +849,17 @@ set_rcvbuf: break; } if (val & SOF_TIMESTAMPING_OPT_ID && - !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) - sk->sk_tskey = 0; + !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) { + if (sk->sk_protocol == IPPROTO_TCP) { + if (sk->sk_state != TCP_ESTABLISHED) { + ret = -EINVAL; + break; + } + sk->sk_tskey = tcp_sk(sk)->snd_una; + } else { + sk->sk_tskey = 0; + } + } sk->sk_tsflags = val; if (val & SOF_TIMESTAMPING_RX_SOFTWARE) sock_enable_timestamp(sk, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9d2118e5fbc7..744af67a5989 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -426,6 +426,15 @@ void tcp_init_sock(struct sock *sk) } EXPORT_SYMBOL(tcp_init_sock); +void tcp_tx_timestamp(struct sock *sk, struct sk_buff *skb) +{ + struct skb_shared_info *shinfo = skb_shinfo(skb); + + sock_tx_timestamp(sk, &shinfo->tx_flags); + if (shinfo->tx_flags & SKBTX_ANY_SW_TSTAMP) + shinfo->tskey = TCP_SKB_CB(skb)->seq + skb->len - 1; +} + /* * Wait for a TCP event. * @@ -523,7 +532,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait) } /* This barrier is coupled with smp_wmb() in tcp_reset() */ smp_rmb(); - if (sk->sk_err) + if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) mask |= POLLERR; return mask; @@ -959,8 +968,10 @@ new_segment: copied += copy; offset += copy; - if (!(size -= copy)) + if (!(size -= copy)) { + tcp_tx_timestamp(sk, skb); goto out; + } if (skb->len < size_goal || (flags & MSG_OOB)) continue; @@ -1252,8 +1263,10 @@ new_segment: from += copy; copied += copy; - if ((seglen -= copy) == 0 && iovlen == 0) + if ((seglen -= copy) == 0 && iovlen == 0) { + tcp_tx_timestamp(sk, skb); goto out; + } if (skb->len < max || (flags & MSG_OOB) || unlikely(tp->repair)) continue; @@ -1617,6 +1630,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, struct sk_buff *skb; u32 urg_hole = 0; + if (unlikely(flags & MSG_ERRQUEUE)) + return ip_recv_error(sk, msg, len, addr_len); + if (sk_can_busy_loop(sk) && skb_queue_empty(&sk->sk_receive_queue) && (sk->sk_state == TCP_ESTABLISHED)) sk_busy_loop(sk, nonblock); diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index 55046ecd083e..f597119fc4e7 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c @@ -14,6 +14,21 @@ #include #include +void tcp_gso_tstamp(struct sk_buff *skb, unsigned int ts_seq, unsigned int seq, + unsigned int mss) +{ + while (skb) { + if (ts_seq < (__u64) seq + mss) { + skb_shinfo(skb)->tx_flags = SKBTX_SW_TSTAMP; + skb_shinfo(skb)->tskey = ts_seq; + return; + } + + skb = skb->next; + seq += mss; + } +} + struct sk_buff *tcp_gso_segment(struct sk_buff *skb, netdev_features_t features) { @@ -91,6 +106,9 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb, th = tcp_hdr(skb); seq = ntohl(th->seq); + if (unlikely(skb_shinfo(gso_skb)->tx_flags & SKBTX_SW_TSTAMP)) + tcp_gso_tstamp(segs, skb_shinfo(gso_skb)->tskey, seq, mss); + newcheck = ~csum_fold((__force __wsum)((__force u32)th->check + (__force u32)delta)); -- cgit v1.2.3 From e1c8a607b28190cd09a271508aa3025d3c2f312e Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 4 Aug 2014 22:11:50 -0400 Subject: net-timestamp: ACK timestamp for bytestreams Add SOF_TIMESTAMPING_TX_ACK, a request for a tstamp when the last byte in the send() call is acknowledged. It implements the feature for TCP. The timestamp is generated when the TCP socket cumulative ACK is moved beyond the tracked seqno for the first time. The feature ignores SACK and FACK, because those acknowledge the specific byte, but not necessarily the entire contents of the buffer up to that byte. Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- include/linux/skbuff.h | 7 ++++++- include/uapi/linux/errqueue.h | 1 + include/uapi/linux/net_tstamp.h | 3 ++- net/ipv4/tcp_input.c | 6 ++++++ net/socket.c | 2 ++ 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 50e1e9b3a5a5..11c270551d25 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -250,9 +250,14 @@ enum { /* generate software time stamp when entering packet scheduling */ SKBTX_SCHED_TSTAMP = 1 << 6, + + /* generate software timestamp on peer data acknowledgment */ + SKBTX_ACK_TSTAMP = 1 << 7, }; -#define SKBTX_ANY_SW_TSTAMP (SKBTX_SW_TSTAMP | SKBTX_SCHED_TSTAMP) +#define SKBTX_ANY_SW_TSTAMP (SKBTX_SW_TSTAMP | \ + SKBTX_SCHED_TSTAMP | \ + SKBTX_ACK_TSTAMP) #define SKBTX_ANY_TSTAMP (SKBTX_HW_TSTAMP | SKBTX_ANY_SW_TSTAMP) /* diff --git a/include/uapi/linux/errqueue.h b/include/uapi/linux/errqueue.h index 17437cf297b7..07bdce1f444a 100644 --- a/include/uapi/linux/errqueue.h +++ b/include/uapi/linux/errqueue.h @@ -40,6 +40,7 @@ struct scm_timestamping { enum { SCM_TSTAMP_SND, /* driver passed skb to NIC, or HW */ SCM_TSTAMP_SCHED, /* data entered the packet scheduler */ + SCM_TSTAMP_ACK, /* data acknowledged by peer */ }; #endif /* _UAPI_LINUX_ERRQUEUE_H */ diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h index 60733845fcdd..ff354021bb69 100644 --- a/include/uapi/linux/net_tstamp.h +++ b/include/uapi/linux/net_tstamp.h @@ -22,8 +22,9 @@ enum { SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6), SOF_TIMESTAMPING_OPT_ID = (1<<7), SOF_TIMESTAMPING_TX_SCHED = (1<<8), + SOF_TIMESTAMPING_TX_ACK = (1<<9), - SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_TX_SCHED, + SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_TX_ACK, SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | SOF_TIMESTAMPING_LAST }; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6a2984507755..a3d47af01906 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -74,6 +74,7 @@ #include #include #include +#include int sysctl_tcp_timestamps __read_mostly = 1; int sysctl_tcp_window_scaling __read_mostly = 1; @@ -3106,6 +3107,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, tp->retrans_stamp = 0; } + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_ACK_TSTAMP) && + between(skb_shinfo(skb)->tskey, prior_snd_una, + tp->snd_una + 1)) + __skb_tstamp_tx(skb, NULL, sk, SCM_TSTAMP_ACK); + if (!fully_acked) break; diff --git a/net/socket.c b/net/socket.c index 3a2778d71631..ae89569a2db5 100644 --- a/net/socket.c +++ b/net/socket.c @@ -619,6 +619,8 @@ void sock_tx_timestamp(struct sock *sk, __u8 *tx_flags) *tx_flags |= SKBTX_SW_TSTAMP; if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED) *tx_flags |= SKBTX_SCHED_TSTAMP; + if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK) + *tx_flags |= SKBTX_ACK_TSTAMP; if (sock_flag(sk, SOCK_WIFI_STATUS)) *tx_flags |= SKBTX_WIFI_STATUS; -- cgit v1.2.3 From fdb0a6626e8ef99fda8c30971c59ba51321dbab9 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Tue, 5 Aug 2014 15:57:15 +0900 Subject: bridge: Update outdated comment on promiscuous mode Now bridge ports can be non-promiscuous, vlan_vid_add() is no longer an unnecessary operation. Signed-off-by: Toshiaki Makita Signed-off-by: David S. Miller --- net/bridge/br_vlan.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 2b2774fe0703..febb0f87fa37 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -55,10 +55,8 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags) if (p) { /* Add VLAN to the device filter if it is supported. - * Stricly speaking, this is not necessary now, since - * devices are made promiscuous by the bridge, but if - * that ever changes this code will allow tagged - * traffic to enter the bridge. + * This ensures tagged traffic enters the bridge when + * promiscuous mode is disabled by br_manage_promisc(). */ err = vlan_vid_add(dev, br->vlan_proto, vid); if (err) -- cgit v1.2.3 From ff204cce75d75678bf75fdd48c4c89fa30c555d3 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Tue, 5 Aug 2014 15:58:50 +0900 Subject: team: Simplify return path of team_newlink The variable "err" is not necessary. Return register_netdevice() directly. Signed-off-by: Toshiaki Makita Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/team/team.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index b4958c7ffa84..ef10302ec936 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2045,16 +2045,10 @@ static void team_setup(struct net_device *dev) static int team_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { - int err; - if (tb[IFLA_ADDRESS] == NULL) eth_hw_addr_random(dev); - err = register_netdevice(dev); - if (err) - return err; - - return 0; + return register_netdevice(dev); } static int team_validate(struct nlattr *tb[], struct nlattr *data[]) -- cgit v1.2.3 From c2a198569aeab71c36156f83128916dce9561741 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 5 Aug 2014 15:41:28 +0530 Subject: cxgb4vf: Turn off SGE RX/TX Callback Timers and interrupts in PCI shutdown routine Need to turn off SGE RX/TX Callback Timers & interrupt in cxgb4vf PCI Shutdown routine in order to prevent crashes during reboot/poweroff when traffic is running. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- .../net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 29 +++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index f002af190a65..d8d28e82ade1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -2876,24 +2876,24 @@ static void cxgb4vf_pci_shutdown(struct pci_dev *pdev) if (!adapter) return; - /* - * Disable all Virtual Interfaces. This will shut down the + /* Disable all Virtual Interfaces. This will shut down the * delivery of all ingress packets into the chip for these * Virtual Interfaces. */ - for_each_port(adapter, pidx) { - struct net_device *netdev; - struct port_info *pi; - - if (!test_bit(pidx, &adapter->registered_device_map)) - continue; - - netdev = adapter->port[pidx]; - if (!netdev) - continue; + for_each_port(adapter, pidx) + if (test_bit(pidx, &adapter->registered_device_map)) + unregister_netdev(adapter->port[pidx]); - pi = netdev_priv(netdev); - t4vf_enable_vi(adapter, pi->viid, false, false); + /* Free up all Queues which will prevent further DMA and + * Interrupts allowing various internal pathways to drain. + */ + t4vf_sge_stop(adapter); + if (adapter->flags & USING_MSIX) { + pci_disable_msix(adapter->pdev); + adapter->flags &= ~USING_MSIX; + } else if (adapter->flags & USING_MSI) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~USING_MSI; } /* @@ -2901,6 +2901,7 @@ static void cxgb4vf_pci_shutdown(struct pci_dev *pdev) * Interrupts allowing various internal pathways to drain. */ t4vf_free_sge_resources(adapter); + pci_set_drvdata(pdev, NULL); } /* -- cgit v1.2.3 From ce7991e8198b80eb6b4441b6f6114bea4a665d66 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 5 Aug 2014 08:13:42 -0300 Subject: Revert "net: phy: Set the driver when registering an MDIO bus device" Commit a71e3c37960ce5f9 ("net: phy: Set the driver when registering an MDIO bus device") caused the following regression on the fec driver: root@imx6qsabresd:~# echo mem > /sys/power/state PM: Syncing filesystems ... done. Freezing user space processes ... (elapsed 0.003 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.002 seconds) done. Unable to handle kernel NULL pointer dereference at virtual address 0000002c pgd = bcd14000 [0000002c] *pgd=4d9e0831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] SMP ARM Modules linked in: CPU: 0 PID: 617 Comm: sh Not tainted 3.16.0 #17 task: bc0c4e00 ti: bceb6000 task.ti: bceb6000 PC is at fec_suspend+0x10/0x70 LR is at dpm_run_callback.isra.7+0x34/0x6c pc : [<803f8a98>] lr : [<80361f44>] psr: 600f0013 sp : bceb7d70 ip : bceb7d88 fp : bceb7d84 r10: 8091523c r9 : 00000000 r8 : bd88f478 r7 : 803f8a88 r6 : 81165988 r5 : 00000000 r4 : 00000000 r3 : 00000000 r2 : 00000000 r1 : bd88f478 r0 : bd88f478 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c5387d Table: 4cd1404a DAC: 00000015 Process sh (pid: 617, stack limit = 0xbceb6240) Stack: (0xbceb7d70 to 0xbceb8000) .... The problem with the original commit is explained by Russell King: "It has the effect (as can be seen from the oops) of attaching the MDIO bus device (itself is a bus-less device) to the platform driver, which means that if the platform driver supports power management, it will be called to power manage the MDIO bus device. Moreover, drivers do not expect to be called for power management operations for devices which they haven't probed, and certainly not for devices which aren't part of the same bus that the driver is registered against." This reverts commit a71e3c37960ce5f9c6a519bc1215e3ba9fa83e75. Cc: #3.16 Signed-off-by: Fabio Estevam Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 203651ebccb0..4eaadcfcb0fe 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -255,7 +255,6 @@ int mdiobus_register(struct mii_bus *bus) bus->dev.parent = bus->parent; bus->dev.class = &mdio_bus_class; - bus->dev.driver = bus->parent->driver; bus->dev.groups = NULL; dev_set_name(&bus->dev, "%s", bus->id); -- cgit v1.2.3 From 757efd32d5ce31f67193cc0e6a56e4dffcc42fb1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 5 Aug 2014 16:49:52 +0200 Subject: sctp: fix possible seqlock seadlock in sctp_packet_transmit() Dave reported following splat, caused by improper use of IP_INC_STATS_BH() in process context. BUG: using __this_cpu_add() in preemptible [00000000] code: trinity-c117/14551 caller is __this_cpu_preempt_check+0x13/0x20 CPU: 3 PID: 14551 Comm: trinity-c117 Not tainted 3.16.0+ #33 ffffffff9ec898f0 0000000047ea7e23 ffff88022d32f7f0 ffffffff9e7ee207 0000000000000003 ffff88022d32f818 ffffffff9e397eaa ffff88023ee70b40 ffff88022d32f970 ffff8801c026d580 ffff88022d32f828 ffffffff9e397ee3 Call Trace: [] dump_stack+0x4e/0x7a [] check_preemption_disabled+0xfa/0x100 [] __this_cpu_preempt_check+0x13/0x20 [] sctp_packet_transmit+0x692/0x710 [sctp] [] sctp_outq_flush+0x2a2/0xc30 [sctp] [] ? mark_held_locks+0x7c/0xb0 [] ? _raw_spin_unlock_irqrestore+0x5d/0x80 [] sctp_outq_uncork+0x1a/0x20 [sctp] [] sctp_cmd_interpreter.isra.23+0x1142/0x13f0 [sctp] [] sctp_do_sm+0xdb/0x330 [sctp] [] ? preempt_count_sub+0xab/0x100 [] ? sctp_cname+0x70/0x70 [sctp] [] sctp_primitive_ASSOCIATE+0x3a/0x50 [sctp] [] sctp_sendmsg+0x88f/0xe30 [sctp] [] ? lock_release_holdtime.part.28+0x9a/0x160 [] ? put_lock_stats.isra.27+0xe/0x30 [] inet_sendmsg+0x104/0x220 [] ? inet_sendmsg+0x5/0x220 [] sock_sendmsg+0x9e/0xe0 [] ? might_fault+0xb9/0xc0 [] ? might_fault+0x5e/0xc0 [] SYSC_sendto+0x124/0x1c0 [] ? syscall_trace_enter+0x250/0x330 [] SyS_sendto+0xe/0x10 [] tracesys+0xdd/0xe2 This is a followup of commits f1d8cba61c3c4b ("inet: fix possible seqlock deadlocks") and 7f88c6b23afbd315 ("ipv6: fix possible seqlock deadlock in ip6_finish_output2") Signed-off-by: Eric Dumazet Cc: Hannes Frederic Sowa Reported-by: Dave Jones Acked-by: Neil Horman Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/sctp/output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/output.c b/net/sctp/output.c index 01ab8e0723f0..407ae2bf97b0 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -599,7 +599,7 @@ out: return err; no_route: kfree_skb(nskb); - IP_INC_STATS_BH(sock_net(asoc->base.sk), IPSTATS_MIB_OUTNOROUTES); + IP_INC_STATS(sock_net(asoc->base.sk), IPSTATS_MIB_OUTNOROUTES); /* FIXME: Returning the 'err' will effect all the associations * associated with a socket, although only one of the paths of the -- cgit v1.2.3 From 2670cc699a66c4cf268cb3e3f6dfc325ec14f224 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 5 Aug 2014 16:44:39 +0100 Subject: net: sun4i-emac: fix memory leak on bad packet Upon reception of a new frame, the emac driver checks for a number of error conditions, and flag the packet as "bad" if any of these are present. It then allocates a skb unconditionally, but only uses it if the packet is "good". On the error path, the skb is just forgotten, and the system leaks memory. The piece of junk I have on my desk seems to encounter such error frequently enough so that the box goes OOM after a couple of days, which makes me grumpy. Fix this by moving the allocation on the "good_packet" path (and convert it to netdev_alloc_skb while we're at it). Tested on a random Allwinner A20 board. Cc: Stefan Roese Cc: Maxime Ripard Cc: # 3.11+ Signed-off-by: Marc Zyngier Acked-by: Maxime Ripard Signed-off-by: David S. Miller --- drivers/net/ethernet/allwinner/sun4i-emac.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c index d81e7167a8b5..29b9f082475d 100644 --- a/drivers/net/ethernet/allwinner/sun4i-emac.c +++ b/drivers/net/ethernet/allwinner/sun4i-emac.c @@ -633,8 +633,10 @@ static void emac_rx(struct net_device *dev) } /* Move data from EMAC */ - skb = dev_alloc_skb(rxlen + 4); - if (good_packet && skb) { + if (good_packet) { + skb = netdev_alloc_skb(dev, rxlen + 4); + if (!skb) + continue; skb_reserve(skb, 2); rdptr = (u8 *) skb_put(skb, rxlen - 4); -- cgit v1.2.3 From f3d0e78d2e733176c2b0d23e7a7d871c7a33c2d6 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 5 Aug 2014 13:30:38 -0500 Subject: amd-xgbe: Use dma_set_mask_and_coherent to set DMA mask Use the dma_set_mask_and_coherent function to set the DMA mask rather than setting the DMA mask fields directly. This was originally done to work around a bug in the arm64 DMA support when RAM started above the 4GB boundary which has since been fixed. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index ec977d36063f..8aa6a9353f7b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -303,8 +303,11 @@ static int xgbe_probe(struct platform_device *pdev) /* Set the DMA mask */ if (!dev->dma_mask) dev->dma_mask = &dev->coherent_dma_mask; - *(dev->dma_mask) = DMA_BIT_MASK(40); - dev->coherent_dma_mask = DMA_BIT_MASK(40); + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); + if (ret) { + dev_err(dev, "dma_set_mask_and_coherent failed\n"); + goto err_io; + } if (of_property_read_bool(dev->of_node, "dma-coherent")) { pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; -- cgit v1.2.3 From 88131a812b16b45cf999e577ad8d89b41ad606e3 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Tue, 5 Aug 2014 13:30:44 -0500 Subject: amd-xgbe: Perform phy connect/disconnect at dev open/stop A change added to the mdiobus/phy api added a module_get/module_put during phy connect/disconnect processing. Currently, the driver performs a phy connect during module probe and a phy disconnect during module remove. With the addition of the module_get during phy connect the amd-xgbe module use count is incremented and can no longer be unloaded. Move the phy connect/disconnect from the driver probe/remove functions to the net_device_ops ndo_open/ndo_stop functions. This allows the module use count to be decremented when the device(s) are brought down and allows the module to be unloaded. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 122 +++++++++++++++++++++++++++++- drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 98 ------------------------ 2 files changed, 121 insertions(+), 99 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 3bf3c0194ad3..1f5487f4888c 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -122,6 +122,7 @@ #include #include #include +#include #include "xgbe.h" #include "xgbe-common.h" @@ -521,6 +522,114 @@ static void xgbe_free_rx_skbuff(struct xgbe_prv_data *pdata) DBGPR("<--xgbe_free_rx_skbuff\n"); } +static void xgbe_adjust_link(struct net_device *netdev) +{ + struct xgbe_prv_data *pdata = netdev_priv(netdev); + struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct phy_device *phydev = pdata->phydev; + int new_state = 0; + + if (phydev == NULL) + return; + + if (phydev->link) { + /* Flow control support */ + if (pdata->pause_autoneg) { + if (phydev->pause || phydev->asym_pause) { + pdata->tx_pause = 1; + pdata->rx_pause = 1; + } else { + pdata->tx_pause = 0; + pdata->rx_pause = 0; + } + } + + if (pdata->tx_pause != pdata->phy_tx_pause) { + hw_if->config_tx_flow_control(pdata); + pdata->phy_tx_pause = pdata->tx_pause; + } + + if (pdata->rx_pause != pdata->phy_rx_pause) { + hw_if->config_rx_flow_control(pdata); + pdata->phy_rx_pause = pdata->rx_pause; + } + + /* Speed support */ + if (phydev->speed != pdata->phy_speed) { + new_state = 1; + + switch (phydev->speed) { + case SPEED_10000: + hw_if->set_xgmii_speed(pdata); + break; + + case SPEED_2500: + hw_if->set_gmii_2500_speed(pdata); + break; + + case SPEED_1000: + hw_if->set_gmii_speed(pdata); + break; + } + pdata->phy_speed = phydev->speed; + } + + if (phydev->link != pdata->phy_link) { + new_state = 1; + pdata->phy_link = 1; + } + } else if (pdata->phy_link) { + new_state = 1; + pdata->phy_link = 0; + pdata->phy_speed = SPEED_UNKNOWN; + } + + if (new_state) + phy_print_status(phydev); +} + +static int xgbe_phy_init(struct xgbe_prv_data *pdata) +{ + struct net_device *netdev = pdata->netdev; + struct phy_device *phydev = pdata->phydev; + int ret; + + pdata->phy_link = -1; + pdata->phy_speed = SPEED_UNKNOWN; + pdata->phy_tx_pause = pdata->tx_pause; + pdata->phy_rx_pause = pdata->rx_pause; + + ret = phy_connect_direct(netdev, phydev, &xgbe_adjust_link, + pdata->phy_mode); + if (ret) { + netdev_err(netdev, "phy_connect_direct failed\n"); + return ret; + } + + if (!phydev->drv || (phydev->drv->phy_id == 0)) { + netdev_err(netdev, "phy_id not valid\n"); + ret = -ENODEV; + goto err_phy_connect; + } + DBGPR(" phy_connect_direct succeeded for PHY %s, link=%d\n", + dev_name(&phydev->dev), phydev->link); + + return 0; + +err_phy_connect: + phy_disconnect(phydev); + + return ret; +} + +static void xgbe_phy_exit(struct xgbe_prv_data *pdata) +{ + if (!pdata->phydev) + return; + + phy_disconnect(pdata->phydev); +} + int xgbe_powerdown(struct net_device *netdev, unsigned int caller) { struct xgbe_prv_data *pdata = netdev_priv(netdev); @@ -986,11 +1095,16 @@ static int xgbe_open(struct net_device *netdev) DBGPR("-->xgbe_open\n"); + /* Initialize the phy */ + ret = xgbe_phy_init(pdata); + if (ret) + return ret; + /* Enable the clocks */ ret = clk_prepare_enable(pdata->sysclk); if (ret) { netdev_alert(netdev, "dma clk_prepare_enable failed\n"); - return ret; + goto err_phy_init; } ret = clk_prepare_enable(pdata->ptpclk); @@ -1047,6 +1161,9 @@ err_ptpclk: err_sysclk: clk_disable_unprepare(pdata->sysclk); +err_phy_init: + xgbe_phy_exit(pdata); + return ret; } @@ -1077,6 +1194,9 @@ static int xgbe_close(struct net_device *netdev) clk_disable_unprepare(pdata->ptpclk); clk_disable_unprepare(pdata->sysclk); + /* Release the phy */ + xgbe_phy_exit(pdata); + DBGPR("<--xgbe_close\n"); return 0; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index eecd360430a4..6d2221e023f4 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -116,7 +116,6 @@ #include #include -#include #include #include #include @@ -158,77 +157,6 @@ static int xgbe_mdio_write(struct mii_bus *mii, int prtad, int mmd_reg, return 0; } -static void xgbe_adjust_link(struct net_device *netdev) -{ - struct xgbe_prv_data *pdata = netdev_priv(netdev); - struct xgbe_hw_if *hw_if = &pdata->hw_if; - struct phy_device *phydev = pdata->phydev; - int new_state = 0; - - if (phydev == NULL) - return; - - DBGPR_MDIO("-->xgbe_adjust_link: address=%d, newlink=%d, curlink=%d\n", - phydev->addr, phydev->link, pdata->phy_link); - - if (phydev->link) { - /* Flow control support */ - if (pdata->pause_autoneg) { - if (phydev->pause || phydev->asym_pause) { - pdata->tx_pause = 1; - pdata->rx_pause = 1; - } else { - pdata->tx_pause = 0; - pdata->rx_pause = 0; - } - } - - if (pdata->tx_pause != pdata->phy_tx_pause) { - hw_if->config_tx_flow_control(pdata); - pdata->phy_tx_pause = pdata->tx_pause; - } - - if (pdata->rx_pause != pdata->phy_rx_pause) { - hw_if->config_rx_flow_control(pdata); - pdata->phy_rx_pause = pdata->rx_pause; - } - - /* Speed support */ - if (phydev->speed != pdata->phy_speed) { - new_state = 1; - - switch (phydev->speed) { - case SPEED_10000: - hw_if->set_xgmii_speed(pdata); - break; - - case SPEED_2500: - hw_if->set_gmii_2500_speed(pdata); - break; - - case SPEED_1000: - hw_if->set_gmii_speed(pdata); - break; - } - pdata->phy_speed = phydev->speed; - } - - if (phydev->link != pdata->phy_link) { - new_state = 1; - pdata->phy_link = 1; - } - } else if (pdata->phy_link) { - new_state = 1; - pdata->phy_link = 0; - pdata->phy_speed = SPEED_UNKNOWN; - } - - if (new_state) - phy_print_status(phydev); - - DBGPR_MDIO("<--xgbe_adjust_link\n"); -} - void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) { struct device *dev = pdata->dev; @@ -278,7 +206,6 @@ void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) int xgbe_mdio_register(struct xgbe_prv_data *pdata) { - struct net_device *netdev = pdata->netdev; struct device_node *phy_node; struct mii_bus *mii; struct phy_device *phydev; @@ -293,7 +220,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) return -EINVAL; } - /* Register with the MDIO bus */ mii = mdiobus_alloc(); if (mii == NULL) { dev_err(pdata->dev, "mdiobus_alloc failed\n"); @@ -348,26 +274,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) pdata->mii = mii; pdata->mdio_mmd = MDIO_MMD_PCS; - pdata->phy_link = -1; - pdata->phy_speed = SPEED_UNKNOWN; - pdata->phy_tx_pause = pdata->tx_pause; - pdata->phy_rx_pause = pdata->rx_pause; - - ret = phy_connect_direct(netdev, phydev, &xgbe_adjust_link, - pdata->phy_mode); - if (ret) { - netdev_err(netdev, "phy_connect_direct failed\n"); - goto err_phy_device; - } - - if (!phydev->drv || (phydev->drv->phy_id == 0)) { - netdev_err(netdev, "phy_id not valid\n"); - ret = -ENODEV; - goto err_phy_connect; - } - DBGPR(" phy_connect_direct succeeded for PHY %s, link=%d\n", - dev_name(&phydev->dev), phydev->link); - phydev->autoneg = pdata->default_autoneg; if (phydev->autoneg == AUTONEG_DISABLE) { phydev->speed = pdata->default_speed; @@ -386,9 +292,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) return 0; -err_phy_connect: - phy_disconnect(phydev); - err_phy_device: phy_device_free(phydev); @@ -408,7 +311,6 @@ void xgbe_mdio_unregister(struct xgbe_prv_data *pdata) { DBGPR("-->xgbe_mdio_unregister\n"); - phy_disconnect(pdata->phydev); pdata->phydev = NULL; module_put(pdata->phy_module); -- cgit v1.2.3 From 4d8fdc95c60e90d84c8257a0067ff4b1729a3757 Mon Sep 17 00:00:00 2001 From: Prashant Sreedharan Date: Tue, 5 Aug 2014 16:02:02 -0700 Subject: tg3: Modify tg3_tso_bug() to handle multiple TX rings tg3_tso_bug() was originally designed to handle only HW TX ring 0, Commit d3f6f3a1d818410c17445bce4f4caab52eb102f1 ("tg3: Prevent page allocation failure during TSO workaround") changed the driver logic to use tg3_tso_bug() for all HW TX rings that are enabled. This patch fixes the regression by modifying tg3_tso_bug() to handle multiple HW TX rings. Signed-off-by: Prashant Sreedharan Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 8afa579e7c40..a3dd5dc64f4c 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -7830,17 +7830,18 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, static netdev_tx_t tg3_start_xmit(struct sk_buff *, struct net_device *); -/* Use GSO to workaround a rare TSO bug that may be triggered when the - * TSO header is greater than 80 bytes. +/* Use GSO to workaround all TSO packets that meet HW bug conditions + * indicated in tg3_tx_frag_set() */ -static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) +static int tg3_tso_bug(struct tg3 *tp, struct tg3_napi *tnapi, + struct netdev_queue *txq, struct sk_buff *skb) { struct sk_buff *segs, *nskb; u32 frag_cnt_est = skb_shinfo(skb)->gso_segs * 3; /* Estimate the number of fragments in the worst case */ - if (unlikely(tg3_tx_avail(&tp->napi[0]) <= frag_cnt_est)) { - netif_stop_queue(tp->dev); + if (unlikely(tg3_tx_avail(tnapi) <= frag_cnt_est)) { + netif_tx_stop_queue(txq); /* netif_tx_stop_queue() must be done before checking * checking tx index in tg3_tx_avail() below, because in @@ -7848,13 +7849,14 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) * netif_tx_queue_stopped(). */ smp_mb(); - if (tg3_tx_avail(&tp->napi[0]) <= frag_cnt_est) + if (tg3_tx_avail(tnapi) <= frag_cnt_est) return NETDEV_TX_BUSY; - netif_wake_queue(tp->dev); + netif_tx_wake_queue(txq); } - segs = skb_gso_segment(skb, tp->dev->features & ~(NETIF_F_TSO | NETIF_F_TSO6)); + segs = skb_gso_segment(skb, tp->dev->features & + ~(NETIF_F_TSO | NETIF_F_TSO6)); if (IS_ERR(segs) || !segs) goto tg3_tso_bug_end; @@ -7930,7 +7932,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!skb_is_gso_v6(skb)) { if (unlikely((ETH_HLEN + hdr_len) > 80) && tg3_flag(tp, TSO_BUG)) - return tg3_tso_bug(tp, skb); + return tg3_tso_bug(tp, tnapi, txq, skb); ip_csum = iph->check; ip_tot_len = iph->tot_len; @@ -8061,7 +8063,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) iph->tot_len = ip_tot_len; } tcph->check = tcp_csum; - return tg3_tso_bug(tp, skb); + return tg3_tso_bug(tp, tnapi, txq, skb); } /* If the workaround fails due to memory/mapping -- cgit v1.2.3 From 1bb5a356c3ea6e633908e0ebd6695b13debc3d86 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Tue, 5 Aug 2014 23:10:52 +0200 Subject: net: reduce USB network driver config options. USB network drivers are already handled in drivers/net/usb/Kconfig. Let's save the maintenance burden of dependencies in drivers/net/Makefile. The newly introduced USB_NET_DRIVERS umbrella config option defaults to 'y' so as to minimize the changes of behavior. Signed-off-by: Francois Romieu Signed-off-by: David S. Miller --- drivers/net/Makefile | 9 +-------- drivers/net/usb/Kconfig | 13 ++++++++----- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index fa49d45f9ff6..61aefdd1e173 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -61,14 +61,7 @@ obj-$(CONFIG_VMXNET3) += vmxnet3/ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o obj-$(CONFIG_XEN_NETDEV_BACKEND) += xen-netback/ -obj-$(CONFIG_USB_CATC) += usb/ -obj-$(CONFIG_USB_KAWETH) += usb/ -obj-$(CONFIG_USB_PEGASUS) += usb/ -obj-$(CONFIG_USB_RTL8150) += usb/ -obj-$(CONFIG_USB_HSO) += usb/ -obj-$(CONFIG_USB_USBNET) += usb/ -obj-$(CONFIG_USB_IPHETH) += usb/ -obj-$(CONFIG_USB_CDC_PHONET) += usb/ +obj-$(CONFIG_USB_NET_DRIVERS) += usb/ obj-$(CONFIG_HYPERV_NET) += hyperv/ obj-$(CONFIG_NTB_NETDEV) += ntb_netdev.o diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 7e7269fd3707..9f194a0bef7c 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -1,12 +1,16 @@ # # USB Network devices configuration # -comment "Networking support is needed for USB Network Adapter support" - depends on USB && !NET +comment "Host-side USB support is needed for USB Network Adapter support" + depends on !USB && NET -menu "USB Network Adapters" +menuconfig USB_NET_DRIVERS + bool "USB Network Adapters" + default y depends on USB && NET +if USB_NET_DRIVERS + config USB_CATC tristate "USB CATC NetMate-based Ethernet device support" select CRC32 @@ -568,5 +572,4 @@ config USB_VL600 http://ubuntuforums.org/showpost.php?p=10589647&postcount=17 - -endmenu +endif # USB_NET_DRIVERS -- cgit v1.2.3 From 30f00847953e3aa3f710d62ffd37b42042807900 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Tue, 5 Aug 2014 16:05:23 -0700 Subject: cxgb4 : Disable recursive mailbox commands when enabling vi Enabling a Virtual Interface can result in an interrupt during the processing of the VI Enable command and, in some paths, result in an attempt to issue another command in the interrupt context, eventually crashing the system. Thus, we disable interrupts during the course of the VI Enable command and ensure enable doesn't sleep. Signed-off-by: Anish Bhatt Signed-off-by: Casey Leedom Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 5 ++++- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 8b46534b06c1..4247356c16ff 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -673,9 +673,12 @@ static int link_start(struct net_device *dev) if (ret == 0) ret = t4_link_start(pi->adapter, mb, pi->tx_chan, &pi->link_cfg); - if (ret == 0) + if (ret == 0) { + local_bh_disable(); ret = t4_enable_vi_params(pi->adapter, mb, pi->viid, true, true, CXGB4_DCB_ENABLED); + local_bh_enable(); + } return ret; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 448bec119c3c..a853133d8db8 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3558,7 +3558,7 @@ int t4_enable_vi_params(struct adapter *adap, unsigned int mbox, c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_IEN(rx_en) | FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c) | FW_VI_ENABLE_CMD_DCB_INFO(dcb_en)); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); + return t4_wr_mbox_ns(adap, mbox, &c, sizeof(c), NULL); } /** -- cgit v1.2.3