From 91c1a09b33c902e20e09d9742560cc238a714de5 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 7 Oct 2014 18:48:12 +0200 Subject: netfilter: kill nf_send_reset6() from include/net/netfilter/ipv6/nf_reject.h nf_send_reset6() now resides in net/ipv6/netfilter/nf_reject_ipv6.c Fixes: c8d7b98 ("netfilter: move nf_send_resetX() code to nf_reject_ipvX modules") Reported-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso Acked-by: Eric Dumazet --- include/net/netfilter/ipv6/nf_reject.h | 157 +-------------------------------- 1 file changed, 2 insertions(+), 155 deletions(-) diff --git a/include/net/netfilter/ipv6/nf_reject.h b/include/net/netfilter/ipv6/nf_reject.h index 7a10cfcd8e33..48e18810a9be 100644 --- a/include/net/netfilter/ipv6/nf_reject.h +++ b/include/net/netfilter/ipv6/nf_reject.h @@ -1,11 +1,7 @@ #ifndef _IPV6_NF_REJECT_H #define _IPV6_NF_REJECT_H -#include -#include -#include -#include -#include +#include static inline void nf_send_unreach6(struct net *net, struct sk_buff *skb_in, unsigned char code, @@ -17,155 +13,6 @@ nf_send_unreach6(struct net *net, struct sk_buff *skb_in, unsigned char code, icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); } -/* Send RST reply */ -static void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook) -{ - struct sk_buff *nskb; - struct tcphdr otcph, *tcph; - unsigned int otcplen, hh_len; - int tcphoff, needs_ack; - const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); - struct ipv6hdr *ip6h; -#define DEFAULT_TOS_VALUE 0x0U - const __u8 tclass = DEFAULT_TOS_VALUE; - struct dst_entry *dst = NULL; - u8 proto; - __be16 frag_off; - struct flowi6 fl6; - - if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) || - (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) { - pr_debug("addr is not unicast.\n"); - return; - } - - proto = oip6h->nexthdr; - tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off); - - if ((tcphoff < 0) || (tcphoff > oldskb->len)) { - pr_debug("Cannot get TCP header.\n"); - return; - } - - otcplen = oldskb->len - tcphoff; - - /* IP header checks: fragment, too short. */ - if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) { - pr_debug("proto(%d) != IPPROTO_TCP, " - "or too short. otcplen = %d\n", - proto, otcplen); - return; - } - - if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr))) - BUG(); - - /* No RST for RST. */ - if (otcph.rst) { - pr_debug("RST is set\n"); - return; - } - - /* Check checksum. */ - if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) { - pr_debug("TCP checksum is invalid\n"); - return; - } - - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_proto = IPPROTO_TCP; - fl6.saddr = oip6h->daddr; - fl6.daddr = oip6h->saddr; - fl6.fl6_sport = otcph.dest; - fl6.fl6_dport = otcph.source; - security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6)); - dst = ip6_route_output(net, NULL, &fl6); - if (dst == NULL || dst->error) { - dst_release(dst); - return; - } - dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); - if (IS_ERR(dst)) - return; - - hh_len = (dst->dev->hard_header_len + 15)&~15; - nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr) - + sizeof(struct tcphdr) + dst->trailer_len, - GFP_ATOMIC); - - if (!nskb) { - net_dbg_ratelimited("cannot alloc skb\n"); - dst_release(dst); - return; - } - - skb_dst_set(nskb, dst); - - skb_reserve(nskb, hh_len + dst->header_len); - - skb_put(nskb, sizeof(struct ipv6hdr)); - skb_reset_network_header(nskb); - ip6h = ipv6_hdr(nskb); - ip6_flow_hdr(ip6h, tclass, 0); - ip6h->hop_limit = ip6_dst_hoplimit(dst); - ip6h->nexthdr = IPPROTO_TCP; - ip6h->saddr = oip6h->daddr; - ip6h->daddr = oip6h->saddr; - - skb_reset_transport_header(nskb); - tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); - /* Truncate to length (no data) */ - tcph->doff = sizeof(struct tcphdr)/4; - tcph->source = otcph.dest; - tcph->dest = otcph.source; - - if (otcph.ack) { - needs_ack = 0; - tcph->seq = otcph.ack_seq; - tcph->ack_seq = 0; - } else { - needs_ack = 1; - tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin - + otcplen - (otcph.doff<<2)); - tcph->seq = 0; - } - - /* Reset flags */ - ((u_int8_t *)tcph)[13] = 0; - tcph->rst = 1; - tcph->ack = needs_ack; - tcph->window = 0; - tcph->urg_ptr = 0; - tcph->check = 0; - - /* Adjust TCP checksum */ - tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr, - &ipv6_hdr(nskb)->daddr, - sizeof(struct tcphdr), IPPROTO_TCP, - csum_partial(tcph, - sizeof(struct tcphdr), 0)); - - nf_ct_attach(nskb, oldskb); - -#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) - /* If we use ip6_local_out for bridged traffic, the MAC source on - * the RST will be ours, instead of the destination's. This confuses - * some routers/firewalls, and they drop the packet. So we need to - * build the eth header using the original destination's MAC as the - * source, and send the RST packet directly. - */ - if (oldskb->nf_bridge) { - struct ethhdr *oeth = eth_hdr(oldskb); - nskb->dev = oldskb->nf_bridge->physindev; - nskb->protocol = htons(ETH_P_IPV6); - ip6h->payload_len = htons(sizeof(struct tcphdr)); - if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), - oeth->h_source, oeth->h_dest, nskb->len) < 0) - return; - dev_queue_xmit(nskb); - } else -#endif - ip6_local_out(nskb); -} +void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook); #endif /* _IPV6_NF_REJECT_H */ -- cgit v1.2.3 From f0d1f04f0a2f662b6b617e24d115fddcf6ef8723 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 7 Oct 2014 19:02:11 +0200 Subject: netfilter: fix wrong arithmetics regarding NFT_REJECT_ICMPX_MAX NFT_REJECT_ICMPX_MAX should be __NFT_REJECT_ICMPX_MAX - 1. nft_reject_icmp_code() and nft_reject_icmpv6_code() are called from the packet path, so BUG_ON in case we try to access an unknown abstracted ICMP code. This should not happen since we already validate this from nft_reject_{inet,bridge}_init(). Fixes: 51b0a5d ("netfilter: nft_reject: introduce icmp code abstraction for inet and bridge") Reported-by: Dan Carpenter Signed-off-by: Pablo Neira Ayuso --- include/uapi/linux/netfilter/nf_tables.h | 2 +- net/netfilter/nft_reject.c | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index c26df6787fb0..f31fe7b660a5 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -774,7 +774,7 @@ enum nft_reject_inet_code { NFT_REJECT_ICMPX_ADMIN_PROHIBITED, __NFT_REJECT_ICMPX_MAX }; -#define NFT_REJECT_ICMPX_MAX (__NFT_REJECT_ICMPX_MAX + 1) +#define NFT_REJECT_ICMPX_MAX (__NFT_REJECT_ICMPX_MAX - 1) /** * enum nft_reject_attributes - nf_tables reject expression netlink attributes diff --git a/net/netfilter/nft_reject.c b/net/netfilter/nft_reject.c index ec8a456092a7..57d3e1af5630 100644 --- a/net/netfilter/nft_reject.c +++ b/net/netfilter/nft_reject.c @@ -72,7 +72,7 @@ nla_put_failure: } EXPORT_SYMBOL_GPL(nft_reject_dump); -static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX] = { +static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX + 1] = { [NFT_REJECT_ICMPX_NO_ROUTE] = ICMP_NET_UNREACH, [NFT_REJECT_ICMPX_PORT_UNREACH] = ICMP_PORT_UNREACH, [NFT_REJECT_ICMPX_HOST_UNREACH] = ICMP_HOST_UNREACH, @@ -81,8 +81,7 @@ static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX] = { int nft_reject_icmp_code(u8 code) { - if (code > NFT_REJECT_ICMPX_MAX) - return -EINVAL; + BUG_ON(code > NFT_REJECT_ICMPX_MAX); return icmp_code_v4[code]; } @@ -90,7 +89,7 @@ int nft_reject_icmp_code(u8 code) EXPORT_SYMBOL_GPL(nft_reject_icmp_code); -static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX] = { +static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX + 1] = { [NFT_REJECT_ICMPX_NO_ROUTE] = ICMPV6_NOROUTE, [NFT_REJECT_ICMPX_PORT_UNREACH] = ICMPV6_PORT_UNREACH, [NFT_REJECT_ICMPX_HOST_UNREACH] = ICMPV6_ADDR_UNREACH, @@ -99,8 +98,7 @@ static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX] = { int nft_reject_icmpv6_code(u8 code) { - if (code > NFT_REJECT_ICMPX_MAX) - return -EINVAL; + BUG_ON(code > NFT_REJECT_ICMPX_MAX); return icmp_code_v6[code]; } -- cgit v1.2.3 From 79ee65659e116a49c81f63480a7672b7cbafa323 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Mon, 6 Oct 2014 20:23:55 +0200 Subject: rtl818x_pci: fix response rate may be incorrect. Currently the allowed "respose rate" set (rates for HW generated frames like ACKs) is the same as the basic rate set. The HW will use the higher allowed response rate that is lower than the rate of the received frame. This is more or less what IEEE80211 mandates, but I missed the fact that IEEE80211 also says that whenever it happens that for a modulation class there is no any rate in the basic rates set, then the response rate set shall include also all the mandatory rates for that modulation class. This patch adds mandatory OFDM rates to the allowed response rate set if no OFDM rate is included in the basic rate set. Depending by the AP, I faced cases in which this patch seems to cause a noticeable perfomance improvement. - With my usual test AP there is no particular perfomance difference. - With a prism54/hostapd AP this patch causes RX thoughput increase from about 5Mbps to about 20Mbps. Hopefully this patch may help people that faced performance regression wrt the old staging driver. Signed-off-by: Andrea Merello Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8180/dev.c | 36 +++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index ded967aa6ecb..706b844bce00 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -742,35 +742,49 @@ static void rtl8180_int_disable(struct ieee80211_hw *dev) } static void rtl8180_conf_basic_rates(struct ieee80211_hw *dev, - u32 rates_mask) + u32 basic_mask) { struct rtl8180_priv *priv = dev->priv; - - u8 max, min; u16 reg; - - max = fls(rates_mask) - 1; - min = ffs(rates_mask) - 1; + u32 resp_mask; + u8 basic_max; + u8 resp_max, resp_min; + + resp_mask = basic_mask; + /* IEEE80211 says the response rate should be equal to the highest basic + * rate that is not faster than received frame. But it says also that if + * the basic rate set does not contains any rate for the current + * modulation class then mandatory rate set must be used for that + * modulation class. Eventually add OFDM mandatory rates.. + */ + if ((resp_mask & 0xf) == resp_mask) + resp_mask |= 0x150; /* 6, 12, 24Mbps */ switch (priv->chip_family) { case RTL818X_CHIP_FAMILY_RTL8180: /* in 8180 this is NOT a BITMAP */ + basic_max = fls(basic_mask) - 1; reg = rtl818x_ioread16(priv, &priv->map->BRSR); reg &= ~3; - reg |= max; + reg |= basic_max; rtl818x_iowrite16(priv, &priv->map->BRSR, reg); break; case RTL818X_CHIP_FAMILY_RTL8185: + resp_max = fls(resp_mask) - 1; + resp_min = ffs(resp_mask) - 1; /* in 8185 this is a BITMAP */ - rtl818x_iowrite16(priv, &priv->map->BRSR, rates_mask); - rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (max << 4) | min); + rtl818x_iowrite16(priv, &priv->map->BRSR, basic_mask); + rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (resp_max << 4) | + resp_min); break; case RTL818X_CHIP_FAMILY_RTL8187SE: - /* in 8187se this is a BITMAP */ - rtl818x_iowrite16(priv, &priv->map->BRSR_8187SE, rates_mask); + /* in 8187se this is a BITMAP. BRSR reg actually sets + * response rates. + */ + rtl818x_iowrite16(priv, &priv->map->BRSR_8187SE, resp_mask); break; } } -- cgit v1.2.3 From d2a993e20e717a4ccbfa9a58b29362e4446208a0 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 7 Oct 2014 10:14:36 +0530 Subject: ath: Fix smatch warning drivers/net/wireless/ath/main.c:88 ath_printk() error: we previously assumed 'common->hw' could be null (see line 82) Reported-by: Dan Carpenter Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c index 83f47af19280..338d72337604 100644 --- a/drivers/net/wireless/ath/main.c +++ b/drivers/net/wireless/ath/main.c @@ -79,13 +79,13 @@ void ath_printk(const char *level, const struct ath_common* common, vaf.fmt = fmt; vaf.va = &args; - if (common && common->hw && common->hw->wiphy) + if (common && common->hw && common->hw->wiphy) { printk("%sath: %s: %pV", level, wiphy_name(common->hw->wiphy), &vaf); - else + trace_ath_log(common->hw->wiphy, &vaf); + } else { printk("%sath: %pV", level, &vaf); - - trace_ath_log(common->hw->wiphy, &vaf); + } va_end(args); } -- cgit v1.2.3 From b18111d911980af52bead74ee45250cc96ad5108 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 7 Oct 2014 10:14:37 +0530 Subject: ath9k: Fix crash in MCC mode When a channel context is removed, the hw_queue_base is set to -1, this will result in a panic because ath9k_chanctx_stop_queues() can be called on an interface that is not assigned to any context yet - for example, when trying to scan. Fix this issue by setting the hw_queue_base to zero when a channel context is removed. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 205162449b72..6f6a974f7fdb 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2332,7 +2332,7 @@ static void ath9k_remove_chanctx(struct ieee80211_hw *hw, conf->def.chan->center_freq); ctx->assigned = false; - ctx->hw_queue_base = -1; + ctx->hw_queue_base = 0; ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN); mutex_unlock(&sc->mutex); -- cgit v1.2.3 From c393d179924685d5c8c72446c5b6401f25fdb2a0 Mon Sep 17 00:00:00 2001 From: Marek Puzyniak Date: Tue, 7 Oct 2014 17:04:30 +0200 Subject: ath9k_htc: avoid kernel panic in ath9k_hw_reset hw pointer of ath_hw is not assigned to proper value in function ath9k_hw_reset what finally causes kernel panic. This can be solved by proper initialization of ath_hw in ath9k_init_priv. Signed-off-by: Marek Puzyniak Acked-by: Oleksij Rempel Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index d779f4fa50e3..4014c4be6e79 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -464,6 +464,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, return -ENOMEM; ah->dev = priv->dev; + ah->hw = priv->hw; ah->hw_version.devid = devid; ah->hw_version.usbdev = drv_info; ah->ah_flags |= AH_USE_EEPROM; -- cgit v1.2.3 From 2f29fed3f814f652a24b10c975b9d415a154fc9c Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 7 Oct 2014 22:20:23 +0200 Subject: net: rfkill: kernel-doc warning fixes s/state/blocked Signed-off-by: Fabian Frederick Signed-off-by: John W. Linville --- net/rfkill/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/rfkill/core.c b/net/rfkill/core.c index b3b16c070a7f..fa7cd792791c 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -329,7 +329,7 @@ static atomic_t rfkill_input_disabled = ATOMIC_INIT(0); /** * __rfkill_switch_all - Toggle state of all switches of given type * @type: type of interfaces to be affected - * @state: the new state + * @blocked: the new state * * This function sets the state of all switches of given type, * unless a specific switch is claimed by userspace (in which case, @@ -353,7 +353,7 @@ static void __rfkill_switch_all(const enum rfkill_type type, bool blocked) /** * rfkill_switch_all - Toggle state of all switches of given type * @type: type of interfaces to be affected - * @state: the new state + * @blocked: the new state * * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). * Please refer to __rfkill_switch_all() for details. -- cgit v1.2.3 From ca14405e3b25b38221d027d8970c1d74ed0b6532 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 8 Oct 2014 08:43:19 +0530 Subject: ath9k: Fix sequence number assignment Currently, ath9k uses a global counter for all frames that need to be assigned a sequence number. QoS-data frames are handled properly since they have a per-tid counter. But, beacons and other management frames use the same counter even if multiple interfaces or contexts are present. Fix this issue by making the counter per-interface and using it when mac80211 sets IEEE80211_TX_CTL_ASSIGN_SEQ. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 +++- drivers/net/wireless/ath/ath9k/beacon.c | 12 ++---------- drivers/net/wireless/ath/ath9k/tx99.c | 8 +++++++- drivers/net/wireless/ath/ath9k/xmit.c | 34 ++++++++++++++++++++++----------- 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index bfa0b1518da1..01a7db061c6a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -294,7 +294,6 @@ struct ath_tx_control { * (axq_qnum). */ struct ath_tx { - u16 seq_no; u32 txqsetup; spinlock_t txbuflock; struct list_head txbuf; @@ -563,6 +562,7 @@ 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); void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop); +void ath_assign_seq(struct ath_common *common, struct sk_buff *skb); int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_tx_control *txctl); void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -592,6 +592,8 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, struct ath_vif { struct list_head list; + u16 seq_no; + /* BSS info */ u8 bssid[ETH_ALEN]; u16 aid; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index a6af855ef6ed..ecb783beeec2 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -144,16 +144,8 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust; info = IEEE80211_SKB_CB(skb); - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - /* - * TODO: make sure the seq# gets assigned properly (vs. other - * TX frames) - */ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - sc->tx.seq_no += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); - } + + ath_assign_seq(common, skb); if (vif->p2p) ath9k_beacon_add_noa(sc, avp, skb); diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index 8a69d08ec55c..40ab65e6882f 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -54,6 +54,12 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info; struct sk_buff *skb; + struct ath_vif *avp; + + if (!sc->tx99_vif) + return NULL; + + avp = (struct ath_vif *)sc->tx99_vif->drv_priv; skb = alloc_skb(len, GFP_KERNEL); if (!skb) @@ -71,7 +77,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); + hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); tx_info = IEEE80211_SKB_CB(skb); memset(tx_info, 0, sizeof(*tx_info)); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 151ae49fa57e..493a183d0aaf 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2139,6 +2139,28 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, return bf; } +void ath_assign_seq(struct ath_common *common, 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 ath_vif *avp; + + if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) + return; + + if (!vif) + return; + + avp = (struct ath_vif *)vif->drv_priv; + + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + avp->seq_no += 0x10; + + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); +} + static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_tx_control *txctl) { @@ -2162,17 +2184,7 @@ static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, if (info->control.hw_key) frmlen += info->control.hw_key->icv_len; - /* - * As a temporary workaround, assign seq# here; this will likely need - * to be cleaned up to work better with Beacon transmission and virtual - * BSSes. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - sc->tx.seq_no += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); - } + ath_assign_seq(ath9k_hw_common(sc->sc_ah), skb); if ((vif && vif->type != NL80211_IFTYPE_AP && vif->type != NL80211_IFTYPE_AP_VLAN) || -- cgit v1.2.3 From 1fca350b761631d182c2e8bce530896e66404bc2 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 8 Oct 2014 12:44:55 -0500 Subject: rtlwifi: Fix possible unaligned array in ether_addr_copy() Two macros used to copy BSSID information use ether_addr_copy(), thus the arrays must be 2-byte aligned. In one case, the array could become unaligned if the struct containing it were changed. Use the __unaligned(2) attribute to retain the necessary alignment. In addition, the magic number used to specify the size of the array is replaced by ETH_ALEN. Signed-off-by: Larry Finger Acked-by: David S. Miller Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/wifi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 976667ae8549..6866dcf24340 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1370,7 +1370,7 @@ struct rtl_mac { bool rdg_en; /*AP*/ - u8 bssid[6]; + u8 bssid[ETH_ALEN] __aligned(2); u32 vendor; u8 mcs[16]; /* 16 bytes mcs for HT rates. */ u32 basic_rates; /* b/g rates */ -- cgit v1.2.3 From 59f35b810e3bb17efef2aa5feadffb66450190d9 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 7 Oct 2014 22:31:32 +0200 Subject: netlabel: kernel-doc warning fix no secid argument in netlbl_cfg_unlbl_static_del 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 0b4692dd1c5e..a845cd4cf21e 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -246,7 +246,6 @@ int netlbl_cfg_unlbl_static_add(struct net *net, * @addr: IP address in network byte order (struct in[6]_addr) * @mask: address mask in network byte order (struct in[6]_addr) * @family: address family - * @secid: LSM secid value for the entry * @audit_info: NetLabel audit information * * Description: -- cgit v1.2.3 From 9a4cbd53b80862c1e57ed20d30468770699b776e Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 7 Oct 2014 10:44:28 +0300 Subject: net/fsl_pq_mdio: Fix asm/ucc.h compile error for ARM The UCC specific code included in fsl_pq_mdio.c (with function calls from asm/ucc.h) is already guarded by these config options, so this ARM build fix only provides consistency with the rest UCC specific code. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fsl_pq_mdio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c index 583e71ab7f51..32136f08515e 100644 --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c @@ -28,7 +28,9 @@ #include #include +#if IS_ENABLED(CONFIG_UCC_GETH) #include /* for ucc_set_qe_mux_mii_mng() */ +#endif #include "gianfar.h" -- cgit v1.2.3 From f5bbd262e70ff2355ce4284b0ad9eaf93fb5e374 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 7 Oct 2014 10:44:29 +0300 Subject: net/fsl_pq_mdio: Use ioread/iowrite32be() portable accessors in_be32()/out_be32() are not defined by ARM. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fsl_pq_mdio.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c index 32136f08515e..a422838b4f1d 100644 --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c @@ -107,14 +107,14 @@ static int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u32 status; /* Set the PHY address and the register address we want to write */ - out_be32(®s->miimadd, (mii_id << 8) | regnum); + iowrite32be((mii_id << 8) | regnum, ®s->miimadd); /* Write out the value we want */ - out_be32(®s->miimcon, value); + iowrite32be(value, ®s->miimcon); /* Wait for the transaction to finish */ - status = spin_event_timeout(!(in_be32(®s->miimind) & MIIMIND_BUSY), - MII_TIMEOUT, 0); + status = spin_event_timeout(!(ioread32be(®s->miimind) & + MIIMIND_BUSY), MII_TIMEOUT, 0); return status ? 0 : -ETIMEDOUT; } @@ -137,21 +137,21 @@ static int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum) u16 value; /* Set the PHY address and the register address we want to read */ - out_be32(®s->miimadd, (mii_id << 8) | regnum); + iowrite32be((mii_id << 8) | regnum, ®s->miimadd); /* Clear miimcom, and then initiate a read */ - out_be32(®s->miimcom, 0); - out_be32(®s->miimcom, MII_READ_COMMAND); + iowrite32be(0, ®s->miimcom); + iowrite32be(MII_READ_COMMAND, ®s->miimcom); /* Wait for the transaction to finish, normally less than 100us */ - status = spin_event_timeout(!(in_be32(®s->miimind) & + status = spin_event_timeout(!(ioread32be(®s->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)), MII_TIMEOUT, 0); if (!status) return -ETIMEDOUT; /* Grab the value of the register from miimstat */ - value = in_be32(®s->miimstat); + value = ioread32be(®s->miimstat); dev_dbg(&bus->dev, "read %04x from address %x/%x\n", value, mii_id, regnum); return value; @@ -167,14 +167,14 @@ static int fsl_pq_mdio_reset(struct mii_bus *bus) mutex_lock(&bus->mdio_lock); /* Reset the management interface */ - out_be32(®s->miimcfg, MIIMCFG_RESET); + iowrite32be(MIIMCFG_RESET, ®s->miimcfg); /* Setup the MII Mgmt clock speed */ - out_be32(®s->miimcfg, MIIMCFG_INIT_VALUE); + iowrite32be(MIIMCFG_INIT_VALUE, ®s->miimcfg); /* Wait until the bus is free */ - status = spin_event_timeout(!(in_be32(®s->miimind) & MIIMIND_BUSY), - MII_TIMEOUT, 0); + status = spin_event_timeout(!(ioread32be(®s->miimind) & + MIIMIND_BUSY), MII_TIMEOUT, 0); mutex_unlock(&bus->mdio_lock); @@ -435,7 +435,7 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev) tbipa = data->get_tbipa(priv->map); - out_be32(tbipa, be32_to_cpup(prop)); + iowrite32be(be32_to_cpup(prop), tbipa); } } -- cgit v1.2.3 From e4b081f543030fc0b23d2cd7d1f6e3ac69d7f47f Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 7 Oct 2014 10:44:30 +0300 Subject: net/fsl_pq_mdio: Replace spin_event_timeout() with arch independent spin_event_timeout() is PPC dependent, use an arch independent equivalent instead. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fsl_pq_mdio.c | 36 ++++++++++++++++++---------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c index a422838b4f1d..964c6bf37710 100644 --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c @@ -104,7 +104,7 @@ static int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, { struct fsl_pq_mdio_priv *priv = bus->priv; struct fsl_pq_mii __iomem *regs = priv->regs; - u32 status; + unsigned int timeout; /* Set the PHY address and the register address we want to write */ iowrite32be((mii_id << 8) | regnum, ®s->miimadd); @@ -113,10 +113,13 @@ static int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, iowrite32be(value, ®s->miimcon); /* Wait for the transaction to finish */ - status = spin_event_timeout(!(ioread32be(®s->miimind) & - MIIMIND_BUSY), MII_TIMEOUT, 0); + timeout = MII_TIMEOUT; + while ((ioread32be(®s->miimind) & MIIMIND_BUSY) && timeout) { + cpu_relax(); + timeout--; + } - return status ? 0 : -ETIMEDOUT; + return timeout ? 0 : -ETIMEDOUT; } /* @@ -133,7 +136,7 @@ static int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum) { struct fsl_pq_mdio_priv *priv = bus->priv; struct fsl_pq_mii __iomem *regs = priv->regs; - u32 status; + unsigned int timeout; u16 value; /* Set the PHY address and the register address we want to read */ @@ -144,10 +147,14 @@ static int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum) iowrite32be(MII_READ_COMMAND, ®s->miimcom); /* Wait for the transaction to finish, normally less than 100us */ - status = spin_event_timeout(!(ioread32be(®s->miimind) & - (MIIMIND_NOTVALID | MIIMIND_BUSY)), - MII_TIMEOUT, 0); - if (!status) + timeout = MII_TIMEOUT; + while ((ioread32be(®s->miimind) & + (MIIMIND_NOTVALID | MIIMIND_BUSY)) && timeout) { + cpu_relax(); + timeout--; + } + + if (!timeout) return -ETIMEDOUT; /* Grab the value of the register from miimstat */ @@ -162,7 +169,7 @@ static int fsl_pq_mdio_reset(struct mii_bus *bus) { struct fsl_pq_mdio_priv *priv = bus->priv; struct fsl_pq_mii __iomem *regs = priv->regs; - u32 status; + unsigned int timeout; mutex_lock(&bus->mdio_lock); @@ -173,12 +180,15 @@ static int fsl_pq_mdio_reset(struct mii_bus *bus) iowrite32be(MIIMCFG_INIT_VALUE, ®s->miimcfg); /* Wait until the bus is free */ - status = spin_event_timeout(!(ioread32be(®s->miimind) & - MIIMIND_BUSY), MII_TIMEOUT, 0); + timeout = MII_TIMEOUT; + while ((ioread32be(®s->miimind) & MIIMIND_BUSY) && timeout) { + cpu_relax(); + timeout--; + } mutex_unlock(&bus->mdio_lock); - if (!status) { + if (!timeout) { dev_err(&bus->dev, "timeout waiting for MII bus\n"); return -EBUSY; } -- cgit v1.2.3 From fd31a9528800b52c7a56a9cfa0af30b44dcfb0c9 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 7 Oct 2014 10:44:31 +0300 Subject: gianfar: Include missing headers for ARM builds Include linux/of_address.h for of_iomap() and linux/of_irq.h for irq_of_parse_and_map(). This wasn't an issue for PPC, because these were implicitly included from asm/prom.h (via linux/of.h) for PPC builds only. ARM builds need these includes explicitly. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index fb29d049f4e1..a488105ec51d 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -100,6 +100,8 @@ #include #include #include +#include +#include #include "gianfar.h" -- cgit v1.2.3 From d6ef0bcce386531f250a8abee3c3595214ea1629 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 7 Oct 2014 10:44:32 +0300 Subject: gianfar: Exclude PPC specific errata handling from ARM builds This excludes the PPC specific instructions for PPC based SoC (MPC85xx family) version identification from ARM builds. The PPC specific macro mfspr() from asm/reg.h is not defined by the ARM architecture. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index a488105ec51d..37e060478630 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -88,8 +88,10 @@ #include #include +#ifdef CONFIG_PPC #include #include +#endif #include #include #include @@ -1063,6 +1065,7 @@ static void gfar_init_filer_table(struct gfar_private *priv) } } +#ifdef CONFIG_PPC static void __gfar_detect_errata_83xx(struct gfar_private *priv) { unsigned int pvr = mfspr(SPRN_PVR); @@ -1095,6 +1098,7 @@ static void __gfar_detect_errata_85xx(struct gfar_private *priv) ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20))) priv->errata |= GFAR_ERRATA_76; /* aka eTSEC 20 */ } +#endif static void gfar_detect_errata(struct gfar_private *priv) { @@ -1103,10 +1107,12 @@ static void gfar_detect_errata(struct gfar_private *priv) /* no plans to fix */ priv->errata |= GFAR_ERRATA_A002; +#ifdef CONFIG_PPC if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2)) __gfar_detect_errata_85xx(priv); else /* non-mpc85xx parts, i.e. e300 core based */ __gfar_detect_errata_83xx(priv); +#endif if (priv->errata) dev_info(dev, "enabled errata workarounds, flags: 0x%x\n", -- cgit v1.2.3 From 83bfc3c4765c35ef0dfff8a3d6dedab88f3f50ea Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 7 Oct 2014 10:44:33 +0300 Subject: gianfar: Make MAC addr setup endian safe, cleanup Fix the 32-bit memory access that is not endian safe, i.e. not giving the desired byte layout for a LE CPU: tempval = *((u32 *) (tmpbuf + 4)), where 'char tmpbuf[]'. Get rid of rendundant local vars (tmpbuf[] and idx) and forced casts. Cleanup comments. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 37e060478630..961198a2bfa8 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -3248,22 +3248,21 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num, { struct gfar_private *priv = netdev_priv(dev); struct gfar __iomem *regs = priv->gfargrp[0].regs; - int idx; - char tmpbuf[ETH_ALEN]; u32 tempval; u32 __iomem *macptr = ®s->macstnaddr1; macptr += num*2; - /* Now copy it into the mac registers backwards, cuz - * little endian is silly + /* For a station address of 0x12345678ABCD in transmission + * order (BE), MACnADDR1 is set to 0xCDAB7856 and + * MACnADDR2 is set to 0x34120000. */ - for (idx = 0; idx < ETH_ALEN; idx++) - tmpbuf[ETH_ALEN - 1 - idx] = addr[idx]; + tempval = (addr[5] << 24) | (addr[4] << 16) | + (addr[3] << 8) | addr[2]; - gfar_write(macptr, *((u32 *) (tmpbuf))); + gfar_write(macptr, tempval); - tempval = *((u32 *) (tmpbuf + 4)); + tempval = (addr[1] << 24) | (addr[0] << 16); gfar_write(macptr+1, tempval); } -- cgit v1.2.3 From a4feee89ce4590c7a4aead49ca5a4853dc6ea5dc Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 7 Oct 2014 10:44:34 +0300 Subject: gianfar: Replace spin_event_timeout() with arch independent Use arch independent code to replace the powerpc dependent spin_event_timeout() from gfar_halt_nodisable(). Added GRS/GTS read accessors to clean-up the implementation of gfar_halt_nodisable(). Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 32 +++++++++++++++++++------------- drivers/net/ethernet/freescale/gianfar.h | 15 +++++++++++++++ 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 961198a2bfa8..356a9982d014 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1762,26 +1762,32 @@ static void gfar_halt_nodisable(struct gfar_private *priv) { struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; + unsigned int timeout; + int stopped; gfar_ints_disable(priv); + if (gfar_is_dma_stopped(priv)) + return; + /* Stop the DMA, and wait for it to stop */ tempval = gfar_read(®s->dmactrl); - if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) != - (DMACTRL_GRS | DMACTRL_GTS)) { - int ret; - - tempval |= (DMACTRL_GRS | DMACTRL_GTS); - gfar_write(®s->dmactrl, tempval); + tempval |= (DMACTRL_GRS | DMACTRL_GTS); + gfar_write(®s->dmactrl, tempval); - do { - ret = spin_event_timeout(((gfar_read(®s->ievent) & - (IEVENT_GRSC | IEVENT_GTSC)) == - (IEVENT_GRSC | IEVENT_GTSC)), 1000000, 0); - if (!ret && !(gfar_read(®s->ievent) & IEVENT_GRSC)) - ret = __gfar_is_rx_idle(priv); - } while (!ret); +retry: + timeout = 1000; + while (!(stopped = gfar_is_dma_stopped(priv)) && timeout) { + cpu_relax(); + timeout--; } + + if (!timeout) + stopped = gfar_is_dma_stopped(priv); + + if (!stopped && !gfar_is_rx_dma_stopped(priv) && + !__gfar_is_rx_idle(priv)) + goto retry; } /* Halt the receive and transmit queues */ diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 84632c569f2c..0b3772217a9a 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -1226,6 +1226,21 @@ static inline void gfar_write_isrg(struct gfar_private *priv) } } +static inline int gfar_is_dma_stopped(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + + return ((gfar_read(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC)) == + (IEVENT_GRSC | IEVENT_GTSC)); +} + +static inline int gfar_is_rx_dma_stopped(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + + return gfar_read(®s->ievent) & IEVENT_GRSC; +} + irqreturn_t gfar_receive(int irq, void *dev_id); int startup_gfar(struct net_device *dev); void stop_gfar(struct net_device *dev); -- cgit v1.2.3 From d55398ba81139bc826a8c2417a01280e99f08cf3 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 7 Oct 2014 10:44:35 +0300 Subject: gianfar: Replace eieio with wmb for non-PPC archs Replace PPC specific eieio() with arch independent wmb() for other architectures, i.e. ARM. The eieio() macro is not defined on ARM and generates build error. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 13 +++---------- drivers/net/ethernet/freescale/gianfar.h | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 356a9982d014..379b1a578d3d 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -165,7 +165,7 @@ static void gfar_init_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp, if (bdp == rx_queue->rx_bd_base + rx_queue->rx_ring_size - 1) lstatus |= BD_LFLAG(RXBD_WRAP); - eieio(); + gfar_wmb(); bdp->lstatus = lstatus; } @@ -2371,18 +2371,11 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) */ spin_lock_irqsave(&tx_queue->txlock, flags); - /* The powerpc-specific eieio() is used, as wmb() has too strong - * semantics (it requires synchronization between cacheable and - * uncacheable mappings, which eieio doesn't provide and which we - * don't need), thus requiring a more expensive sync instruction. At - * some point, the set of architecture-independent barrier functions - * should be expanded to include weaker barriers. - */ - eieio(); + gfar_wmb(); txbdp_start->lstatus = lstatus; - eieio(); /* force lstatus write before tx_skbuff */ + gfar_wmb(); /* force lstatus write before tx_skbuff */ tx_queue->tx_skbuff[tx_queue->skb_curtx] = skb; diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 0b3772217a9a..2805cfbf1765 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -1241,6 +1241,22 @@ static inline int gfar_is_rx_dma_stopped(struct gfar_private *priv) return gfar_read(®s->ievent) & IEVENT_GRSC; } +static inline void gfar_wmb(void) +{ +#if defined(CONFIG_PPC) + /* The powerpc-specific eieio() is used, as wmb() has too strong + * semantics (it requires synchronization between cacheable and + * uncacheable mappings, which eieio() doesn't provide and which we + * don't need), thus requiring a more expensive sync instruction. At + * some point, the set of architecture-independent barrier functions + * should be expanded to include weaker barriers. + */ + eieio(); +#else + wmb(); /* order write acesses for BD (or FCB) fields */ +#endif +} + irqreturn_t gfar_receive(int irq, void *dev_id); int startup_gfar(struct net_device *dev); void stop_gfar(struct net_device *dev); -- cgit v1.2.3 From 7207c0d1540b679993d1f0bb9c1ff8e068958c75 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 9 Oct 2014 05:48:45 +0530 Subject: cxgb4/cxgb4vf: Updated the LSO transfer length in CPL_TX_PKT_LSO for T5 Update the lso length for T5 adapter and fix PIDX_T5 macro Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/sge.c | 5 ++++- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 1 + drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 5 ++--- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 5 ++++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index fab4c84a1da4..5e1b314e11af 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -1123,7 +1123,10 @@ out_free: dev_kfree_skb_any(skb); lso->c.ipid_ofst = htons(0); lso->c.mss = htons(ssi->gso_size); lso->c.seqno_offset = htonl(0); - lso->c.len = htonl(skb->len); + if (is_t4(adap->params.chip)) + lso->c.len = htonl(skb->len); + else + lso->c.len = htonl(LSO_T5_XFER_SIZE(skb->len)); cpl = (void *)(lso + 1); cntrl = TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) | TXPKT_IPHDR_LEN(l3hdr_len) | diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index 52e08103f221..5f4db2398c71 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -527,6 +527,7 @@ struct cpl_tx_pkt_lso_core { #define LSO_LAST_SLICE (1 << 22) #define LSO_FIRST_SLICE (1 << 23) #define LSO_OPCODE(x) ((x) << 24) +#define LSO_T5_XFER_SIZE(x) ((x) << 0) __be16 ipid_ofst; __be16 mss; __be32 seqno_offset; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index eee272883027..a1024db5dc13 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -72,9 +72,8 @@ #define PIDX_MASK 0x00003fffU #define PIDX_SHIFT 0 #define PIDX(x) ((x) << PIDX_SHIFT) -#define S_PIDX_T5 0 -#define M_PIDX_T5 0x1fffU -#define PIDX_T5(x) (((x) >> S_PIDX_T5) & M_PIDX_T5) +#define PIDX_SHIFT_T5 0 +#define PIDX_T5(x) ((x) << PIDX_SHIFT_T5) #define SGE_TIMERREGS 6 diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index a5fb9493dee8..85036e6b42c4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -1208,7 +1208,10 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev) lso->ipid_ofst = cpu_to_be16(0); lso->mss = cpu_to_be16(ssi->gso_size); lso->seqno_offset = cpu_to_be32(0); - lso->len = cpu_to_be32(skb->len); + if (is_t4(adapter->params.chip)) + lso->len = cpu_to_be32(skb->len); + else + lso->len = cpu_to_be32(LSO_T5_XFER_SIZE(skb->len)); /* * Set up TX Packet CPL pointer, control word and perform -- cgit v1.2.3 From 897d55df3ca794ad4522472d46aa2dbbface8c37 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 9 Oct 2014 05:48:46 +0530 Subject: cxgb4vf: Add 40G support for cxgb4vf driver Add 40G support for cxgb4vf driver. ethtool speed values are just numbers of megabits and there is no SPEED_40000 in ethtool speed values. To be consistent, use integer constants directly for all speeds. Use is_x_10g_port()("is 10Gb/s or higher") in cfg_queues() instead of is_10g_port() ("is exactly 10Gb/s"). Else we will end up using a single "Queue Set" on 40Gb/s adapters. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 12 ++++++++---- drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h | 6 ++++++ drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c | 10 +++++++--- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index 8498a641b2e3..bfa398d91826 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -163,15 +163,19 @@ void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok) netif_carrier_on(dev); switch (pi->link_cfg.speed) { - case SPEED_10000: + case 40000: + s = "40Gbps"; + break; + + case 10000: s = "10Gbps"; break; - case SPEED_1000: + case 1000: s = "1000Mbps"; break; - case SPEED_100: + case 100: s = "100Mbps"; break; @@ -2351,7 +2355,7 @@ static void cfg_queues(struct adapter *adapter) struct port_info *pi = adap2pinfo(adapter, pidx); pi->first_qset = qidx; - pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1; + pi->nqsets = is_x_10g_port(&pi->link_cfg) ? q10g : 1; qidx += pi->nqsets; } s->ethqsets = qidx; diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h index f412d0fa0850..95df61dcb4ce 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h @@ -228,6 +228,12 @@ static inline bool is_10g_port(const struct link_config *lc) return (lc->supported & SUPPORTED_10000baseT_Full) != 0; } +static inline bool is_x_10g_port(const struct link_config *lc) +{ + return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0 || + (lc->supported & FW_PORT_CAP_SPEED_40G) != 0; +} + static inline unsigned int core_ticks_per_usec(const struct adapter *adapter) { return adapter->params.vpd.cclk / 1000; diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c index 25dfeb8f28ed..e984fdc48ba2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -327,6 +327,8 @@ int t4vf_port_init(struct adapter *adapter, int pidx) v |= SUPPORTED_1000baseT_Full; if (word & FW_PORT_CAP_SPEED_10G) v |= SUPPORTED_10000baseT_Full; + if (word & FW_PORT_CAP_SPEED_40G) + v |= SUPPORTED_40000baseSR4_Full; if (word & FW_PORT_CAP_ANEG) v |= SUPPORTED_Autoneg; init_link_config(&pi->link_cfg, v); @@ -1352,11 +1354,13 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl) if (word & FW_PORT_CMD_TXPAUSE) fc |= PAUSE_TX; if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M)) - speed = SPEED_100; + speed = 100; else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G)) - speed = SPEED_1000; + speed = 1000; else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) - speed = SPEED_10000; + speed = 10000; + else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G)) + speed = 40000; /* * Scan all of our "ports" (Virtual Interfaces) looking for -- cgit v1.2.3 From 8203b509c5b7aab7a8170626ce02372c61da2cdd Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 9 Oct 2014 05:48:47 +0530 Subject: cxgb4: Wait for device to get ready before reading any register Call t4_wait_dev_ready() before attempting to read the PL_WHOAMI register (to determine which function we have been attached to). This prevents us from failing on that read if it comes right after a RESET. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 2 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 6 +++++- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 17 ++++++++++------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 9b2c669b6522..410ed5805a9a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -968,7 +968,7 @@ void t4_intr_enable(struct adapter *adapter); void t4_intr_disable(struct adapter *adapter); int t4_slow_intr_handler(struct adapter *adapter); -int t4_wait_dev_ready(struct adapter *adap); +int t4_wait_dev_ready(void __iomem *regs); 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); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 321f3d9385c9..5b38e955af6e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -6137,7 +6137,7 @@ static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev) pci_save_state(pdev); pci_cleanup_aer_uncorrect_error_status(pdev); - if (t4_wait_dev_ready(adap) < 0) + if (t4_wait_dev_ready(adap->regs) < 0) return PCI_ERS_RESULT_DISCONNECT; if (t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, NULL) < 0) return PCI_ERS_RESULT_DISCONNECT; @@ -6530,6 +6530,10 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_disable_device; } + err = t4_wait_dev_ready(regs); + if (err < 0) + goto out_unmap_bar0; + /* We control everything through one PF */ func = SOURCEPF_GET(readl(regs + PL_WHOAMI)); if (func != ent->driver_data) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 22d7581341a9..1fff1495fe31 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3845,12 +3845,19 @@ static void init_link_config(struct link_config *lc, unsigned int caps) } } -int t4_wait_dev_ready(struct adapter *adap) +#define CIM_PF_NOACCESS 0xeeeeeeee + +int t4_wait_dev_ready(void __iomem *regs) { - if (t4_read_reg(adap, PL_WHOAMI) != 0xffffffff) + u32 whoami; + + whoami = readl(regs + PL_WHOAMI); + if (whoami != 0xffffffff && whoami != CIM_PF_NOACCESS) return 0; + msleep(500); - return t4_read_reg(adap, PL_WHOAMI) != 0xffffffff ? 0 : -EIO; + whoami = readl(regs + PL_WHOAMI); + return (whoami != 0xffffffff && whoami != CIM_PF_NOACCESS ? 0 : -EIO); } struct flash_desc { @@ -3919,10 +3926,6 @@ int t4_prep_adapter(struct adapter *adapter) uint16_t device_id; u32 pl_rev; - ret = t4_wait_dev_ready(adapter); - if (ret < 0) - return ret; - get_pci_mode(adapter, &adapter->params.pci); pl_rev = G_REV(t4_read_reg(adapter, PL_REV)); -- cgit v1.2.3 From de3f0d0effecc2ccfbd679705519ed5b35f9cb33 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Thu, 9 Oct 2014 12:58:08 +0900 Subject: net: Missing @ before descriptions cause make xmldocs warning This patch fix following warning. Warning(.//net/core/skbuff.c:4142): No description found for parameter 'header_len' Warning(.//net/core/skbuff.c:4142): No description found for parameter 'data_len' Warning(.//net/core/skbuff.c:4142): No description found for parameter 'max_page_order' Warning(.//net/core/skbuff.c:4142): No description found for parameter 'errcode' Warning(.//net/core/skbuff.c:4142): No description found for parameter 'gfp_mask' Acutually the descriptions exist, but missing "@" in front. This problem start to happen when following commit was merged into Linus's tree during 3.18-rc1 merge period. commit 2e4e44107176d552f8bb1bb76053e850e3809841 net: add alloc_skb_with_frags() helper Signed-off-by: Masanari Iida Signed-off-by: David S. Miller --- net/core/skbuff.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 7b3df0d518ab..a30d750647e7 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4126,11 +4126,11 @@ EXPORT_SYMBOL(skb_vlan_untag); /** * alloc_skb_with_frags - allocate skb with page frags * - * header_len: size of linear part - * data_len: needed length in frags - * max_page_order: max page order desired. - * errcode: pointer to error code if any - * gfp_mask: allocation mask + * @header_len: size of linear part + * @data_len: needed length in frags + * @max_page_order: max page order desired. + * @errcode: pointer to error code if any + * @gfp_mask: allocation mask * * This can be used to allocate a paged skb, given a maximal order for frags. */ -- cgit v1.2.3 From 405f8a0ec71c869a374066cce22f88670d27a739 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 9 Oct 2014 18:00:24 +0800 Subject: r8152: autoresume before setting feature Resume the device before setting the feature. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 5cfd414b9a3e..c5afe8c85cbc 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2145,6 +2145,11 @@ static int rtl8152_set_features(struct net_device *dev, { netdev_features_t changed = features ^ dev->features; struct r8152 *tp = netdev_priv(dev); + int ret; + + ret = usb_autopm_get_interface(tp->intf); + if (ret < 0) + goto out; if (changed & NETIF_F_HW_VLAN_CTAG_RX) { if (features & NETIF_F_HW_VLAN_CTAG_RX) @@ -2153,7 +2158,10 @@ static int rtl8152_set_features(struct net_device *dev, rtl_rx_vlan_en(tp, false); } - return 0; + usb_autopm_put_interface(tp->intf); + +out: + return ret; } #define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) -- cgit v1.2.3 From 8d4a4d7286eb6fc783149de44aa90de4bc72a9fe Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 9 Oct 2014 18:00:25 +0800 Subject: r8152: adjust usb_autopm_xxx Add usb_autopm_xxx for rtl8152_get_settings() ,and remove usb_autopm_xxx from read_mii_word() and write_mii_word(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index c5afe8c85cbc..1d2fc8effda6 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -942,15 +942,8 @@ static int read_mii_word(struct net_device *netdev, int phy_id, int reg) if (phy_id != R8152_PHY_ID) return -EINVAL; - ret = usb_autopm_get_interface(tp->intf); - if (ret < 0) - goto out; - ret = r8152_mdio_read(tp, reg); - usb_autopm_put_interface(tp->intf); - -out: return ret; } @@ -965,12 +958,7 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val) if (phy_id != R8152_PHY_ID) return; - if (usb_autopm_get_interface(tp->intf) < 0) - return; - r8152_mdio_write(tp, reg, val); - - usb_autopm_put_interface(tp->intf); } static int @@ -3290,11 +3278,21 @@ static int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) { struct r8152 *tp = netdev_priv(netdev); + int ret; if (!tp->mii.mdio_read) return -EOPNOTSUPP; - return mii_ethtool_gset(&tp->mii, cmd); + ret = usb_autopm_get_interface(tp->intf); + if (ret < 0) + goto out; + + ret = mii_ethtool_gset(&tp->mii, cmd); + + usb_autopm_put_interface(tp->intf); + +out: + return ret; } static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -- cgit v1.2.3 From b54032736dbba2ae18995b930d0176bd8b0386c8 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 9 Oct 2014 18:00:26 +0800 Subject: r8152: add mutex for hw settings Use the mutex to avoid the settings are interrupted by other ones. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 1d2fc8effda6..864159eb744e 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -26,7 +26,7 @@ #include /* Version Information */ -#define DRIVER_VERSION "v1.06.1 (2014/10/01)" +#define DRIVER_VERSION "v1.07.0 (2014/10/09)" #define DRIVER_AUTHOR "Realtek linux nic maintainers " #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define MODULENAME "r8152" @@ -566,6 +566,7 @@ struct r8152 { spinlock_t rx_lock, tx_lock; struct delayed_work schedule; struct mii_if_info mii; + struct mutex control; /* use for hw setting */ struct rtl_ops { void (*init)(struct r8152 *); @@ -977,12 +978,16 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p) if (ret < 0) goto out1; + mutex_lock(&tp->control); + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, addr->sa_data); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); + mutex_unlock(&tp->control); + usb_autopm_put_interface(tp->intf); out1: return ret; @@ -2139,6 +2144,8 @@ static int rtl8152_set_features(struct net_device *dev, if (ret < 0) goto out; + mutex_lock(&tp->control); + if (changed & NETIF_F_HW_VLAN_CTAG_RX) { if (features & NETIF_F_HW_VLAN_CTAG_RX) rtl_rx_vlan_en(tp, true); @@ -2146,6 +2153,8 @@ static int rtl8152_set_features(struct net_device *dev, rtl_rx_vlan_en(tp, false); } + mutex_unlock(&tp->control); + usb_autopm_put_interface(tp->intf); out: @@ -2847,6 +2856,11 @@ static void rtl_work_func_t(struct work_struct *work) if (test_bit(RTL8152_UNPLUG, &tp->flags)) goto out1; + if (!mutex_trylock(&tp->control)) { + schedule_delayed_work(&tp->schedule, 0); + goto out1; + } + if (test_bit(RTL8152_LINK_CHG, &tp->flags)) set_carrier(tp); @@ -2862,6 +2876,8 @@ static void rtl_work_func_t(struct work_struct *work) if (test_bit(PHY_RESET, &tp->flags)) rtl_phy_reset(tp); + mutex_unlock(&tp->control); + out1: usb_autopm_put_interface(tp->intf); } @@ -2881,6 +2897,8 @@ static int rtl8152_open(struct net_device *netdev) goto out; } + mutex_lock(&tp->control); + /* The WORK_ENABLE may be set when autoresume occurs */ if (test_bit(WORK_ENABLE, &tp->flags)) { clear_bit(WORK_ENABLE, &tp->flags); @@ -2909,6 +2927,8 @@ static int rtl8152_open(struct net_device *netdev) free_all_mem(tp); } + mutex_unlock(&tp->control); + usb_autopm_put_interface(tp->intf); out: @@ -2929,6 +2949,8 @@ static int rtl8152_close(struct net_device *netdev) if (res < 0) { rtl_drop_queued_tx(tp); } else { + mutex_lock(&tp->control); + /* The autosuspend may have been enabled and wouldn't * be disable when autoresume occurs, because the * netif_running() would be false. @@ -2941,6 +2963,9 @@ static int rtl8152_close(struct net_device *netdev) tasklet_disable(&tp->tl); tp->rtl_ops.down(tp); tasklet_enable(&tp->tl); + + mutex_unlock(&tp->control); + usb_autopm_put_interface(tp->intf); } @@ -3165,6 +3190,8 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) { struct r8152 *tp = usb_get_intfdata(intf); + mutex_lock(&tp->control); + if (PMSG_IS_AUTO(message)) set_bit(SELECTIVE_SUSPEND, &tp->flags); else @@ -3184,6 +3211,8 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) tasklet_enable(&tp->tl); } + mutex_unlock(&tp->control); + return 0; } @@ -3191,6 +3220,8 @@ static int rtl8152_resume(struct usb_interface *intf) { struct r8152 *tp = usb_get_intfdata(intf); + mutex_lock(&tp->control); + if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) { tp->rtl_ops.init(tp); netif_device_attach(tp->netdev); @@ -3216,6 +3247,8 @@ static int rtl8152_resume(struct usb_interface *intf) usb_submit_urb(tp->intr_urb, GFP_KERNEL); } + mutex_unlock(&tp->control); + return 0; } @@ -3226,9 +3259,13 @@ static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (usb_autopm_get_interface(tp->intf) < 0) return; + mutex_lock(&tp->control); + wol->supported = WAKE_ANY; wol->wolopts = __rtl_get_wol(tp); + mutex_unlock(&tp->control); + usb_autopm_put_interface(tp->intf); } @@ -3241,9 +3278,13 @@ static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (ret < 0) goto out_set_wol; + mutex_lock(&tp->control); + __rtl_set_wol(tp, wol->wolopts); tp->saved_wolopts = wol->wolopts & WAKE_ANY; + mutex_unlock(&tp->control); + usb_autopm_put_interface(tp->intf); out_set_wol: @@ -3287,8 +3328,12 @@ int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) if (ret < 0) goto out; + mutex_lock(&tp->control); + ret = mii_ethtool_gset(&tp->mii, cmd); + mutex_unlock(&tp->control); + usb_autopm_put_interface(tp->intf); out: @@ -3304,8 +3349,12 @@ static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (ret < 0) goto out; + mutex_lock(&tp->control); + ret = rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex); + mutex_unlock(&tp->control); + usb_autopm_put_interface(tp->intf); out: @@ -3465,8 +3514,12 @@ rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata) if (ret < 0) goto out; + mutex_lock(&tp->control); + ret = tp->rtl_ops.eee_get(tp, edata); + mutex_unlock(&tp->control); + usb_autopm_put_interface(tp->intf); out: @@ -3483,10 +3536,14 @@ rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *edata) if (ret < 0) goto out; + mutex_lock(&tp->control); + ret = tp->rtl_ops.eee_set(tp, edata); if (!ret) ret = mii_nway_restart(&tp->mii); + mutex_unlock(&tp->control); + usb_autopm_put_interface(tp->intf); out: @@ -3528,7 +3585,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) break; case SIOCGMIIREG: + mutex_lock(&tp->control); data->val_out = r8152_mdio_read(tp, data->reg_num); + mutex_unlock(&tp->control); break; case SIOCSMIIREG: @@ -3536,7 +3595,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) res = -EPERM; break; } + mutex_lock(&tp->control); r8152_mdio_write(tp, data->reg_num, data->val_in); + mutex_unlock(&tp->control); break; default: @@ -3729,6 +3790,7 @@ static int rtl8152_probe(struct usb_interface *intf, goto out; tasklet_init(&tp->tl, bottom_half, (unsigned long)tp); + mutex_init(&tp->control); INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); netdev->netdev_ops = &rtl8152_netdev_ops; -- cgit v1.2.3 From b8358d70ce1066dd4cc658cfdaf7862d459e2d78 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Thu, 9 Oct 2014 12:18:10 +0200 Subject: net_sched: restore qdisc quota fairness limits after bulk dequeue Restore the quota fairness between qdisc's, that we broke with commit 5772e9a346 ("qdisc: bulk dequeue support for qdiscs with TCQ_F_ONETXQUEUE"). Before that commit, the quota in __qdisc_run() were in packets as dequeue_skb() would only dequeue a single packet, that assumption broke with bulk dequeue. We choose not to account for the number of packets inside the TSO/GSO packets (accessable via "skb_gso_segs"). As the previous fairness also had this "defect". Thus, GSO/TSO packets counts as a single packet. Further more, we choose to slack on accuracy, by allowing a bulk dequeue try_bulk_dequeue_skb() to exceed the "packets" limit, only limited by the BQL bytelimit. This is done because BQL prefers to get its full budget for appropriate feedback from TX completion. In future, we might consider reworking this further and, if it allows, switch to a time-based model, as suggested by Eric. Right now, we only restore old semantics. Joint work with Eric, Hannes, Daniel and Jesper. Hannes wrote the first patch in cooperation with Daniel and Jesper. Eric rewrote the patch. Fixes: 5772e9a346 ("qdisc: bulk dequeue support for qdiscs with TCQ_F_ONETXQUEUE") Signed-off-by: Eric Dumazet Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Hannes Frederic Sowa Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/sched/sch_generic.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 38d58e6cef07..6efca30894aa 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -57,7 +57,8 @@ static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) static void try_bulk_dequeue_skb(struct Qdisc *q, struct sk_buff *skb, - const struct netdev_queue *txq) + const struct netdev_queue *txq, + int *packets) { int bytelimit = qdisc_avail_bulklimit(txq) - skb->len; @@ -70,6 +71,7 @@ static void try_bulk_dequeue_skb(struct Qdisc *q, bytelimit -= nskb->len; /* covers GSO len */ skb->next = nskb; skb = nskb; + (*packets)++; /* GSO counts as one pkt */ } skb->next = NULL; } @@ -77,11 +79,13 @@ static void try_bulk_dequeue_skb(struct Qdisc *q, /* Note that dequeue_skb can possibly return a SKB list (via skb->next). * A requeued skb (via q->gso_skb) can also be a SKB list. */ -static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate) +static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate, + int *packets) { struct sk_buff *skb = q->gso_skb; const struct netdev_queue *txq = q->dev_queue; + *packets = 1; *validate = true; if (unlikely(skb)) { /* check the reason of requeuing without tx lock first */ @@ -98,7 +102,7 @@ static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate) !netif_xmit_frozen_or_stopped(txq)) { skb = q->dequeue(q); if (skb && qdisc_may_bulk(q)) - try_bulk_dequeue_skb(q, skb, txq); + try_bulk_dequeue_skb(q, skb, txq, packets); } } return skb; @@ -204,7 +208,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, * >0 - queue is not empty. * */ -static inline int qdisc_restart(struct Qdisc *q) +static inline int qdisc_restart(struct Qdisc *q, int *packets) { struct netdev_queue *txq; struct net_device *dev; @@ -213,7 +217,7 @@ static inline int qdisc_restart(struct Qdisc *q) bool validate; /* Dequeue packet */ - skb = dequeue_skb(q, &validate); + skb = dequeue_skb(q, &validate, packets); if (unlikely(!skb)) return 0; @@ -227,14 +231,16 @@ static inline int qdisc_restart(struct Qdisc *q) void __qdisc_run(struct Qdisc *q) { int quota = weight_p; + int packets; - while (qdisc_restart(q)) { + while (qdisc_restart(q, &packets)) { /* * Ordered by possible occurrence: Postpone processing if * 1. we've exceeded packet quota * 2. another process needs the CPU; */ - if (--quota <= 0 || need_resched()) { + quota -= packets; + if (quota <= 0 || need_resched()) { __netif_schedule(q); break; } -- cgit v1.2.3 From 7b4ecf39a2fb2285b3ffc869411461a3e83e1b63 Mon Sep 17 00:00:00 2001 From: LEROY Christophe Date: Thu, 9 Oct 2014 16:54:43 +0200 Subject: net: fs_enet: error: 'SCCE_ENET_TXF' undeclared [linux-devel:devel-hourly-2014100909 3763/3915] drivers/net/ethernet/freescale/fs_enet/mac-scc.c:119:32: error: 'SCCE_ENET_TXF' undeclared Due to patch d43a396 net: fs_enet: Add NAPI TX, it appears that some target compilations are broken. This is due to the fact that unlike the FEC, the SCC and FCC don't have a TXF event (complete Frame transmitted) but only TXB (buffer transmitted). Signed-off-by: Christophe Leroy Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fs_enet/mac-fcc.c | 2 +- drivers/net/ethernet/freescale/fs_enet/mac-scc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c index 2c578db401e8..08f5b911d96b 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c @@ -125,7 +125,7 @@ out: } #define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB) -#define FCC_NAPI_TX_EVENT_MSK (FCC_ENET_TXF | FCC_ENET_TXB) +#define FCC_NAPI_TX_EVENT_MSK (FCC_ENET_TXB) #define FCC_RX_EVENT (FCC_ENET_RXF) #define FCC_TX_EVENT (FCC_ENET_TXB) #define FCC_ERR_EVENT_MSK (FCC_ENET_TXE) diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c index 41aa0b475ca0..f30411f0701f 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c @@ -116,7 +116,7 @@ static int do_pd_setup(struct fs_enet_private *fep) } #define SCC_NAPI_RX_EVENT_MSK (SCCE_ENET_RXF | SCCE_ENET_RXB) -#define SCC_NAPI_TX_EVENT_MSK (SCCE_ENET_TXF | SCCE_ENET_TXB) +#define SCC_NAPI_TX_EVENT_MSK (SCCE_ENET_TXB) #define SCC_RX_EVENT (SCCE_ENET_RXF) #define SCC_TX_EVENT (SCCE_ENET_TXB) #define SCC_ERR_EVENT_MSK (SCCE_ENET_TXE | SCCE_ENET_BSY) -- cgit v1.2.3 From b71b12dce200e4709bd9f709e71c84dcb2cf8a82 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Fri, 10 Oct 2014 01:19:06 -0400 Subject: networking: fm10k: Fix build failure The latest linus git tip (3.18-rc1) fails with the following build failure. Fix this by making PTP support explicit for fm10k driver. rivers/built-in.o: In function `fm10k_ptp_register': (.text+0x12e760): undefined reference to `ptp_clock_registER' drivers/built-in.o: In function `fm10k_ptp_unregister': (.text+0x12e7dc): undefined reference to `ptp_clock_unregister' Makefile:930: recipe for target 'vmlinux' failed Signed-off-by: Pranith Kumar Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 6a6d5ee51e6a..6919adb66f53 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -304,6 +304,7 @@ config FM10K tristate "Intel(R) FM10000 Ethernet Switch Host Interface Support" default n depends on PCI_MSI + select PTP_1588_CLOCK ---help--- This driver supports Intel(R) FM10000 Ethernet Switch Host Interface. For more information on how to identify your adapter, -- cgit v1.2.3 From 3b3d136cf7e5e8e5ec80850e25bfea3e70d1bbe8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 9 Oct 2014 16:15:42 +0200 Subject: net: pxa168_eth: PXA168_ETH should depend on HAS_DMA If NO_DMA=y: drivers/built-in.o: In function `rxq_deinit': pxa168_eth.c:(.text+0x2a2f2e): undefined reference to `dma_free_coherent' drivers/built-in.o: In function `txq_reclaim': pxa168_eth.c:(.text+0x2a3044): undefined reference to `dma_unmap_single' drivers/built-in.o: In function `txq_deinit': pxa168_eth.c:(.text+0x2a310a): undefined reference to `dma_free_coherent' drivers/built-in.o: In function `txq_init': pxa168_eth.c:(.text+0x2a3226): undefined reference to `dma_alloc_coherent' drivers/built-in.o: In function `rxq_init': pxa168_eth.c:(.text+0x2a32d4): undefined reference to `dma_alloc_coherent' drivers/built-in.o: In function `init_hash_table': pxa168_eth.c:(.text+0x2a3354): undefined reference to `dma_alloc_coherent' drivers/built-in.o: In function `rxq_refill': pxa168_eth.c:(.text+0x2a345a): undefined reference to `dma_map_single' drivers/built-in.o: In function `rxq_process': pxa168_eth.c:(.text+0x2a39cc): undefined reference to `dma_unmap_single' drivers/built-in.o: In function `pxa168_eth_remove': pxa168_eth.c:(.text+0x2a3b84): undefined reference to `dma_free_coherent' drivers/built-in.o: In function `pxa168_eth_start_xmit': pxa168_eth.c:(.text+0x2a3e8a): undefined reference to `dma_map_single' Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index b3b72ad92d4a..d323a695dfbc 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -64,7 +64,8 @@ config MVPP2 config PXA168_ETH tristate "Marvell pxa168 ethernet support" - depends on (CPU_PXA168 || ARCH_BERLIN || COMPILE_TEST) && HAS_IOMEM + depends on HAS_IOMEM && HAS_DMA + depends on CPU_PXA168 || ARCH_BERLIN || COMPILE_TEST select PHYLIB ---help--- This driver supports the pxa168 Ethernet ports. -- cgit v1.2.3 From 3dab99e0b37e16525949757f46e33fb9612c73ec Mon Sep 17 00:00:00 2001 From: Vince Bridgers Date: Thu, 9 Oct 2014 10:10:36 -0500 Subject: stmmac: correct mc_filter local variable in set_filter and set_mac_addr call Testing revealed that the local variable mc_filter was dimensioned incorrectly for all possible configurations and get_mac_addr should have been set_mac_addr (a typo). Make sure mc_filter is dimensioned to 8 32-bit unsigned longs - the largest size of the Synopsys multicast filter register set. Signed-off-by: Vince Bridgers Acked-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index 5efe60ea6526..0adcf73cf722 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -134,7 +134,7 @@ static void dwmac1000_set_filter(struct mac_device_info *hw, void __iomem *ioaddr = (void __iomem *)dev->base_addr; unsigned int value = 0; unsigned int perfect_addr_number = hw->unicast_filter_entries; - u32 mc_filter[2]; + u32 mc_filter[8]; int mcbitslog2 = hw->mcast_bits_log2; pr_debug("%s: # mcasts %d, # unicast %d\n", __func__, @@ -182,7 +182,7 @@ static void dwmac1000_set_filter(struct mac_device_info *hw, struct netdev_hw_addr *ha; netdev_for_each_uc_addr(ha, dev) { - stmmac_get_mac_addr(ioaddr, ha->addr, + stmmac_set_mac_addr(ioaddr, ha->addr, GMAC_ADDR_HIGH(reg), GMAC_ADDR_LOW(reg)); reg++; -- cgit v1.2.3 From 38b3629adb8c048dda8b98e888505c79ed33ae92 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Thu, 9 Oct 2014 15:16:41 -0700 Subject: net: bpf: fix bpf syscall dependence on anon_inodes minimal configurations where EPOLL, PERF_EVENTS, etc are disabled, but NET is enabled, are failing to build with link error: kernel/built-in.o: In function `bpf_prog_load': syscall.c:(.text+0x3b728): undefined reference to `anon_inode_getfd' fix it by selecting ANON_INODES when NET is enabled Reported-by: Michal Sojka Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- net/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/net/Kconfig b/net/Kconfig index d6b138e2c263..6272420a721b 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -6,6 +6,7 @@ menuconfig NET bool "Networking support" select NLATTR select GENERIC_NET_UTILS + select ANON_INODES ---help--- Unless you really know what you are doing, you should say Y here. The reason is that some programs need kernel networking support even -- cgit v1.2.3 From b61d18904e2a99ed16b6e97d5419f1db19e08bd2 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Thu, 9 Oct 2014 18:32:02 -0700 Subject: MAINTAINERS: Update APM X-Gene section Updated APM X-Gene ethernet driver maintainers list. Signed-off-by: Iyappan Subramanian Signed-off-by: Keyur Chudgar Signed-off-by: David S. Miller --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 9e315a44ae0c..1a85af843326 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -734,7 +734,6 @@ F: net/appletalk/ APPLIED MICRO (APM) X-GENE SOC ETHERNET DRIVER M: Iyappan Subramanian M: Keyur Chudgar -M: Ravi Patel S: Supported F: drivers/net/ethernet/apm/xgene/ F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt -- cgit v1.2.3 From 5239b978b686e336a501680c80399e4786ac12fc Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Thu, 9 Oct 2014 18:32:03 -0700 Subject: Documentation: dts: Update section header for APM X-Gene Signed-off-by: Iyappan Subramanian Signed-off-by: Keyur Chudgar Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/apm-xgene-enet.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/apm-xgene-enet.txt b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt index ebcad25efd0a..cfcc52705ed8 100644 --- a/Documentation/devicetree/bindings/net/apm-xgene-enet.txt +++ b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt @@ -3,7 +3,7 @@ APM X-Gene SoC Ethernet nodes Ethernet nodes are defined to describe on-chip ethernet interfaces in APM X-Gene SoC. -Required properties: +Required properties for all the ethernet interfaces: - compatible: Should be "apm,xgene-enet" - reg: Address and length of the register set for the device. It contains the information of registers in the same order as described by reg-names @@ -15,6 +15,8 @@ Required properties: - clocks: Reference to the clock entry. - local-mac-address: MAC address assigned to this device - phy-connection-type: Interface type between ethernet device and PHY device + +Required properties for ethernet interfaces that have external PHY: - phy-handle: Reference to a PHY node connected to this device - mdio: Device tree subnode with the following required properties: -- cgit v1.2.3 From 5fb32417b7e52d2e6d5f5c64d277a03e5c998a02 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Thu, 9 Oct 2014 18:32:04 -0700 Subject: dtb: Add 10GbE node to APM X-Gene SoC device tree Added 10GbE interface and clock nodes. Signed-off-by: Iyappan Subramanian Signed-off-by: Keyur Chudgar Signed-off-by: David S. Miller --- arch/arm64/boot/dts/apm-mustang.dts | 4 ++++ arch/arm64/boot/dts/apm-storm.dtsi | 29 +++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts index b2f56229aa5e..2ae782bbdf0f 100644 --- a/arch/arm64/boot/dts/apm-mustang.dts +++ b/arch/arm64/boot/dts/apm-mustang.dts @@ -32,3 +32,7 @@ &menet { status = "ok"; }; + +&xgenet { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi index f391972ad135..d16cc03b7c5d 100644 --- a/arch/arm64/boot/dts/apm-storm.dtsi +++ b/arch/arm64/boot/dts/apm-storm.dtsi @@ -176,6 +176,16 @@ clock-output-names = "menetclk"; }; + xge0clk: xge0clk@1f61c000 { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f61c000 0x0 0x1000>; + reg-names = "csr-reg"; + csr-mask = <0x3>; + clock-output-names = "xge0clk"; + }; + sataphy1clk: sataphy1clk@1f21c000 { compatible = "apm,xgene-device-clock"; #clock-cells = <1>; @@ -420,7 +430,8 @@ interrupts = <0x0 0x3c 0x4>; dma-coherent; clocks = <&menetclk 0>; - local-mac-address = [00 01 73 00 00 01]; + /* mac address will be overwritten by the bootloader */ + local-mac-address = [00 00 00 00 00 00]; phy-connection-type = "rgmii"; phy-handle = <&menetphy>; mdio { @@ -435,12 +446,26 @@ }; }; + xgenet: ethernet@1f610000 { + compatible = "apm,xgene-enet"; + status = "disabled"; + reg = <0x0 0x1f610000 0x0 0xd100>, + <0x0 0x1f600000 0x0 0X400>, + <0x0 0x18000000 0x0 0X200>; + reg-names = "enet_csr", "ring_csr", "ring_cmd"; + interrupts = <0x0 0x60 0x4>; + dma-coherent; + clocks = <&xge0clk 0>; + /* mac address will be overwritten by the bootloader */ + local-mac-address = [00 00 00 00 00 00]; + phy-connection-type = "xgmii"; + }; + rng: rng@10520000 { compatible = "apm,xgene-rng"; reg = <0x0 0x10520000 0x0 0x100>; interrupts = <0x0 0x41 0x4>; clocks = <&rngpkaclk 0>; }; - }; }; -- cgit v1.2.3 From d0eb74582fa7b5c15710d293a3c4d8d3409ae165 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Thu, 9 Oct 2014 18:32:05 -0700 Subject: drivers: net: xgene: Preparing for adding 10GbE support - Rearranged code to pave the way for adding 10GbE support - Added mac_ops structure containing function pointers for mac specific functions - Added port_ops structure containing function pointers for port specific functions Signed-off-by: Iyappan Subramanian Signed-off-by: Keyur Chudgar Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 44 ++++++++++++++++-------- drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 16 ++------- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 40 +++++++++++++-------- drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 19 ++++++++++ 4 files changed, 78 insertions(+), 41 deletions(-) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 812d8d65159b..c8f3824f7606 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -402,7 +402,7 @@ static int xgene_mii_phy_read(struct xgene_enet_pdata *pdata, return data; } -void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) +static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) { u32 addr0, addr1; u8 *dev_addr = pdata->ndev->dev_addr; @@ -436,13 +436,13 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) return 0; } -void xgene_gmac_reset(struct xgene_enet_pdata *pdata) +static void xgene_gmac_reset(struct xgene_enet_pdata *pdata) { xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1); xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, 0); } -void xgene_gmac_init(struct xgene_enet_pdata *pdata, int speed) +static void xgene_gmac_init(struct xgene_enet_pdata *pdata) { u32 value, mc2; u32 intf_ctl, rgmii; @@ -456,7 +456,7 @@ void xgene_gmac_init(struct xgene_enet_pdata *pdata, int speed) xgene_enet_rd_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, &intf_ctl); xgene_enet_rd_csr(pdata, RGMII_REG_0_ADDR, &rgmii); - switch (speed) { + switch (pdata->phy_speed) { case SPEED_10: ENET_INTERFACE_MODE2_SET(&mc2, 1); CFG_MACMODE_SET(&icm0, 0); @@ -525,8 +525,8 @@ static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, val); } -void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, - u32 dst_ring_num, u16 bufpool_id) +static void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, + u32 dst_ring_num, u16 bufpool_id) { u32 cb; u32 fpsel; @@ -544,7 +544,7 @@ void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, xgene_enet_wr_csr(pdata, CLE_BYPASS_REG1_0_ADDR, cb); } -void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata) +static void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata) { u32 data; @@ -552,7 +552,7 @@ void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata) xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN); } -void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata) +static void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata) { u32 data; @@ -560,7 +560,7 @@ void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata) xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN); } -void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata) +static void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata) { u32 data; @@ -568,7 +568,7 @@ void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata) xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN); } -void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata) +static void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata) { u32 data; @@ -576,7 +576,7 @@ void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata) xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN); } -void xgene_enet_reset(struct xgene_enet_pdata *pdata) +static void xgene_enet_reset(struct xgene_enet_pdata *pdata) { u32 val; @@ -593,7 +593,7 @@ void xgene_enet_reset(struct xgene_enet_pdata *pdata) xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val); } -void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) +static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) { clk_disable_unprepare(pdata->clk); } @@ -627,10 +627,10 @@ static void xgene_enet_adjust_link(struct net_device *ndev) if (phydev->link) { if (pdata->phy_speed != phydev->speed) { - xgene_gmac_init(pdata, phydev->speed); + pdata->phy_speed = phydev->speed; + xgene_gmac_init(pdata); xgene_gmac_rx_enable(pdata); xgene_gmac_tx_enable(pdata); - pdata->phy_speed = phydev->speed; phy_print_status(phydev); } } else { @@ -726,3 +726,19 @@ void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata) mdiobus_free(pdata->mdio_bus); pdata->mdio_bus = NULL; } + +struct xgene_mac_ops xgene_gmac_ops = { + .init = xgene_gmac_init, + .reset = xgene_gmac_reset, + .rx_enable = xgene_gmac_rx_enable, + .tx_enable = xgene_gmac_tx_enable, + .rx_disable = xgene_gmac_rx_disable, + .tx_disable = xgene_gmac_tx_disable, + .set_mac_addr = xgene_gmac_set_mac_addr, +}; + +struct xgene_port_ops xgene_gport_ops = { + .reset = xgene_enet_reset, + .cle_bypass = xgene_enet_cle_bypass, + .shutdown = xgene_gport_shutdown, +}; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index 371e7a5b2507..084ac68aed8d 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -318,20 +318,10 @@ void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, struct xgene_enet_pdata *pdata, enum xgene_enet_err_code status); -void xgene_enet_reset(struct xgene_enet_pdata *priv); -void xgene_gmac_reset(struct xgene_enet_pdata *priv); -void xgene_gmac_init(struct xgene_enet_pdata *priv, int speed); -void xgene_gmac_tx_enable(struct xgene_enet_pdata *priv); -void xgene_gmac_rx_enable(struct xgene_enet_pdata *priv); -void xgene_gmac_tx_disable(struct xgene_enet_pdata *priv); -void xgene_gmac_rx_disable(struct xgene_enet_pdata *priv); -void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata); -void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, - u32 dst_ring_num, u16 bufpool_id); -void xgene_gport_shutdown(struct xgene_enet_pdata *priv); -void xgene_gmac_get_tx_stats(struct xgene_enet_pdata *pdata); - int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata); void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata); +extern struct xgene_mac_ops xgene_gmac_ops; +extern struct xgene_port_ops xgene_gport_ops; + #endif /* __XGENE_ENET_HW_H__ */ diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index e4222af2baa6..c4326444deaf 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -413,7 +413,7 @@ static void xgene_enet_timeout(struct net_device *ndev) { struct xgene_enet_pdata *pdata = netdev_priv(ndev); - xgene_gmac_reset(pdata); + pdata->mac_ops->reset(pdata); } static int xgene_enet_register_irq(struct net_device *ndev) @@ -445,10 +445,11 @@ static void xgene_enet_free_irq(struct net_device *ndev) static int xgene_enet_open(struct net_device *ndev) { struct xgene_enet_pdata *pdata = netdev_priv(ndev); + struct xgene_mac_ops *mac_ops = pdata->mac_ops; int ret; - xgene_gmac_tx_enable(pdata); - xgene_gmac_rx_enable(pdata); + mac_ops->tx_enable(pdata); + mac_ops->rx_enable(pdata); ret = xgene_enet_register_irq(ndev); if (ret) @@ -466,6 +467,7 @@ static int xgene_enet_open(struct net_device *ndev) static int xgene_enet_close(struct net_device *ndev) { struct xgene_enet_pdata *pdata = netdev_priv(ndev); + struct xgene_mac_ops *mac_ops = pdata->mac_ops; netif_stop_queue(ndev); @@ -476,8 +478,8 @@ static int xgene_enet_close(struct net_device *ndev) xgene_enet_free_irq(ndev); xgene_enet_process_ring(pdata->rx_ring, -1); - xgene_gmac_tx_disable(pdata); - xgene_gmac_rx_disable(pdata); + mac_ops->tx_disable(pdata); + mac_ops->rx_disable(pdata); return 0; } @@ -724,7 +726,7 @@ static int xgene_enet_set_mac_address(struct net_device *ndev, void *addr) ret = eth_mac_addr(ndev, addr); if (ret) return ret; - xgene_gmac_set_mac_addr(pdata); + pdata->mac_ops->set_mac_addr(pdata); return ret; } @@ -834,8 +836,8 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) u16 dst_ring_num; int ret; - xgene_gmac_tx_disable(pdata); - xgene_gmac_rx_disable(pdata); + pdata->mac_ops->tx_disable(pdata); + pdata->mac_ops->rx_disable(pdata); ret = xgene_enet_create_desc_rings(ndev); if (ret) { @@ -853,11 +855,17 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) } dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring); - xgene_enet_cle_bypass(pdata, dst_ring_num, buf_pool->id); + pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id); return ret; } +static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata) +{ + pdata->mac_ops = &xgene_gmac_ops; + pdata->port_ops = &xgene_gport_ops; +} + static int xgene_enet_probe(struct platform_device *pdev) { struct net_device *ndev; @@ -886,8 +894,9 @@ static int xgene_enet_probe(struct platform_device *pdev) if (ret) goto err; - xgene_enet_reset(pdata); - xgene_gmac_init(pdata, SPEED_1000); + xgene_enet_setup_ops(pdata); + pdata->port_ops->reset(pdata); + pdata->mac_ops->init(pdata); ret = register_netdev(ndev); if (ret) { @@ -918,19 +927,21 @@ err: static int xgene_enet_remove(struct platform_device *pdev) { struct xgene_enet_pdata *pdata; + struct xgene_mac_ops *mac_ops; struct net_device *ndev; pdata = platform_get_drvdata(pdev); + mac_ops = pdata->mac_ops; ndev = pdata->ndev; - xgene_gmac_rx_disable(pdata); - xgene_gmac_tx_disable(pdata); + mac_ops->rx_disable(pdata); + mac_ops->tx_disable(pdata); netif_napi_del(&pdata->rx_ring->napi); xgene_enet_mdio_remove(pdata); xgene_enet_delete_desc_rings(pdata); unregister_netdev(ndev); - xgene_gport_shutdown(pdata); + pdata->port_ops->shutdown(pdata); free_netdev(ndev); return 0; @@ -956,5 +967,6 @@ module_platform_driver(xgene_enet_driver); MODULE_DESCRIPTION("APM X-Gene SoC Ethernet driver"); MODULE_VERSION(XGENE_DRV_VERSION); +MODULE_AUTHOR("Iyappan Subramanian "); MODULE_AUTHOR("Keyur Chudgar "); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 0815866986b0..ac180f980fcd 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -68,6 +68,23 @@ struct xgene_enet_desc_ring { }; }; +struct xgene_mac_ops { + void (*init)(struct xgene_enet_pdata *pdata); + void (*reset)(struct xgene_enet_pdata *pdata); + void (*tx_enable)(struct xgene_enet_pdata *pdata); + void (*rx_enable)(struct xgene_enet_pdata *pdata); + void (*tx_disable)(struct xgene_enet_pdata *pdata); + void (*rx_disable)(struct xgene_enet_pdata *pdata); + void (*set_mac_addr)(struct xgene_enet_pdata *pdata); +}; + +struct xgene_port_ops { + void (*reset)(struct xgene_enet_pdata *pdata); + void (*cle_bypass)(struct xgene_enet_pdata *pdata, + u32 dst_ring_num, u16 bufpool_id); + void (*shutdown)(struct xgene_enet_pdata *pdata); +}; + /* ethernet private data */ struct xgene_enet_pdata { struct net_device *ndev; @@ -98,6 +115,8 @@ struct xgene_enet_pdata { u32 speed; u16 rm; struct rtnl_link_stats64 stats; + struct xgene_mac_ops *mac_ops; + struct xgene_port_ops *port_ops; }; /* Set the specified value into a bit-field defined by its starting position -- cgit v1.2.3 From 0148d38d36b76b190ddddff68f02d2617ada3bcb Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Thu, 9 Oct 2014 18:32:06 -0700 Subject: drivers: net: xgene: Add 10GbE support - Added 10GbE support - Removed unused macros/variables - Moved mac_init call to the end of hardware init Signed-off-by: Iyappan Subramanian Signed-off-by: Keyur Chudgar Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/Makefile | 3 +- drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 14 +- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 58 ++-- drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 5 +- drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 331 ++++++++++++++++++++++ drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | 57 ++++ 6 files changed, 438 insertions(+), 30 deletions(-) create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h diff --git a/drivers/net/ethernet/apm/xgene/Makefile b/drivers/net/ethernet/apm/xgene/Makefile index c643e8a0a0dc..589b35247713 100644 --- a/drivers/net/ethernet/apm/xgene/Makefile +++ b/drivers/net/ethernet/apm/xgene/Makefile @@ -2,5 +2,6 @@ # Makefile for APM X-Gene Ethernet Driver. # -xgene-enet-objs := xgene_enet_hw.o xgene_enet_main.o xgene_enet_ethtool.o +xgene-enet-objs := xgene_enet_hw.o xgene_enet_xgmac.o \ + xgene_enet_main.o xgene_enet_ethtool.o obj-$(CONFIG_NET_XGENE) += xgene-enet.o diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index 084ac68aed8d..15ec4267779c 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -42,6 +42,11 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) return (val & GENMASK(end, start)) >> start; } +enum xgene_enet_rm { + RM0, + RM3 = 3 +}; + #define CSR_RING_ID 0x0008 #define OVERWRITE BIT(31) #define IS_BUFFER_POOL BIT(20) @@ -52,7 +57,6 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) #define CSR_RING_WR_BASE 0x0070 #define NUM_RING_CONFIG 5 #define BUFPOOL_MODE 3 -#define RM3 3 #define INC_DEC_CMD_ADDR 0x002c #define UDP_HDR_SIZE 2 #define BUF_LEN_CODE_2K 0x5000 @@ -94,11 +98,9 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) #define BLOCK_ETH_CSR_OFFSET 0x2000 #define BLOCK_ETH_RING_IF_OFFSET 0x9000 -#define BLOCK_ETH_CLKRST_CSR_OFFSET 0xC000 #define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000 #define BLOCK_ETH_MAC_OFFSET 0x0000 -#define BLOCK_ETH_STATS_OFFSET 0x0014 #define BLOCK_ETH_MAC_CSR_OFFSET 0x2800 #define MAC_ADDR_REG_OFFSET 0x00 @@ -107,12 +109,6 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) #define MAC_READ_REG_OFFSET 0x0c #define MAC_COMMAND_DONE_REG_OFFSET 0x10 -#define STAT_ADDR_REG_OFFSET 0x00 -#define STAT_COMMAND_REG_OFFSET 0x04 -#define STAT_WRITE_REG_OFFSET 0x08 -#define STAT_READ_REG_OFFSET 0x0c -#define STAT_COMMAND_DONE_REG_OFFSET 0x10 - #define MII_MGMT_CONFIG_ADDR 0x20 #define MII_MGMT_COMMAND_ADDR 0x24 #define MII_MGMT_ADDRESS_ADDR 0x28 diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index c4326444deaf..9b85239ceedf 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -21,6 +21,7 @@ #include "xgene_enet_main.h" #include "xgene_enet_hw.h" +#include "xgene_enet_xgmac.h" static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool) { @@ -390,7 +391,7 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring, } } - return budget; + return count; } static int xgene_enet_napi(struct napi_struct *napi, const int budget) @@ -456,8 +457,10 @@ static int xgene_enet_open(struct net_device *ndev) return ret; napi_enable(&pdata->rx_ring->napi); - if (pdata->phy_dev) + if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) phy_start(pdata->phy_dev); + else + schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF); netif_start_queue(ndev); @@ -471,8 +474,10 @@ static int xgene_enet_close(struct net_device *ndev) netif_stop_queue(ndev); - if (pdata->phy_dev) + if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) phy_stop(pdata->phy_dev); + else + cancel_delayed_work_sync(&pdata->link_work); napi_disable(&pdata->rx_ring->napi); xgene_enet_free_irq(ndev); @@ -615,7 +620,6 @@ static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring( ring->cmd_base = pdata->ring_cmd_addr + (ring->num << 6); ring->cmd = ring->cmd_base + INC_DEC_CMD_ADDR; - pdata->rm = RM3; ring = xgene_enet_setup_ring(ring); netdev_dbg(ndev, "ring info: num=%d size=%d id=%d slots=%d\n", ring->num, ring->size, ring->id, ring->slots); @@ -805,8 +809,13 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node); if (pdata->phy_mode < 0) { - dev_err(dev, "Incorrect phy-connection-type in DTS\n"); - return -EINVAL; + dev_err(dev, "Unable to get phy-connection-type\n"); + return pdata->phy_mode; + } + if (pdata->phy_mode != PHY_INTERFACE_MODE_RGMII && + pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { + dev_err(dev, "Incorrect phy-connection-type specified\n"); + return -ENODEV; } pdata->clk = devm_clk_get(&pdev->dev, NULL); @@ -821,12 +830,18 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET; pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET; pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET; - pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET; - pdata->mcx_stats_addr = base_addr + BLOCK_ETH_STATS_OFFSET; - pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET; + if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { + pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET; + pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET; + pdata->rm = RM3; + } else { + pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET; + pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET; + pdata->rm = RM0; + } pdata->rx_buff_cnt = NUM_PKT_BUF; - return ret; + return 0; } static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) @@ -836,8 +851,7 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) u16 dst_ring_num; int ret; - pdata->mac_ops->tx_disable(pdata); - pdata->mac_ops->rx_disable(pdata); + pdata->port_ops->reset(pdata); ret = xgene_enet_create_desc_rings(ndev); if (ret) { @@ -856,14 +870,23 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring); pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id); + pdata->mac_ops->init(pdata); return ret; } static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata) { - pdata->mac_ops = &xgene_gmac_ops; - pdata->port_ops = &xgene_gport_ops; + switch (pdata->phy_mode) { + case PHY_INTERFACE_MODE_RGMII: + pdata->mac_ops = &xgene_gmac_ops; + pdata->port_ops = &xgene_gport_ops; + break; + default: + pdata->mac_ops = &xgene_xgmac_ops; + pdata->port_ops = &xgene_xgport_ops; + break; + } } static int xgene_enet_probe(struct platform_device *pdev) @@ -895,8 +918,6 @@ static int xgene_enet_probe(struct platform_device *pdev) goto err; xgene_enet_setup_ops(pdata); - pdata->port_ops->reset(pdata); - pdata->mac_ops->init(pdata); ret = register_netdev(ndev); if (ret) { @@ -916,7 +937,10 @@ static int xgene_enet_probe(struct platform_device *pdev) napi = &pdata->rx_ring->napi; netif_napi_add(ndev, napi, xgene_enet_napi, NAPI_POLL_WEIGHT); - ret = xgene_enet_mdio_config(pdata); + if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + ret = xgene_enet_mdio_config(pdata); + else + INIT_DELAYED_WORK(&pdata->link_work, xgene_enet_link_state); return ret; err: diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index ac180f980fcd..86cf68b65584 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -105,18 +105,17 @@ struct xgene_enet_pdata { void __iomem *eth_ring_if_addr; void __iomem *eth_diag_csr_addr; void __iomem *mcx_mac_addr; - void __iomem *mcx_stats_addr; void __iomem *mcx_mac_csr_addr; void __iomem *base_addr; void __iomem *ring_csr_addr; void __iomem *ring_cmd_addr; u32 phy_addr; int phy_mode; - u32 speed; - u16 rm; + enum xgene_enet_rm rm; struct rtnl_link_stats64 stats; struct xgene_mac_ops *mac_ops; struct xgene_port_ops *port_ops; + struct delayed_work link_work; }; /* Set the specified value into a bit-field defined by its starting position diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c new file mode 100644 index 000000000000..cd64b9f18b58 --- /dev/null +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c @@ -0,0 +1,331 @@ +/* Applied Micro X-Gene SoC Ethernet Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Authors: Iyappan Subramanian + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "xgene_enet_main.h" +#include "xgene_enet_hw.h" +#include "xgene_enet_xgmac.h" + +static void xgene_enet_wr_csr(struct xgene_enet_pdata *pdata, + u32 offset, u32 val) +{ + void __iomem *addr = pdata->eth_csr_addr + offset; + + iowrite32(val, addr); +} + +static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *pdata, + u32 offset, u32 val) +{ + void __iomem *addr = pdata->eth_ring_if_addr + offset; + + iowrite32(val, addr); +} + +static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *pdata, + u32 offset, u32 val) +{ + void __iomem *addr = pdata->eth_diag_csr_addr + offset; + + iowrite32(val, addr); +} + +static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr, + void __iomem *cmd, void __iomem *cmd_done, + u32 wr_addr, u32 wr_data) +{ + u32 done; + u8 wait = 10; + + iowrite32(wr_addr, addr); + iowrite32(wr_data, wr); + iowrite32(XGENE_ENET_WR_CMD, cmd); + + /* wait for write command to complete */ + while (!(done = ioread32(cmd_done)) && wait--) + udelay(1); + + if (!done) + return false; + + iowrite32(0, cmd); + + return true; +} + +static void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, + u32 wr_addr, u32 wr_data) +{ + void __iomem *addr, *wr, *cmd, *cmd_done; + + addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; + wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; + cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; + cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; + + if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data)) + netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n", + wr_addr); +} + +static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata, + u32 offset, u32 *val) +{ + void __iomem *addr = pdata->eth_csr_addr + offset; + + *val = ioread32(addr); +} + +static void xgene_enet_rd_diag_csr(struct xgene_enet_pdata *pdata, + u32 offset, u32 *val) +{ + void __iomem *addr = pdata->eth_diag_csr_addr + offset; + + *val = ioread32(addr); +} + +static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd, + void __iomem *cmd, void __iomem *cmd_done, + u32 rd_addr, u32 *rd_data) +{ + u32 done; + u8 wait = 10; + + iowrite32(rd_addr, addr); + iowrite32(XGENE_ENET_RD_CMD, cmd); + + /* wait for read command to complete */ + while (!(done = ioread32(cmd_done)) && wait--) + udelay(1); + + if (!done) + return false; + + *rd_data = ioread32(rd); + iowrite32(0, cmd); + + return true; +} + +static void xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, + u32 rd_addr, u32 *rd_data) +{ + void __iomem *addr, *rd, *cmd, *cmd_done; + + addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; + rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; + cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; + cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; + + if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data)) + netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n", + rd_addr); +} + +static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) +{ + struct net_device *ndev = pdata->ndev; + u32 data; + u8 wait = 10; + + xgene_enet_wr_diag_csr(pdata, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0); + do { + usleep_range(100, 110); + xgene_enet_rd_diag_csr(pdata, ENET_BLOCK_MEM_RDY_ADDR, &data); + } while ((data != 0xffffffff) && wait--); + + if (data != 0xffffffff) { + netdev_err(ndev, "Failed to release memory from shutdown\n"); + return -ENODEV; + } + + return 0; +} + +static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) +{ + xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, 0); + xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPQASSOC_ADDR, 0); + xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEWQASSOC_ADDR, 0); + xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, 0); +} + +static void xgene_xgmac_reset(struct xgene_enet_pdata *pdata) +{ + xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_0, HSTMACRST); + xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_0, 0); +} + +static void xgene_xgmac_set_mac_addr(struct xgene_enet_pdata *pdata) +{ + u32 addr0, addr1; + u8 *dev_addr = pdata->ndev->dev_addr; + + addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | + (dev_addr[1] << 8) | dev_addr[0]; + addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16); + + xgene_enet_wr_mac(pdata, HSTMACADR_LSW_ADDR, addr0); + xgene_enet_wr_mac(pdata, HSTMACADR_MSW_ADDR, addr1); +} + +static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata) +{ + u32 data; + + xgene_enet_rd_csr(pdata, XG_LINK_STATUS_ADDR, &data); + + return data; +} + +static void xgene_xgmac_init(struct xgene_enet_pdata *pdata) +{ + u32 data; + + xgene_xgmac_reset(pdata); + + xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data |= HSTPPEN; + data &= ~HSTLENCHK; + xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data); + + xgene_enet_wr_mac(pdata, HSTMAXFRAME_LENGTH_ADDR, 0x06000600); + xgene_xgmac_set_mac_addr(pdata); + + xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, &data); + data |= CFG_RSIF_FPBUFF_TIMEOUT_EN; + xgene_enet_wr_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, data); + + xgene_enet_wr_csr(pdata, XG_CFG_BYPASS_ADDR, RESUME_TX); + xgene_enet_wr_csr(pdata, XGENET_RX_DV_GATE_REG_0_ADDR, 0); + xgene_enet_rd_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, &data); + data |= BIT(12); + xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, data); + xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_1_ADDR, 0x82); +} + +static void xgene_xgmac_rx_enable(struct xgene_enet_pdata *pdata) +{ + u32 data; + + xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTRFEN); +} + +static void xgene_xgmac_tx_enable(struct xgene_enet_pdata *pdata) +{ + u32 data; + + xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTTFEN); +} + +static void xgene_xgmac_rx_disable(struct xgene_enet_pdata *pdata) +{ + u32 data; + + xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTRFEN); +} + +static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata) +{ + u32 data; + + xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTTFEN); +} + +static void xgene_enet_reset(struct xgene_enet_pdata *pdata) +{ + clk_prepare_enable(pdata->clk); + clk_disable_unprepare(pdata->clk); + clk_prepare_enable(pdata->clk); + + xgene_enet_ecc_init(pdata); + xgene_enet_config_ring_if_assoc(pdata); +} + +static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata, + u32 dst_ring_num, u16 bufpool_id) +{ + u32 cb, fpsel; + + xgene_enet_rd_csr(pdata, XCLE_BYPASS_REG0_ADDR, &cb); + cb |= CFG_CLE_BYPASS_EN0; + CFG_CLE_IP_PROTOCOL0_SET(&cb, 3); + xgene_enet_wr_csr(pdata, XCLE_BYPASS_REG0_ADDR, cb); + + fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20; + xgene_enet_rd_csr(pdata, XCLE_BYPASS_REG1_ADDR, &cb); + CFG_CLE_DSTQID0_SET(&cb, dst_ring_num); + CFG_CLE_FPSEL0_SET(&cb, fpsel); + xgene_enet_wr_csr(pdata, XCLE_BYPASS_REG1_ADDR, cb); +} + +static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) +{ + clk_disable_unprepare(pdata->clk); +} + +void xgene_enet_link_state(struct work_struct *work) +{ + struct xgene_enet_pdata *pdata = container_of(to_delayed_work(work), + struct xgene_enet_pdata, link_work); + struct net_device *ndev = pdata->ndev; + u32 link_status, poll_interval; + + link_status = xgene_enet_link_status(pdata); + if (link_status) { + if (!netif_carrier_ok(ndev)) { + netif_carrier_on(ndev); + xgene_xgmac_init(pdata); + xgene_xgmac_rx_enable(pdata); + xgene_xgmac_tx_enable(pdata); + netdev_info(ndev, "Link is Up - 10Gbps\n"); + } + poll_interval = PHY_POLL_LINK_ON; + } else { + if (netif_carrier_ok(ndev)) { + xgene_xgmac_rx_disable(pdata); + xgene_xgmac_tx_disable(pdata); + netif_carrier_off(ndev); + netdev_info(ndev, "Link is Down\n"); + } + poll_interval = PHY_POLL_LINK_OFF; + } + + schedule_delayed_work(&pdata->link_work, poll_interval); +} + +struct xgene_mac_ops xgene_xgmac_ops = { + .init = xgene_xgmac_init, + .reset = xgene_xgmac_reset, + .rx_enable = xgene_xgmac_rx_enable, + .tx_enable = xgene_xgmac_tx_enable, + .rx_disable = xgene_xgmac_rx_disable, + .tx_disable = xgene_xgmac_tx_disable, + .set_mac_addr = xgene_xgmac_set_mac_addr, +}; + +struct xgene_port_ops xgene_xgport_ops = { + .reset = xgene_enet_reset, + .cle_bypass = xgene_enet_xgcle_bypass, + .shutdown = xgene_enet_shutdown, +}; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h new file mode 100644 index 000000000000..d2d59e7ed9ab --- /dev/null +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h @@ -0,0 +1,57 @@ +/* Applied Micro X-Gene SoC Ethernet Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Authors: Iyappan Subramanian + * Keyur Chudgar + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __XGENE_ENET_XGMAC_H__ +#define __XGENE_ENET_XGMAC_H__ + +#define BLOCK_AXG_MAC_OFFSET 0x0800 +#define BLOCK_AXG_MAC_CSR_OFFSET 0x2000 + +#define AXGMAC_CONFIG_0 0x0000 +#define AXGMAC_CONFIG_1 0x0004 +#define HSTMACRST BIT(31) +#define HSTTCTLEN BIT(31) +#define HSTTFEN BIT(30) +#define HSTRCTLEN BIT(29) +#define HSTRFEN BIT(28) +#define HSTPPEN BIT(7) +#define HSTDRPLT64 BIT(5) +#define HSTLENCHK BIT(3) +#define HSTMACADR_LSW_ADDR 0x0010 +#define HSTMACADR_MSW_ADDR 0x0014 +#define HSTMAXFRAME_LENGTH_ADDR 0x0020 + +#define XG_RSIF_CONFIG_REG_ADDR 0x00a0 +#define XCLE_BYPASS_REG0_ADDR 0x0160 +#define XCLE_BYPASS_REG1_ADDR 0x0164 +#define XG_CFG_BYPASS_ADDR 0x0204 +#define XG_LINK_STATUS_ADDR 0x0228 +#define XG_ENET_SPARE_CFG_REG_ADDR 0x040c +#define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 +#define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 + +#define PHY_POLL_LINK_ON (10 * HZ) +#define PHY_POLL_LINK_OFF (PHY_POLL_LINK_ON / 5) + +void xgene_enet_link_state(struct work_struct *work); +extern struct xgene_mac_ops xgene_xgmac_ops; +extern struct xgene_port_ops xgene_xgport_ops; + +#endif /* __XGENE_ENET_XGMAC_H__ */ -- cgit v1.2.3 From 41aace6e088d198f2441f3d0e579657d6815234c Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Thu, 9 Oct 2014 18:32:07 -0700 Subject: drivers: net: xgene: Add 10GbE ethtool support Signed-off-by: Iyappan Subramanian Signed-off-by: Keyur Chudgar Signed-off-by: David S. Miller --- .../net/ethernet/apm/xgene/xgene_enet_ethtool.c | 28 +++++++++++++++++----- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index 63f2aa54a594..c1c997b92342 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -59,10 +59,22 @@ static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) struct xgene_enet_pdata *pdata = netdev_priv(ndev); struct phy_device *phydev = pdata->phy_dev; - if (phydev == NULL) - return -ENODEV; + if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { + if (phydev == NULL) + return -ENODEV; - return phy_ethtool_gset(phydev, cmd); + return phy_ethtool_gset(phydev, cmd); + } + + cmd->supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE; + cmd->advertising = cmd->supported; + ethtool_cmd_speed_set(cmd, SPEED_10000); + cmd->duplex = DUPLEX_FULL; + cmd->port = PORT_FIBRE; + cmd->transceiver = XCVR_EXTERNAL; + cmd->autoneg = AUTONEG_DISABLE; + + return 0; } static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) @@ -70,10 +82,14 @@ static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) struct xgene_enet_pdata *pdata = netdev_priv(ndev); struct phy_device *phydev = pdata->phy_dev; - if (phydev == NULL) - return -ENODEV; + if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { + if (phydev == NULL) + return -ENODEV; + + return phy_ethtool_sset(phydev, cmd); + } - return phy_ethtool_sset(phydev, cmd); + return -EINVAL; } static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data) -- cgit v1.2.3 From 4c9799359bc691becc888f97a4b5bb035cb206f9 Mon Sep 17 00:00:00 2001 From: "jbaron@akamai.com" Date: Fri, 10 Oct 2014 03:13:27 +0000 Subject: macvlan: pass 'bool' type to macvlan_count_rx() Pass last argument to macvlan_count_rx() as the correct bool type. Signed-off-by: Jason Baron Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 38b4fae61f04..c7c58aff1ff7 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -260,7 +260,7 @@ static void macvlan_broadcast(struct sk_buff *skb, mode == MACVLAN_MODE_BRIDGE) ?: netif_rx_ni(nskb); macvlan_count_rx(vlan, skb->len + ETH_HLEN, - err == NET_RX_SUCCESS, 1); + err == NET_RX_SUCCESS, true); } } } @@ -379,7 +379,7 @@ static void macvlan_forward_source_one(struct sk_buff *skb, nskb->pkt_type = PACKET_HOST; ret = netif_rx(nskb); - macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0); + macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false); } static void macvlan_forward_source(struct sk_buff *skb, @@ -457,7 +457,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) ret = netif_rx(skb); out: - macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0); + macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false); return RX_HANDLER_CONSUMED; } -- cgit v1.2.3 From d1dd911930885659420421cfe123957610c54299 Mon Sep 17 00:00:00 2001 From: "jbaron@akamai.com" Date: Fri, 10 Oct 2014 03:13:31 +0000 Subject: macvlan: optimize the receive path The netif_rx() call on the fast path of macvlan_handle_frame() appears to be there to ensure that we properly throttle incoming packets. However, it would appear as though the proper throttling is already in place for all possible ingress paths, and that the call is redundant. If packets are arriving from the physical NIC, we've already throttled them by this point. Otherwise, if they are coming via macvlan_queue_xmit(), it calls either 'dev_forward_skb()', which ends up calling netif_rx_internal(), or else in the broadcast case, we are throttling via macvlan_broadcast_enqueue(). The test results below are from off the box to an lxc instance running macvlan. Once the tranactions/sec stop increasing, the cpu idle time has gone to 0. Results are from a quad core Intel E3-1270 V2@3.50GHz box with bnx2x 10G card. for i in {10,100,200,300,400,500}; do super_netperf $i -H $ip -t TCP_RR; done Average of 5 runs. trans/sec trans/sec (3.17-rc7-net-next) (3.17-rc7-net-next + this patch) ---------- ---------- 208101 211534 (+1.6%) 839493 850162 (+1.3%) 845071 844053 (-.12%) 816330 819623 (+.4%) 778700 789938 (+1.4%) 735984 754408 (+2.5%) Signed-off-by: Jason Baron Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index c7c58aff1ff7..29b3bb410781 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -407,7 +407,8 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) const struct macvlan_dev *src; struct net_device *dev; unsigned int len = 0; - int ret = NET_RX_DROP; + int ret; + rx_handler_result_t handle_res; port = macvlan_port_get_rcu(skb->dev); if (is_multicast_ether_addr(eth->h_dest)) { @@ -423,6 +424,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) vlan = src; ret = macvlan_broadcast_one(skb, vlan, eth, 0) ?: netif_rx(skb); + handle_res = RX_HANDLER_CONSUMED; goto out; } @@ -448,17 +450,20 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) } len = skb->len + ETH_HLEN; skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) + if (!skb) { + ret = NET_RX_DROP; + handle_res = RX_HANDLER_CONSUMED; goto out; + } skb->dev = dev; skb->pkt_type = PACKET_HOST; - ret = netif_rx(skb); - + ret = NET_RX_SUCCESS; + handle_res = RX_HANDLER_ANOTHER; out: macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false); - return RX_HANDLER_CONSUMED; + return handle_res; } static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) -- cgit v1.2.3 From 1a9525f68e948d53cf99c963bdbf01223a08f4ed Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Fri, 10 Oct 2014 11:36:54 +0800 Subject: Documentation: replace __sk_run_filter with __bpf_prog_run __sk_run_filter has been renamed as __bpf_prog_run, so replace them in comments Signed-off-by: Li RongQing Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- Documentation/networking/filter.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt index b1935f9ce081..58d08f8d8d80 100644 --- a/Documentation/networking/filter.txt +++ b/Documentation/networking/filter.txt @@ -700,11 +700,11 @@ Some core changes of the new internal format: bpf_exit If f2 is JITed and the pointer stored to '_f2'. The calls f1 -> f2 -> f3 and - returns will be seamless. Without JIT, __sk_run_filter() interpreter needs to + returns will be seamless. Without JIT, __bpf_prog_run() interpreter needs to be used to call into f2. For practical reasons all eBPF programs have only one argument 'ctx' which is - already placed into R1 (e.g. on __sk_run_filter() startup) and the programs + already placed into R1 (e.g. on __bpf_prog_run() startup) and the programs can call kernel functions with up to 5 arguments. Calls with 6 or more arguments are currently not supported, but these restrictions can be lifted if necessary in the future. -- cgit v1.2.3 From 8ea6e345a6123fa831e42cd8747f55892a58abff Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Fri, 10 Oct 2014 13:56:51 +0800 Subject: net: filter: fix the comments 1. sk_run_filter has been renamed, sk_filter() is using SK_RUN_FILTER. 2. Remove wrong comments about storing intermediate value. 3. replace sk_run_filter with __bpf_prog_run for check_load_and_stores's comments Cc: Alexei Starovoitov Signed-off-by: Li RongQing Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- net/core/filter.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index fcd3f6742a6a..647b12265e18 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -51,9 +51,9 @@ * @skb: buffer to filter * * Run the filter code and then cut skb->data to correct size returned by - * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller + * SK_RUN_FILTER. If pkt_len is 0 we toss packet. If skb->len is smaller * than pkt_len we keep whole skb->data. This is the socket level - * wrapper to sk_run_filter. It returns 0 if the packet should + * wrapper to SK_RUN_FILTER. It returns 0 if the packet should * be accepted or -EPERM if the packet should be tossed. * */ @@ -565,12 +565,9 @@ err: } /* Security: - * - * A BPF program is able to use 16 cells of memory to store intermediate - * values (check u32 mem[BPF_MEMWORDS] in sk_run_filter()). * * As we dont want to clear mem[] array for each packet going through - * sk_run_filter(), we check that filter loaded by user never try to read + * __bpf_prog_run(), we check that filter loaded by user never try to read * a cell if not previously written, and we check all branches to be sure * a malicious user doesn't try to abuse us. */ -- cgit v1.2.3 From 5af7fb6e3e92c2797ee30d66138cf6aa6b29240d Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 10 Oct 2014 12:09:12 -0700 Subject: flow-dissector: Fix alignment issue in __skb_flow_get_ports This patch addresses a kernel unaligned access bug seen on a sparc64 system with an igb adapter. Specifically the __skb_flow_get_ports was returning a be32 pointer which was then having the value directly returned. In order to prevent this it is actually easier to simply not populate the ports or address values when an skb is not present. In this case the assumption is that the data isn't needed and rather than slow down the faster aligned accesses by making them have to assume the unaligned path on architectures that don't support efficent unaligned access it makes more sense to simply switch off the bits that were copying the source and destination address/port for the case where we only care about the protocol types and lengths which are normally 16 bit fields anyway. Reported-by: David S. Miller Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- net/core/flow_dissector.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 8560dea58803..45084938c403 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -100,6 +100,13 @@ ip: if (ip_is_fragment(iph)) ip_proto = 0; + /* skip the address processing if skb is NULL. The assumption + * here is that if there is no skb we are not looking for flow + * info but lengths and protocols. + */ + if (!skb) + break; + iph_to_flow_copy_addrs(flow, iph); break; } @@ -114,17 +121,15 @@ ipv6: return false; ip_proto = iph->nexthdr; - flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr); - flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); nhoff += sizeof(struct ipv6hdr); - /* skip the flow label processing if skb is NULL. The - * assumption here is that if there is no skb we are not - * looking for flow info as much as we are length. - */ + /* see comment above in IPv4 section */ if (!skb) break; + flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr); + flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); + flow_label = ip6_flowlabel(iph); if (flow_label) { /* Awesome, IPv6 packet has a flow label so we can @@ -231,9 +236,13 @@ ipv6: flow->n_proto = proto; flow->ip_proto = ip_proto; - flow->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, data, hlen); flow->thoff = (u16) nhoff; + /* unless skb is set we don't need to record port info */ + if (skb) + flow->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, + data, hlen); + return true; } EXPORT_SYMBOL(__skb_flow_dissect); @@ -334,15 +343,16 @@ u32 __skb_get_poff(const struct sk_buff *skb, void *data, switch (keys->ip_proto) { case IPPROTO_TCP: { - const struct tcphdr *tcph; - struct tcphdr _tcph; + /* access doff as u8 to avoid unaligned access */ + const u8 *doff; + u8 _doff; - tcph = __skb_header_pointer(skb, poff, sizeof(_tcph), - data, hlen, &_tcph); - if (!tcph) + doff = __skb_header_pointer(skb, poff + 12, sizeof(_doff), + data, hlen, &_doff); + if (!doff) return poff; - poff += max_t(u32, sizeof(struct tcphdr), tcph->doff * 4); + poff += max_t(u32, sizeof(struct tcphdr), (*doff & 0xF0) >> 2); break; } case IPPROTO_UDP: -- cgit v1.2.3 From 1fadee0c364572f2b2e098b34001fbaa82ee2e00 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 10 Oct 2014 09:48:05 +0200 Subject: net/phy: micrel: Add clock support for KSZ8021/KSZ8031 The KSZ8021 and KSZ8031 support RMII reference input clocks of 25MHz and 50MHz. Both PHYs differ in the default frequency they expect after reset. If this differs from the actual input clock, then register 0x1f bit 7 must be changed. Signed-off-by: Sascha Hauer Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/micrel.txt | 6 +++++ drivers/net/phy/micrel.c | 31 ++++++++++++++++++++++-- include/linux/micrel_phy.h | 1 + 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/micrel.txt b/Documentation/devicetree/bindings/net/micrel.txt index 98a3e61f9ee8..e1d99b95c4ec 100644 --- a/Documentation/devicetree/bindings/net/micrel.txt +++ b/Documentation/devicetree/bindings/net/micrel.txt @@ -16,3 +16,9 @@ Optional properties: KSZ8051: register 0x1f, bits 5..4 See the respective PHY datasheet for the mode values. + + - clocks, clock-names: contains clocks according to the common clock bindings. + + supported clocks: + - KSZ8021, KSZ8031: "rmii-ref": The RMII refence input clock. Used + to determine the XI input clock. diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 011dbda2b2f1..492435fce1d4 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -26,6 +26,7 @@ #include #include #include +#include /* Operation Mode Strap Override */ #define MII_KSZPHY_OMSO 0x16 @@ -72,9 +73,12 @@ static int ksz_config_flags(struct phy_device *phydev) { int regval; - if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) { + if (phydev->dev_flags & (MICREL_PHY_50MHZ_CLK | MICREL_PHY_25MHZ_CLK)) { regval = phy_read(phydev, MII_KSZPHY_CTRL); - regval |= KSZ8051_RMII_50MHZ_CLK; + if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) + regval |= KSZ8051_RMII_50MHZ_CLK; + else + regval &= ~KSZ8051_RMII_50MHZ_CLK; return phy_write(phydev, MII_KSZPHY_CTRL, regval); } return 0; @@ -440,6 +444,27 @@ ksz9021_wr_mmd_phyreg(struct phy_device *phydev, int ptrad, int devnum, { } +static int ksz8021_probe(struct phy_device *phydev) +{ + struct clk *clk; + + clk = devm_clk_get(&phydev->dev, "rmii-ref"); + if (!IS_ERR(clk)) { + unsigned long rate = clk_get_rate(clk); + + if (rate > 24500000 && rate < 25500000) { + phydev->dev_flags |= MICREL_PHY_25MHZ_CLK; + } else if (rate > 49500000 && rate < 50500000) { + phydev->dev_flags |= MICREL_PHY_50MHZ_CLK; + } else { + dev_err(&phydev->dev, "Clock rate out of range: %ld\n", rate); + return -EINVAL; + } + } + + return 0; +} + static struct phy_driver ksphy_driver[] = { { .phy_id = PHY_ID_KS8737, @@ -462,6 +487,7 @@ static struct phy_driver ksphy_driver[] = { .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .probe = ksz8021_probe, .config_init = ksz8021_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -477,6 +503,7 @@ static struct phy_driver ksphy_driver[] = { .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .probe = ksz8021_probe, .config_init = ksz8021_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h index 2e5b194b9b19..53d33dee70e1 100644 --- a/include/linux/micrel_phy.h +++ b/include/linux/micrel_phy.h @@ -37,6 +37,7 @@ /* struct phy_device dev_flags definitions */ #define MICREL_PHY_50MHZ_CLK 0x00000001 +#define MICREL_PHY_25MHZ_CLK 0x00000002 #define MICREL_KSZ9021_EXTREG_CTRL 0xB #define MICREL_KSZ9021_EXTREG_DATA_WRITE 0xC -- cgit v1.2.3 From 42b0270b40e2ad692ef59e28233202ee6f293e1e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 10 Oct 2014 04:48:14 -0700 Subject: fm10k: fix race accessing page->_count This is illegal to use atomic_set(&page->_count, 2) even if we 'own' the page. Other entities in the kernel need to use get_page_unless_zero() to get a reference to the page before testing page properties, so we could loose a refcount increment. Signed-off-by: Eric Dumazet Acked-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/fm10k/fm10k_main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index 6c800a330d66..9d7118a0d67a 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -219,11 +219,10 @@ static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer, /* flip page offset to other buffer */ rx_buffer->page_offset ^= FM10K_RX_BUFSZ; - /* since we are the only owner of the page and we need to - * increment it, just set the value to 2 in order to avoid - * an unnecessary locked operation + /* Even if we own the page, we are not allowed to use atomic_set() + * This would break get_page_unless_zero() users. */ - atomic_set(&page->_count, 2); + atomic_inc(&page->_count); #else /* move offset up to the next cache line */ rx_buffer->page_offset += truesize; -- cgit v1.2.3 From 00cd5adb0313f540aa58672d14e764d164586a43 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 10 Oct 2014 04:48:15 -0700 Subject: igb: fix race accessing page->_count This is illegal to use atomic_set(&page->_count, 2) even if we 'own' the page. Other entities in the kernel need to use get_page_unless_zero() to get a reference to the page before testing page properties, so we could loose a refcount increment. Signed-off-by: Eric Dumazet Acked-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/igb/igb_main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index ae59c0b108c5..a21b14495ebd 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6545,11 +6545,10 @@ static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer, /* flip page offset to other buffer */ rx_buffer->page_offset ^= IGB_RX_BUFSZ; - /* since we are the only owner of the page and we need to - * increment it, just set the value to 2 in order to avoid - * an unnecessary locked operation + /* Even if we own the page, we are not allowed to use atomic_set() + * This would break get_page_unless_zero() users. */ - atomic_set(&page->_count, 2); + atomic_inc(&page->_count); #else /* move offset up to the next cache line */ rx_buffer->page_offset += truesize; -- cgit v1.2.3 From ec91698360b3818ff426488a1529811f7a7ab87f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 10 Oct 2014 04:48:16 -0700 Subject: ixgbe: fix race accessing page->_count This is illegal to use atomic_set(&page->_count, 2) even if we 'own' the page. Other entities in the kernel need to use get_page_unless_zero() to get a reference to the page before testing page properties, so we could loose a refcount increment. Signed-off-by: Eric Dumazet Acked-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index d677b5a23b58..fec5212d4337 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1865,12 +1865,10 @@ static bool ixgbe_add_rx_frag(struct ixgbe_ring *rx_ring, /* flip page offset to other buffer */ rx_buffer->page_offset ^= truesize; - /* - * since we are the only owner of the page and we need to - * increment it, just set the value to 2 in order to avoid - * an unecessary locked operation + /* Even if we own the page, we are not allowed to use atomic_set() + * This would break get_page_unless_zero() users. */ - atomic_set(&page->_count, 2); + atomic_inc(&page->_count); #else /* move offset up to the next cache line */ rx_buffer->page_offset += truesize; -- cgit v1.2.3 From 98226208c8a1fe5834e92d827a2a1e8051a17943 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 10 Oct 2014 04:48:17 -0700 Subject: mlx4: fix race accessing page->_count This is illegal to use atomic_set(&page->_count, ...) even if we 'own' the page. Other entities in the kernel need to use get_page_unless_zero() to get a reference to the page before testing page properties, so we could loose a refcount increment. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index a33048ee9621..01660c595f5c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -76,10 +76,10 @@ static int mlx4_alloc_pages(struct mlx4_en_priv *priv, page_alloc->dma = dma; page_alloc->page_offset = frag_info->frag_align; /* Not doing get_page() for each frag is a big win - * on asymetric workloads. + * on asymetric workloads. Note we can not use atomic_set(). */ - atomic_set(&page->_count, - page_alloc->page_size / frag_info->frag_stride); + atomic_add(page_alloc->page_size / frag_info->frag_stride - 1, + &page->_count); return 0; } -- cgit v1.2.3 From 4c450583d9d0a8241f0f62b80038ac47b43ff843 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 10 Oct 2014 04:48:18 -0700 Subject: net: fix races in page->_count manipulation This is illegal to use atomic_set(&page->_count, ...) even if we 'own' the page. Other entities in the kernel need to use get_page_unless_zero() to get a reference to the page before testing page properties, so we could loose a refcount increment. The only case it is valid is when page->_count is 0 Fixes: 540eb7bf0bbed ("net: Update alloc frag to reduce get/put page usage and recycle pages") Signed-off-by: Eric Dumaze Signed-off-by: David S. Miller --- net/core/skbuff.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index a30d750647e7..829d013745ab 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -360,18 +360,29 @@ refill: goto end; } nc->frag.size = PAGE_SIZE << order; -recycle: - atomic_set(&nc->frag.page->_count, NETDEV_PAGECNT_MAX_BIAS); + /* Even if we own the page, we do not use atomic_set(). + * This would break get_page_unless_zero() users. + */ + atomic_add(NETDEV_PAGECNT_MAX_BIAS - 1, + &nc->frag.page->_count); nc->pagecnt_bias = NETDEV_PAGECNT_MAX_BIAS; nc->frag.offset = 0; } if (nc->frag.offset + fragsz > nc->frag.size) { - /* avoid unnecessary locked operations if possible */ - if ((atomic_read(&nc->frag.page->_count) == nc->pagecnt_bias) || - atomic_sub_and_test(nc->pagecnt_bias, &nc->frag.page->_count)) - goto recycle; - goto refill; + if (atomic_read(&nc->frag.page->_count) != nc->pagecnt_bias) { + if (!atomic_sub_and_test(nc->pagecnt_bias, + &nc->frag.page->_count)) + goto refill; + /* OK, page count is 0, we can safely set it */ + atomic_set(&nc->frag.page->_count, + NETDEV_PAGECNT_MAX_BIAS); + } else { + atomic_add(NETDEV_PAGECNT_MAX_BIAS - nc->pagecnt_bias, + &nc->frag.page->_count); + } + nc->pagecnt_bias = NETDEV_PAGECNT_MAX_BIAS; + nc->frag.offset = 0; } data = page_address(nc->frag.page) + nc->frag.offset; -- cgit v1.2.3 From cf377d886f7944a5ccdbd164b89949e13617b096 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 10 Oct 2014 10:51:52 -0700 Subject: net: bcmgenet: fix off-by-one in incrementing read pointer Commit b629be5c8399d7c423b92135eb43a86c924d1cbc ("net: bcmgenet: check harder for out of memory conditions") moved the increment of the local read pointer *before* reading from the hardware descriptor using dmadesc_get_length_status(), which creates an off-by-one situation. Fix this by moving again the read_ptr increment after we have read the hardware descriptor to get both the control block and the read pointer back in sync. Fixes: b629be5c8399 ("net: bcmgenet: check harder for out of memory conditions") Signed-off-by: Jaedon Shin Signed-off-by: Florian Fainelli Acked-by: Petri Gynther Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index fff2634b6f34..fdc9ec09e453 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1285,11 +1285,6 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, cb = &priv->rx_cbs[priv->rx_read_ptr]; skb = cb->skb; - rxpktprocessed++; - - priv->rx_read_ptr++; - priv->rx_read_ptr &= (priv->num_rx_bds - 1); - /* We do not have a backing SKB, so we do not have a * corresponding DMA mapping for this incoming packet since * bcmgenet_rx_refill always either has both skb and mapping or @@ -1404,6 +1399,10 @@ refill: err = bcmgenet_rx_refill(priv, cb); if (err) netif_err(priv, rx_err, dev, "Rx refill failed\n"); + + rxpktprocessed++; + priv->rx_read_ptr++; + priv->rx_read_ptr &= (priv->num_rx_bds - 1); } return rxpktprocessed; -- cgit v1.2.3 From 083731a8fbe71d83fc908adf137dc98ee352f280 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 10 Oct 2014 10:51:53 -0700 Subject: net: bcmgenet: avoid unbalanced enable_irq_wake calls Multiple enable_irq_wake() calls will keep increasing the IRQ wake_depth, which ultimately leads to the following types of situation: 1) enable Wake-on-LAN interrupt w/o password 2) enable Wake-on-LAN interrupt w/ password 3) enable Wake-on-LAN interrupt w/o password 4) disable Wake-on-LAN interrupt After step 4), GENET would always wake-up the system no matter what wake-up device we use, which is not what we want. Fix this by making sure there are no unbalanced enable_irq_wake() calls. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c index b82b7e4e06b2..149a0d70c108 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c @@ -86,7 +86,9 @@ int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) /* Flag the device and relevant IRQ as wakeup capable */ if (wol->wolopts) { device_set_wakeup_enable(kdev, 1); - enable_irq_wake(priv->wol_irq); + /* Avoid unbalanced enable_irq_wake calls */ + if (priv->wol_irq_disabled) + enable_irq_wake(priv->wol_irq); priv->wol_irq_disabled = false; } else { device_set_wakeup_enable(kdev, 0); -- cgit v1.2.3 From 61b423a8a0bd9aeaa046f9a24bed42e3a953a936 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 10 Oct 2014 10:51:54 -0700 Subject: net: systemport: avoid unbalanced enable_irq_wake calls Multiple enable_irq_wake() calls will keep increasing the IRQ wake_depth, which ultimately leads to the following types of situation: 1) enable Wake-on-LAN interrupt w/o password 2) enable Wake-on-LAN interrupt w/ password 3) enable Wake-on-LAN interrupt w/o password 4) disable Wake-on-LAN interrupt After step 4), SYSTEMPORT would always wake-up the system no matter what wake-up device we use, which is not what we want. Fix this by making sure there are no unbalanced enable_irq_wake() calls. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 075688188644..9ae36979bdee 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -436,7 +436,8 @@ static int bcm_sysport_set_wol(struct net_device *dev, /* Flag the device and relevant IRQ as wakeup capable */ if (wol->wolopts) { device_set_wakeup_enable(kdev, 1); - enable_irq_wake(priv->wol_irq); + if (priv->wol_irq_disabled) + enable_irq_wake(priv->wol_irq); priv->wol_irq_disabled = 0; } else { device_set_wakeup_enable(kdev, 0); -- cgit v1.2.3