diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-13 10:51:48 +0900 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-13 10:51:48 +0900 |
commit | 98260daa184c4a171834463cf85ab3a2c509d983 (patch) | |
tree | 318c3bfff9edef4da84a69895a3ac2aa39b8256a /drivers | |
parent | e225ca27057e70e7cbb14ae4c1e5f758973af645 (diff) | |
parent | dabdaf0caa3af520dbc1df87b2fb4e77224037bd (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull networking updates from David Miller:
1) Alexey Kuznetsov noticed we routed TCP resets improperly in the
assymetric routing case, fix this by reverting a change that made us
use the incoming interface in the outgoing route key when we didn't
have a socket context to work with.
2) TCP sysctl kernel memory leakage to userspace fix from Alan Cox.
3) Move UAPI bits from David Howells, WIMAX and CAN this time.
4) Fix TX stalls in e1000e wrt. Byte Queue Limits, from Hiroaki
SHIMODA, Denys Fedoryshchenko, and Jesse Brandeburg.
5) Fix IPV6 crashes in packet generator module, from Amerigo Wang.
6) Tidies and fixes in the new VXLAN driver from Stephen Hemminger.
7) Bridge IP options parse doesn't check first if SKB header has at
least an IP header's worth of content present. Fix from Sarveshwar
Bandi.
8) The kernel now generates compound pages on transmit and the Xen
netback drivers needs some adjustments in order to handle this. Fix
from Ian Campbell.
9) Turn off ASPM in JME driver, from Kevin Bardon and Matthew Garrett.
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (43 commits)
mcs7830: Fix link state detection
net: add doc for in4_pton()
net: add doc for in6_pton()
vti: fix sparse bit endian warnings
tcp: resets are misrouted
usbnet: Support devices reporting idleness
Add CDC-ACM support for the CX93010-2x UCMxx USB Modem
net/ethernet/jme: disable ASPM
tcp: sysctl interface leaks 16 bytes of kernel memory
kaweth: print correct debug ptr
e1000e: Change wthresh to 1 to avoid possible Tx stalls
ipv4: fix route mark sparse warning
xen: netback: handle compound page fragments on transmit.
bridge: Pull ip header into skb->data before looking into ip header.
isdn: fix a wrapping bug in isdn_ppp_ioctl()
vxlan: fix oops when give unknown ifindex
vxlan: fix receive checksum handling
vxlan: add additional headroom
vxlan: allow configuring port range
vxlan: associate with tunnel socket on transmit
...
Diffstat (limited to 'drivers')
27 files changed, 344 insertions, 142 deletions
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index a1e76015082..61d78fa03b1 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -595,7 +595,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) j = ipc->num / (sizeof(long) * 8); i = ipc->num % (sizeof(long) * 8); if (j < 8) - protos[j] |= (0x1 << i); + protos[j] |= (1UL << i); ipc = ipc->next; } if ((r = set_arg(argp, protos, 8 * sizeof(long)))) diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index cb3356c9af8..04668b47a1d 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -175,13 +175,13 @@ struct e1000_info; /* * in the case of WTHRESH, it appears at least the 82571/2 hardware * writes back 4 descriptors when WTHRESH=5, and 3 descriptors when - * WTHRESH=4, and since we want 64 bytes at a time written back, set - * it to 5 + * WTHRESH=4, so a setting of 5 gives the most efficient bus + * utilization but to avoid possible Tx stalls, set it to 1 */ #define E1000_TXDCTL_DMA_BURST_ENABLE \ (E1000_TXDCTL_GRAN | /* set descriptor granularity */ \ E1000_TXDCTL_COUNT_DESC | \ - (5 << 16) | /* wthresh must be +1 more than desired */\ + (1 << 16) | /* wthresh must be +1 more than desired */\ (1 << 8) | /* hthresh */ \ 0x1f) /* pthresh */ diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index de57a2ba6bd..f444eb0b76d 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -2831,7 +2831,7 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) * set up some performance related parameters to encourage the * hardware to use the bus more efficiently in bursts, depends * on the tx_int_delay to be enabled, - * wthresh = 5 ==> burst write a cacheline (64 bytes) at a time + * wthresh = 1 ==> burst write is disabled to avoid Tx stalls * hthresh = 1 ==> prefetch when one or more available * pthresh = 0x1f ==> prefetch if internal cache 31 or less * BEWARE: this seems to work but should be considered first if diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index c911d883c27..f8064df10cc 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/pci-aspm.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -2973,6 +2974,9 @@ jme_init_one(struct pci_dev *pdev, /* * set up PCI device basics */ + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | + PCIE_LINK_STATE_CLKPM); + rc = pci_enable_device(pdev); if (rc) { pr_err("Cannot enable PCI device\n"); diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index 434d5af8e6f..c81e278629f 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -244,8 +244,12 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb) * - suspend: peripheral ready to suspend * - response: suggest N millisec polling * - response complete: suggest N sec polling + * + * Suspend is reported and maybe heeded. */ case 2: /* Suspend hint */ + usbnet_device_suggests_idle(dev); + continue; case 3: /* Response hint */ case 4: /* Response complete hint */ continue; diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index c75e11e1b38..afb117c16d2 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -424,7 +424,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, netdev_dbg(kaweth->net, "Downloading firmware at %p to kaweth device at %p\n", - fw->data, kaweth); + kaweth->firmware_buf, kaweth); netdev_dbg(kaweth->net, "Firmware length: %d\n", data_len); return kaweth_control(kaweth, diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 03c2d8d653d..cc7e72010ac 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -117,6 +117,7 @@ enum { struct mcs7830_data { u8 multi_filter[8]; u8 config; + u8 link_counter; }; static const char driver_name[] = "MOSCHIP usb-ethernet driver"; @@ -632,20 +633,31 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) static void mcs7830_status(struct usbnet *dev, struct urb *urb) { u8 *buf = urb->transfer_buffer; - bool link; + bool link, link_changed; + struct mcs7830_data *data = mcs7830_get_data(dev); if (urb->actual_length < 16) return; link = !(buf[1] & 0x20); - if (netif_carrier_ok(dev->net) != link) { - if (link) { - netif_carrier_on(dev->net); - usbnet_defer_kevent(dev, EVENT_LINK_RESET); - } else - netif_carrier_off(dev->net); - netdev_dbg(dev->net, "Link Status is: %d\n", link); - } + link_changed = netif_carrier_ok(dev->net) != link; + if (link_changed) { + data->link_counter++; + /* + track link state 20 times to guard against erroneous + link state changes reported sometimes by the chip + */ + if (data->link_counter > 20) { + data->link_counter = 0; + if (link) { + netif_carrier_on(dev->net); + usbnet_defer_kevent(dev, EVENT_LINK_RESET); + } else + netif_carrier_off(dev->net); + netdev_dbg(dev->net, "Link Status is: %d\n", link); + } + } else + data->link_counter = 0; } static const struct driver_info moschip_info = { diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index fc9f578a1e2..f9819d10b1f 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1588,10 +1588,27 @@ int usbnet_resume (struct usb_interface *intf) tasklet_schedule (&dev->bh); } } + + if (test_and_clear_bit(EVENT_DEVICE_REPORT_IDLE, &dev->flags)) + usb_autopm_get_interface_no_resume(intf); + return 0; } EXPORT_SYMBOL_GPL(usbnet_resume); +/* + * Either a subdriver implements manage_power, then it is assumed to always + * be ready to be suspended or it reports the readiness to be suspended + * explicitly + */ +void usbnet_device_suggests_idle(struct usbnet *dev) +{ + if (!test_and_set_bit(EVENT_DEVICE_REPORT_IDLE, &dev->flags)) { + dev->intf->needs_remote_wakeup = 1; + usb_autopm_put_interface_async(dev->intf); + } +} +EXPORT_SYMBOL(usbnet_device_suggests_idle); /*-------------------------------------------------------------------------*/ diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 8be9bf07bd3..607976c0016 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -106,6 +106,8 @@ struct vxlan_dev { __be32 gaddr; /* multicast group */ __be32 saddr; /* source address */ unsigned int link; /* link to multicast over */ + __u16 port_min; /* source port range */ + __u16 port_max; __u8 tos; /* TOS override */ __u8 ttl; bool learn; @@ -228,9 +230,9 @@ static u32 eth_hash(const unsigned char *addr) /* only want 6 bytes */ #ifdef __BIG_ENDIAN - value <<= 16; -#else value >>= 16; +#else + value <<= 16; #endif return hash_64(value, FDB_HASH_BITS); } @@ -535,7 +537,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) } __skb_pull(skb, sizeof(struct vxlanhdr)); - skb_postpull_rcsum(skb, eth_hdr(skb), sizeof(struct vxlanhdr)); /* Is this VNI defined? */ vni = ntohl(vxh->vx_vni) >> 8; @@ -554,7 +555,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) /* Re-examine inner Ethernet packet */ oip = ip_hdr(skb); skb->protocol = eth_type_trans(skb, vxlan->dev); - skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); /* Ignore packet loops (and multicast echo) */ if (compare_ether_addr(eth_hdr(skb)->h_source, @@ -566,6 +566,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) __skb_tunnel_rx(skb, vxlan->dev); skb_reset_network_header(skb); + skb->ip_summed = CHECKSUM_NONE; err = IP_ECN_decapsulate(oip, skb); if (unlikely(err)) { @@ -621,46 +622,89 @@ static inline u8 vxlan_ecn_encap(u8 tos, return INET_ECN_encapsulate(tos, inner); } +static __be32 vxlan_find_dst(struct vxlan_dev *vxlan, struct sk_buff *skb) +{ + const struct ethhdr *eth = (struct ethhdr *) skb->data; + const struct vxlan_fdb *f; + + if (is_multicast_ether_addr(eth->h_dest)) + return vxlan->gaddr; + + f = vxlan_find_mac(vxlan, eth->h_dest); + if (f) + return f->remote_ip; + else + return vxlan->gaddr; + +} + +static void vxlan_sock_free(struct sk_buff *skb) +{ + sock_put(skb->sk); +} + +/* On transmit, associate with the tunnel socket */ +static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb) +{ + struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); + struct sock *sk = vn->sock->sk; + + skb_orphan(skb); + sock_hold(sk); + skb->sk = sk; + skb->destructor = vxlan_sock_free; +} + +/* Compute source port for outgoing packet + * first choice to use L4 flow hash since it will spread + * better and maybe available from hardware + * secondary choice is to use jhash on the Ethernet header + */ +static u16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb) +{ + unsigned int range = (vxlan->port_max - vxlan->port_min) + 1; + u32 hash; + + hash = skb_get_rxhash(skb); + if (!hash) + hash = jhash(skb->data, 2 * ETH_ALEN, + (__force u32) skb->protocol); + + return (((u64) hash * range) >> 32) + vxlan->port_min; +} + /* Transmit local packets over Vxlan * * Outer IP header inherits ECN and DF from inner header. * Outer UDP destination is the VXLAN assigned port. - * source port is based on hash of flow if available - * otherwise use a random value + * source port is based on hash of flow */ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); struct rtable *rt; - const struct ethhdr *eth; const struct iphdr *old_iph; struct iphdr *iph; struct vxlanhdr *vxh; struct udphdr *uh; struct flowi4 fl4; - struct vxlan_fdb *f; unsigned int pkt_len = skb->len; - u32 hash; __be32 dst; + __u16 src_port; __be16 df = 0; __u8 tos, ttl; int err; + dst = vxlan_find_dst(vxlan, skb); + if (!dst) + goto drop; + /* Need space for new headers (invalidates iph ptr) */ if (skb_cow_head(skb, VXLAN_HEADROOM)) goto drop; - eth = (void *)skb->data; old_iph = ip_hdr(skb); - if (!is_multicast_ether_addr(eth->h_dest) && - (f = vxlan_find_mac(vxlan, eth->h_dest))) - dst = f->remote_ip; - else if (vxlan->gaddr) { - dst = vxlan->gaddr; - } else - goto drop; - ttl = vxlan->ttl; if (!ttl && IN_MULTICAST(ntohl(dst))) ttl = 1; @@ -669,11 +713,15 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) if (tos == 1) tos = vxlan_get_dsfield(old_iph, skb); - hash = skb_get_rxhash(skb); + src_port = vxlan_src_port(vxlan, skb); + + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_oif = vxlan->link; + fl4.flowi4_tos = RT_TOS(tos); + fl4.daddr = dst; + fl4.saddr = vxlan->saddr; - rt = ip_route_output_gre(dev_net(dev), &fl4, dst, - vxlan->saddr, vxlan->vni, - RT_TOS(tos), vxlan->link); + rt = ip_route_output_key(dev_net(dev), &fl4); if (IS_ERR(rt)) { netdev_dbg(dev, "no route to %pI4\n", &dst); dev->stats.tx_carrier_errors++; @@ -702,7 +750,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) uh = udp_hdr(skb); uh->dest = htons(vxlan_port); - uh->source = hash ? :random32(); + uh->source = htons(src_port); uh->len = htons(skb->len); uh->check = 0; @@ -715,10 +763,12 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) iph->frag_off = df; iph->protocol = IPPROTO_UDP; iph->tos = vxlan_ecn_encap(tos, old_iph, skb); - iph->daddr = fl4.daddr; + iph->daddr = dst; iph->saddr = fl4.saddr; iph->ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + vxlan_set_owner(dev, skb); + /* See __IPTUNNEL_XMIT */ skb->ip_summed = CHECKSUM_NONE; ip_select_ident(iph, &rt->dst, NULL); @@ -928,9 +978,11 @@ static void vxlan_setup(struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); unsigned h; + int low, high; eth_hw_addr_random(dev); ether_setup(dev); + dev->hard_header_len = ETH_HLEN + VXLAN_HEADROOM; dev->netdev_ops = &vxlan_netdev_ops; dev->destructor = vxlan_free; @@ -947,6 +999,10 @@ static void vxlan_setup(struct net_device *dev) vxlan->age_timer.function = vxlan_cleanup; vxlan->age_timer.data = (unsigned long) vxlan; + inet_get_local_port_range(&low, &high); + vxlan->port_min = low; + vxlan->port_max = high; + vxlan->dev = dev; for (h = 0; h < FDB_HASH_SIZE; ++h) @@ -963,6 +1019,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 }, [IFLA_VXLAN_AGEING] = { .type = NLA_U32 }, [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 }, + [IFLA_VXLAN_PORT_RANGE] = { .len = sizeof(struct ifla_vxlan_port_range) }, }; static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -995,6 +1052,18 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[]) return -EADDRNOTAVAIL; } } + + if (data[IFLA_VXLAN_PORT_RANGE]) { + const struct ifla_vxlan_port_range *p + = nla_data(data[IFLA_VXLAN_PORT_RANGE]); + + if (ntohs(p->high) < ntohs(p->low)) { + pr_debug("port range %u .. %u not valid\n", + ntohs(p->low), ntohs(p->high)); + return -EINVAL; + } + } + return 0; } @@ -1021,14 +1090,18 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, if (data[IFLA_VXLAN_LOCAL]) vxlan->saddr = nla_get_be32(data[IFLA_VXLAN_LOCAL]); - if (data[IFLA_VXLAN_LINK]) { - vxlan->link = nla_get_u32(data[IFLA_VXLAN_LINK]); + if (data[IFLA_VXLAN_LINK] && + (vxlan->link = nla_get_u32(data[IFLA_VXLAN_LINK]))) { + struct net_device *lowerdev + = __dev_get_by_index(net, vxlan->link); - if (!tb[IFLA_MTU]) { - struct net_device *lowerdev; - lowerdev = __dev_get_by_index(net, vxlan->link); - dev->mtu = lowerdev->mtu - VXLAN_HEADROOM; + if (!lowerdev) { + pr_info("ifindex %d does not exist\n", vxlan->link); + return -ENODEV; } + + if (!tb[IFLA_MTU]) + dev->mtu = lowerdev->mtu - VXLAN_HEADROOM; } if (data[IFLA_VXLAN_TOS]) @@ -1045,6 +1118,13 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, if (data[IFLA_VXLAN_LIMIT]) vxlan->addrmax = nla_get_u32(data[IFLA_VXLAN_LIMIT]); + if (data[IFLA_VXLAN_PORT_RANGE]) { + const struct ifla_vxlan_port_range *p + = nla_data(data[IFLA_VXLAN_PORT_RANGE]); + vxlan->port_min = ntohs(p->low); + vxlan->port_max = ntohs(p->high); + } + err = register_netdevice(dev); if (!err) hlist_add_head_rcu(&vxlan->hlist, vni_head(net, vxlan->vni)); @@ -1073,12 +1153,17 @@ static size_t vxlan_get_size(const struct net_device *dev) nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LEARNING */ nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_AGEING */ nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LIMIT */ + nla_total_size(sizeof(struct ifla_vxlan_port_range)) + 0; } static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) { const struct vxlan_dev *vxlan = netdev_priv(dev); + struct ifla_vxlan_port_range ports = { + .low = htons(vxlan->port_min), + .high = htons(vxlan->port_max), + }; if (nla_put_u32(skb, IFLA_VXLAN_ID, vxlan->vni)) goto nla_put_failure; @@ -1099,6 +1184,9 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax)) goto nla_put_failure; + if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 9fd6d9a9942..9f31cfa56cc 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1804,7 +1804,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { int ret; struct ath5k_hw *ah = hw->priv; - struct ath5k_vif *avf = (void *)vif->drv_priv; + struct ath5k_vif *avf; struct sk_buff *skb; if (WARN_ON(!vif)) { @@ -1819,6 +1819,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) goto out; } + avf = (void *)vif->drv_priv; ath5k_txbuf_free_skb(ah, avf->bbuf); avf->bbuf->skb = skb; ret = ath5k_beacon_setup(ah, avf->bbuf); diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 76f07d8c272..1b48414dca9 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -120,7 +120,7 @@ static void ath9k_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) if (ath_tx_start(hw, skb, &txctl) != 0) { ath_dbg(common, XMIT, "CABQ TX failed\n"); - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); } } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f9a6ec5cf47..8e1559aba49 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1450,9 +1450,14 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + if (!ah->reset_power_on) + type = ATH9K_RESET_POWER_ON; + switch (type) { case ATH9K_RESET_POWER_ON: ret = ath9k_hw_set_reset_power_on(ah); + if (!ret) + ah->reset_power_on = true; break; case ATH9K_RESET_WARM: case ATH9K_RESET_COLD: diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 566a4ce4f15..dbc1b7a4cbf 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -741,6 +741,7 @@ struct ath_hw { u32 rfkill_polarity; u32 ah_flags; + bool reset_power_on; bool htc_reset_init; enum nl80211_iftype opmode; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 31ab82e3ba8..dd45edfa6ba 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -639,8 +639,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ath_err(common, "Unable to reset hardware; reset status %d (freq %u MHz)\n", r, curchan->center_freq); - spin_unlock_bh(&sc->sc_pcu_lock); - goto mutex_unlock; + ah->reset_power_on = false; } /* Setup our intr mask. */ @@ -665,11 +664,8 @@ static int ath9k_start(struct ieee80211_hw *hw) clear_bit(SC_OP_INVALID, &sc->sc_flags); sc->sc_ah->is_monitoring = false; - if (!ath_complete_reset(sc, false)) { - r = -EIO; - spin_unlock_bh(&sc->sc_pcu_lock); - goto mutex_unlock; - } + if (!ath_complete_reset(sc, false)) + ah->reset_power_on = false; if (ah->led_pin >= 0) { ath9k_hw_cfg_output(ah, ah->led_pin, @@ -688,12 +684,11 @@ static int ath9k_start(struct ieee80211_hw *hw) if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) common->bus_ops->extn_synch_en(common); -mutex_unlock: mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); - return r; + return 0; } static void ath9k_tx(struct ieee80211_hw *hw, @@ -770,7 +765,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, return; exit: - dev_kfree_skb_any(skb); + ieee80211_free_txskb(hw, skb); } static void ath9k_stop(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 0e630a99b68..f088f4bf9a2 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -324,6 +324,10 @@ static int ath_pci_suspend(struct device *device) static int ath_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); u32 val; /* @@ -335,6 +339,9 @@ static int ath_pci_resume(struct device *device) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + ath_pci_aspm_init(common); + ah->reset_power_on = false; + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 36618e3a5e6..378bd70256b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -66,8 +66,7 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct sk_buff *skb, - bool dequeue); + struct sk_buff *skb); enum { MCS_HT20, @@ -176,7 +175,15 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) fi = get_frame_info(skb); bf = fi->bf; - if (bf && fi->retries) { + if (!bf) { + bf = ath_tx_setup_buffer(sc, txq, tid, skb); + if (!bf) { + ieee80211_free_txskb(sc->hw, skb); + continue; + } + } + + if (fi->retries) { list_add_tail(&bf->list, &bf_head); ath_tx_update_baw(sc, tid, bf->bf_state.seqno); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); @@ -785,10 +792,13 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, fi = get_frame_info(skb); bf = fi->bf; if (!fi->bf) - bf = ath_tx_setup_buffer(sc, txq, tid, skb, true); + bf = ath_tx_setup_buffer(sc, txq, tid, skb); - if (!bf) + if (!bf) { + __skb_unlink(skb, &tid->buf_q); + ieee80211_free_txskb(sc->hw, skb); continue; + } bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR; seqno = bf->bf_state.seqno; @@ -1731,9 +1741,11 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, return; } - bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false); - if (!bf) + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + if (!bf) { + ieee80211_free_txskb(sc->hw, skb); return; + } bf->bf_state.bf_type = BUF_AMPDU; INIT_LIST_HEAD(&bf_head); @@ -1757,11 +1769,6 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf; bf = fi->bf; - if (!bf) - bf = ath_tx_setup_buffer(sc, txq, tid, skb, false); - - if (!bf) - return; INIT_LIST_HEAD(&bf_head); list_add_tail(&bf->list, &bf_head); @@ -1839,8 +1846,7 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct sk_buff *skb, - bool dequeue) + struct sk_buff *skb) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_frame_info *fi = get_frame_info(skb); @@ -1852,7 +1858,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, bf = ath_tx_get_buffer(sc); if (!bf) { ath_dbg(common, XMIT, "TX buffers are full\n"); - goto error; + return NULL; } ATH_TXBUF_RESET(bf); @@ -1881,18 +1887,12 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, ath_err(ath9k_hw_common(sc->sc_ah), "dma_mapping_error() on TX\n"); ath_tx_return_buffer(sc, bf); - goto error; + return NULL; } fi->bf = bf; return bf; - -error: - if (dequeue) - __skb_unlink(skb, &tid->buf_q); - dev_kfree_skb_any(skb); - return NULL; } /* FIXME: tx power */ @@ -1921,9 +1921,14 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, */ ath_tx_send_ampdu(sc, tid, skb, txctl); } else { - bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false); - if (!bf) + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + if (!bf) { + if (txctl->paprd) + dev_kfree_skb_any(skb); + else + ieee80211_free_txskb(sc->hw, skb); return; + } bf->bf_state.bfs_paprd = txctl->paprd; diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 2aa4a59c72c..2df17f1e49e 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -303,6 +303,7 @@ struct ar9170 { unsigned long queue_stop_timeout[__AR9170_NUM_TXQ]; unsigned long max_queue_stop_timeout[__AR9170_NUM_TXQ]; bool needs_full_reset; + bool force_usb_reset; atomic_t pending_restarts; /* interface mode settings |