diff options
Diffstat (limited to 'drivers')
282 files changed, 11980 insertions, 5854 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 1266ead6ace0..9e7d4e56c85b 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -107,3 +107,4 @@ obj-$(CONFIG_SSB) += ssb/ obj-$(CONFIG_VIRTIO) += virtio/ obj-$(CONFIG_STAGING) += staging/ obj-y += platform/ +obj-y += ieee802154/ diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 31693bc24444..965ece2c7e4d 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -34,13 +34,6 @@ new_skb(ulong len) skb_reset_mac_header(skb); skb_reset_network_header(skb); skb->protocol = __constant_htons(ETH_P_AOE); - skb->priority = 0; - skb->next = skb->prev = NULL; - - /* tell the network layer not to perform IP checksums - * or to get the NIC to do it - */ - skb->ip_summed = CHECKSUM_NONE; } return skb; } diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 0bbefba6469c..1df9dda2e377 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -40,7 +40,7 @@ #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> -#define VERSION "1.2" +#define VERSION "1.3" static int minor = MISC_DYNAMIC_MINOR; @@ -51,14 +51,8 @@ struct vhci_data { wait_queue_head_t read_wait; struct sk_buff_head readq; - - struct fasync_struct *fasync; }; -#define VHCI_FASYNC 0x0010 - -static struct miscdevice vhci_miscdev; - static int vhci_open_dev(struct hci_dev *hdev) { set_bit(HCI_RUNNING, &hdev->flags); @@ -105,9 +99,6 @@ static int vhci_send_frame(struct sk_buff *skb) memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); skb_queue_tail(&data->readq, skb); - if (data->flags & VHCI_FASYNC) - kill_fasync(&data->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&data->read_wait); return 0; @@ -179,41 +170,31 @@ static inline ssize_t vhci_put_user(struct vhci_data *data, static ssize_t vhci_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { - DECLARE_WAITQUEUE(wait, current); struct vhci_data *data = file->private_data; struct sk_buff *skb; ssize_t ret = 0; - add_wait_queue(&data->read_wait, &wait); while (count) { - set_current_state(TASK_INTERRUPTIBLE); - skb = skb_dequeue(&data->readq); - if (!skb) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - schedule(); - continue; + if (skb) { + ret = vhci_put_user(data, skb, buf, count); + if (ret < 0) + skb_queue_head(&data->readq, skb); + else + kfree_skb(skb); + break; } - if (access_ok(VERIFY_WRITE, buf, count)) - ret = vhci_put_user(data, skb, buf, count); - else - ret = -EFAULT; + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } - kfree_skb(skb); - break; + ret = wait_event_interruptible(data->read_wait, + !skb_queue_empty(&data->readq)); + if (ret < 0) + break; } - set_current_state(TASK_RUNNING); - remove_wait_queue(&data->read_wait, &wait); return ret; } @@ -223,9 +204,6 @@ static ssize_t vhci_write(struct file *file, { struct vhci_data *data = file->private_data; - if (!access_ok(VERIFY_READ, buf, count)) - return -EFAULT; - return vhci_get_user(data, buf, count); } @@ -259,11 +237,9 @@ static int vhci_open(struct inode *inode, struct file *file) skb_queue_head_init(&data->readq); init_waitqueue_head(&data->read_wait); - lock_kernel(); hdev = hci_alloc_dev(); if (!hdev) { kfree(data); - unlock_kernel(); return -ENOMEM; } @@ -284,12 +260,10 @@ static int vhci_open(struct inode *inode, struct file *file) BT_ERR("Can't register HCI device"); kfree(data); hci_free_dev(hdev); - unlock_kernel(); return -EBUSY; } file->private_data = data; - unlock_kernel(); return nonseekable_open(inode, file); } @@ -310,48 +284,25 @@ static int vhci_release(struct inode *inode, struct file *file) return 0; } -static int vhci_fasync(int fd, struct file *file, int on) -{ - struct vhci_data *data = file->private_data; - int err = 0; - - lock_kernel(); - err = fasync_helper(fd, file, on, &data->fasync); - if (err < 0) - goto out; - - if (on) - data->flags |= VHCI_FASYNC; - else - data->flags &= ~VHCI_FASYNC; - -out: - unlock_kernel(); - return err; -} - static const struct file_operations vhci_fops = { - .owner = THIS_MODULE, .read = vhci_read, .write = vhci_write, .poll = vhci_poll, .ioctl = vhci_ioctl, .open = vhci_open, .release = vhci_release, - .fasync = vhci_fasync, }; static struct miscdevice vhci_miscdev= { - .name = "vhci", - .fops = &vhci_fops, + .name = "vhci", + .fops = &vhci_fops, + .minor = MISC_DYNAMIC_MINOR, }; static int __init vhci_init(void) { BT_INFO("Virtual HCI driver ver %s", VERSION); - vhci_miscdev.minor = minor; - if (misc_register(&vhci_miscdev) < 0) { BT_ERR("Can't register misc device with minor %d", minor); return -EIO; @@ -369,9 +320,6 @@ static void __exit vhci_exit(void) module_init(vhci_init); module_exit(vhci_exit); -module_param(minor, int, 0444); -MODULE_PARM_DESC(minor, "Miscellaneous minor device number"); - MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig new file mode 100644 index 000000000000..25740bd54975 --- /dev/null +++ b/drivers/ieee802154/Kconfig @@ -0,0 +1,22 @@ +menuconfig IEEE802154_DRIVERS + bool "IEEE 802.15.4 drivers" + depends on NETDEVICES && IEEE802154 + default y + ---help--- + Say Y here to get to see options for IEEE 802.15.4 Low-Rate + Wireless Personal Area Network device drivers. This option alone + does not add any kernel code. + + If you say N, all options in this submenu will be skipped and + disabled. + +config IEEE802154_FAKEHARD + tristate "Fake LR-WPAN driver with several interconnected devices" + depends on IEEE802154_DRIVERS + ---help--- + Say Y here to enable the fake driver that serves as an example + of HardMAC device driver. + + This driver can also be built as a module. To do so say M here. + The module will be called 'fakehard'. + diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile new file mode 100644 index 000000000000..e0e8e1a184ff --- /dev/null +++ b/drivers/ieee802154/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o + +EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c new file mode 100644 index 000000000000..0384144c0b34 --- /dev/null +++ b/drivers/ieee802154/fakehard.c @@ -0,0 +1,270 @@ +/* + * Sample driver for HardMAC IEEE 802.15.4 devices + * + * Copyright (C) 2009 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com> + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> + +#include <net/ieee802154/af_ieee802154.h> +#include <net/ieee802154/netdevice.h> +#include <net/ieee802154/mac_def.h> +#include <net/ieee802154/nl802154.h> + +static u16 fake_get_pan_id(struct net_device *dev) +{ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + return 0xeba1; +} + +static u16 fake_get_short_addr(struct net_device *dev) +{ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + return 0x1; +} + +static u8 fake_get_dsn(struct net_device *dev) +{ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + return 0x00; /* DSN are implemented in HW, so return just 0 */ +} + +static u8 fake_get_bsn(struct net_device *dev) +{ + BUG_ON(dev->type != ARPHRD_IEEE802154); + + return 0x00; /* BSN are implemented in HW, so return just 0 */ +} + +static int fake_assoc_req(struct net_device *dev, + struct ieee802154_addr *addr, u8 channel, u8 cap) +{ + /* We simply emulate it here */ + return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev), + IEEE802154_SUCCESS); +} + +static int fake_assoc_resp(struct net_device *dev, + struct ieee802154_addr *addr, u16 short_addr, u8 status) +{ + return 0; +} + +static int fake_disassoc_req(struct net_device *dev, + struct ieee802154_addr *addr, u8 reason) +{ + return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS); +} + +static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, + u8 channel, + u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, + u8 coord_realign) +{ + return 0; +} + +static int fake_scan_req(struct net_device *dev, u8 type, u32 channels, + u8 duration) +{ + u8 edl[27] = {}; + return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type, + channels, + type == IEEE802154_MAC_SCAN_ED ? edl : NULL); +} + +static struct ieee802154_mlme_ops fake_mlme = { + .assoc_req = fake_assoc_req, + .assoc_resp = fake_assoc_resp, + .disassoc_req = fake_disassoc_req, + .start_req = fake_start_req, + .scan_req = fake_scan_req, + + .get_pan_id = fake_get_pan_id, + .get_short_addr = fake_get_short_addr, + .get_dsn = fake_get_dsn, + .get_bsn = fake_get_bsn, +}; + +static int ieee802154_fake_open(struct net_device *dev) +{ + netif_start_queue(dev); + return 0; +} + +static int ieee802154_fake_close(struct net_device *dev) +{ + netif_stop_queue(dev); + return 0; +} + +static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev) +{ + skb->iif = dev->ifindex; + skb->dev = dev; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + + dev->trans_start = jiffies; + + /* FIXME: do hardware work here ... */ + + return 0; +} + + +static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr, + int cmd) +{ + struct sockaddr_ieee802154 *sa = + (struct sockaddr_ieee802154 *)&ifr->ifr_addr; + u16 pan_id, short_addr; + + switch (cmd) { + case SIOCGIFADDR: + /* FIXME: fixed here, get from device IRL */ + pan_id = fake_get_pan_id(dev); + short_addr = fake_get_short_addr(dev); + if (pan_id == IEEE802154_PANID_BROADCAST || + short_addr == IEEE802154_ADDR_BROADCAST) + return -EADDRNOTAVAIL; + + sa->family = AF_IEEE802154; + sa->addr.addr_type = IEEE802154_ADDR_SHORT; + sa->addr.pan_id = pan_id; + sa->addr.short_addr = short_addr; + return 0; + } + return -ENOIOCTLCMD; +} + +static int ieee802154_fake_mac_addr(struct net_device *dev, void *p) +{ + return -EBUSY; /* HW address is built into the device */ +} + +static const struct net_device_ops fake_ops = { + .ndo_open = ieee802154_fake_open, + .ndo_stop = ieee802154_fake_close, + .ndo_start_xmit = ieee802154_fake_xmit, + .ndo_do_ioctl = ieee802154_fake_ioctl, + .ndo_set_mac_address = ieee802154_fake_mac_addr, +}; + + +static void ieee802154_fake_setup(struct net_device *dev) +{ + dev->addr_len = IEEE802154_ADDR_LEN; + memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN); + dev->features = NETIF_F_NO_CSUM; + dev->needed_tailroom = 2; /* FCS */ + dev->mtu = 127; + dev->tx_queue_len = 10; + dev->type = ARPHRD_IEEE802154; + dev->flags = IFF_NOARP | IFF_BROADCAST; + dev->watchdog_timeo = 0; +} + + +static int __devinit ieee802154fake_probe(struct platform_device *pdev) +{ + struct net_device *dev = + alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup); + int err; + + if (!dev) + return -ENOMEM; + + memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef", + dev->addr_len); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + + dev->netdev_ops = &fake_ops; + dev->ml_priv = &fake_mlme; + + /* + * If the name is a format string the caller wants us to do a + * name allocation. + */ + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto out; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + + platform_set_drvdata(pdev, dev); + + err = register_netdev(dev); + if (err < 0) + goto out; + + + dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n"); + return 0; + +out: + unregister_netdev(dev); + return err; +} + +static int __devexit ieee802154fake_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + unregister_netdev(dev); + free_netdev(dev); + return 0; +} + +static struct platform_device *ieee802154fake_dev; + +static struct platform_driver ieee802154fake_driver = { + .probe = ieee802154fake_probe, + .remove = __devexit_p(ieee802154fake_remove), + .driver = { + .name = "ieee802154hardmac", + .owner = THIS_MODULE, + }, +}; + +static __init int fake_init(void) +{ + ieee802154fake_dev = platform_device_register_simple( + "ieee802154hardmac", -1, NULL, 0); + return platform_driver_register(&ieee802154fake_driver); +} + +static __exit void fake_exit(void) +{ + platform_driver_unregister(&ieee802154fake_driver); + platform_device_unregister(ieee802154fake_dev); +} + +module_init(fake_init); +module_exit(fake_exit); +MODULE_LICENSE("GPL"); + diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 4248c3139364..181b1f32325f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1394,8 +1394,8 @@ void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, struct ipoib_dev_priv *priv = netdev_priv(dev); int e = skb_queue_empty(&priv->cm.skb_queue); - if (skb->dst) - skb->dst->ops->update_pmtu(skb->dst, mtu); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); skb_queue_tail(&priv->cm.skb_queue, skb); if (e) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index ab2c192c76bc..e319d91f60a6 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -561,7 +561,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) struct ipoib_neigh *neigh; unsigned long flags; - neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev); + neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour, skb->dev); if (!neigh) { ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); @@ -570,9 +570,9 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&priv->lock, flags); - path = __path_find(dev, skb->dst->neighbour->ha + 4); + path = __path_find(dev, skb_dst(skb)->neighbour->ha + 4); if (!path) { - path = path_rec_create(dev, skb->dst->neighbour->ha + 4); + path = path_rec_create(dev, skb_dst(skb)->neighbour->ha + 4); if (!path) goto err_path; @@ -605,7 +605,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) goto err_drop; } } else - ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha)); + ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha)); } else { neigh->ah = NULL; @@ -635,15 +635,15 @@ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev) struct ipoib_dev_priv *priv = netdev_priv(skb->dev); /* Look up path record for unicasts */ - if (skb->dst->neighbour->ha[4] != 0xff) { + if (skb_dst(skb)->neighbour->ha[4] != 0xff) { neigh_add_path(skb, dev); return; } /* Add in the P_Key for multicasts */ - skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; - skb->dst->neighbour->ha[9] = priv->pkey & 0xff; - ipoib_mcast_send(dev, skb->dst->neighbour->ha + 4, skb); + skb_dst(skb)->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; + skb_dst(skb)->neighbour->ha[9] = priv->pkey & 0xff; + ipoib_mcast_send(dev, skb_dst(skb)->neighbour->ha + 4, skb); } static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, @@ -708,16 +708,16 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) struct ipoib_neigh *neigh; unsigned long flags; - if (likely(skb->dst && skb->dst->neighbour)) { - if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) { + if (likely(skb_dst(skb) && skb_dst(skb)->neighbour)) { + if (unlikely(!*to_ipoib_neigh(skb_dst(skb)->neighbour))) { ipoib_path_lookup(skb, dev); return NETDEV_TX_OK; } - neigh = *to_ipoib_neigh(skb->dst->neighbour); + neigh = *to_ipoib_neigh(skb_dst(skb)->neighbour); if (unlikely((memcmp(&neigh->dgid.raw, - skb->dst->neighbour->ha + 4, + skb_dst(skb)->neighbour->ha + 4, sizeof(union ib_gid))) || (neigh->dev != dev))) { spin_lock_irqsave(&priv->lock, flags); @@ -743,7 +743,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } } else if (neigh->ah) { - ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha)); + ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha)); return NETDEV_TX_OK; } @@ -772,7 +772,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) if ((be16_to_cpup((__be16 *) skb->data) != ETH_P_ARP) && (be16_to_cpup((__be16 *) skb->data) != ETH_P_RARP)) { ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x %pI6\n", - skb->dst ? "neigh" : "dst", + skb_dst(skb) ? "neigh" : "dst", be16_to_cpup((__be16 *) skb->data), IPOIB_QPN(phdr->hwaddr), phdr->hwaddr + 4); @@ -817,7 +817,7 @@ static int ipoib_hard_header(struct sk_buff *skb, * destination address onto the front of the skb so we can * figure out where to send the packet later. */ - if ((!skb->dst || !skb->dst->neighbour) && daddr) { + if ((!skb_dst(skb) || !skb_dst(skb)->neighbour) && daddr) { struct ipoib_pseudoheader *phdr = (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr); memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); @@ -1053,6 +1053,7 @@ static void ipoib_setup(struct net_device *dev) dev->tx_queue_len = ipoib_sendq_size * 2; dev->features = (NETIF_F_VLAN_CHALLENGED | NETIF_F_HIGHDMA); + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 425e31112ed7..a0e97532e714 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -261,7 +261,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, skb->dev = dev; - if (!skb->dst || !skb->dst->neighbour) { + if (!skb_dst(skb) || !skb_dst(skb)->neighbour) { /* put pseudoheader back on for next time */ skb_push(skb, sizeof (struct ipoib_pseudoheader)); } @@ -707,10 +707,10 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) out: if (mcast && mcast->ah) { - if (skb->dst && - skb->dst->neighbour && - !*to_ipoib_neigh(skb->dst->neighbour)) { - struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour, + if (skb_dst(skb) && + skb_dst(skb)->neighbour && + !*to_ipoib_neigh(skb_dst(skb)->neighbour)) { + struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour, skb->dev); if (neigh) { diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c index 29419a8d31dc..16f2e465e5f9 100644 --- a/drivers/isdn/capi/capiutil.c +++ b/drivers/isdn/capi/capiutil.c @@ -490,7 +490,14 @@ static void pars_2_message(_cmsg * cmsg) } } -/*-------------------------------------------------------*/ +/** + * capi_cmsg2message() - assemble CAPI 2.0 message from _cmsg structure + * @cmsg: _cmsg structure + * @msg: buffer for assembled message + * + * Return value: 0 for success + */ + unsigned capi_cmsg2message(_cmsg * cmsg, u8 * msg) { cmsg->m = msg; @@ -553,7 +560,14 @@ static void message_2_pars(_cmsg * cmsg) } } -/*-------------------------------------------------------*/ +/** + * capi_message2cmsg() - disassemble CAPI 2.0 message into _cmsg structure + * @cmsg: _cmsg structure + * @msg: buffer for assembled message + * + * Return value: 0 for success + */ + unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg) { memset(cmsg, 0, sizeof(_cmsg)); @@ -573,7 +587,18 @@ unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg) return 0; } -/*-------------------------------------------------------*/ +/** + * capi_cmsg_header() - initialize header part of _cmsg structure + * @cmsg: _cmsg structure + * @_ApplId: ApplID field value + * @_Command: Command field value + * @_Subcommand: Subcommand field value + * @_Messagenumber: Message Number field value + * @_Controller: Controller/PLCI/NCCI field value + * + * Return value: 0 for success + */ + unsigned capi_cmsg_header(_cmsg * cmsg, u16 _ApplId, u8 _Command, u8 _Subcommand, u16 _Messagenumber, u32 _Controller) @@ -641,6 +666,14 @@ static char *mnames[] = [0x4e] = "MANUFACTURER_RESP" }; +/** + * capi_cmd2str() - convert CAPI 2.0 command/subcommand number to name + * @cmd: command number + * @subcmd: subcommand number + * + * Return value: static string, NULL if command/subcommand unknown + */ + char *capi_cmd2str(u8 cmd, u8 subcmd) { return mnames[command_2_index(cmd, subcmd)]; @@ -879,6 +912,11 @@ init: return cdb; } +/** + * cdebbuf_free() - free CAPI debug buffer + * @cdb: buffer to free + */ + void cdebbuf_free(_cdebbuf *cdb) { if (likely(cdb == g_debbuf)) { @@ -891,6 +929,16 @@ void cdebbuf_free(_cdebbuf *cdb) } +/** + * capi_message2str() - format CAPI 2.0 message for printing + * @msg: CAPI 2.0 message + * + * Allocates a CAPI debug buffer and fills it with a printable representation + * of the CAPI 2.0 message in @msg. + * Return value: allocated debug buffer, NULL on error + * The returned buffer should be freed by a call to cdebbuf_free() after use. + */ + _cdebbuf *capi_message2str(u8 * msg) { _cdebbuf *cdb; @@ -926,10 +974,23 @@ _cdebbuf *capi_message2str(u8 * msg) return cdb; } +/** + * capi_cmsg2str() - format _cmsg structure for printing + * @cmsg: _cmsg structure + * + * Allocates a CAPI debug buffer and fills it with a printable representation + * of the CAPI 2.0 message stored in @cmsg by a previous call to + * capi_cmsg2message() or capi_message2cmsg(). + * Return value: allocated debug buffer, NULL on error + * The returned buffer should be freed by a call to cdebbuf_free() after use. + */ + _cdebbuf *capi_cmsg2str(_cmsg * cmsg) { _cdebbuf *cdb; + if (!cmsg->m) + return NULL; /* no message */ cdb = cdebbuf_alloc(); if (!cdb) return NULL; diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index f33170368cd1..57d26360f64e 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -377,14 +377,14 @@ void capi_ctr_ready(struct capi_ctr * card) EXPORT_SYMBOL(capi_ctr_ready); /** - * capi_ctr_reseted() - signal CAPI controller reset + * capi_ctr_down() - signal CAPI controller not ready * @card: controller descriptor structure. * * Called by hardware driver to signal that the controller is down and * unavailable for use. */ -void capi_ctr_reseted(struct capi_ctr * card) +void capi_ctr_down(struct capi_ctr * card) { u16 appl; @@ -413,7 +413,7 @@ void capi_ctr_reseted(struct capi_ctr * card) notify_push(KCI_CONTRDOWN, card->cnr, 0, 0); } -EXPORT_SYMBOL(capi_ctr_reseted); +EXPORT_SYMBOL(capi_ctr_down); /** * capi_ctr_suspend_output() - suspend controller @@ -517,7 +517,7 @@ EXPORT_SYMBOL(attach_capi_ctr); int detach_capi_ctr(struct capi_ctr *card) { if (card->cardstate != CARD_DETECTED) - capi_ctr_reseted(card); + capi_ctr_down(card); ncards--; diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index abf05ec31760..a7c0083e78a7 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -330,7 +330,7 @@ void b1_reset_ctr(struct capi_ctr *ctrl) spin_lock_irqsave(&card->lock, flags); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } void b1_register_appl(struct capi_ctr *ctrl, diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index da34b98e3de7..0e84aaae43fd 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -759,7 +759,7 @@ void b1dma_reset_ctr(struct capi_ctr *ctrl) memset(cinfo->version, 0, sizeof(cinfo->version)); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 9df1d3f66c87..6833301a45fc 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -681,7 +681,7 @@ static irqreturn_t c4_handle_interrupt(avmcard *card) spin_lock_irqsave(&card->lock, flags); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_reseted(&cinfo->capi_ctrl); + capi_ctr_down(&cinfo->capi_ctrl); } card->nlogcontr = 0; return IRQ_HANDLED; @@ -909,7 +909,7 @@ static void c4_reset_ctr(struct capi_ctr *ctrl) for (i=0; i < card->nr_controllers; i++) { cinfo = &card->ctrlinfo[i]; memset(cinfo->version, 0, sizeof(cinfo->version)); - capi_ctr_reseted(&cinfo->capi_ctrl); + capi_ctr_down(&cinfo->capi_ctrl); } card->nlogcontr = 0; } diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c index e7724493738c..1c53fd49adb6 100644 --- a/drivers/isdn/hardware/avm/t1isa.c +++ b/drivers/isdn/hardware/avm/t1isa.c @@ -339,7 +339,7 @@ static void t1isa_reset_ctr(struct capi_ctr *ctrl) spin_lock_irqsave(&card->lock, flags); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } static void t1isa_remove(struct pci_dev *pdev) diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c index 53f6ad1235db..4ffaa14b9fc4 100644 --- a/drivers/isdn/hysdn/hycapi.c +++ b/drivers/isdn/hysdn/hycapi.c @@ -67,7 +67,7 @@ hycapi_reset_ctr(struct capi_ctr *ctrl) printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n"); #endif capilib_release(&cinfo->ncci_head); - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } /****************************** @@ -347,7 +347,7 @@ int hycapi_capi_stop(hysdn_card *card) if(cinfo) { ctrl = &cinfo->capi_ctrl; /* ctrl->suspend_output(ctrl); */ - capi_ctr_reseted(ctrl); + capi_ctr_down(ctrl); } return 0; } diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 8d9aa49de145..d2137efbd455 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -480,9 +480,13 @@ static int pnp_registered; #ifdef CONFIG_EISA static struct eisa_device_id el3_eisa_ids[] = { + { "TCM5090" }, + { "TCM5091" }, { "TCM5092" }, { "TCM5093" }, + { "TCM5094" }, { "TCM5095" }, + { "TCM5098" }, { "" } }; MODULE_DEVICE_TABLE(eisa, el3_eisa_ids); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 43a5254df98d..3f739cfd92fa 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1001,7 +1001,7 @@ config SMC911X config SMSC911X tristate "SMSC LAN911x/LAN921x families embedded ethernet support" - depends on ARM || SUPERH + depends on ARM || SUPERH || BLACKFIN select CRC32 select MII select PHYLIB @@ -1723,6 +1723,11 @@ config TLAN Please email feedback to <torben.mathiasen@compaq.com>. +config KS8842 + tristate "Micrel KSZ8842" + help + This platform driver is for Micrel KSZ8842 chip. + config VIA_RHINE tristate "VIA Rhine support" depends on NET_PCI && PCI @@ -1859,8 +1864,8 @@ config 68360_ENET the Motorola 68360 processor. config FEC - bool "FEC ethernet controller (of ColdFire CPUs)" - depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27 + bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)" + depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27 || ARCH_MX35 help Say Y here if you want to use the built-in 10/100 Fast ethernet controller on some Motorola ColdFire and Freescale i.MX processors. @@ -2720,6 +2725,8 @@ source "drivers/net/wan/Kconfig" source "drivers/atm/Kconfig" +source "drivers/ieee802154/Kconfig" + source "drivers/s390/net/Kconfig" config XEN_NETDEV_FRONTEND diff --git a/drivers/net/Makefile b/drivers/net/Makefile index f07a1e956417..1c378dd5933e 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_TC35815) += tc35815.o obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SKY2) += sky2.o obj-$(CONFIG_SKFP) += skfp/ +obj-$(CONFIG_KS8842) += ks8842.o obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o @@ -105,7 +106,7 @@ obj-$(CONFIG_HAMACHI) += hamachi.o obj-$(CONFIG_NET) += Space.o loopback.o obj-$(CONFIG_SEEQ8005) += seeq8005.o obj-$(CONFIG_NET_SB1000) += sb1000.o -obj-$(CONFIG_MAC8390) += mac8390.o 8390.o +obj-$(CONFIG_MAC8390) += mac8390.o obj-$(CONFIG_APNE) += apne.o 8390.o obj-$(CONFIG_PCMCIA_PCNET) += 8390.o obj-$(CONFIG_HP100) += hp100.o diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 57bc71527850..08419ee10290 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2573,7 +2573,6 @@ restart: netif_wake_queue(dev); } - dev->trans_start = jiffies; return NETDEV_TX_OK; overflow: diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index f939e92fcf8a..78cea5e80b1d 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -39,6 +39,7 @@ static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n"; static struct ipddp_route *ipddp_route_list; +static DEFINE_SPINLOCK(ipddp_route_lock); #ifdef CONFIG_IPDDP_ENCAP static int ipddp_mode = IPDDP_ENCAP; @@ -50,7 +51,7 @@ static int ipddp_mode = IPDDP_DECAP; static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); static int ipddp_create(struct ipddp_route *new_rt); static int ipddp_delete(struct ipddp_route *rt); -static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt); +static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt); static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static const struct net_device_ops ipddp_netdev_ops = { @@ -114,11 +115,13 @@ static struct net_device * __init ipddp_init(void) */ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) { - __be32 paddr = ((struct rtable*)skb->dst)->rt_gateway; + __be32 paddr = skb_rtable(skb)->rt_gateway; struct ddpehdr *ddp; struct ipddp_route *rt; struct atalk_addr *our_addr; + spin_lock(&ipddp_route_lock); + /* * Find appropriate route to use, based only on IP number. */ @@ -127,8 +130,10 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) if(rt->ip == paddr) break; } - if(rt == NULL) + if(rt == NULL) { + spin_unlock(&ipddp_route_lock); return 0; + } our_addr = atalk_find_dev_addr(rt->dev); @@ -174,6 +179,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) dev_kfree_skb(skb); + spin_unlock(&ipddp_route_lock); + return 0; } @@ -196,7 +203,9 @@ static int ipddp_create(struct ipddp_route *new_rt) return -ENETUNREACH; } - if (ipddp_find_route(rt)) { + spin_lock_bh(&ipddp_route_lock); + if (__ipddp_find_route(rt)) { + spin_unlock_bh(&ipddp_route_lock); kfree(rt); return -EEXIST; } @@ -204,6 +213,8 @@ static int ipddp_create(struct ipddp_route *new_rt) rt->next = ipddp_route_list; ipddp_route_list = rt; + spin_unlock_bh(&ipddp_route_lock); + return 0; } @@ -216,6 +227,7 @@ static int ipddp_delete(struct ipddp_route *rt) struct ipddp_route **r = &ipddp_route_list; struct ipddp_route *tmp; + spin_lock_bh(&ipddp_route_lock); while((tmp = *r) != NULL) { if(tmp->ip == rt->ip @@ -223,19 +235,21 @@ static int ipddp_delete(struct ipddp_route *rt) && tmp->at.s_node == rt->at.s_node) { *r = tmp->next; + spin_unlock_bh(&ipddp_route_lock); kfree(tmp); return 0; } r = &tmp->next; } + spin_unlock_bh(&ipddp_route_lock); return (-ENOENT); } /* * Find a routing entry, we only return a FULL match */ -static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt) +static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt) { struct ipddp_route *f; @@ -253,7 +267,7 @@ static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt) static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct ipddp_route __user *rt = ifr->ifr_data; - struct ipddp_route rcp; + struct ipddp_route rcp, rcp2, *rp; if(!capable(CAP_NET_ADMIN)) return -EPERM; @@ -267,9 +281,19 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return (ipddp_create(&rcp)); case SIOCFINDIPDDPRT: - if(copy_to_user(rt, ipddp_find_route(&rcp), sizeof(struct ipddp_route))) - return -EFAULT; - return 0; + spin_lock_bh(&ipddp_route_lock); + rp = __ipddp_find_route(&rcp); + if (rp) + memcpy(&rcp2, rp, sizeof(rcp2)); + spin_unlock_bh(&ipddp_route_lock); + + if (rp) { + if (copy_to_user(rt, &rcp2, + sizeof(struct ipddp_route))) + return -EFAULT; + return 0; + } else + return -ENOENT; case SIOCDELIPDDPRT: return (ipddp_delete(&rcp)); diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index b72b3d639f6e..fbf4645417d4 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -253,7 +253,7 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget) skb = dev_alloc_skb(length + 2); if (likely(skb != NULL)) { skb_reserve(skb, 2); - dma_sync_single(NULL, ep->descs->rdesc[entry].buf_addr, + dma_sync_single_for_cpu(NULL, ep->descs->rdesc[entry].buf_addr, length, DMA_FROM_DEVICE); skb_copy_to_linear_data(skb, ep->rx_buf[entry], length); skb_put(skb, length); @@ -331,7 +331,7 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) ep->descs->tdesc[entry].tdesc1 = TDESC1_EOF | (entry << 16) | (skb->len & 0xfff); skb_copy_and_csum_dev(skb, ep->tx_buf[entry]); - dma_sync_single(NULL, ep->descs->tdesc[entry].buf_addr, + dma_sync_single_for_cpu(NULL, ep->descs->tdesc[entry].buf_addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb(skb); diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index 322c49b908dc..1fcf8388b1c8 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -561,8 +561,8 @@ static int eth_poll(struct napi_struct *napi, int budget) dma_unmap_single(&dev->dev, desc->data - NET_IP_ALIGN, RX_BUFF_SIZE, DMA_FROM_DEVICE); #else - dma_sync_single(&dev->dev, desc->data - NET_IP_ALIGN, - RX_BUFF_SIZE, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(&dev->dev, desc->data - NET_IP_ALIGN, + RX_BUFF_SIZE, DMA_FROM_DEVICE); memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n], ALIGN(NET_IP_ALIGN + desc->pkt_len, 4) / 4); #endif diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c index 45c5b7332cd3..e4afbd628c23 100644 --- a/drivers/net/atl1c/atl1c_ethtool.c +++ b/drivers/net/atl1c/atl1c_ethtool.c @@ -271,7 +271,7 @@ static int atl1c_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) struct atl1c_adapter *adapter = netdev_priv(netdev); if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | - WAKE_MCAST | WAKE_BCAST | WAKE_MCAST)) + WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)) return -EOPNOTSUPP; /* these settings will always override what we currently have */ adapter->wol = 0; diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index fc1092b835d2..cd547a205fb9 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -164,6 +164,24 @@ static inline void atl1c_irq_reset(struct atl1c_adapter *adapter) } /* + * atl1c_wait_until_idle - wait up to AT_HW_MAX_IDLE_DELAY reads + * of the idle status register until the device is actually idle + */ +static u32 atl1c_wait_until_idle(struct atl1c_hw *hw) +{ + int timeout; + u32 data; + + for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { + AT_READ_REG(hw, REG_IDLE_STATUS, &data); + if ((data & IDLE_STATUS_MASK) == 0) + return 0; + msleep(1); + } + return data; +} + +/* * atl1c_phy_config - Timer Call-back * @data: pointer to netdev cast into an unsigned long */ @@ -1106,7 +1124,6 @@ static void atl1c_configure_dma(struct atl1c_adapter *adapter) static int atl1c_stop_mac(struct atl1c_hw *hw) { u32 data; - int timeout; AT_READ_REG(hw, REG_RXQ_CTRL, &data); data &= ~(RXQ1_CTRL_EN | RXQ2_CTRL_EN | @@ -1117,25 +1134,13 @@ static int atl1c_stop_mac(struct atl1c_hw *hw) data &= ~TXQ_CTRL_EN; AT_WRITE_REG(hw, REG_TWSI_CTRL, data); - for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { - AT_READ_REG(hw, REG_IDLE_STATUS, &data); - if ((data & (IDLE_STATUS_RXQ_NO_IDLE | - IDLE_STATUS_TXQ_NO_IDLE)) == 0) - break; - msleep(1); - } + atl1c_wait_until_idle(hw); AT_READ_REG(hw, REG_MAC_CTRL, &data); data &= ~(MAC_CTRL_TX_EN | MAC_CTRL_RX_EN); AT_WRITE_REG(hw, REG_MAC_CTRL, data); - for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { - AT_READ_REG(hw, REG_IDLE_STATUS, &data); - if ((data & IDLE_STATUS_MASK) == 0) - return 0; - msleep(1); - } - return data; + return (int)atl1c_wait_until_idle(hw); } static void atl1c_enable_rx_ctrl(struct atl1c_hw *hw) @@ -1178,8 +1183,6 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) { struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter; struct pci_dev *pdev = adapter->pdev; - u32 idle_status_data = 0; - int timeout = 0; int ret; AT_WRITE_REG(hw, REG_IMR, 0); @@ -1198,15 +1201,10 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) AT_WRITE_FLUSH(hw); msleep(10); /* Wait at least 10ms for All module to be Idle */ - for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { - AT_READ_REG(hw, REG_IDLE_STATUS, &idle_status_data); - if ((idle_status_data & IDLE_STATUS_MASK) == 0) - break; - msleep(1); - } - if (timeout >= AT_HW_MAX_IDLE_DELAY) { + + if (atl1c_wait_until_idle(hw)) { dev_err(&pdev->dev, - "MAC state machine cann't be idle since" + "MAC state machine can't be idle since" " disabled for 10ms second\n"); return -1; } @@ -2113,7 +2111,6 @@ static int atl1c_xmit_frame(struct sk_buff *skb, struct net_device *netdev) atl1c_tx_map(adapter, skb, tpd, type); atl1c_tx_queue(adapter, skb, tpd, type); - netdev->trans_start = jiffies; spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_OK; } diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index c271b7537fab..e1ae10cf30c1 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -37,6 +37,7 @@ char atl1e_driver_version[] = DRV_VERSION; */ static struct pci_device_id atl1e_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1E)}, + {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1066)}, /* required last entry */ { 0 } }; @@ -1893,7 +1894,7 @@ static int atl1e_xmit_frame(struct sk_buff *skb, struct net_device *netdev) atl1e_tx_map(adapter, skb, tpd); atl1e_tx_queue(adapter, tpd_req, tpd); - netdev->trans_start = jiffies; + netdev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_OK; } diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 13f0bdc32449..560f3873d347 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -82,6 +82,12 @@ #include "atl1.h" +#define ATLX_DRIVER_VERSION "2.1.3" +MODULE_AUTHOR("Xiong Huang <xiong.huang@atheros.com>, \ + Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(ATLX_DRIVER_VERSION); + /* Temporary hack for merging atl1 and atl2 */ #include "atlx.c" @@ -2431,7 +2437,6 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) atl1_tx_queue(adapter, count, ptpd); atl1_update_mailbox(adapter); mmiowb(); - netdev->trans_start = jiffies; return NETDEV_TX_OK; } diff --git a/drivers/net/atlx/atlx.h b/drivers/net/atlx/atlx.h index 297a03da6b7f..14054b75aa62 100644 --- a/drivers/net/atlx/atlx.h +++ b/drivers/net/atlx/atlx.h @@ -29,12 +29,6 @@ #include <linux/module.h> #include <linux/types.h> -#define ATLX_DRIVER_VERSION "2.1.3" -MODULE_AUTHOR("Xiong Huang <xiong.huang@atheros.com>, \ - Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(ATLX_DRIVER_VERSION); - #define ATLX_ERR_PHY 2 #define ATLX_ERR_PHY_SPEED 7 #define ATLX_ERR_PHY_RES 8 diff --git a/drivers/net/b44.c b/drivers/net/b44.c index b70b81ec34c3..36d4d377ec2f 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -782,7 +782,7 @@ static int b44_rx(struct b44 *bp, int budget) drop_it: b44_recycle_rx(bp, cons, bp->rx_prod); drop_it_no_recycle: - bp->stats.rx_dropped++; + bp->dev->stats.rx_dropped++; goto next_pkt; } @@ -1647,7 +1647,7 @@ static int b44_close(struct net_device *dev) static struct net_device_stats *b44_get_stats(struct net_device *dev) { struct b44 *bp = netdev_priv(dev); - struct net_device_stats *nstat = &bp->stats; + struct net_device_stats *nstat = &dev->stats; struct b44_hw_stats *hwstat = &bp->hw_stats; /* Convert HW stats into netdevice stats. */ diff --git a/drivers/net/b44.h b/drivers/net/b44.h index e678498de6db..0443f6801f60 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -384,7 +384,6 @@ struct b44 { struct timer_list timer; - struct net_device_stats stats; struct b44_hw_stats hw_stats; struct ssb_device *sdev; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index ae2f6b58ba25..66bb56874d9b 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -168,6 +168,7 @@ static void netdev_stats_update(struct be_adapter *adapter) struct be_port_rxf_stats *port_stats = &rxf_stats->port[adapter->port_num]; struct net_device_stats *dev_stats = &adapter->stats.net_stats; + struct be_erx_stats *erx_stats = &hw_stats->erx; dev_stats->rx_packets = port_stats->rx_total_frames; dev_stats->tx_packets = port_stats->tx_unicastframes + @@ -181,29 +182,33 @@ static void netdev_stats_update(struct be_adapter *adapter) dev_stats->rx_errors = port_stats->rx_crc_errors + port_stats->rx_alignment_symbol_errors + port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; - - /* packet transmit problems */ - dev_stats->tx_errors = 0; - - /* no space in linux buffers */ - dev_stats->rx_dropped = 0; - - /* no space available in linux */ - dev_stats->tx_dropped = 0; - - dev_stats->multicast = port_stats->tx_multicastframes; - dev_stats->collisions = 0; + port_stats->rx_out_range_errors + + port_stats->rx_frame_too_long + + port_stats->rx_dropped_too_small + + port_stats->rx_dropped_too_short + + port_stats->rx_dropped_header_too_small + + port_stats->rx_dropped_tcp_length + + port_stats->rx_dropped_runt + + port_stats->rx_tcp_checksum_errs + + port_stats->rx_ip_checksum_errs + + port_stats->rx_udp_checksum_errs; + + /* no space in linux buffers: best possible approximation */ + dev_stats->rx_dropped = erx_stats->rx_drops_no_fragments[0]; /* detailed rx errors */ dev_stats->rx_length_errors = port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; + port_stats->rx_out_range_errors + + port_stats->rx_frame_too_long; + /* receive ring buffer overflow */ dev_stats->rx_over_errors = 0; + dev_stats->rx_crc_errors = port_stats->rx_crc_errors; /* frame alignment errors */ dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors; + /* receiver fifo overrun */ /* drops_no_pbuf is no per i/f, it's per BE card */ dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow + @@ -211,6 +216,16 @@ static void netdev_stats_update(struct be_adapter *adapter) rxf_stats->rx_drops_no_pbuf; /* receiver missed packetd */ dev_stats->rx_missed_errors = 0; + + /* packet transmit problems */ + dev_stats->tx_errors = 0; + + /* no space available in linux */ + dev_stats->tx_dropped = 0; + + dev_stats->multicast = port_stats->tx_multicastframes; + dev_stats->collisions = 0; + /* detailed tx_errors */ dev_stats->tx_aborted_errors = 0; dev_stats->tx_carrier_errors = 0; @@ -337,13 +352,10 @@ static void be_tx_stats_update(struct be_adapter *adapter, /* Determine number of WRB entries needed to xmit data in an skb */ static u32 wrb_cnt_for_skb(struct sk_buff *skb, bool *dummy) { - int cnt = 0; - while (skb) { - if (skb->len > skb->data_len) - cnt++; - cnt += skb_shinfo(skb)->nr_frags; - skb = skb_shinfo(skb)->frag_list; - } + int cnt = (skb->len > skb->data_len); + + cnt += skb_shinfo(skb)->nr_frags; + /* to account for hdr wrb */ cnt++; if (cnt & 1) { @@ -409,31 +421,28 @@ static int make_tx_wrbs(struct be_adapter *adapter, hdr = queue_head_node(txq); queue_head_inc(txq); - while (skb) { - if (skb->len > skb->data_len) { - int len = skb->len - skb->data_len; - busaddr = pci_map_single(pdev, skb->data, len, - PCI_DMA_TODEVICE); - wrb = queue_head_node(txq); - wrb_fill(wrb, busaddr, len); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - queue_head_inc(txq); - copied += len; - } + if (skb->len > skb->data_len) { + int len = skb->len - skb->data_len; + busaddr = pci_map_single(pdev, skb->data, len, + PCI_DMA_TODEVICE); + wrb = queue_head_node(txq); + wrb_fill(wrb, busaddr, len); + be_dws_cpu_to_le(wrb, sizeof(*wrb)); + queue_head_inc(txq); + copied += len; + } - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - struct skb_frag_struct *frag = - &skb_shinfo(skb)->frags[i]; - busaddr = pci_map_page(pdev, frag->page, - frag->page_offset, - frag->size, PCI_DMA_TODEVICE); - wrb = queue_head_node(txq); - wrb_fill(wrb, busaddr, frag->size); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - queue_head_inc(txq); - copied += frag->size; - } - skb = skb_shinfo(skb)->frag_list; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + struct skb_frag_struct *frag = + &skb_shinfo(skb)->frags[i]; + busaddr = pci_map_page(pdev, frag->page, + frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + wrb = queue_head_node(txq); + wrb_fill(wrb, busaddr, frag->size); + be_dws_cpu_to_le(wrb, sizeof(*wrb)); + queue_head_inc(txq); + copied += frag->size; } if (dummy_wrb) { @@ -478,8 +487,6 @@ static int be_xmit(struct sk_buff *skb, struct net_device *netdev) be_txq_notify(&adapter->ctrl, txq->id, wrb_cnt); - netdev->trans_start = jiffies; - be_tx_stats_update(adapter, wrb_cnt, copied, stopped); return NETDEV_TX_OK; } @@ -736,7 +743,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, if (pktsize <= rx_frag_size) { BUG_ON(num_rcvd != 1); - return; + goto done; } /* More frags present for this completion */ @@ -758,6 +765,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, memset(page_info, 0, sizeof(*page_info)); } +done: be_rx_stats_update(adapter, pktsize, num_rcvd); return; } @@ -868,12 +876,19 @@ static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter) be_dws_le_to_cpu(rxcp, sizeof(*rxcp)); - rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0; - queue_tail_inc(&adapter->rx_obj.cq); return rxcp; } +/* To reset the valid bit, we need to reset the whole word as + * when walking the queue the valid entries are little-endian + * and invalid entries are host endian + */ +static inline void be_rx_compl_reset(struct be_eth_rx_compl *rxcp) +{ + rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0; +} + static inline struct page *be_alloc_pages(u32 size) { gfp_t alloc_flags = GFP_ATOMIC; @@ -1005,6 +1020,7 @@ static void be_rx_q_clean(struct be_adapter *adapter) /* First cleanup pending rx completions */ while ((rxcp = be_rx_compl_get(adapter)) != NULL) { be_rx_compl_discard(adapter, rxcp); + be_rx_compl_reset(rxcp); be_cq_notify(&adapter->ctrl, rx_cq->id, true, 1); } @@ -1040,8 +1056,13 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) struct be_queue_info *q; q = &adapter->tx_obj.q; - if (q->created) + if (q->created) { be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_TXQ); + + /* No more tx completions can be rcvd now; clean up if there + * are any pending completions or pending tx requests */ + be_tx_q_clean(adapter); + } be_queue_free(adapter, q); q = &adapter->tx_obj.cq; @@ -1049,10 +1070,6 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ); be_queue_free(adapter, q); - /* No more tx completions can be rcvd now; clean up if there are - * any pending completions or pending tx requests */ - be_tx_q_clean(adapter); - q = &adapter->tx_eq.q; if (q->created) be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ); @@ -1286,6 +1303,8 @@ int be_poll_rx(struct napi_struct *napi, int budget) be_rx_compl_process_lro(adapter, rxcp); else be_rx_compl_process(adapter, rxcp); + + be_rx_compl_reset(rxcp); } lro_flush_all(&adapter->rx_obj.lro_mgr); @@ -1541,7 +1560,7 @@ static int be_close(struct net_device *netdev) struct be_eq_obj *tx_eq = &adapter->tx_eq; int vec; - cancel_delayed_work(&adapter->work); + cancel_delayed_work_sync(&adapter->work); netif_stop_queue(netdev); netif_carrier_off(netdev); diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 9f971ed6b58d..c15fc281f79f 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -194,13 +194,13 @@ static int desc_list_init(void) struct dma_descriptor *b = &(r->desc_b); /* allocate a new skb for next time receive */ - new_skb = dev_alloc_skb(PKT_BUF_SZ + 2); + new_skb = dev_alloc_skb(PKT_BUF_SZ + NET_IP_ALIGN); if (!new_skb) { printk(KERN_NOTICE DRV_NAME ": init: low on mem - packet dropped\n"); goto init_error; } - skb_reserve(new_skb, 2); + skb_reserve(new_skb, NET_IP_ALIGN); r->skb = new_skb; /* @@ -566,9 +566,9 @@ static void adjust_tx_list(void) */ if (current_tx_ptr->next->next == tx_list_head) { while (tx_list_head->status.status_word == 0) { - mdelay(1); + udelay(10); if (tx_list_head->status.status_word != 0 - || !(bfin_read_DMA2_IRQ_STATUS() & 0x08)) { + || !(bfin_read_DMA2_IRQ_STATUS() & DMA_RUN)) { goto adjust_head; } if (timeout_cnt-- < 0) { @@ -606,93 +606,41 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { u16 *data; - + u32 data_align = (unsigned long)(skb->data) & 0x3; current_tx_ptr->skb = skb; - if (ANOMALY_05000285) { - /* - * TXDWA feature is not avaible to older revision < 0.3 silicon - * of BF537 - * - * Only if data buffer is ODD WORD alignment, we do not - * need to memcpy - */ - u32 data_align = (u32)(skb->data) & 0x3; - if (data_align == 0x2) { - /* move skb->data to current_tx_ptr payload */ - data = (u16 *)(skb->data) - 1; - *data = (u16)(skb->len); - current_tx_ptr->desc_a.start_addr = (u32)data; - /* this is important! */ - blackfin_dcache_flush_range((u32)data, - (u32)((u8 *)data + skb->len + 4)); - } else { - *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); - memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, - skb->len); - current_tx_ptr->desc_a.start_addr = - (u32)current_tx_ptr->packet; - if (current_tx_ptr->status.status_word != 0) - current_tx_ptr->status.status_word = 0; - blackfin_dcache_flush_range( - (u32)current_tx_ptr->packet, - (u32)(current_tx_ptr->packet + skb->len + 2)); - } + if (data_align == 0x2) { + /* move skb->data to current_tx_ptr payload */ + data = (u16 *)(skb->data) - 1; + *data = (u16)(skb->len); + current_tx_ptr->desc_a.start_addr = (u32)data; + /* this is important! */ + blackfin_dcache_flush_range((u32)data, + (u32)((u8 *)data + skb->len + 4)); } else { - /* - * TXDWA feature is avaible to revision < 0.3 silicon of - * BF537 and always avaible to BF52x - */ - u32 data_align = (u32)(skb->data) & 0x3; - if (data_align == 0x0) { - u16 sysctl = bfin_read_EMAC_SYSCTL(); - sysctl |= TXDWA; - bfin_write_EMAC_SYSCTL(sysctl); - - /* move skb->data to current_tx_ptr payload */ - data = (u16 *)(skb->data) - 2; - *data = (u16)(skb->len); - current_tx_ptr->desc_a.start_addr = (u32)data; - /* this is important! */ - blackfin_dcache_flush_range( - (u32)data, - (u32)((u8 *)data + skb->len + 4)); - } else if (data_align == 0x2) { - u16 sysctl = bfin_read_EMAC_SYSCTL(); - sysctl &= ~TXDWA; - bfin_write_EMAC_SYSCTL(sysctl); - - /* move skb->data to current_tx_ptr payload */ - data = (u16 *)(skb->data) - 1; - *data = (u16)(skb->len); - current_tx_ptr->desc_a.start_addr = (u32)data; - /* this is important! */ - blackfin_dcache_flush_range( - (u32)data, - (u32)((u8 *)data + skb->len + 4)); - } else { - u16 sysctl = bfin_read_EMAC_SYSCTL(); - sysctl &= ~TXDWA; - bfin_write_EMAC_SYSCTL(sysctl); - - *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); - memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, - skb->len); - current_tx_ptr->desc_a.start_addr = - (u32)current_tx_ptr->packet; - if (current_tx_ptr->status.status_word != 0) - current_tx_ptr->status.status_word = 0; - blackfin_dcache_flush_range( - (u32)current_tx_ptr->packet, - (u32)(current_tx_ptr->packet + skb->len + 2)); - } + *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len); + memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data, + skb->len); + current_tx_ptr->desc_a.start_addr = + (u32)current_tx_ptr->packet; + if (current_tx_ptr->status.status_word != 0) + current_tx_ptr->status.status_word = 0; + blackfin_dcache_flush_range( + (u32)current_tx_ptr->packet, + (u32)(current_tx_ptr->packet + skb->len + 2)); } + /* make sure the internal data buffers in the core are drained + * so that the DMA descriptors are completely written when the + * DMA engine goes to fetch them below + */ + SSYNC(); + /* enable this packet's dma */ current_tx_ptr->desc_a.config |= DMAEN; /* tx dma is running, just return */ - if (bfin_read_DMA2_IRQ_STATUS() & 0x08) + if (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN) goto out; /* tx dma is not running */ @@ -718,7 +666,7 @@ static void bfin_mac_rx(struct net_device *dev) /* allocate a new skb for next time receive */ skb = current_rx_ptr->skb; - new_skb = dev_alloc_skb(PKT_BUF_SZ + 2); + new_skb = dev_alloc_skb(PKT_BUF_SZ + NET_IP_ALIGN); if (!new_skb) { printk(KERN_NOTICE DRV_NAME ": rx: low on mem - packet dropped\n"); @@ -726,7 +674,7 @@ static void bfin_mac_rx(struct net_device *dev) goto out; } /* reserve 2 bytes for RXDWA padding */ - skb_reserve(new_skb, 2); + skb_reserve(new_skb, NET_IP_ALIGN); current_rx_ptr->skb = new_skb; current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2; @@ -979,22 +927,7 @@ static int bfin_mac_open(struct net_device *dev) return 0; } -static const struct net_device_ops bfin_mac_netdev_ops = { - .ndo_open = bfin_mac_open, - .ndo_stop = bfin_mac_close, - .ndo_start_xmit = bfin_mac_hard_start_xmit, - .ndo_set_mac_address = bfin_mac_set_mac_address, - .ndo_tx_timeout = bfin_mac_timeout, - .ndo_set_multicast_list = bfin_mac_set_multicast_list, - .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = eth_change_mtu, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = bfin_mac_poll, -#endif -}; - /* - * * this makes the board clean up everything that it can * and not talk to the outside world. Caused by * an 'ifconfig ethX down' @@ -1019,11 +952,26 @@ static int bfin_mac_close(struct net_device *dev) return 0; } +static const struct net_device_ops bfin_mac_netdev_ops = { + .ndo_open = bfin_mac_open, + .ndo_stop = bfin_mac_close, + .ndo_start_xmit = bfin_mac_hard_start_xmit, + .ndo_set_mac_address = bfin_mac_set_mac_address, + .ndo_tx_timeout = bfin_mac_timeout, + .ndo_set_multicast_list = bfin_mac_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = bfin_mac_poll, +#endif +}; + static int __devinit bfin_mac_probe(struct platform_device *pdev) { struct net_device *ndev; struct bfin_mac_local *lp; - int rc, i; + struct platform_device *pd; + int rc; ndev = alloc_etherdev(sizeof(struct bfin_mac_local)); if (!ndev) { @@ -1048,13 +996,6 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) goto out_err_probe_mac; } - /* set the GPIO pins to Ethernet mode */ - rc = peripheral_request_list(pin_req, DRV_NAME); - if (rc) { - dev_err(&pdev->dev, "Requesting peripherals failed!\n"); - rc = -EFAULT; - goto out_err_setup_pin_mux; - } /* * Is it valid? (Did bootloader initialize it?) @@ -1070,26 +1011,14 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) setup_mac_addr(ndev->dev_addr); - /* MDIO bus initial */ - lp->mii_bus = mdiobus_alloc(); - if (lp->mii_bus == NULL) - goto out_err_mdiobus_alloc; - - lp->mii_bus->priv = ndev; - lp->mii_bus->read = bfin_mdiobus_read; - lp->mii_bus->write = bfin_mdiobus_write; - lp->mii_bus->reset = bfin_mdiobus_reset; - lp->mii_bus->name = "bfin_mac_mdio"; - snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "0"); - lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); - for (i = 0; i < PHY_MAX_ADDR; ++i) - lp->mii_bus->irq[i] = PHY_POLL; - - rc = mdiobus_register(lp->mii_bus); - if (rc) { - dev_err(&pdev->dev, "Cannot register MDIO bus!\n"); - goto out_err_mdiobus_register; + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "Cannot get platform device bfin_mii_bus!\n"); + rc = -ENODEV; + goto out_err_probe_mac; } + pd = pdev->dev.platform_data; + lp->mii_bus = platform_get_drvdata(pd); + lp->mii_bus->priv = ndev; rc = mii_probe(ndev); if (rc) { @@ -1108,7 +1037,7 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) /* now, enable interrupts */ /* register irq handler */ rc = request_irq(IRQ_MAC_RX, bfin_mac_interrupt, - IRQF_DISABLED | IRQF_SHARED, "EMAC_RX", ndev); + IRQF_DISABLED, "EMAC_RX", ndev); if (rc) { dev_err(&pdev->dev, "Cannot request Blackfin MAC RX IRQ!\n"); rc = -EBUSY; @@ -1131,11 +1060,8 @@ out_err_reg_ndev: out_err_request_irq: out_err_mii_probe: mdiobus_unregister(lp->mii_bus); -out_err_mdiobus_register: mdiobus_free(lp->mii_bus); -out_err_mdiobus_alloc: peripheral_free_list(pin_req); -out_err_setup_pin_mux: out_err_probe_mac: platform_set_drvdata(pdev, NULL); free_netdev(ndev); @@ -1150,8 +1076,7 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - mdiobus_unregister(lp->mii_bus); - mdiobus_free(lp->mii_bus); + lp->mii_bus->priv = NULL; unregister_netdev(ndev); @@ -1189,6 +1114,74 @@ static int bfin_mac_resume(struct platform_device *pdev) #define bfin_mac_resume NULL #endif /* CONFIG_PM */ +static int __devinit bfin_mii_bus_probe(struct platform_device *pdev) +{ + struct mii_bus *miibus; + int rc, i; + + /* + * We are setting up a network card, + * so set the GPIO pins to Ethernet mode + */ + rc = peripheral_request_list(pin_req, DRV_NAME); + if (rc) { + dev_err(&pdev->dev, "Requesting peripherals failed!\n"); + return rc; + } + + rc = -ENOMEM; + miibus = mdiobus_alloc(); + if (miibus == NULL) + goto out_err_alloc; + miibus->read = bfin_mdiobus_read; + miibus->write = bfin_mdiobus_write; + miibus->reset = bfin_mdiobus_reset; + + miibus->parent = &pdev->dev; + miibus->name = "bfin_mii_bus"; + snprintf(miibus->id, MII_BUS_ID_SIZE, "0"); + miibus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + if (miibus->irq == NULL) + goto out_err_alloc; + for (i = 0; i < PHY_MAX_ADDR; ++i) + miibus->irq[i] = PHY_POLL; + + rc = mdiobus_register(miibus); + if (rc) { + dev_err(&pdev->dev, "Cannot register MDIO bus!\n"); + goto out_err_mdiobus_register; + } + + platform_set_drvdata(pdev, miibus); + return 0; + +out_err_mdiobus_register: + mdiobus_free(miibus); +out_err_alloc: + peripheral_free_list(pin_req); + + return rc; +} + +static int __devexit bfin_mii_bus_remove(struct platform_device *pdev) +{ + struct mii_bus *miibus = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + mdiobus_unregister(miibus); + mdiobus_free(miibus); + peripheral_free_list(pin_req); + return 0; +} + +static struct platform_driver bfin_mii_bus_driver = { + .probe = bfin_mii_bus_probe, + .remove = __devexit_p(bfin_mii_bus_remove), + .driver = { + .name = "bfin_mii_bus", + .owner = THIS_MODULE, + }, +}; + static struct platform_driver bfin_mac_driver = { .probe = bfin_mac_probe, .remove = __devexit_p(bfin_mac_remove), @@ -1202,7 +1195,11 @@ static struct platform_driver bfin_mac_driver = { static int __init bfin_mac_init(void) { - return platform_driver_register(&bfin_mac_driver); + int ret; + ret = platform_driver_register(&bfin_mii_bus_driver); + if (!ret) + return platform_driver_register(&bfin_mac_driver); + return -ENODEV; } module_init(bfin_mac_init); @@ -1210,6 +1207,7 @@ module_init(bfin_mac_init); static void __exit bfin_mac_cleanup(void) { platform_driver_unregister(&bfin_mac_driver); + platform_driver_unregister(&bfin_mii_bus_driver); } module_exit(bfin_mac_cleanup); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index c37acc1d10ac..f99e17e0a319 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -48,6 +48,7 @@ #include <linux/cache.h> #include <linux/firmware.h> #include <linux/log2.h> +#include <linux/list.h> #include "bnx2.h" #include "bnx2_fw.h" @@ -545,8 +546,7 @@ bnx2_free_rx_mem(struct bnx2 *bp) rxr->rx_desc_mapping[j]); rxr->rx_desc_ring[j] = NULL; } - if (rxr->rx_buf_ring) - vfree(rxr->rx_buf_ring); + vfree(rxr->rx_buf_ring); rxr->rx_buf_ring = NULL; for (j = 0; j < bp->rx_max_pg_ring; j++) { @@ -556,8 +556,7 @@ bnx2_free_rx_mem(struct bnx2 *bp) rxr->rx_pg_desc_mapping[j]); rxr->rx_pg_desc_ring[j] = NULL; } - if (rxr->rx_pg_ring) - vfree(rxr->rx_pg_ring); + vfree(rxr->rx_pg_ring); rxr->rx_pg_ring = NULL; } } @@ -3310,7 +3309,7 @@ bnx2_set_rx_mode(struct net_device *dev) { struct bnx2 *bp = netdev_priv(dev); u32 rx_mode, sort_mode; - struct dev_addr_list *uc_ptr; + struct netdev_hw_addr *ha; int i; if (!netif_running(dev)) @@ -3369,21 +3368,19 @@ bnx2_set_rx_mode(struct net_device *dev) sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN; } - uc_ptr = NULL; if (dev->uc_count > BNX2_MAX_UNICAST_ADDRESSES) { rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS; sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN | BNX2_RPM_SORT_USER0_PROM_VLAN; } else if (!(dev->flags & IFF_PROMISC)) { - uc_ptr = dev->uc_list; - /* Add all entries into to the match filter list */ - for (i = 0; i < dev->uc_count; i++) { - bnx2_set_mac_addr(bp, uc_ptr->da_addr, + i = 0; + list_for_each_entry(ha, &dev->uc_list, list) { + bnx2_set_mac_addr(bp, ha->addr, i + BNX2_START_UNICAST_ADDRESS_INDEX); sort_mode |= (1 << (i + BNX2_START_UNICAST_ADDRESS_INDEX)); - uc_ptr = uc_ptr->next; + i++; } } @@ -5488,7 +5485,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) dev_kfree_skb(skb); return -EIO; } - map = skb_shinfo(skb)->dma_maps[0]; + map = skb_shinfo(skb)->dma_head; REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); @@ -6168,7 +6165,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) } sp = skb_shinfo(skb); - mapping = sp->dma_maps[0]; + mapping = sp->dma_head; tx_buf = &txr->tx_buf_ring[ring_prod]; tx_buf->skb = skb; @@ -6192,7 +6189,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd = &txr->tx_desc_ring[ring_prod]; len = frag->size; - mapping = sp->dma_maps[i + 1]; + mapping = sp->dma_maps[i]; txbd->tx_bd_haddr_hi = (u64) mapping >> 32; txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff; @@ -6211,7 +6208,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) mmiowb(); txr->tx_prod = prod; - dev->trans_start = jiffies; if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) { netif_tx_stop_queue(txq); diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index e01539c33b8a..fbf1352e9c1c 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -10617,7 +10617,6 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) mmiowb(); fp->tx_bd_prod += nbd; - dev->trans_start = jiffies; if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) { /* We want bnx2x_tx_int to "see" the updated tx_bd_prod diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 92a9d69c5650..2f4329e91a4c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2405,8 +2405,7 @@ static void bond_miimon_commit(struct bonding *bond) bond_3ad_handle_link_change(slave, BOND_LINK_DOWN); - if (bond->params.mode == BOND_MODE_TLB || - bond->params.mode == BOND_MODE_ALB) + if (bond_is_lb(bond)) bond_alb_handle_link_change(bond, slave, BOND_LINK_DOWN); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 3a1b7b04eb79..5fb861a08664 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1541,6 +1541,7 @@ int bond_create_sysfs(void) printk(KERN_ERR "network device named %s already exists in sysfs", class_attr_bonding_masters.attr.name); + ret = 0; } return ret; diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index ca849d2adf98..41ceca12c68f 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -286,8 +286,7 @@ static inline unsigned long slave_last_rx(struct bonding *bond, static inline void bond_set_slave_inactive_flags(struct slave *slave) { struct bonding *bond = netdev_priv(slave->dev->master); - if (bond->params.mode != BOND_MODE_TLB && - bond->params.mode != BOND_MODE_ALB) + if (!bond_is_lb(bond)) slave->state = BOND_STATE_BACKUP; slave->dev->priv_flags |= IFF_SLAVE_INACTIVE; if (slave_do_arp_validate(bond, slave)) diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index cfd6c5a285fa..d5e18812bf49 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -51,6 +51,15 @@ config CAN_SJA1000_PLATFORM boards from Phytec (http://www.phytec.de) like the PCM027, PCM038. +config CAN_SJA1000_OF_PLATFORM + depends on CAN_SJA1000 && PPC_OF + tristate "Generic OF Platform Bus based SJA1000 driver" + ---help--- + This driver adds support for the SJA1000 chips connected to + the OpenFirmware "platform bus" found on embedded systems with + OpenFirmware bindings, e.g. if you have a PowerPC based system + you may want to enable this option. + config CAN_EMS_PCI tristate "EMS CPC-PCI and CPC-PCIe Card" depends on PCI && CAN_SJA1000 diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 52b0e7d8901d..574daddc21bf 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -477,7 +477,7 @@ int open_candev(struct net_device *dev) return 0; } -EXPORT_SYMBOL(open_candev); +EXPORT_SYMBOL_GPL(open_candev); /* * Common close function for cleanup before the device gets closed. diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index d6c631f9e665..9d0c08da273c 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000.o obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o +obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c index 3cd2ff9165e3..121b64101d72 100644 --- a/drivers/net/can/sja1000/ems_pci.c +++ b/drivers/net/can/sja1000/ems_pci.c @@ -99,25 +99,21 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl); */ static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port) { - return readb((void __iomem *)card->base_addr - + (port * EMS_PCI_PORT_BYTES)); + return readb(card->base_addr + (port * EMS_PCI_PORT_BYTES)); } -static u8 ems_pci_read_reg(const struct net_device *dev, int port) +static u8 ems_pci_read_reg(const struct sja1000_priv *priv, int port) { - return readb((void __iomem *)dev->base_addr - + (port * EMS_PCI_PORT_BYTES)); + return readb(priv->reg_base + (port * EMS_PCI_PORT_BYTES)); } -static void ems_pci_write_reg(const struct net_device *dev, int port, u8 val) +static void ems_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val) { - writeb(val, (void __iomem *)dev->base_addr - + (port * EMS_PCI_PORT_BYTES)); + writeb(val, priv->reg_base + (port * EMS_PCI_PORT_BYTES)); } -static void ems_pci_post_irq(const struct net_device *dev) +static void ems_pci_post_irq(const struct sja1000_priv *priv) { - struct sja1000_priv *priv = netdev_priv(dev); struct ems_pci_card *card = (struct ems_pci_card *)priv->priv; /* reset int flag of pita */ @@ -129,17 +125,17 @@ static void ems_pci_post_irq(const struct net_device *dev) * Check if a CAN controller is present at the specified location * by trying to set 'em into the PeliCAN mode */ -static inline int ems_pci_check_chan(struct net_device *dev) +static inline int ems_pci_check_chan(const struct sja1000_priv *priv) { unsigned char res; /* Make sure SJA1000 is in reset mode */ - ems_pci_write_reg(dev, REG_MOD, 1); + ems_pci_write_reg(priv, REG_MOD, 1); - ems_pci_write_reg(dev, REG_CDR, CDR_PELICAN); + ems_pci_write_reg(priv, REG_CDR, CDR_PELICAN); /* read reset-values */ - res = ems_pci_read_reg(dev, REG_CDR); + res = ems_pci_read_reg(priv, REG_CDR); if (res == CDR_PELICAN) return 1; @@ -218,14 +214,12 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE); if (card->conf_addr == NULL) { err = -ENOMEM; - goto failure_cleanup; } card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE); if (card->base_addr == NULL) { err = -ENOMEM; - goto failure_cleanup; } @@ -239,7 +233,6 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, ems_pci_readb(card, 3) != 0xCB || ems_pci_readb(card, 4) != 0x11) { dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n"); - err = -ENODEV; goto failure_cleanup; } @@ -260,12 +253,11 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, priv->irq_flags = IRQF_SHARED; dev->irq = pdev->irq; - dev->base_addr = (unsigned long)(card->base_addr - + EMS_PCI_CAN_BASE_OFFSET - + (i * EMS_PCI_CAN_CTRL_SIZE)); + priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET + + (i * EMS_PCI_CAN_CTRL_SIZE); /* Check if channel is present */ - if (ems_pci_check_chan(dev)) { + if (ems_pci_check_chan(priv)) { priv->read_reg = ems_pci_read_reg; priv->write_reg = ems_pci_write_reg; priv->post_irq = ems_pci_post_irq; @@ -289,9 +281,8 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev, card->channels++; - dev_info(&pdev->dev, "Channel #%d at %#lX, irq %d\n", - i + 1, dev->base_addr, - dev->irq); + dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d\n", + i + 1, priv->reg_base, dev->irq); } else { free_sja1000dev(dev); } diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c index 00830b358c4f..7dd7769b9713 100644 --- a/drivers/net/can/sja1000/kvaser_pci.c +++ b/drivers/net/can/sja1000/kvaser_pci.c @@ -117,14 +117,15 @@ static struct pci_device_id kvaser_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, kvaser_pci_tbl); -static u8 kvaser_pci_read_reg(const struct net_device *dev, int port) +static u8 kvaser_pci_read_reg(const struct sja1000_priv *priv, int port) { - return ioread8((void __iomem *)(dev->base_addr + port)); + return ioread8(priv->reg_base + port); } -static void kvaser_pci_write_reg(const struct net_device *dev, int port, u8 val) +static void kvaser_pci_write_reg(const struct sja1000_priv *priv, + int port, u8 val) { - iowrite8(val, (void __iomem *)(dev->base_addr + port)); + iowrite8(val, priv->reg_base + port); } static void kvaser_pci_disable_irq(struct net_device *dev) @@ -199,7 +200,7 @@ static void kvaser_pci_del_chan(struct net_device *dev) } unregister_sja1000dev(dev); - pci_iounmap(board->pci_dev, (void __iomem *)dev->base_addr); + pci_iounmap(board->pci_dev, priv->reg_base); pci_iounmap(board->pci_dev, board->conf_addr); pci_iounmap(board->pci_dev, board->res_addr); @@ -210,7 +211,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, struct net_device **master_dev, void __iomem *conf_addr, void __iomem *res_addr, - unsigned long base_addr) + void __iomem *base_addr) { struct net_device *dev; struct sja1000_priv *priv; @@ -252,7 +253,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, board->xilinx_ver = master_board->xilinx_ver; } - dev->base_addr = base_addr + channel * KVASER_PCI_PORT_BYTES; + priv->reg_base = base_addr + channel * KVASER_PCI_PORT_BYTES; priv->read_reg = kvaser_pci_read_reg; priv->write_reg = kvaser_pci_write_reg; @@ -267,8 +268,8 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, init_step = 4; - dev_info(&pdev->dev, "base_addr=%#lx conf_addr=%p irq=%d\n", - dev->base_addr, board->conf_addr, dev->irq); + dev_info(&pdev->dev, "reg_base=%p conf_addr=%p irq=%d\n", + priv->reg_base, board->conf_addr, dev->irq); SET_NETDEV_DEV(dev, &pdev->dev); @@ -343,7 +344,7 @@ static int __devinit kvaser_pci_init_one(struct pci_dev *pdev, for (i = 0; i < no_channels; i++) { err = kvaser_pci_add_chan(pdev, i, &master_dev, conf_addr, res_addr, - (unsigned long)base_addr); + base_addr); if (err) goto failure_cleanup; } diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 05b38dde648e..571f133a8fec 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -89,7 +89,7 @@ static int sja1000_probe_chip(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - if (dev->base_addr && (priv->read_reg(dev, 0) == 0xFF)) { + if (priv->reg_base && (priv->read_reg(priv, 0) == 0xFF)) { printk(KERN_INFO "%s: probing @0x%lX failed\n", DRV_NAME, dev->base_addr); return 0; @@ -100,11 +100,11 @@ static int sja1000_probe_chip(struct net_device *dev) static void set_reset_mode(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - unsigned char status = priv->read_reg(dev, REG_MOD); + unsigned char status = priv->read_reg(priv, REG_MOD); int i; /* disable interrupts */ - priv->write_reg(dev, REG_IER, IRQ_OFF); + priv->write_reg(priv, REG_IER, IRQ_OFF); for (i = 0; i < 100; i++) { /* check reset bit */ @@ -113,9 +113,9 @@ static void set_reset_mode(struct net_device *dev) return; } - priv->write_reg(dev, REG_MOD, MOD_RM); /* reset chip */ + priv->write_reg(priv, REG_MOD, MOD_RM); /* reset chip */ udelay(10); - status = priv->read_reg(dev, REG_MOD); + status = priv->read_reg(priv, REG_MOD); } dev_err(dev->dev.parent, "setting SJA1000 into reset mode failed!\n"); @@ -124,7 +124,7 @@ static void set_reset_mode(struct net_device *dev) static void set_normal_mode(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); - unsigned char status = priv->read_reg(dev, REG_MOD); + unsigned char status = priv->read_reg(priv, REG_MOD); int i; for (i = 0; i < 100; i++) { @@ -132,14 +132,14 @@ static void set_normal_mode(struct net_device *dev) if ((status & MOD_RM) == 0) { priv->can.state = CAN_STATE_ERROR_ACTIVE; /* enable all interrupts */ - priv->write_reg(dev, REG_IER, IRQ_ALL); + priv->write_reg(priv, REG_IER, IRQ_ALL); return; } /* set chip to normal mode */ - priv->write_reg(dev, REG_MOD, 0x00); + priv->write_reg(priv, REG_MOD, 0x00); udelay(10); - status = priv->read_reg(dev, REG_MOD); + status = priv->read_reg(priv, REG_MOD); } dev_err(dev->dev.parent, "setting SJA1000 into normal mode failed!\n"); @@ -154,9 +154,9 @@ static void sja1000_start(struct net_device *dev) set_reset_mode(dev); /* Clear error counters and error code capture */ - priv->write_reg(dev, REG_TXERR, 0x0); - priv->write_reg(dev, REG_RXERR, 0x0); - priv->read_reg(dev, REG_ECC); + priv->write_reg(priv, REG_TXERR, 0x0); + priv->write_reg(priv, REG_RXERR, 0x0); + priv->read_reg(priv, REG_ECC); /* leave reset mode */ set_normal_mode(dev); @@ -198,8 +198,8 @@ static int sja1000_set_bittiming(struct net_device *dev) dev_info(dev->dev.parent, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); - priv->write_reg(dev, REG_BTR0, btr0); - priv->write_reg(dev, REG_BTR1, btr1); + priv->write_reg(priv, REG_BTR0, btr0); + priv->write_reg(priv, REG_BTR1, btr1); return 0; } @@ -217,20 +217,20 @@ static void chipset_init(struct net_device *dev) struct sja1000_priv *priv = netdev_priv(dev); /* set clock divider and output control register */ - priv->write_reg(dev, REG_CDR, priv->cdr | CDR_PELICAN); + priv->write_reg(priv, REG_CDR, priv->cdr | CDR_PELICAN); /* set acceptance filter (accept all) */ - priv->write_reg(dev, REG_ACCC0, 0x00); - priv->write_reg(dev, REG_ACCC1, 0x00); - priv->write_reg(dev, REG_ACCC2, 0x00); - priv->write_reg(dev, REG_ACCC3, 0x00); + priv->write_reg(priv, REG_ACCC0, 0x00); + priv->write_reg(priv, REG_ACCC1, 0x00); + priv->write_reg(priv, REG_ACCC2, 0x00); + priv->write_reg(priv, REG_ACCC3, 0x00); - priv->write_reg(dev, REG_ACCM0, 0xFF); - priv->write_reg(dev, REG_ACCM1, 0xFF); - priv->write_reg(dev, REG_ACCM2, 0xFF); - priv->write_reg(dev, REG_ACCM3, 0xFF); + priv->write_reg(priv, REG_ACCM0, 0xFF); + priv->write_reg(priv, REG_ACCM1, 0xFF); + priv->write_reg(priv, REG_ACCM2, 0xFF); + priv->write_reg(priv, REG_ACCM3, 0xFF); - priv->write_reg(dev, REG_OCR, priv->ocr | OCR_MODE_NORMAL); + priv->write_reg(priv, REG_OCR, priv->ocr | OCR_MODE_NORMAL); } /* @@ -261,27 +261,27 @@ static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev) if (id & CAN_EFF_FLAG) { fi |= FI_FF; dreg = EFF_BUF; - priv->write_reg(dev, REG_FI, fi); - priv->write_reg(dev, REG_ID1, (id & 0x1fe00000) >> (5 + 16)); - priv->write_reg(dev, REG_ID2, (id & 0x001fe000) >> (5 + 8)); - priv->write_reg(dev, REG_ID3, (id & 0x00001fe0) >> 5); - priv->write_reg(dev, REG_ID4, (id & 0x0000001f) << 3); + priv->write_reg(priv, REG_FI, fi); + priv->write_reg(priv, REG_ID1, (id & 0x1fe00000) >> (5 + 16)); + priv->write_reg(priv, REG_ID2, (id & 0x001fe000) >> (5 + 8)); + priv->write_reg(priv, REG_ID3, (id & 0x00001fe0) >> 5); + priv->write_reg(priv, REG_ID4, (id & 0x0000001f) << 3); } else { dreg = SFF_BUF; - priv->write_reg(dev, REG_FI, fi); - priv->write_reg(dev, REG_ID1, (id & 0x000007f8) >> 3); - priv->write_reg(dev, REG_ID2, (id & 0x00000007) << 5); + priv->write_reg(priv, REG_FI, fi); + priv->write_reg(priv, REG_ID1, (id & 0x000007f8) >> 3); + priv->write_reg(priv, REG_ID2, (id & 0x00000007) << 5); } for (i = 0; i < dlc; i++) - priv->write_reg(dev, dreg++, cf->data[i]); + priv->write_reg(priv, dreg++, cf->data[i]); stats->tx_bytes += dlc; dev->trans_start = jiffies; can_put_echo_skb(skb, dev, 0); - priv->write_reg(dev, REG_CMR, CMD_TR); + priv->write_reg(priv, REG_CMR, CMD_TR); return 0; } @@ -304,22 +304,22 @@ static void sja1000_rx(struct net_device *dev) skb->dev = dev; skb->protocol = htons(ETH_P_CAN); - fi = priv->read_reg(dev, REG_FI); + fi = priv->read_reg(priv, REG_FI); dlc = fi & 0x0F; if (fi & FI_FF) { /* extended frame format (EFF) */ dreg = EFF_BUF; - id = (priv->read_reg(dev, REG_ID1) << (5 + 16)) - | (priv->read_reg(dev, REG_ID2) << (5 + 8)) - | (priv->read_reg(dev, REG_ID3) << 5) - | (priv->read_reg(dev, REG_ID4) >> 3); + id = (priv->read_reg(priv, REG_ID1) << (5 + 16)) + | (priv->read_reg(priv, REG_ID2) << (5 + 8)) + | (priv->read_reg(priv, REG_ID3) << 5) + | (priv->read_reg(priv, REG_ID4) >> 3); id |= CAN_EFF_FLAG; } else { /* standard frame format (SFF) */ dreg = SFF_BUF; - id = (priv->read_reg(dev, REG_ID1) << 3) - | (priv->read_reg(dev, REG_ID2) >> 5); + id = (priv->read_reg(priv, REG_ID1) << 3) + | (priv->read_reg(priv, REG_ID2) >> 5); } if (fi & FI_RTR) @@ -330,13 +330,13 @@ static void sja1000_rx(struct net_device *dev) cf->can_id = id; cf->can_dlc = dlc; for (i = 0; i < dlc; i++) - cf->data[i] = priv->read_reg(dev, dreg++); + cf->data[i] = priv->read_reg(priv, dreg++); while (i < 8) cf->data[i++] = 0; /* release receive buffer */ - priv->write_reg(dev, REG_CMR, CMD_RRB); + priv->write_reg(priv, REG_CMR, CMD_RRB); netif_rx(skb); @@ -371,7 +371,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; stats->rx_errors++; - priv->write_reg(dev, REG_CMR, CMD_CDO); /* clear bit */ + priv->write_reg(priv, REG_CMR, CMD_CDO); /* clear bit */ } if (isrc & IRQ_EI) { @@ -392,7 +392,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) priv->can.can_stats.bus_error++; stats->rx_errors++; - ecc = priv->read_reg(dev, REG_ECC); + ecc = priv->read_reg(priv, REG_ECC); cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; @@ -426,7 +426,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) if (isrc & IRQ_ALI) { /* arbitration lost interrupt */ dev_dbg(dev->dev.parent, "arbitration lost interrupt\n"); - alc = priv->read_reg(dev, REG_ALC); + alc = priv->read_reg(priv, REG_ALC); priv->can.can_stats.arbitration_lost++; stats->rx_errors++; cf->can_id |= CAN_ERR_LOSTARB; @@ -435,8 +435,8 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING || state == CAN_STATE_ERROR_PASSIVE)) { - uint8_t rxerr = priv->read_reg(dev, REG_RXERR); - uint8_t txerr = priv->read_reg(dev, REG_TXERR); + uint8_t rxerr = priv->read_reg(priv, REG_RXERR); + uint8_t txerr = priv->read_reg(priv, REG_TXERR); cf->can_id |= CAN_ERR_CRTL; if (state == CAN_STATE_ERROR_WARNING) { priv->can.can_stats.error_warning++; @@ -471,15 +471,15 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) int n = 0; /* Shared interrupts and IRQ off? */ - if (priv->read_reg(dev, REG_IER) == IRQ_OFF) + if (priv->read_reg(priv, REG_IER) == IRQ_OFF) return IRQ_NONE; if (priv->pre_irq) - priv->pre_irq(dev); + priv->pre_irq(priv); - while ((isrc = priv->read_reg(dev, REG_IR)) && (n < SJA1000_MAX_IRQ)) { + while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) { n++; - status = priv->read_reg(dev, REG_SR); + status = priv->read_reg(priv, REG_SR); if (isrc & IRQ_WUI) dev_warn(dev->dev.parent, "wakeup interrupt\n"); @@ -494,7 +494,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) /* receive interrupt */ while (status & SR_RBS) { sja1000_rx(dev); - status = priv->read_reg(dev, REG_SR); + status = priv->read_reg(priv, REG_SR); } } if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) { @@ -505,7 +505,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) } if (priv->post_irq) - priv->post_irq(dev); + priv->post_irq(priv); if (n >= SJA1000_MAX_IRQ) dev_dbg(dev->dev.parent, "%d messages handled in ISR", n); @@ -532,8 +532,8 @@ static int sja1000_open(struct net_device *dev) err = request_irq(dev->irq, &sja1000_interrupt, priv->irq_flags, dev->name, (void *)dev); if (err) { - return -EAGAIN; close_candev(dev); + return -EAGAIN; } } diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h index ccd302887964..302d2c763ad7 100644 --- a/drivers/net/can/sja1000/sja1000.h +++ b/drivers/net/can/sja1000/sja1000.h @@ -155,14 +155,15 @@ struct sja1000_priv { struct sk_buff *echo_skb; /* the lower-layer is responsible for appropriate locking */ - u8 (*read_reg) (const struct net_device *dev, int reg); - void (*write_reg) (const struct net_device *dev, int reg, u8 val); - void (*pre_irq) (const struct net_device *dev); - void (*post_irq) (const struct net_device *dev); + u8 (*read_reg) (const struct sja1000_priv *priv, int reg); + void (*write_reg) (const struct sja1000_priv *priv, int reg, u8 val); + void (*pre_irq) (const struct sja1000_priv *priv); + void (*post_irq) (const struct sja1000_priv *priv); void *priv; /* for board-specific data */ struct net_device *dev; + void __iomem *reg_base; /* ioremap'ed address to registers */ unsigned long irq_flags; /* for request_irq() */ u16 flags; /* custom mode flags */ diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c new file mode 100644 index 000000000000..3373560405ba --- /dev/null +++ b/drivers/net/can/sja1000/sja1000_of_platform.c @@ -0,0 +1,235 @@ +/* + * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus + * + * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This is a generic driver for SJA1000 chips on the OpenFirmware platform + * bus found on embedded PowerPC systems. You need a SJA1000 CAN node + * definition in your flattened device tree source (DTS) file similar to: + * + * can@3,100 { + * compatible = "nxp,sja1000"; + * reg = <3 0x100 0x80>; + * interrupts = <2 0>; + * interrupt-parent = <&mpic>; + * nxp,external-clock-frequency = <16000000>; + * }; + * + * See "Documentation/powerpc/dts-bindings/can/sja1000.txt" for further + * information. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/netdevice.h> +#include <linux/delay.h> +#include <linux/can.h> +#include <linux/can/dev.h> + +#include <linux/of_platform.h> +#include <asm/prom.h> + +#include "sja1000.h" + +#define DRV_NAME "sja1000_of_platform" + +MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); +MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus"); +MODULE_LICENSE("GPL v2"); + +#define SJA1000_OFP_CAN_CLOCK (16000000 / 2) + +#define SJA1000_OFP_OCR OCR_TX0_PULLDOWN +#define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF) + +static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg) +{ + return in_8(priv->reg_base + reg); +} + +static void sja1000_ofp_write_reg(const struct sja1000_priv *priv, + int reg, u8 val) +{ + out_8(priv->reg_base + reg, val); +} + +static int __devexit sja1000_ofp_remove(struct of_device *ofdev) +{ + struct net_device *dev = dev_get_drvdata(&ofdev->dev); + struct sja1000_priv *priv = netdev_priv(dev); + struct device_node *np = ofdev->node; + struct resource res; + + dev_set_drvdata(&ofdev->dev, NULL); + + unregister_sja1000dev(dev); + free_sja1000dev(dev); + iounmap(priv->reg_base); + irq_dispose_mapping(dev->irq); + + of_address_to_resource(np, 0, &res); + release_mem_region(res.start, resource_size(&res)); + + return 0; +} + +static int __devinit sja1000_ofp_probe(struct of_device *ofdev, + const struct of_device_id *id) +{ + struct device_node *np = ofdev->node; + struct net_device *dev; + struct sja1000_priv *priv; + struct resource res; + const u32 *prop; + int err, irq, res_size, prop_size; + void __iomem *base; + + err = of_address_to_resource(np, 0, &res); + if (err) { + dev_err(&ofdev->dev, "invalid address\n"); + return err; + } + + res_size = resource_size(&res); + + if (!request_mem_region(res.start, res_size, DRV_NAME)) { + dev_err(&ofdev->dev, "couldn't request %#llx..%#llx\n", + (unsigned long long)res.start, + (unsigned long long)res.end); + return -EBUSY; + } + + base = ioremap_nocache(res.start, res_size); + if (!base) { + dev_err(&ofdev->dev, "couldn't ioremap %#llx..%#llx\n", + (unsigned long long)res.start, + (unsigned long long)res.end); + err = -ENOMEM; + goto exit_release_mem; + } + + irq = irq_of_parse_and_map(np, 0); + if (irq == NO_IRQ) { + dev_err(&ofdev->dev, "no irq found\n"); + err = -ENODEV; + goto exit_unmap_mem; + } + + dev = alloc_sja1000dev(0); + if (!dev) { + err = -ENOMEM; + goto exit_dispose_irq; + } + + priv = netdev_priv(dev); + + priv->read_reg = sja1000_ofp_read_reg; + priv->write_reg = sja1000_ofp_write_reg; + + prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size); + if (prop && (prop_size == sizeof(u32))) + priv->can.clock.freq = *prop / 2; + else + priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */ + + prop = of_get_property(np, "nxp,tx-output-mode", &prop_size); + if (prop && (prop_size == sizeof(u32))) + priv->ocr |= *prop & OCR_MODE_MASK; + else + priv->ocr |= OCR_MODE_NORMAL; /* default */ + + prop = of_get_property(np, "nxp,tx-output-config", &prop_size); + if (prop && (prop_size == sizeof(u32))) + priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK; + else + priv->ocr |= OCR_TX0_PULLDOWN; /* default */ + + prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size); + if (prop && (prop_size == sizeof(u32)) && *prop) { + u32 divider = priv->can.clock.freq * 2 / *prop; + + if (divider > 1) + priv->cdr |= divider / 2 - 1; + else + priv->cdr |= CDR_CLKOUT_MASK; + } else { + priv->cdr |= CDR_CLK_OFF; /* default */ + } + + prop = of_get_property(np, "nxp,no-comparator-bypass", NULL); + if (!prop) + priv->cdr |= CDR_CBP; /* default */ + + priv->irq_flags = IRQF_SHARED; + priv->reg_base = base; + + dev->irq = irq; + + dev_info(&ofdev->dev, + "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n", + priv->reg_base, dev->irq, priv->can.clock.freq, + priv->ocr, priv->cdr); + + dev_set_drvdata(&ofdev->dev, dev); + SET_NETDEV_DEV(dev, &ofdev->dev); + + err = register_sja1000dev(dev); + if (err) { + dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", + DRV_NAME, err); + goto exit_free_sja1000; + } + + return 0; + +exit_free_sja1000: + free_sja1000dev(dev); +exit_dispose_irq: + irq_dispose_mapping(irq); +exit_unmap_mem: + iounmap(base); +exit_release_mem: + release_mem_region(res.start, res_size); + + return err; +} + +static struct of_device_id __devinitdata sja1000_ofp_table[] = { + {.compatible = "nxp,sja1000"}, + {}, +}; + +static struct of_platform_driver sja1000_ofp_driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .probe = sja1000_ofp_probe, + .remove = __devexit_p(sja1000_ofp_remove), + .match_table = sja1000_ofp_table, +}; + +static int __init sja1000_ofp_init(void) +{ + return of_register_platform_driver(&sja1000_ofp_driver); +} +module_init(sja1000_ofp_init); + +static void __exit sja1000_ofp_exit(void) +{ + return of_unregister_platform_driver(&sja1000_ofp_driver); +}; +module_exit(sja1000_ofp_exit); diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index 8017229d6fd6..628374c2a05f 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -37,14 +37,14 @@ MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); MODULE_LICENSE("GPL v2"); -static u8 sp_read_reg(const struct net_device *dev, int reg) +static u8 sp_read_reg(const struct sja1000_priv *priv, int reg) { - return ioread8((void __iomem *)(dev->base_addr + reg)); + return ioread8(priv->reg_base + reg); } -static void sp_write_reg(const struct net_device *dev, int reg, u8 val) +static void sp_write_reg(const struct sja1000_priv *priv, int reg, u8 val) { - iowrite8(val, (void __iomem *)(dev->base_addr + reg)); + iowrite8(val, priv->reg_base + reg); } static int sp_probe(struct platform_device *pdev) @@ -89,9 +89,9 @@ static int sp_probe(struct platform_device *pdev) } priv = netdev_priv(dev); - dev->base_addr = (unsigned long)addr; dev->irq = res_irq->start; priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; + priv->reg_base = addr; priv->read_reg = sp_read_reg; priv->write_reg = sp_write_reg; priv->can.clock.freq = pdata->clock; @@ -108,8 +108,8 @@ static int sp_probe(struct platform_device *pdev) goto exit_free; } - dev_info(&pdev->dev, "%s device registered (base_addr=%#lx, irq=%d)\n", - DRV_NAME, dev->base_addr, dev->irq); + dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n", + DRV_NAME, priv->reg_base, dev->irq); return 0; exit_free: @@ -125,13 +125,14 @@ static int sp_probe(struct platform_device *pdev) static int sp_remove(struct platform_device *pdev) { struct net_device *dev = dev_get_drvdata(&pdev->dev); + struct sja1000_priv *priv = netdev_priv(dev); struct resource *res; unregister_sja1000dev(dev); dev_set_drvdata(&pdev->dev, NULL); - if (dev->base_addr) - iounmap((void __iomem *)dev->base_addr); + if (priv->reg_base) + iounmap(priv->reg_base); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 5e97a1a71d88..3711d64e45ef 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1879,7 +1879,6 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) cpl->vlan_valid = 0; send: - dev->trans_start = jiffies; ret = t1_sge_tx(skb, adapter, 0, dev); /* If transmit busy, and we reallocated skb's due to headroom limit, diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index cfb4198b6776..58afafbd3b9c 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -615,13 +615,13 @@ static void cpmac_end_xmit(struct net_device *dev, int queue) dev_kfree_skb_irq(desc->skb); desc->skb = NULL; - if (netif_subqueue_stopped(dev, queue)) + if (__netif_subqueue_stopped(dev, queue)) netif_wake_subqueue(dev, queue); } else { if (netif_msg_tx_err(priv) && net_ratelimit()) printk(KERN_WARNING "%s: end_xmit: spurious interrupt\n", dev->name); - if (netif_subqueue_stopped(dev, queue)) + if (__netif_subqueue_stopped(dev, queue)) netif_wake_subqueue(dev, queue); } } @@ -731,7 +731,6 @@ static void cpmac_clear_tx(struct net_device *dev) static void cpmac_hw_error(struct work_struct *work) { - int i; struct cpmac_priv *priv = container_of(work, struct cpmac_priv, reset_work); @@ -818,7 +817,6 @@ static irqreturn_t cpmac_irq(int irq, void *dev_id) static void cpmac_tx_timeout(struct net_device *dev) { - int i; struct cpmac_priv *priv = netdev_priv(dev); spin_lock(&priv->lock); @@ -1110,7 +1108,7 @@ static int external_switch; static int __devinit cpmac_probe(struct platform_device *pdev) { - int rc, phy_id, i; + int rc, phy_id; char *mdio_bus_id = "0"; struct resource *mem; struct cpmac_priv *priv; diff --git a/drivers/net/cxgb3/Makefile b/drivers/net/cxgb3/Makefile index 343467985321..29aff78c7820 100644 --- a/drivers/net/cxgb3/Makefile +++ b/drivers/net/cxgb3/Makefile @@ -5,4 +5,4 @@ obj-$(CONFIG_CHELSIO_T3) += cxgb3.o cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \ - xgmac.o sge.o l2t.o cxgb3_offload.o + xgmac.o sge.o l2t.o cxgb3_offload.o aq100x.o diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 322434ac42fc..1694fad38720 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -85,8 +85,8 @@ struct fl_pg_chunk { struct page *page; void *va; unsigned int offset; - u64 *p_cnt; - DECLARE_PCI_UNMAP_ADDR(mapping); + unsigned long *p_cnt; + dma_addr_t mapping; }; struct rx_desc; @@ -253,6 +253,8 @@ struct adapter { struct mutex mdio_lock; spinlock_t stats_lock; spinlock_t work_lock; + + struct sk_buff *nofail_skb; }; static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr) diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c index df1f58576689..9fe008ec9ba5 100644 --- a/drivers/net/cxgb3/ael1002.c +++ b/drivers/net/cxgb3/ael1002.c @@ -44,12 +44,33 @@ enum { AEL_I2C_STAT = 0xc30c, AEL2005_GPIO_CTRL = 0xc214, AEL2005_GPIO_STAT = 0xc215, + + AEL2020_GPIO_INTR = 0xc103, /* Latch High (LH) */ + AEL2020_GPIO_CTRL = 0xc108, /* Store Clear (SC) */ + AEL2020_GPIO_STAT = 0xc10c, /* Read Only (RO) */ + AEL2020_GPIO_CFG = 0xc110, /* Read Write (RW) */ + + AEL2020_GPIO_SDA = 0, /* IN: i2c serial data */ + AEL2020_GPIO_MODDET = 1, /* IN: Module Detect */ + AEL2020_GPIO_0 = 3, /* IN: unassigned */ + AEL2020_GPIO_1 = 2, /* OUT: unassigned */ + AEL2020_GPIO_LSTAT = AEL2020_GPIO_1, /* wired to link status LED */ }; enum { edc_none, edc_sr, edc_twinax }; /* PHY module I2C device address */ -#define MODULE_DEV_ADDR 0xa0 +enum { + MODULE_DEV_ADDR = 0xa0, + SFF_DEV_ADDR = 0xa2, +}; + +/* PHY transceiver type */ +enum { + phy_transtype_unknown = 0, + phy_transtype_sfp = 3, + phy_transtype_xfp = 6, +}; #define AEL2005_MODDET_IRQ 4 @@ -86,6 +107,37 @@ static void ael100x_txon(struct cphy *phy) msleep(30); } +/* + * Read an 8-bit word from a device attached to the PHY's i2c bus. + */ +static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) +{ + int i, err; + unsigned int stat, data; + + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL, + (dev_addr << 8) | (1 << 8) | word_addr); + if (err) + return err; + + for (i = 0; i < 200; i++) { + msleep(1); + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat); + if (err) + return err; + if ((stat & 3) == 1) { + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA, + &data); + if (err) + return err; + return data >> 8; + } + } + CH_WARN(phy->adapter, "PHY %u i2c read of dev.addr %#x.%#x timed out\n", + phy->mdio.prtad, dev_addr, word_addr); + return -ETIMEDOUT; +} + static int ael1002_power_down(struct cphy *phy, int enable) { int err; @@ -199,6 +251,51 @@ int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, return 0; } +/* + * Decode our module type. + */ +static int ael2xxx_get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + + if (delay_ms) + msleep(delay_ms); + + /* see SFF-8472 for below */ + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 3); + if (v < 0) + return v; + + if (v == 0x10) + return phy_modtype_sr; + if (v == 0x20) + return phy_modtype_lr; + if (v == 0x40) + return phy_modtype_lrm; + + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 6); + if (v < 0) + return v; + if (v != 4) + goto unknown; + + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 10); + if (v < 0) + return v; + + if (v & 0x80) { + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 0x12); + if (v < 0) + return v; + return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax; + } +unknown: + return phy_modtype_unknown; +} + +/* + * Code to support the Aeluros/NetLogic 2005 10Gb PHY. + */ static int ael2005_setup_sr_edc(struct cphy *phy) { static struct reg_val regs[] = { @@ -893,35 +990,7 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) return err; } -static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) -{ - int i, err; - unsigned int stat, data; - - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL, - (dev_addr << 8) | (1 << 8) | word_addr); - if (err) - return err; - - for (i = 0; i < 5; i++) { - msleep(1); - err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat); - if (err) - return err; - if ((stat & 3) == 1) { - err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA, - &data); - if (err) - return err; - return data >> 8; - } - } - CH_WARN(phy->adapter, "PHY %u I2C read of addr %u timed out\n", - phy->mdio.prtad, word_addr); - return -ETIMEDOUT; -} - -static int get_module_type(struct cphy *phy, int delay_ms) +static int ael2005_get_module_type(struct cphy *phy, int delay_ms) { int v; unsigned int stat; @@ -933,39 +1002,7 @@ static int get_module_type(struct cphy *phy, int delay_ms) if (stat & (1 << 8)) /* module absent */ return phy_modtype_none; - if (delay_ms) - msleep(delay_ms); - - /* see SFF-8472 for below */ - v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 3); - if (v < 0) - return v; - - if (v == 0x10) - return phy_modtype_sr; - if (v == 0x20) - return phy_modtype_lr; - if (v == 0x40) - return phy_modtype_lrm; - - v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 6); - if (v < 0) - return v; - if (v != 4) - goto unknown; - - v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 10); - if (v < 0) - return v; - - if (v & 0x80) { - v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0x12); - if (v < 0) - return v; - return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax; - } -unknown: - return phy_modtype_unknown; + return ael2xxx_get_module_type(phy, delay_ms); } static int ael2005_intr_enable(struct cphy *phy) @@ -1024,7 +1061,7 @@ static int ael2005_reset(struct cphy *phy, int wait) msleep(50); - err = get_module_type(phy, 0); + err = ael2005_get_module_type(phy, 0); if (err < 0) return err; phy->modtype = err; @@ -1062,7 +1099,7 @@ static int ael2005_intr_handler(struct cphy *phy) return ret; /* modules have max 300 ms init time after hot plug */ - ret = get_module_type(phy, 300); + ret = ael2005_get_module_type(phy, 300); if (ret < 0) return ret; @@ -1113,6 +1150,662 @@ int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, } /* + * Setup EDC and other parameters for operation with an optical module. + */ +static int ael2020_setup_sr_edc(struct cphy *phy) +{ + static struct reg_val regs[] = { + /* set CDR offset to 10 */ + { MDIO_MMD_PMAPMD, 0xcc01, 0xffff, 0x488a }, + + /* adjust 10G RX bias current */ + { MDIO_MMD_PMAPMD, 0xcb1b, 0xffff, 0x0200 }, + { MDIO_MMD_PMAPMD, 0xcb1c, 0xffff, 0x00f0 }, + { MDIO_MMD_PMAPMD, 0xcc06, 0xffff, 0x00e0 }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + + err = set_phy_regs(phy, regs); + msleep(50); + if (err) + return err; + + phy->priv = edc_sr; + return 0; +} + +/* + * Setup EDC and other parameters for operation with an TWINAX module. + */ +static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype) +{ + /* set uC to 40MHz */ + static struct reg_val uCclock40MHz[] = { + { MDIO_MMD_PMAPMD, 0xff28, 0xffff, 0x4001 }, + { MDIO_MMD_PMAPMD, 0xff2a, 0xffff, 0x0002 }, + { 0, 0, 0, 0 } + }; + + /* activate uC clock */ + static struct reg_val uCclockActivate[] = { + { MDIO_MMD_PMAPMD, 0xd000, 0xffff, 0x5200 }, + { 0, 0, 0, 0 } + }; + + /* set PC to start of SRAM and activate uC */ + static struct reg_val uCactivate[] = { + { MDIO_MMD_PMAPMD, 0xd080, 0xffff, 0x0100 }, + { MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 }, + { 0, 0, 0, 0 } + }; + + /* TWINAX EDC firmware */ + static u16 twinax_edc[] = { + 0xd800, 0x4009, + 0xd801, 0x2fff, + 0xd802, 0x300f, + 0xd803, 0x40aa, + 0xd804, 0x401c, + 0xd805, 0x401e, + 0xd806, 0x2ff4, + 0xd807, 0x3dc4, + 0xd808, 0x2035, + 0xd809, 0x3035, + 0xd80a, 0x6524, + 0xd80b, 0x2cb2, + 0xd80c, 0x3012, + 0xd80d, 0x1002, + 0xd80e, 0x26e2, + 0xd80f, 0x3022, + 0xd810, 0x1002, + 0xd811, 0x27d2, + 0xd812, 0x3022, + 0xd813, 0x1002, + 0xd814, 0x2822, + 0xd815, 0x3012, + 0xd816, 0x1002, + 0xd817, 0x2492, + 0xd818, 0x3022, + 0xd819, 0x1002, + 0xd81a, 0x2772, + 0xd81b, 0x3012, + 0xd81c, 0x1002, + 0xd81d, 0x23d2, + 0xd81e, 0x3022, + 0xd81f, 0x1002, + 0xd820, 0x22cd, + 0xd821, 0x301d, + 0xd822, 0x27f2, + 0xd823, 0x3022, + 0xd824, 0x1002, + 0xd825, 0x5553, + 0xd826, 0x0307, + 0xd827, 0x2522, + 0xd828, 0x3022, + 0xd829, 0x1002, + 0xd82a, 0x2142, + 0xd82b, 0x3012, + 0xd82c, 0x1002, + 0xd82d, 0x4016, + 0xd82e, 0x5e63, + 0xd82f, 0x0344, + 0xd830, 0x2142, + 0xd831, 0x3012, + 0xd832, 0x1002, + 0xd833, 0x400e, + 0xd834, 0x2522, + 0xd835, 0x3022, + 0xd836, 0x1002, + 0xd837, 0x2b52, + 0xd838, 0x3012, + 0xd839, 0x1002, + 0xd83a, 0x2742, + 0xd83b, 0x3022, + 0xd83c, 0x1002, + 0xd83d, 0x25e2, + 0xd83e, 0x3022, + 0xd83f, 0x1002, + 0xd840, 0x2fa4, + 0xd841, 0x3dc4, + 0xd842, 0x6624, + 0xd843, 0x414b, + 0xd844, 0x56b3, + 0xd845, 0x03c6, + 0xd846, 0x866b, + 0xd847, 0x400c, + 0xd848, 0x2712, + 0xd849, 0x3012, + 0xd84a, 0x1002, + 0xd84b, 0x2c4b, + 0xd84c, 0x309b, + 0xd84d, 0x56b3, + 0xd84e, 0x03c3, + 0xd84f, 0x866b, + 0xd850, 0x400c, + 0xd851, 0x2272, + 0xd852, 0x3022, + 0xd853, 0x1002, + 0xd854, 0x2742, + 0xd855, 0x3022, + 0xd856, 0x1002, + 0xd857, 0x25e2, + 0xd858, 0x3022, + 0xd859, 0x1002, + 0xd85a, 0x2fb4, + 0xd85b, 0x3dc4, + 0xd85c, 0x6624, + 0xd85d, 0x56b3, + 0xd85e, 0x03c3, + 0xd85f, 0x866b, + 0xd860, 0x401c, + 0xd861, 0x2c45, + 0xd862, 0x3095, + 0xd863, 0x5b53, + 0xd864, 0x2372, + 0xd865, 0x3012, + 0xd866, 0x13c2, + 0xd867, 0x5cc3, + 0xd868, 0x2712, + 0xd869, 0x3012, + 0xd86a, 0x1312, + 0xd86b, 0x2b52, + 0xd86c, 0x3012, + 0xd86d, 0x1002, + 0xd86e, 0x2742, + 0xd86f, 0x3022, + 0xd870, 0x1002, + 0xd871, 0x2582, + 0xd872, 0x3022, + 0xd873, 0x1002, + 0xd874, 0x2142, + 0xd875, 0x3012, + 0xd876, 0x1002, + 0xd877, 0x628f, + 0xd878, 0x2985, + 0xd879, 0x33a5, + 0xd87a, 0x25e2, + 0xd87b, 0x3022, + 0xd87c, 0x1002, + 0xd87d, 0x5653, + 0xd87e, 0x03d2, + 0xd87f, 0x401e, + 0xd880, 0x6f72, + 0xd881, 0x1002, + 0xd882, 0x628f, + 0xd883, 0x2304, + 0xd884, 0x3c84, + 0xd885, 0x6436, + 0xd886, 0xdff4, + 0xd887, 0x6436, + 0xd888, 0x2ff5, + 0xd889, 0x3005, + 0xd88a, 0x8656, + 0xd88b, 0xdfba, + 0xd88c, 0x56a3, + 0xd88d, 0xd05a, + 0xd88e, 0x2972, + 0xd88f, 0x3012, + 0xd890, 0x1392, + 0xd891, 0xd05a, + 0xd892, 0x56a3, + 0xd893, 0xdfba, + 0xd894, 0x0383, + 0xd895, 0x6f72, + 0xd896, 0x1002, + 0xd897, 0x2b45, + 0xd898, 0x3005, + 0xd899, 0x4178, + 0xd89a, 0x5653, + 0xd89b, 0x0384, + 0xd89c, 0x2a62, + 0xd89d, 0x3012, + 0xd89e, 0x1002, + 0xd89f, 0x2f05, + 0xd8a0, 0x3005, + 0xd8a1, 0x41c8, + 0xd8a2, 0x5653, + 0xd8a3, 0x0382, + 0xd8a4, 0x0002, + 0xd8a5, 0x4218, + 0xd8a6, 0x2474, + 0xd8a7, 0x3c84, + 0xd8a8, 0x6437, + 0xd8a9, 0xdff4, + 0xd8aa, 0x6437, + 0xd8ab, 0x2ff5, + 0xd8ac, 0x3c05, + 0xd8ad, 0x8757, + 0xd8ae, 0xb888, + 0xd8af, 0x9787, + 0xd8b0, 0xdff4, + 0xd8b1, 0x6724, + 0xd8b2, 0x866a, + 0xd8b3, 0x6f72, + 0xd8b4, 0x1002, + 0xd8b5, 0x2641, + 0xd8b6, 0x3021, + 0xd8b7, 0x1001, + 0xd8b8, 0xc620, + 0xd8b9, 0x0000, + 0xd8ba, 0xc621, + 0xd8bb, 0x0000, + 0xd8bc, 0xc622, + 0xd8bd, 0x00ce, + 0xd8be, 0xc623, + 0xd8bf, 0x007f, + 0xd8c0, 0xc624, + 0xd8c1, 0x0032, + 0xd8c2, 0xc625, + 0xd8c3, 0x0000, + 0xd8c4, 0xc627, + 0xd8c5, 0x0000, + 0xd8c6, 0xc628, + 0xd8c7, 0x0000, + 0xd8c8, 0xc62c, + 0xd8c9, 0x0000, + 0xd8ca, 0x0000, + 0xd8cb, 0x2641, + 0xd8cc, 0x3021, + 0xd8cd, 0x1001, + 0xd8ce, 0xc502, + 0xd8cf, 0x53ac, + 0xd8d0, 0xc503, + 0xd8d1, 0x2cd3, + 0xd8d2, 0xc600, + 0xd8d3, 0x2a6e, + 0xd8d4, 0xc601, + 0xd8d5, 0x2a2c, + 0xd8d6, 0xc605, + 0xd8d7, 0x5557, + 0xd8d8, 0xc60c, + 0xd8d9, 0x5400, + 0xd8da, 0xc710, + 0xd8db, 0x0700, + 0xd8dc, 0xc711, + 0xd8dd, 0x0f06, + 0xd8de, 0xc718, + 0xd8df, 0x0700, + 0xd8e0, 0xc719, + 0xd8e1, 0x0f06, + 0xd8e2, 0xc720, + 0xd8e3, 0x4700, + 0xd8e4, 0xc721, + 0xd8e5, 0x0f06, + 0xd8e6, 0xc728, + 0xd8e7, 0x0700, + 0xd8e8, 0xc729, + 0xd8e9, 0x1207, + 0xd8ea, 0xc801, + 0xd8eb, 0x7f50, + 0xd8ec, 0xc802, + 0xd8ed, 0x7760, + 0xd8ee, 0xc803, + 0xd8ef, 0x7fce, + 0xd8f0, 0xc804, + 0xd8f1, 0x520e, + 0xd8f2, 0xc805, + 0xd8f3, 0x5c11, + 0xd8f4, 0xc806, + 0xd8f5, 0x3c51, + 0xd8f6, 0xc807, + 0xd8f7, 0x4061, + 0xd8f8, 0xc808, + 0xd8f9, 0x49c1, + 0xd8fa, 0xc809, + 0xd8fb, 0x3840, + 0xd8fc, 0xc80a, + 0xd8fd, 0x0000, + 0xd8fe, 0xc821, + 0xd8ff, 0x0002, + 0xd900, 0xc822, + 0xd901, 0x0046, + 0xd902, 0xc844, + 0xd903, 0x182f, + 0xd904, 0xc013, + 0xd905, 0xf341, + 0xd906, 0xc084, + 0xd907, 0x0030, + 0xd908, 0xc904, + 0xd909, 0x1401, + 0xd90a, 0xcb0c, + 0xd90b, 0x0004, + 0xd90c, 0xcb0e, + 0xd90d, 0xa00a, + 0xd90e, 0xcb0f, + 0xd90f, 0xc0c0, + 0xd910, 0xcb10, + 0xd911, 0xc0c0, + 0xd912, 0xcb11, + 0xd913, 0x00a0, + 0xd914, 0xcb12, + 0xd915, 0x0007, + 0xd916, 0xc241, + 0xd917, 0xa000, + 0xd918, 0xc243, + 0xd919, 0x7fe0, + 0xd91a, 0xc604, + 0xd91b, 0x000e, + 0xd91c, 0xc609, + 0xd91d, 0x00f5, + 0xd91e, 0xc611, + 0xd91f, 0x000e, + 0xd920, 0xc660, + 0xd921, 0x9600, + 0xd922, 0xc687, + 0xd923, 0x0004, + 0xd924, 0xc60a, + 0xd925, 0x04f5, + 0xd926, 0x0000, + 0xd927, 0x2641, + 0xd928, 0x3021, + 0xd929, 0x1001, + 0xd92a, 0xc620, + 0xd92b, 0x14e5, + 0xd92c, 0xc621, + 0xd92d, 0xc53d, + 0xd92e, 0xc622, + 0xd92f, 0x3cbe, + 0xd930, 0xc623, + 0xd931, 0x4452, + 0xd932, 0xc624, + 0xd933, 0xc5c5, + 0xd934, 0xc625, + 0xd935, 0xe01e, + 0xd936, 0xc627, + 0xd937, 0x0000, + 0xd938, 0xc628, + 0xd939, 0x0000, + 0xd93a, 0xc62c, + 0xd93b, 0x0000, + 0xd93c, 0x0000, + 0xd93d, 0x2b84, + 0xd93e, 0x3c74, + 0xd93f, 0x6435, + 0xd940, 0xdff4, + 0xd941, 0x6435, + 0xd942, 0x2806, + 0xd943, 0x3006, + 0xd944, 0x8565, + 0xd945, 0x2b24, + 0xd946, 0x3c24, + 0xd947, 0x6436, + 0xd948, 0x1002, + 0xd949, 0x2b24, + 0xd94a, 0x3c24, + 0xd94b, 0x6436, + 0xd94c, 0x4045, + 0xd94d, 0x8656, + 0xd94e, 0x5663, + 0xd94f, 0x0302, + 0xd950, 0x401e, + 0xd951, 0x1002, + 0xd952, 0x2807, + 0xd953, 0x31a7, + 0xd954, 0x20c4, + 0xd955, 0x3c24, + 0xd956, 0x6724, + 0xd957, 0x1002, + 0xd958, 0x2807, + 0xd959, 0x3187, + 0xd95a, 0x20c4, + 0xd95b, 0x3c24, + 0xd95c, 0x6724, + 0xd95d, 0x1002, + 0xd95e, 0x24f4, + 0xd95f, 0x3c64, + 0xd960, 0x6436, + 0xd961, 0xdff4, + 0xd962, 0x6436, + 0xd963, 0x1002, + 0xd964, 0x2006, + 0xd965, 0x3d76, + 0xd966, 0xc161, + 0xd967, 0x6134, + 0xd968, 0x6135, + 0xd969, 0x5443, + 0xd96a, 0x0303, + 0xd96b, 0x6524, + 0xd96c, 0x00fb, + 0xd96d, 0x1002, + 0xd96e, 0x20d4, + 0xd96f, 0x3c24, + 0xd970, 0x2025, + 0xd971, 0x3005, + 0xd972, 0x6524, + 0xd973, 0x1002, + 0xd974, 0xd019, + 0xd975, 0x2104, + 0xd976, 0x3c24, + 0xd977, 0x2105, + 0xd978, 0x3805, + 0xd979, 0x6524, + 0xd97a, 0xdff4, + 0xd97b, 0x4005, + 0xd97c, 0x6524, + 0xd97d, 0x2e8d, + 0xd97e, 0x303d, + 0xd97f, 0x2408, + 0xd980, 0x35d8, + 0xd981, 0x5dd3, + 0xd982, 0x0307, + 0xd983, 0x8887, + 0xd984, 0x63a7, + 0xd985, 0x8887, + 0xd986, 0x63a7, + 0xd987, 0xdffd, + 0xd988, 0x00f9, + 0xd989, 0x1002, + 0xd98a, 0x0000, + }; + int i, err; + + /* set uC clock and activate it */ + err = set_phy_regs(phy, uCclock40MHz); + msleep(500); + if (err) + return err; + err = set_phy_regs(phy, uCclockActivate); + msleep(500); + if (err) + return err; + + /* write TWINAX EDC firmware into PHY */ + for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i], + twinax_edc[i + 1]); + /* activate uC */ + err = set_phy_regs(phy, uCactivate); + if (!err) + phy->priv = edc_twinax; + return err; +} + +/* + * Return Module Type. + */ +static int ael2020_get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + unsigned int stat; + + v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_STAT, &stat); + if (v) + return v; + + if (stat & (0x1 << (AEL2020_GPIO_MODDET*4))) { + /* module absent */ + return phy_modtype_none; + } + + return ael2xxx_get_module_type(phy, delay_ms); +} + +/* + * Enable PHY interrupts. We enable "Module Detection" interrupts (on any + * state transition) and then generic Link Alarm Status Interrupt (LASI). + */ +static int ael2020_intr_enable(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0x2 << (AEL2020_GPIO_MODDET*4)); + return err ? err : t3_phy_lasi_intr_enable(phy); +} + +/* + * Disable PHY interrupts. The mirror of the above ... + */ +static int ael2020_intr_disable(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0x1 << (AEL2020_GPIO_MODDET*4)); + return err ? err : t3_phy_lasi_intr_disable(phy); +} + +/* + * Clear PHY interrupt state. + */ +static int ael2020_intr_clear(struct cphy *phy) +{ + /* + * The GPIO Interrupt register on the AEL2020 is a "Latching High" + * (LH) register which is cleared to the current state when it's read. + * Thus, we simply read the register and discard the result. + */ + unsigned int stat; + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat); + return err ? err : t3_phy_lasi_intr_clear(phy); +} + +/* + * Reset the PHY and put it into a canonical operating state. + */ +static int ael2020_reset(struct cphy *phy, int wait) +{ + static struct reg_val regs0[] = { + /* Erratum #2: CDRLOL asserted, causing PMA link down status */ + { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 }, + + /* force XAUI to send LF when RX_LOS is asserted */ + { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 }, + + /* RX_LOS pin is active high */ + { MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, + 0x0020, 0x0020 }, + + /* output Module's Loss Of Signal (LOS) to LED */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT, + 0xffff, 0x0004 }, + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + unsigned int lasi_ctrl; + + /* grab current interrupt state */ + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + &lasi_ctrl); + if (err) + return err; + + err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 125); + if (err) + return err; + msleep(100); + + /* basic initialization for all module types */ + phy->priv = edc_none; + err = set_phy_regs(phy, regs0); + if (err) + return err; + + /* determine module type and perform appropriate initialization */ + err = ael2020_get_module_type(phy, 0); + if (err < 0) + return err; + phy->modtype = (u8)err; + if (err == phy_modtype_twinax || err == phy_modtype_twinax_long) + err = ael2020_setup_twinax_edc(phy, err); + else + err = ael2020_setup_sr_edc(phy); + if (err) + return err; + + /* reset wipes out interrupts, reenable them if they were on */ + if (lasi_ctrl & 1) + err = ael2005_intr_enable(phy); + return err; +} + +/* + * Handle a PHY interrupt. + */ +static int ael2020_intr_handler(struct cphy *phy) +{ + unsigned int stat; + int ret, edc_needed, cause = 0; + + ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat); + if (ret) + return ret; + + if (stat & (0x1 << AEL2020_GPIO_MODDET)) { + /* modules have max 300 ms init time after hot plug */ + ret = ael2020_get_module_type(phy, 300); + if (ret < 0) + return ret; + + phy->modtype = (u8)ret; + if (ret == phy_modtype_none) + edc_needed = phy->priv; /* on unplug retain EDC */ + else if (ret == phy_modtype_twinax || + ret == phy_modtype_twinax_long) + edc_needed = edc_twinax; + else + edc_needed = edc_sr; + + if (edc_needed != phy->priv) { + ret = ael2020_reset(phy, 0); + return ret ? ret : cphy_cause_module_change; + } + cause = cphy_cause_module_change; + } + + ret = t3_phy_lasi_intr_handler(phy); + if (ret < 0) + return ret; + + ret |= cause; + return ret ? ret : cphy_cause_link_change; +} + +static struct cphy_ops ael2020_ops = { + .reset = ael2020_reset, + .intr_enable = ael2020_intr_enable, + .intr_disable = ael2020_intr_disable, + .intr_clear = ael2020_intr_clear, + .intr_handler = ael2020_intr_handler, + .get_link_status = get_link_status_r, + .power_down = ael1002_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, +}; + +int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_IRQ, "10GBASE-R"); + msleep(125); + return 0; +} + +/* * Get link status for a 10GBASE-X device. */ static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed, diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/cxgb3/aq100x.c new file mode 100644 index 000000000000..b1fd5bf836e4 --- /dev/null +++ b/drivers/net/cxgb3/aq100x.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "common.h" +#include "regs.h" + +enum { + /* MDIO_DEV_PMA_PMD registers */ + AQ_LINK_STAT = 0xe800, + AQ_IMASK_PMA = 0xf000, + + /* MDIO_DEV_XGXS registers */ + AQ_XAUI_RX_CFG = 0xc400, + AQ_XAUI_TX_CFG = 0xe400, + + /* MDIO_DEV_ANEG registers */ + AQ_1G_CTRL = 0xc400, + AQ_ANEG_STAT = 0xc800, + + /* MDIO_DEV_VEND1 registers */ + AQ_FW_VERSION = 0x0020, + AQ_IFLAG_GLOBAL = 0xfc00, + AQ_IMASK_GLOBAL = 0xff00, +}; + +enum { + IMASK_PMA = 1 << 2, + IMASK_GLOBAL = 1 << 15, + ADV_1G_FULL = 1 << 15, + ADV_1G_HALF = 1 << 14, + ADV_10G_FULL = 1 << 12, + AQ_RESET = (1 << 14) | (1 << 15), + AQ_LOWPOWER = 1 << 12, +}; + +static int aq100x_reset(struct cphy *phy, int wait) +{ + /* + * Ignore the caller specified wait time; always wait for the reset to + * complete. Can take up to 3s. + */ + int err = t3_phy_reset(phy, MDIO_MMD_VEND1, 3000); + + if (err) + CH_WARN(phy->adapter, "PHY%d: reset failed (0x%x).\n", + phy->mdio.prtad, err); + + return err; +} + +static int aq100x_intr_enable(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AQ_IMASK_PMA, IMASK_PMA); + if (err) + return err; + + err = t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, IMASK_GLOBAL); + return err; +} + +static int aq100x_intr_disable(struct cphy *phy) +{ + return t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, 0); +} + +static int aq100x_intr_clear(struct cphy *phy) +{ + unsigned int v; + + t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &v); + t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v); + + return 0; +} + +static int aq100x_intr_handler(struct cphy *phy) +{ + int err; + unsigned int cause, v; + + err = t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &cause); + if (err) + return err; + + /* Read (and reset) the latching version of the status */ + t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v); + + return cphy_cause_link_change; +} + +static int aq100x_power_down(struct cphy *phy, int off) +{ + return mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_LPOWER, off); +} + +static int aq100x_autoneg_enable(struct cphy *phy) +{ + int err; + + err = aq100x_power_down(phy, 0); + if (!err) + err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_AN, MDIO_CTRL1, + BMCR_ANENABLE | BMCR_ANRESTART, 1); + + return err; +} + +static int aq100x_autoneg_restart(struct cphy *phy) +{ + int err; + + err = aq100x_power_down(phy, 0); + if (!err) + err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_AN, MDIO_CTRL1, + BMCR_ANENABLE | BMCR_ANRESTART, 1); + + return err; +} + +static int aq100x_advertise(struct cphy *phy, unsigned int advertise_map) +{ + unsigned int adv; + int err; + + /* 10G advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_10000baseT_Full) + adv |= ADV_10G_FULL; + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + ADV_10G_FULL, adv); + if (err) + return err; + + /* 1G advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_1000baseT_Full) + adv |= ADV_1G_FULL; + if (advertise_map & ADVERTISED_1000baseT_Half) + adv |= ADV_1G_HALF; + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, AQ_1G_CTRL, + ADV_1G_FULL | ADV_1G_HALF, adv); + if (err) + return err; + + /* 100M, pause advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise_map & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + if (advertise_map & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise_map & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_ADVERTISE, + 0xfe0, adv); + + return err; +} + +static int aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable) +{ + return mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_PMAPMD, MDIO_CTRL1, + BMCR_LOOPBACK, enable); +} + +static int aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex) +{ + /* no can do */ + return -1; +} + +static int aq100x_get_link_status(struct cphy *phy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + int err; + unsigned int v; + + if (link_ok) { + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AQ_LINK_STAT, &v); + if (err) + return err; + + *link_ok = v & 1; + if (!*link_ok) + return 0; + } + + err = t3_mdio_read(phy, MDIO_MMD_AN, AQ_ANEG_STAT, &v); + if (err) + return err; + + if (speed) { + switch (v & 0x6) { + case 0x6: + *speed = SPEED_10000; + break; + case 0x4: + *speed = SPEED_1000; + break; + case 0x2: + *speed = SPEED_100; + break; + case 0x0: + *speed = SPEED_10; + break; + } + } + + if (duplex) + *duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF; + + return 0; +} + +static struct cphy_ops aq100x_ops = { + .reset = aq100x_reset, + .intr_enable = aq100x_intr_enable, + .intr_disable = aq100x_intr_disable, + .intr_clear = aq100x_intr_clear, + .intr_handler = aq100x_intr_handler, + .autoneg_enable = aq100x_autoneg_enable, + .autoneg_restart = aq100x_autoneg_restart, + .advertise = aq100x_advertise, + .set_loopback = aq100x_set_loopback, + .set_speed_duplex = aq100x_set_speed_duplex, + .get_link_status = aq100x_get_link_status, + .power_down = aq100x_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, +}; + +int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops) +{ + unsigned int v, v2, gpio, wait; + int err; + + cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops, + SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_AUI, "1000/10GBASE-T"); + + /* + * The PHY has been out of reset ever since the system powered up. So + * we do a hard reset over here. + */ + gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL; + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0); + msleep(1); + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio); + + /* + * Give it enough time to load the firmware and get ready for mdio. + */ + msleep(1000); + wait = 500; /* in 10ms increments */ + do { + err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v); + if (err || v == 0xffff) { + + /* Allow prep_adapter to succeed when ffff is read */ + + CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n", + phy_addr, err, v); + goto done; + } + + v &= AQ_RESET; + if (v) + msleep(10); + } while (v && --wait); + if (v) { + CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n", + phy_addr, v); + + goto done; /* let prep_adapter succeed */ + } + + /* Datasheet says 3s max but this has been observed */ + wait = (500 - wait) * 10 + 1000; + if (wait > 3000) + CH_WARN(adapter, "PHY%d: reset took %ums\n", phy_addr, wait); + + /* Firmware version check. */ + t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v); + if (v != 30) { + CH_WARN(adapter, "PHY%d: unsupported firmware %d\n", + phy_addr, v); + return 0; /* allow t3_prep_adapter to succeed */ + } + + /* + * The PHY should start in really-low-power mode. Prepare it for normal + * operations. + */ + err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v); + if (err) + return err; + if (v & AQ_LOWPOWER) { + err = t3_mdio_change_bits(phy, MDIO_MMD_VEND1, MDIO_CTRL1, + AQ_LOWPOWER, 0); + if (err) + return err; + msleep(10); + } else + CH_WARN(adapter, "PHY%d does not start in low power mode.\n", + phy_addr); + + /* + * Verify XAUI settings, but let prep succeed no matter what. + */ + v = v2 = 0; + t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_RX_CFG, &v); + t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_TX_CFG, &v2); + if (v != 0x1b || v2 != 0x1b) + CH_WARN(adapter, + "PHY%d: incorrect XAUI settings (0x%x, 0x%x).\n", + phy_addr, v, v2); + +done: + return err; +} diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 79a113b99e2f..d21b705501a9 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -802,8 +802,12 @@ int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, const struct mdio_ops *mdio_ops); int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, const struct mdio_ops *mdio_ops); +int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, const struct mdio_ops *mdio_ops); int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, const struct mdio_ops *mdio_ops); +int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); #endif /* __CHELSIO_COMMON_H */ diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 0b87fee023f5..538dda4422dc 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -91,6 +91,8 @@ static const struct pci_device_id cxgb3_pci_tbl[] = { CH_DEVICE(0x31, 3), /* T3B20 */ CH_DEVICE(0x32, 1), /* T3B02 */ CH_DEVICE(0x35, 6), /* T3C20-derived T3C10 */ + CH_DEVICE(0x36, 3), /* S320E-CR */ + CH_DEVICE(0x37, 7), /* N320E-G2 */ {0,} }; @@ -431,40 +433,78 @@ static int init_tp_parity(struct adapter *adap) for (i = 0; i < 16; i++) { struct cpl_smt_write_req *req; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); req->iff = i; t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } } for (i = 0; i < 2048; i++) { struct cpl_l2t_write_req *req; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); req->params = htonl(V_L2T_W_IDX(i)); t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, 16 + i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } } for (i = 0; i < 2048; i++) { struct cpl_rte_write_req *req; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); req->l2t_idx = htonl(V_L2T_W_IDX(i)); t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, 16 + 2048 + i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } } - skb = alloc_skb(sizeof(*greq), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq)); memset(greq, 0, sizeof(*greq)); greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); @@ -473,8 +513,17 @@ static int init_tp_parity(struct adapter *adap) t3_mgmt_tx(adap, skb); i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); + if (skb == adap->nofail_skb) { + i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + } + t3_tp_set_offload_mode(adap, 0); return i; + +alloc_skb_fail: + t3_tp_set_offload_mode(adap, 0); + return -ENOMEM; } /** @@ -869,7 +918,12 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, struct mngt_pktsched_wr *req; int ret; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + return -ENOMEM; + req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req)); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; @@ -879,6 +933,12 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, req->max = hi; req->binding = port; ret = t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + adap->nofail_skb = alloc_skb(sizeof(struct cpl_set_tcb_field), + GFP_KERNEL); + if (!adap->nofail_skb) + ret = -ENOMEM; + } return ret; } @@ -2451,14 +2511,16 @@ static void check_link_status(struct adapter *adapter) for_each_port(adapter, i) { struct net_device *dev = adapter->port[i]; struct port_info *p = netdev_priv(dev); + int link_fault; spin_lock_irq(&adapter->work_lock); - if (p->link_fault) { + link_fault = p->link_fault; + spin_unlock_irq(&adapter->work_lock); + + if (link_fault) { t3_link_fault(adapter, i); - spin_unlock_irq(&adapter->work_lock); continue; } - spin_unlock_irq(&adapter->work_lock); if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) { t3_xgm_intr_disable(adapter, i); @@ -3016,6 +3078,14 @@ static int __devinit init_one(struct pci_dev *pdev, goto out_disable_device; } + adapter->nofail_skb = + alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_KERNEL); + if (!adapter->nofail_skb) { + dev_err(&pdev->dev, "cannot allocate nofail buffer\n"); + err = -ENOMEM; + goto out_free_adapter; + } + adapter->regs = ioremap_nocache(mmio_start, mmio_len); if (!adapter->regs) { dev_err(&pdev->dev, "cannot map device registers\n"); @@ -3059,7 +3129,6 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; - netdev->features |= NETIF_F_LLTX; netdev->features |= NETIF_F_GRO; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; @@ -3173,6 +3242,8 @@ static void __devexit remove_one(struct pci_dev *pdev) free_netdev(adapter->port[i]); iounmap(adapter->regs); + if (adapter->nofail_skb) + kfree_skb(adapter->nofail_skb); kfree(adapter); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 620d80be6aac..f9f54b57b28c 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -566,13 +566,31 @@ static void t3_process_tid_release_list(struct work_struct *work) spin_unlock_bh(&td->tid_release_lock); skb = alloc_skb(sizeof(struct cpl_tid_release), - GFP_KERNEL | __GFP_NOFAIL); + GFP_KERNEL); + if (!skb) + skb = td->nofail_skb; + if (!skb) { + spin_lock_bh(&td->tid_release_lock); + p->ctx = (void *)td->tid_release_list; + td->tid_release_list = (struct t3c_tid_entry *)p; + break; + } mk_tid_release(skb, p - td->tid_maps.tid_tab); cxgb3_ofld_send(tdev, skb); p->ctx = NULL; + if (skb == td->nofail_skb) + td->nofail_skb = + alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL); spin_lock_bh(&td->tid_release_lock); } + td->release_list_incomplete = (td->tid_release_list == NULL) ? 0 : 1; spin_unlock_bh(&td->tid_release_lock); + + if (!td->nofail_skb) + td->nofail_skb = + alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL); } /* use ctx as a next pointer in the tid release list */ @@ -585,7 +603,7 @@ void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid) p->ctx = (void *)td->tid_release_list; p->client = NULL; td->tid_release_list = p; - if (!p->ctx) + if (!p->ctx || td->release_list_incomplete) schedule_work(&td->tid_release_task); spin_unlock_bh(&td->tid_release_lock); } @@ -1274,6 +1292,9 @@ int cxgb3_offload_activate(struct adapter *adapter) if (list_empty(&adapter_list)) register_netevent_notifier(&nb); + t->nofail_skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_KERNEL); + t->release_list_incomplete = 0; + add_adapter(adapter); return 0; @@ -1298,6 +1319,8 @@ void cxgb3_offload_deactivate(struct adapter *adapter) T3C_DATA(tdev) = NULL; t3_free_l2t(L2DATA(tdev)); L2DATA(tdev) = NULL; + if (t->nofail_skb) + kfree_skb(t->nofail_skb); kfree(t); } diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h index a8e8e5fcdf84..55945f422aec 100644 --- a/drivers/net/cxgb3/cxgb3_offload.h +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -191,6 +191,9 @@ struct t3c_data { struct t3c_tid_entry *tid_release_list; spinlock_t tid_release_lock; struct work_struct tid_release_task; + + struct sk_buff *nofail_skb; + unsigned int release_list_incomplete; }; /* diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 73d569e758ec..29c79eb43beb 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -355,7 +355,7 @@ static void clear_rx_desc(struct pci_dev *pdev, const struct sge_fl *q, (*d->pg_chunk.p_cnt)--; if (!*d->pg_chunk.p_cnt) pci_unmap_page(pdev, - pci_unmap_addr(&d->pg_chunk, mapping), + d->pg_chunk.mapping, q->alloc_size, PCI_DMA_FROMDEVICE); put_page(d->pg_chunk.page); @@ -454,7 +454,7 @@ static int alloc_pg_chunk(struct adapter *adapter, struct sge_fl *q, q->pg_chunk.offset = 0; mapping = pci_map_page(adapter->pdev, q->pg_chunk.page, 0, q->alloc_size, PCI_DMA_FROMDEVICE); - pci_unmap_addr_set(&q->pg_chunk, mapping, mapping); + q->pg_chunk.mapping = mapping; } sd->pg_chunk = q->pg_chunk; @@ -511,8 +511,7 @@ static int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) nomem: q->alloc_failed++; break; } - mapping = pci_unmap_addr(&sd->pg_chunk, mapping) + - sd->pg_chunk.offset; + mapping = sd->pg_chunk.mapping + sd->pg_chunk.offset; pci_unmap_addr_set(sd, dma_addr, mapping); add_one_rx_chunk(mapping, d, q->gen); @@ -882,7 +881,7 @@ recycle: (*sd->pg_chunk.p_cnt)--; if (!*sd->pg_chunk.p_cnt) pci_unmap_page(adap->pdev, - pci_unmap_addr(&sd->pg_chunk, mapping), + sd->pg_chunk.mapping, fl->alloc_size, PCI_DMA_FROMDEVICE); if (!skb) { @@ -1241,7 +1240,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) q = &qs->txq[TXQ_ETH]; txq = netdev_get_tx_queue(dev, qidx); - spin_lock(&q->lock); reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); credits = q->size - q->in_use; @@ -1252,7 +1250,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) dev_err(&adap->pdev->dev, "%s: Tx ring %u full while queue awake!\n", dev->name, q->cntxt_id & 7); - spin_unlock(&q->lock); return NETDEV_TX_BUSY; } @@ -1286,9 +1283,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) if (vlan_tx_tag_present(skb) && pi->vlan_grp) qs->port_stats[SGE_PSTAT_VLANINS]++; - dev->trans_start = jiffies; - spin_unlock(&q->lock); - /* * We do not use Tx completion interrupts to free DMAd Tx packets. * This is good for performamce but means that we rely on new Tx @@ -2096,7 +2090,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, (*sd->pg_chunk.p_cnt)--; if (!*sd->pg_chunk.p_cnt) pci_unmap_page(adap->pdev, - pci_unmap_addr(&sd->pg_chunk, mapping), + sd->pg_chunk.mapping, fl->alloc_size, PCI_DMA_FROMDEVICE); @@ -2858,11 +2852,12 @@ static void sge_timer_tx(unsigned long data) unsigned int tbd[SGE_TXQ_PER_SET] = {0, 0}; unsigned long next_period; - if (spin_trylock(&qs->txq[TXQ_ETH].lock)) { - tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH], - TX_RECLAIM_TIMER_CHUNK); - spin_unlock(&qs->txq[TXQ_ETH].lock); + if (__netif_tx_trylock(qs->tx_q)) { + tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH], + TX_RECLAIM_TIMER_CHUNK); + __netif_tx_unlock(qs->tx_q); } + if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) { tbd[TXQ_OFLD] = reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD], TX_RECLAIM_TIMER_CHUNK); @@ -2870,8 +2865,8 @@ static void sge_timer_tx(unsigned long data) } next_period = TX_RECLAIM_PERIOD >> - (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) / - TX_RECLAIM_TIMER_CHUNK); + (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) / + TX_RECLAIM_TIMER_CHUNK); mod_timer(&qs->tx_reclaim_timer, jiffies + next_period); } diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index fc7db8a9ba89..870d44992c70 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -526,6 +526,11 @@ static const struct adapter_info t3_adap_info[] = { F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, &mi1_mdio_ext_ops, "Chelsio T310" }, + {1, 0, 0, + F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | + F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL, + { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, + &mi1_mdio_ext_ops, "Chelsio N320E-G2" }, }; /* @@ -552,6 +557,8 @@ static const struct port_type_info port_types[] = { { t3_qt2045_phy_prep }, { t3_ael1006_phy_prep }, { NULL }, + { t3_aq100x_phy_prep }, + { t3_ael2020_phy_prep }, }; #define VPD_ENTRY(name, len) \ @@ -1281,6 +1288,11 @@ void t3_link_fault(struct adapter *adapter, int port_id) A_XGM_INT_STATUS + mac->offset); link_fault &= F_LINKFAULTCHANGE; + link_ok = lc->link_ok; + speed = lc->speed; + duplex = lc->duplex; + fc = lc->fc; + phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); if (link_fault) { diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index 7bf963ec5548..9d0bd9dd9ab1 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -35,10 +35,10 @@ #define DRV_DESC "Chelsio T3 Network Driver" #define DRV_NAME "cxgb3" /* Driver version */ -#define DRV_VERSION "1.1.2-ko" +#define DRV_VERSION "1.1.3-ko" /* Firmware version */ #define FW_VERSION_MAJOR 7 -#define FW_VERSION_MINOR 1 +#define FW_VERSION_MINOR 4 #define FW_VERSION_MICRO 0 #endif /* __CHELSIO_VERSION_H */ diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index cf689a056b38..0e9b9f9632c1 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -1819,7 +1819,6 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr) struct emac_rxch *rxch = priv->rxch[EMAC_DEF_RX_CH]; struct device *emac_dev = &priv->ndev->dev; struct sockaddr *sa = addr; - DECLARE_MAC_BUF(mac); /* Store mac addr in priv and rx channel and set it in EMAC hw */ memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len); @@ -1828,8 +1827,8 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr) emac_setmac(priv, EMAC_DEF_RX_CH, rxch->mac_addr); if (netif_msg_drv(priv)) - dev_notice(emac_dev, "DaVinci EMAC: emac_dev_setmac_addr %s\n", - print_mac(mac, priv->mac_addr)); + dev_notice(emac_dev, "DaVinci EMAC: emac_dev_setmac_addr %pM\n", + priv->mac_addr); return 0; } @@ -2683,11 +2682,10 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev) ndev->irq = res->start; if (!is_valid_ether_addr(priv->mac_addr)) { - DECLARE_MAC_BUF(buf); /* Use random MAC if none passed */ random_ether_addr(priv->mac_addr); - printk(KERN_WARNING "%s: using random MAC addr: %s\n", - __func__, print_mac(buf, priv->mac_addr)); + printk(KERN_WARNING "%s: using random MAC addr: %pM\n", + __func__, priv->mac_addr); } ndev->netdev_ops = &emac_netdev_ops; diff --git a/drivers/net/declance.c b/drivers/net/declance.c index b62405a69180..2b22e580c4de 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -895,6 +895,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; volatile u16 *ib = (volatile u16 *)dev->mem_start; + unsigned long flags; int entry, len; len = skb->len; @@ -907,6 +908,8 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += len; + spin_lock_irqsave(&lp->lock, flags); + entry = lp->tx_new; *lib_ptr(ib, btx_ring[entry].length, lp->type) = (-len); *lib_ptr(ib, btx_ring[entry].misc, lp->type) = 0; @@ -925,6 +928,8 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Kick the lance: transmit now */ writereg(&ll->rdp, LE_C0_INEA | LE_C0_TDMD); + spin_unlock_irqrestore(&lp->lock, flags); + dev->trans_start = jiffies; dev_kfree_skb(skb); diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 4a1b554654eb..895d72143ee0 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -539,7 +539,7 @@ rio_tx_timeout (struct net_device *dev) dev->name, readl (ioaddr + TxStatus)); rio_free_tx(dev, 0); dev->if_port = 0; - dev->trans_start = jiffies; + dev->trans_start = jiffies; /* prevent tx timeout */ } /* allocate and initialize Tx and Rx descriptors */ @@ -610,7 +610,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev) if (np->link_status == 0) { /* Link Down */ dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } ioaddr = dev->base_addr; entry = np->cur_tx % TX_RING_SIZE; @@ -665,9 +665,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev) writel (0, dev->base_addr + TFDListPtr1); } - /* NETDEV WATCHDOG timer */ - dev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static irqreturn_t diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 0f9ee1348552..119dc5300f9d 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -143,6 +143,8 @@ * FIXES: * 2005/12/02 - Michael O'Donnell <Michael.ODonnell at stratus dot com> * - Stratus87247: protect MDI control register manipulations + * 2009/06/01 - Andreas Mohr <andi at lisas dot de> + * - add clean lowlevel I/O emulation for cards with MII-lacking PHYs */ #include <linux/module.h> @@ -372,6 +374,7 @@ enum eeprom_op { enum eeprom_offsets { eeprom_cnfg_mdix = 0x03, + eeprom_phy_iface = 0x06, eeprom_id = 0x0A, eeprom_config_asf = 0x0D, eeprom_smbus_addr = 0x90, @@ -381,6 +384,18 @@ enum eeprom_cnfg_mdix { eeprom_mdix_enabled = 0x0080, }; +enum eeprom_phy_iface { + NoSuchPhy = 0, + I82553AB, + I82553C, + I82503, + DP83840, + S80C240, + S80C24, + I82555, + DP83840A = 10, +}; + enum eeprom_id { eeprom_id_wol = 0x0020, }; @@ -545,6 +560,7 @@ struct nic { u32 msg_enable ____cacheline_aligned; struct net_device *netdev; struct pci_dev *pdev; + u16 (*mdio_ctrl)(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data); struct rx *rxs ____cacheline_aligned; struct rx *rx_to_use; @@ -899,7 +915,21 @@ err_unlock: return err; } -static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) +static int mdio_read(struct net_device *netdev, int addr, int reg) +{ + struct nic *nic = netdev_priv(netdev); + return nic->mdio_ctrl(nic, addr, mdi_read, reg, 0); +} + +static void mdio_write(struct net_device *netdev, int addr, int reg, int data) +{ + struct nic *nic = netdev_priv(netdev); + + nic->mdio_ctrl(nic, addr, mdi_write, reg, data); +} + +/* the standard mdio_ctrl() function for usual MII-compliant hardware */ +static u16 mdio_ctrl_hw(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) { u32 data_out = 0; unsigned int i; @@ -938,30 +968,83 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) return (u16)data_out; } -static int mdio_read(struct net_device *netdev, int addr, int reg) -{ - return mdio_ctrl(netdev_priv(netdev), addr, mdi_read, reg, 0); +/* slightly tweaked mdio_ctrl() function for phy_82552_v specifics */ +static u16 mdio_ctrl_phy_82552_v(struct nic *nic, + u32 addr, + u32 dir, + u32 reg, + u16 data) +{ + if ((reg == MII_BMCR) && (dir == mdi_write)) { + if (data & (BMCR_ANRESTART | BMCR_ANENABLE)) { + u16 advert = mdio_read(nic->netdev, nic->mii.phy_id, + MII_ADVERTISE); + + /* + * Workaround Si issue where sometimes the part will not + * autoneg to 100Mbps even when advertised. + */ + if (advert & ADVERTISE_100FULL) + data |= BMCR_SPEED100 | BMCR_FULLDPLX; + else if (advert & ADVERTISE_100HALF) + data |= BMCR_SPEED100; + } + } + return mdio_ctrl_hw(nic, addr, dir, reg, data); } -static void mdio_write(struct net_device *netdev, int addr, int reg, int data) -{ - struct nic *nic = netdev_priv(netdev); - - if ((nic->phy == phy_82552_v) && (reg == MII_BMCR) && - (data & (BMCR_ANRESTART | BMCR_ANENABLE))) { - u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE); - - /* - * Workaround Si issue where sometimes the part will not - * autoneg to 100Mbps even when advertised. - */ - if (advert & ADVERTISE_100FULL) - data |= BMCR_SPEED100 | BMCR_FULLDPLX; - else if (advert & ADVERTISE_100HALF) - data |= BMCR_SPEED100; +/* Fully software-emulated mdio_ctrl() function for cards without + * MII-compliant PHYs. + * For now, this is mainly geared towards 80c24 support; in case of further + * requirements for other types (i82503, ...?) either extend this mechanism + * or split it, whichever is cleaner. + */ +static u16 mdio_ctrl_phy_mii_emulated(struct nic *nic, + u32 addr, + u32 dir, + u32 reg, + u16 data) +{ + /* might need to allocate a netdev_priv'ed register array eventually + * to be able to record state changes, but for now + * some fully hardcoded register handling ought to be ok I guess. */ + + if (dir == mdi_read) { + switch (reg) { + case MII_BMCR: + /* Auto-negotiation, right? */ + return BMCR_ANENABLE | + BMCR_FULLDPLX; + case MII_BMSR: + return BMSR_LSTATUS /* for mii_link_ok() */ | + BMSR_ANEGCAPABLE | + BMSR_10FULL; + case MII_ADVERTISE: + /* 80c24 is a "combo card" PHY, right? */ + return ADVERTISE_10HALF | + ADVERTISE_10FULL; + default: + DPRINTK(HW, DEBUG, + "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n", + dir == mdi_read ? "READ" : "WRITE", addr, reg, data); + return 0xFFFF; + } + } else { + switch (reg) { + default: + DPRINTK(HW, DEBUG, + "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n", + dir == mdi_read ? "READ" : "WRITE", addr, reg, data); + return 0xFFFF; + } } - - mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data); +} +static inline int e100_phy_supports_mii(struct nic *nic) +{ + /* for now, just check it by comparing whether we + are using MII software emulation. + */ + return (nic->mdio_ctrl != mdio_ctrl_phy_mii_emulated); } static void e100_get_defaults(struct nic *nic) @@ -1013,7 +1096,8 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) config->standard_stat_counter = 0x1; /* 1=standard, 0=extended */ config->rx_discard_short_frames = 0x1; /* 1=discard, 0=pass */ config->tx_underrun_retry = 0x3; /* # of underrun retries */ - config->mii_mode = 0x1; /* 1=MII mode, 0=503 mode */ + if (e100_phy_supports_mii(nic)) + config->mii_mode = 1; /* 1=MII mode, 0=i82503 mode */ config->pad10 = 0x6; config->no_source_addr_insertion = 0x1; /* 1=no, 0=yes */ config->preamble_length = 0x2; /* 0=1, 1=3, 2=7, 3=15 bytes */ @@ -1270,6 +1354,42 @@ static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb) offsetof(struct mem, dump_buf)); } +static int e100_phy_check_without_mii(struct nic *nic) +{ + u8 phy_type; + int without_mii; + + phy_type = (nic->eeprom[eeprom_phy_iface] >> 8) & 0x0f; + + switch (phy_type) { + case NoSuchPhy: /* Non-MII PHY; UNTESTED! */ + case I82503: /* Non-MII PHY; UNTESTED! */ + case S80C24: /* Non-MII PHY; tested and working */ + /* paragraph from the FreeBSD driver, "FXP_PHY_80C24": + * The Seeq 80c24 AutoDUPLEX(tm) Ethernet Interface Adapter + * doesn't have a programming interface of any sort. The + * media is sensed automatically based on how the link partner + * is configured. This is, in essence, manual configuration. + */ + DPRINTK(PROBE, INFO, + "found MII-less i82503 or 80c24 or other PHY\n"); + + nic->mdio_ctrl = mdio_ctrl_phy_mii_emulated; + nic->mii.phy_id = 0; /* is this ok for an MII-less PHY? */ + + /* these might be needed for certain MII-less cards... + * nic->flags |= ich; + * nic->flags |= ich_10h_workaround; */ + + without_mii = 1; + break; + default: + without_mii = 0; + break; + } + return without_mii; +} + #define NCONFIG_AUTO_SWITCH 0x0080 #define MII_NSC_CONG MII_RESV1 #define NSC_CONG_ENABLE 0x0100 @@ -1290,9 +1410,21 @@ static int e100_phy_init(struct nic *nic) if (!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0)))) break; } - DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id); - if (addr == 32) - return -EAGAIN; + if (addr == 32) { + /* uhoh, no PHY detected: check whether we seem to be some + * weird, rare variant which is *known* to not have any MII. + * But do this AFTER MII checking only, since this does + * lookup of EEPROM values which may easily be unreliable. */ + if (e100_phy_check_without_mii(nic)) + return 0; /* simply return and hope for the best */ + else { + /* for unknown cases log a fatal error */ + DPRINTK(HW, ERR, + "Failed to locate any known PHY, aborting.\n"); + return -EAGAIN; + } + } else + DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id); /* Isolate all the PHY ids */ for (addr = 0; addr < 32; addr++) @@ -1320,6 +1452,9 @@ static int e100_phy_init(struct nic *nic) if (nic->phy == phy_82552_v) { u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE); + /* assign special tweaked mdio_ctrl() function */ + nic->mdio_ctrl = mdio_ctrl_phy_82552_v; + /* Workaround Si not advertising flow-control during autoneg */ advert |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; mdio_write(netdev, nic->mii.phy_id, MII_ADVERTISE, advert); @@ -2585,6 +2720,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, nic->netdev = netdev; nic->pdev = pdev; nic->msg_enable = (1 << debug) - 1; + nic->mdio_ctrl = mdio_ctrl_hw; pci_set_drvdata(pdev, netdev); if ((err = pci_enable_device(pdev))) { @@ -2822,12 +2958,13 @@ static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); - /* Similar to calling e100_down(), but avoids adapter I/O. */ - e100_close(netdev); - - /* Detach; put netif into a state similar to hotplug unplug. */ - napi_enable(&nic->napi); netif_device_detach(netdev); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + if (netif_running(netdev)) + e100_down(nic); pci_disable_device(pdev); /* Request a slot reset. */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 9a32d0c73cb3..8d36743c8140 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2330,7 +2330,8 @@ static void e1000_set_rx_mode(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct dev_addr_list *uc_ptr; + struct netdev_hw_addr *ha; + bool use_uc = false; struct dev_addr_list *mc_ptr; u32 rctl; u32 hash_value; @@ -2369,12 +2370,11 @@ static void e1000_set_rx_mode(struct net_device *netdev) rctl |= E1000_RCTL_VFE; } - uc_ptr = NULL; if (netdev->uc_count > rar_entries - 1) { rctl |= E1000_RCTL_UPE; } else if (!(netdev->flags & IFF_PROMISC)) { rctl &= ~E1000_RCTL_UPE; - uc_ptr = netdev->uc_list; + use_uc = true; } ew32(RCTL, rctl); @@ -2392,13 +2392,20 @@ static void e1000_set_rx_mode(struct net_device *netdev) * if there are not 14 addresses, go ahead and clear the filters * -- with 82571 controllers only 0-13 entries are filled here */ + i = 1; + if (use_uc) + list_for_each_entry(ha, &netdev->uc_list, list) { + if (i == rar_entries) + break; + e1000_rar_set(hw, ha->addr, i++); + } + + WARN_ON(i == rar_entries); + mc_ptr = netdev->mc_list; - for (i = 1; i < rar_entries; i++) { - if (uc_ptr) { - e1000_rar_set(hw, uc_ptr->da_addr, i); - uc_ptr = uc_ptr->next; - } else if (mc_ptr) { + for (; i < rar_entries; i++) { + if (mc_ptr) { e1000_rar_set(hw, mc_ptr->da_addr, i); mc_ptr = mc_ptr->next; } else { @@ -2408,7 +2415,6 @@ static void e1000_set_rx_mode(struct net_device *netdev) E1000_WRITE_FLUSH(); } } - WARN_ON(uc_ptr != NULL); /* load any remaining addresses into the hash table */ @@ -2992,7 +2998,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, size -= 4; buffer_info->length = size; - buffer_info->dma = map[0] + offset; + buffer_info->dma = skb_shinfo(skb)->dma_head + offset; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; @@ -3033,7 +3039,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, size -= 4; buffer_info->length = size; - buffer_info->dma = map[f + 1] + offset; + buffer_info->dma = map[f] + offset; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; @@ -3365,7 +3371,6 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (count) { e1000_tx_queue(adapter, tx_ring, tx_flags, count); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2); @@ -4030,8 +4035,9 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, PCI_DMA_FROMDEVICE); length = le16_to_cpu(rx_desc->length); - - if (unlikely(!(status & E1000_RXD_STAT_EOP))) { + /* !EOP means multiple descriptors were used to store a single + * packet, also make sure the frame isn't just CRC only */ + if (unlikely(!(status & E1000_RXD_STAT_EOP) || (length <= 4))) { /* All receives must fit into a single buffer */ E1000_DBG("%s: Receive packet consumed multiple" " buffers\n", netdev->name); diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 6c01a2072c87..b53b40ba88a8 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -71,6 +71,7 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw); static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); static s32 e1000_led_on_82574(struct e1000_hw *hw); +static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); /** * e1000_init_phy_params_82571 - Init PHY func ptrs. @@ -212,6 +213,9 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; struct e1000_mac_info *mac = &hw->mac; struct e1000_mac_operations *func = &mac->ops; + u32 swsm = 0; + u32 swsm2 = 0; + bool force_clear_smbi = false; /* Set media type */ switch (adapter->pdev->device) { @@ -276,6 +280,50 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) break; } + /* + * Ensure that the inter-port SWSM.SMBI lock bit is clear before + * first NVM or PHY acess. This should be done for single-port + * devices, and for one port only on dual-port devices so that + * for those devices we can still use the SMBI lock to synchronize + * inter-port accesses to the PHY & NVM. + */ + switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + swsm2 = er32(SWSM2); + + if (!(swsm2 & E1000_SWSM2_LOCK)) { + /* Only do this for the first interface on this card */ + ew32(SWSM2, + swsm2 | E1000_SWSM2_LOCK); + force_clear_smbi = true; + } else + force_clear_smbi = false; + break; + default: + force_clear_smbi = true; + break; + } + + if (force_clear_smbi) { + /* Make sure SWSM.SMBI is clear */ + swsm = er32(SWSM); + if (swsm & E1000_SWSM_SMBI) { + /* This bit should not be set on a first interface, and + * indicates that the bootagent or EFI code has + * improperly left this bit enabled + */ + hw_dbg(hw, "Please update your 82571 Bootagent\n"); + } + ew32(SWSM, swsm & ~E1000_SWSM_SMBI); + } + + /* + * Initialze device specific counter of SMBI acquisition + * timeouts. + */ + hw->dev_spec.e82571.smb_counter = 0; + return 0; } @@ -341,8 +389,10 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter) if (e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1, &eeprom_data) < 0) break; - if (eeprom_data & NVM_WORD1A_ASPM_MASK) - adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; + if (!(eeprom_data & NVM_WORD1A_ASPM_MASK)) { + adapter->flags |= FLAG_HAS_JUMBO_FRAMES; + adapter->max_hw_frame_size = DEFAULT_JUMBO; + } } break; default: @@ -411,11 +461,37 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) { u32 swsm; - s32 timeout = hw->nvm.word_size + 1; + s32 sw_timeout = hw->nvm.word_size + 1; + s32 fw_timeout = hw->nvm.word_size + 1; s32 i = 0; + /* + * If we have timedout 3 times on trying to acquire + * the inter-port SMBI semaphore, there is old code + * operating on the other port, and it is not + * releasing SMBI. Modify the number of times that + * we try for the semaphore to interwork with this + * older code. + */ + if (hw->dev_spec.e82571.smb_counter > 2) + sw_timeout = 1; + + /* Get the SW semaphore */ + while (i < sw_timeout) { + swsm = er32(SWSM); + if (!(swsm & E1000_SWSM_SMBI)) + break; + + udelay(50); + i++; + } + + if (i == sw_timeout) { + hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n"); + hw->dev_spec.e82571.smb_counter++; + } /* Get the FW semaphore. */ - for (i = 0; i < timeout; i++) { + for (i = 0; i < fw_timeout; i++) { swsm = er32(SWSM); ew32(SWSM, swsm | E1000_SWSM_SWESMBI); @@ -426,9 +502,9 @@ static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) udelay(50); } - if (i == timeout) { + if (i == fw_timeout) { /* Release semaphores */ - e1000e_put_hw_semaphore(hw); + e1000_put_hw_semaphore_82571(hw); hw_dbg(hw, "Driver can't access the NVM\n"); return -E1000_ERR_NVM; } @@ -447,9 +523,7 @@ static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) u32 swsm; swsm = er32(SWSM); - - swsm &= ~E1000_SWSM_SWESMBI; - + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); ew32(SWSM, swsm); } @@ -1585,6 +1659,7 @@ static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw) static struct e1000_mac_operations e82571_mac_ops = { /* .check_mng_mode: mac type dependent */ /* .check_for_link: media type dependent */ + .id_led_init = e1000e_id_led_init, .cleanup_led = e1000e_cleanup_led_generic, .clear_hw_cntrs = e1000_clear_hw_cntrs_82571, .get_bus_info = e1000e_get_bus_info_pcie, @@ -1596,6 +1671,7 @@ static struct e1000_mac_operations e82571_mac_ops = { .init_hw = e1000_init_hw_82571, .setup_link = e1000_setup_link_82571, /* .setup_physical_interface: media type dependent */ + .setup_led = e1000e_setup_led_generic, }; static struct e1000_phy_operations e82_phy_ops_igp = { @@ -1672,6 +1748,7 @@ struct e1000_info e1000_82571_info = { | FLAG_TARC_SPEED_MODE_BIT /* errata */ | FLAG_APME_CHECK_PORT_B, .pba = 38, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_igp, @@ -1688,6 +1765,7 @@ struct e1000_info e1000_82572_info = { | FLAG_HAS_CTRLEXT_ON_LOAD | FLAG_TARC_SPEED_MODE_BIT, /* errata */ .pba = 38, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_igp, @@ -1706,6 +1784,7 @@ struct e1000_info e1000_82573_info = { | FLAG_HAS_ERT | FLAG_HAS_SWSM_ON_LOAD, .pba = 20, + .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_m88, @@ -1724,6 +1803,7 @@ struct e1000_info e1000_82574_info = { | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, .pba = 20, + .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_bm, @@ -1740,6 +1820,7 @@ struct e1000_info e1000_82583_info = { | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, .pba = 20, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, .mac_ops = &e82571_mac_ops, .phy_ops = &e82_phy_ops_bm, diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 243aa499fe90..8890c97e1120 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -56,6 +56,7 @@ /* Wake Up Control */ #define E1000_WUC_APME 0x00000001 /* APM Enable */ #define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ +#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ /* Wake Up Filter Control */ #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ @@ -65,6 +66,13 @@ #define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ #define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ +/* Wake Up Status */ +#define E1000_WUS_LNKC E1000_WUFC_LNKC +#define E1000_WUS_MAG E1000_WUFC_MAG +#define E1000_WUS_EX E1000_WUFC_EX +#define E1000_WUS_MC E1000_WUFC_MC +#define E1000_WUS_BC E1000_WUFC_BC + /* Extended Device Control */ #define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */ #define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ @@ -77,6 +85,7 @@ #define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ #define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ #define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ +#define E1000_CTRL_EXT_PHYPDEN 0x00100000 /* Receive Descriptor bit definitions */ #define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ @@ -140,6 +149,7 @@ #define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ #define E1000_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min threshold size */ #define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ #define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ /* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ #define E1000_RCTL_SZ_2048 0x00000000 /* Rx buffer size 2048 */ @@ -153,6 +163,7 @@ #define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ #define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ #define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ #define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ #define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ @@ -255,11 +266,16 @@ #define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX /* LED Control */ +#define E1000_PHY_LED0_MODE_MASK 0x00000007 +#define E1000_PHY_LED0_IVRT 0x00000008 +#define E1000_PHY_LED0_MASK 0x0000001F + #define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F #define E1000_LEDCTL_LED0_MODE_SHIFT 0 #define E1000_LEDCTL_LED0_IVRT 0x00000040 #define E1000_LEDCTL_LED0_BLINK 0x00000080 +#define E1000_LEDCTL_MODE_LINK_UP 0x2 #define E1000_LEDCTL_MODE_LED_ON 0xE #define E1000_LEDCTL_MODE_LED_OFF 0xF @@ -360,6 +376,8 @@ #define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ #define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ +#define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */ + /* Interrupt Cause Read */ #define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ #define E1000_ICR_LSC 0x00000004 /* Link Status Change */ @@ -469,6 +487,8 @@ #define AUTO_READ_DONE_TIMEOUT 10 /* Flow Control */ +#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ +#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ #define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ /* Transmit Configuration Word */ @@ -674,6 +694,8 @@ #define IFE_C_E_PHY_ID 0x02A80310 #define BME1000_E_PHY_ID 0x01410CB0 #define BME1000_E_PHY_ID_R2 0x01410CB1 +#define I82577_E_PHY_ID 0x01540050 +#define I82578_E_PHY_ID 0x004DD040 /* M88E1000 Specific Registers */ #define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ @@ -727,6 +749,9 @@ #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 +#define I82578_EPSCR_DOWNSHIFT_ENABLE 0x0020 +#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK 0x001C + /* BME1000 PHY Specific Control Register */ #define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */ diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index f37360aa12a8..d6e491bc58c9 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -96,6 +96,51 @@ struct e1000_info; /* Number of packet split data buffers (not including the header buffer) */ #define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1) +#define DEFAULT_JUMBO 9234 + +/* BM/HV Specific Registers */ +#define BM_PORT_CTRL_PAGE 769 + +#define PHY_UPPER_SHIFT 21 +#define BM_PHY_REG(page, reg) \ + (((reg) & MAX_PHY_REG_ADDRESS) |\ + (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\ + (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT))) + +/* PHY Wakeup Registers and defines */ +#define BM_RCTL PHY_REG(BM_WUC_PAGE, 0) +#define BM_WUC PHY_REG(BM_WUC_PAGE, 1) +#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2) +#define BM_WUS PHY_REG(BM_WUC_PAGE, 3) +#define BM_RAR_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2))) +#define BM_RAR_M(_i) (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2))) +#define BM_RAR_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2))) +#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2))) +#define BM_MTA(_i) (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1))) + +#define BM_RCTL_UPE 0x0001 /* Unicast Promiscuous Mode */ +#define BM_RCTL_MPE 0x0002 /* Multicast Promiscuous Mode */ +#define BM_RCTL_MO_SHIFT 3 /* Multicast Offset Shift */ +#define BM_RCTL_MO_MASK (3 << 3) /* Multicast Offset Mask */ +#define BM_RCTL_BAM 0x0020 /* Broadcast Accept Mode */ +#define BM_RCTL_PMCF 0x0040 /* Pass MAC Control Frames */ +#define BM_RCTL_RFCE 0x0080 /* Rx Flow Control Enable */ + +#define HV_SCC_UPPER PHY_REG(778, 16) /* Single Collision Count */ +#define HV_SCC_LOWER PHY_REG(778, 17) +#define HV_ECOL_UPPER PHY_REG(778, 18) /* Excessive Collision Count */ +#define HV_ECOL_LOWER PHY_REG(778, 19) +#define HV_MCC_UPPER PHY_REG(778, 20) /* Multiple Collision Count */ +#define HV_MCC_LOWER PHY_REG(778, 21) +#define HV_LATECOL_UPPER PHY_REG(778, 23) /* Late Collision Count */ +#define HV_LATECOL_LOWER PHY_REG(778, 24) +#define HV_COLC_UPPER PHY_REG(778, 25) /* Collision Count */ +#define HV_COLC_LOWER PHY_REG(778, 26) +#define HV_DC_UPPER PHY_REG(778, 27) /* Defer Count */ +#define HV_DC_LOWER PHY_REG(778, 28) +#define HV_TNCRS_UPPER PHY_REG(778, 29) /* Transmit with no CRS */ +#define HV_TNCRS_LOWER PHY_REG(778, 30) + enum e1000_boards { board_82571, board_82572, @@ -106,6 +151,7 @@ enum e1000_boards { board_ich8lan, board_ich9lan, board_ich10lan, + board_pchlan, }; struct e1000_queue_stats { @@ -293,6 +339,7 @@ struct e1000_adapter { u32 eeprom_wol; u32 wol; u32 pba; + u32 max_hw_frame_size; bool fc_autoneg; @@ -302,6 +349,7 @@ struct e1000_adapter { unsigned int flags2; struct work_struct downshift_task; struct work_struct update_phy_task; + struct work_struct led_blink_task; }; struct e1000_info { @@ -309,6 +357,7 @@ struct e1000_info { unsigned int flags; unsigned int flags2; u32 pba; + u32 max_hw_frame_size; s32 (*get_variants)(struct e1000_adapter *); struct e1000_mac_operations *mac_ops; struct e1000_phy_operations *phy_ops; @@ -351,6 +400,7 @@ struct e1000_info { /* CRC Stripping defines */ #define FLAG2_CRC_STRIPPING (1 << 0) +#define FLAG2_HAS_PHY_WAKEUP (1 << 1) #define E1000_RX_DESC_PS(R, i) \ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) @@ -404,6 +454,7 @@ extern struct e1000_info e1000_82583_info; extern struct e1000_info e1000_ich8_info; extern struct e1000_info e1000_ich9_info; extern struct e1000_info e1000_ich10_info; +extern struct e1000_info e1000_pch_info; extern struct e1000_info e1000_es2_info; extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num); @@ -425,6 +476,7 @@ extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw); extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw); extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw); extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw); +extern s32 e1000e_setup_led_generic(struct e1000_hw *hw); extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw); extern s32 e1000e_led_on_generic(struct e1000_hw *hw); extern s32 e1000e_led_off_generic(struct e1000_hw *hw); @@ -493,6 +545,15 @@ extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw); extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); extern s32 e1000e_check_downshift(struct e1000_hw *hw); +extern s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data); +extern s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data); +extern s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow); +extern s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw); +extern s32 e1000_copper_link_setup_82577(struct e1000_hw *hw); +extern s32 e1000_check_polarity_82577(struct e1000_hw *hw); +extern s32 e1000_get_phy_info_82577(struct e1000_hw *hw); +extern s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw); +extern s32 e1000_get_cable_length_82577(struct e1000_hw *hw); static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw) { diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index 8964838c686b..ae5d73689353 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -1366,6 +1366,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw) } static struct e1000_mac_operations es2_mac_ops = { + .id_led_init = e1000e_id_led_init, .check_mng_mode = e1000e_check_mng_mode_generic, /* check_for_link dependent on media type */ .cleanup_led = e1000e_cleanup_led_generic, @@ -1379,6 +1380,7 @@ static struct e1000_mac_operations es2_mac_ops = { .init_hw = e1000_init_hw_80003es2lan, .setup_link = e1000e_setup_link, /* setup_physical_interface dependent on media type */ + .setup_led = e1000e_setup_led_generic, }; static struct e1000_phy_operations es2_phy_ops = { @@ -1422,6 +1424,7 @@ struct e1000_info e1000_es2_info = { | FLAG_DISABLE_FC_PAUSE_TIME /* errata */ | FLAG_TIPG_MEDIUM_FOR_80003ESLAN, .pba = 38, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_80003es2lan, .mac_ops = &es2_mac_ops, .phy_ops = &es2_phy_ops, diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 4d25ede88369..1bf4d2a5d34f 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -167,6 +167,15 @@ static int e1000_get_settings(struct net_device *netdev, ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + + /* MDI-X => 2; MDI =>1; Invalid =>0 */ + if ((hw->phy.media_type == e1000_media_type_copper) && + !hw->mac.get_link_status) + ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X : + ETH_TP_MDI; + else + ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID; + return 0; } @@ -776,6 +785,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) u32 after; u32 i; u32 toggle; + u32 mask; /* * The status register is Read Only, so a write should fail. @@ -788,17 +798,9 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) case e1000_80003es2lan: toggle = 0x7FFFF3FF; break; - case e1000_82573: - case e1000_82574: - case e1000_82583: - case e1000_ich8lan: - case e1000_ich9lan: - case e1000_ich10lan: + default: toggle = 0x7FFFF033; break; - default: - toggle = 0xFFFFF833; - break; } before = er32(STATUS); @@ -844,11 +846,18 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF); REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF); + mask = 0x8003FFFF; + switch (mac->type) { + case e1000_ich10lan: + case e1000_pchlan: + mask |= (1 << 18); + break; + default: + break; + } for (i = 0; i < mac->rar_entry_count; i++) REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), - ((mac->type == e1000_ich10lan) ? - 0x8007FFFF : 0x8003FFFF), - 0xFFFFFFFF); + mask, 0xFFFFFFFF); for (i = 0; i < mac->mta_reg_count; i++) REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); @@ -1786,15 +1795,22 @@ static int e1000_set_wol(struct net_device *netdev, /* bit defines for adapter->led_status */ #define E1000_LED_ON 0 -static void e1000_led_blink_callback(unsigned long data) +static void e1000e_led_blink_task(struct work_struct *work) { - struct e1000_adapter *adapter = (struct e1000_adapter *) data; + struct e1000_adapter *adapter = container_of(work, + struct e1000_adapter, led_blink_task); if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) adapter->hw.mac.ops.led_off(&adapter->hw); else adapter->hw.mac.ops.led_on(&adapter->hw); +} + +static void e1000_led_blink_callback(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + schedule_work(&adapter->led_blink_task); mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); } @@ -1807,7 +1823,9 @@ static int e1000_phys_id(struct net_device *netdev, u32 data) data = INT_MAX; if ((hw->phy.type == e1000_phy_ife) || + (hw->mac.type == e1000_pchlan) || (hw->mac.type == e1000_82574)) { + INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task); if (!adapter->blink_timer.function) { init_timer(&adapter->blink_timer); adapter->blink_timer.function = diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 6cdb703be951..163c1c0cfee7 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -193,7 +193,11 @@ enum e1e_registers { E1000_RXCSUM = 0x05000, /* Rx Checksum Control - RW */ E1000_RFCTL = 0x05008, /* Receive Filter Control */ E1000_MTA = 0x05200, /* Multicast Table Array - RW Array */ - E1000_RA = 0x05400, /* Receive Address - RW Array */ + E1000_RAL_BASE = 0x05400, /* Receive Address Low - RW */ +#define E1000_RAL(_n) (E1000_RAL_BASE + ((_n) * 8)) +#define E1000_RA (E1000_RAL(0)) + E1000_RAH_BASE = 0x05404, /* Receive Address High - RW */ +#define E1000_RAH(_n) (E1000_RAH_BASE + ((_n) * 8)) E1000_VFTA = 0x05600, /* VLAN Filter Table Array - RW Array */ E1000_WUC = 0x05800, /* Wakeup Control - RW */ E1000_WUFC = 0x05808, /* Wakeup Filter Control - RW */ @@ -210,6 +214,7 @@ enum e1e_registers { E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */ E1000_SWSM = 0x05B50, /* SW Semaphore */ E1000_FWSM = 0x05B54, /* FW Semaphore */ + E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */ E1000_HICR = 0x08F00, /* Host Interface Control */ }; @@ -368,6 +373,10 @@ enum e1e_registers { #define E1000_DEV_ID_ICH10_R_BM_V 0x10CE #define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE #define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF +#define E1000_DEV_ID_PCH_M_HV_LM 0x10EA +#define E1000_DEV_ID_PCH_M_HV_LC 0x10EB +#define E1000_DEV_ID_PCH_D_HV_DM 0x10EF +#define E1000_DEV_ID_PCH_D_HV_DC 0x10F0 #define E1000_REVISION_4 4 @@ -383,6 +392,7 @@ enum e1000_mac_type { e1000_ich8lan, e1000_ich9lan, e1000_ich10lan, + e1000_pchlan, }; enum e1000_media_type { @@ -417,6 +427,8 @@ enum e1000_phy_type { e1000_phy_igp_3, e1000_phy_ife, e1000_phy_bm, + e1000_phy_82578, + e1000_phy_82577, }; enum e1000_bus_width { @@ -720,6 +732,7 @@ struct e1000_host_mng_command_info { /* Function pointers and static data for the MAC. */ struct e1000_mac_operations { + s32 (*id_led_init)(struct e1000_hw *); bool (*check_mng_mode)(struct e1000_hw *); s32 (*check_for_link)(struct e1000_hw *); s32 (*cleanup_led)(struct e1000_hw *); @@ -733,11 +746,13 @@ struct e1000_mac_operations { s32 (*init_hw)(struct e1000_hw *); s32 (*setup_link)(struct e1000_hw *); s32 (*setup_physical_interface)(struct e1000_hw *); + s32 (*setup_led)(struct e1000_hw *); }; /* Function pointers for the PHY. */ struct e1000_phy_operations { s32 (*acquire_phy)(struct e1000_hw *); + s32 (*check_polarity)(struct e1000_hw *); s32 (*check_reset_block)(struct e1000_hw *); s32 (*commit_phy)(struct e1000_hw *); s32 (*force_speed_duplex)(struct e1000_hw *); @@ -869,6 +884,7 @@ struct e1000_fc_info { struct e1000_dev_spec_82571 { bool laa_is_present; bool alt_mac_addr_is_present; + u32 smb_counter; }; struct e1000_shadow_ram { diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 6d1aab6316ba..9e23f50fb9cd 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -48,6 +48,10 @@ * 82567LF-3 Gigabit Network Connection * 82567LM-3 Gigabit Network Connection * 82567LM-4 Gigabit Network Connection + * 82577LM Gigabit Network Connection + * 82577LC Gigabit Network Connection + * 82578DM Gigabit Network Connection + * 82578DC Gigabit Network Connection */ #include <linux/netdevice.h> @@ -116,6 +120,8 @@ #define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300 #define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200 +#define HV_LED_CONFIG PHY_REG(768, 30) /* LED Configuration */ + /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ /* Offset 04h HSFSTS */ union ich8_hws_flash_status { @@ -186,6 +192,14 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw); static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); +static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); +static s32 e1000_led_on_ich8lan(struct e1000_hw *hw); +static s32 e1000_led_off_ich8lan(struct e1000_hw *hw); +static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw); +static s32 e1000_setup_led_pchlan(struct e1000_hw *hw); +static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); +static s32 e1000_led_on_pchlan(struct e1000_hw *hw); +static s32 e1000_led_off_pchlan(struct e1000_hw *hw); static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) { @@ -213,6 +227,41 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val) #define ew32flash(reg,val) __ew32flash(hw, (reg), (val)) /** + * e1000_init_phy_params_pchlan - Initialize PHY function pointers + * @hw: pointer to the HW structure + * + * Initialize family-specific PHY parameters and function pointers. + **/ +static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = 0; + + phy->addr = 1; + phy->reset_delay_us = 100; + + phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan; + phy->ops.read_phy_reg = e1000_read_phy_reg_hv; + phy->ops.write_phy_reg = e1000_write_phy_reg_hv; + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + + phy->id = e1000_phy_unknown; + e1000e_get_phy_id(hw); + phy->type = e1000e_get_phy_type_from_id(phy->id); + + if (phy->type == e1000_phy_82577) { + phy->ops.check_polarity = e1000_check_polarity_82577; + phy->ops.force_speed_duplex = + e1000_phy_force_speed_duplex_82577; + phy->ops.get_cable_length = e1000_get_cable_length_82577; + phy->ops.get_phy_info = e1000_get_phy_info_82577; + phy->ops.commit_phy = e1000e_phy_sw_reset; + } + + return ret_val; +} + +/** * e1000_init_phy_params_ich8lan - Initialize PHY function pointers * @hw: pointer to the HW structure * @@ -273,6 +322,8 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) break; } + phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan; + return 0; } @@ -358,6 +409,36 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter) /* Set if manageability features are enabled. */ mac->arc_subsystem_valid = 1; + /* LED operations */ + switch (mac->type) { + case e1000_ich8lan: + case e1000_ich9lan: + case e1000_ich10lan: + /* ID LED init */ + mac->ops.id_led_init = e1000e_id_led_init; + /* setup LED */ + mac->ops.setup_led = e1000e_setup_led_generic; + /* cleanup LED */ + mac->ops.cleanup_led = e1000_cleanup_led_ich8lan; + /* turn on/off LED */ + mac->ops.led_on = e1000_led_on_ich8lan; + mac->ops.led_off = e1000_led_off_ich8lan; + break; + case e1000_pchlan: + /* ID LED init */ + mac->ops.id_led_init = e1000_id_led_init_pchlan; + /* setup LED */ + mac->ops.setup_led = e1000_setup_led_pchlan; + /* cleanup LED */ + mac->ops.cleanup_led = e1000_cleanup_led_pchlan; + /* turn on/off LED */ + mac->ops.led_on = e1000_led_on_pchlan; + mac->ops.led_off = e1000_led_off_pchlan; + break; + default: + break; + } + /* Enable PCS Lock-loss workaround for ICH8 */ if (mac->type == e1000_ich8lan) e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, 1); @@ -378,10 +459,18 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) if (rc) return rc; - rc = e1000_init_phy_params_ich8lan(hw); + if (hw->mac.type == e1000_pchlan) + rc = e1000_init_phy_params_pchlan(hw); + else + rc = e1000_init_phy_params_ich8lan(hw); if (rc) return rc; + if (adapter->hw.phy.type == e1000_phy_ife) { + adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; + adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN; + } + if ((adapter->hw.mac.type == e1000_ich8lan) && (adapter->hw.phy.type == e1000_phy_igp_3)) adapter->flags |= FLAG_LSC_GIG_SPEED_DROP; @@ -410,12 +499,15 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) while (timeout) { extcnf_ctrl = er32(EXTCNF_CTRL); - extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; - ew32(EXTCNF_CTRL, extcnf_ctrl); - extcnf_ctrl = er32(EXTCNF_CTRL); - if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) - break; + if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) { + extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; + ew32(EXTCNF_CTRL, extcnf_ctrl); + + extcnf_ctrl = er32(EXTCNF_CTRL); + if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + break; + } mdelay(1); timeout--; } @@ -555,6 +647,53 @@ static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw) } /** + * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be + * done after every PHY reset. + **/ +static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = 0; + + if (hw->mac.type != e1000_pchlan) + return ret_val; + + if (((hw->phy.type == e1000_phy_82577) && + ((hw->phy.revision == 1) || (hw->phy.revision == 2))) || + ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) { + /* Disable generation of early preamble */ + ret_val = e1e_wphy(hw, PHY_REG(769, 25), 0x4431); + if (ret_val) + return ret_val; + + /* Preamble tuning for SSC */ + ret_val = e1e_wphy(hw, PHY_REG(770, 16), 0xA204); + if (ret_val) + return ret_val; + } + + if (hw->phy.type == e1000_phy_82578) { + /* + * Return registers to default by doing a soft reset then + * writing 0x3140 to the control register. + */ + if (hw->phy.revision < 2) { + e1000e_phy_sw_reset(hw); + ret_val = e1e_wphy(hw, PHY_CONTROL, 0x3140); + } + } + + /* Select page 0 */ + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + hw->phy.addr = 1; + e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** * e1000_phy_hw_reset_ich8lan - Performs a PHY reset * @hw: pointer to the HW structure * @@ -575,6 +714,12 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) if (ret_val) return ret_val; + if (hw->mac.type == e1000_pchlan) { + ret_val = e1000_hv_phy_workarounds_ich8lan(hw); + if (ret_val) + return ret_val; + } + /* * Initialize the PHY from the NVM on ICH platforms. This * is needed due to an issue where the NVM configuration is @@ -701,7 +846,7 @@ static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw) phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE)); if (phy->polarity_correction) { - ret_val = e1000_check_polarity_ife_ich8lan(hw); + ret_val = phy->ops.check_polarity(hw); if (ret_val) return ret_val; } else { @@ -741,6 +886,8 @@ static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw) break; case e1000_phy_igp_3: case e1000_phy_bm: + case e1000_phy_82578: + case e1000_phy_82577: return e1000e_get_phy_info_igp(hw); break; default: @@ -1852,6 +1999,79 @@ static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) } /** + * e1000_id_led_init_pchlan - store LED configurations + * @hw: pointer to the HW structure + * + * PCH does not control LEDs via the LEDCTL register, rather it uses + * the PHY LED configuration register. + * + * PCH also does not have an "always on" or "always off" mode which + * complicates the ID feature. Instead of using the "on" mode to indicate + * in ledctl_mode2 the LEDs to use for ID (see e1000e_id_led_init()), + * use "link_up" mode. The LEDs will still ID on request if there is no + * link based on logic in e1000_led_[on|off]_pchlan(). + **/ +static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP; + const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT; + u16 data, i, temp, shift; + + /* Get default ID LED modes */ + ret_val = hw->nvm.ops.valid_led_default(hw, &data); + if (ret_val) + goto out; + + mac->ledctl_default = er32(LEDCTL); + mac->ledctl_mode1 = mac->ledctl_default; + mac->ledctl_mode2 = mac->ledctl_default; + + for (i = 0; i < 4; i++) { + temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK; + shift = (i * 5); + switch (temp) { + case ID_LED_ON1_DEF2: + case ID_LED_ON1_ON2: + case ID_LED_ON1_OFF2: + mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode1 |= (ledctl_on << shift); + break; + case ID_LED_OFF1_DEF2: + case ID_LED_OFF1_ON2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode1 |= (ledctl_off << shift); + break; + default: + /* Do nothing */ + break; + } + switch (temp) { + case ID_LED_DEF1_ON2: + case ID_LED_ON1_ON2: + case ID_LED_OFF1_ON2: + mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode2 |= (ledctl_on << shift); + break; + case ID_LED_DEF1_OFF2: + case ID_LED_ON1_OFF2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); + mac->ledctl_mode2 |= (ledctl_off << shift); + break; + default: + /* Do nothing */ + break; + } + } + +out: + return ret_val; +} + +/** * e1000_get_bus_info_ich8lan - Get/Set the bus type and width * @hw: pointer to the HW structure * @@ -1960,6 +2180,9 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) kab |= E1000_KABGTXD_BGSQLBIAS; ew32(KABGTXD, kab); + if (hw->mac.type == e1000_pchlan) + ret_val = e1000_hv_phy_workarounds_ich8lan(hw); + return ret_val; } @@ -1985,7 +2208,7 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) e1000_initialize_hw_bits_ich8lan(hw); /* Initialize identification LED */ - ret_val = e1000e_id_led_init(hw); + ret_val = mac->ops.id_led_init(hw); if (ret_val) { hw_dbg(hw, "Error initializing identification LED\n"); return ret_val; @@ -2031,6 +2254,16 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) ew32(CTRL_EXT, ctrl_ext); /* + * The 82578 Rx buffer will stall if wakeup is enabled in host and + * the ME. Reading the BM_WUC register will clear the host wakeup bit. + * Reset the phy after disabling host wakeup to reset the Rx buffer. + */ + if (hw->phy.type == e1000_phy_82578) { + e1e_rphy(hw, BM_WUC, &i); + e1000e_phy_hw_reset_generic(hw); + } + + /* * Clear all of the statistics registers (clear on read). It is * important that we do this after we have tried to establish link * because the symbol error count will increment wildly if there @@ -2054,6 +2287,9 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) /* Extended Device Control */ reg = er32(CTRL_EXT); reg |= (1 << 22); + /* Enable PHY low-power state when MAC is at D3 w/o WoL */ + if (hw->mac.type >= e1000_pchlan) + reg |= E1000_CTRL_EXT_PHYPDEN; ew32(CTRL_EXT, reg); /* Transmit Descriptor Control 0 */ @@ -2112,8 +2348,13 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) * the default flow control setting, so we explicitly * set it to full. */ - if (hw->fc.requested_mode == e1000_fc_default) - hw->fc.requested_mode = e1000_fc_full; + if (hw->fc.requested_mode == e1000_fc_default) { + /* Workaround h/w hang when Tx flow control enabled */ + if (hw->mac.type == e1000_pchlan) + hw->fc.requested_mode = e1000_fc_rx_pause; + else + hw->fc.requested_mode = e1000_fc_full; + } /* * Save off the requested flow control mode for use later. Depending @@ -2130,6 +2371,14 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) return ret_val; ew32(FCTTV, hw->fc.pause_time); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + ret_val = hw->phy.ops.write_phy_reg(hw, + PHY_REG(BM_PORT_CTRL_PAGE, 27), + hw->fc.pause_time); + if (ret_val) + return ret_val; + } return e1000e_set_fc_watermarks(hw); } @@ -2169,18 +2418,26 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) if (ret_val) return ret_val; - if (hw->phy.type == e1000_phy_igp_3) { + switch (hw->phy.type) { + case e1000_phy_igp_3: ret_val = e1000e_copper_link_setup_igp(hw); if (ret_val) return ret_val; - } else if (hw->phy.type == e1000_phy_bm) { + break; + case e1000_phy_bm: + case e1000_phy_82578: ret_val = e1000e_copper_link_setup_m88(hw); if (ret_val) return ret_val; - } - - if (hw->phy.type == e1000_phy_ife) { - ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, ®_data); + break; + case e1000_phy_82577: + ret_val = e1000_copper_link_setup_82577(hw); + if (ret_val) + return ret_val; + break; + case e1000_phy_ife: + ret_val = hw->phy.ops.read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, + ®_data); if (ret_val) return ret_val; @@ -2198,9 +2455,13 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) reg_data |= IFE_PMC_AUTO_MDIX; break; } - ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, reg_data); + ret_val = hw->phy.ops.write_phy_reg(hw, IFE_PHY_MDIX_CONTROL, + reg_data); if (ret_val) return ret_val; + break; + default: + break; } return e1000e_setup_copper_link(hw); } @@ -2417,18 +2678,26 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation * to a lower speed. * - * Should only be called for ICH9 and ICH10 devices. + * Should only be called for applicable parts. **/ void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw) { u32 phy_ctrl; - if ((hw->mac.type == e1000_ich10lan) || - (hw->mac.type == e1000_ich9lan)) { + switch (hw->mac.type) { + case e1000_ich9lan: + case e1000_ich10lan: + case e1000_pchlan: phy_ctrl = er32(PHY_CTRL); phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE; ew32(PHY_CTRL, phy_ctrl); + + /* Workaround SWFLAG unexpectedly set during S0->Sx */ + if (hw->mac.type == e1000_pchlan) + udelay(500); + default: + break; } return; @@ -2482,13 +2751,99 @@ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) } /** + * e1000_setup_led_pchlan - Configures SW controllable LED + * @hw: pointer to the HW structure + * + * This prepares the SW controllable LED for use. + **/ +static s32 e1000_setup_led_pchlan(struct e1000_hw *hw) +{ + return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, + (u16)hw->mac.ledctl_mode1); +} + +/** + * e1000_cleanup_led_pchlan - Restore the default LED operation + * @hw: pointer to the HW structure + * + * Return the LED back to the default configuration. + **/ +static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw) +{ + return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, + (u16)hw->mac.ledctl_default); +} + +/** + * e1000_led_on_pchlan - Turn LEDs on + * @hw: pointer to the HW structure + * + * Turn on the LEDs. + **/ +static s32 e1000_led_on_pchlan(struct e1000_hw *hw) +{ + u16 data = (u16)hw->mac.ledctl_mode2; + u32 i, led; + + /* + * If no link, then turn LED on by setting the invert bit + * for each LED that's mode is "link_up" in ledctl_mode2. + */ + if (!(er32(STATUS) & E1000_STATUS_LU)) { + for (i = 0; i < 3; i++) { + led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; + if ((led & E1000_PHY_LED0_MODE_MASK) != + E1000_LEDCTL_MODE_LINK_UP) + continue; + if (led & E1000_PHY_LED0_IVRT) + data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); + else + data |= (E1000_PHY_LED0_IVRT << (i * 5)); + } + } + + return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, data); +} + +/** + * e1000_led_off_pchlan - Turn LEDs off + * @hw: pointer to the HW structure + * + * Turn off the LEDs. + **/ +static s32 e1000_led_off_pchlan(struct e1000_hw *hw) +{ + u16 data = (u16)hw->mac.ledctl_mode1; + u32 i, led; + + /* + * If no link, then turn LED off by clearing the invert bit + * for each LED that's mode is "link_up" in ledctl_mode1. + */ + if (!(er32(STATUS) & E1000_STATUS_LU)) { + for (i = 0; i < 3; i++) { + led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; + if ((led & E1000_PHY_LED0_MODE_MASK) != + E1000_LEDCTL_MODE_LINK_UP) + continue; + if (led & E1000_PHY_LED0_IVRT) + data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); + else + data |= (E1000_PHY_LED0_IVRT << (i * 5)); + } + } + + return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, data); +} + +/** * e1000_get_cfg_done_ich8lan - Read config done bit * @hw: pointer to the HW structure * * Read the management control register for the config done bit for * completion status. NOTE: silicon which is EEPROM-less will fail trying * to read the config done bit, so an error is *ONLY* logged and returns - * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon + * 0. If we were to return with error, EEPROM-less silicon * would not be able to be reset or change link. **/ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) @@ -2498,7 +2853,8 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) e1000e_get_cfg_done(hw); /* If EEPROM is not marked present, init the IGP 3 PHY manually */ - if (hw->mac.type != e1000_ich10lan) { + if ((hw->mac.type != e1000_ich10lan) && + (hw->mac.type != e1000_pchlan)) { if (((er32(EECD) & E1000_EECD_PRES) == 0) && (hw->phy.type == e1000_phy_igp_3)) { e1000e_phy_init_script_igp3(hw); @@ -2524,6 +2880,7 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) { u32 temp; + u16 phy_data; e1000e_clear_hw_cntrs_base(hw); @@ -2541,22 +2898,42 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) temp = er32(IAC); temp = er32(ICRXOC); + /* Clear PHY statistics registers */ + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + hw->phy.ops.read_phy_reg(hw, HV_SCC_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_SCC_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_ECOL_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_ECOL_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_MCC_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_MCC_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_LATECOL_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_LATECOL_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_COLC_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_COLC_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_DC_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_DC_LOWER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_TNCRS_UPPER, &phy_data); + hw->phy.ops.read_phy_reg(hw, HV_TNCRS_LOWER, &phy_data); + } } static struct e1000_mac_operations ich8_mac_ops = { + .id_led_init = e1000e_id_led_init, .check_mng_mode = e1000_check_mng_mode_ich8lan, .check_for_link = e1000e_check_for_copper_link, - .cleanup_led = e1000_cleanup_led_ich8lan, + /* cleanup_led dependent on mac type */ .clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan, .get_bus_info = e1000_get_bus_info_ich8lan, .get_link_up_info = e1000_get_link_up_info_ich8lan, - .led_on = e1000_led_on_ich8lan, - .led_off = e1000_led_off_ich8lan, + /* led_on dependent on mac type */ + /* led_off dependent on mac type */ .update_mc_addr_list = e1000e_update_mc_addr_list_generic, .reset_hw = e1000_reset_hw_ich8lan, .init_hw = e1000_init_hw_ich8lan, .setup_link = e1000_setup_link_ich8lan, .setup_physical_interface= e1000_setup_copper_link_ich8lan, + /* id_led_init dependent on mac type */ }; static struct e1000_phy_operations ich8_phy_ops = { @@ -2595,6 +2972,7 @@ struct e1000_info e1000_ich8_info = { | FLAG_HAS_FLASH | FLAG_APME_IN_WUC, .pba = 8, + .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_ich8lan, .mac_ops = &ich8_mac_ops, .phy_ops = &ich8_phy_ops, @@ -2613,6 +2991,7 @@ struct e1000_info e1000_ich9_info = { | FLAG_HAS_FLASH | FLAG_APME_IN_WUC, .pba = 10, + .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_ich8lan, .mac_ops = &ich8_mac_ops, .phy_ops = &ich8_phy_ops, @@ -2631,6 +3010,25 @@ struct e1000_info e1000_ich10_info = { | FLAG_HAS_FLASH | FLAG_APME_IN_WUC, .pba = 10, + .max_hw_frame_size = DEFAULT_JUMBO, + .get_variants = e1000_get_variants_ich8lan, + .mac_ops = &ich8_mac_ops, + .phy_ops = &ich8_phy_ops, + .nvm_ops = &ich8_nvm_ops, +}; + +struct e1000_info e1000_pch_info = { + .mac = e1000_pchlan, + .flags = FLAG_IS_ICH + | FLAG_HAS_WOL + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_FLASH + | FLAG_HAS_JUMBO_FRAMES + | FLAG_APME_IN_WUC, + .pba = 26, + .max_hw_frame_size = 4096, .get_variants = e1000_get_variants_ich8lan, .mac_ops = &ich8_mac_ops, .phy_ops = &ich8_phy_ops, diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 18a4f5902f3b..be6d9e990374 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -378,6 +378,12 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) mac->get_link_status = 0; + if (hw->phy.type == e1000_phy_82578) { + ret_val = e1000_link_stall_workaround_hv(hw); + if (ret_val) + return ret_val; + } + /* * Check if there was DownShift, must be checked * immediately after link-up @@ -1406,6 +1412,38 @@ s32 e1000e_id_led_init(struct e1000_hw *hw) } /** + * e1000e_setup_led_generic - Configures SW controllable LED + * @hw: pointer to the HW structure + * + * This prepares the SW controllable LED for use and saves the current state + * of the LED so it can be later restored. + **/ +s32 e1000e_setup_led_generic(struct e1000_hw *hw) +{ + u32 ledctl; + + if (hw->mac.ops.setup_led != e1000e_setup_led_generic) { + return -E1000_ERR_CONFIG; + } + + if (hw->phy.media_type == e1000_media_type_fiber) { + ledctl = er32(LEDCTL); + hw->mac.ledctl_default = ledctl; + /* Turn off LED0 */ + ledctl &= ~(E1000_LEDCTL_LED0_IVRT | + E1000_LEDCTL_LED0_BLINK | + E1000_LEDCTL_LED0_MODE_MASK); + ledctl |= (E1000_LEDCTL_MODE_LED_OFF << + E1000_LEDCTL_LED0_MODE_SHIFT); + ew32(LEDCTL, ledctl); + } else if (hw->phy.media_type == e1000_media_type_copper) { + ew32(LEDCTL, hw->mac.ledctl_mode1); + } + + return 0; +} + +/** * e1000e_cleanup_led_generic - Set LED config to default operation * @hw: pointer to the HW structure * diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index ccaaee0951cf..677f60490f67 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -48,7 +48,7 @@ #include "e1000.h" -#define DRV_VERSION "0.3.3.4-k4" +#define DRV_VERSION "1.0.2-k2" char e1000e_driver_name[] = "e1000e"; const char e1000e_driver_version[] = DRV_VERSION; @@ -62,6 +62,7 @@ static const struct e1000_info *e1000_info_tbl[] = { [board_ich8lan] = &e1000_ich8_info, [board_ich9lan] = &e1000_ich9_info, [board_ich10lan] = &e1000_ich10_info, + [board_pchlan] = &e1000_pch_info, }; #ifdef DEBUG @@ -2255,8 +2256,6 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) ew32(TARC(1), tarc); } - e1000e_config_collision_dist(hw); - /* Setup Transmit Descriptor Settings for eop descriptor */ adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; @@ -2269,6 +2268,8 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) ew32(TCTL, tctl); + e1000e_config_collision_dist(hw); + adapter->tx_queue_len = adapter->netdev->tx_queue_len; } @@ -2308,6 +2309,23 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) if (adapter->flags2 & FLAG2_CRC_STRIPPING) rctl |= E1000_RCTL_SECRC; + /* Workaround Si errata on 82577 PHY - configure IPG for jumbos */ + if ((hw->phy.type == e1000_phy_82577) && (rctl & E1000_RCTL_LPE)) { + u16 phy_data; + + e1e_rphy(hw, PHY_REG(770, 26), &phy_data); + phy_data &= 0xfff8; + phy_data |= (1 << 2); + e1e_wphy(hw, PHY_REG(770, 26), phy_data); + + e1e_rphy(hw, 22, &phy_data); + phy_data &= 0x0fff; + phy_data |= (1 << 14); + e1e_wphy(hw, 0x10, 0x2823); + e1e_wphy(hw, 0x11, 0x0003); + e1e_wphy(hw, 22, phy_data); + } + /* Setup buffer sizes */ rctl &= ~E1000_RCTL_SZ_4096; rctl |= E1000_RCTL_BSEX; @@ -2751,23 +2769,25 @@ void e1000e_reset(struct e1000_adapter *adapter) /* * flow control settings * - * The high water mark must be low enough to fit one full frame + * The high water mark must be low enough to fit two full frame * (or the size used for early receive) above it in the Rx FIFO. * Set it to the lower of: * - 90% of the Rx FIFO size, and * - the full Rx FIFO size minus the early receive size (for parts * with ERT support assuming ERT set to E1000_ERT_2048), or - * - the full Rx FIFO size minus one full frame + * - the full Rx FIFO size minus two full frames */ - if (adapter->flags & FLAG_HAS_ERT) + if ((adapter->flags & FLAG_HAS_ERT) && + (adapter->netdev->mtu > ETH_DATA_LEN)) hwm = min(((pba << 10) * 9 / 10), ((pba << 10) - (E1000_ERT_2048 << 3))); else hwm = min(((pba << 10) * 9 / 10), - ((pba << 10) - adapter->max_frame_size)); + ((pba << 10) - (2 * adapter->max_frame_size))); - fc->high_water = hwm & 0xFFF8; /* 8-byte granularity */ - fc->low_water = fc->high_water - 8; + fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */ + fc->low_water = (fc->high_water - (2 * adapter->max_frame_size)); + fc->low_water &= E1000_FCRTL_RTL; /* 8-byte granularity */ if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME) fc->pause_time = 0xFFFF; @@ -2787,6 +2807,8 @@ void e1000e_reset(struct e1000_adapter *adapter) e1000_get_hw_control(adapter); ew32(WUC, 0); + if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) + e1e_wphy(&adapter->hw, BM_WUC, 0); if (mac->ops.init_hw(hw)) e_err("Hardware Error\n"); @@ -2799,7 +2821,8 @@ void e1000e_reset(struct e1000_adapter *adapter) e1000e_reset_adaptive(hw); e1000_get_phy_info(hw); - if (!(adapter->flags & FLAG_SMART_POWER_DOWN)) { + if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) && + !(adapter->flags & FLAG_SMART_POWER_DOWN)) { u16 phy_data = 0; /* * speed up time to link by disabling smart power down, ignore @@ -3266,6 +3289,7 @@ void e1000e_update_stats(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; + u16 phy_data; /* * Prevent stats update while adapter is being reset, or if the pci @@ -3285,11 +3309,34 @@ void e1000e_update_stats(struct e1000_adapter *adapter) adapter->stats.roc += er32(ROC); adapter->stats.mpc += er32(MPC); - adapter->stats.scc += er32(SCC); - adapter->stats.ecol += er32(ECOL); - adapter->stats.mcc += er32(MCC); - adapter->stats.latecol += er32(LATECOL); - adapter->stats.dc += er32(DC); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + e1e_rphy(hw, HV_SCC_UPPER, &phy_data); + e1e_rphy(hw, HV_SCC_LOWER, &phy_data); + adapter->stats.scc += phy_data; + + e1e_rphy(hw, HV_ECOL_UPPER, &phy_data); + e1e_rphy(hw, HV_ECOL_LOWER, &phy_data); + adapter->stats.ecol += phy_data; + + e1e_rphy(hw, HV_MCC_UPPER, &phy_data); + e1e_rphy(hw, HV_MCC_LOWER, &phy_data); + adapter->stats.mcc += phy_data; + + e1e_rphy(hw, HV_LATECOL_UPPER, &phy_data); + e1e_rphy(hw, HV_LATECOL_LOWER, &phy_data); + adapter->stats.latecol += phy_data; + + e1e_rphy(hw, HV_DC_UPPER, &phy_data); + e1e_rphy(hw, HV_DC_LOWER, &phy_data); + adapter->stats.dc += phy_data; + } else { + adapter->stats.scc += er32(SCC); + adapter->stats.ecol += er32(ECOL); + adapter->stats.mcc += er32(MCC); + adapter->stats.latecol += er32(LATECOL); + adapter->stats.dc += er32(DC); + } adapter->stats.xonrxc += er32(XONRXC); adapter->stats.xontxc += er32(XONTXC); adapter->stats.xoffrxc += er32(XOFFRXC); @@ -3307,13 +3354,28 @@ void e1000e_update_stats(struct e1000_adapter *adapter) hw->mac.tx_packet_delta = er32(TPT); adapter->stats.tpt += hw->mac.tx_packet_delta; - hw->mac.collision_delta = er32(COLC); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + e1e_rphy(hw, HV_COLC_UPPER, &phy_data); + e1e_rphy(hw, HV_COLC_LOWER, &phy_data); + hw->mac.collision_delta = phy_data; + } else { + hw->mac.collision_delta = er32(COLC); + } adapter->stats.colc += hw->mac.collision_delta; adapter->stats.algnerrc += er32(ALGNERRC); adapter->stats.rxerrc += er32(RXERRC); - if ((hw->mac.type != e1000_82574) && (hw->mac.type != e1000_82583)) - adapter->stats.tncrs += er32(TNCRS); + if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82577)) { + e1e_rphy(hw, HV_TNCRS_UPPER, &phy_data); + e1e_rphy(hw, HV_TNCRS_LOWER, &phy_data); + adapter->stats.tncrs += phy_data; + } else { + if ((hw->mac.type != e1000_82574) && + (hw->mac.type != e1000_82583)) + adapter->stats.tncrs += er32(TNCRS); + } adapter->stats.cexterr += er32(CEXTERR); adapter->stats.tsctc += er32(TSCTC); adapter->stats.tsctfc += er32(TSCTFC); @@ -3854,7 +3916,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, buffer_info->length = size; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[0] + offset; + buffer_info->dma = skb_shinfo(skb)->dma_head + offset; count++; len -= size; @@ -3885,7 +3947,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, buffer_info->length = size; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[f + 1] + offset; + buffer_info->dma = map[f] + offset; len -= size; offset += size; @@ -4149,7 +4211,6 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss); if (count) { e1000_tx_queue(adapter, tx_flags, count); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2); @@ -4210,27 +4271,17 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) struct e1000_adapter *adapter = netdev_priv(netdev); int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; - if ((new_mtu < ETH_ZLEN + ETH_FCS_LEN + VLAN_HLEN) || - (max_frame > MAX_JUMBO_FRAME_SIZE)) { - e_err("Invalid MTU setting\n"); + /* Jumbo frame support */ + if ((max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) && + !(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { + e_err("Jumbo Frames not supported.\n"); return -EINVAL; } - /* Jumbo frame size limits */ - if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) { - if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) { - e_err("Jumbo Frames not supported.\n"); - return -EINVAL; - } - if (adapter->hw.phy.type == e1000_phy_ife) { - e_err("Jumbo Frames not supported.\n"); - return -EINVAL; - } - } - -#define MAX_STD_JUMBO_FRAME_SIZE 9234 - if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { - e_err("MTU > 9216 not supported.\n"); + /* Supported frame sizes */ + if ((new_mtu < ETH_ZLEN + ETH_FCS_LEN + VLAN_HLEN) || + (max_frame > adapter->max_hw_frame_size)) { + e_err("Unsupported MTU setting\n"); return -EINVAL; } @@ -4350,6 +4401,81 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) } } +static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc) +{ + struct e1000_hw *hw = &adapter->hw; + u32 i, mac_reg; + u16 phy_reg; + int retval = 0; + + /* copy MAC RARs to PHY RARs */ + for (i = 0; i < adapter->hw.mac.rar_entry_count; i++) { + mac_reg = er32(RAL(i)); + e1e_wphy(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF)); + e1e_wphy(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF)); + mac_reg = er32(RAH(i)); + e1e_wphy(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF)); + e1e_wphy(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0xFFFF)); + } + + /* copy MAC MTA to PHY MTA */ + for (i = 0; i < adapter->hw.mac.mta_reg_count; i++) { + mac_reg = E1000_READ_REG_ARRAY(hw, E1000_MTA, i); + e1e_wphy(hw, BM_MTA(i), (u16)(mac_reg & 0xFFFF)); + e1e_wphy(hw, BM_MTA(i) + 1, (u16)((mac_reg >> 16) & 0xFFFF)); + } + + /* configure PHY Rx Control register */ + e1e_rphy(&adapter->hw, BM_RCTL, &phy_reg); + mac_reg = er32(RCTL); + if (mac_reg & E1000_RCTL_UPE) + phy_reg |= BM_RCTL_UPE; + if (mac_reg & E1000_RCTL_MPE) + phy_reg |= BM_RCTL_MPE; + phy_reg &= ~(BM_RCTL_MO_MASK); + if (mac_reg & E1000_RCTL_MO_3) + phy_reg |= (((mac_reg & E1000_RCTL_MO_3) >> E1000_RCTL_MO_SHIFT) + << BM_RCTL_MO_SHIFT); + if (mac_reg & E1000_RCTL_BAM) + phy_reg |= BM_RCTL_BAM; + if (mac_reg & E1000_RCTL_PMCF) + phy_reg |= BM_RCTL_PMCF; + mac_reg = er32(CTRL); + if (mac_reg & E1000_CTRL_RFCE) + phy_reg |= BM_RCTL_RFCE; + e1e_wphy(&adapter->hw, BM_RCTL, phy_reg); + + /* enable PHY wakeup in MAC register */ + ew32(WUFC, wufc); + ew32(WUC, E1000_WUC_PHY_WAKE | E1000_WUC_PME_EN); + + /* configure and enable PHY wakeup in PHY registers */ + e1e_wphy(&adapter->hw, BM_WUFC, wufc); + e1e_wphy(&adapter->hw, BM_WUC, E1000_WUC_PME_EN); + + /* activate PHY wakeup */ + retval = hw->phy.ops.acquire_phy(hw); + if (retval) { + e_err("Could not acquire PHY\n"); + return retval; + } + e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, + (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT)); + retval = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg); + if (retval) { + e_err("Could not read PHY page 769\n"); + goto out; + } + phy_reg |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT; + retval = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); + if (retval) + e_err("Could not set PHY Host Wakeup bit\n"); +out: + hw->phy.ops.release_phy(hw); + + return retval; +} + static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) { struct net_device *netdev = pci_get_drvdata(pdev); @@ -4392,8 +4518,9 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) #define E1000_CTRL_ADVD3WUC 0x00100000 /* phy power management enable */ #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 - ctrl |= E1000_CTRL_ADVD3WUC | - E1000_CTRL_EN_PHY_PWR_MGMT; + ctrl |= E1000_CTRL_ADVD3WUC; + if (!(adapter->flags2 & FLAG2_HAS_PHY_WAKEUP)) + ctrl |= E1000_CTRL_EN_PHY_PWR_MGMT; ew32(CTRL, ctrl); if (adapter->hw.phy.media_type == e1000_media_type_fiber || @@ -4411,8 +4538,17 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) /* Allow time for pending master requests to run */ e1000e_disable_pcie_master(&adapter->hw); - ew32(WUC, E1000_WUC_PME_EN); - ew32(WUFC, wufc); + if ((adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) && + !(hw->mac.ops.check_mng_mode(hw))) { + /* enable wakeup by the PHY */ + retval = e1000_init_phy_wakeup(adapter, wufc); + if (retval) + return retval; + } else { + /* enable wakeup by the MAC */ + ew32(WUFC, wufc); + ew32(WUC, E1000_WUC_PME_EN); + } } else { ew32(WUC, 0); ew32(WUFC, 0); @@ -4555,8 +4691,37 @@ static int e1000_resume(struct pci_dev *pdev) } e1000e_power_up_phy(adapter); + + /* report the system wakeup cause from S3/S4 */ + if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) { + u16 phy_data; + + e1e_rphy(&adapter->hw, BM_WUS, &phy_data); + if (phy_data) { + e_info("PHY Wakeup cause - %s\n", + phy_data & E1000_WUS_EX ? "Unicast Packet" : + phy_data & E1000_WUS_MC ? "Multicast Packet" : + phy_data & E1000_WUS_BC ? "Broadcast Packet" : + phy_data & E1000_WUS_MAG ? "Magic Packet" : + phy_data & E1000_WUS_LNKC ? "Link Status " + " Change" : "other"); + } + e1e_wphy(&adapter->hw, BM_WUS, ~0); + } else { + u32 wus = er32(WUS); + if (wus) { + e_info("MAC Wakeup cause - %s\n", + wus & E1000_WUS_EX ? "Unicast Packet" : + wus & E1000_WUS_MC ? "Multicast Packet" : + wus & E1000_WUS_BC ? "Broadcast Packet" : + wus & E1000_WUS_MAG ? "Magic Packet" : + wus & E1000_WUS_LNKC ? "Link Status Change" : + "other"); + } + ew32(WUS, ~0); + } + e1000e_reset(adapter); - ew32(WUS, ~0); e1000_init_manageability(adapter); @@ -4846,6 +5011,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter->flags2 = ei->flags2; adapter->hw.adapter = adapter; adapter->hw.mac.type = ei->mac; + adapter->max_hw_frame_size = ei->max_hw_frame_size; adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1; mmio_start = pci_resource_start(pdev, 0); @@ -5001,6 +5167,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, /* APME bit in EEPROM is mapped to WUC.APME */ eeprom_data = er32(WUC); eeprom_apme_mask = E1000_WUC_APME; + if (eeprom_data & E1000_WUC_PHY_WAKE) + adapter->flags2 |= FLAG2_HAS_PHY_WAKEUP; } else if (adapter->flags & FLAG_APME_IN_CTRL3) { if (adapter->flags & FLAG_APME_CHECK_PORT_B && (adapter->hw.bus.func == 1)) @@ -5202,6 +5370,11 @@ static struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LM), board_pchlan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LC), board_pchlan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DM), board_pchlan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DC), board_pchlan }, + { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c index e909f96698e8..1342e0b1815c 100644 --- a/drivers/net/e1000e/param.c +++ b/drivers/net/e1000e/param.c @@ -427,6 +427,8 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter) e1000_validate_option(&crc_stripping, &opt, adapter); if (crc_stripping == OPTION_ENABLED) adapter->flags2 |= FLAG2_CRC_STRIPPING; + } else { + adapter->flags2 |= FLAG2_CRC_STRIPPING; } } { /* Kumeran Lock Loss Workaround */ diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index dc4a9cba6a73..e23459cf3d0e 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -37,6 +37,9 @@ static s32 e1000_wait_autoneg(struct e1000_hw *hw); static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg); static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data, bool read); +static u32 e1000_get_phy_addr_for_hv_page(u32 page); +static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, + u16 *data, bool read); /* Cable length tables */ static const u16 e1000_m88_cable_length_table[] = @@ -54,6 +57,55 @@ static const u16 e1000_igp_2_cable_length_table[] = #define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ ARRAY_SIZE(e1000_igp_2_cable_length_table) +#define BM_PHY_REG_PAGE(offset) \ + ((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF)) +#define BM_PHY_REG_NUM(offset) \ + ((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\ + (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\ + ~MAX_PHY_REG_ADDRESS))) + +#define HV_INTC_FC_PAGE_START 768 +#define I82578_ADDR_REG 29 +#define I82577_ADDR_REG 16 +#define I82577_CFG_REG 22 +#define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15) +#define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */ +#define I82577_CTRL_REG 23 +#define I82577_CTRL_DOWNSHIFT_MASK (7 << 10) + +/* 82577 specific PHY registers */ +#define I82577_PHY_CTRL_2 18 +#define I82577_PHY_STATUS_2 26 +#define I82577_PHY_DIAG_STATUS 31 + +/* I82577 PHY Status 2 */ +#define I82577_PHY_STATUS2_REV_POLARITY 0x0400 +#define I82577_PHY_STATUS2_MDIX 0x0800 +#define I82577_PHY_STATUS2_SPEED_MASK 0x0300 +#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200 + +/* I82577 PHY Control 2 */ +#define I82577_PHY_CTRL2_AUTO_MDIX 0x0400 +#define I82577_PHY_CTRL2_FORCE_MDI_MDIX 0x0200 + +/* I82577 PHY Diagnostics Status */ +#define I82577_DSTATUS_CABLE_LENGTH 0x03FC +#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2 + +/* BM PHY Copper Specific Control 1 */ +#define BM_CS_CTRL1 16 + +/* BM PHY Copper Specific Status */ +#define BM_CS_STATUS 17 +#define BM_CS_STATUS_LINK_UP 0x0400 +#define BM_CS_STATUS_RESOLVED 0x0800 +#define BM_CS_STATUS_SPEED_MASK 0xC000 +#define BM_CS_STATUS_SPEED_1000 0x8000 + +#define HV_MUX_DATA_CTRL PHY_REG(776, 16) +#define HV_MUX_DATA_CTRL_GEN_TO_MAC 0x0400 +#define HV_MUX_DATA_CTRL_FORCE_SPEED 0x0004 + /** * e1000e_check_reset_block_generic - Check if PHY reset is blocked * @hw: pointer to the HW structure @@ -82,23 +134,48 @@ s32 e1000e_check_reset_block_generic(struct e1000_hw *hw) s32 e1000e_get_phy_id(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; + s32 ret_val = 0; u16 phy_id; + u16 retry_count = 0; - ret_val = e1e_rphy(hw, PHY_ID1, &phy_id); - if (ret_val) - return ret_val; + if (!(phy->ops.read_phy_reg)) + goto out; - phy->id = (u32)(phy_id << 16); - udelay(20); - ret_val = e1e_rphy(hw, PHY_ID2, &phy_id); - if (ret_val) - return ret_val; + while (retry_count < 2) { + ret_val = e1e_rphy(hw, PHY_ID1, &phy_id); + if (ret_val) + goto out; - phy->id |= (u32)(phy_id & PHY_REVISION_MASK); - phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + phy->id = (u32)(phy_id << 16); + udelay(20); + ret_val = e1e_rphy(hw, PHY_ID2, &phy_id); + if (ret_val) + goto out; - return 0; + phy->id |= (u32)(phy_id & PHY_REVISION_MASK); + phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + + if (phy->id != 0 && phy->id != PHY_REVISION_MASK) + goto out; + + /* + * If the PHY ID is still unknown, we may have an 82577i + * without link. We will try again after setting Slow + * MDIC mode. No harm in trying again in this case since + * the PHY ID is unknown at this point anyway + */ + ret_val = e1000_set_mdio_slow_mode_hv(hw, true); + if (ret_val) + goto out; + + retry_count++; + } +out: + /* Revert to MDIO fast mode, if applicable */ + if (retry_count) + ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + + return ret_val; } /** @@ -410,6 +487,43 @@ s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data) } /** + * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link + * @hw: pointer to the HW structure + * + * Sets up Carrier-sense on Transmit and downshift values. + **/ +s32 e1000_copper_link_setup_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + ret_val = phy->ops.read_phy_reg(hw, I82577_CFG_REG, &phy_data); + if (ret_val) + goto out; + + phy_data |= I82577_CFG_ASSERT_CRS_ON_TX; + + /* Enable downshift */ + phy_data |= I82577_CFG_ENABLE_DOWNSHIFT; + + ret_val = phy->ops.write_phy_reg(hw, I82577_CFG_REG, phy_data); + if (ret_val) + goto out; + + /* Set number of link attempts before downshift */ + ret_val = phy->ops.read_phy_reg(hw, I82577_CTRL_REG, &phy_data); + if (ret_val) + goto out; + phy_data &= ~I82577_CTRL_DOWNSHIFT_MASK; + ret_val = phy->ops.write_phy_reg(hw, I82577_CTRL_REG, phy_data); + +out: + return ret_val; +} + +/** * e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link * @hw: pointer to the HW structure * @@ -427,8 +541,8 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) if (ret_val) return ret_val; - /* For newer PHYs this bit is downshift enable */ - if (phy->type == e1000_phy_m88) + /* For BM PHY this bit is downshift enable */ + if (phy->type != e1000_phy_bm) phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; /* @@ -520,10 +634,27 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) /* Commit the changes. */ ret_val = e1000e_commit_phy(hw); - if (ret_val) + if (ret_val) { hw_dbg(hw, "Error committing the PHY changes\n"); + return ret_val; + } - return ret_val; + if (phy->type == e1000_phy_82578) { + ret_val = phy->ops.read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + &phy_data); + if (ret_val) + return ret_val; + + /* 82578 PHY - set the downshift count to 1x. */ + phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE; + phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK; + ret_val = phy->ops.write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + phy_data); + if (ret_val) + return ret_val; + } + + return 0; } /** @@ -1251,6 +1382,8 @@ s32 e1000e_check_downshift(struct e1000_hw *hw) switch (phy->type) { case e1000_phy_m88: case e1000_phy_gg82563: + case e1000_phy_82578: + case e1000_phy_82577: offset = M88E1000_PHY_SPEC_STATUS; mask = M88E1000_PSSR_DOWNSHIFT; break; @@ -1886,6 +2019,12 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id) case BME1000_E_PHY_ID_R2: phy_type = e1000_phy_bm; break; + case I82578_E_PHY_ID: + phy_type = e1000_phy_82578; + break; + case I82577_E_PHY_ID: + phy_type = e1000_phy_82577; + break; default: phy_type = e1000_phy_unknown; break; @@ -2181,11 +2320,16 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data, bool read) { s32 ret_val; - u16 reg = ((u16)offset) & PHY_REG_MASK; + u16 reg = BM_PHY_REG_NUM(offset); u16 phy_reg = 0; u8 phy_acquired = 1; + /* Gig must be disabled for MDIO accesses to page 800 */ + if ((hw->mac.type == e1000_pchlan) && + (!(er32(PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE))) + hw_dbg(hw, "Attempting to access page 800 while gig enabled\n"); + ret_val = hw->phy.ops.acquire_phy(hw); if (ret_val) { phy_acquired = 0; @@ -2289,3 +2433,524 @@ static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active) return 0; } + +s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow) +{ + s32 ret_val = 0; + u16 data = 0; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + /* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */ + hw->phy.addr = 1; + ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, + (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT)); + if (ret_val) { + hw->phy.ops.release_phy(hw); + return ret_val; + } + ret_val = e1000e_write_phy_reg_mdic(hw, BM_CS_CTRL1, + (0x2180 | (slow << 10))); + + /* dummy read when reverting to fast mode - throw away result */ + if (!slow) + e1000e_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data); + + hw->phy.ops.release_phy(hw); + + return ret_val; +} + +/** + * e1000_read_phy_reg_hv - Read HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphore before exiting. + **/ +s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + u16 page = BM_PHY_REG_PAGE(offset); + u16 reg = BM_PHY_REG_NUM(offset); + bool in_slow_mode = false; + + /* Workaround failure in MDIO access while cable is disconnected */ + if ((hw->phy.type == e1000_phy_82577) && + !(er32(STATUS) & E1000_STATUS_LU)) { + ret_val = e1000_set_mdio_slow_mode_hv(hw, true); + if (ret_val) + goto out; + + in_slow_mode = true; + } + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, + data, true); + goto out; + } + + if (page > 0 && page < HV_INTC_FC_PAGE_START) { + ret_val = e1000_access_phy_debug_regs_hv(hw, offset, + data, true); + goto out; + } + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + goto out; + + hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); + + if (page == HV_INTC_FC_PAGE_START) + page = 0; + + if (reg > MAX_PHY_MULTI_PAGE_REG) { + if ((hw->phy.type != e1000_phy_82578) || + ((reg != I82578_ADDR_REG) && + (reg != I82578_ADDR_REG + 1))) { + u32 phy_addr = hw->phy.addr; + + hw->phy.addr = 1; + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000e_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (page << IGP_PAGE_SHIFT)); + if (ret_val) { + hw->phy.ops.release_phy(hw); + goto out; + } + hw->phy.addr = phy_addr; + } + } + + ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, + data); + hw->phy.ops.release_phy(hw); + +out: + /* Revert to MDIO fast mode, if applicable */ + if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) + ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + + return ret_val; +} + +/** + * e1000_write_phy_reg_hv - Write HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + u16 page = BM_PHY_REG_PAGE(offset); + u16 reg = BM_PHY_REG_NUM(offset); + bool in_slow_mode = false; + + /* Workaround failure in MDIO access while cable is disconnected */ + if ((hw->phy.type == e1000_phy_82577) && + !(er32(STATUS) & E1000_STATUS_LU)) { + ret_val = e1000_set_mdio_slow_mode_hv(hw, true); + if (ret_val) + goto out; + + in_slow_mode = true; + } + + /* Page 800 works differently than the rest so it has its own func */ + if (page == BM_WUC_PAGE) { + ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, + &data, false); + goto out; + } + + if (page > 0 && page < HV_INTC_FC_PAGE_START) { + ret_val = e1000_access_phy_debug_regs_hv(hw, offset, + &data, false); + goto out; + } + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + goto out; + + hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); + + if (page == HV_INTC_FC_PAGE_START) + page = 0; + + /* + * Workaround MDIO accesses being disabled after entering IEEE Power + * Down (whenever bit 11 of the PHY Control register is set) + */ + if ((hw->phy.type == e1000_phy_82578) && + (hw->phy.revision >= 1) && + (hw->phy.addr == 2) && + ((MAX_PHY_REG_ADDRESS & reg) == 0) && + (data & (1 << 11))) { + u16 data2 = 0x7EFF; + hw->phy.ops.release_phy(hw); + ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3, + &data2, false); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + goto out; + } + + if (reg > MAX_PHY_MULTI_PAGE_REG) { + if ((hw->phy.type != e1000_phy_82578) || + ((reg != I82578_ADDR_REG) && + (reg != I82578_ADDR_REG + 1))) { + u32 phy_addr = hw->phy.addr; + + hw->phy.addr = 1; + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000e_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (page << IGP_PAGE_SHIFT)); + if (ret_val) { + hw->phy.ops.release_phy(hw); + goto out; + } + hw->phy.addr = phy_addr; + } + } + + ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, + data); + hw->phy.ops.release_phy(hw); + +out: + /* Revert to MDIO fast mode, if applicable */ + if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) + ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + + return ret_val; +} + +/** + * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page + * @page: page to be accessed + **/ +static u32 e1000_get_phy_addr_for_hv_page(u32 page) +{ + u32 phy_addr = 2; + + if (page >= HV_INTC_FC_PAGE_START) + phy_addr = 1; + + return phy_addr; +} + +/** + * e1000_access_phy_debug_regs_hv - Read HV PHY vendor specific high registers + * @hw: pointer to the HW structure + * @offset: register offset to be read or written + * @data: pointer to the data to be read or written + * @read: determines if operation is read or written + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retreived information in data. Release any acquired + * semaphores before exiting. Note that the procedure to read these regs + * uses the address port and data port to read/write. + **/ +static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, + u16 *data, bool read) +{ + s32 ret_val; + u32 addr_reg = 0; + u32 data_reg = 0; + u8 phy_acquired = 1; + + /* This takes care of the difference with desktop vs mobile phy */ + addr_reg = (hw->phy.type == e1000_phy_82578) ? + I82578_ADDR_REG : I82577_ADDR_REG; + data_reg = addr_reg + 1; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) { + hw_dbg(hw, "Could not acquire PHY\n"); + phy_acquired = 0; + goto out; + } + + /* All operations in this function are phy address 2 */ + hw->phy.addr = 2; + + /* masking with 0x3F to remove the page from offset */ + ret_val = e1000e_write_phy_reg_mdic(hw, addr_reg, (u16)offset & 0x3F); + if (ret_val) { + hw_dbg(hw, "Could not write PHY the HV address register\n"); + goto out; + } + + /* Read or write the data value next */ + if (read) + ret_val = e1000e_read_phy_reg_mdic(hw, data_reg, data); + else + ret_val = e1000e_write_phy_reg_mdic(hw, data_reg, *data); + + if (ret_val) { + hw_dbg(hw, "Could not read data value from HV data register\n"); + goto out; + } + +out: + if (phy_acquired == 1) + hw->phy.ops.release_phy(hw); + return ret_val; +} + +/** + * e1000_link_stall_workaround_hv - Si workaround + * @hw: pointer to the HW structure + * + * This function works around a Si bug where the link partner can get + * a link up indication before the PHY does. If small packets are sent + * by the link partner they can be placed in the packet buffer without + * being properly accounted for by the PHY and will stall preventing + * further packets from being received. The workaround is to clear the + * packet buffer after the PHY detects link up. + **/ +s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u16 data; + + if (hw->phy.type != e1000_phy_82578) + goto out; + + /* check if link is up and at 1Gbps */ + ret_val = hw->phy.ops.read_phy_reg(hw, BM_CS_STATUS, &data); + if (ret_val) + goto out; + + data &= BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_MASK; + + if (data != (BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_1000)) + goto out; + + mdelay(200); + + /* flush the packets in the fifo buffer */ + ret_val = hw->phy.ops.write_phy_reg(hw, HV_MUX_DATA_CTRL, + HV_MUX_DATA_CTRL_GEN_TO_MAC | + HV_MUX_DATA_CTRL_FORCE_SPEED); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.write_phy_reg(hw, HV_MUX_DATA_CTRL, + HV_MUX_DATA_CTRL_GEN_TO_MAC); + +out: + return ret_val; +} + +/** + * e1000_check_polarity_82577 - Checks the polarity. + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + * + * Polarity is determined based on the PHY specific status register. + **/ +s32 e1000_check_polarity_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_STATUS_2, &data); + + if (!ret_val) + phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** + * e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY + * @hw: pointer to the HW structure + * + * Calls the PHY setup function to force speed and duplex. Clears the + * auto-crossover to force MDI manually. Waits for link and returns + * successful if link up is successful, else -E1000_ERR_PHY (-2). + **/ +s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + ret_val = phy->ops.read_phy_reg(hw, PHY_CONTROL, &phy_data); + if (ret_val) + goto out; + + e1000e_phy_force_speed_duplex_setup(hw, &phy_data); + + ret_val = phy->ops.write_phy_reg(hw, PHY_CONTROL, phy_data); + if (ret_val) + goto out; + + /* + * Clear Auto-Crossover to force MDI manually. 82577 requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_CTRL_2, &phy_data); + if (ret_val) + goto out; + + phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX; + phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX; + + ret_val = phy->ops.write_phy_reg(hw, I82577_PHY_CTRL_2, phy_data); + if (ret_val) + goto out; + + hw_dbg(hw, "I82577_PHY_CTRL_2: %X\n", phy_data); + + udelay(1); + + if (phy->autoneg_wait_to_complete) { + hw_dbg(hw, "Waiting for forced speed/duplex link on 82577 phy\n"); + + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + + if (!link) + hw_dbg(hw, "Link taking longer than expected.\n"); + + /* Try once more */ + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_get_phy_info_82577 - Retrieve I82577 PHY information + * @hw: pointer to the HW structure + * + * Read PHY status to determine if link is up. If link is up, then + * set/determine 10base-T extended distance and polarity correction. Read + * PHY port status to determine MDI/MDIx and speed. Based on the speed, + * determine on the cable length, local and remote receiver. + **/ +s32 e1000_get_phy_info_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) { + hw_dbg(hw, "Phy info is only valid if link is up\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + phy->polarity_correction = true; + + ret_val = e1000_check_polarity_82577(hw); + if (ret_val) + goto out; + + ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_STATUS_2, &data); + if (ret_val) + goto out; + + phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false; + + if ((data & I82577_PHY_STATUS2_SPEED_MASK) == + I82577_PHY_STATUS2_SPEED_1000MBPS) { + ret_val = hw->phy.ops.get_cable_length(hw); + if (ret_val) + goto out; + + ret_val = phy->ops.read_phy_reg(hw, PHY_1000T_STATUS, &data); + if (ret_val) + goto out; + + phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + + phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + } else { + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + } + +out: + return ret_val; +} + +/** + * e1000_get_cable_length_82577 - Determine cable length for 82577 PHY + * @hw: pointer to the HW structure + * + * Reads the diagnostic status register and verifies result is valid before + * placing it in the phy_cable_length field. + **/ +s32 e1000_get_cable_length_82577(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, length; + + ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data); + if (ret_val) + goto out; + + length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >> + I82577_DSTATUS_CABLE_LENGTH_SHIFT; + + if (length == E1000_CABLE_LENGTH_UNDEFINED) + ret_val = E1000_ERR_PHY; + + phy->cable_length = length; + +out: + return ret_val; +} diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 9080f07da8fe..8005b602f776 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -661,8 +661,6 @@ static int enic_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + 1) netif_stop_queue(netdev); - netdev->trans_start = jiffies; - spin_unlock_irqrestore(&enic->wq_lock[0], flags); return NETDEV_TX_OK; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index d0b1d9f17a5d..b60a3041b64c 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -77,27 +77,31 @@ * Hardware access: */ -#define DEV_NEED_TIMERIRQ 0x000001 /* set the timer irq flag in the irq mask */ -#define DEV_NEED_LINKTIMER 0x000002 /* poll link settings. Relies on the timer irq */ -#define DEV_HAS_LARGEDESC 0x000004 /* device supports jumbo frames and needs packet format 2 */ -#define DEV_HAS_HIGH_DMA 0x000008 /* device supports 64bit dma */ -#define DEV_HAS_CHECKSUM 0x000010 /* device supports tx and rx checksum offloads */ -#define DEV_HAS_VLAN 0x000020 /* device supports vlan tagging and striping */ -#define DEV_HAS_MSI 0x000040 /* device supports MSI */ -#define DEV_HAS_MSI_X 0x000080 /* device supports MSI-X */ -#define DEV_HAS_POWER_CNTRL 0x000100 /* device supports power savings */ -#define DEV_HAS_STATISTICS_V1 0x000200 /* device supports hw statistics version 1 */ -#define DEV_HAS_STATISTICS_V2 0x000600 /* device supports hw statistics version 2 */ -#define DEV_HAS_STATISTICS_V3 0x000e00 /* device supports hw statistics version 3 */ -#define DEV_HAS_TEST_EXTENDED 0x001000 /* device supports extended diagnostic test */ -#define DEV_HAS_MGMT_UNIT 0x002000 /* device supports management unit */ -#define DEV_HAS_CORRECT_MACADDR 0x004000 /* device supports correct mac address order */ -#define DEV_HAS_COLLISION_FIX 0x008000 /* device supports tx collision fix */ -#define DEV_HAS_PAUSEFRAME_TX_V1 0x010000 /* device supports tx pause frames version 1 */ -#define DEV_HAS_PAUSEFRAME_TX_V2 0x020000 /* device supports tx pause frames version 2 */ -#define DEV_HAS_PAUSEFRAME_TX_V3 0x040000 /* device supports tx pause frames version 3 */ -#define DEV_NEED_TX_LIMIT 0x080000 /* device needs to limit tx */ -#define DEV_HAS_GEAR_MODE 0x100000 /* device supports gear mode */ +#define DEV_NEED_TIMERIRQ 0x0000001 /* set the timer irq flag in the irq mask */ +#define DEV_NEED_LINKTIMER 0x0000002 /* poll link settings. Relies on the timer irq */ +#define DEV_HAS_LARGEDESC 0x0000004 /* device supports jumbo frames and needs packet format 2 */ +#define DEV_HAS_HIGH_DMA 0x0000008 /* device supports 64bit dma */ +#define DEV_HAS_CHECKSUM 0x0000010 /* device supports tx and rx checksum offloads */ +#define DEV_HAS_VLAN 0x0000020 /* device supports vlan tagging and striping */ +#define DEV_HAS_MSI 0x0000040 /* device supports MSI */ +#define DEV_HAS_MSI_X 0x0000080 /* device supports MSI-X */ +#define DEV_HAS_POWER_CNTRL 0x0000100 /* device supports power savings */ +#define DEV_HAS_STATISTICS_V1 0x0000200 /* device supports hw statistics version 1 */ +#define DEV_HAS_STATISTICS_V2 0x0000600 /* device supports hw statistics version 2 */ +#define DEV_HAS_STATISTICS_V3 0x0000e00 /* device supports hw statistics version 3 */ +#define DEV_HAS_TEST_EXTENDED 0x0001000 /* device supports extended diagnostic test */ +#define DEV_HAS_MGMT_UNIT 0x0002000 /* device supports management unit */ +#define DEV_HAS_CORRECT_MACADDR 0x0004000 /* device supports correct mac address order */ +#define DEV_HAS_COLLISION_FIX 0x0008000 /* device supports tx collision fix */ +#define DEV_HAS_PAUSEFRAME_TX_V1 0x0010000 /* device supports tx pause frames version 1 */ +#define DEV_HAS_PAUSEFRAME_TX_V2 0x0020000 /* device supports tx pause frames version 2 */ +#define DEV_HAS_PAUSEFRAME_TX_V3 0x0040000 /* device supports tx pause frames version 3 */ +#define DEV_NEED_TX_LIMIT 0x0080000 /* device needs to limit tx */ +#define DEV_NEED_TX_LIMIT2 0x0180000 /* device needs to limit tx, expect for some revs */ +#define DEV_HAS_GEAR_MODE 0x0200000 /* device supports gear mode */ +#define DEV_NEED_PHY_INIT_FIX 0x0400000 /* device needs specific phy workaround */ +#define DEV_NEED_LOW_POWER_FIX 0x0800000 /* device needs special power up workaround */ +#define DEV_NEED_MSI_FIX 0x1000000 /* device needs msi workaround */ enum { NvRegIrqStatus = 0x000, @@ -898,6 +902,12 @@ enum { }; static int phy_cross = NV_CROSSOVER_DETECTION_DISABLED; +/* + * Power down phy when interface is down (persists through reboot; + * older Linux and other OSes may not power it up again) + */ +static int phy_power_down = 0; + static inline struct fe_priv *get_nvpriv(struct net_device *dev) { return netdev_priv(dev); @@ -1265,14 +1275,7 @@ static int phy_init(struct net_device *dev) } } if (np->phy_model == PHY_MODEL_REALTEK_8201) { - if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) { + if (np->driver_data & DEV_NEED_PHY_INIT_FIX) { phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ); phy_reserved |= PHY_REALTEK_INIT7; if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) { @@ -1463,14 +1466,7 @@ static int phy_init(struct net_device *dev) } } if (np->phy_model == PHY_MODEL_REALTEK_8201) { - if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 || - np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) { + if (np->driver_data & DEV_NEED_PHY_INIT_FIX) { phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ); phy_reserved |= PHY_REALTEK_INIT7; if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) { @@ -1503,7 +1499,10 @@ static int phy_init(struct net_device *dev) /* restart auto negotiation, power down phy */ mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); - mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE | BMCR_PDOWN); + mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE); + if (phy_power_down) { + mii_control |= BMCR_PDOWN; + } if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) { return PHY_ERROR; } @@ -5534,7 +5533,7 @@ static int nv_close(struct net_device *dev) nv_drain_rxtx(dev); - if (np->wolenabled) { + if (np->wolenabled || !phy_power_down) { nv_txrx_gate(dev, false); writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); nv_start_rx(dev); @@ -5835,8 +5834,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i /* take phy and nic out of low power mode */ powerstate = readl(base + NvRegPowerState2); powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK; - if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_13) && + if ((id->driver_data & DEV_NEED_LOW_POWER_FIX) && pci_dev->revision >= 0xA3) powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3; writel(powerstate, base + NvRegPowerState2); @@ -5892,14 +5890,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i /* Limit the number of tx's outstanding for hw bug */ if (id->driver_data & DEV_NEED_TX_LIMIT) { np->tx_limit = 1; - if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_32 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_33 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_34 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_35 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_36 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_37 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_38 || - id->device == PCI_DEVICE_ID_NVIDIA_NVENET_39) && + if ((id->driver_data & DEV_NEED_TX_LIMIT2) && pci_dev->revision >= 0xA2) np->tx_limit = 0; } @@ -6149,7 +6140,8 @@ static int nv_resume(struct pci_dev *pdev) for (i = 0;i <= np->register_size/sizeof(u32); i++) writel(np->saved_config_space[i], base+i*sizeof(u32)); - pci_write_config_dword(pdev, NV_MSI_PRIV_OFFSET, NV_MSI_PRIV_VALUE); + if (np->driver_data & DEV_NEED_MSI_FIX) + pci_write_config_dword(pdev, NV_MSI_PRIV_OFFSET, NV_MSI_PRIV_VALUE); /* restore phy state, including autoneg */ phy_init(dev); @@ -6198,160 +6190,164 @@ static void nv_shutdown(struct pci_dev *pdev) static struct pci_device_id pci_tbl[] = { { /* nForce Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_1), + PCI_DEVICE(0x10DE, 0x01C3), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce2 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_2), + PCI_DEVICE(0x10DE, 0x0066), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_3), + PCI_DEVICE(0x10DE, 0x00D6), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4), + PCI_DEVICE(0x10DE, 0x0086), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5), + PCI_DEVICE(0x10DE, 0x008C), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6), + PCI_DEVICE(0x10DE, 0x00E6), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7), + PCI_DEVICE(0x10DE, 0x00DF), .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* CK804 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), + PCI_DEVICE(0x10DE, 0x0056), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* CK804 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), + PCI_DEVICE(0x10DE, 0x0057), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP04 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), + PCI_DEVICE(0x10DE, 0x0037), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP04 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), + PCI_DEVICE(0x10DE, 0x0038), .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT, }, { /* MCP51 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, + PCI_DEVICE(0x10DE, 0x0268), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1|DEV_NEED_LOW_POWER_FIX, }, { /* MCP51 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, + PCI_DEVICE(0x10DE, 0x0269), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1|DEV_NEED_LOW_POWER_FIX, }, { /* MCP55 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT, + PCI_DEVICE(0x10DE, 0x0372), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX, }, { /* MCP55 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT, + PCI_DEVICE(0x10DE, 0x0373), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX, }, { /* MCP61 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + PCI_DEVICE(0x10DE, 0x03E5), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX, }, { /* MCP61 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + PCI_DEVICE(0x10DE, 0x03E6), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX, }, { /* MCP61 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + PCI_DEVICE(0x10DE, 0x03EE), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX, }, { /* MCP61 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + PCI_DEVICE(0x10DE, 0x03EF), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX, }, { /* MCP65 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0450), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP65 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0451), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP65 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0452), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP65 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0453), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP67 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x054C), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP67 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x054D), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP67 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x054E), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP67 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x054F), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP73 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x07DC), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP73 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x07DD), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP73 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x07DE), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP73 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x07DF), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX, }, { /* MCP77 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0760), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP77 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0761), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP77 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0762), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP77 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0763), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP79 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0AB0), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP79 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0AB1), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP79 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0AB2), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, }, { /* MCP79 Ethernet Controller */ - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + PCI_DEVICE(0x10DE, 0x0AB3), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX, + }, + { /* MCP89 Ethernet Controller */ + PCI_DEVICE(0x10DE, 0x0D7D), + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX, }, {0,}, }; @@ -6390,6 +6386,8 @@ module_param(dma_64bit, int, 0); MODULE_PARM_DESC(dma_64bit, "High DMA is enabled by setting to 1 and disabled by setting to 0."); module_param(phy_cross, int, 0); MODULE_PARM_DESC(phy_cross, "Phy crossover detection for Realtek 8201 phy is enabled by setting to 1 and disabled by setting to 0."); +module_param(phy_power_down, int, 0); +MODULE_PARM_DESC(phy_power_down, "Power down phy and disable link when interface is down (1), or leave phy powered up (0)."); MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>"); MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver"); diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c index d12e0e0336f4..3af581303ca2 100644 --- a/drivers/net/fsl_pq_mdio.c +++ b/drivers/net/fsl_pq_mdio.c @@ -301,13 +301,17 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev, of_device_is_compatible(np, "ucc_geth_phy")) { #ifdef CONFIG_UCC_GETH u32 id; + static u32 mii_mng_master; tbipa = ®s->utbipar; if ((err = get_ucc_id_for_range(addr, addr + size, &id))) goto err_free_irqs; - ucc_set_qe_mux_mii_mng(id - 1); + if (!mii_mng_master) { + mii_mng_master = id; + ucc_set_qe_mux_mii_mng(id - 1); + } #else err = -ENODEV; goto err_free_irqs; diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 91317bc11154..2cd94338b5d3 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -259,7 +259,7 @@ extern const char gfar_driver_version[]; (IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \ IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \ | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR \ - | IEVENT_MAG) + | IEVENT_MAG | IEVENT_BABR) #define IMASK_INIT_CLEAR 0x00000000 #define IMASK_BABR 0x80000000 diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 310ee035067c..26151fa35df5 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1163,7 +1163,7 @@ static void hamachi_tx_timeout(struct net_device *dev) hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); /* Trigger an immediate transmit demand. */ - dev->trans_start = jiffies; + dev->trans_start = jiffies; /* prevent tx timeout */ hmp->stats.tx_errors++; /* Restart the chip's Tx/Rx processes . */ @@ -1364,7 +1364,6 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) hmp->tx_full = 1; netif_stop_queue(dev); } - dev->trans_start = jiffies; if (hamachi_debug > 4) { printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n", diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 8e93750d5120..ea17319624aa 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3139,8 +3139,7 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter, /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[count]; - count++; + buffer_info->dma = skb_shinfo(skb)->dma_head; for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { struct skb_frag_struct *frag; @@ -3164,7 +3163,7 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter, tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; - return count; + return count + 1; } static inline void igb_tx_queue_adv(struct igb_adapter *adapter, @@ -3344,7 +3343,6 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, if (count) { igb_tx_queue_adv(adapter, tx_ring, tx_flags, count, skb->len, hdr_len); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ igb_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 4); } else { diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 44a8eef03a74..22aadb7884fa 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2119,8 +2119,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter, /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[count]; - count++; + buffer_info->dma = skb_shinfo(skb)->dma_head; for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { struct skb_frag_struct *frag; @@ -2144,7 +2143,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter, tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; - return count; + return count + 1; } static inline void igbvf_tx_queue_adv(struct igbvf_adapter *adapter, @@ -2270,7 +2269,6 @@ static int igbvf_xmit_frame_ring_adv(struct sk_buff *skb, if (count) { igbvf_tx_queue_adv(adapter, tx_ring, tx_flags, count, skb->len, hdr_len); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ igbvf_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 4); } else { diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 006ba23110db..394b2b17075e 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1859,6 +1859,42 @@ static void irda_usb_disconnect(struct usb_interface *intf) IRDA_DEBUG(0, "%s(), USB IrDA Disconnected\n", __func__); } +#ifdef CONFIG_PM +/* USB suspend, so power off the transmitter/receiver */ +static int irda_usb_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct irda_usb_cb *self = usb_get_intfdata(intf); + int i; + + netif_device_detach(self->netdev); + + if (self->tx_urb != NULL) + usb_kill_urb(self->tx_urb); + if (self->speed_urb != NULL) + usb_kill_urb(self->speed_urb); + for (i = 0; i < self->max_rx_urb; i++) { + if (self->rx_urb[i] != NULL) + usb_kill_urb(self->rx_urb[i]); + } + return 0; +} + +/* Coming out of suspend, so reset hardware */ +static int irda_usb_resume(struct usb_interface *intf) +{ + struct irda_usb_cb *self = usb_get_intfdata(intf); + int i; + + for (i = 0; i < self->max_rx_urb; i++) { + if (self->rx_urb[i] != NULL) + usb_submit_urb(self->rx_urb[i], GFP_KERNEL); + } + + netif_device_attach(self->netdev); + return 0; +} +#endif + /*------------------------------------------------------------------*/ /* * USB device callbacks @@ -1868,6 +1904,10 @@ static struct usb_driver irda_driver = { .probe = irda_usb_probe, .disconnect = irda_usb_disconnect, .id_table = dongles, +#ifdef CONFIG_PM + .suspend = irda_usb_suspend, + .resume = irda_usb_resume, +#endif }; /************************* MODULE CALLBACKS *************************/ diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 04cb81a739c2..9c897cf86b9f 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1300,7 +1300,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, buffer_info->length = size; WARN_ON(buffer_info->dma != 0); buffer_info->time_stamp = jiffies; - buffer_info->dma = map[0] + offset; + buffer_info->dma = skb_shinfo(skb)->dma_head + offset; pci_map_single(adapter->pdev, skb->data + offset, size, @@ -1340,7 +1340,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, buffer_info->length = size; buffer_info->time_stamp = jiffies; - buffer_info->dma = map[f + 1] + offset; + buffer_info->dma = map[f] + offset; buffer_info->next_to_watch = 0; len -= size; @@ -1488,7 +1488,6 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (count) { ixgb_tx_queue(adapter, count, vlan_id, tx_flags); - netdev->trans_start = jiffies; /* Make sure there is space in the ring for the next send. */ ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, DESC_NEEDED); diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 05a24055ac2f..cd22323cfd22 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -121,17 +121,18 @@ struct ixgbe_queue_stats { struct ixgbe_ring { void *desc; /* descriptor ring memory */ - dma_addr_t dma; /* phys. address of descriptor ring */ - unsigned int size; /* length in bytes */ - unsigned int count; /* amount of descriptors */ - unsigned int next_to_use; - unsigned int next_to_clean; - - int queue_index; /* needed for multiqueue queue management */ union { struct ixgbe_tx_buffer *tx_buffer_info; struct ixgbe_rx_buffer *rx_buffer_info; }; + u8 atr_sample_rate; + u8 atr_count; + u16 count; /* amount of descriptors */ + u16 rx_buf_len; + u16 next_to_use; + u16 next_to_clean; + + u8 queue_index; /* needed for multiqueue queue management */ u16 head; u16 tail; @@ -139,23 +140,24 @@ struct ixgbe_ring { unsigned int total_bytes; unsigned int total_packets; - u16 reg_idx; /* holds the special value that gets the hardware register - * offset associated with this ring, which is different - * for DCB and RSS modes */ - #ifdef CONFIG_IXGBE_DCA /* cpu for tx queue */ int cpu; #endif - struct ixgbe_queue_stats stats; - u64 v_idx; /* maps directly to the index for this ring in the hardware - * vector array, can also be used for finding the bit in EICR - * and friends that represents the vector for this ring */ + u16 work_limit; /* max work per interrupt */ + u16 reg_idx; /* holds the special value that gets + * the hardware register offset + * associated with this ring, which is + * different for DCB and RSS modes + */ - u16 work_limit; /* max work per interrupt */ - u16 rx_buf_len; - u64 rsc_count; /* stat for coalesced packets */ + struct ixgbe_queue_stats stats; + unsigned long reinit_state; + u64 rsc_count; /* stat for coalesced packets */ + + unsigned int size; /* length in bytes */ + dma_addr_t dma; /* phys. address of descriptor ring */ }; enum ixgbe_ring_f_enum { @@ -163,6 +165,7 @@ enum ixgbe_ring_f_enum { RING_F_DCB, RING_F_VMDQ, RING_F_RSS, + RING_F_FDIR, #ifdef IXGBE_FCOE RING_F_FCOE, #endif /* IXGBE_FCOE */ @@ -173,6 +176,7 @@ enum ixgbe_ring_f_enum { #define IXGBE_MAX_DCB_INDICES 8 #define IXGBE_MAX_RSS_INDICES 16 #define IXGBE_MAX_VMDQ_INDICES 16 +#define IXGBE_MAX_FDIR_INDICES 64 #ifdef IXGBE_FCOE #define IXGBE_MAX_FCOE_INDICES 8 #endif /* IXGBE_FCOE */ @@ -193,6 +197,9 @@ struct ixgbe_ring_feature { */ struct ixgbe_q_vector { struct ixgbe_adapter *adapter; + unsigned int v_idx; /* index of q_vector within array, also used for + * finding the bit in EICR and friends that + * represents the vector for this ring */ struct napi_struct napi; DECLARE_BITMAP(rxr_idx, MAX_RX_QUEUES); /* Rx ring indices */ DECLARE_BITMAP(txr_idx, MAX_TX_QUEUES); /* Tx ring indices */ @@ -201,7 +208,6 @@ struct ixgbe_q_vector { u8 tx_itr; u8 rx_itr; u32 eitr; - u32 v_idx; /* vector index in list */ }; /* Helper macros to switch between ints/sec and what the register uses. @@ -223,6 +229,10 @@ struct ixgbe_q_vector { #define IXGBE_TX_CTXTDESC_ADV(R, i) \ (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i])) +#define IXGBE_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) +#define IXGBE_TX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_tx_desc) +#define IXGBE_RX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_rx_desc) + #define IXGBE_MAX_JUMBO_FRAME_SIZE 16128 #ifdef IXGBE_FCOE /* Use 3K as the baby jumbo frame size for FCoE */ @@ -315,10 +325,13 @@ struct ixgbe_adapter { #define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) #define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 24) #define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 25) -#define IXGBE_FLAG_RSC_CAPABLE (u32)(1 << 26) -#define IXGBE_FLAG_RSC_ENABLED (u32)(1 << 27) +#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 26) +#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 27) #define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 29) + u32 flags2; +#define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) +#define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1) /* default to trying for four seconds */ #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) @@ -327,6 +340,10 @@ struct ixgbe_adapter { struct pci_dev *pdev; struct net_device_stats net_stats; + u32 test_icr; + struct ixgbe_ring test_tx_ring; + struct ixgbe_ring test_rx_ring; + /* structs defined in ixgbe_hw.h */ struct ixgbe_hw hw; u16 msg_enable; @@ -349,6 +366,10 @@ struct ixgbe_adapter { struct timer_list sfp_timer; struct work_struct multispeed_fiber_task; struct work_struct sfp_config_module_task; + u32 fdir_pballoc; + u32 atr_sample_rate; + spinlock_t fdir_perfect_lock; + struct work_struct fdir_reinit_task; #ifdef IXGBE_FCOE struct ixgbe_fcoe fcoe; #endif /* IXGBE_FCOE */ @@ -361,6 +382,7 @@ enum ixbge_state_t { __IXGBE_TESTING, __IXGBE_RESETTING, __IXGBE_DOWN, + __IXGBE_FDIR_INIT_DONE, __IXGBE_SFP_MODULE_NOT_FOUND }; @@ -393,7 +415,63 @@ extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *) extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter); extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter); -extern void ixgbe_write_eitr(struct ixgbe_adapter *, int, u32); +extern void ixgbe_write_eitr(struct ixgbe_q_vector *); +extern int ethtool_ioctl(struct ifreq *ifr); +extern s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw); +extern s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc); +extern s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc); +extern s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + u8 queue); +extern s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + u16 soft_id, + u8 queue); +extern u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *input, u32 key); +extern s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, + u16 vlan_id); +extern s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, + u32 src_addr); +extern s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, + u32 dst_addr); +extern s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 src_addr_1, u32 src_addr_2, + u32 src_addr_3, u32 src_addr_4); +extern s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input, + u32 dst_addr_1, u32 dst_addr_2, + u32 dst_addr_3, u32 dst_addr_4); +extern s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, + u16 src_port); +extern s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, + u16 dst_port); +extern s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, + u16 flex_byte); +extern s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, + u8 vm_pool); +extern s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, + u8 l4type); +extern s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, + u16 *vlan_id); +extern s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, + u32 *src_addr); +extern s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, + u32 *dst_addr); +extern s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 *src_addr_1, u32 *src_addr_2, + u32 *src_addr_3, u32 *src_addr_4); +extern s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input, + u32 *dst_addr_1, u32 *dst_addr_2, + u32 *dst_addr_3, u32 *dst_addr_4); +extern s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, + u16 *src_port); +extern s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, + u16 *dst_port); +extern s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, + u16 *flex_byte); +extern s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, + u8 *vm_pool); +extern s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, + u8 *l4type); #ifdef IXGBE_FCOE extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter); extern int ixgbe_fso(struct ixgbe_adapter *adapter, diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 88e8350aa786..b9923047ce11 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -293,6 +293,17 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) u32 rmcs_reg; u32 reg; +#ifdef CONFIG_DCB + if (hw->fc.requested_mode == ixgbe_fc_pfc) + goto out; + +#endif /* CONFIG_DCB */ + /* Negotiate the fc mode to use */ + ret_val = ixgbe_fc_autoneg(hw); + if (ret_val) + goto out; + + /* Disable any previous flow control settings */ fctrl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); fctrl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE); @@ -304,14 +315,20 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) * 0: Flow control is completely disabled * 1: Rx flow control is enabled (we can receive pause frames, * but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames but + * 2: Tx flow control is enabled (we can send pause frames but * we do not support receiving pause frames). * 3: Both Rx and Tx flow control (symmetric) are enabled. * other: Invalid. +#ifdef CONFIG_DCB + * 4: Priority Flow Control is enabled. +#endif */ switch (hw->fc.current_mode) { case ixgbe_fc_none: - /* Flow control completely disabled by software override. */ + /* + * Flow control is disabled by software override or autoneg. + * The code below will actually disable it in the HW. + */ break; case ixgbe_fc_rx_pause: /* @@ -336,6 +353,11 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) fctrl_reg |= IXGBE_FCTRL_RFCE; rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; break; +#ifdef CONFIG_DCB + case ixgbe_fc_pfc: + goto out; + break; +#endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = -IXGBE_ERR_CONFIG; @@ -343,7 +365,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) break; } - /* Enable 802.3x based flow control settings. */ + /* Set 802.3x based flow control settings. */ fctrl_reg |= IXGBE_FCTRL_DPF; IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl_reg); IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); @@ -377,79 +399,6 @@ out: } /** - * ixgbe_setup_fc_82598 - Configure flow control settings - * @hw: pointer to hardware structure - * @packetbuf_num: packet buffer number (0-7) - * - * Configures the flow control settings based on SW configuration. This - * function is used for 802.3x flow control configuration only. - **/ -static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num) -{ - s32 ret_val = 0; - ixgbe_link_speed speed; - bool link_up; - - /* Validate the packetbuf configuration */ - if (packetbuf_num < 0 || packetbuf_num > 7) { - hw_dbg(hw, "Invalid packet buffer number [%d], expected range is" - " 0-7\n", packetbuf_num); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } - - /* - * Validate the water mark configuration. Zero water marks are invalid - * because it causes the controller to just blast out fc packets. - */ - if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) { - if (hw->fc.requested_mode != ixgbe_fc_none) { - hw_dbg(hw, "Invalid water mark configuration\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } - } - - /* - * Validate the requested mode. Strict IEEE mode does not allow - * ixgbe_fc_rx_pause because it will cause testing anomalies. - */ - if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { - hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } - - /* - * 10gig parts do not have a word in the EEPROM to determine the - * default flow control setting, so we explicitly set it to full. - */ - if (hw->fc.requested_mode == ixgbe_fc_default) - hw->fc.requested_mode = ixgbe_fc_full; - - /* - * Save off the requested flow control mode for use later. Depending - * on the link partner's capabilities, we may or may not use this mode. - */ - - hw->fc.current_mode = hw->fc.requested_mode; - - /* Decide whether to use autoneg or not. */ - hw->mac.ops.check_link(hw, &speed, &link_up, false); - if (!hw->fc.disable_fc_autoneg && hw->phy.multispeed_fiber && - (speed == IXGBE_LINK_SPEED_1GB_FULL)) - ret_val = ixgbe_fc_autoneg(hw); - - if (ret_val) - goto out; - - ret_val = ixgbe_fc_enable_82598(hw, packetbuf_num); - -out: - return ret_val; -} - -/** * ixgbe_setup_mac_link_82598 - Configures MAC link settings * @hw: pointer to hardware structure * @@ -488,13 +437,6 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) } } - /* - * We want to save off the original Flow Control configuration just in - * case we get disconnected and then reconnected into a different hub - * or switch with different Flow Control capabilities. - */ - ixgbe_setup_fc_82598(hw, 0); - /* Add delay to filter out noises during initial link setup */ msleep(50); @@ -581,6 +523,11 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, else *speed = IXGBE_LINK_SPEED_1GB_FULL; + /* if link is down, zero out the current_mode */ + if (*link_up == false) { + hw->fc.current_mode = ixgbe_fc_none; + hw->fc.fc_was_autonegged = false; + } out: return 0; } @@ -1168,7 +1115,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = { .disable_mc = &ixgbe_disable_mc_generic, .clear_vfta = &ixgbe_clear_vfta_82598, .set_vfta = &ixgbe_set_vfta_82598, - .setup_fc = &ixgbe_setup_fc_82598, + .fc_enable = &ixgbe_fc_enable_82598, }; static struct ixgbe_eeprom_operations eeprom_ops_82598 = { diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 5d2783081a94..1984cab7d48b 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -71,10 +71,10 @@ s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw); s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw); s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val); s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val); -s32 ixgbe_start_hw_rev_0_82599(struct ixgbe_hw *hw); s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw); s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw); u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw); +static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) { @@ -122,10 +122,9 @@ s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) IXGBE_WRITE_FLUSH(hw); hw->eeprom.ops.read(hw, ++data_offset, &data_value); } - /* Now restart DSP */ - IXGBE_WRITE_REG(hw, IXGBE_CORECTL, 0x00000102); - IXGBE_WRITE_REG(hw, IXGBE_CORECTL, 0x00000b1d); - IXGBE_WRITE_FLUSH(hw); + /* Now restart DSP by setting Restart_AN */ + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, + (IXGBE_READ_REG(hw, IXGBE_AUTOC) | IXGBE_AUTOC_AN_RESTART)); /* Release the semaphore */ ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); @@ -414,9 +413,6 @@ s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw) } } - /* Set up flow control */ - status = ixgbe_setup_fc_generic(hw, 0); - /* Add delay to filter out noises during initial link setup */ msleep(50); @@ -462,11 +458,31 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); bool link_up = false; bool negotiation; + int i; /* Mask off requested but non-supported speeds */ hw->mac.ops.get_link_capabilities(hw, &phy_link_speed, &negotiation); speed &= phy_link_speed; + /* Set autoneg_advertised value based on input link speed */ + hw->phy.autoneg_advertised = 0; + + if (speed & IXGBE_LINK_SPEED_10GB_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; + + if (speed & IXGBE_LINK_SPEED_1GB_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; + + /* + * When the driver changes the link speeds that it can support, + * it sets autotry_restart to true to indicate that we need to + * initiate a new autotry session with the link partner. To do + * so, we set the speed then disable and re-enable the tx laser, to + * alert the link partner that it also needs to restart autotry on its + * end. This is consistent with true clause 37 autoneg, which also + * involves a loss of signal. + */ + /* * Try each speed one by one, highest priority first. We do this in * software because 10gb fiber doesn't support speed autonegotiation. @@ -475,21 +491,52 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, speedcnt++; highest_link_speed = IXGBE_LINK_SPEED_10GB_FULL; - /* Set hardware SDP's */ + /* If we already have link at this speed, just jump out */ + hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false); + + if ((phy_link_speed == IXGBE_LINK_SPEED_10GB_FULL) && link_up) + goto out; + + /* Set the module link speed */ esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5); IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - ixgbe_setup_mac_link_speed_82599(hw, - IXGBE_LINK_SPEED_10GB_FULL, - autoneg, - autoneg_wait_to_complete); + /* Allow module to change analog characteristics (1G->10G) */ + msleep(40); - msleep(50); - - /* If we have link, just jump out */ - hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false); - if (link_up) + status = ixgbe_setup_mac_link_speed_82599(hw, + IXGBE_LINK_SPEED_10GB_FULL, + autoneg, + autoneg_wait_to_complete); + if (status != 0) goto out; + + /* Flap the tx laser if it has not already been done */ + if (hw->mac.autotry_restart) { + /* Disable tx laser; allow 100us to go dark per spec */ + esdp_reg |= IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + udelay(100); + + /* Enable tx laser; allow 2ms to light up per spec */ + esdp_reg &= ~IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + msleep(2); + + hw->mac.autotry_restart = false; + } + + /* The controller may take up to 500ms at 10g to acquire link */ + for (i = 0; i < 5; i++) { + /* Wait for the link partner to also set speed */ + msleep(100); + + /* If we have link, just jump out */ + hw->mac.ops.check_link(hw, &phy_link_speed, + &link_up, false); + if (link_up) + goto out; + } } if (speed & IXGBE_LINK_SPEED_1GB_FULL) { @@ -497,16 +544,44 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw, if (highest_link_speed == IXGBE_LINK_SPEED_UNKNOWN) highest_link_speed = IXGBE_LINK_SPEED_1GB_FULL; - /* Set hardware SDP's */ + /* If we already have link at this speed, just jump out */ + hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false); + + if ((phy_link_speed == IXGBE_LINK_SPEED_1GB_FULL) && link_up) + goto out; + + /* Set the module link speed */ esdp_reg &= ~IXGBE_ESDP_SDP5; esdp_reg |= IXGBE_ESDP_SDP5_DIR; IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - ixgbe_setup_mac_link_speed_82599( - hw, IXGBE_LINK_SPEED_1GB_FULL, autoneg, - autoneg_wait_to_complete); + /* Allow module to change analog characteristics (10G->1G) */ + msleep(40); - msleep(50); + status = ixgbe_setup_mac_link_speed_82599(hw, + IXGBE_LINK_SPEED_1GB_FULL, + autoneg, + autoneg_wait_to_complete); + if (status != 0) + goto out; + + /* Flap the tx laser if it has not already been done */ + if (hw->mac.autotry_restart) { + /* Disable tx laser; allow 100us to go dark per spec */ + esdp_reg |= IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + udelay(100); + + /* Enable tx laser; allow 2ms to light up per spec */ + esdp_reg &= ~IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + msleep(2); + + hw->mac.autotry_restart = false; + } + + /* Wait for the link partner to also set speed */ + msleep(100); /* If we have link, just jump out */ hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false); @@ -572,6 +647,11 @@ s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, else *speed = IXGBE_LINK_SPEED_100_FULL; + /* if link is down, zero out the current_mode */ + if (*link_up == false) { + hw->fc.current_mode = ixgbe_fc_none; + hw->fc.fc_was_autonegged = false; + } return 0; } @@ -592,6 +672,7 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, s32 status = 0; u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); + u32 start_autoc = autoc; u32 orig_autoc = 0; u32 link_mode = autoc & IXGBE_AUTOC_LMS_MASK; u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; @@ -604,6 +685,11 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, hw->mac.ops.get_link_capabilities(hw, &link_capabilities, &autoneg); speed &= link_capabilities; + if (speed == IXGBE_LINK_SPEED_UNKNOWN) { + status = IXGBE_ERR_LINK_SETUP; + goto out; + } + /* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/ if (hw->mac.orig_link_settings_stored) orig_autoc = hw->mac.orig_autoc; @@ -611,11 +697,9 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, orig_autoc = autoc; - if (speed == IXGBE_LINK_SPEED_UNKNOWN) { - status = IXGBE_ERR_LINK_SETUP; - } else if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR || - link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN || - link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) { + if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR || + link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN || + link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) { /* Set KX4/KX/KR support according to speed requested */ autoc &= ~(IXGBE_AUTOC_KX4_KX_SUPP_MASK | IXGBE_AUTOC_KR_SUPP); if (speed & IXGBE_LINK_SPEED_10GB_FULL) @@ -647,7 +731,7 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, } } - if (status == 0) { + if (autoc != start_autoc) { /* Restart link */ autoc |= IXGBE_AUTOC_AN_RESTART; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); @@ -674,13 +758,11 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw, } } - /* Set up flow control */ - status = ixgbe_setup_fc_generic(hw, 0); - /* Add delay to filter out noises during initial link setup */ msleep(50); } +out: return status; } @@ -1083,6 +1165,931 @@ s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw) } /** + * ixgbe_reinit_fdir_tables_82599 - Reinitialize Flow Director tables. + * @hw: pointer to hardware structure + **/ +s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw) +{ + int i; + u32 fdirctrl = IXGBE_READ_REG(hw, IXGBE_FDIRCTRL); + fdirctrl &= ~IXGBE_FDIRCTRL_INIT_DONE; + + /* + * Before starting reinitialization process, + * FDIRCMD.CMD must be zero. + */ + for (i = 0; i < IXGBE_FDIRCMD_CMD_POLL; i++) { + if (!(IXGBE_READ_REG(hw, IXGBE_FDIRCMD) & + IXGBE_FDIRCMD_CMD_MASK)) + break; + udelay(10); + } + if (i >= IXGBE_FDIRCMD_CMD_POLL) { + hw_dbg(hw ,"Flow Director previous command isn't complete, " + "aborting table re-initialization. \n"); + return IXGBE_ERR_FDIR_REINIT_FAILED; + } + + IXGBE_WRITE_REG(hw, IXGBE_FDIRFREE, 0); + IXGBE_WRITE_FLUSH(hw); + /* + * 82599 adapters flow director init flow cannot be restarted, + * Workaround 82599 silicon errata by performing the following steps + * before re-writing the FDIRCTRL control register with the same value. + * - write 1 to bit 8 of FDIRCMD register & + * - write 0 to bit 8 of FDIRCMD register + */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, + (IXGBE_READ_REG(hw, IXGBE_FDIRCMD) | + IXGBE_FDIRCMD_CLEARHT)); + IXGBE_WRITE_FLUSH(hw); + IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, + (IXGBE_READ_REG(hw, IXGBE_FDIRCMD) & + ~IXGBE_FDIRCMD_CLEARHT)); + IXGBE_WRITE_FLUSH(hw); + /* + * Clear FDIR Hash register to clear any leftover hashes + * waiting to be programmed. + */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, 0x00); + IXGBE_WRITE_FLUSH(hw); + + IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl); + IXGBE_WRITE_FLUSH(hw); + + /* Poll init-done after we write FDIRCTRL register */ + for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) { + if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & + IXGBE_FDIRCTRL_INIT_DONE) + break; + udelay(10); + } + if (i >= IXGBE_FDIR_INIT_DONE_POLL) { + hw_dbg(hw, "Flow Director Signature poll time exceeded!\n"); + return IXGBE_ERR_FDIR_REINIT_FAILED; + } + + /* Clear FDIR statistics registers (read to clear) */ + IXGBE_READ_REG(hw, IXGBE_FDIRUSTAT); + IXGBE_READ_REG(hw, IXGBE_FDIRFSTAT); + IXGBE_READ_REG(hw, IXGBE_FDIRMATCH); + IXGBE_READ_REG(hw, IXGBE_FDIRMISS); + IXGBE_READ_REG(hw, IXGBE_FDIRLEN); + + return 0; +} + +/** + * ixgbe_init_fdir_signature_82599 - Initialize Flow Director signature filters + * @hw: pointer to hardware structure + * @pballoc: which mode to allocate filters with + **/ +s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc) +{ + u32 fdirctrl = 0; + u32 pbsize; + int i; + + /* + * Before enabling Flow Director, the Rx Packet Buffer size + * must be reduced. The new value is the current size minus + * flow director memory usage size. + */ + pbsize = (1 << (IXGBE_FDIR_PBALLOC_SIZE_SHIFT + pballoc)); + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0), + (IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) - pbsize)); + + /* + * The defaults in the HW for RX PB 1-7 are not zero and so should be + * intialized to zero for non DCB mode otherwise actual total RX PB + * would be bigger than programmed and filter space would run into + * the PB 0 region. + */ + for (i = 1; i < 8; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0); + + /* Send interrupt when 64 filters are left */ + fdirctrl |= 4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT; + + /* Set the maximum length per hash bucket to 0xA filters */ + fdirctrl |= 0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT; + + switch (pballoc) { + case IXGBE_FDIR_PBALLOC_64K: + /* 8k - 1 signature filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_64K; + break; + case IXGBE_FDIR_PBALLOC_128K: + /* 16k - 1 signature filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_128K; + break; + case IXGBE_FDIR_PBALLOC_256K: + /* 32k - 1 signature filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_256K; + break; + default: + /* bad value */ + return IXGBE_ERR_CONFIG; + }; + + /* Move the flexible bytes to use the ethertype - shift 6 words */ + fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT); + + fdirctrl |= IXGBE_FDIRCTRL_REPORT_STATUS; + + /* Prime the keys for hashing */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY, + htonl(IXGBE_ATR_BUCKET_HASH_KEY)); + IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY, + htonl(IXGBE_ATR_SIGNATURE_HASH_KEY)); + + /* + * Poll init-done after we write the register. Estimated times: + * 10G: PBALLOC = 11b, timing is 60us + * 1G: PBALLOC = 11b, timing is 600us + * 100M: PBALLOC = 11b, timing is 6ms + * + * Multiple these timings by 4 if under full Rx load + * + * So we'll poll for IXGBE_FDIR_INIT_DONE_POLL times, sleeping for + * 1 msec per poll time. If we're at line rate and drop to 100M, then + * this might not finish in our poll time, but we can live with that + * for now. + */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl); + IXGBE_WRITE_FLUSH(hw); + for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) { + if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & + IXGBE_FDIRCTRL_INIT_DONE) + break; + msleep(1); + } + if (i >= IXGBE_FDIR_INIT_DONE_POLL) + hw_dbg(hw, "Flow Director Signature poll time exceeded!\n"); + + return 0; +} + +/** + * ixgbe_init_fdir_perfect_82599 - Initialize Flow Director perfect filters + * @hw: pointer to hardware structure + * @pballoc: which mode to allocate filters with + **/ +s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc) +{ + u32 fdirctrl = 0; + u32 pbsize; + int i; + + /* + * Before enabling Flow Director, the Rx Packet Buffer size + * must be reduced. The new value is the current size minus + * flow director memory usage size. + */ + pbsize = (1 << (IXGBE_FDIR_PBALLOC_SIZE_SHIFT + pballoc)); + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0), + (IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) - pbsize)); + + /* + * The defaults in the HW for RX PB 1-7 are not zero and so should be + * intialized to zero for non DCB mode otherwise actual total RX PB + * would be bigger than programmed and filter space would run into + * the PB 0 region. + */ + for (i = 1; i < 8; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0); + + /* Send interrupt when 64 filters are left */ + fdirctrl |= 4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT; + + switch (pballoc) { + case IXGBE_FDIR_PBALLOC_64K: + /* 2k - 1 perfect filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_64K; + break; + case IXGBE_FDIR_PBALLOC_128K: + /* 4k - 1 perfect filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_128K; + break; + case IXGBE_FDIR_PBALLOC_256K: + /* 8k - 1 perfect filters */ + fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_256K; + break; + default: + /* bad value */ + return IXGBE_ERR_CONFIG; + }; + + /* Turn perfect match filtering on */ + fdirctrl |= IXGBE_FDIRCTRL_PERFECT_MATCH; + fdirctrl |= IXGBE_FDIRCTRL_REPORT_STATUS; + + /* Move the flexible bytes to use the ethertype - shift 6 words */ + fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT); + + /* Prime the keys for hashing */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY, + htonl(IXGBE_ATR_BUCKET_HASH_KEY)); + IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY, + htonl(IXGBE_ATR_SIGNATURE_HASH_KEY)); + + /* + * Poll init-done after we write the register. Estimated times: + * 10G: PBALLOC = 11b, timing is 60us + * 1G: PBALLOC = 11b, timing is 600us + * 100M: PBALLOC = 11b, timing is 6ms + * + * Multiple these timings by 4 if under full Rx load + * + * So we'll poll for IXGBE_FDIR_INIT_DONE_POLL times, sleeping for + * 1 msec per poll time. If we're at line rate and drop to 100M, then + * this might not finish in our poll time, but we can live with that + * for now. + */ + + /* Set the maximum length per hash bucket to 0xA filters */ + fdirctrl |= (0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT); + + IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl); + IXGBE_WRITE_FLUSH(hw); + for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) { + if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & + IXGBE_FDIRCTRL_INIT_DONE) + break; + msleep(1); + } + if (i >= IXGBE_FDIR_INIT_DONE_POLL) + hw_dbg(hw, "Flow Director Perfect poll time exceeded!\n"); + + return 0; +} + + +/** + * ixgbe_atr_compute_hash_82599 - Compute the hashes for SW ATR + * @stream: input bitstream to compute the hash on + * @key: 32-bit hash key + **/ +u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input, u32 key) +{ + /* + * The algorithm is as follows: + * Hash[15:0] = Sum { S[n] x K[n+16] }, n = 0...350 + * where Sum {A[n]}, n = 0...n is bitwise XOR of A[0], A[1]...A[n] + * and A[n] x B[n] is bitwise AND between same length strings + * + * K[n] is 16 bits, defined as: + * for n modulo 32 >= 15, K[n] = K[n % 32 : (n % 32) - 15] + * for n modulo 32 < 15, K[n] = + * K[(n % 32:0) | (31:31 - (14 - (n % 32)))] + * + * S[n] is 16 bits, defined as: + * for n >= 15, S[n] = S[n:n - 15] + * for n < 15, S[n] = S[(n:0) | (350:350 - (14 - n))] + * + * To simplify for programming, the algorithm is implemented + * in software this way: + * + * Key[31:0], Stream[335:0] + * + * tmp_key[11 * 32 - 1:0] = 11{Key[31:0] = key concatenated 11 times + * int_key[350:0] = tmp_key[351:1] + * int_stream[365:0] = Stream[14:0] | Stream[335:0] | Stream[335:321] + * + * hash[15:0] = 0; + * for (i = 0; i < 351; i++) { + * if (int_key[i]) + * hash ^= int_stream[(i + 15):i]; + * } + */ + + union { + u64 fill[6]; + u32 key[11]; + u8 key_stream[44]; + } tmp_key; + + u8 *stream = (u8 *)atr_input; + u8 int_key[44]; /* upper-most bit unused */ + u8 hash_str[46]; /* upper-most 2 bits unused */ + u16 hash_result = 0; + int i, j, k, h; + + /* + * Initialize the fill member to prevent warnings + * on some compilers + */ + tmp_key.fill[0] = 0; + + /* First load the temporary key stream */ + for (i = 0; i < 6; i++) { + u64 fillkey = ((u64)key << 32) | key; + tmp_key.fill[i] = fillkey; + } + + /* + * Set the interim key for the hashing. Bit 352 is unused, so we must + * shift and compensate when building the key. + */ + + int_key[0] = tmp_key.key_stream[0] >> 1; + for (i = 1, j = 0; i < 44; i++) { + unsigned int this_key = tmp_key.key_stream[j] << 7; + j++; + int_key[i] = (u8)(this_key | (tmp_key.key_stream[j] >> 1)); + } + + /* + * Set the interim bit string for the hashing. Bits 368 and 367 are + * unused, so shift and compensate when building the string. + */ + hash_str[0] = (stream[40] & 0x7f) >> 1; + for (i = 1, j = 40; i < 46; i++) { + unsigned int this_str = stream[j] << 7; + j++; + if (j > 41) + j = 0; + hash_str[i] = (u8)(this_str | (stream[j] >> 1)); + } + + /* + * Now compute the hash. i is the index into hash_str, j is into our + * key stream, k is counting the number of bits, and h interates within + * each byte. + */ + for (i = 45, j = 43, k = 0; k < 351 && i >= 2 && j >= 0; i--, j--) { + for (h = 0; h < 8 && k < 351; h++, k++) { + if (int_key[j] & (1 << h)) { + /* + * Key bit is set, XOR in the current 16-bit + * string. Example of processing: + * h = 0, + * tmp = (hash_str[i - 2] & 0 << 16) | + * (hash_str[i - 1] & 0xff << 8) | + * (hash_str[i] & 0xff >> 0) + * So tmp = hash_str[15 + k:k], since the + * i + 2 clause rolls off the 16-bit value + * h = 7, + * tmp = (hash_str[i - 2] & 0x7f << 9) | + * (hash_str[i - 1] & 0xff << 1) | + * (hash_str[i] & 0x80 >> 7) + */ + int tmp = (hash_str[i] >> h); + tmp |= (hash_str[i - 1] << (8 - h)); + tmp |= (int)(hash_str[i - 2] & ((1 << h) - 1)) + << (16 - h); + hash_result ^= (u16)tmp; + } + } + } + + return hash_result; +} + +/** + * ixgbe_atr_set_vlan_id_82599 - Sets the VLAN id in the ATR input stream + * @input: input stream to modify + * @vlan: the VLAN id to load + **/ +s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan) +{ + input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] = vlan >> 8; + input->byte_stream[IXGBE_ATR_VLAN_OFFSET] = vlan & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_src_ipv4_82599 - Sets the source IPv4 address + * @input: input stream to modify + * @src_addr: the IP address to load + **/ +s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, u32 src_addr) +{ + input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 3] = src_addr >> 24; + input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 2] = + (src_addr >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] = + (src_addr >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET] = src_addr & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_dst_ipv4_82599 - Sets the destination IPv4 address + * @input: input stream to modify + * @dst_addr: the IP address to load + **/ +s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr) +{ + input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 3] = dst_addr >> 24; + input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 2] = + (dst_addr >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] = + (dst_addr >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET] = dst_addr & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_src_ipv6_82599 - Sets the source IPv6 address + * @input: input stream to modify + * @src_addr_1: the first 4 bytes of the IP address to load + * @src_addr_2: the second 4 bytes of the IP address to load + * @src_addr_3: the third 4 bytes of the IP address to load + * @src_addr_4: the fourth 4 bytes of the IP address to load + **/ +s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 src_addr_1, u32 src_addr_2, + u32 src_addr_3, u32 src_addr_4) +{ + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET] = src_addr_4 & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] = + (src_addr_4 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 2] = + (src_addr_4 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 3] = src_addr_4 >> 24; + + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 4] = src_addr_3 & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 5] = + (src_addr_3 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 6] = + (src_addr_3 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 7] = src_addr_3 >> 24; + + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 8] = src_addr_2 & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 9] = + (src_addr_2 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 10] = + (src_addr_2 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 11] = src_addr_2 >> 24; + + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12] = src_addr_1 & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] = + (src_addr_1 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 14] = + (src_addr_1 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 15] = src_addr_1 >> 24; + + return 0; +} + +/** + * ixgbe_atr_set_dst_ipv6_82599 - Sets the destination IPv6 address + * @input: input stream to modify + * @dst_addr_1: the first 4 bytes of the IP address to load + * @dst_addr_2: the second 4 bytes of the IP address to load + * @dst_addr_3: the third 4 bytes of the IP address to load + * @dst_addr_4: the fourth 4 bytes of the IP address to load + **/ +s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input, + u32 dst_addr_1, u32 dst_addr_2, + u32 dst_addr_3, u32 dst_addr_4) +{ + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET] = dst_addr_4 & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] = + (dst_addr_4 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 2] = + (dst_addr_4 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 3] = dst_addr_4 >> 24; + + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 4] = dst_addr_3 & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 5] = + (dst_addr_3 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 6] = + (dst_addr_3 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 7] = dst_addr_3 >> 24; + + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 8] = dst_addr_2 & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 9] = + (dst_addr_2 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 10] = + (dst_addr_2 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 11] = dst_addr_2 >> 24; + + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 12] = dst_addr_1 & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 13] = + (dst_addr_1 >> 8) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 14] = + (dst_addr_1 >> 16) & 0xff; + input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 15] = dst_addr_1 >> 24; + + return 0; +} + +/** + * ixgbe_atr_set_src_port_82599 - Sets the source port + * @input: input stream to modify + * @src_port: the source port to load + **/ +s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, u16 src_port) +{ + input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1] = src_port >> 8; + input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] = src_port & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_dst_port_82599 - Sets the destination port + * @input: input stream to modify + * @dst_port: the destination port to load + **/ +s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, u16 dst_port) +{ + input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1] = dst_port >> 8; + input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] = dst_port & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_flex_byte_82599 - Sets the flexible bytes + * @input: input stream to modify + * @flex_bytes: the flexible bytes to load + **/ +s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte) +{ + input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] = flex_byte >> 8; + input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET] = flex_byte & 0xff; + + return 0; +} + +/** + * ixgbe_atr_set_vm_pool_82599 - Sets the Virtual Machine pool + * @input: input stream to modify + * @vm_pool: the Virtual Machine pool to load + **/ +s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, u8 vm_pool) +{ + input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET] = vm_pool; + + return 0; +} + +/** + * ixgbe_atr_set_l4type_82599 - Sets the layer 4 packet type + * @input: input stream to modify + * @l4type: the layer 4 type value to load + **/ +s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type) +{ + input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET] = l4type; + + return 0; +} + +/** + * ixgbe_atr_get_vlan_id_82599 - Gets the VLAN id from the ATR input stream + * @input: input stream to search + * @vlan: the VLAN id to load + **/ +s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan) +{ + *vlan = input->byte_stream[IXGBE_ATR_VLAN_OFFSET]; + *vlan |= input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] << 8; + + return 0; +} + +/** + * ixgbe_atr_get_src_ipv4_82599 - Gets the source IPv4 address + * @input: input stream to search + * @src_addr: the IP address to load + **/ +s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, u32 *src_addr) +{ + *src_addr = input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET]; + *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] << 8; + *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 2] << 16; + *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 3] << 24; + + return 0; +} + +/** + * ixgbe_atr_get_dst_ipv4_82599 - Gets the destination IPv4 address + * @input: input stream to search + * @dst_addr: the IP address to load + **/ +s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 *dst_addr) +{ + *dst_addr = input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET]; + *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] << 8; + *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 2] << 16; + *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 3] << 24; + + return 0; +} + +/** + * ixgbe_atr_get_src_ipv6_82599 - Gets the source IPv6 address + * @input: input stream to search + * @src_addr_1: the first 4 bytes of the IP address to load + * @src_addr_2: the second 4 bytes of the IP address to load + * @src_addr_3: the third 4 bytes of the IP address to load + * @src_addr_4: the fourth 4 bytes of the IP address to load + **/ +s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input, + u32 *src_addr_1, u32 *src_addr_2, + u32 *src_addr_3, u32 *src_addr_4) +{ + *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12]; + *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] << 8; + *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 14] << 16; + *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 15] << 24; + + *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 8]; + *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 9] << 8; + *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 10] << 16; + *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 11] << 24; + + *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 4]; + *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 5] << 8; + *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 6] << 16; + *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 7] << 24; + + *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET]; + *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] << 8; + *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 2] << 16; + *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 3] << 24; + + return 0; +} + +/** + * ixgbe_atr_get_dst_ipv6_82599 - Gets the destination IPv6 address + * @input: input stream to search + * @dst_addr_1: the first 4 bytes of the IP address to load + * @dst_addr_2: the second 4 bytes of the IP address to load + * @dst_addr_3: the third 4 bytes of the IP address to load + * @dst_addr_4: the fourth 4 bytes of the IP address to load + **/ +s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input, + u32 *dst_addr_1, u32 *dst_addr_2, + u32 *dst_addr_3, u32 *dst_addr_4) +{ + *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 12]; + *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 13] << 8; + *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 14] << 16; + *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 15] << 24; + + *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 8]; + *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 9] << 8; + *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 10] << 16; + *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 11] << 24; + + *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 4]; + *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 5] << 8; + *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 6] << 16; + *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 7] << 24; + + *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET]; + *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] << 8; + *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 2] << 16; + *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 3] << 24; + + return 0; +} + +/** + * ixgbe_atr_get_src_port_82599 - Gets the source port + * @input: input stream to modify + * @src_port: the source port to load + * + * Even though the input is given in big-endian, the FDIRPORT registers + * expect the ports to be programmed in little-endian. Hence the need to swap + * endianness when retrieving the data. This can be confusing since the + * internal hash engine expects it to be big-endian. + **/ +s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, u16 *src_port) +{ + *src_port = input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] << 8; + *src_port |= input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1]; + + return 0; +} + +/** + * ixgbe_atr_get_dst_port_82599 - Gets the destination port + * @input: input stream to modify + * @dst_port: the destination port to load + * + * Even though the input is given in big-endian, the FDIRPORT registers + * expect the ports to be programmed in little-endian. Hence the need to swap + * endianness when retrieving the data. This can be confusing since the + * internal hash engine expects it to be big-endian. + **/ +s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, u16 *dst_port) +{ + *dst_port = input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] << 8; + *dst_port |= input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1]; + + return 0; +} + +/** + * ixgbe_atr_get_flex_byte_82599 - Gets the flexible bytes + * @input: input stream to modify + * @flex_bytes: the flexible bytes to load + **/ +s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, u16 *flex_byte) +{ + *flex_byte = input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET]; + *flex_byte |= input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] << 8; + + return 0; +} + +/** + * ixgbe_atr_get_vm_pool_82599 - Gets the Virtual Machine pool + * @input: input stream to modify + * @vm_pool: the Virtual Machine pool to load + **/ +s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, u8 *vm_pool) +{ + *vm_pool = input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET]; + + return 0; +} + +/** + * ixgbe_atr_get_l4type_82599 - Gets the layer 4 packet type + * @input: input stream to modify + * @l4type: the layer 4 type value to load + **/ +s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, u8 *l4type) +{ + *l4type = input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET]; + + return 0; +} + +/** + * ixgbe_atr_add_signature_filter_82599 - Adds a signature hash filter + * @hw: pointer to hardware structure + * @stream: input bitstream + * @queue: queue index to direct traffic to + **/ +s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + u8 queue) +{ + u64 fdirhashcmd; + u64 fdircmd; + u32 fdirhash; + u16 bucket_hash, sig_hash; + u8 l4type; + + bucket_hash = ixgbe_atr_compute_hash_82599(input, + IXGBE_ATR_BUCKET_HASH_KEY); + + /* bucket_hash is only 15 bits */ + bucket_hash &= IXGBE_ATR_HASH_MASK; + + sig_hash = ixgbe_atr_compute_hash_82599(input, + IXGBE_ATR_SIGNATURE_HASH_KEY); + + /* Get the l4type in order to program FDIRCMD properly */ + /* lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6 */ + ixgbe_atr_get_l4type_82599(input, &l4type); + + /* + * The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits + * is for FDIRCMD. Then do a 64-bit register write from FDIRHASH. + */ + fdirhash = sig_hash << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT | bucket_hash; + + fdircmd = (IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE | + IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN); + + switch (l4type & IXGBE_ATR_L4TYPE_MASK) { + case IXGBE_ATR_L4TYPE_TCP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_TCP; + break; + case IXGBE_ATR_L4TYPE_UDP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_UDP; + break; + case IXGBE_ATR_L4TYPE_SCTP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_SCTP; + break; + default: + hw_dbg(hw, "Error on l4type input\n"); + return IXGBE_ERR_CONFIG; + } + + if (l4type & IXGBE_ATR_L4TYPE_IPV6_MASK) + fdircmd |= IXGBE_FDIRCMD_IPV6; + + fdircmd |= ((u64)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT); + fdirhashcmd = ((fdircmd << 32) | fdirhash); + + IXGBE_WRITE_REG64(hw, IXGBE_FDIRHASH, fdirhashcmd); + + return 0; +} + +/** + * ixgbe_fdir_add_perfect_filter_82599 - Adds a perfect filter + * @hw: pointer to hardware structure + * @input: input bitstream + * @queue: queue index to direct traffic to + * + * Note that the caller to this function must lock before calling, since the + * hardware writes must be protected from one another. + **/ +s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw, + struct ixgbe_atr_input *input, + u16 soft_id, + u8 queue) +{ + u32 fdircmd = 0; + u32 fdirhash; + u32 src_ipv4, dst_ipv4; + u32 src_ipv6_1, src_ipv6_2, src_ipv6_3, src_ipv6_4; + u16 src_port, dst_port, vlan_id, flex_bytes; + u16 bucket_hash; + u8 l4type; + + /* Get our input values */ + ixgbe_atr_get_l4type_82599(input, &l4type); + + /* + * Check l4type formatting, and bail out before we touch the hardware + * if there's a configuration issue + */ + switch (l4type & IXGBE_ATR_L4TYPE_MASK) { + case IXGBE_ATR_L4TYPE_TCP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_TCP; + break; + case IXGBE_ATR_L4TYPE_UDP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_UDP; + break; + case IXGBE_ATR_L4TYPE_SCTP: + fdircmd |= IXGBE_FDIRCMD_L4TYPE_SCTP; + break; + default: + hw_dbg(hw, "Error on l4type input\n"); + return IXGBE_ERR_CONFIG; + } + + bucket_hash = ixgbe_atr_compute_hash_82599(input, + IXGBE_ATR_BUCKET_HASH_KEY); + + /* bucket_hash is only 15 bits */ + bucket_hash &= IXGBE_ATR_HASH_MASK; + + ixgbe_atr_get_vlan_id_82599(input, &vlan_id); + ixgbe_atr_get_src_port_82599(input, &src_port); + ixgbe_atr_get_dst_port_82599(input, &dst_port); + ixgbe_atr_get_flex_byte_82599(input, &flex_bytes); + + fdirhash = soft_id << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT | bucket_hash; + + /* Now figure out if we're IPv4 or IPv6 */ + if (l4type & IXGBE_ATR_L4TYPE_IPV6_MASK) { + /* IPv6 */ + ixgbe_atr_get_src_ipv6_82599(input, &src_ipv6_1, &src_ipv6_2, + &src_ipv6_3, &src_ipv6_4); + + IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(0), src_ipv6_1); + IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(1), src_ipv6_2); + IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(2), src_ipv6_3); + /* The last 4 bytes is the same register as IPv4 */ + IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv6_4); + + fdircmd |= IXGBE_FDIRCMD_IPV6; + fdircmd |= IXGBE_FDIRCMD_IPv6DMATCH; + } else { + /* IPv4 */ + ixgbe_atr_get_src_ipv4_82599(input, &src_ipv4); + IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv4); + + } + + ixgbe_atr_get_dst_ipv4_82599(input, &dst_ipv4); + IXGBE_WRITE_REG(hw, IXGBE_FDIRIPDA, dst_ipv4); + + IXGBE_WRITE_REG(hw, IXGBE_FDIRVLAN, (vlan_id | + (flex_bytes << IXGBE_FDIRVLAN_FLEX_SHIFT))); + IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, (src_port | + (dst_port << IXGBE_FDIRPORT_DESTINATION_SHIFT))); + + fdircmd |= IXGBE_FDIRCMD_CMD_ADD_FLOW; + fdircmd |= IXGBE_FDIRCMD_FILTER_UPDATE; + fdircmd |= IXGBE_FDIRCMD_LAST; + fdircmd |= IXGBE_FDIRCMD_QUEUE_EN; + fdircmd |= queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT; + + IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, fdirhash); + IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, fdircmd); + + return 0; +} +/** * ixgbe_read_analog_reg8_82599 - Reads 8 bit Omer analog register * @hw: pointer to hardware structure * @reg: analog register to read @@ -1135,8 +2142,9 @@ s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) { u32 q_num; + s32 ret_val; - ixgbe_start_hw_generic(hw); + ret_val = ixgbe_start_hw_generic(hw); /* Clear the rate limiters */ for (q_num = 0; q_num < hw->mac.max_tx_queues; q_num++) { @@ -1145,7 +2153,13 @@ s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) } IXGBE_WRITE_FLUSH(hw); - return 0; + /* We need to run link autotry after the driver loads */ + hw->mac.autotry_restart = true; + + if (ret_val == 0) + ret_val = ixgbe_verify_fw_version_82599(hw); + + return ret_val; } /** @@ -1397,6 +2411,54 @@ san_mac_addr_out: return 0; } +/** + * ixgbe_verify_fw_version_82599 - verify fw version for 82599 + * @hw: pointer to hardware structure + * + * Verifies that installed the firmware version is 0.6 or higher + * for SFI devices. All 82599 SFI devices should have version 0.6 or higher. + * + * Returns IXGBE_ERR_EEPROM_VERSION if the FW is not present or + * if the FW version is not supported. + **/ +static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_ERR_EEPROM_VERSION; + u16 fw_offset, fw_ptp_cfg_offset; + u16 fw_version = 0; + + /* firmware check is only necessary for SFI devices */ + if (hw->phy.media_type != ixgbe_media_type_fiber) { + status = 0; + goto fw_version_out; + } + + /* get the offset to the Firmware Module block */ + hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset); + + if ((fw_offset == 0) || (fw_offset == 0xFFFF)) + goto fw_version_out; + + /* get the offset to the Pass Through Patch Configuration block */ + hw->eeprom.ops.read(hw, (fw_offset + + IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR), + &fw_ptp_cfg_offset); + + if ((fw_ptp_cfg_offset == 0) || (fw_ptp_cfg_offset == 0xFFFF)) + goto fw_version_out; + + /* get the firmware version */ + hw->eeprom.ops.read(hw, (fw_ptp_cfg_offset + + IXGBE_FW_PATCH_VERSION_4), + &fw_version); + + if (fw_version > 0x5) + status = 0; + +fw_version_out: + return status; +} + static struct ixgbe_mac_operations mac_ops_82599 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82599, @@ -1432,7 +2494,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .disable_mc = &ixgbe_disable_mc_generic, .clear_vfta = &ixgbe_clear_vfta_82599, .set_vfta = &ixgbe_set_vfta_82599, - .setup_fc = &ixgbe_setup_fc_generic, + .fc_enable = &ixgbe_fc_enable_generic, .init_uta_tables = &ixgbe_init_uta_tables_82599, .setup_sfp = &ixgbe_setup_sfp_modules_82599, }; diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 0cc3c47cb453..96a185953777 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -28,6 +28,8 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/sched.h> +#include <linux/list.h> +#include <linux/netdevice.h> #include "ixgbe.h" #include "ixgbe_common.h" @@ -83,6 +85,9 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); IXGBE_WRITE_FLUSH(hw); + /* Setup flow control */ + ixgbe_setup_fc(hw, 0); + /* Clear adapter stopped flag */ hw->adapter_stopped = false; @@ -101,13 +106,17 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) **/ s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw) { + s32 status; + /* Reset the hardware */ - hw->mac.ops.reset_hw(hw); + status = hw->mac.ops.reset_hw(hw); - /* Start the HW */ - hw->mac.ops.start_hw(hw); + if (status == 0) { + /* Start the HW */ + status = hw->mac.ops.start_hw(hw); + } - return 0; + return status; } /** @@ -1356,15 +1365,14 @@ static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq) * Drivers using secondary unicast addresses must set user_set_promisc when * manually putting the device into promiscuous mode. **/ -s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, - u32 addr_count, ixgbe_mc_addr_itr next) +s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, + struct list_head *uc_list) { - u8 *addr; u32 i; u32 old_promisc_setting = hw->addr_ctrl.overflow_promisc; u32 uc_addr_in_use; u32 fctrl; - u32 vmdq; + struct netdev_hw_addr *ha; /* * Clear accounting of old secondary address list, @@ -1382,10 +1390,9 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, } /* Add the new addresses */ - for (i = 0; i < addr_count; i++) { + list_for_each_entry(ha, uc_list, list) { hw_dbg(hw, " Adding the secondary addresses:\n"); - addr = next(hw, &addr_list, &vmdq); - ixgbe_add_uc_addr(hw, addr, vmdq); + ixgbe_add_uc_addr(hw, ha->addr, 0); } if (hw->addr_ctrl.overflow_promisc) { @@ -1577,17 +1584,16 @@ s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw) } /** - * ixgbe_fc_enable - Enable flow control + * ixgbe_fc_enable_generic - Enable flow control * @hw: pointer to hardware structure * @packetbuf_num: packet buffer number (0-7) * * Enable flow control according to the current settings. **/ -s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) +s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) { s32 ret_val = 0; - u32 mflcn_reg; - u32 fccfg_reg; + u32 mflcn_reg, fccfg_reg; u32 reg; u32 rx_pba_size; @@ -1596,7 +1602,12 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) goto out; #endif /* CONFIG_DCB */ + /* Negotiate the fc mode to use */ + ret_val = ixgbe_fc_autoneg(hw); + if (ret_val) + goto out; + /* Disable any previous flow control settings */ mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); mflcn_reg &= ~(IXGBE_MFLCN_RFCE | IXGBE_MFLCN_RPFCE); @@ -1616,7 +1627,10 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) */ switch (hw->fc.current_mode) { case ixgbe_fc_none: - /* Flow control completely disabled by software override. */ + /* + * Flow control is disabled by software override or autoneg. + * The code below will actually disable it in the HW. + */ break; case ixgbe_fc_rx_pause: /* @@ -1645,7 +1659,7 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) case ixgbe_fc_pfc: goto out; break; -#endif +#endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = -IXGBE_ERR_CONFIG; @@ -1653,7 +1667,7 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) break; } - /* Enable 802.3x based flow control settings. */ + /* Set 802.3x based flow control settings. */ mflcn_reg |= IXGBE_MFLCN_DPF; IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg); IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg); @@ -1661,10 +1675,12 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num) reg = IXGBE_READ_REG(hw, IXGBE_MTQC); /* Thresholds are different for link flow control when in DCB mode */ if (reg & IXGBE_MTQC_RT_ENA) { + rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num)); + /* Always disable XON for LFC when in DCB mode */ - IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), 0); + reg = (rx_pba_size >> 5) & 0xFFE0; + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), reg); - rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num)); reg = (rx_pba_size >> 2) & 0xFFE0; if (hw->fc.current_mode & ixgbe_fc_tx_pause) reg |= IXGBE_FCRTH_FCEN; @@ -1709,100 +1725,41 @@ out: * ixgbe_fc_autoneg - Configure flow control * @hw: pointer to hardware structure * - * Negotiates flow control capabilities with link partner using autoneg and - * applies the results. + * Compares our advertised flow control capabilities to those advertised by + * our link partner, and determines the proper flow control mode to use. **/ s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw) { s32 ret_val = 0; - u32 i, reg, pcs_anadv_reg, pcs_lpab_reg; - - reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); + ixgbe_link_speed speed; + u32 pcs_anadv_reg, pcs_lpab_reg, linkstat; + bool link_up; /* - * The possible values of fc.current_mode are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames, - * but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames but - * we do not support receiving pause frames). - * 3: Both Rx and Tx flow control (symmetric) are enabled. - * 4: Priority Flow Control is enabled. - * other: Invalid. + * AN should have completed when the cable was plugged in. + * Look for reasons to bail out. Bail out if: + * - FC autoneg is disabled, or if + * - we don't have multispeed fiber, or if + * - we're not running at 1G, or if + * - link is not up, or if + * - link is up but AN did not complete, or if + * - link is up and AN completed but timed out + * + * Since we're being called from an LSC, link is already know to be up. + * So use link_up_wait_to_complete=false. */ - switch (hw->fc.current_mode) { - case ixgbe_fc_none: - /* Flow control completely disabled by software override. */ - reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - break; - case ixgbe_fc_rx_pause: - /* - * Rx Flow control is enabled and Tx Flow control is - * disabled by software override. Since there really - * isn't a way to advertise that we are capable of RX - * Pause ONLY, we will advertise that we support both - * symmetric and asymmetric Rx PAUSE. Later, we will - * disable the adapter's ability to send PAUSE frames. - */ - reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - break; - case ixgbe_fc_tx_pause: - /* - * Tx Flow control is enabled, and Rx Flow control is - * disabled by software override. - */ - reg |= (IXGBE_PCS1GANA_ASM_PAUSE); - reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE); - break; - case ixgbe_fc_full: - /* Flow control (both Rx and Tx) is enabled by SW override. */ - reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - break; -#ifdef CONFIG_DCB - case ixgbe_fc_pfc: - goto out; - break; -#endif - default: - hw_dbg(hw, "Flow control param set incorrectly\n"); - ret_val = -IXGBE_ERR_CONFIG; - goto out; - break; - } - - IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg); - reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); - - /* Set PCS register for autoneg */ - /* Enable and restart autoneg */ - reg |= IXGBE_PCS1GLCTL_AN_ENABLE | IXGBE_PCS1GLCTL_AN_RESTART; - - /* Disable AN timeout */ - if (hw->fc.strict_ieee) - reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN; - - hw_dbg(hw, "Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg); - IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg); - - /* See if autonegotiation has succeeded */ - hw->mac.autoneg_succeeded = 0; - for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { - msleep(10); - reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); - if ((reg & (IXGBE_PCS1GLSTA_LINK_OK | - IXGBE_PCS1GLSTA_AN_COMPLETE)) == - (IXGBE_PCS1GLSTA_LINK_OK | - IXGBE_PCS1GLSTA_AN_COMPLETE)) { - if (!(reg & IXGBE_PCS1GLSTA_AN_TIMED_OUT)) - hw->mac.autoneg_succeeded = 1; - break; - } - } - - if (!hw->mac.autoneg_succeeded) { - /* Autoneg failed to achieve a link, so we turn fc off */ - hw->fc.current_mode = ixgbe_fc_none; - hw_dbg(hw, "Flow Control = NONE.\n"); + hw->mac.ops.check_link(hw, &speed, &link_up, false); + linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); + + if (hw->fc.disable_fc_autoneg || + !hw->phy.multispeed_fiber || + (speed != IXGBE_LINK_SPEED_1GB_FULL) || + !link_up || + ((linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) || + ((linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) { + hw->fc.fc_was_autonegged = false; + hw->fc.current_mode = hw->fc.requested_mode; + hw_dbg(hw, "Autoneg FC was skipped.\n"); goto out; } @@ -1845,21 +1802,23 @@ s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw) hw_dbg(hw, "Flow Control = NONE.\n"); } + /* Record that current_mode is the result of a successful autoneg */ + hw->fc.fc_was_autonegged = true; + out: return ret_val; } /** - * ixgbe_setup_fc_generic - Set up flow control + * ixgbe_setup_fc - Set up flow control * @hw: pointer to hardware structure * - * Sets up flow control. + * Called at init time to set up flow control. **/ -s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num) +s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) { s32 ret_val = 0; - ixgbe_link_speed speed; - bool link_up; + u32 reg; #ifdef CONFIG_DCB if (hw->fc.requested_mode == ixgbe_fc_pfc) { @@ -1881,16 +1840,14 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num) * because it causes the controller to just blast out fc packets. */ if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) { - if (hw->fc.requested_mode != ixgbe_fc_none) { - hw_dbg(hw, "Invalid water mark configuration\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } + hw_dbg(hw, "Invalid water mark configuration\n"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; } /* * Validate the requested mode. Strict IEEE mode does not allow - * ixgbe_fc_rx_pause because it will cause testing anomalies. + * ixgbe_fc_rx_pause because it will cause us to fail at UNH. */ if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict " @@ -1907,21 +1864,77 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num) hw->fc.requested_mode = ixgbe_fc_full; /* - * Save off the requested flow control mode for use later. Depending - * on the link partner's capabilities, we may or may not use this mode. + * Set up the 1G flow control advertisement registers so the HW will be + * able to do fc autoneg once the cable is plugged in. If we end up + * using 10g instead, this is harmless. */ - hw->fc.current_mode = hw->fc.requested_mode; - - /* Decide whether to use autoneg or not. */ - hw->mac.ops.check_link(hw, &speed, &link_up, false); - if (!hw->fc.disable_fc_autoneg && hw->phy.multispeed_fiber && - (speed == IXGBE_LINK_SPEED_1GB_FULL)) - ret_val = ixgbe_fc_autoneg(hw); + reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); - if (ret_val) + /* + * The possible values of fc.requested_mode are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames, + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but + * we do not support receiving pause frames). + * 3: Both Rx and Tx flow control (symmetric) are enabled. +#ifdef CONFIG_DCB + * 4: Priority Flow Control is enabled. +#endif + * other: Invalid. + */ + switch (hw->fc.requested_mode) { + case ixgbe_fc_none: + /* Flow control completely disabled by software override. */ + reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + break; + case ixgbe_fc_rx_pause: + /* + * Rx Flow control is enabled and Tx Flow control is + * disabled by software override. Since there really + * isn't a way to advertise that we are capable of RX + * Pause ONLY, we will advertise that we support both + * symmetric and asymmetric Rx PAUSE. Later, we will + * disable the adapter's ability to send PAUSE frames. + */ + reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + break; + case ixgbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + reg |= (IXGBE_PCS1GANA_ASM_PAUSE); + reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE); + break; + case ixgbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + break; +#ifdef CONFIG_DCB + case ixgbe_fc_pfc: + goto out; + break; +#endif /* CONFIG_DCB */ + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + ret_val = -IXGBE_ERR_CONFIG; goto out; + break; + } - ret_val = ixgbe_fc_enable(hw, packetbuf_num); + IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg); + reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); + + /* Enable and restart autoneg to inform the link partner */ + reg |= IXGBE_PCS1GLCTL_AN_ENABLE | IXGBE_PCS1GLCTL_AN_RESTART; + + /* Disable AN timeout */ + if (hw->fc.strict_ieee) + reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN; + + IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg); + hw_dbg(hw, "Set up FC; PCS1GLCTL = 0x%08X\n", reg); out: return ret_val; @@ -2068,6 +2081,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) hw->mac.ops.check_link(hw, &speed, &link_up, false); if (!link_up) { + autoc_reg |= IXGBE_AUTOC_AN_RESTART; autoc_reg |= IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); msleep(10); diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index dd260890ad0a..0d34d4d8244c 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -59,13 +59,13 @@ s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw); s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list, u32 mc_addr_count, ixgbe_mc_addr_itr func); -s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, - u32 addr_count, ixgbe_mc_addr_itr func); +s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, + struct list_head *uc_list); s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval); -s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num); -s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packtetbuf_num); +s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); +s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packtetbuf_num); s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw); s32 ixgbe_validate_mac_addr(u8 *mac_addr); diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c index f4417fc3b0fd..589f62c7062a 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c @@ -295,7 +295,7 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, /* If PFC is disabled globally then fall back to LFC. */ if (!dcb_config->pfc_mode_enable) { for (i = 0; i < MAX_TRAFFIC_CLASS; i++) - hw->mac.ops.setup_fc(hw, i); + hw->mac.ops.fc_enable(hw, i); goto out; } diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 35255b8e90b7..86f4f3e36f27 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -68,6 +68,8 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"rx_crc_errors", IXGBE_STAT(net_stats.rx_crc_errors)}, {"rx_frame_errors", IXGBE_STAT(net_stats.rx_frame_errors)}, {"hw_rsc_count", IXGBE_STAT(rsc_count)}, + {"fdir_match", IXGBE_STAT(stats.fdirmatch)}, + {"fdir_miss", IXGBE_STAT(stats.fdirmiss)}, {"rx_fifo_errors", IXGBE_STAT(net_stats.rx_fifo_errors)}, {"rx_missed_errors", IXGBE_STAT(net_stats.rx_missed_errors)}, {"tx_aborted_errors", IXGBE_STAT(net_stats.tx_aborted_errors)}, @@ -118,6 +120,13 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { IXGBE_PB_STATS_LEN + \ IXGBE_QUEUE_STATS_LEN) +static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = { + "Register test (offline)", "Eeprom test (offline)", + "Interrupt test (offline)", "Loopback test (offline)", + "Link test (on/offline)" +}; +#define IXGBE_TEST_LEN sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN + static int ixgbe_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { @@ -129,11 +138,12 @@ static int ixgbe_get_settings(struct net_device *netdev, ecmd->supported = SUPPORTED_10000baseT_Full; ecmd->autoneg = AUTONEG_ENABLE; ecmd->transceiver = XCVR_EXTERNAL; - if (hw->phy.media_type == ixgbe_media_type_copper) { + if ((hw->phy.media_type == ixgbe_media_type_copper) || + (hw->mac.type == ixgbe_mac_82599EB)) { ecmd->supported |= (SUPPORTED_1000baseT_Full | - SUPPORTED_TP | SUPPORTED_Autoneg); + SUPPORTED_Autoneg); - ecmd->advertising = (ADVERTISED_TP | ADVERTISED_Autoneg); + ecmd->advertising = ADVERTISED_Autoneg; if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) ecmd->advertising |= ADVERTISED_10000baseT_Full; if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) @@ -148,7 +158,15 @@ static int ixgbe_get_settings(struct net_device *netdev, ecmd->advertising |= (ADVERTISED_10000baseT_Full | ADVERTISED_1000baseT_Full); - ecmd->port = PORT_TP; + if (hw->phy.media_type == ixgbe_media_type_copper) { + ecmd->supported |= SUPPORTED_TP; + ecmd->advertising |= ADVERTISED_TP; + ecmd->port = PORT_TP; + } else { + ecmd->supported |= SUPPORTED_FIBRE; + ecmd->advertising |= ADVERTISED_FIBRE; + ecmd->port = PORT_FIBRE; + } } else if (hw->phy.media_type == ixgbe_media_type_backplane) { /* Set as FIBRE until SERDES defined in kernel */ switch (hw->device_id) { @@ -196,16 +214,10 @@ static int ixgbe_set_settings(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; u32 advertised, old; - s32 err; + s32 err = 0; - switch (hw->phy.media_type) { - case ixgbe_media_type_fiber: - if ((ecmd->autoneg == AUTONEG_ENABLE) || - (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) - return -EINVAL; - /* in this case we currently only support 10Gb/FULL */ - break; - case ixgbe_media_type_copper: + if ((hw->phy.media_type == ixgbe_media_type_copper) || + (hw->mac.type == ixgbe_mac_82599EB)) { /* 10000/copper and 1000/copper must autoneg * this function does not support any duplex forcing, but can * limit the advertising of the adapter to only 10000 or 1000 */ @@ -221,20 +233,23 @@ static int ixgbe_set_settings(struct net_device *netdev, advertised |= IXGBE_LINK_SPEED_1GB_FULL; if (old == advertised) - break; + return err; /* this sets the link speed and restarts auto-neg */ + hw->mac.autotry_restart = true; err = hw->mac.ops.setup_link_speed(hw, advertised, true, true); if (err) { DPRINTK(PROBE, INFO, "setup link failed with code %d\n", err); hw->mac.ops.setup_link_speed(hw, old, true, true); } - break; - default: - break; + } else { + /* in this case we currently only support 10Gb/FULL */ + if ((ecmd->autoneg == AUTONEG_ENABLE) || + (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) + return -EINVAL; } - return 0; + return err; } static void ixgbe_get_pauseparam(struct net_device *netdev, @@ -276,6 +291,7 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_fc_info fc; #ifdef CONFIG_DCB if (adapter->dcb_cfg.pfc_mode_enable || @@ -284,26 +300,37 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, return -EINVAL; #endif + + fc = hw->fc; + if (pause->autoneg != AUTONEG_ENABLE) - hw->fc.disable_fc_autoneg = true; + fc.disable_fc_autoneg = true; else - hw->fc.disable_fc_autoneg = false; + fc.disable_fc_autoneg = false; if (pause->rx_pause && pause->tx_pause) - hw->fc.requested_mode = ixgbe_fc_full; + fc.requested_mode = ixgbe_fc_full; else if (pause->rx_pause && !pause->tx_pause) - hw->fc.requested_mode = ixgbe_fc_rx_pause; + fc.requested_mode = ixgbe_fc_rx_pause; else if (!pause->rx_pause && pause->tx_pause) - hw->fc.requested_mode = ixgbe_fc_tx_pause; + fc.requested_mode = ixgbe_fc_tx_pause; else if (!pause->rx_pause && !pause->tx_pause) - hw->fc.requested_mode = ixgbe_fc_none; + fc.requested_mode = ixgbe_fc_none; else return -EINVAL; #ifdef CONFIG_DCB - adapter->last_lfc_mode = hw->fc.requested_mode; + adapter->last_lfc_mode = fc.requested_mode; #endif - hw->mac.ops.setup_fc(hw, 0); + + /* if the thing changed then we'll update and use new autoneg */ + if (memcmp(&fc, &hw->fc, sizeof(struct ixgbe_fc_info))) { + hw->fc = fc; + if (netif_running(netdev)) + ixgbe_reinit_locked(adapter); + else + ixgbe_reset(adapter); + } return 0; } @@ -743,6 +770,7 @@ static void ixgbe_get_drvinfo(struct net_device *netdev, strncpy(drvinfo->fw_version, firmware_version, 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); drvinfo->n_stats = IXGBE_STATS_LEN; + drvinfo->testinfo_len = IXGBE_TEST_LEN; drvinfo->regdump_len = ixgbe_get_regs_len(netdev); } @@ -814,7 +842,6 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } goto err_setup; } - temp_tx_ring[i].v_idx = adapter->tx_ring[i].v_idx; } need_update = true; } @@ -844,7 +871,6 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } goto err_setup; } - temp_rx_ring[i].v_idx = adapter->rx_ring[i].v_idx; } need_update = true; } @@ -884,6 +910,8 @@ err_setup: static int ixgbe_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { + case ETH_SS_TEST: + return IXGBE_TEST_LEN; case ETH_SS_STATS: return IXGBE_STATS_LEN; default: @@ -938,6 +966,10 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, int i; switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *ixgbe_gstrings_test, + IXGBE_TEST_LEN * ETH_GSTRING_LEN); + break; case ETH_SS_STATS: for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { memcpy(p, ixgbe_gstrings_stats[i].stat_string, @@ -975,6 +1007,815 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, } } +static int ixgbe_link_test(struct ixgbe_adapter *adapter, u64 *data) +{ + struct ixgbe_hw *hw = &adapter->hw; + bool link_up; + u32 link_speed = 0; + *data = 0; + + hw->mac.ops.check_link(hw, &link_speed, &link_up, true); + if (link_up) + return *data; + else + *data = 1; + return *data; +} + +/* ethtool register test data */ +struct ixgbe_reg_test { + u16 reg; + u8 array_len; + u8 test_type; + u32 mask; + u32 write; +}; + +/* In the hardware, registers are laid out either singly, in arrays + * spaced 0x40 bytes apart, or in contiguous tables. We assume + * most tests take place on arrays or single registers (handled + * as a single-element array) and special-case the tables. + * Table tests are always pattern tests. + * + * We also make provision for some required setup steps by specifying + * registers to be written without any read-back testing. + */ + +#define PATTERN_TEST 1 +#define SET_READ_TEST 2 +#define WRITE_NO_TEST 3 +#define TABLE32_TEST 4 +#define TABLE64_TEST_LO 5 +#define TABLE64_TEST_HI 6 + +/* default 82599 register test */ +static struct ixgbe_reg_test reg_test_82599[] = { + { IXGBE_FCRTL_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_FCRTH_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_VLNCTRL, 1, PATTERN_TEST, 0x00000000, 0x00000000 }, + { IXGBE_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 }, + { IXGBE_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE }, + { IXGBE_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 }, + { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_FCTTV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { IXGBE_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFF80 }, + { IXGBE_RXCTRL, 1, SET_READ_TEST, 0x00000001, 0x00000001 }, + { IXGBE_RAL(0), 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_RAL(0), 16, TABLE64_TEST_HI, 0x8001FFFF, 0x800CFFFF }, + { IXGBE_MTA(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0, 0, 0, 0 } +}; + +/* default 82598 register test */ +static struct ixgbe_reg_test reg_test_82598[] = { + { IXGBE_FCRTL(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_VLNCTRL, 1, PATTERN_TEST, 0x00000000, 0x00000000 }, + { IXGBE_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { IXGBE_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + /* Enable all four RX queues before testing. */ + { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE }, + /* RDH is read-only for 82598, only test RDT. */ + { IXGBE_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 }, + { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 }, + { IXGBE_FCTTV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_TIPG, 1, PATTERN_TEST, 0x000000FF, 0x000000FF }, + { IXGBE_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { IXGBE_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + { IXGBE_RXCTRL, 1, SET_READ_TEST, 0x00000003, 0x00000003 }, + { IXGBE_DTXCTL, 1, SET_READ_TEST, 0x00000005, 0x00000005 }, + { IXGBE_RAL(0), 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, + { IXGBE_RAL(0), 16, TABLE64_TEST_HI, 0x800CFFFF, 0x800CFFFF }, + { IXGBE_MTA(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0, 0, 0, 0 } +}; + +#define REG_PATTERN_TEST(R, M, W) \ +{ \ + u32 pat, val, before; \ + const u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ + for (pat = 0; pat < ARRAY_SIZE(_test); pat++) { \ + before = readl(adapter->hw.hw_addr + R); \ + writel((_test[pat] & W), (adapter->hw.hw_addr + R)); \ + val = readl(adapter->hw.hw_addr + R); \ + if (val != (_test[pat] & W & M)) { \ + DPRINTK(DRV, ERR, "pattern test reg %04X failed: got "\ + "0x%08X expected 0x%08X\n", \ + R, val, (_test[pat] & W & M)); \ + *data = R; \ + writel(before, adapter->hw.hw_addr + R); \ + return 1; \ + } \ + writel(before, adapter->hw.hw_addr + R); \ + } \ +} + +#define REG_SET_AND_CHECK(R, M, W) \ +{ \ + u32 val, before; \ + before = readl(adapter->hw.hw_addr + R); \ + writel((W & M), (adapter->hw.hw_addr + R)); \ + val = readl(adapter->hw.hw_addr + R); \ + if ((W & M) != (val & M)) { \ + DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\ + "expected 0x%08X\n", R, (val & M), (W & M)); \ + *data = R; \ + writel(before, (adapter->hw.hw_addr + R)); \ + return 1; \ + } \ + writel(before, (adapter->hw.hw_addr + R)); \ +} + +static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) +{ + struct ixgbe_reg_test *test; + u32 value, before, after; + u32 i, toggle; + + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + toggle = 0x7FFFF30F; + test = reg_test_82599; + } else { + toggle = 0x7FFFF3FF; + test = reg_test_82598; + } + + /* + * Because the status register is such a special case, + * we handle it separately from the rest of the register + * tests. Some bits are read-only, some toggle, and some + * are writeable on newer MACs. + */ + before = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS); + value = (IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, toggle); + after = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle; + if (value != after) { + DPRINTK(DRV, ERR, "failed STATUS register test got: " + "0x%08X expected: 0x%08X\n", after, value); + *data = 1; + return 1; + } + /* restore previous status */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, before); + + /* + * Perform the remainder of the register test, looping through + * the test table until we either fail or reach the null entry. + */ + while (test->reg) { + for (i = 0; i < test->array_len; i++) { + switch (test->test_type) { + case PATTERN_TEST: + REG_PATTERN_TEST(test->reg + (i * 0x40), + test->mask, + test->write); + break; + case SET_READ_TEST: + REG_SET_AND_CHECK(test->reg + (i * 0x40), + test->mask, + test->write); + break; + case WRITE_NO_TEST: + writel(test->write, + (adapter->hw.hw_addr + test->reg) + + (i * 0x40)); + break; + case TABLE32_TEST: + REG_PATTERN_TEST(test->reg + (i * 4), + test->mask, + test->write); + break; + case TABLE64_TEST_LO: + REG_PATTERN_TEST(test->reg + (i * 8), + test->mask, + test->write); + break; + case TABLE64_TEST_HI: + REG_PATTERN_TEST((test->reg + 4) + (i * 8), + test->mask, + test->write); + break; + } + } + test++; + } + + *data = 0; + return 0; +} + +static int ixgbe_eeprom_test(struct ixgbe_adapter *adapter, u64 *data) +{ + struct ixgbe_hw *hw = &adapter->hw; + if (hw->eeprom.ops.validate_checksum(hw, NULL)) + *data = 1; + else + *data = 0; + return *data; +} + +static irqreturn_t ixgbe_test_intr(int irq, void *data) +{ + struct net_device *netdev = (struct net_device *) data; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->test_icr |= IXGBE_READ_REG(&adapter->hw, IXGBE_EICR); + + return IRQ_HANDLED; +} + +static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) +{ + struct net_device *netdev = adapter->netdev; + u32 mask, i = 0, shared_int = true; + u32 irq = adapter->pdev->irq; + + *data = 0; + + /* Hook up test interrupt handler just for this test */ + if (adapter->msix_entries) { + /* NOTE: we don't test MSI-X interrupts here, yet */ + return 0; + } else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { + shared_int = false; + if (request_irq(irq, &ixgbe_test_intr, 0, netdev->name, + netdev)) { + *data = 1; + return -1; + } + } else if (!request_irq(irq, &ixgbe_test_intr, IRQF_PROBE_SHARED, + netdev->name, netdev)) { + shared_int = false; + } else if (request_irq(irq, &ixgbe_test_intr, IRQF_SHARED, + netdev->name, netdev)) { + *data = 1; + return -1; + } + DPRINTK(HW, INFO, "testing %s interrupt\n", + (shared_int ? "shared" : "unshared")); + + /* Disable all the interrupts */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); + msleep(10); + + /* Test each interrupt */ + for (; i < 10; i++) { + /* Interrupt to test */ + mask = 1 << i; + + if (!shared_int) { + /* + * Disable the interrupts to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, + ~mask & 0x00007FFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, + ~mask & 0x00007FFF); + msleep(10); + + if (adapter->test_icr & mask) { + *data = 3; + break; + } + } + + /* + * Enable the interrupt to be reported in the cause + * register and then force the same interrupt and see + * if one gets posted. If an interrupt was not posted + * to the bus, the test failed. + */ + adapter->test_icr = 0; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); + msleep(10); + + if (!(adapter->test_icr &mask)) { + *data = 4; + break; + } + + if (!shared_int) { + /* + * Disable the other interrupts to be reported in + * the cause register and then force the other + * interrupts and see if any get posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, + ~mask & 0x00007FFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, + ~mask & 0x00007FFF); + msleep(10); + + if (adapter->test_icr) { + *data = 5; + break; + } + } + } + + /* Disable all the interrupts */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); + msleep(10); + + /* Unhook test interrupt handler */ + free_irq(irq, netdev); + + return *data; +} + +static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter) +{ + struct ixgbe_ring *tx_ring = &adapter->test_tx_ring; + struct ixgbe_ring *rx_ring = &adapter->test_rx_ring; + struct ixgbe_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + u32 reg_ctl; + int i; + + /* shut down the DMA engines now so they can be reinitialized later */ + + /* first Rx */ + reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + reg_ctl &= ~IXGBE_RXCTRL_RXEN; + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_ctl); + reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(0)); + reg_ctl &= ~IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(0), reg_ctl); + + /* now Tx */ + reg_ctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(0)); + reg_ctl &= ~IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(0), reg_ctl); + if (hw->mac.type == ixgbe_mac_82599EB) { + reg_ctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); + reg_ctl &= ~IXGBE_DMATXCTL_TE; + IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_ctl); + } + + ixgbe_reset(adapter); + + if (tx_ring->desc && tx_ring->tx_buffer_info) { + for (i = 0; i < tx_ring->count; i++) { + struct ixgbe_tx_buffer *buf = + &(tx_ring->tx_buffer_info[i]); + if (buf->dma) + pci_unmap_single(pdev, buf->dma, buf->length, + PCI_DMA_TODEVICE); + if (buf->skb) + dev_kfree_skb(buf->skb); + } + } + + if (rx_ring->desc && rx_ring->rx_buffer_info) { + for (i = 0; i < rx_ring->count; i++) { + struct ixgbe_rx_buffer *buf = + &(rx_ring->rx_buffer_info[i]); + if (buf->dma) + pci_unmap_single(pdev, buf->dma, + IXGBE_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + if (buf->skb) + dev_kfree_skb(buf->skb); + } + } + + if (tx_ring->desc) { + pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, + tx_ring->dma); + tx_ring->desc = NULL; + } + if (rx_ring->desc) { + pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, + rx_ring->dma); + rx_ring->desc = NULL; + } + + kfree(tx_ring->tx_buffer_info); + tx_ring->tx_buffer_info = NULL; + kfree(rx_ring->rx_buffer_info); + rx_ring->rx_buffer_info = NULL; + + return; +} + +static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter) +{ + struct ixgbe_ring *tx_ring = &adapter->test_tx_ring; + struct ixgbe_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + u32 rctl, reg_data; + int i, ret_val; + + /* Setup Tx descriptor ring and Tx buffers */ + + if (!tx_ring->count) + tx_ring->count = IXGBE_DEFAULT_TXD; + + tx_ring->tx_buffer_info = kcalloc(tx_ring->count, + sizeof(struct ixgbe_tx_buffer), + GFP_KERNEL); + if (!(tx_ring->tx_buffer_info)) { + ret_val = 1; + goto err_nomem; + } + + tx_ring->size = tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc); + tx_ring->size = ALIGN(tx_ring->size, 4096); + if (!(tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, + &tx_ring->dma))) { + ret_val = 2; + goto err_nomem; + } + tx_ring->next_to_use = tx_ring->next_to_clean = 0; + + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAL(0), + ((u64) tx_ring->dma & 0x00000000FFFFFFFF)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0), + ((u64) tx_ring->dma >> 32)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0), + tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); + reg_data |= IXGBE_HLREG0_TXPADEN; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); + + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL); + reg_data |= IXGBE_DMATXCTL_TE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data); + } + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_TXDCTL(0)); + reg_data |= IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data); + + for (i = 0; i < tx_ring->count; i++) { + struct ixgbe_legacy_tx_desc *desc = IXGBE_TX_DESC(*tx_ring, i); + struct sk_buff *skb; + unsigned int size = 1024; + + skb = alloc_skb(size, GFP_KERNEL); + if (!skb) { + ret_val = 3; + goto err_nomem; + } + skb_put(skb, size); + tx_ring->tx_buffer_info[i].skb = skb; + tx_ring->tx_buffer_info[i].length = skb->len; + tx_ring->tx_buffer_info[i].dma = + pci_map_single(pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + desc->buffer_addr = cpu_to_le64(tx_ring->tx_buffer_info[i].dma); + desc->lower.data = cpu_to_le32(skb->len); + desc->lower.data |= cpu_to_le32(IXGBE_TXD_CMD_EOP | + IXGBE_TXD_CMD_IFCS | + IXGBE_TXD_CMD_RS); + desc->upper.data = 0; + } + + /* Setup Rx Descriptor ring and Rx buffers */ + + if (!rx_ring->count) + rx_ring->count = IXGBE_DEFAULT_RXD; + + rx_ring->rx_buffer_info = kcalloc(rx_ring->count, + sizeof(struct ixgbe_rx_buffer), + GFP_KERNEL); + if (!(rx_ring->rx_buffer_info)) { + ret_val = 4; + goto err_nomem; + } + + rx_ring->size = rx_ring->count * sizeof(struct ixgbe_legacy_rx_desc); + rx_ring->size = ALIGN(rx_ring->size, 4096); + if (!(rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size, + &rx_ring->dma))) { + ret_val = 5; + goto err_nomem; + } + rx_ring->next_to_use = rx_ring->next_to_clean = 0; + + rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl & ~IXGBE_RXCTRL_RXEN); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAL(0), + ((u64)rx_ring->dma & 0xFFFFFFFF)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAH(0), + ((u64) rx_ring->dma >> 32)); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDLEN(0), rx_ring->size); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDH(0), 0); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(0), 0); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); + reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); + reg_data &= ~IXGBE_HLREG0_LPBK; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_RDRXCTL); +#define IXGBE_RDRXCTL_RDMTS_MASK 0x00000003 /* Receive Descriptor Minimum + Threshold Size mask */ + reg_data &= ~IXGBE_RDRXCTL_RDMTS_MASK; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDRXCTL, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_MCSTCTRL); +#define IXGBE_MCSTCTRL_MO_MASK 0x00000003 /* Multicast Offset mask */ + reg_data &= ~IXGBE_MCSTCTRL_MO_MASK; + reg_data |= adapter->hw.mac.mc_filter_type; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_MCSTCTRL, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(0)); + reg_data |= IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(0), reg_data); + if (adapter->hw.mac.type == ixgbe_mac_82599EB) { + int j = adapter->rx_ring[0].reg_idx; + u32 k; + for (k = 0; k < 10; k++) { + if (IXGBE_READ_REG(&adapter->hw, + IXGBE_RXDCTL(j)) & IXGBE_RXDCTL_ENABLE) + break; + else + msleep(1); + } + } + + rctl |= IXGBE_RXCTRL_RXEN | IXGBE_RXCTRL_DMBYPS; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl); + + for (i = 0; i < rx_ring->count; i++) { + struct ixgbe_legacy_rx_desc *rx_desc = + IXGBE_RX_DESC(*rx_ring, i); + struct sk_buff *skb; + + skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL); + if (!skb) { + ret_val = 6; + goto err_nomem; + } + skb_reserve(skb, NET_IP_ALIGN); + rx_ring->rx_buffer_info[i].skb = skb; + rx_ring->rx_buffer_info[i].dma = + pci_map_single(pdev, skb->data, IXGBE_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + rx_desc->buffer_addr = + cpu_to_le64(rx_ring->rx_buffer_info[i].dma); + memset(skb->data, 0x00, skb->len); + } + + return 0; + +err_nomem: + ixgbe_free_desc_rings(adapter); + return ret_val; +} + +static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 reg_data; + + /* right now we only support MAC loopback in the driver */ + + /* Setup MAC loopback */ + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); + reg_data |= IXGBE_HLREG0_LPBK; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_AUTOC); + reg_data &= ~IXGBE_AUTOC_LMS_MASK; + reg_data |= IXGBE_AUTOC_LMS_10G_LINK_NO_AN | IXGBE_AUTOC_FLU; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_AUTOC, reg_data); + + /* Disable Atlas Tx lanes; re-enabled in reset path */ + if (hw->mac.type == ixgbe_mac_82598EB) { + u8 atlas; + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &atlas); + atlas |= IXGBE_ATLAS_PDN_TX_REG_EN; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, atlas); + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &atlas); + atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, atlas); + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &atlas); + atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, atlas); + + hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &atlas); + atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL; + hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, atlas); + } + + return 0; +} + +static void ixgbe_loopback_cleanup(struct ixgbe_adapter *adapter) +{ + u32 reg_data; + + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); + reg_data &= ~IXGBE_HLREG0_LPBK; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data); +} + +static void ixgbe_create_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + memset(skb->data, 0xFF, frame_size); + frame_size &= ~1; + memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1); + memset(&skb->data[frame_size / 2 + 10], 0xBE, 1); + memset(&skb->data[frame_size / 2 + 12], 0xAF, 1); +} + +static int ixgbe_check_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + frame_size &= ~1; + if (*(skb->data + 3) == 0xFF) { + if ((*(skb->data + frame_size / 2 + 10) == 0xBE) && + (*(skb->data + frame_size / 2 + 12) == 0xAF)) { + return 0; + } + } + return 13; +} + +static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter) +{ + struct ixgbe_ring *tx_ring = &adapter->test_tx_ring; + struct ixgbe_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + int i, j, k, l, lc, good_cnt, ret_val = 0; + unsigned long time; + + IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(0), rx_ring->count - 1); + + /* + * Calculate the loop count based on the largest descriptor ring + * The idea is to wrap the largest ring a number of times using 64 + * send/receive pairs during each loop + */ + + if (rx_ring->count <= tx_ring->count) + lc = ((tx_ring->count / 64) * 2) + 1; + else + lc = ((rx_ring->count / 64) * 2) + 1; + + k = l = 0; + for (j = 0; j <= lc; j++) { + for (i = 0; i < 64; i++) { + ixgbe_create_lbtest_frame( + tx_ring->tx_buffer_info[k].skb, + 1024); + pci_dma_sync_single_for_device(pdev, + tx_ring->tx_buffer_info[k].dma, + tx_ring->tx_buffer_info[k].length, + PCI_DMA_TODEVICE); + if (unlikely(++k == tx_ring->count)) + k = 0; + } + IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), k); + msleep(200); + /* set the start time for the receive */ + time = jiffies; + good_cnt = 0; + do { + /* receive the sent packets */ + pci_dma_sync_single_for_cpu(pdev, + rx_ring->rx_buffer_info[l].dma, + IXGBE_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + ret_val = ixgbe_check_lbtest_frame( + rx_ring->rx_buffer_info[l].skb, 1024); + if (!ret_val) + good_cnt++; + if (++l == rx_ring->count) + l = 0; + /* + * time + 20 msecs (200 msecs on 2.4) is more than + * enough time to complete the receives, if it's + * exceeded, break and error off + */ + } while (good_cnt < 64 && jiffies < (time + 20)); + if (good_cnt != 64) { + /* ret_val is the same as mis-compare */ + ret_val = 13; + break; + } + if (jiffies >= (time + 20)) { + /* Error code for time out error */ + ret_val = 14; + break; + } + } + + return ret_val; +} + +static int ixgbe_loopback_test(struct ixgbe_adapter *adapter, u64 *data) +{ + *data = ixgbe_setup_desc_rings(adapter); + if (*data) + goto out; + *data = ixgbe_setup_loopback_test(adapter); + if (*data) + goto err_loopback; + *data = ixgbe_run_loopback_test(adapter); + ixgbe_loopback_cleanup(adapter); + +err_loopback: + ixgbe_free_desc_rings(adapter); +out: + return *data; +} + +static void ixgbe_diag_test(struct net_device *netdev, + struct ethtool_test *eth_test, u64 *data) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + bool if_running = netif_running(netdev); + + set_bit(__IXGBE_TESTING, &adapter->state); + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { + /* Offline tests */ + + DPRINTK(HW, INFO, "offline testing starting\n"); + + /* Link test performed before hardware reset so autoneg doesn't + * interfere with test result */ + if (ixgbe_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + if (if_running) + /* indicate we're in test mode */ + dev_close(netdev); + else + ixgbe_reset(adapter); + + DPRINTK(HW, INFO, "register testing starting\n"); + if (ixgbe_reg_test(adapter, &data[0])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbe_reset(adapter); + DPRINTK(HW, INFO, "eeprom testing starting\n"); + if (ixgbe_eeprom_test(adapter, &data[1])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbe_reset(adapter); + DPRINTK(HW, INFO, "interrupt testing starting\n"); + if (ixgbe_intr_test(adapter, &data[2])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbe_reset(adapter); + DPRINTK(HW, INFO, "loopback testing starting\n"); + if (ixgbe_loopback_test(adapter, &data[3])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + ixgbe_reset(adapter); + + clear_bit(__IXGBE_TESTING, &adapter->state); + if (if_running) + dev_open(netdev); + } else { + DPRINTK(HW, INFO, "online testing starting\n"); + /* Online tests */ + if (ixgbe_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* Online tests aren't run; pass by default */ + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + + clear_bit(__IXGBE_TESTING, &adapter->state); + } + msleep_interruptible(4 * 1000); +} static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter, struct ethtool_wolinfo *wol) @@ -1146,8 +1987,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev, else /* rx only or mixed */ q_vector->eitr = adapter->eitr_param; - ixgbe_write_eitr(adapter, i, - EITR_INTS_PER_SEC_TO_REG(q_vector->eitr)); + ixgbe_write_eitr(q_vector); } return 0; @@ -1159,13 +1999,13 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data) ethtool_op_set_flags(netdev, data); - if (!(adapter->flags & IXGBE_FLAG_RSC_CAPABLE)) + if (!(adapter->flags & IXGBE_FLAG2_RSC_CAPABLE)) return 0; /* if state changes we need to update adapter->flags and reset */ if ((!!(data & ETH_FLAG_LRO)) != - (!!(adapter->flags & IXGBE_FLAG_RSC_ENABLED))) { - adapter->flags ^= IXGBE_FLAG_RSC_ENABLED; + (!!(adapter->flags & IXGBE_FLAG2_RSC_ENABLED))) { + adapter->flags ^= IXGBE_FLAG2_RSC_ENABLED; if (netif_running(netdev)) ixgbe_reinit_locked(adapter); else @@ -1201,6 +2041,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = { .set_msglevel = ixgbe_set_msglevel, .get_tso = ethtool_op_get_tso, .set_tso = ixgbe_set_tso, + .self_test = ixgbe_diag_test, .get_strings = ixgbe_get_strings, .phys_id = ixgbe_phys_id, .get_sset_count = ixgbe_get_sset_count, diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index d5939de8ba28..3c3bf1f07b81 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -280,7 +280,9 @@ out_noddp_unmap: * * This checks ddp status. * - * Returns : 0 for success and skb will not be delivered to ULD + * Returns : < 0 indicates an error or not a FCiE ddp, 0 indicates + * not passing the skb to ULD, > 0 indicates is the length of data + * being ddped. */ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, union ixgbe_adv_rx_desc *rx_desc, @@ -334,6 +336,8 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, /* return 0 to bypass going to ULD for DDPed data */ if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_DDP) rc = 0; + else + rc = ddp->len; } ddp_out: diff --git a/drivers/net/ixgbe/ixgbe_fcoe.h b/drivers/net/ixgbe/ixgbe_fcoe.h index b7f9b63aa49f..c5b50026a897 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.h +++ b/drivers/net/ixgbe/ixgbe_fcoe.h @@ -28,6 +28,7 @@ #ifndef _IXGBE_FCOE_H #define _IXGBE_FCOE_H +#include <scsi/fc/fc_fs.h> #include <scsi/fc/fc_fcoe.h> /* shift bits within STAT fo FCSTAT */ diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index dff1da8ae5c4..a551a96ce676 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -48,7 +48,7 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; -#define DRV_VERSION "2.0.24-k2" +#define DRV_VERSION "2.0.34-k2" const char ixgbe_driver_version[] = DRV_VERSION; static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation."; @@ -186,6 +186,22 @@ static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction, } } +static inline void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter, + u64 qmask) +{ + u32 mask; + + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & qmask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); + } else { + mask = (qmask & 0xFFFFFFFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); + mask = (qmask >> 32); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); + } +} + static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter, struct ixgbe_tx_buffer *tx_buffer_info) @@ -248,14 +264,13 @@ static void ixgbe_tx_timeout(struct net_device *netdev); /** * ixgbe_clean_tx_irq - Reclaim resources after transmit completes - * @adapter: board private structure + * @q_vector: structure containing interrupt and ring information * @tx_ring: tx ring to clean - * - * returns true if transmit work is done **/ -static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, +static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, struct ixgbe_ring *tx_ring) { + struct ixgbe_adapter *adapter = q_vector->adapter; struct net_device *netdev = adapter->netdev; union ixgbe_adv_tx_desc *tx_desc, *eop_desc; struct ixgbe_tx_buffer *tx_buffer_info; @@ -278,12 +293,24 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, if (cleaned && skb) { unsigned int segs, bytecount; + unsigned int hlen = skb_headlen(skb); /* gso_segs is currently only valid for tcp */ segs = skb_shinfo(skb)->gso_segs ?: 1; +#ifdef IXGBE_FCOE + /* adjust for FCoE Sequence Offload */ + if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) + && (skb->protocol == htons(ETH_P_FCOE)) && + skb_is_gso(skb)) { + hlen = skb_transport_offset(skb) + + sizeof(struct fc_frame_header) + + sizeof(struct fcoe_crc_eof); + segs = DIV_ROUND_UP(skb->len - hlen, + skb_shinfo(skb)->gso_size); + } +#endif /* IXGBE_FCOE */ /* multiply data chunks by size of headers */ - bytecount = ((segs - 1) * skb_headlen(skb)) + - skb->len; + bytecount = ((segs - 1) * hlen) + skb->len; total_packets += segs; total_bytes += bytecount; } @@ -329,18 +356,8 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, } /* re-arm the interrupt */ - if (count >= tx_ring->work_limit) { - if (adapter->hw.mac.type == ixgbe_mac_82598EB) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, - tx_ring->v_idx); - else if (tx_ring->v_idx & 0xFFFFFFFF) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), - tx_ring->v_idx); - else - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), - (tx_ring->v_idx >> 32)); - } - + if (count >= tx_ring->work_limit) + ixgbe_irq_rearm_queues(adapter, ((u64)1 << q_vector->v_idx)); tx_ring->total_bytes += total_bytes; tx_ring->total_packets += total_packets; @@ -678,6 +695,9 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, bool cleaned = false; int cleaned_count = 0; unsigned int total_rx_bytes = 0, total_rx_packets = 0; +#ifdef IXGBE_FCOE + int ddp_bytes = 0; +#endif /* IXGBE_FCOE */ i = rx_ring->next_to_clean; rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); @@ -708,7 +728,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, prefetch(skb->data - NET_IP_ALIGN); rx_buffer_info->skb = NULL; - if (len && !skb_shinfo(skb)->nr_frags) { + if (rx_buffer_info->dma) { pci_unmap_single(pdev, rx_buffer_info->dma, rx_ring->rx_buf_len, PCI_DMA_FROMDEVICE); @@ -743,7 +763,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, prefetch(next_rxd); cleaned_count++; - if (adapter->flags & IXGBE_FLAG_RSC_CAPABLE) + if (adapter->flags & IXGBE_FLAG2_RSC_CAPABLE) rsc_count = ixgbe_get_rsc_count(rx_desc); if (rsc_count) { @@ -788,9 +808,11 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, skb->protocol = eth_type_trans(skb, adapter->netdev); #ifdef IXGBE_FCOE /* if ddp, not passing to ULD unless for FCP_RSP or error */ - if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) - if (!ixgbe_fcoe_ddp(adapter, rx_desc, skb)) + if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { + ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb); + if (!ddp_bytes) goto next_desc; + } #endif /* IXGBE_FCOE */ ixgbe_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc); @@ -816,6 +838,21 @@ next_desc: if (cleaned_count) ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count); +#ifdef IXGBE_FCOE + /* include DDPed FCoE data */ + if (ddp_bytes > 0) { + unsigned int mss; + + mss = adapter->netdev->mtu - sizeof(struct fcoe_hdr) - + sizeof(struct fc_frame_header) - + sizeof(struct fcoe_crc_eof); + if (mss > 512) + mss &= ~511; + total_rx_bytes += ddp_bytes; + total_rx_packets += DIV_ROUND_UP(ddp_bytes, mss); + } +#endif /* IXGBE_FCOE */ + rx_ring->total_packets += total_rx_packets; rx_ring->total_bytes += total_rx_bytes; adapter->net_stats.rx_bytes += total_rx_bytes; @@ -875,12 +912,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter) /* rx only */ q_vector->eitr = adapter->eitr_param; - /* - * since this is initial set up don't need to call - * ixgbe_write_eitr helper - */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), - EITR_INTS_PER_SEC_TO_REG(q_vector->eitr)); + ixgbe_write_eitr(q_vector); } if (adapter->hw.mac.type == ixgbe_mac_82598EB) @@ -965,17 +997,19 @@ update_itr_done: /** * ixgbe_write_eitr - write EITR register in hardware specific way - * @adapter: pointer to adapter struct - * @v_idx: vector index into q_vector array - * @itr_reg: new value to be written in *register* format, not ints/s + * @q_vector: structure containing interrupt and ring information * * This function is made to be called by ethtool and by the driver * when it needs to update EITR registers at runtime. Hardware * specific quirks/differences are taken care of here. */ -void ixgbe_write_eitr(struct ixgbe_adapter *adapter, int v_idx, u32 itr_reg) +void ixgbe_write_eitr(struct ixgbe_q_vector *q_vector) { + struct ixgbe_adapter *adapter = q_vector->adapter; struct ixgbe_hw *hw = &adapter->hw; + int v_idx = q_vector->v_idx; + u32 itr_reg = EITR_INTS_PER_SEC_TO_REG(q_vector->eitr); + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { /* must write high and low 16 bits to reset counter */ itr_reg |= (itr_reg << 16); @@ -994,7 +1028,7 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) struct ixgbe_adapter *adapter = q_vector->adapter; u32 new_itr; u8 current_itr, ret_itr; - int i, r_idx, v_idx = q_vector->v_idx; + int i, r_idx; struct ixgbe_ring *rx_ring, *tx_ring; r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); @@ -1044,14 +1078,13 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) } if (new_itr != q_vector->eitr) { - u32 itr_reg; + /* do an exponential smoothing */ + new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); /* save the algorithm value here, not the smoothed one */ q_vector->eitr = new_itr; - /* do an exponential smoothing */ - new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); - itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr); - ixgbe_write_eitr(adapter, v_idx, itr_reg); + + ixgbe_write_eitr(q_vector); } return; @@ -1122,14 +1155,64 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) if (hw->mac.type == ixgbe_mac_82598EB) ixgbe_check_fan_failure(adapter, eicr); - if (hw->mac.type == ixgbe_mac_82599EB) + if (hw->mac.type == ixgbe_mac_82599EB) { ixgbe_check_sfp_event(adapter, eicr); + + /* Handle Flow Director Full threshold interrupt */ + if (eicr & IXGBE_EICR_FLOW_DIR) { + int i; + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_FLOW_DIR); + /* Disable transmits before FDIR Re-initialization */ + netif_tx_stop_all_queues(netdev); + for (i = 0; i < adapter->num_tx_queues; i++) { + struct ixgbe_ring *tx_ring = + &adapter->tx_ring[i]; + if (test_and_clear_bit(__IXGBE_FDIR_INIT_DONE, + &tx_ring->reinit_state)) + schedule_work(&adapter->fdir_reinit_task); + } + } + } if (!test_bit(__IXGBE_DOWN, &adapter->state)) IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); return IRQ_HANDLED; } +static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter, + u64 qmask) +{ + u32 mask; + + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & qmask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); + } else { + mask = (qmask & 0xFFFFFFFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(0), mask); + mask = (qmask >> 32); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask); + } + /* skip the flush */ +} + +static inline void ixgbe_irq_disable_queues(struct ixgbe_adapter *adapter, + u64 qmask) +{ + u32 mask; + + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & qmask); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, mask); + } else { + mask = (qmask & 0xFFFFFFFF); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), mask); + mask = (qmask >> 32); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), mask); + } + /* skip the flush */ +} + static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data) { struct ixgbe_q_vector *q_vector = data; @@ -1143,17 +1226,16 @@ static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data) r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); for (i = 0; i < q_vector->txr_count; i++) { tx_ring = &(adapter->tx_ring[r_idx]); -#ifdef CONFIG_IXGBE_DCA - if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) - ixgbe_update_tx_dca(adapter, tx_ring); -#endif tx_ring->total_bytes = 0; tx_ring->total_packets = 0; - ixgbe_clean_tx_irq(adapter, tx_ring); r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, r_idx + 1); } + /* disable interrupts on this vector only */ + ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx)); + napi_schedule(&q_vector->napi); + return IRQ_HANDLED; } @@ -1185,13 +1267,7 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); rx_ring = &(adapter->rx_ring[r_idx]); /* disable interrupts on this vector only */ - if (adapter->hw.mac.type == ixgbe_mac_82598EB) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rx_ring->v_idx); - else if (rx_ring->v_idx & 0xFFFFFFFF) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), rx_ring->v_idx); - else - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), - (rx_ring->v_idx >> 32)); + ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx)); napi_schedule(&q_vector->napi); return IRQ_HANDLED; @@ -1199,27 +1275,38 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) static irqreturn_t ixgbe_msix_clean_many(int irq, void *data) { - ixgbe_msix_clean_rx(irq, data); - ixgbe_msix_clean_tx(irq, data); + struct ixgbe_q_vector *q_vector = data; + struct ixgbe_adapter *adapter = q_vector->adapter; + struct ixgbe_ring *ring; + int r_idx; + int i; - return IRQ_HANDLED; -} + if (!q_vector->txr_count && !q_vector->rxr_count) + return IRQ_HANDLED; -static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter, - u64 qmask) -{ - u32 mask; + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + for (i = 0; i < q_vector->txr_count; i++) { + ring = &(adapter->tx_ring[r_idx]); + ring->total_bytes = 0; + ring->total_packets = 0; + r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, + r_idx + 1); + } - if (adapter->hw.mac.type == ixgbe_mac_82598EB) { - mask = (IXGBE_EIMS_RTX_QUEUE & qmask); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); - } else { - mask = (qmask & 0xFFFFFFFF); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(0), mask); - mask = (qmask >> 32); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask); + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + for (i = 0; i < q_vector->rxr_count; i++) { + ring = &(adapter->rx_ring[r_idx]); + ring->total_bytes = 0; + ring->total_packets = 0; + r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, + r_idx + 1); } - /* skip the flush */ + + /* disable interrupts on this vector only */ + ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx)); + napi_schedule(&q_vector->napi); + + return IRQ_HANDLED; } /** @@ -1254,29 +1341,42 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget) if (adapter->itr_setting & 1) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) - ixgbe_irq_enable_queues(adapter, rx_ring->v_idx); + ixgbe_irq_enable_queues(adapter, + ((u64)1 << q_vector->v_idx)); } return work_done; } /** - * ixgbe_clean_rxonly_many - msix (aka one shot) rx clean routine + * ixgbe_clean_rxtx_many - msix (aka one shot) rx clean routine * @napi: napi struct with our devices info in it * @budget: amount of work driver is allowed to do this pass, in packets * * This function will clean more than one rx queue associated with a * q_vector. **/ -static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) +static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget) { struct ixgbe_q_vector *q_vector = container_of(napi, struct ixgbe_q_vector, napi); struct ixgbe_adapter *adapter = q_vector->adapter; - struct ixgbe_ring *rx_ring = NULL; + struct ixgbe_ring *ring = NULL; int work_done = 0, i; long r_idx; - u64 enable_mask = 0; + bool tx_clean_complete = true; + + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + for (i = 0; i < q_vector->txr_count; i++) { + ring = &(adapter->tx_ring[r_idx]); +#ifdef CONFIG_IXGBE_DCA + if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) + ixgbe_update_tx_dca(adapter, ring); +#endif + tx_clean_complete &= ixgbe_clean_tx_irq(q_vector, ring); + r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, + r_idx + 1); + } /* attempt to distribute budget to each queue fairly, but don't allow * the budget to go below 1 because we'll exit polling */ @@ -1284,31 +1384,71 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) budget = max(budget, 1); r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); for (i = 0; i < q_vector->rxr_count; i++) { - rx_ring = &(adapter->rx_ring[r_idx]); + ring = &(adapter->rx_ring[r_idx]); #ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) - ixgbe_update_rx_dca(adapter, rx_ring); + ixgbe_update_rx_dca(adapter, ring); #endif - ixgbe_clean_rx_irq(q_vector, rx_ring, &work_done, budget); - enable_mask |= rx_ring->v_idx; + ixgbe_clean_rx_irq(q_vector, ring, &work_done, budget); r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, r_idx + 1); } r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); - rx_ring = &(adapter->rx_ring[r_idx]); + ring = &(adapter->rx_ring[r_idx]); /* If all Rx work done, exit the polling mode */ if (work_done < budget) { napi_complete(napi); if (adapter->itr_setting & 1) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) - ixgbe_irq_enable_queues(adapter, enable_mask); + ixgbe_irq_enable_queues(adapter, + ((u64)1 << q_vector->v_idx)); return 0; } return work_done; } + +/** + * ixgbe_clean_txonly - msix (aka one shot) tx clean routine + * @napi: napi struct with our devices info in it + * @budget: amount of work driver is allowed to do this pass, in packets + * + * This function is optimized for cleaning one queue only on a single + * q_vector!!! + **/ +static int ixgbe_clean_txonly(struct napi_struct *napi, int budget) +{ + struct ixgbe_q_vector *q_vector = + container_of(napi, struct ixgbe_q_vector, napi); + struct ixgbe_adapter *adapter = q_vector->adapter; + struct ixgbe_ring *tx_ring = NULL; + int work_done = 0; + long r_idx; + + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + tx_ring = &(adapter->tx_ring[r_idx]); +#ifdef CONFIG_IXGBE_DCA + if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) + ixgbe_update_tx_dca(adapter, tx_ring); +#endif + + if (!ixgbe_clean_tx_irq(q_vector, tx_ring)) + work_done = budget; + + /* If all Rx work done, exit the polling mode */ + if (work_done < budget) { + napi_complete(napi); + if (adapter->itr_setting & 1) + ixgbe_set_itr_msix(q_vector); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + ixgbe_irq_enable_queues(adapter, ((u64)1 << q_vector->v_idx)); + } + + return work_done; +} + static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx, int r_idx) { @@ -1316,7 +1456,6 @@ static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx, set_bit(r_idx, q_vector->rxr_idx); q_vector->rxr_count++; - a->rx_ring[r_idx].v_idx = (u64)1 << v_idx; } static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx, @@ -1326,7 +1465,6 @@ static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx, set_bit(t_idx, q_vector->txr_idx); q_vector->txr_count++; - a->tx_ring[t_idx].v_idx = (u64)1 << v_idx; } /** @@ -1505,14 +1643,13 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter) } if (new_itr != q_vector->eitr) { - u32 itr_reg; + /* do an exponential smoothing */ + new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); /* save the algorithm value here, not the smoothed one */ q_vector->eitr = new_itr; - /* do an exponential smoothing */ - new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100); - itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr); - ixgbe_write_eitr(adapter, 0, itr_reg); + + ixgbe_write_eitr(q_vector); } return; @@ -1534,6 +1671,9 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) mask |= IXGBE_EIMS_GPI_SDP1; mask |= IXGBE_EIMS_GPI_SDP2; } + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) + mask |= IXGBE_EIMS_FLOW_DIR; IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); ixgbe_irq_enable_queues(adapter, ~0); @@ -1879,7 +2019,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); } } else { - if (!(adapter->flags & IXGBE_FLAG_RSC_ENABLED) && + if (!(adapter->flags & IXGBE_FLAG2_RSC_ENABLED) && (netdev->mtu <= ETH_DATA_LEN)) rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; else @@ -2008,7 +2148,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); } - if (adapter->flags & IXGBE_FLAG_RSC_ENABLED) { + if (adapter->flags & IXGBE_FLAG2_RSC_ENABLED) { /* Enable 82599 HW-RSC */ for (i = 0; i < adapter->num_rx_queues; i++) { j = adapter->rx_ring[i].reg_idx; @@ -2181,11 +2321,7 @@ static void ixgbe_set_rx_mode(struct net_device *netdev) IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); /* reprogram secondary unicast list */ - addr_count = netdev->uc_count; - if (addr_count) - addr_list = netdev->uc_list->dmi_addr; - hw->mac.ops.update_uc_addr_list(hw, addr_list, addr_count, - ixgbe_addr_list_itr); + hw->mac.ops.update_uc_addr_list(hw, &netdev->uc_list); /* reprogram multicast list */ addr_count = netdev->mc_count; @@ -2208,12 +2344,15 @@ static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter) for (q_idx = 0; q_idx < q_vectors; q_idx++) { struct napi_struct *napi; q_vector = adapter->q_vector[q_idx]; - if (!q_vector->rxr_count) - continue; napi = &q_vector->napi; - if ((adapter->flags & IXGBE_FLAG_MSIX_ENABLED) && - (q_vector->rxr_count > 1)) - napi->poll = &ixgbe_clean_rxonly_many; + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + if (!q_vector->rxr_count || !q_vector->txr_count) { + if (q_vector->txr_count == 1) + napi->poll = &ixgbe_clean_txonly; + else if (q_vector->rxr_count == 1) + napi->poll = &ixgbe_clean_rxonly; + } + } napi_enable(napi); } @@ -2231,8 +2370,6 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter) for (q_idx = 0; q_idx < q_vectors; q_idx++) { q_vector = adapter->q_vector[q_idx]; - if (!q_vector->rxr_count) - continue; napi_disable(&q_vector->napi); } } @@ -2290,6 +2427,7 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) static void ixgbe_configure(struct ixgbe_adapter *adapter) { struct net_device *netdev = adapter->netdev; + struct ixgbe_hw *hw = &adapter->hw; int i; ixgbe_set_rx_mode(netdev); @@ -2311,6 +2449,15 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter) ixgbe_configure_fcoe(adapter); #endif /* IXGBE_FCOE */ + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) { + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].atr_sample_rate = + adapter->atr_sample_rate; + ixgbe_init_fdir_signature_82599(hw, adapter->fdir_pballoc); + } else if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) { + ixgbe_init_fdir_perfect_82599(hw, adapter->fdir_pballoc); + } + ixgbe_configure_tx(adapter); ixgbe_configure_rx(adapter); for (i = 0; i < adapter->num_rx_queues; i++) @@ -2567,6 +2714,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) DPRINTK(PROBE, ERR, "link_config FAILED %d\n", err); } + for (i = 0; i < adapter->num_tx_queues; i++) + set_bit(__IXGBE_FDIR_INIT_DONE, + &(adapter->tx_ring[i].reinit_state)); + /* enable transmits */ netif_tx_start_all_queues(netdev); @@ -2602,12 +2753,28 @@ void ixgbe_reset(struct ixgbe_adapter *adapter) int err; err = hw->mac.ops.init_hw(hw); - if (err && (err != IXGBE_ERR_SFP_NOT_PRESENT)) - dev_err(&adapter->pdev->dev, "Hardware Error\n"); + switch (err) { + case 0: + case IXGBE_ERR_SFP_NOT_PRESENT: + break; + case IXGBE_ERR_MASTER_REQUESTS_PENDING: + dev_err(&adapter->pdev->dev, "master disable timed out\n"); + break; + case IXGBE_ERR_EEPROM_VERSION: + /* We are running on a pre-production device, log a warning */ + dev_warn(&adapter->pdev->dev, "This device is a pre-production " + "adapter/LOM. Please be aware there may be issues " + "associated with your hardware. If you are " + "experiencing problems please contact your Intel or " + "hardware representative who provided you with this " + "hardware.\n"); + break; + default: + dev_err(&adapter->pdev->dev, "Hardware Error: %d\n", err); + } /* reprogram the RAR[0] in case user changed it. */ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); - } /** @@ -2755,6 +2922,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter) del_timer_sync(&adapter->watchdog_timer); cancel_work_sync(&adapter->watchdog_task); + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) + cancel_work_sync(&adapter->fdir_reinit_task); + /* disable transmits in the hardware now that interrupts are off */ for (i = 0; i < adapter->num_tx_queues; i++) { j = adapter->tx_ring[i].reg_idx; @@ -2802,7 +2973,7 @@ static int ixgbe_poll(struct napi_struct *napi, int budget) } #endif - tx_clean_complete = ixgbe_clean_tx_irq(adapter, adapter->tx_ring); + tx_clean_complete = ixgbe_clean_tx_irq(q_vector, adapter->tx_ring); ixgbe_clean_rx_irq(q_vector, adapter->rx_ring, &work_done, budget); if (!tx_clean_complete) @@ -2889,6 +3060,38 @@ static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter) return ret; } +/** + * ixgbe_set_fdir_queues: Allocate queues for Flow Director + * @adapter: board private structure to initialize + * + * Flow Director is an advanced Rx filter, attempting to get Rx flows back + * to the original CPU that initiated the Tx session. This runs in addition + * to RSS, so if a packet doesn't match an FDIR filter, we can still spread the + * Rx load across CPUs using RSS. + * + **/ +static bool inline ixgbe_set_fdir_queues(struct ixgbe_adapter *adapter) +{ + bool ret = false; + struct ixgbe_ring_feature *f_fdir = &adapter->ring_feature[RING_F_FDIR]; + + f_fdir->indices = min((int)num_online_cpus(), f_fdir->indices); + f_fdir->mask = 0; + + /* Flow Director must have RSS enabled */ + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED && + ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)))) { + adapter->num_tx_queues = f_fdir->indices; + adapter->num_rx_queues = f_fdir->indices; + ret = true; + } else { + adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; + } + return ret; +} + #ifdef IXGBE_FCOE /** * ixgbe_set_fcoe_queues: Allocate queues for Fiber Channel over Ethernet (FCoE) @@ -2953,6 +3156,9 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) goto done; #endif + if (ixgbe_set_fdir_queues(adapter)) + goto done; + if (ixgbe_set_rss_queues(adapter)) goto done; @@ -3123,6 +3329,31 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter) } #endif +/** + * ixgbe_cache_ring_fdir - Descriptor ring to register mapping for Flow Director + * @adapter: board private structure to initialize + * + * Cache the descriptor ring offsets for Flow Director to the assigned rings. + * + **/ +static bool inline ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter) +{ + int i; + bool ret = false; + + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED && + ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) || + (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))) { + for (i = 0; i < adapter->num_rx_queues; i++) + adapter->rx_ring[i].reg_idx = i; + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].reg_idx = i; + ret = true; + } + + return ret; +} + #ifdef IXGBE_FCOE /** * ixgbe_cache_ring_fcoe - Descriptor ring to register mapping for the FCoE @@ -3183,6 +3414,9 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) return; #endif + if (ixgbe_cache_ring_fdir(adapter)) + return; + if (ixgbe_cache_ring_rss(adapter)) return; } @@ -3276,6 +3510,9 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter) adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; + adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; + adapter->atr_sample_rate = 0; ixgbe_set_num_queues(adapter); err = pci_enable_msi(adapter->pdev); @@ -3309,7 +3546,7 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter) if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; napi_vectors = adapter->num_rx_queues; - poll = &ixgbe_clean_rxonly; + poll = &ixgbe_clean_rxtx_many; } else { num_q_vectors = 1; napi_vectors = 1; @@ -3321,11 +3558,9 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter) if (!q_vector) goto err_out; q_vector->adapter = adapter; - q_vector->v_idx = q_idx; q_vector->eitr = adapter->eitr_param; - if (q_idx < napi_vectors) - netif_napi_add(adapter->netdev, &q_vector->napi, - (*poll), 64); + q_vector->v_idx = q_idx; + netif_napi_add(adapter->netdev, &q_vector->napi, (*poll), 64); adapter->q_vector[q_idx] = q_vector; } @@ -3353,22 +3588,16 @@ err_out: static void ixgbe_free_q_vectors(struct ixgbe_adapter *adapter) { int q_idx, num_q_vectors; - int napi_vectors; - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; - napi_vectors = adapter->num_rx_queues; - } else { + else num_q_vectors = 1; - napi_vectors = 1; - } for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { struct ixgbe_q_vector *q_vector = adapter->q_vector[q_idx]; - adapter->q_vector[q_idx] = NULL; - if (q_idx < napi_vectors) - netif_napi_del(&q_vector->napi); + netif_napi_del(&q_vector->napi); kfree(q_vector); } } @@ -3547,8 +3776,13 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598; } else if (hw->mac.type == ixgbe_mac_82599EB) { adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599; - adapter->flags |= IXGBE_FLAG_RSC_CAPABLE; - adapter->flags |= IXGBE_FLAG_RSC_ENABLED; + adapter->flags |= IXGBE_FLAG2_RSC_CAPABLE; + adapter->flags |= IXGBE_FLAG2_RSC_ENABLED; + adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->ring_feature[RING_F_FDIR].indices = + IXGBE_MAX_FDIR_INDICES; + adapter->atr_sample_rate = 20; + adapter->fdir_pballoc = 0; #ifdef IXGBE_FCOE adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; adapter->ring_feature[RING_F_FCOE].indices = IXGBE_FCRETA_SIZE; @@ -4138,6 +4372,8 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */ adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); + adapter->stats.fdirmatch += IXGBE_READ_REG(hw, IXGBE_FDIRMATCH); + adapter->stats.fdirmiss += IXGBE_READ_REG(hw, IXGBE_FDIRMISS); #ifdef IXGBE_FCOE adapter->stats.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); adapter->stats.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); @@ -4213,57 +4449,43 @@ static void ixgbe_watchdog(unsigned long data) { struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; struct ixgbe_hw *hw = &adapter->hw; + u64 eics = 0; + int i; - /* Do the watchdog outside of interrupt context due to the lovely - * delays that some of the newer hardware requires */ - if (!test_bit(__IXGBE_DOWN, &adapter->state)) { - u64 eics = 0; - int i; + /* + * Do the watchdog outside of interrupt context due to the lovely + * delays that some of the newer hardware requires + */ - for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) - eics |= ((u64)1 << i); + if (test_bit(__IXGBE_DOWN, &adapter->state)) + goto watchdog_short_circuit; - /* Cause software interrupt to ensure rx rings are cleaned */ - switch (hw->mac.type) { - case ixgbe_mac_82598EB: - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { - IXGBE_WRITE_REG(hw, IXGBE_EICS, (u32)eics); - } else { - /* - * for legacy and MSI interrupts don't set any - * bits that are enabled for EIAM, because this - * operation would set *both* EIMS and EICS for - * any bit in EIAM - */ - IXGBE_WRITE_REG(hw, IXGBE_EICS, - (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); - } - break; - case ixgbe_mac_82599EB: - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { - IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(0), - (u32)(eics & 0xFFFFFFFF)); - IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(1), - (u32)(eics >> 32)); - } else { - /* - * for legacy and MSI interrupts don't set any - * bits that are enabled for EIAM, because this - * operation would set *both* EIMS and EICS for - * any bit in EIAM - */ - IXGBE_WRITE_REG(hw, IXGBE_EICS, - (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); - } - break; - default: - break; - } - /* Reset the timer */ - mod_timer(&adapter->watchdog_timer, - round_jiffies(jiffies + 2 * HZ)); + if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { + /* + * for legacy and MSI interrupts don't set any bits + * that are enabled for EIAM, because this operation + * would set *both* EIMS and EICS for any bit in EIAM + */ + IXGBE_WRITE_REG(hw, IXGBE_EICS, + (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); + goto watchdog_reschedule; } + /* get one bit for every active tx/rx interrupt vector */ + for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { + struct ixgbe_q_vector *qv = adapter->q_vector[i]; + if (qv->rxr_count || qv->txr_count) + eics |= ((u64)1 << i); + } + + /* Cause software interrupt to ensure rx rings are cleaned */ + ixgbe_irq_rearm_queues(adapter, eics); + +watchdog_reschedule: + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ)); + +watchdog_short_circuit: schedule_work(&adapter->watchdog_task); } @@ -4317,6 +4539,30 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work) } /** + * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table + * @work: pointer to work_struct containing our data + **/ +static void ixgbe_fdir_reinit_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter = container_of(work, + struct ixgbe_adapter, + fdir_reinit_task); + struct ixgbe_hw *hw = &adapter->hw; + int i; + + if (ixgbe_reinit_fdir_tables_82599(hw) == 0) { + for (i = 0; i < adapter->num_tx_queues; i++) + set_bit(__IXGBE_FDIR_INIT_DONE, + &(adapter->tx_ring[i].reinit_state)); + } else { + DPRINTK(PROBE, ERR, "failed to finish FDIR re-initialization, " + "ignored adding FDIR ATR filters \n"); + } + /* Done FDIR Re-initialization, enable transmits */ + netif_tx_start_all_queues(adapter->netdev); +} + +/** * ixgbe_watchdog_task - worker thread to bring link up * @work: pointer to work_struct containing our data **/ @@ -4341,12 +4587,12 @@ static void ixgbe_watchdog_task(struct work_struct *work) #ifdef CONFIG_DCB if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { for (i = 0; i < MAX_TRAFFIC_CLASS; i++) - hw->mac.ops.setup_fc(hw, i); + hw->mac.ops.fc_enable(hw, i); } else { - hw->mac.ops.setup_fc(hw, 0); + hw->mac.ops.fc_enable(hw, 0); } #else - hw->mac.ops.setup_fc(hw, 0); + hw->mac.ops.fc_enable(hw, 0); #endif } @@ -4623,7 +4869,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); tx_buffer_info->length = size; - tx_buffer_info->dma = map[0] + offset; + tx_buffer_info->dma = skb_shinfo(skb)->dma_head + offset; tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; @@ -4655,7 +4901,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); tx_buffer_info->length = size; - tx_buffer_info->dma = map[f + 1] + offset; + tx_buffer_info->dma = map[f] + offset; tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; @@ -4743,6 +4989,58 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, writel(i, adapter->hw.hw_addr + tx_ring->tail); } +static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, + int queue, u32 tx_flags) +{ + /* Right now, we support IPv4 only */ + struct ixgbe_atr_input atr_input; + struct tcphdr *th; + struct udphdr *uh; + struct iphdr *iph = ip_hdr(skb); + struct ethhdr *eth = (struct ethhdr *)skb->data; + u16 vlan_id, src_port, dst_port, flex_bytes; + u32 src_ipv4_addr, dst_ipv4_addr; + u8 l4type = 0; + + /* check if we're UDP or TCP */ + if (iph->protocol == IPPROTO_TCP) { + th = tcp_hdr(skb); + src_port = th->source; + dst_port = th->dest; + l4type |= IXGBE_ATR_L4TYPE_TCP; + /* l4type IPv4 type is 0, no need to assign */ + } else if(iph->protocol == IPPROTO_UDP) { + uh = udp_hdr(skb); + src_port = uh->source; + dst_port = uh->dest; + l4type |= IXGBE_ATR_L4TYPE_UDP; + /* l4type IPv4 type is 0, no need to assign */ + } else { + /* Unsupported L4 header, just bail here */ + return; + } + + memset(&atr_input, 0, sizeof(struct ixgbe_atr_input)); + + vlan_id = (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK) >> + IXGBE_TX_FLAGS_VLAN_SHIFT; + src_ipv4_addr = iph->saddr; + dst_ipv4_addr = iph->daddr; + flex_bytes = eth->h_proto; + + ixgbe_atr_set_vlan_id_82599(&atr_input, vlan_id); + ixgbe_atr_set_src_port_82599(&atr_input, dst_port); + ixgbe_atr_set_dst_port_82599(&atr_input, src_port); + ixgbe_atr_set_flex_byte_82599(&atr_input, flex_bytes); + ixgbe_atr_set_l4type_82599(&atr_input, l4type); + /* src and dst are inverted, think how the receiver sees them */ + ixgbe_atr_set_src_ipv4_82599(&atr_input, dst_ipv4_addr); + ixgbe_atr_set_dst_ipv4_82599(&atr_input, src_ipv4_addr); + + /* This assumes the Rx queue and Tx queue are bound to the same CPU */ + ixgbe_fdir_add_signature_filter_82599(&adapter->hw, &atr_input, queue); +} + static int __ixgbe_maybe_stop_tx(struct net_device *netdev, struct ixgbe_ring *tx_ring, int size) { @@ -4777,6 +5075,9 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) { struct ixgbe_adapter *adapter = netdev_priv(dev); + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) + return smp_processor_id(); + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) return 0; /* All traffic should default to class 0 */ @@ -4861,9 +5162,19 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) count = ixgbe_tx_map(adapter, tx_ring, skb, tx_flags, first); if (count) { + /* add the ATR filter if ATR is on */ + if (tx_ring->atr_sample_rate) { + ++tx_ring->atr_count; + if ((tx_ring->atr_count >= tx_ring->atr_sample_rate) && + test_bit(__IXGBE_FDIR_INIT_DONE, + &tx_ring->reinit_state)) { + ixgbe_atr(adapter, skb, tx_ring->queue_index, + tx_flags); + tx_ring->atr_count = 0; + } + } ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len, hdr_len); - netdev->trans_start = jiffies; ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED); } else { @@ -5244,6 +5555,12 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_FCOE_CRC; netdev->features |= NETIF_F_FSO; netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; + DPRINTK(DRV, INFO, "FCoE enabled, " + "disabling Flow Director\n"); + adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE; + adapter->flags &= + ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE; + adapter->atr_sample_rate = 0; } else { adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; } @@ -5253,7 +5570,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; - if (adapter->flags & IXGBE_FLAG_RSC_ENABLED) + if (adapter->flags & IXGBE_FLAG2_RSC_ENABLED) netdev->features |= NETIF_F_LRO; /* make sure the EEPROM is good */ @@ -5287,6 +5604,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, case IXGBE_DEV_ID_82599_KX4: adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX | IXGBE_WUFC_MC | IXGBE_WUFC_BC); + /* Enable ACPI wakeup in GRC */ + IXGBE_WRITE_REG(hw, IXGBE_GRC, + (IXGBE_READ_REG(hw, IXGBE_GRC) & ~IXGBE_GRC_APME)); break; default: adapter->wol = 0; @@ -5329,8 +5649,17 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, hw->eeprom.ops.read(hw, 0x29, &adapter->eeprom_version); /* reset the hardware with the new settings */ - hw->mac.ops.start_hw(hw); + err = hw->mac.ops.start_hw(hw); + if (err == IXGBE_ERR_EEPROM_VERSION) { + /* We are running on a pre-production device, log a warning */ + dev_warn(&pdev->dev, "This device is a pre-production " + "adapter/LOM. Please be aware there may be issues " + "associated with your hardware. If you are " + "experiencing problems please contact your Intel or " + "hardware representative who provided you with this " + "hardware.\n"); + } strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) @@ -5339,6 +5668,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) + INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task); + #ifdef CONFIG_IXGBE_DCA if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IXGBE_FLAG_DCA_ENABLED; @@ -5401,6 +5734,9 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) cancel_work_sync(&adapter->sfp_task); cancel_work_sync(&adapter->multispeed_fiber_task); cancel_work_sync(&adapter->sfp_config_module_task); + if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || + adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) + cancel_work_sync(&adapter->fdir_reinit_task); flush_scheduled_work(); #ifdef CONFIG_IXGBE_DCA diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index e43d6248d7d4..453e966762f0 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -606,6 +606,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.sfp_setup_needed = true; /* Determine if the SFP+ PHY is dual speed or not. */ + hw->phy.multispeed_fiber = false; if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index df1f7034c284..fa87309dc087 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -30,6 +30,7 @@ #include <linux/types.h> #include <linux/mdio.h> +#include <linux/list.h> /* Vendor ID */ #define IXGBE_INTEL_VENDOR_ID 0x8086 @@ -230,6 +231,34 @@ #define IXGBE_RETA(_i) (0x05C00 + ((_i) * 4)) /* 32 of these (0-31) */ #define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* 10 of these (0-9) */ +/* Flow Director registers */ +#define IXGBE_FDIRCTRL 0x0EE00 +#define IXGBE_FDIRHKEY 0x0EE68 +#define IXGBE_FDIRSKEY 0x0EE6C +#define IXGBE_FDIRDIP4M 0x0EE3C +#define IXGBE_FDIRSIP4M 0x0EE40 +#define IXGBE_FDIRTCPM 0x0EE44 +#define IXGBE_FDIRUDPM 0x0EE48 +#define IXGBE_FDIRIP6M 0x0EE74 +#define IXGBE_FDIRM 0x0EE70 + +/* Flow Director Stats registers */ +#define IXGBE_FDIRFREE 0x0EE38 +#define IXGBE_FDIRLEN 0x0EE4C +#define IXGBE_FDIRUSTAT 0x0EE50 +#define IXGBE_FDIRFSTAT 0x0EE54 +#define IXGBE_FDIRMATCH 0x0EE58 +#define IXGBE_FDIRMISS 0x0EE5C + +/* Flow Director Programming registers */ +#define IXGBE_FDIRSIPv6(_i) (0x0EE0C + ((_i) * 4)) /* 3 of these (0-2) */ +#define IXGBE_FDIRIPSA 0x0EE18 +#define IXGBE_FDIRIPDA 0x0EE1C +#define IXGBE_FDIRPORT 0x0EE20 +#define IXGBE_FDIRVLAN 0x0EE24 +#define IXGBE_FDIRHASH 0x0EE28 +#define IXGBE_FDIRCMD 0x0EE2C + /* Transmit DMA registers */ #define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40)) /* 32 of these (0-31)*/ #define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40)) @@ -1264,8 +1293,10 @@ #define IXGBE_STATUS_LAN_ID_1 0x00000004 /* LAN ID 1 */ /* ESDP Bit Masks */ -#define IXGBE_ESDP_SDP0 0x00000001 -#define IXGBE_ESDP_SDP1 0x00000002 +#define IXGBE_ESDP_SDP0 0x00000001 /* SDP0 Data Value */ +#define IXGBE_ESDP_SDP1 0x00000002 /* SDP1 Data Value */ +#define IXGBE_ESDP_SDP2 0x00000004 /* SDP2 Data Value */ +#define IXGBE_ESDP_SDP3 0x00000008 /* SDP3 Data Value */ #define IXGBE_ESDP_SDP4 0x00000010 /* SDP4 Data Value */ #define IXGBE_ESDP_SDP5 0x00000020 /* SDP5 Data Value */ #define IXGBE_ESDP_SDP6 0x00000040 /* SDP6 Data Value */ @@ -1365,8 +1396,6 @@ #define IXGBE_LINK_UP_TIME 90 /* 9.0 Seconds */ #define IXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */ -#define FIBER_LINK_UP_LIMIT 50 - /* PCS1GLSTA Bit Masks */ #define IXGBE_PCS1GLSTA_LINK_OK 1 #define IXGBE_PCS1GLSTA_SYNK_OK 0x10 @@ -1487,6 +1516,8 @@ #define IXGBE_SAN_MAC_ADDR_PORT1_OFFSET 0x3 #define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 #define IXGBE_DEVICE_CAPS_FCOE_OFFLOADS 0x2 +#define IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR 0x4 +#define IXGBE_FW_PATCH_VERSION_4 0x7 /* PCI Bus Info */ #define IXGBE_PCI_LINK_STATUS 0xB2 @@ -1651,6 +1682,9 @@ #define IXGBE_RXDADV_ERR_SHIFT 20 /* RDESC.ERRORS shift */ #define IXGBE_RXDADV_ERR_FCEOFE 0x80000000 /* FCoEFe/IPE */ #define IXGBE_RXDADV_ERR_FCERR 0x00700000 /* FCERR/FDIRERR */ +#define IXGBE_RXDADV_ERR_FDIR_LEN 0x00100000 /* FDIR Length error */ +#define IXGBE_RXDADV_ERR_FDIR_DROP 0x00200000 /* FDIR Drop error */ +#define IXGBE_RXDADV_ERR_FDIR_COLL 0x00400000 /* FDIR Collision error */ #define IXGBE_RXDADV_ERR_HBO 0x00800000 /*Header Buffer Overflow */ #define IXGBE_RXDADV_ERR_CE 0x01000000 /* CRC Error */ #define IXGBE_RXDADV_ERR_LE 0x02000000 /* Length Error */ @@ -1783,6 +1817,82 @@ #endif +enum ixgbe_fdir_pballoc_type { + IXGBE_FDIR_PBALLOC_64K = 0, + IXGBE_FDIR_PBALLOC_128K, + IXGBE_FDIR_PBALLOC_256K, +}; +#define IXGBE_FDIR_PBALLOC_SIZE_SHIFT 16 + +/* Flow Director register values */ +#define IXGBE_FDIRCTRL_PBALLOC_64K 0x00000001 +#define IXGBE_FDIRCTRL_PBALLOC_128K 0x00000002 +#define IXGBE_FDIRCTRL_PBALLOC_256K 0x00000003 +#define IXGBE_FDIRCTRL_INIT_DONE 0x00000008 +#define IXGBE_FDIRCTRL_PERFECT_MATCH 0x00000010 +#define IXGBE_FDIRCTRL_REPORT_STATUS 0x00000020 +#define IXGBE_FDIRCTRL_REPORT_STATUS_ALWAYS 0x00000080 +#define IXGBE_FDIRCTRL_DROP_Q_SHIFT 8 +#define IXGBE_FDIRCTRL_FLEX_SHIFT 16 +#define IXGBE_FDIRCTRL_SEARCHLIM 0x00800000 +#define IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT 24 +#define IXGBE_FDIRCTRL_FULL_THRESH_MASK 0xF0000000 +#define IXGBE_FDIRCTRL_FULL_THRESH_SHIFT 28 + +#define IXGBE_FDIRTCPM_DPORTM_SHIFT 16 +#define IXGBE_FDIRUDPM_DPORTM_SHIFT 16 +#define IXGBE_FDIRIP6M_DIPM_SHIFT 16 +#define IXGBE_FDIRM_VLANID 0x00000001 +#define IXGBE_FDIRM_VLANP 0x00000002 +#define IXGBE_FDIRM_POOL 0x00000004 +#define IXGBE_FDIRM_L3P 0x00000008 +#define IXGBE_FDIRM_L4P 0x00000010 +#define IXGBE_FDIRM_FLEX 0x00000020 +#define IXGBE_FDIRM_DIPv6 0x00000040 + +#define IXGBE_FDIRFREE_FREE_MASK 0xFFFF +#define IXGBE_FDIRFREE_FREE_SHIFT 0 +#define IXGBE_FDIRFREE_COLL_MASK 0x7FFF0000 +#define IXGBE_FDIRFREE_COLL_SHIFT 16 +#define IXGBE_FDIRLEN_MAXLEN_MASK 0x3F +#define IXGBE_FDIRLEN_MAXLEN_SHIFT 0 +#define IXGBE_FDIRLEN_MAXHASH_MASK 0x7FFF0000 +#define IXGBE_FDIRLEN_MAXHASH_SHIFT 16 +#define IXGBE_FDIRUSTAT_ADD_MASK 0xFFFF +#define IXGBE_FDIRUSTAT_ADD_SHIFT 0 +#define IXGBE_FDIRUSTAT_REMOVE_MASK 0xFFFF0000 +#define IXGBE_FDIRUSTAT_REMOVE_SHIFT 16 +#define IXGBE_FDIRFSTAT_FADD_MASK 0x00FF +#define IXGBE_FDIRFSTAT_FADD_SHIFT 0 +#define IXGBE_FDIRFSTAT_FREMOVE_MASK 0xFF00 +#define IXGBE_FDIRFSTAT_FREMOVE_SHIFT 8 +#define IXGBE_FDIRPORT_DESTINATION_SHIFT 16 +#define IXGBE_FDIRVLAN_FLEX_SHIFT 16 +#define IXGBE_FDIRHASH_BUCKET_VALID_SHIFT 15 +#define IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT 16 + +#define IXGBE_FDIRCMD_CMD_MASK 0x00000003 +#define IXGBE_FDIRCMD_CMD_ADD_FLOW 0x00000001 +#define IXGBE_FDIRCMD_CMD_REMOVE_FLOW 0x00000002 +#define IXGBE_FDIRCMD_CMD_QUERY_REM_FILT 0x00000003 +#define IXGBE_FDIRCMD_CMD_QUERY_REM_HASH 0x00000007 +#define IXGBE_FDIRCMD_FILTER_UPDATE 0x00000008 +#define IXGBE_FDIRCMD_IPv6DMATCH 0x00000010 +#define IXGBE_FDIRCMD_L4TYPE_UDP 0x00000020 +#define IXGBE_FDIRCMD_L4TYPE_TCP 0x00000040 +#define IXGBE_FDIRCMD_L4TYPE_SCTP 0x00000060 +#define IXGBE_FDIRCMD_IPV6 0x00000080 +#define IXGBE_FDIRCMD_CLEARHT 0x00000100 +#define IXGBE_FDIRCMD_DROP 0x00000200 +#define IXGBE_FDIRCMD_INT 0x00000400 +#define IXGBE_FDIRCMD_LAST 0x00000800 +#define IXGBE_FDIRCMD_COLLISION 0x00001000 +#define IXGBE_FDIRCMD_QUEUE_EN 0x00008000 +#define IXGBE_FDIRCMD_RX_QUEUE_SHIFT 16 +#define IXGBE_FDIRCMD_VT_POOL_SHIFT 24 +#define IXGBE_FDIR_INIT_DONE_POLL 10 +#define IXGBE_FDIRCMD_CMD_POLL 10 + /* Transmit Descriptor - Legacy */ struct ixgbe_legacy_tx_desc { u64 buffer_addr; /* Address of the descriptor's data buffer */ @@ -1956,6 +2066,45 @@ typedef u32 ixgbe_physical_layer; #define IXGBE_PHYSICAL_LAYER_10GBASE_KR 0x0800 #define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI 0x1000 +/* Software ATR hash keys */ +#define IXGBE_ATR_BUCKET_HASH_KEY 0xE214AD3D +#define IXGBE_ATR_SIGNATURE_HASH_KEY 0x14364D17 + +/* Software ATR input stream offsets and masks */ +#define IXGBE_ATR_VLAN_OFFSET 0 +#define IXGBE_ATR_SRC_IPV6_OFFSET 2 +#define IXGBE_ATR_SRC_IPV4_OFFSET 14 +#define IXGBE_ATR_DST_IPV6_OFFSET 18 +#define IXGBE_ATR_DST_IPV4_OFFSET 30 +#define IXGBE_ATR_SRC_PORT_OFFSET 34 +#define IXGBE_ATR_DST_PORT_OFFSET 36 +#define IXGBE_ATR_FLEX_BYTE_OFFSET 38 +#define IXGBE_ATR_VM_POOL_OFFSET 40 +#define IXGBE_ATR_L4TYPE_OFFSET 41 + +#define IXGBE_ATR_L4TYPE_MASK 0x3 +#define IXGBE_ATR_L4TYPE_IPV6_MASK 0x4 +#define IXGBE_ATR_L4TYPE_UDP 0x1 +#define IXGBE_ATR_L4TYPE_TCP 0x2 +#define IXGBE_ATR_L4TYPE_SCTP 0x3 +#define IXGBE_ATR_HASH_MASK 0x7fff + +/* Flow Director ATR input struct. */ +struct ixgbe_atr_input { + /* Byte layout in order, all values with MSB first: + * + * vlan_id - 2 bytes + * src_ip - 16 bytes + * dst_ip - 16 bytes + * src_port - 2 bytes + * dst_port - 2 bytes + * flex_bytes - 2 bytes + * vm_pool - 1 byte + * l4type - 1 byte + */ + u8 byte_stream[42]; +}; + enum ixgbe_eeprom_type { ixgbe_eeprom_uninitialized = 0, ixgbe_eeprom_spi, @@ -2091,7 +2240,8 @@ struct ixgbe_fc_info { u16 pause_time; /* Flow Control Pause timer */ bool send_xon; /* Flow control send XON */ bool strict_ieee; /* Strict IEEE mode */ - bool disable_fc_autoneg; /* Turn off autoneg FC mode */ + bool disable_fc_autoneg; /* Do not autonegotiate FC */ + bool fc_was_autonegged; /* Is current_mode the result of autonegging? */ enum ixgbe_fc_mode current_mode; /* FC mode in effect */ enum ixgbe_fc_mode requested_mode; /* FC mode requested by caller */ }; @@ -2223,8 +2373,7 @@ struct ixgbe_mac_operations { s32 (*set_vmdq)(struct ixgbe_hw *, u32, u32); s32 (*clear_vmdq)(struct ixgbe_hw *, u32, u32); s32 (*init_rx_addrs)(struct ixgbe_hw *); - s32 (*update_uc_addr_list)(struct ixgbe_hw *, u8 *, u32, - ixgbe_mc_addr_itr); + s32 (*update_uc_addr_list)(struct ixgbe_hw *, struct list_head *); s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32, ixgbe_mc_addr_itr); s32 (*enable_mc)(struct ixgbe_hw *); @@ -2234,7 +2383,7 @@ struct ixgbe_mac_operations { s32 (*init_uta_tables)(struct ixgbe_hw *); /* Flow Control */ - s32 (*setup_fc)(struct ixgbe_hw *, s32); + s32 (*fc_enable)(struct ixgbe_hw *, s32); }; struct ixgbe_phy_operations { @@ -2281,6 +2430,7 @@ struct ixgbe_mac_info { bool orig_link_settings_stored; bool autoneg; bool autoneg_succeeded; + bool autotry_restart; }; struct ixgbe_phy_info { @@ -2346,6 +2496,8 @@ struct ixgbe_info { #define IXGBE_ERR_SFP_NOT_SUPPORTED -19 #define IXGBE_ERR_SFP_NOT_PRESENT -20 #define IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT -21 +#define IXGBE_ERR_FDIR_REINIT_FAILED -23 +#define IXGBE_ERR_EEPROM_VERSION -24 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF #endif /* _IXGBE_TYPE_H_ */ diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 621a7c0c46ba..1e3c63d67b91 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -1939,7 +1939,6 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev) TXCS_SELECT_QUEUE0 | TXCS_QUEUE0S | TXCS_ENABLE); - netdev->trans_start = jiffies; tx_dbg(jme, "xmit: %d+%d@%lu\n", idx, skb_shinfo(skb)->nr_frags + 2, diff --git a/drivers/net/korina.c b/drivers/net/korina.c index dc238567cae1..b4cf602c32b0 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -133,6 +133,7 @@ struct korina_private { int dma_halt_cnt; int dma_run_cnt; struct napi_struct napi; + struct timer_list media_check_timer; struct mii_if_info mii_if; struct net_device *dev; int phy_addr; @@ -664,6 +665,15 @@ static void korina_check_media(struct net_device *dev, unsigned int init_media) &lp->eth_regs->ethmac2); } +static void korina_poll_media(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct korina_private *lp = netdev_priv(dev); + + korina_check_media(dev, 0); + mod_timer(&lp->media_check_timer, jiffies + HZ); +} + static void korina_set_carrier(struct mii_if_info *mii) { if (mii->force_media) { @@ -1034,6 +1044,7 @@ static int korina_open(struct net_device *dev) dev->name, lp->und_irq); goto err_free_ovr_irq; } + mod_timer(&lp->media_check_timer, jiffies + 1); out: return ret; @@ -1053,6 +1064,8 @@ static int korina_close(struct net_device *dev) struct korina_private *lp = netdev_priv(dev); u32 tmp; + del_timer(&lp->media_check_timer); + /* Disable interrupts */ disable_irq(lp->rx_irq); disable_irq(lp->tx_irq); @@ -1183,6 +1196,7 @@ static int korina_probe(struct platform_device *pdev) ": cannot register net device %d\n", rc); goto probe_err_register; } + setup_timer(&lp->media_check_timer, korina_poll_media, (unsigned long) dev); out: return rc; diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c new file mode 100644 index 000000000000..39b0aea2aab3 --- /dev/null +++ b/drivers/net/ks8842.c @@ -0,0 +1,732 @@ +/* + * ks8842_main.c timberdale KS8842 ethernet driver + * Copyright (c) 2009 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Supports: + * The Micrel KS8842 behind the timberdale FPGA + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> + +#define DRV_NAME "ks8842" + +/* Timberdale specific Registers */ +#define REG_TIMB_RST 0x1c + +/* KS8842 registers */ + +#define REG_SELECT_BANK 0x0e + +/* bank 0 registers */ +#define REG_QRFCR 0x04 + +/* bank 2 registers */ +#define REG_MARL 0x00 +#define REG_MARM 0x02 +#define REG_MARH 0x04 + +/* bank 3 registers */ +#define REG_GRR 0x06 + +/* bank 16 registers */ +#define REG_TXCR 0x00 +#define REG_TXSR 0x02 +#define REG_RXCR 0x04 +#define REG_TXMIR 0x08 +#define REG_RXMIR 0x0A + +/* bank 17 registers */ +#define REG_TXQCR 0x00 +#define REG_RXQCR 0x02 +#define REG_TXFDPR 0x04 +#define REG_RXFDPR 0x06 +#define REG_QMU_DATA_LO 0x08 +#define REG_QMU_DATA_HI 0x0A + +/* bank 18 registers */ +#define REG_IER 0x00 +#define IRQ_LINK_CHANGE 0x8000 +#define IRQ_TX 0x4000 +#define IRQ_RX 0x2000 +#define IRQ_RX_OVERRUN 0x0800 +#define IRQ_TX_STOPPED 0x0200 +#define IRQ_RX_STOPPED 0x0100 +#define IRQ_RX_ERROR 0x0080 +#define ENABLED_IRQS (IRQ_LINK_CHANGE | IRQ_TX | IRQ_RX | IRQ_RX_STOPPED | \ + IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR) +#define REG_ISR 0x02 +#define REG_RXSR 0x04 +#define RXSR_VALID 0x8000 +#define RXSR_BROADCAST 0x80 +#define RXSR_MULTICAST 0x40 +#define RXSR_UNICAST 0x20 +#define RXSR_FRAMETYPE 0x08 +#define RXSR_TOO_LONG 0x04 +#define RXSR_RUNT 0x02 +#define RXSR_CRC_ERROR 0x01 +#define RXSR_ERROR (RXSR_TOO_LONG | RXSR_RUNT | RXSR_CRC_ERROR) + +/* bank 32 registers */ +#define REG_SW_ID_AND_ENABLE 0x00 +#define REG_SGCR1 0x02 +#define REG_SGCR2 0x04 +#define REG_SGCR3 0x06 + +/* bank 39 registers */ +#define REG_MACAR1 0x00 +#define REG_MACAR2 0x02 +#define REG_MACAR3 0x04 + +/* bank 45 registers */ +#define REG_P1MBCR 0x00 +#define REG_P1MBSR 0x02 + +/* bank 46 registers */ +#define REG_P2MBCR 0x00 +#define REG_P2MBSR 0x02 + +/* bank 48 registers */ +#define REG_P1CR2 0x02 + +/* bank 49 registers */ +#define REG_P1CR4 0x02 +#define REG_P1SR 0x04 + +struct ks8842_adapter { + void __iomem *hw_addr; + int irq; + struct tasklet_struct tasklet; + spinlock_t lock; /* spinlock to be interrupt safe */ + struct platform_device *pdev; +}; + +static inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank) +{ + iowrite16(bank, adapter->hw_addr + REG_SELECT_BANK); +} + +static inline void ks8842_write8(struct ks8842_adapter *adapter, u16 bank, + u8 value, int offset) +{ + ks8842_select_bank(adapter, bank); + iowrite8(value, adapter->hw_addr + offset); +} + +static inline void ks8842_write16(struct ks8842_adapter *adapter, u16 bank, + u16 value, int offset) +{ + ks8842_select_bank(adapter, bank); + iowrite16(value, adapter->hw_addr + offset); +} + +static inline void ks8842_enable_bits(struct ks8842_adapter *adapter, u16 bank, + u16 bits, int offset) +{ + u16 reg; + ks8842_select_bank(adapter, bank); + reg = ioread16(adapter->hw_addr + offset); + reg |= bits; + iowrite16(reg, adapter->hw_addr + offset); +} + +static inline void ks8842_clear_bits(struct ks8842_adapter *adapter, u16 bank, + u16 bits, int offset) +{ + u16 reg; + ks8842_select_bank(adapter, bank); + reg = ioread16(adapter->hw_addr + offset); + reg &= ~bits; + iowrite16(reg, adapter->hw_addr + offset); +} + +static inline void ks8842_write32(struct ks8842_adapter *adapter, u16 bank, + u32 value, int offset) +{ + ks8842_select_bank(adapter, bank); + iowrite32(value, adapter->hw_addr + offset); +} + +static inline u8 ks8842_read8(struct ks8842_adapter *adapter, u16 bank, + int offset) +{ + ks8842_select_bank(adapter, bank); + return ioread8(adapter->hw_addr + offset); +} + +static inline u16 ks8842_read16(struct ks8842_adapter *adapter, u16 bank, + int offset) +{ + ks8842_select_bank(adapter, bank); + return ioread16(adapter->hw_addr + offset); +} + +static inline u32 ks8842_read32(struct ks8842_adapter *adapter, u16 bank, + int offset) +{ + ks8842_select_bank(adapter, bank); + return ioread32(adapter->hw_addr + offset); +} + +static void ks8842_reset(struct ks8842_adapter *adapter) +{ + /* The KS8842 goes haywire when doing softare reset + * a work around in the timberdale IP is implemented to + * do a hardware reset instead + ks8842_write16(adapter, 3, 1, REG_GRR); + msleep(10); + iowrite16(0, adapter->hw_addr + REG_GRR); + */ + iowrite16(32, adapter->hw_addr + REG_SELECT_BANK); + iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST); + msleep(20); +} + +static void ks8842_update_link_status(struct net_device *netdev, + struct ks8842_adapter *adapter) +{ + /* check the status of the link */ + if (ks8842_read16(adapter, 45, REG_P1MBSR) & 0x4) { + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } else { + netif_stop_queue(netdev); + netif_carrier_off(netdev); + } +} + +static void ks8842_enable_tx(struct ks8842_adapter *adapter) +{ + ks8842_enable_bits(adapter, 16, 0x01, REG_TXCR); +} + +static void ks8842_disable_tx(struct ks8842_adapter *adapter) +{ + ks8842_clear_bits(adapter, 16, 0x01, REG_TXCR); +} + +static void ks8842_enable_rx(struct ks8842_adapter *adapter) +{ + ks8842_enable_bits(adapter, 16, 0x01, REG_RXCR); +} + +static void ks8842_disable_rx(struct ks8842_adapter *adapter) +{ + ks8842_clear_bits(adapter, 16, 0x01, REG_RXCR); +} + +static void ks8842_reset_hw(struct ks8842_adapter *adapter) +{ + /* reset the HW */ + ks8842_reset(adapter); + + /* Enable QMU Transmit flow control / transmit padding / Transmit CRC */ + ks8842_write16(adapter, 16, 0x000E, REG_TXCR); + + /* enable the receiver, uni + multi + broadcast + flow ctrl + + crc strip */ + ks8842_write16(adapter, 16, 0x8 | 0x20 | 0x40 | 0x80 | 0x400, + REG_RXCR); + + /* TX frame pointer autoincrement */ + ks8842_write16(adapter, 17, 0x4000, REG_TXFDPR); + + /* RX frame pointer autoincrement */ + ks8842_write16(adapter, 17, 0x4000, REG_RXFDPR); + + /* RX 2 kb high watermark */ + ks8842_write16(adapter, 0, 0x1000, REG_QRFCR); + + /* aggresive back off in half duplex */ + ks8842_enable_bits(adapter, 32, 1 << 8, REG_SGCR1); + + /* enable no excessive collison drop */ + ks8842_enable_bits(adapter, 32, 1 << 3, REG_SGCR2); + + /* Enable port 1 force flow control / back pressure / transmit / recv */ + ks8842_write16(adapter, 48, 0x1E07, REG_P1CR2); + + /* restart port auto-negotiation */ + ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4); + /* only advertise 10Mbps */ + ks8842_clear_bits(adapter, 49, 3 << 2, REG_P1CR4); + + /* Enable the transmitter */ + ks8842_enable_tx(adapter); + + /* Enable the receiver */ + ks8842_enable_rx(adapter); + + /* clear all interrupts */ + ks8842_write16(adapter, 18, 0xffff, REG_ISR); + + /* enable interrupts */ + ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER); + + /* enable the switch */ + ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE); +} + +static void ks8842_read_mac_addr(struct ks8842_adapter *adapter, u8 *dest) +{ + int i; + u16 mac; + + for (i = 0; i < ETH_ALEN; i++) + dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + i); + + /* make sure the switch port uses the same MAC as the QMU */ + mac = ks8842_read16(adapter, 2, REG_MARL); + ks8842_write16(adapter, 39, mac, REG_MACAR1); + mac = ks8842_read16(adapter, 2, REG_MARM); + ks8842_write16(adapter, 39, mac, REG_MACAR2); + mac = ks8842_read16(adapter, 2, REG_MARH); + ks8842_write16(adapter, 39, mac, REG_MACAR3); +} + +static inline u16 ks8842_tx_fifo_space(struct ks8842_adapter *adapter) +{ + return ks8842_read16(adapter, 16, REG_TXMIR) & 0x1fff; +} + +static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + int len = skb->len; + u32 *ptr = (u32 *)skb->data; + u32 ctrl; + + dev_dbg(&adapter->pdev->dev, + "%s: len %u head %p data %p tail %p end %p\n", + __func__, skb->len, skb->head, skb->data, + skb_tail_pointer(skb), skb_end_pointer(skb)); + + /* check FIFO buffer space, we need space for CRC and command bits */ + if (ks8842_tx_fifo_space(adapter) < len + 8) + return NETDEV_TX_BUSY; + + /* the control word, enable IRQ, port 1 and the length */ + ctrl = 0x8000 | 0x100 | (len << 16); + ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO); + + netdev->stats.tx_bytes += len; + + /* copy buffer */ + while (len > 0) { + iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO); + len -= sizeof(u32); + ptr++; + } + + /* enqueue packet */ + ks8842_write16(adapter, 17, 1, REG_TXQCR); + + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +static void ks8842_rx_frame(struct net_device *netdev, + struct ks8842_adapter *adapter) +{ + u32 status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO); + int len = (status >> 16) & 0x7ff; + + status &= 0xffff; + + dev_dbg(&adapter->pdev->dev, "%s - rx_data: status: %x\n", + __func__, status); + + /* check the status */ + if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) { + struct sk_buff *skb = netdev_alloc_skb(netdev, len + 2); + + dev_dbg(&adapter->pdev->dev, "%s, got package, len: %d\n", + __func__, len); + if (skb) { + u32 *data; + + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += len; + if (status & RXSR_MULTICAST) + netdev->stats.multicast++; + + /* Align socket buffer in 4-byte boundary for + better performance. */ + skb_reserve(skb, 2); + data = (u32 *)skb_put(skb, len); + + ks8842_select_bank(adapter, 17); + while (len > 0) { + *data++ = ioread32(adapter->hw_addr + + REG_QMU_DATA_LO); + len -= sizeof(u32); + } + + skb->protocol = eth_type_trans(skb, netdev); + netif_rx(skb); + } else + netdev->stats.rx_dropped++; + } else { + dev_dbg(&adapter->pdev->dev, "RX error, status: %x\n", status); + netdev->stats.rx_errors++; + if (status & RXSR_TOO_LONG) + netdev->stats.rx_length_errors++; + if (status & RXSR_CRC_ERROR) + netdev->stats.rx_crc_errors++; + if (status & RXSR_RUNT) + netdev->stats.rx_frame_errors++; + } + + /* set high watermark to 3K */ + ks8842_clear_bits(adapter, 0, 1 << 12, REG_QRFCR); + + /* release the frame */ + ks8842_write16(adapter, 17, 0x01, REG_RXQCR); + + /* set high watermark to 2K */ + ks8842_enable_bits(adapter, 0, 1 << 12, REG_QRFCR); +} + +void ks8842_handle_rx(struct net_device *netdev, struct ks8842_adapter *adapter) +{ + u16 rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff; + dev_dbg(&adapter->pdev->dev, "%s Entry - rx_data: %d\n", + __func__, rx_data); + while (rx_data) { + ks8842_rx_frame(netdev, adapter); + rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff; + } +} + +void ks8842_handle_tx(struct net_device *netdev, struct ks8842_adapter *adapter) +{ + u16 sr = ks8842_read16(adapter, 16, REG_TXSR); + dev_dbg(&adapter->pdev->dev, "%s - entry, sr: %x\n", __func__, sr); + netdev->stats.tx_packets++; + if (netif_queue_stopped(netdev)) + netif_wake_queue(netdev); +} + +void ks8842_handle_rx_overrun(struct net_device *netdev, + struct ks8842_adapter *adapter) +{ + dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); + netdev->stats.rx_errors++; + netdev->stats.rx_fifo_errors++; +} + +void ks8842_tasklet(unsigned long arg) +{ + struct net_device *netdev = (struct net_device *)arg; + struct ks8842_adapter *adapter = netdev_priv(netdev); + u16 isr; + unsigned long flags; + u16 entry_bank; + + /* read current bank to be able to set it back */ + spin_lock_irqsave(&adapter->lock, flags); + entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK); + spin_unlock_irqrestore(&adapter->lock, flags); + + isr = ks8842_read16(adapter, 18, REG_ISR); + dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr); + + /* Ack */ + ks8842_write16(adapter, 18, isr, REG_ISR); + + if (!netif_running(netdev)) + return; + + if (isr & IRQ_LINK_CHANGE) + ks8842_update_link_status(netdev, adapter); + + if (isr & (IRQ_RX | IRQ_RX_ERROR)) + ks8842_handle_rx(netdev, adapter); + + if (isr & IRQ_TX) + ks8842_handle_tx(netdev, adapter); + + if (isr & IRQ_RX_OVERRUN) + ks8842_handle_rx_overrun(netdev, adapter); + + if (isr & IRQ_TX_STOPPED) { + ks8842_disable_tx(adapter); + ks8842_enable_tx(adapter); + } + + if (isr & IRQ_RX_STOPPED) { + ks8842_disable_rx(adapter); + ks8842_enable_rx(adapter); + } + + /* re-enable interrupts, put back the bank selection register */ + spin_lock_irqsave(&adapter->lock, flags); + ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER); + iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +static irqreturn_t ks8842_irq(int irq, void *devid) +{ + struct ks8842_adapter *adapter = devid; + u16 isr; + u16 entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK); + irqreturn_t ret = IRQ_NONE; + + isr = ks8842_read16(adapter, 18, REG_ISR); + dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr); + + if (isr) { + /* disable IRQ */ + ks8842_write16(adapter, 18, 0x00, REG_IER); + + /* schedule tasklet */ + tasklet_schedule(&adapter->tasklet); + + ret = IRQ_HANDLED; + } + + iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK); + + return ret; +} + + +/* Netdevice operations */ + +static int ks8842_open(struct net_device *netdev) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + int err; + + dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__); + + /* reset the HW */ + ks8842_reset_hw(adapter); + + ks8842_update_link_status(netdev, adapter); + + err = request_irq(adapter->irq, ks8842_irq, IRQF_SHARED, DRV_NAME, + adapter); + if (err) { + printk(KERN_ERR "Failed to request IRQ: %d: %d\n", + adapter->irq, err); + return err; + } + + return 0; +} + +static int ks8842_close(struct net_device *netdev) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + + dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__); + + /* free the irq */ + free_irq(adapter->irq, adapter); + + /* disable the switch */ + ks8842_write16(adapter, 32, 0x0, REG_SW_ID_AND_ENABLE); + + return 0; +} + +static int ks8842_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + int ret; + struct ks8842_adapter *adapter = netdev_priv(netdev); + + dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); + + ret = ks8842_tx_frame(skb, netdev); + + if (ks8842_tx_fifo_space(adapter) < netdev->mtu + 8) + netif_stop_queue(netdev); + + return ret; +} + +static int ks8842_set_mac(struct net_device *netdev, void *p) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + struct sockaddr *addr = p; + char *mac = (u8 *)addr->sa_data; + int i; + + dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, mac, netdev->addr_len); + + spin_lock_irqsave(&adapter->lock, flags); + for (i = 0; i < ETH_ALEN; i++) { + ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i); + ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1], + REG_MACAR1 + i); + } + spin_unlock_irqrestore(&adapter->lock, flags); + return 0; +} + +static void ks8842_tx_timeout(struct net_device *netdev) +{ + struct ks8842_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + + dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__); + + spin_lock_irqsave(&adapter->lock, flags); + /* disable interrupts */ + ks8842_write16(adapter, 18, 0, REG_IER); + ks8842_write16(adapter, 18, 0xFFFF, REG_ISR); + spin_unlock_irqrestore(&adapter->lock, flags); + + ks8842_reset_hw(adapter); + + ks8842_update_link_status(netdev, adapter); +} + +static const struct net_device_ops ks8842_netdev_ops = { + .ndo_open = ks8842_open, + .ndo_stop = ks8842_close, + .ndo_start_xmit = ks8842_xmit_frame, + .ndo_set_mac_address = ks8842_set_mac, + .ndo_tx_timeout = ks8842_tx_timeout, + .ndo_validate_addr = eth_validate_addr +}; + +static struct ethtool_ops ks8842_ethtool_ops = { + .get_link = ethtool_op_get_link, +}; + +static int __devinit ks8842_probe(struct platform_device *pdev) +{ + int err = -ENOMEM; + struct resource *iomem; + struct net_device *netdev; + struct ks8842_adapter *adapter; + u16 id; + + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!request_mem_region(iomem->start, resource_size(iomem), DRV_NAME)) + goto err_mem_region; + + netdev = alloc_etherdev(sizeof(struct ks8842_adapter)); + if (!netdev) + goto err_alloc_etherdev; + + SET_NETDEV_DEV(netdev, &pdev->dev); + + adapter = netdev_priv(netdev); + adapter->hw_addr = ioremap(iomem->start, resource_size(iomem)); + if (!adapter->hw_addr) + goto err_ioremap; + + adapter->irq = platform_get_irq(pdev, 0); + if (adapter->irq < 0) { + err = adapter->irq; + goto err_get_irq; + } + + adapter->pdev = pdev; + + tasklet_init(&adapter->tasklet, ks8842_tasklet, (unsigned long)netdev); + spin_lock_init(&adapter->lock); + + netdev->netdev_ops = &ks8842_netdev_ops; + netdev->ethtool_ops = &ks8842_ethtool_ops; + + ks8842_read_mac_addr(adapter, netdev->dev_addr); + + id = ks8842_read16(adapter, 32, REG_SW_ID_AND_ENABLE); + + strcpy(netdev->name, "eth%d"); + err = register_netdev(netdev); + if (err) + goto err_register; + + platform_set_drvdata(pdev, netdev); + + printk(KERN_INFO DRV_NAME + " Found chip, family: 0x%x, id: 0x%x, rev: 0x%x\n", + (id >> 8) & 0xff, (id >> 4) & 0xf, (id >> 1) & 0x7); + + return 0; + +err_register: +err_get_irq: + iounmap(adapter->hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + release_mem_region(iomem->start, resource_size(iomem)); +err_mem_region: + return err; +} + +static int __devexit ks8842_remove(struct platform_device *pdev) +{ + struct net_device *netdev = platform_get_drvdata(pdev); + struct ks8842_adapter *adapter = netdev_priv(netdev); + struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + unregister_netdev(netdev); + tasklet_kill(&adapter->tasklet); + iounmap(adapter->hw_addr); + free_netdev(netdev); + release_mem_region(iomem->start, resource_size(iomem)); + platform_set_drvdata(pdev, NULL); + return 0; +} + + +static struct platform_driver ks8842_platform_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ks8842_probe, + .remove = ks8842_remove, +}; + +static int __init ks8842_init(void) +{ + return platform_driver_register(&ks8842_platform_driver); +} + +static void __exit ks8842_exit(void) +{ + platform_driver_unregister(&ks8842_platform_driver); +} + +module_init(ks8842_init); +module_exit(ks8842_exit); + +MODULE_DESCRIPTION("Timberdale KS8842 ethernet driver"); +MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:ks8842"); + diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 8e884869a05b..f8fa0c3f0f64 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -304,7 +304,7 @@ struct net_device * __init mac8390_probe(int unit) if (!MACH_IS_MAC) return ERR_PTR(-ENODEV); - dev = alloc_ei_netdev(); + dev = ____alloc_ei_netdev(0); if (!dev) return ERR_PTR(-ENOMEM); @@ -481,15 +481,15 @@ void cleanup_module(void) static const struct net_device_ops mac8390_netdev_ops = { .ndo_open = mac8390_open, .ndo_stop = mac8390_close, - .ndo_start_xmit = ei_start_xmit, - .ndo_tx_timeout = ei_tx_timeout, - .ndo_get_stats = ei_get_stats, - .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_start_xmit = __ei_start_xmit, + .ndo_tx_timeout = __ei_tx_timeout, + .ndo_get_stats = __ei_get_stats, + .ndo_set_multicast_list = __ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ei_poll, + .ndo_poll_controller = __ei_poll, #endif }; @@ -620,19 +620,12 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd /* Good, done, now spit out some messages */ printk(KERN_INFO "%s: %s in slot %X (type %s)\n", - dev->name, ndev->board->name, ndev->board->slot, cardname[type]); - printk(KERN_INFO "MAC "); - { - int i; - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - } - printk(" IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n", - dev->irq, (int)((dev->mem_end - dev->mem_start)/0x1000) * 4, - dev->mem_start, access_bitmode?32:16); + dev->name, ndev->board->name, ndev->board->slot, cardname[type]); + printk(KERN_INFO + "MAC %pM IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n", + dev->dev_addr, dev->irq, + (unsigned int)(dev->mem_end - dev->mem_start) >> 10, + dev->mem_start, access_bitmode ? 32 : 16); return 0; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index d5334b41e4b4..99eed9f37c84 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -232,7 +232,7 @@ static int macvlan_open(struct net_device *dev) if (macvlan_addr_busy(vlan->port, dev->dev_addr)) goto out; - err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN); + err = dev_unicast_add(lowerdev, dev->dev_addr); if (err < 0) goto out; if (dev->flags & IFF_ALLMULTI) { @@ -244,7 +244,7 @@ static int macvlan_open(struct net_device *dev) return 0; del_unicast: - dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(lowerdev, dev->dev_addr); out: return err; } @@ -258,7 +258,7 @@ static int macvlan_stop(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(lowerdev, -1); - dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(lowerdev, dev->dev_addr); macvlan_hash_del(vlan); return 0; @@ -282,10 +282,11 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p) if (macvlan_addr_busy(vlan->port, addr->sa_data)) return -EBUSY; - if ((err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN))) + err = dev_unicast_add(lowerdev, addr->sa_data); + if (err) return err; - dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN); + dev_unicast_delete(lowerdev, dev->dev_addr); macvlan_hash_change_addr(vlan, addr->sa_data); } @@ -358,6 +359,7 @@ static int macvlan_init(struct net_device *dev) (lowerdev->state & MACVLAN_STATE_MASK); dev->features = lowerdev->features & MACVLAN_FEATURES; dev->iflink = lowerdev->ifindex; + dev->hard_header_len = lowerdev->hard_header_len; macvlan_set_lockdep_class(dev); diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index 66483035f683..dc45e9856c35 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -296,6 +296,23 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX || ecmd->speed == SPEED_10000); } + + /* 10GBASE-T MDI/MDI-X */ + if (ecmd->port == PORT_TP && ecmd->speed == SPEED_10000) { + switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_PMA_10GBT_SWAPPOL)) { + case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: + ecmd->eth_tp_mdix = ETH_TP_MDI; + break; + case 0: + ecmd->eth_tp_mdix = ETH_TP_MDI_X; + break; + default: + /* It's complicated... */ + ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID; + break; + } + } } EXPORT_SYMBOL(mdio45_ethtool_gset_npage); diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile index 21040a0d81fe..1fd068e1d930 100644 --- a/drivers/net/mlx4/Makefile +++ b/drivers/net/mlx4/Makefile @@ -5,5 +5,5 @@ mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \ obj-$(CONFIG_MLX4_EN) += mlx4_en.o -mlx4_en-y := en_main.o en_tx.o en_rx.o en_params.o en_port.o en_cq.o \ +mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \ en_resources.o en_netdev.o diff --git a/drivers/net/mlx4/en_params.c b/drivers/net/mlx4/en_ethtool.c index c1bd040b9e05..091f99052c91 100644 --- a/drivers/net/mlx4/en_params.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -38,64 +38,6 @@ #include "mlx4_en.h" #include "en_port.h" -#define MLX4_EN_PARM_INT(X, def_val, desc) \ - static unsigned int X = def_val;\ - module_param(X , uint, 0444); \ - MODULE_PARM_DESC(X, desc); - - -/* - * Device scope module parameters - */ - - -/* Use a XOR rathern than Toeplitz hash function for RSS */ -MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS"); - -/* RSS hash type mask - default to <saddr, daddr, sport, dport> */ -MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask"); - -/* Number of LRO sessions per Rx ring (rounded up to a power of two) */ -MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS, - "Number of LRO sessions per ring or disabled (0)"); - -/* Priority pausing */ -MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." - " Per priority bit mask"); -MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]." - " Per priority bit mask"); - -int mlx4_en_get_profile(struct mlx4_en_dev *mdev) -{ - struct mlx4_en_profile *params = &mdev->profile; - int i; - - params->rss_xor = (rss_xor != 0); - params->rss_mask = rss_mask & 0x1f; - params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS); - for (i = 1; i <= MLX4_MAX_PORTS; i++) { - params->prof[i].rx_pause = 1; - params->prof[i].rx_ppp = pfcrx; - params->prof[i].tx_pause = 1; - params->prof[i].tx_ppp = pfctx; - params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; - params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; - } - if (pfcrx || pfctx) { - params->prof[1].tx_ring_num = MLX4_EN_TX_RING_NUM; - params->prof[2].tx_ring_num = MLX4_EN_TX_RING_NUM; - } else { - params->prof[1].tx_ring_num = 1; - params->prof[2].tx_ring_num = 1; - } - - return 0; -} - - -/* - * Ethtool support - */ static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv) { @@ -326,8 +268,7 @@ static int mlx4_en_set_coalesce(struct net_device *dev, priv->rx_frames = (coal->rx_max_coalesced_frames == MLX4_EN_AUTO_CONF) ? - MLX4_EN_RX_COAL_TARGET / - priv->dev->mtu + 1 : + MLX4_EN_RX_COAL_TARGET : coal->rx_max_coalesced_frames; priv->rx_usecs = (coal->rx_coalesce_usecs == MLX4_EN_AUTO_CONF) ? @@ -371,7 +312,7 @@ static int mlx4_en_set_pauseparam(struct net_device *dev, priv->prof->rx_pause, priv->prof->rx_ppp); if (err) - mlx4_err(mdev, "Failed setting pause params to\n"); + en_err(priv, "Failed setting pause params\n"); return err; } @@ -421,13 +362,13 @@ static int mlx4_en_set_ringparam(struct net_device *dev, err = mlx4_en_alloc_resources(priv); if (err) { - mlx4_err(mdev, "Failed reallocating port resources\n"); + en_err(priv, "Failed reallocating port resources\n"); goto out; } if (port_up) { err = mlx4_en_start_port(dev); if (err) - mlx4_err(mdev, "Failed starting port\n"); + en_err(priv, "Failed starting port\n"); } out: diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 510633fd57f6..9ed4a158f895 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -51,6 +51,55 @@ static const char mlx4_en_version[] = DRV_NAME ": Mellanox ConnectX HCA Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; +#define MLX4_EN_PARM_INT(X, def_val, desc) \ + static unsigned int X = def_val;\ + module_param(X , uint, 0444); \ + MODULE_PARM_DESC(X, desc); + + +/* + * Device scope module parameters + */ + + +/* Use a XOR rathern than Toeplitz hash function for RSS */ +MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS"); + +/* RSS hash type mask - default to <saddr, daddr, sport, dport> */ +MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask"); + +/* Number of LRO sessions per Rx ring (rounded up to a power of two) */ +MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS, + "Number of LRO sessions per ring or disabled (0)"); + +/* Priority pausing */ +MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." + " Per priority bit mask"); +MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]." + " Per priority bit mask"); + +static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) +{ + struct mlx4_en_profile *params = &mdev->profile; + int i; + + params->rss_xor = (rss_xor != 0); + params->rss_mask = rss_mask & 0x1f; + params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS); + for (i = 1; i <= MLX4_MAX_PORTS; i++) { + params->prof[i].rx_pause = 1; + params->prof[i].rx_ppp = pfcrx; + params->prof[i].tx_pause = 1; + params->prof[i].tx_ppp = pfctx; + params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; + params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; + params->prof[i].tx_ring_num = MLX4_EN_NUM_TX_RINGS + + (!!pfcrx) * MLX4_EN_NUM_PPP_RINGS; + } + + return 0; +} + static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr, enum mlx4_dev_event event, int port) { @@ -194,28 +243,11 @@ static void *mlx4_en_add(struct mlx4_dev *dev) /* Create a netdev for each port */ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { mlx4_info(mdev, "Activating port:%d\n", i); - if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) { + if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) mdev->pndev[i] = NULL; - goto err_free_netdev; - } } return mdev; - -err_free_netdev: - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { - if (mdev->pndev[i]) - mlx4_en_destroy_netdev(mdev->pndev[i]); - } - - mutex_lock(&mdev->state_lock); - mdev->device_up = false; - mutex_unlock(&mdev->state_lock); - flush_workqueue(mdev->workqueue); - - /* Stop event queue before we drop down to release shared SW state */ - destroy_workqueue(mdev->workqueue); - err_mr: mlx4_mr_free(dev, &mdev->mr); err_uar: diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 0cd185a2e089..0a7e78ade63f 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -51,14 +51,14 @@ static void mlx4_en_vlan_rx_register(struct net_device *dev, struct vlan_group * struct mlx4_en_dev *mdev = priv->mdev; int err; - mlx4_dbg(HW, priv, "Registering VLAN group:%p\n", grp); + en_dbg(HW, priv, "Registering VLAN group:%p\n", grp); priv->vlgrp = grp; mutex_lock(&mdev->state_lock); if (mdev->device_up && priv->port_up) { err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, grp); if (err) - mlx4_err(mdev, "Failed configuring VLAN filter\n"); + en_err(priv, "Failed configuring VLAN filter\n"); } mutex_unlock(&mdev->state_lock); } @@ -72,15 +72,15 @@ static void mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) if (!priv->vlgrp) return; - mlx4_dbg(HW, priv, "adding VLAN:%d (vlgrp entry:%p)\n", - vid, vlan_group_get_device(priv->vlgrp, vid)); + en_dbg(HW, priv, "adding VLAN:%d (vlgrp entry:%p)\n", + vid, vlan_group_get_device(priv->vlgrp, vid)); /* Add VID to port VLAN filter */ mutex_lock(&mdev->state_lock); if (mdev->device_up && priv->port_up) { err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); if (err) - mlx4_err(mdev, "Failed configuring VLAN filter\n"); + en_err(priv, "Failed configuring VLAN filter\n"); } mutex_unlock(&mdev->state_lock); } @@ -94,9 +94,8 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) if (!priv->vlgrp) return; - mlx4_dbg(HW, priv, "Killing VID:%d (vlgrp:%p vlgrp " - "entry:%p)\n", vid, priv->vlgrp, - vlan_group_get_device(priv->vlgrp, vid)); + en_dbg(HW, priv, "Killing VID:%d (vlgrp:%p vlgrp entry:%p)\n", + vid, priv->vlgrp, vlan_group_get_device(priv->vlgrp, vid)); vlan_group_set_device(priv->vlgrp, vid, NULL); /* Remove VID from port VLAN filter */ @@ -104,7 +103,7 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) if (mdev->device_up && priv->port_up) { err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); if (err) - mlx4_err(mdev, "Failed configuring VLAN filter\n"); + en_err(priv, "Failed configuring VLAN filter\n"); } mutex_unlock(&mdev->state_lock); } @@ -150,9 +149,10 @@ static void mlx4_en_do_set_mac(struct work_struct *work) err = mlx4_register_mac(mdev->dev, priv->port, priv->mac, &priv->mac_index); if (err) - mlx4_err(mdev, "Failed changing HW MAC address\n"); + en_err(priv, "Failed changing HW MAC address\n"); } else - mlx4_dbg(HW, priv, "Port is down, exiting...\n"); + en_dbg(HW, priv, "Port is down while " + "registering mac, exiting...\n"); mutex_unlock(&mdev->state_lock); } @@ -174,7 +174,6 @@ static void mlx4_en_clear_list(struct net_device *dev) static void mlx4_en_cache_mclist(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; struct dev_mc_list *mclist; struct dev_mc_list *tmp; struct dev_mc_list *plist = NULL; @@ -182,7 +181,7 @@ static void mlx4_en_cache_mclist(struct net_device *dev) for (mclist = dev->mc_list; mclist; mclist = mclist->next) { tmp = kmalloc(sizeof(struct dev_mc_list), GFP_ATOMIC); if (!tmp) { - mlx4_err(mdev, "failed to allocate multicast list\n"); + en_err(priv, "failed to allocate multicast list\n"); mlx4_en_clear_list(dev); return; } @@ -219,13 +218,13 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) mutex_lock(&mdev->state_lock); if (!mdev->device_up) { - mlx4_dbg(HW, priv, "Card is not up, ignoring " - "multicast change.\n"); + en_dbg(HW, priv, "Card is not up, " + "ignoring multicast change.\n"); goto out; } if (!priv->port_up) { - mlx4_dbg(HW, priv, "Port is down, ignoring " - "multicast change.\n"); + en_dbg(HW, priv, "Port is down, " + "ignoring multicast change.\n"); goto out; } @@ -236,29 +235,27 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) if (dev->flags & IFF_PROMISC) { if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) { if (netif_msg_rx_status(priv)) - mlx4_warn(mdev, "Port:%d entering promiscuous mode\n", - priv->port); + en_warn(priv, "Entering promiscuous mode\n"); priv->flags |= MLX4_EN_FLAG_PROMISC; /* Enable promiscouos mode */ err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 1); if (err) - mlx4_err(mdev, "Failed enabling " - "promiscous mode\n"); + en_err(priv, "Failed enabling " + "promiscous mode\n"); /* Disable port multicast filter (unconditionally) */ err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_DISABLE); if (err) - mlx4_err(mdev, "Failed disabling " - "multicast filter\n"); + en_err(priv, "Failed disabling " + "multicast filter\n"); /* Disable port VLAN filter */ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL); if (err) - mlx4_err(mdev, "Failed disabling " - "VLAN filter\n"); + en_err(priv, "Failed disabling VLAN filter\n"); } goto out; } @@ -269,20 +266,19 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) if (priv->flags & MLX4_EN_FLAG_PROMISC) { if (netif_msg_rx_status(priv)) - mlx4_warn(mdev, "Port:%d leaving promiscuous mode\n", - priv->port); + en_warn(priv, "Leaving promiscuous mode\n"); priv->flags &= ~MLX4_EN_FLAG_PROMISC; /* Disable promiscouos mode */ err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); if (err) - mlx4_err(mdev, "Failed disabling promiscous mode\n"); + en_err(priv, "Failed disabling promiscous mode\n"); /* Enable port VLAN filter */ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); if (err) - mlx4_err(mdev, "Failed enabling VLAN filter\n"); + en_err(priv, "Failed enabling VLAN filter\n"); } /* Enable/disable the multicast filter according to IFF_ALLMULTI */ @@ -290,12 +286,12 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_DISABLE); if (err) - mlx4_err(mdev, "Failed disabling multicast filter\n"); + en_err(priv, "Failed disabling multicast filter\n"); } else { err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_DISABLE); if (err) - mlx4_err(mdev, "Failed disabling multicast filter\n"); + en_err(priv, "Failed disabling multicast filter\n"); /* Flush mcast filter and init it with broadcast address */ mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, @@ -314,7 +310,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_ENABLE); if (err) - mlx4_err(mdev, "Failed enabling multicast filter\n"); + en_err(priv, "Failed enabling multicast filter\n"); mlx4_en_clear_list(dev); } @@ -346,10 +342,10 @@ static void mlx4_en_tx_timeout(struct net_device *dev) struct mlx4_en_dev *mdev = priv->mdev; if (netif_msg_timer(priv)) - mlx4_warn(mdev, "Tx timeout called on port:%d\n", priv->port); + en_warn(priv, "Tx timeout called on port:%d\n", priv->port); priv->port_stats.tx_timeout++; - mlx4_dbg(DRV, priv, "Scheduling watchdog\n"); + en_dbg(DRV, priv, "Scheduling watchdog\n"); queue_work(mdev->workqueue, &priv->watchdog_task); } @@ -376,10 +372,10 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) * satisfy our coelsing target. * - moder_time is set to a fixed value. */ - priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->mtu + 1; + priv->rx_frames = MLX4_EN_RX_COAL_TARGET; priv->rx_usecs = MLX4_EN_RX_COAL_TIME; - mlx4_dbg(INTR, priv, "Default coalesing params for mtu:%d - " - "rx_frames:%d rx_usecs:%d\n", + en_dbg(INTR, priv, "Default coalesing params for mtu:%d - " + "rx_frames:%d rx_usecs:%d\n", priv->dev->mtu, priv->rx_frames, priv->rx_usecs); /* Setup cq moderation params */ @@ -412,7 +408,6 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) { unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies); - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_cq *cq; unsigned long packets; unsigned long rate; @@ -472,11 +467,11 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) moder_time = priv->rx_usecs; } - mlx4_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n", - tx_pkt_diff * HZ / period, rx_pkt_diff * HZ / period); + en_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n", + tx_pkt_diff * HZ / period, rx_pkt_diff * HZ / period); - mlx4_dbg(INTR, priv, "Rx moder_time changed from:%d to %d period:%lu " - "[jiff] packets:%lu avg_pkt_size:%lu rate:%lu [p/s])\n", + en_dbg(INTR, priv, "Rx moder_time changed from:%d to %d period:%lu " + "[jiff] packets:%lu avg_pkt_size:%lu rate:%lu [p/s])\n", priv->last_moder_time, moder_time, period, packets, avg_pkt_size, rate); @@ -487,8 +482,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) cq->moder_time = moder_time; err = mlx4_en_set_cq_moder(priv, cq); if (err) { - mlx4_err(mdev, "Failed modifying moderation for cq:%d " - "on port:%d\n", i, priv->port); + en_err(priv, "Failed modifying moderation for cq:%d\n", i); break; } } @@ -511,8 +505,7 @@ static void mlx4_en_do_get_stats(struct work_struct *work) err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0); if (err) - mlx4_dbg(HW, priv, "Could not update stats for " - "port:%d\n", priv->port); + en_dbg(HW, priv, "Could not update stats \n"); mutex_lock(&mdev->state_lock); if (mdev->device_up) { @@ -536,12 +529,10 @@ static void mlx4_en_linkstate(struct work_struct *work) * report to system log */ if (priv->last_link_state != linkstate) { if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) { - if (netif_msg_link(priv)) - mlx4_info(mdev, "Port %d - link down\n", priv->port); + en_dbg(LINK, priv, "Link Down\n"); netif_carrier_off(priv->dev); } else { - if (netif_msg_link(priv)) - mlx4_info(mdev, "Port %d - link up\n", priv->port); + en_dbg(LINK, priv, "Link Up\n"); netif_carrier_on(priv->dev); } } @@ -563,19 +554,19 @@ int mlx4_en_start_port(struct net_device *dev) int j; if (priv->port_up) { - mlx4_dbg(DRV, priv, "start port called while port already up\n"); + en_dbg(DRV, priv, "start port called while port already up\n"); return 0; } /* Calculate Rx buf size */ dev->mtu = min(dev->mtu, priv->max_mtu); mlx4_en_calc_rx_buf(dev); - mlx4_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size); + en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size); /* Configure rx cq's and rings */ err = mlx4_en_activate_rx_rings(priv); if (err) { - mlx4_err(mdev, "Failed to activate RX rings\n"); + en_err(priv, "Failed to activate RX rings\n"); return err; } for (i = 0; i < priv->rx_ring_num; i++) { @@ -583,14 +574,14 @@ int mlx4_en_start_port(struct net_device *dev) err = mlx4_en_activate_cq(priv, cq); if (err) { - mlx4_err(mdev, "Failed activating Rx CQ\n"); + en_err(priv, "Failed activating Rx CQ\n"); goto cq_err; } for (j = 0; j < cq->size; j++) cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK; err = mlx4_en_set_cq_moder(priv, cq); if (err) { - mlx4_err(mdev, "Failed setting cq moderation parameters"); + en_err(priv, "Failed setting cq moderation parameters"); mlx4_en_deactivate_cq(priv, cq); goto cq_err; } @@ -601,7 +592,7 @@ int mlx4_en_start_port(struct net_device *dev) err = mlx4_en_config_rss_steer(priv); if (err) { - mlx4_err(mdev, "Failed configuring rss steering\n"); + en_err(priv, "Failed configuring rss steering\n"); goto cq_err; } @@ -611,16 +602,16 @@ int mlx4_en_start_port(struct net_device *dev) cq = &priv->tx_cq[i]; err = mlx4_en_activate_cq(priv, cq); if (err) { - mlx4_err(mdev, "Failed allocating Tx CQ\n"); + en_err(priv, "Failed allocating Tx CQ\n"); goto tx_err; } err = mlx4_en_set_cq_moder(priv, cq); if (err) { - mlx4_err(mdev, "Failed setting cq moderation parameters"); + en_err(priv, "Failed setting cq moderation parameters"); mlx4_en_deactivate_cq(priv, cq); goto tx_err; } - mlx4_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i); + en_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i); cq->buf->wqe_index = cpu_to_be16(0xffff); /* Configure ring */ @@ -628,7 +619,7 @@ int mlx4_en_start_port(struct net_device *dev) err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn, priv->rx_ring[0].srq.srqn); if (err) { - mlx4_err(mdev, "Failed allocating Tx ring\n"); + en_err(priv, "Failed allocating Tx ring\n"); mlx4_en_deactivate_cq(priv, cq); goto tx_err; } @@ -646,30 +637,30 @@ int mlx4_en_start_port(struct net_device *dev) priv->prof->rx_pause, priv->prof->rx_ppp); if (err) { - mlx4_err(mdev, "Failed setting port general configurations" - " for port %d, with error %d\n", priv->port, err); + en_err(priv, "Failed setting port general configurations " + "for port %d, with error %d\n", priv->port, err); goto tx_err; } /* Set default qp number */ err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); if (err) { - mlx4_err(mdev, "Failed setting default qp numbers\n"); + en_err(priv, "Failed setting default qp numbers\n"); goto tx_err; } /* Set port mac number */ - mlx4_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); + en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); err = mlx4_register_mac(mdev->dev, priv->port, priv->mac, &priv->mac_index); if (err) { - mlx4_err(mdev, "Failed setting port mac\n"); + en_err(priv, "Failed setting port mac\n"); goto tx_err; } /* Init port */ - mlx4_dbg(HW, priv, "Initializing port\n"); + en_dbg(HW, priv, "Initializing port\n"); err = mlx4_INIT_PORT(mdev->dev, priv->port); if (err) { - mlx4_err(mdev, "Failed Initializing port\n"); + en_err(priv, "Failed Initializing port\n"); goto mac_err; } @@ -706,8 +697,7 @@ void mlx4_en_stop_port(struct net_device *dev) int i; if (!priv->port_up) { - mlx4_dbg(DRV, priv, "stop port (%d) called while port already down\n", - priv->port); + en_dbg(DRV, priv, "stop port called while port already down\n"); return; } netif_stop_queue(dev); @@ -752,13 +742,13 @@ static void mlx4_en_restart(struct work_struct *work) struct mlx4_en_dev *mdev = priv->mdev; struct net_device *dev = priv->dev; - mlx4_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); + en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); mutex_lock(&mdev->state_lock); if (priv->port_up) { mlx4_en_stop_port(dev); if (mlx4_en_start_port(dev)) - mlx4_err(mdev, "Failed restarting port %d\n", priv->port); + en_err(priv, "Failed restarting port %d\n", priv->port); } mutex_unlock(&mdev->state_lock); } @@ -774,14 +764,14 @@ static int mlx4_en_open(struct net_device *dev) mutex_lock(&mdev->state_lock); if (!mdev->device_up) { - mlx4_err(mdev, "Cannot open - device down/disabled\n"); + en_err(priv, "Cannot open - device down/disabled\n"); err = -EBUSY; goto out; } /* Reset HW statistics and performance counters */ if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) - mlx4_dbg(HW, priv, "Failed dumping statistics\n"); + en_dbg(HW, priv, "Failed dumping statistics\n"); memset(&priv->stats, 0, sizeof(priv->stats)); memset(&priv->pstats, 0, sizeof(priv->pstats)); @@ -798,7 +788,7 @@ static int mlx4_en_open(struct net_device *dev) mlx4_en_set_default_moderation(priv); err = mlx4_en_start_port(dev); if (err) - mlx4_err(mdev, "Failed starting port:%d\n", priv->port); + en_err(priv, "Failed starting port:%d\n", priv->port); out: mutex_unlock(&mdev->state_lock); @@ -811,8 +801,7 @@ static int mlx4_en_close(struct net_device *dev) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; - if (netif_msg_ifdown(priv)) - mlx4_info(mdev, "Close called for port:%d\n", priv->port); + en_dbg(IFDOWN, priv, "Close port called\n"); mutex_lock(&mdev->state_lock); @@ -844,7 +833,6 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv) int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) { - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_port_profile *prof = priv->prof; int i; @@ -873,7 +861,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) return 0; err: - mlx4_err(mdev, "Failed to allocate NIC resources\n"); + en_err(priv, "Failed to allocate NIC resources\n"); return -ENOMEM; } @@ -883,7 +871,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; - mlx4_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); + en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); /* Unregister device - this will close the port if it was up */ if (priv->registered) @@ -912,11 +900,11 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) struct mlx4_en_dev *mdev = priv->mdev; int err = 0; - mlx4_dbg(DRV, priv, "Change MTU called - current:%d new:%d\n", + en_dbg(DRV, priv, "Change MTU called - current:%d new:%d\n", dev->mtu, new_mtu); if ((new_mtu < MLX4_EN_MIN_MTU) || (new_mtu > priv->max_mtu)) { - mlx4_err(mdev, "Bad MTU size:%d.\n", new_mtu); + en_err(priv, "Bad MTU size:%d.\n", new_mtu); return -EPERM; } dev->mtu = new_mtu; @@ -926,13 +914,13 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) if (!mdev->device_up) { /* NIC is probably restarting - let watchdog task reset * the port */ - mlx4_dbg(DRV, priv, "Change MTU called with card down!?\n"); + en_dbg(DRV, priv, "Change MTU called with card down!?\n"); } else { mlx4_en_stop_port(dev); mlx4_en_set_default_moderation(priv); err = mlx4_en_start_port(dev); if (err) { - mlx4_err(mdev, "Failed restarting port:%d\n", + en_err(priv, "Failed restarting port:%d\n", priv->port); queue_work(mdev->workqueue, &priv->watchdog_task); } @@ -946,6 +934,7 @@ static const struct net_device_ops mlx4_netdev_ops = { .ndo_open = mlx4_en_open, .ndo_stop = mlx4_en_close, .ndo_start_xmit = mlx4_en_xmit, + .ndo_select_queue = mlx4_en_select_queue, .ndo_get_stats = mlx4_en_get_stats, .ndo_set_multicast_list = mlx4_en_set_multicast, .ndo_set_mac_address = mlx4_en_set_mac, @@ -968,7 +957,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, int i; int err; - dev = alloc_etherdev(sizeof(struct mlx4_en_priv)); + dev = alloc_etherdev_mq(sizeof(struct mlx4_en_priv), prof->tx_ring_num); if (dev == NULL) { mlx4_err(mdev, "Net device allocation failed\n"); return -ENOMEM; @@ -1006,7 +995,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; priv->mac = mdev->dev->caps.def_mac[priv->port]; if (ILLEGAL_MAC(priv->mac)) { - mlx4_err(mdev, "Port: %d, invalid mac burned: 0x%llx, quiting\n", + en_err(priv, "Port: %d, invalid mac burned: 0x%llx, quiting\n", priv->port, priv->mac); err = -EINVAL; goto out; @@ -1025,19 +1014,17 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); if (err) { - mlx4_err(mdev, "Failed to allocate page for rx qps\n"); + en_err(priv, "Failed to allocate page for rx qps\n"); goto out; } priv->allocated = 1; - /* Populate Tx priority mappings */ - mlx4_en_set_prio_map(priv, priv->tx_prio_map, prof->tx_ring_num); - /* * Initialize netdev entry points */ dev->netdev_ops = &mlx4_netdev_ops; dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT; + dev->real_num_tx_queues = MLX4_EN_NUM_TX_RINGS; SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops); @@ -1051,7 +1038,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, * Set driver features */ dev->features |= NETIF_F_SG; + dev->vlan_features |= NETIF_F_SG; dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; dev->features |= NETIF_F_HIGHDMA; dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | @@ -1061,6 +1050,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, if (mdev->LSO_support) { dev->features |= NETIF_F_TSO; dev->features |= NETIF_F_TSO6; + dev->vlan_features |= NETIF_F_TSO; + dev->vlan_features |= NETIF_F_TSO6; } mdev->pndev[port] = dev; @@ -1068,9 +1059,13 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, netif_carrier_off(dev); err = register_netdev(dev); if (err) { - mlx4_err(mdev, "Netdev registration failed\n"); + en_err(priv, "Netdev registration failed for port %d\n", port); goto out; } + + en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); + en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); + priv->registered = 1; queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); return 0; diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 6bfab6e5ba1d..5a14899c1e25 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -114,8 +114,8 @@ static int mlx4_en_init_allocator(struct mlx4_en_priv *priv, goto out; page_alloc->offset = priv->frag_info[i].frag_align; - mlx4_dbg(DRV, priv, "Initialized allocator:%d with page:%p\n", - i, page_alloc->page); + en_dbg(DRV, priv, "Initialized allocator:%d with page:%p\n", + i, page_alloc->page); } return 0; @@ -136,8 +136,8 @@ static void mlx4_en_destroy_allocator(struct mlx4_en_priv *priv, for (i = 0; i < priv->num_frags; i++) { page_alloc = &ring->page_alloc[i]; - mlx4_dbg(DRV, priv, "Freeing allocator:%d count:%d\n", - i, page_count(page_alloc->page)); + en_dbg(DRV, priv, "Freeing allocator:%d count:%d\n", + i, page_count(page_alloc->page)); put_page(page_alloc->page); page_alloc->page = NULL; @@ -214,10 +214,10 @@ static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv, skb_frags = ring->rx_info + (index << priv->log_rx_info); for (nr = 0; nr < priv->num_frags; nr++) { - mlx4_dbg(DRV, priv, "Freeing fragment:%d\n", nr); + en_dbg(DRV, priv, "Freeing fragment:%d\n", nr); dma = be64_to_cpu(rx_desc->data[nr].addr); - mlx4_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma); + en_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma); pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size, PCI_DMA_FROMDEVICE); put_page(skb_frags[nr].page); @@ -226,7 +226,6 @@ static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv, static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) { - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_rx_ring *ring; int ring_ind; int buf_ind; @@ -239,14 +238,14 @@ static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) if (mlx4_en_prepare_rx_desc(priv, ring, ring->actual_size)) { if (ring->actual_size < MLX4_EN_MIN_RX_SIZE) { - mlx4_err(mdev, "Failed to allocate " - "enough rx buffers\n"); + en_err(priv, "Failed to allocate " + "enough rx buffers\n"); return -ENOMEM; } else { new_size = rounddown_pow_of_two(ring->actual_size); - mlx4_warn(mdev, "Only %d buffers allocated " - "reducing ring size to %d", - ring->actual_size, new_size); + en_warn(priv, "Only %d buffers allocated " + "reducing ring size to %d", + ring->actual_size, new_size); goto reduce_rings; } } @@ -282,8 +281,7 @@ static int mlx4_en_fill_rx_buf(struct net_device *dev, ring->size_mask); if (err) { if (netif_msg_rx_err(priv)) - mlx4_warn(priv->mdev, - "Failed preparing rx descriptor\n"); + en_warn(priv, "Failed preparing rx descriptor\n"); priv->port_stats.rx_alloc_failed++; break; } @@ -301,14 +299,14 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv, { int index; - mlx4_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n", - ring->cons, ring->prod); + en_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n", + ring->cons, ring->prod); /* Unmap and free Rx buffers */ BUG_ON((u32) (ring->prod - ring->cons) > ring->actual_size); while (ring->cons != ring->prod) { index = ring->cons & ring->size_mask; - mlx4_dbg(DRV, priv, "Processing descriptor:%d\n", index); + en_dbg(DRV, priv, "Processing descriptor:%d\n", index); mlx4_en_free_rx_desc(priv, ring, index); ++ring->cons; } @@ -373,10 +371,10 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, sizeof(struct skb_frag_struct)); ring->rx_info = vmalloc(tmp); if (!ring->rx_info) { - mlx4_err(mdev, "Failed allocating rx_info ring\n"); + en_err(priv, "Failed allocating rx_info ring\n"); return -ENOMEM; } - mlx4_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d\n", + en_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d\n", ring->rx_info, tmp); err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, @@ -386,7 +384,7 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, err = mlx4_en_map_buffer(&ring->wqres.buf); if (err) { - mlx4_err(mdev, "Failed to map RX buffer\n"); + en_err(priv, "Failed to map RX buffer\n"); goto err_hwq; } ring->buf = ring->wqres.buf.direct.buf; @@ -404,7 +402,7 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, sizeof(struct net_lro_desc), GFP_KERNEL); if (!ring->lro.lro_arr) { - mlx4_err(mdev, "Failed to allocate lro array\n"); + en_err(priv, "Failed to allocate lro array\n"); goto err_map; } ring->lro.get_frag_header = mlx4_en_get_frag_header; @@ -455,7 +453,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) /* Initialize page allocators */ err = mlx4_en_init_allocator(priv, ring); if (err) { - mlx4_err(mdev, "Failed initializing ring allocator\n"); + en_err(priv, "Failed initializing ring allocator\n"); ring_ind--; goto err_allocator; } @@ -486,7 +484,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) err = mlx4_srq_alloc(mdev->dev, mdev->priv_pdn, &ring->wqres.mtt, ring->wqres.db.dma, &ring->srq); if (err){ - mlx4_err(mdev, "Failed to allocate srq\n"); + en_err(priv, "Failed to allocate srq\n"); ring_ind--; goto err_srq; } @@ -601,7 +599,7 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv, skb = dev_alloc_skb(SMALL_PACKET_SIZE + NET_IP_ALIGN); if (!skb) { - mlx4_dbg(RX_ERR, priv, "Failed allocating skb\n"); + en_dbg(RX_ERR, priv, "Failed allocating skb\n"); return NULL; } skb->dev = priv->dev; @@ -680,7 +678,6 @@ static void mlx4_en_copy_desc(struct mlx4_en_priv *priv, int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_cqe *cqe; struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring]; struct skb_frag_struct *skb_frags; @@ -717,14 +714,14 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud /* Drop packet on bad receive or bad checksum */ if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == MLX4_CQE_OPCODE_ERROR)) { - mlx4_err(mdev, "CQE completed in error - vendor " + en_err(priv, "CQE completed in error - vendor " "syndrom:%d syndrom:%d\n", ((struct mlx4_err_cqe *) cqe)->vendor_err_syndrome, ((struct mlx4_err_cqe *) cqe)->syndrome); goto next; } if (unlikely(cqe->badfcs_enc & MLX4_CQE_BAD_FCS)) { - mlx4_dbg(RX_ERR, priv, "Accepted frame with bad FCS\n"); + en_dbg(RX_ERR, priv, "Accepted frame with bad FCS\n"); goto next; } @@ -874,7 +871,7 @@ static int mlx4_en_last_alloc_offset(struct mlx4_en_priv *priv, u16 stride, u16 u16 res = MLX4_EN_ALLOC_SIZE % stride; u16 offset = MLX4_EN_ALLOC_SIZE - stride - res + align; - mlx4_dbg(DRV, priv, "Calculated last offset for stride:%d align:%d " + en_dbg(DRV, priv, "Calculated last offset for stride:%d align:%d " "res:%d offset:%d\n", stride, align, res, offset); return offset; } @@ -919,10 +916,10 @@ void mlx4_en_calc_rx_buf(struct net_device *dev) priv->rx_skb_size = eff_mtu; priv->log_rx_info = ROUNDUP_LOG2(i * sizeof(struct skb_frag_struct)); - mlx4_dbg(DRV, priv, "Rx buffer scatter-list (effective-mtu:%d " + en_dbg(DRV, priv, "Rx buffer scatter-list (effective-mtu:%d " "num_frags:%d):\n", eff_mtu, priv->num_frags); for (i = 0; i < priv->num_frags; i++) { - mlx4_dbg(DRV, priv, " frag:%d - size:%d prefix:%d align:%d " + en_dbg(DRV, priv, " frag:%d - size:%d prefix:%d align:%d " "stride:%d last_offset:%d\n", i, priv->frag_info[i].frag_size, priv->frag_info[i].frag_prefix_size, @@ -942,12 +939,12 @@ void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv, int i; rss_map->size = roundup_pow_of_two(num_entries); - mlx4_dbg(DRV, priv, "Setting default RSS map of %d entires\n", - rss_map->size); + en_dbg(DRV, priv, "Setting default RSS map of %d entires\n", + rss_map->size); for (i = 0; i < rss_map->size; i++) { rss_map->map[i] = i % num_rings; - mlx4_dbg(DRV, priv, "Entry %d ---> ring %d\n", i, rss_map->map[i]); + en_dbg(DRV, priv, "Entry %d ---> ring %d\n", i, rss_map->map[i]); } } @@ -962,13 +959,13 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, context = kmalloc(sizeof *context , GFP_KERNEL); if (!context) { - mlx4_err(mdev, "Failed to allocate qp context\n"); + en_err(priv, "Failed to allocate qp context\n"); return -ENOMEM; } err = mlx4_qp_alloc(mdev->dev, qpn, qp); if (err) { - mlx4_err(mdev, "Failed to allocate qp #%d\n", qpn); + en_err(priv, "Failed to allocate qp #%x\n", qpn); goto out; } qp->event = mlx4_en_sqp_event; @@ -1000,12 +997,11 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) int err = 0; int good_qps = 0; - mlx4_dbg(DRV, priv, "Configuring rss steering for port %u\n", priv->port); + en_dbg(DRV, priv, "Configuring rss steering\n"); err = mlx4_qp_reserve_range(mdev->dev, rss_map->size, rss_map->size, &rss_map->base_qpn); if (err) { - mlx4_err(mdev, "Failed reserving %d qps for port %u\n", - rss_map->size, priv->port); + en_err(priv, "Failed reserving %d qps\n", rss_map->size); return err; } @@ -1025,13 +1021,13 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) /* Configure RSS indirection qp */ err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &priv->base_qpn); if (err) { - mlx4_err(mdev, "Failed to reserve range for RSS " - "indirection qp\n"); + en_err(priv, "Failed to reserve range for RSS " + "indirection qp\n"); goto rss_err; } err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); if (err) { - mlx4_err(mdev, "Failed to allocate RSS indirection QP\n"); + en_err(priv, "Failed to allocate RSS indirection QP\n"); goto reserve_err; } rss_map->indir_qp.event = mlx4_en_sqp_event; diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index ac6fc499b280..5dc7466ad035 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -68,15 +68,15 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, tmp = size * sizeof(struct mlx4_en_tx_info); ring->tx_info = vmalloc(tmp); if (!ring->tx_info) { - mlx4_err(mdev, "Failed allocating tx_info ring\n"); + en_err(priv, "Failed allocating tx_info ring\n"); return -ENOMEM; } - mlx4_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n", + en_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n", ring->tx_info, tmp); ring->bounce_buf = kmalloc(MAX_DESC_SIZE, GFP_KERNEL); if (!ring->bounce_buf) { - mlx4_err(mdev, "Failed allocating bounce buffer\n"); + en_err(priv, "Failed allocating bounce buffer\n"); err = -ENOMEM; goto err_tx; } @@ -85,31 +85,31 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size, 2 * PAGE_SIZE); if (err) { - mlx4_err(mdev, "Failed allocating hwq resources\n"); + en_err(priv, "Failed allocating hwq resources\n"); goto err_bounce; } err = mlx4_en_map_buffer(&ring->wqres.buf); if (err) { - mlx4_err(mdev, "Failed to map TX buffer\n"); + en_err(priv, "Failed to map TX buffer\n"); goto err_hwq_res; } ring->buf = ring->wqres.buf.direct.buf; - mlx4_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d " - "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, - ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); + en_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d " + "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, + ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &ring->qpn); if (err) { - mlx4_err(mdev, "Failed reserving qp for tx ring.\n"); + en_err(priv, "Failed reserving qp for tx ring.\n"); goto err_map; } err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp); if (err) { - mlx4_err(mdev, "Failed allocating qp %d\n", ring->qpn); + en_err(priv, "Failed allocating qp %d\n", ring->qpn); goto err_reserve; } ring->qp.event = mlx4_en_sqp_event; @@ -135,7 +135,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring) { struct mlx4_en_dev *mdev = priv->mdev; - mlx4_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); + en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); mlx4_qp_remove(mdev->dev, &ring->qp); mlx4_qp_free(mdev->dev, &ring->qp); @@ -274,12 +274,12 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) /* Skip last polled descriptor */ ring->cons += ring->last_nr_txbb; - mlx4_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n", + en_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n", ring->cons, ring->prod); if ((u32) (ring->prod - ring->cons) > ring->size) { if (netif_msg_tx_err(priv)) - mlx4_warn(priv->mdev, "Tx consumer passed producer!\n"); + en_warn(priv, "Tx consumer passed producer!\n"); return 0; } @@ -292,39 +292,11 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) } if (cnt) - mlx4_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt); + en_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt); return cnt; } -void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num) -{ - int block = 8 / ring_num; - int extra = 8 - (block * ring_num); - int num = 0; - u16 ring = 1; - int prio; - - if (ring_num == 1) { - for (prio = 0; prio < 8; prio++) - prio_map[prio] = 0; - return; - } - - for (prio = 0; prio < 8; prio++) { - if (extra && (num == block + 1)) { - ring++; - num = 0; - extra--; - } else if (!extra && (num == block)) { - ring++; - num = 0; - } - prio_map[prio] = ring; - mlx4_dbg(DRV, priv, " prio:%d --> ring:%d\n", prio, ring); - num++; - } -} static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) { @@ -386,18 +358,8 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) if (unlikely(ring->blocked)) { if ((u32) (ring->prod - ring->cons) <= ring->size - HEADROOM - MAX_DESC_TXBBS) { - - /* TODO: support multiqueue netdevs. Currently, we block - * when *any* ring is full. Note that: - * - 2 Tx rings can unblock at the same time and call - * netif_wake_queue(), which is OK since this - * operation is idempotent. - * - We might wake the queue just after another ring - * stopped it. This is no big deal because the next - * transmission on that ring would stop the queue. - */ ring->blocked = 0; - netif_wake_queue(dev); + netif_tx_wake_queue(netdev_get_tx_queue(dev, cq->ring)); priv->port_stats.wake_queue++; } } @@ -426,7 +388,7 @@ void mlx4_en_poll_tx_cq(unsigned long data) INC_PERF_COUNTER(priv->pstats.tx_poll); - if (!spin_trylock(&ring->comp_lock)) { + if (!spin_trylock_irq(&ring->comp_lock)) { mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); return; } @@ -439,7 +401,7 @@ void mlx4_en_poll_tx_cq(unsigned long data) if (inflight && priv->port_up) mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); - spin_unlock(&ring->comp_lock); + spin_unlock_irq(&ring->comp_lock); } static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv, @@ -482,9 +444,9 @@ static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind) /* Poll the CQ every mlx4_en_TX_MODER_POLL packets */ if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0) - if (spin_trylock(&ring->comp_lock)) { + if (spin_trylock_irq(&ring->comp_lock)) { mlx4_en_process_tx_cq(priv->dev, cq); - spin_unlock(&ring->comp_lock); + spin_unlock_irq(&ring->comp_lock); } } @@ -539,7 +501,6 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev, int *lso_header_size) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; int real_size; if (skb_is_gso(skb)) { @@ -553,14 +514,14 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev, real_size += DS_SIZE; else { if (netif_msg_tx_err(priv)) - mlx4_warn(mdev, "Non-linear headers\n"); + en_warn(priv, "Non-linear headers\n"); dev_kfree_skb_any(skb); return 0; } } if (unlikely(*lso_header_size > MAX_LSO_HDR_SIZE)) { if (netif_msg_tx_err(priv)) - mlx4_warn(mdev, "LSO header size too big\n"); + en_warn(priv, "LSO header size too big\n"); dev_kfree_skb_any(skb); return 0; } @@ -617,21 +578,20 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f; } -static int get_vlan_info(struct mlx4_en_priv *priv, struct sk_buff *skb, - u16 *vlan_tag) +u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb) { - int tx_ind; + struct mlx4_en_priv *priv = netdev_priv(dev); + u16 vlan_tag = 0; - /* Obtain VLAN information if present */ - if (priv->vlgrp && vlan_tx_tag_present(skb)) { - *vlan_tag = vlan_tx_tag_get(skb); - /* Set the Tx ring to use according to vlan priority */ - tx_ind = priv->tx_prio_map[*vlan_tag >> 13]; - } else { - *vlan_tag = 0; - tx_ind = 0; + /* If we support per priority flow control and the packet contains + * a vlan tag, send the packet to the TX ring assigned to that priority + */ + if (priv->prof->rx_ppp && priv->vlgrp && vlan_tx_tag_present(skb)) { + vlan_tag = vlan_tx_tag_get(skb); + return MLX4_EN_NUM_TX_RINGS + (vlan_tag >> 13); } - return tx_ind; + + return skb_tx_hash(dev, skb); } int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) @@ -651,7 +611,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) dma_addr_t dma; u32 index; __be32 op_own; - u16 vlan_tag; + u16 vlan_tag = 0; int i; int lso_header_size; void *fragptr; @@ -669,20 +629,21 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) nr_txbb = desc_size / TXBB_SIZE; if (unlikely(nr_txbb > MAX_DESC_TXBBS)) { if (netif_msg_tx_err(priv)) - mlx4_warn(mdev, "Oversized header or SG list\n"); + en_warn(priv, "Oversized header or SG list\n"); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } - tx_ind = get_vlan_info(priv, skb, &vlan_tag); + tx_ind = skb->queue_mapping; ring = &priv->tx_ring[tx_ind]; + if (priv->vlgrp && vlan_tx_tag_present(skb)) + vlan_tag = vlan_tx_tag_get(skb); /* Check available TXBBs And 2K spare for prefetch */ if (unlikely(((int)(ring->prod - ring->cons)) > ring->size - HEADROOM - MAX_DESC_TXBBS)) { - /* every full Tx ring stops queue. - * TODO: implement multi-queue support (per-queue stop) */ - netif_stop_queue(dev); + /* every full Tx ring stops queue */ + netif_tx_stop_queue(netdev_get_tx_queue(dev, tx_ind)); ring->blocked = 1; priv->port_stats.queue_stopped++; @@ -695,7 +656,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Now that we know what Tx ring to use */ if (unlikely(!priv->port_up)) { if (netif_msg_tx_err(priv)) - mlx4_warn(mdev, "xmit: port down!\n"); + en_warn(priv, "xmit: port down!\n"); dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -819,7 +780,6 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Ring doorbell! */ wmb(); writel(ring->doorbell_qpn, mdev->uar_map + MLX4_SEND_DOORBELL); - dev->trans_start = jiffies; /* Poll CQ here */ mlx4_en_xmit_poll(priv, tx_ind); diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 8830dcb92ec8..dee188761a3c 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -623,8 +623,10 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE, (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, &priv->eq_table.eq[i]); - if (err) + if (err) { + --i; goto err_out_unmap; + } } err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE, diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index ef840abbcd39..d43a9e4c2aea 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -49,26 +49,42 @@ #include "en_port.h" #define DRV_NAME "mlx4_en" -#define DRV_VERSION "1.4.0" -#define DRV_RELDATE "Sep 2008" +#define DRV_VERSION "1.4.1.1" +#define DRV_RELDATE "June 2009" #define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) -#define mlx4_dbg(mlevel, priv, format, arg...) \ - if (NETIF_MSG_##mlevel & priv->msg_enable) \ - printk(KERN_DEBUG "%s %s: " format , DRV_NAME ,\ - (dev_name(&priv->mdev->pdev->dev)) , ## arg) +#define en_print(level, priv, format, arg...) \ + { \ + if ((priv)->registered) \ + printk(level "%s: %s: " format, DRV_NAME, \ + (priv->dev)->name, ## arg); \ + else \ + printk(level "%s: %s: Port %d: " format, \ + DRV_NAME, dev_name(&priv->mdev->pdev->dev), \ + (priv)->port, ## arg); \ + } + +#define en_dbg(mlevel, priv, format, arg...) \ + { \ + if (NETIF_MSG_##mlevel & priv->msg_enable) \ + en_print(KERN_DEBUG, priv, format, ## arg) \ + } +#define en_warn(priv, format, arg...) \ + en_print(KERN_WARNING, priv, format, ## arg) +#define en_err(priv, format, arg...) \ + en_print(KERN_ERR, priv, format, ## arg) #define mlx4_err(mdev, format, arg...) \ printk(KERN_ERR "%s %s: " format , DRV_NAME ,\ - (dev_name(&mdev->pdev->dev)) , ## arg) + dev_name(&mdev->pdev->dev) , ## arg) #define mlx4_info(mdev, format, arg...) \ printk(KERN_INFO "%s %s: " format , DRV_NAME ,\ - (dev_name(&mdev->pdev->dev)) , ## arg) + dev_name(&mdev->pdev->dev) , ## arg) #define mlx4_warn(mdev, format, arg...) \ printk(KERN_WARNING "%s %s: " format , DRV_NAME ,\ - (dev_name(&mdev->pdev->dev)) , ## arg) + dev_name(&mdev->pdev->dev) , ## arg) /* * Device constants @@ -123,12 +139,14 @@ enum { #define MLX4_EN_MIN_RX_SIZE (MLX4_EN_ALLOC_SIZE / SMP_CACHE_BYTES) #define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE) -#define MLX4_EN_TX_RING_NUM 9 -#define MLX4_EN_DEF_TX_RING_SIZE 1024 +#define MLX4_EN_SMALL_PKT_SIZE 64 +#define MLX4_EN_NUM_TX_RINGS 8 +#define MLX4_EN_NUM_PPP_RINGS 8 +#define MLX4_EN_DEF_TX_RING_SIZE 512 #define MLX4_EN_DEF_RX_RING_SIZE 1024 -/* Target number of bytes to coalesce with interrupt moderation */ -#define MLX4_EN_RX_COAL_TARGET 0x20000 +/* Target number of packets to coalesce with interrupt moderation */ +#define MLX4_EN_RX_COAL_TARGET 44 #define MLX4_EN_RX_COAL_TIME 0x10 #define MLX4_EN_TX_COAL_PKTS 5 @@ -462,7 +480,6 @@ struct mlx4_en_priv { int base_qpn; struct mlx4_en_rss_map rss_map; - u16 tx_prio_map[8]; u32 flags; #define MLX4_EN_FLAG_PROMISC 0x1 u32 tx_ring_num; @@ -500,8 +517,6 @@ void mlx4_en_stop_port(struct net_device *dev); void mlx4_en_free_resources(struct mlx4_en_priv *priv); int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); -int mlx4_en_get_profile(struct mlx4_en_dev *mdev); - int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, int entries, int ring, enum cq_type mode); void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); @@ -512,6 +527,7 @@ int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); void mlx4_en_poll_tx_cq(unsigned long data); void mlx4_en_tx_irq(struct mlx4_cq *mcq); +u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb); int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, @@ -546,7 +562,6 @@ void mlx4_en_calc_rx_buf(struct net_device *dev); void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv, struct mlx4_en_rss_map *rss_map, int num_entries, int num_rings); -void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num); int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv); void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv); int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring); diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 0caf74cae8bc..0a467785f065 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -402,7 +402,8 @@ static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, for (i = 0; i < npages; ++i) mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - dma_sync_single(&dev->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE); + dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle, + npages * sizeof (u64), DMA_TO_DEVICE); return 0; } @@ -549,8 +550,8 @@ int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list for (i = 0; i < npages; ++i) fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - dma_sync_single(&dev->pdev->dev, fmr->dma_handle, - npages * sizeof(u64), DMA_TO_DEVICE); + dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle, + npages * sizeof(u64), DMA_TO_DEVICE); fmr->mpt->key = cpu_to_be32(key); fmr->mpt->lkey = cpu_to_be32(key); diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 1361ddc8d31f..b4e18a58cb1b 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -55,6 +55,7 @@ #include <linux/types.h> #include <linux/inet_lro.h> #include <asm/system.h> +#include <linux/list.h> static char mv643xx_eth_driver_name[] = "mv643xx_eth"; static char mv643xx_eth_driver_version[] = "1.4"; @@ -1721,20 +1722,20 @@ static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr) static u32 uc_addr_filter_mask(struct net_device *dev) { - struct dev_addr_list *uc_ptr; + struct netdev_hw_addr *ha; u32 nibbles; if (dev->flags & IFF_PROMISC) return 0; nibbles = 1 << (dev->dev_addr[5] & 0x0f); - for (uc_ptr = dev->uc_list; uc_ptr != NULL; uc_ptr = uc_ptr->next) { - if (memcmp(dev->dev_addr, uc_ptr->da_addr, 5)) + list_for_each_entry(ha, &dev->uc_list, list) { + if (memcmp(dev->dev_addr, ha->addr, 5)) return 0; - if ((dev->dev_addr[5] ^ uc_ptr->da_addr[5]) & 0xf0) + if ((dev->dev_addr[5] ^ ha->addr[5]) & 0xf0) return 0; - nibbles |= 1 << (uc_ptr->da_addr[5] & 0x0f); + nibbles |= 1 << (ha->addr[5] & 0x0f); } return nibbles; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 7e28b4610122..c9a30d3a66fb 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2892,7 +2892,6 @@ again: tx->stop_queue++; netif_tx_stop_queue(netdev_queue); } - dev->trans_start = jiffies; return 0; abort_linearize: diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 4a51c31330da..6f77ad58e3b3 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -178,10 +178,8 @@ void netxen_free_sw_resources(struct netxen_adapter *adapter) for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; - if (rds_ring->rx_buf_arr) { - vfree(rds_ring->rx_buf_arr); - rds_ring->rx_buf_arr = NULL; - } + vfree(rds_ring->rx_buf_arr); + rds_ring->rx_buf_arr = NULL; } kfree(recv_ctx->rds_rings); @@ -190,8 +188,7 @@ skip_rds: return; tx_ring = adapter->tx_ring; - if (tx_ring->cmd_buf_arr) - vfree(tx_ring->cmd_buf_arr); + vfree(tx_ring->cmd_buf_arr); } int netxen_alloc_sw_resources(struct netxen_adapter *adapter) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 50477f5c3ecb..98737ef72936 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1496,7 +1496,6 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) netxen_nic_update_cmd_producer(adapter, tx_ring, producer); adapter->stats.xmitcalled++; - netdev->trans_start = jiffies; return NETDEV_TX_OK; diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 0d9de5ac4130..fa61a12c5e15 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -22,6 +22,7 @@ #include <linux/log2.h> #include <linux/jiffies.h> #include <linux/crc32.h> +#include <linux/list.h> #include <linux/io.h> @@ -6362,6 +6363,7 @@ static void niu_set_rx_mode(struct net_device *dev) struct niu *np = netdev_priv(dev); int i, alt_cnt, err; struct dev_addr_list *addr; + struct netdev_hw_addr *ha; unsigned long flags; u16 hash[16] = { 0, }; @@ -6383,9 +6385,8 @@ static void niu_set_rx_mode(struct net_device *dev) if (alt_cnt) { int index = 0; - for (addr = dev->uc_list; addr; addr = addr->next) { - err = niu_set_alt_mac(np, index, - addr->da_addr); + list_for_each_entry(ha, &dev->uc_list, list) { + err = niu_set_alt_mac(np, index, ha->addr); if (err) printk(KERN_WARNING PFX "%s: Error %d " "adding alt mac %d\n", @@ -6777,8 +6778,6 @@ static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_tx_wake_queue(txq); } - dev->trans_start = jiffies; - out: return NETDEV_TX_OK; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index d531614a90b5..940962ae8f23 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1204,9 +1204,7 @@ again: if (stopped && (dev->tx_done_idx != tx_done_idx) && start_tx_okay(dev)) netif_start_queue(ndev); - /* set the transmit start time to catch transmit timeouts */ - ndev->trans_start = jiffies; - return 0; + return NETDEV_TX_OK; } static void ns83820_update_stats(struct ns83820 *dev) @@ -1626,7 +1624,7 @@ static void ns83820_tx_watch(unsigned long data) ); #endif - if (time_after(jiffies, ndev->trans_start + 1*HZ) && + if (time_after(jiffies, dev_trans_start(ndev) + 1*HZ) && dev->tx_done_idx != dev->tx_free_idx) { printk(KERN_DEBUG "%s: ns83820_tx_watch: %u %u %d\n", ndev->name, diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 7a3ec9d39a9a..dd6f54d1b495 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -243,6 +243,7 @@ static int m88e1111_config_init(struct phy_device *phydev) temp &= ~(MII_M1111_HWCFG_MODE_MASK); temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; + temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); if (err < 0) diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 5981debcde5e..e7935d09c896 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -433,8 +433,7 @@ static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct s * to the inner packet either */ secpath_reset(skb); - dst_release(skb->dst); - skb->dst = NULL; + skb_dst_drop(skb); nf_reset(skb); po = pppox_sk(session_sock); @@ -976,7 +975,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh /* Calculate UDP checksum if configured to do so */ if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) skb->ip_summed = CHECKSUM_NONE; - else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) { + else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) { skb->ip_summed = CHECKSUM_COMPLETE; csum = skb_checksum(skb, 0, udp_len, 0); uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, @@ -1172,14 +1171,14 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) nf_reset(skb); /* Get routing info from the tunnel socket */ - dst_release(skb->dst); - skb->dst = dst_clone(__sk_dst_get(sk_tun)); + skb_dst_drop(skb); + skb_dst_set(skb, dst_clone(__sk_dst_get(sk_tun))); pppol2tp_skb_set_owner_w(skb, sk_tun); /* Calculate UDP checksum if configured to do so */ if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) skb->ip_summed = CHECKSUM_NONE; - else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) { + else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) { skb->ip_summed = CHECKSUM_COMPLETE; csum = skb_checksum(skb, 0, udp_len, 0); uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index cadc32c94c1e..8a823ecc99a9 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2617,7 +2617,6 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) &port_regs->CommonRegs.reqQProducerIndex, qdev->req_producer_index); - ndev->trans_start = jiffies; if (netif_msg_tx_queued(qdev)) printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n", ndev->name, qdev->req_producer_index, skb->len); diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index fcb159e4df54..156e02e8905d 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -27,6 +27,8 @@ "%s: " fmt, __func__, ##args); \ } while (0) +#define WQ_ADDR_ALIGN 0x3 /* 4 byte alignment */ + #define QLGE_VENDOR_ID 0x1077 #define QLGE_DEVICE_ID_8012 0x8012 #define QLGE_DEVICE_ID_8000 0x8000 @@ -39,7 +41,18 @@ #define NUM_SMALL_BUFFERS 512 #define NUM_LARGE_BUFFERS 512 +#define DB_PAGE_SIZE 4096 + +/* Calculate the number of (4k) pages required to + * contain a buffer queue of the given length. + */ +#define MAX_DB_PAGES_PER_BQ(x) \ + (((x * sizeof(u64)) / DB_PAGE_SIZE) + \ + (((x * sizeof(u64)) % DB_PAGE_SIZE) ? 1 : 0)) +#define RX_RING_SHADOW_SPACE (sizeof(u64) + \ + MAX_DB_PAGES_PER_BQ(NUM_SMALL_BUFFERS) * sizeof(u64) + \ + MAX_DB_PAGES_PER_BQ(NUM_LARGE_BUFFERS) * sizeof(u64)) #define SMALL_BUFFER_SIZE 256 #define LARGE_BUFFER_SIZE PAGE_SIZE #define MAX_SPLIT_SIZE 1023 @@ -50,7 +63,7 @@ #define MAX_INTER_FRAME_WAIT 10 /* 10 usec max interframe-wait for coalescing */ #define DFLT_INTER_FRAME_WAIT (MAX_INTER_FRAME_WAIT/2) #define UDELAY_COUNT 3 -#define UDELAY_DELAY 10 +#define UDELAY_DELAY 100 #define TX_DESC_PER_IOCB 8 @@ -63,7 +76,16 @@ #define TX_DESC_PER_OAL 0 #endif -#define DB_PAGE_SIZE 4096 +/* MPI test register definitions. This register + * is used for determining alternate NIC function's + * PCI->func number. + */ +enum { + MPI_TEST_FUNC_PORT_CFG = 0x1002, + MPI_TEST_NIC1_FUNC_SHIFT = 1, + MPI_TEST_NIC2_FUNC_SHIFT = 5, + MPI_TEST_NIC_FUNC_MASK = 0x00000007, +}; /* * Processor Address Register (PROC_ADDR) bit definitions. @@ -1430,7 +1452,10 @@ struct ql_adapter { /* Hardware information */ u32 chip_rev_id; + u32 fw_rev_id; u32 func; /* PCI function for this adapter */ + u32 alt_func; /* PCI function for alternate adapter */ + u32 port; /* Port number this adapter */ spinlock_t adapter_lock; spinlock_t hw_lock; @@ -1580,6 +1605,8 @@ void ql_mpi_idc_work(struct work_struct *work); void ql_mpi_port_cfg_work(struct work_struct *work); int ql_mb_get_fw_state(struct ql_adapter *qdev); int ql_cam_route_initialize(struct ql_adapter *qdev); +int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data); +int ql_mb_about_fw(struct ql_adapter *qdev); #if 1 #define QL_ALL_DUMP diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 913b2a5fafc9..37c99fe79770 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -293,7 +293,10 @@ static void ql_get_drvinfo(struct net_device *ndev, struct ql_adapter *qdev = netdev_priv(ndev); strncpy(drvinfo->driver, qlge_driver_name, 32); strncpy(drvinfo->version, qlge_driver_version, 32); - strncpy(drvinfo->fw_version, "N/A", 32); + snprintf(drvinfo->fw_version, 32, "v%d.%d.%d", + (qdev->fw_rev_id & 0x00ff0000) >> 16, + (qdev->fw_rev_id & 0x0000ff00) >> 8, + (qdev->fw_rev_id & 0x000000ff)); strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32); drvinfo->n_stats = 0; drvinfo->testinfo_len = 0; @@ -401,6 +404,7 @@ const struct ethtool_ops qlge_ethtool_ops = { .get_rx_csum = ql_get_rx_csum, .set_rx_csum = ql_set_rx_csum, .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index c92ced247947..b9a5f59d6c9b 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -675,11 +675,12 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev) int status; __le32 *p = (__le32 *)&qdev->flash; u32 offset; + u8 mac_addr[6]; /* Get flash offset for function and adjust * for dword access. */ - if (!qdev->func) + if (!qdev->port) offset = FUNC0_FLASH_OFFSET / sizeof(u32); else offset = FUNC1_FLASH_OFFSET / sizeof(u32); @@ -705,14 +706,26 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev) goto exit; } - if (!is_valid_ether_addr(qdev->flash.flash_params_8000.mac_addr)) { + /* Extract either manufacturer or BOFM modified + * MAC address. + */ + if (qdev->flash.flash_params_8000.data_type1 == 2) + memcpy(mac_addr, + qdev->flash.flash_params_8000.mac_addr1, + qdev->ndev->addr_len); + else + memcpy(mac_addr, + qdev->flash.flash_params_8000.mac_addr, + qdev->ndev->addr_len); + + if (!is_valid_ether_addr(mac_addr)) { QPRINTK(qdev, IFUP, ERR, "Invalid MAC address.\n"); status = -EINVAL; goto exit; } memcpy(qdev->ndev->dev_addr, - qdev->flash.flash_params_8000.mac_addr, + mac_addr, qdev->ndev->addr_len); exit: @@ -731,7 +744,7 @@ static int ql_get_8012_flash_params(struct ql_adapter *qdev) /* Second function's parameters follow the first * function's. */ - if (qdev->func) + if (qdev->port) offset = size; if (ql_sem_spinlock(qdev, SEM_FLASH_MASK)) @@ -837,6 +850,13 @@ exit: static int ql_8000_port_initialize(struct ql_adapter *qdev) { int status; + /* + * Get MPI firmware version for driver banner + * and ethool info. + */ + status = ql_mb_about_fw(qdev); + if (status) + goto exit; status = ql_mb_get_fw_state(qdev); if (status) goto exit; @@ -1518,6 +1538,22 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, return; } + /* Frame error, so drop the packet. */ + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) { + QPRINTK(qdev, DRV, ERR, "Receive error, flags2 = 0x%x\n", + ib_mac_rsp->flags2); + dev_kfree_skb_any(skb); + return; + } + + /* The max framesize filter on this chip is set higher than + * MTU since FCoE uses 2k frames. + */ + if (skb->len > ndev->mtu + ETH_HLEN) { + dev_kfree_skb_any(skb); + return; + } + prefetch(skb->data); skb->dev = ndev; if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) { @@ -1540,7 +1576,6 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, * csum or frame errors. */ if (qdev->rx_csum && - !(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) && !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { @@ -2108,7 +2143,6 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev) wmb(); ql_write_db_reg(tx_ring->prod_idx, tx_ring->prod_idx_db_reg); - ndev->trans_start = jiffies; QPRINTK(qdev, TX_QUEUED, DEBUG, "tx queued, slot %d, len %d\n", tx_ring->prod_idx, skb->len); @@ -2203,7 +2237,7 @@ static int ql_alloc_tx_resources(struct ql_adapter *qdev, &tx_ring->wq_base_dma); if ((tx_ring->wq_base == NULL) - || tx_ring->wq_base_dma & (tx_ring->wq_size - 1)) { + || tx_ring->wq_base_dma & WQ_ADDR_ALIGN) { QPRINTK(qdev, IFUP, ERR, "tx_ring alloc failed.\n"); return -ENOMEM; } @@ -2518,14 +2552,16 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) { struct cqicb *cqicb = &rx_ring->cqicb; void *shadow_reg = qdev->rx_ring_shadow_reg_area + - (rx_ring->cq_id * sizeof(u64) * 4); + (rx_ring->cq_id * RX_RING_SHADOW_SPACE); u64 shadow_reg_dma = qdev->rx_ring_shadow_reg_dma + - (rx_ring->cq_id * sizeof(u64) * 4); + (rx_ring->cq_id * RX_RING_SHADOW_SPACE); void __iomem *doorbell_area = qdev->doorbell_area + (DB_PAGE_SIZE * (128 + rx_ring->cq_id)); int err = 0; u16 bq_len; u64 tmp; + __le64 *base_indirect_ptr; + int page_entries; /* Set up the shadow registers for this ring. */ rx_ring->prod_idx_sh_reg = shadow_reg; @@ -2534,8 +2570,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) shadow_reg_dma += sizeof(u64); rx_ring->lbq_base_indirect = shadow_reg; rx_ring->lbq_base_indirect_dma = shadow_reg_dma; - shadow_reg += sizeof(u64); - shadow_reg_dma += sizeof(u64); + shadow_reg += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); + shadow_reg_dma += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); rx_ring->sbq_base_indirect = shadow_reg; rx_ring->sbq_base_indirect_dma = shadow_reg_dma; @@ -2572,7 +2608,14 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) if (rx_ring->lbq_len) { cqicb->flags |= FLAGS_LL; /* Load lbq values */ tmp = (u64)rx_ring->lbq_base_dma;; - *((__le64 *) rx_ring->lbq_base_indirect) = cpu_to_le64(tmp); + base_indirect_ptr = (__le64 *) rx_ring->lbq_base_indirect; + page_entries = 0; + do { + *base_indirect_ptr = cpu_to_le64(tmp); + tmp += DB_PAGE_SIZE; + base_indirect_ptr++; + page_entries++; + } while (page_entries < MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); cqicb->lbq_addr = cpu_to_le64(rx_ring->lbq_base_indirect_dma); bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 : @@ -2589,7 +2632,14 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) if (rx_ring->sbq_len) { cqicb->flags |= FLAGS_LS; /* Load sbq values */ tmp = (u64)rx_ring->sbq_base_dma;; - *((__le64 *) rx_ring->sbq_base_indirect) = cpu_to_le64(tmp); + base_indirect_ptr = (__le64 *) rx_ring->sbq_base_indirect; + page_entries = 0; + do { + *base_indirect_ptr = cpu_to_le64(tmp); + tmp += DB_PAGE_SIZE; + base_indirect_ptr++; + page_entries++; + } while (page_entries < MAX_DB_PAGES_PER_BQ(rx_ring->sbq_len)); cqicb->sbq_addr = cpu_to_le64(rx_ring->sbq_base_indirect_dma); cqicb->sbq_buf_size = @@ -3186,9 +3236,10 @@ static void ql_display_dev_info(struct net_device *ndev) struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev); QPRINTK(qdev, PROBE, INFO, - "Function #%d, NIC Roll %d, NIC Rev = %d, " + "Function #%d, Port %d, NIC Roll %d, NIC Rev = %d, " "XG Roll = %d, XG Rev = %d.\n", qdev->func, + qdev->port, qdev->chip_rev_id & 0x0000000f, qdev->chip_rev_id >> 4 & 0x0000000f, qdev->chip_rev_id >> 8 & 0x0000000f, @@ -3264,7 +3315,6 @@ static int ql_adapter_up(struct ql_adapter *qdev) err = ql_adapter_initialize(qdev); if (err) { QPRINTK(qdev, IFUP, INFO, "Unable to initialize adapter.\n"); - spin_unlock(&qdev->hw_lock); goto err_init; } set_bit(QL_ADAPTER_UP, &qdev->flags); @@ -3361,7 +3411,6 @@ static int ql_configure_rings(struct ql_adapter *qdev) * completion handler rx_rings. */ qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1; - netif_set_gso_max_size(qdev->ndev, 65536); for (i = 0; i < qdev->tx_ring_count; i++) { tx_ring = &qdev->tx_ring[i]; @@ -3644,12 +3693,53 @@ static struct nic_operations qla8000_nic_ops = { .port_initialize = ql_8000_port_initialize, }; +/* Find the pcie function number for the other NIC + * on this chip. Since both NIC functions share a + * common firmware we have the lowest enabled function + * do any common work. Examples would be resetting + * after a fatal firmware error, or doing a firmware + * coredump. + */ +static int ql_get_alt_pcie_func(struct ql_adapter *qdev) +{ + int status = 0; + u32 temp; + u32 nic_func1, nic_func2; + + status = ql_read_mpi_reg(qdev, MPI_TEST_FUNC_PORT_CFG, + &temp); + if (status) + return status; + + nic_func1 = ((temp >> MPI_TEST_NIC1_FUNC_SHIFT) & + MPI_TEST_NIC_FUNC_MASK); + nic_func2 = ((temp >> MPI_TEST_NIC2_FUNC_SHIFT) & + MPI_TEST_NIC_FUNC_MASK); + + if (qdev->func == nic_func1) + qdev->alt_func = nic_func2; + else if (qdev->func == nic_func2) + qdev->alt_func = nic_func1; + else + status = -EIO; + + return status; +} -static void ql_get_board_info(struct ql_adapter *qdev) +static int ql_get_board_info(struct ql_adapter *qdev) { + int status; qdev->func = (ql_read32(qdev, STS) & STS_FUNC_ID_MASK) >> STS_FUNC_ID_SHIFT; - if (qdev->func) { + if (qdev->func > 3) + return -EIO; + + status = ql_get_alt_pcie_func(qdev); + if (status) + return status; + + qdev->port = (qdev->func < qdev->alt_func) ? 0 : 1; + if (qdev->port) { qdev->xg_sem_mask = SEM_XGMAC1_MASK; qdev->port_link_up = STS_PL1; qdev->port_init = STS_PI1; @@ -3668,6 +3758,7 @@ static void ql_get_board_info(struct ql_adapter *qdev) qdev->nic_ops = &qla8012_nic_ops; else if (qdev->device_id == QLGE_DEVICE_ID_8000) qdev->nic_ops = &qla8000_nic_ops; + return status; } static void ql_release_all(struct pci_dev *pdev) @@ -3762,7 +3853,12 @@ static int __devinit ql_init_device(struct pci_dev *pdev, qdev->ndev = ndev; qdev->pdev = pdev; - ql_get_board_info(qdev); + err = ql_get_board_info(qdev); + if (err) { + dev_err(&pdev->dev, "Register access failed.\n"); + err = -EIO; + goto err_out; + } qdev->msg_enable = netif_msg_init(debug, default_msg); spin_lock_init(&qdev->hw_lock); spin_lock_init(&qdev->stats_lock); diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 9f81b797f10b..a67c14a7befd 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -90,14 +90,14 @@ static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) */ static int ql_wait_mbx_cmd_cmplt(struct ql_adapter *qdev) { - int count = 50; /* TODO: arbitrary for now. */ + int count = 100; u32 value; do { value = ql_read32(qdev, STS); if (value & STS_PI) return 0; - udelay(UDELAY_DELAY); /* 10us */ + mdelay(UDELAY_DELAY); /* 100ms */ } while (--count); return -ETIMEDOUT; } @@ -453,6 +453,13 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) } end: ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); + /* Restore the original mailbox count to + * what the caller asked for. This can get + * changed when a mailbox command is waiting + * for a response and an AEN arrives and + * is handled. + * */ + mbcp->out_count = orig_count; return status; } @@ -540,6 +547,40 @@ end: return status; } + +/* Get MPI firmware version. This will be used for + * driver banner and for ethtool info. + * Returns zero on success. + */ +int ql_mb_about_fw(struct ql_adapter *qdev) +{ + struct mbox_params mbc; + struct mbox_params *mbcp = &mbc; + int status = 0; + + memset(mbcp, 0, sizeof(struct mbox_params)); + + mbcp->in_count = 1; + mbcp->out_count = 3; + + mbcp->mbox_in[0] = MB_CMD_ABOUT_FW; + + status = ql_mailbox_command(qdev, mbcp); + if (status) + return status; + + if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { + QPRINTK(qdev, DRV, ERR, + "Failed about firmware command\n"); + status = -EIO; + } + + /* Store the firmware version */ + qdev->fw_rev_id = mbcp->mbox_out[1]; + + return status; +} + /* Get functional state for MPI firmware. * Returns zero on success. */ @@ -754,7 +795,6 @@ void ql_mpi_port_cfg_work(struct work_struct *work) { struct ql_adapter *qdev = container_of(work, struct ql_adapter, mpi_port_cfg_work.work); - struct net_device *ndev = qdev->ndev; int status; status = ql_mb_get_port_cfg(qdev); @@ -764,9 +804,7 @@ void ql_mpi_port_cfg_work(struct work_struct *work) goto err; } - if (ndev->mtu <= 2500) - goto end; - else if (qdev->link_config & CFG_JUMBO_FRAME_SIZE && + if (qdev->link_config & CFG_JUMBO_FRAME_SIZE && qdev->max_frame_size == CFG_DEFAULT_MAX_FRAME_SIZE) goto end; @@ -831,13 +869,19 @@ void ql_mpi_work(struct work_struct *work) container_of(work, struct ql_adapter, mpi_work.work); struct mbox_params mbc; struct mbox_params *mbcp = &mbc; + int err = 0; mutex_lock(&qdev->mpi_mutex); while (ql_read32(qdev, STS) & STS_PI) { memset(mbcp, 0, sizeof(struct mbox_params)); mbcp->out_count = 1; - ql_mpi_handler(qdev, mbcp); + /* Don't continue if an async event + * did not complete properly. + */ + err = ql_mpi_handler(qdev, mbcp); + if (err) + break; } mutex_unlock(&qdev->mpi_mutex); diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 1508b124e3d8..ed63d23a6452 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -401,6 +401,9 @@ static void r6040_init_mac_regs(struct net_device *dev) * we may got called by r6040_tx_timeout which has left * some unsent tx buffers */ iowrite16(0x01, ioaddr + MTPR); + + /* Check media */ + mii_check_media(&lp->mii_if, 1, 1); } static void r6040_tx_timeout(struct net_device *dev) @@ -528,6 +531,8 @@ static int r6040_phy_mode_chk(struct net_device *dev) phy_dat = 0x0000; } + mii_check_media(&lp->mii_if, 0, 1); + return phy_dat; }; @@ -810,7 +815,6 @@ static void r6040_timer(unsigned long data) lp->phy_mode = phy_mode; lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode; iowrite16(lp->mcr0, ioaddr); - printk(KERN_INFO "Link Change %x \n", ioread16(ioaddr)); } /* Timer active again */ diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 0ec0605bcebd..007c881896d2 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3279,8 +3279,6 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); txd->opts1 = cpu_to_le32(status); - dev->trans_start = jiffies; - tp->cur_tx += frags + 1; smp_wmb(); @@ -3381,7 +3379,7 @@ static void rtl8169_tx_interrupt(struct net_device *dev, rtl8169_unmap_tx_skb(tp->pci_dev, tx_skb, tp->TxDescArray + entry); if (status & LastFrag) { - dev_kfree_skb_irq(tx_skb->skb); + dev_kfree_skb(tx_skb->skb); tx_skb->skb = NULL; } dirty_tx++; @@ -3563,54 +3561,64 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) int handled = 0; int status; + /* loop handling interrupts until we have no new ones or + * we hit a invalid/hotplug case. + */ status = RTL_R16(IntrStatus); + while (status && status != 0xffff) { + handled = 1; - /* hotplug/major error/no more work/shared irq */ - if ((status == 0xffff) || !status) - goto out; - - handled = 1; + /* Handle all of the error cases first. These will reset + * the chip, so just exit the loop. + */ + if (unlikely(!netif_running(dev))) { + rtl8169_asic_down(ioaddr); + break; + } - if (unlikely(!netif_running(dev))) { - rtl8169_asic_down(ioaddr); - goto out; - } + /* Work around for rx fifo overflow */ + if (unlikely(status & RxFIFOOver) && + (tp->mac_version == RTL_GIGA_MAC_VER_11)) { + netif_stop_queue(dev); + rtl8169_tx_timeout(dev); + break; + } - status &= tp->intr_mask; - RTL_W16(IntrStatus, - (status & RxFIFOOver) ? (status | RxOverflow) : status); + if (unlikely(status & SYSErr)) { + rtl8169_pcierr_interrupt(dev); + break; + } - if (!(status & tp->intr_event)) - goto out; + if (status & LinkChg) + rtl8169_check_link_status(dev, tp, ioaddr); - /* Work around for rx fifo overflow */ - if (unlikely(status & RxFIFOOver) && - (tp->mac_version == RTL_GIGA_MAC_VER_11)) { - netif_stop_queue(dev); - rtl8169_tx_timeout(dev); - goto out; - } + /* We need to see the lastest version of tp->intr_mask to + * avoid ignoring an MSI interrupt and having to wait for + * another event which may never come. + */ + smp_rmb(); + if (status & tp->intr_mask & tp->napi_event) { + RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event); + tp->intr_mask = ~tp->napi_event; + + if (likely(napi_schedule_prep(&tp->napi))) + __napi_schedule(&tp->napi); + else if (netif_msg_intr(tp)) { + printk(KERN_INFO "%s: interrupt %04x in poll\n", + dev->name, status); + } + } - if (unlikely(status & SYSErr)) { - rtl8169_pcierr_interrupt(dev); - goto out; + /* We only get a new MSI interrupt when all active irq + * sources on the chip have been acknowledged. So, ack + * everything we've seen and check if new sources have become + * active to avoid blocking all interrupts from the chip. + */ + RTL_W16(IntrStatus, + (status & RxFIFOOver) ? (status | RxOverflow) : status); + status = RTL_R16(IntrStatus); } - if (status & LinkChg) - rtl8169_check_link_status(dev, tp, ioaddr); - - if (status & tp->napi_event) { - RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event); - tp->intr_mask = ~tp->napi_event; - - if (likely(napi_schedule_prep(&tp->napi))) - __napi_schedule(&tp->napi); - else if (netif_msg_intr(tp)) { - printk(KERN_INFO "%s: interrupt %04x in poll\n", - dev->name, status); - } - } -out: return IRQ_RETVAL(handled); } @@ -3626,13 +3634,15 @@ static int rtl8169_poll(struct napi_struct *napi, int budget) if (work_done < budget) { napi_complete(napi); - tp->intr_mask = 0xffff; - /* - * 20040426: the barrier is not strictly required but the - * behavior of the irq handler could be less predictable - * without it. Btw, the lack of flush for the posted pci - * write is safe - FR + + /* We need for force the visibility of tp->intr_mask + * for other CPUs, as we can loose an MSI interrupt + * and potentially wait for a retransmit timeout if we don't. + * The posted write to IntrMask is safe, as it will + * eventually make it to the chip and we won't loose anything + * until it does. */ + tp->intr_mask = 0xffff; smp_wmb(); RTL_W16(IntrMask, tp->intr_event); } diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 80562ea77de3..458daa06ed41 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1764,7 +1764,7 @@ static int init_nic(struct s2io_nic *nic) * by then we return error. */ time = 0; - while (TRUE) { + while (true) { val64 = readq(&bar0->rti_command_mem); if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) break; @@ -2137,7 +2137,7 @@ static int verify_pcc_quiescent(struct s2io_nic *sp, int flag) herc = (sp->device_type == XFRAME_II_DEVICE); - if (flag == FALSE) { + if (flag == false) { if ((!herc && (sp->pdev->revision >= 4)) || herc) { if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE)) ret = 1; @@ -3587,7 +3587,7 @@ static void s2io_reset(struct s2io_nic * sp) writeq(val64, &bar0->pcc_err_reg); } - sp->device_enabled_once = FALSE; + sp->device_enabled_once = false; } /** @@ -4299,7 +4299,6 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) s2io_stop_tx_queue(sp, fifo->fifo_no); } mac_control->stats_info->sw_stat.mem_allocated += skb->truesize; - dev->trans_start = jiffies; spin_unlock_irqrestore(&fifo->tx_lock, flags); if (sp->config.intr_type == MSI_X) @@ -5573,10 +5572,10 @@ static void s2io_ethtool_getpause_data(struct net_device *dev, val64 = readq(&bar0->rmac_pause_cfg); if (val64 & RMAC_PAUSE_GEN_ENABLE) - ep->tx_pause = TRUE; + ep->tx_pause = true; if (val64 & RMAC_PAUSE_RX_ENABLE) - ep->rx_pause = TRUE; - ep->autoneg = FALSE; + ep->rx_pause = true; + ep->autoneg = false; } /** @@ -6807,7 +6806,7 @@ static void s2io_set_link(struct work_struct *work) val64 |= ADAPTER_LED_ON; writeq(val64, &bar0->adapter_control); } - nic->device_enabled_once = TRUE; + nic->device_enabled_once = true; } else { DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name); DBG_PRINT(ERR_DBG, "device is not Quiescent\n"); @@ -7755,7 +7754,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) struct s2io_nic *sp; struct net_device *dev; int i, j, ret; - int dma_flag = FALSE; + int dma_flag = false; u32 mac_up, mac_down; u64 val64 = 0, tmp64 = 0; struct XENA_dev_config __iomem *bar0 = NULL; @@ -7778,7 +7777,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n"); - dma_flag = TRUE; + dma_flag = true; if (pci_set_consistent_dma_mask (pdev, DMA_BIT_MASK(64))) { DBG_PRINT(ERR_DBG, @@ -7819,7 +7818,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->dev = dev; sp->pdev = pdev; sp->high_dma_flag = dma_flag; - sp->device_enabled_once = FALSE; + sp->device_enabled_once = false; if (rx_ring_mode == 1) sp->rxd_mode = RXD_MODE_1; if (rx_ring_mode == 2) @@ -7965,7 +7964,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - if (sp->high_dma_flag == TRUE) + if (sp->high_dma_flag == true) dev->features |= NETIF_F_HIGHDMA; dev->features |= NETIF_F_TSO; dev->features |= NETIF_F_TSO6; diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 55cb943f23f8..d5c5be6c07b9 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -18,15 +18,6 @@ #define vBIT(val, loc, sz) (((u64)val) << (64-loc-sz)) #define INV(d) ((d&0xff)<<24) | (((d>>8)&0xff)<<16) | (((d>>16)&0xff)<<8)| ((d>>24)&0xff) -#ifndef BOOL -#define BOOL int -#endif - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - #undef SUCCESS #define SUCCESS 0 #define FAILURE -1 diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 043795715955..b67ccca3fc1a 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -438,6 +438,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) kfree_skb(skb); return -EPIPE; } + efx->net_dev->trans_start = jiffies; } return 0; diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index db723c58f6f1..f4d509015f75 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -63,6 +63,7 @@ /* extended status register */ #define PMA_PMD_XSTATUS_REG 49153 +#define PMA_PMD_XSTAT_MDIX_LBN 14 #define PMA_PMD_XSTAT_FLP_LBN (12) /* LED control register */ @@ -741,9 +742,17 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa); - if (efx->phy_type != PHY_TYPE_SFX7101) + if (efx->phy_type != PHY_TYPE_SFX7101) { ecmd->supported |= (SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full); + if (ecmd->speed != SPEED_10000) { + ecmd->eth_tp_mdix = + (efx_mdio_read(efx, MDIO_MMD_PMAPMD, + PMA_PMD_XSTATUS_REG) & + (1 << PMA_PMD_XSTAT_MDIX_LBN)) + ? ETH_TP_MDI_X : ETH_TP_MDI; + } + } /* In loopback, the PHY automatically brings up the correct interface, * but doesn't advertise the correct speed. So override it */ diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index d6681edb7014..14a14788566c 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -360,13 +360,6 @@ inline int efx_xmit(struct efx_nic *efx, /* Map fragments for DMA and add to TX queue */ rc = efx_enqueue_skb(tx_queue, skb); - if (unlikely(rc != NETDEV_TX_OK)) - goto out; - - /* Update last TX timer */ - efx->net_dev->trans_start = jiffies; - - out: return rc; } diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 55ccd51d247e..e2247669a495 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -47,7 +47,7 @@ #define PHY_ID_ANY 0x1f #define MII_REG_ANY 0x1f -#define DRV_VERSION "1.2" +#define DRV_VERSION "1.3" #define DRV_NAME "sis190" #define SIS190_DRIVER_NAME DRV_NAME " Gigabit Ethernet driver " DRV_VERSION #define PFX DRV_NAME ": " @@ -317,6 +317,7 @@ static struct mii_chip_info { unsigned int type; u32 feature; } mii_chip_table[] = { + { "Atheros PHY", { 0x004d, 0xd010 }, LAN, 0 }, { "Atheros PHY AR8012", { 0x004d, 0xd020 }, LAN, 0 }, { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 }, { "Broadcom PHY AC131", { 0x0143, 0xbc70 }, LAN, 0 }, @@ -347,7 +348,7 @@ static struct { u32 msg_enable; } debug = { -1 }; -MODULE_DESCRIPTION("SiS sis190 Gigabit Ethernet driver"); +MODULE_DESCRIPTION("SiS sis190/191 Gigabit Ethernet driver"); module_param(rx_copybreak, int, 0); MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); module_param_named(debug, debug.msg_enable, int, 0); @@ -539,8 +540,8 @@ static bool sis190_try_rx_copy(struct sis190_private *tp, if (!skb) goto out; - pci_dma_sync_single_for_device(tp->pci_dev, addr, pkt_size, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(tp->pci_dev, addr, tp->rx_buf_sz, + PCI_DMA_FROMDEVICE); skb_reserve(skb, 2); skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size); *sk_buff = skb; @@ -942,9 +943,9 @@ static void sis190_phy_task(struct work_struct *work) u32 ctl; const char *msg; } reg31[] = { - { LPA_1000XFULL | LPA_SLCT, 0x07000c00 | 0x00001000, + { LPA_1000FULL, 0x07000c00 | 0x00001000, "1000 Mbps Full Duplex" }, - { LPA_1000XHALF | LPA_SLCT, 0x07000c00, + { LPA_1000HALF, 0x07000c00, "1000 Mbps Half Duplex" }, { LPA_100FULL, 0x04000800 | 0x00001000, "100 Mbps Full Duplex" }, @@ -955,22 +956,35 @@ static void sis190_phy_task(struct work_struct *work) { LPA_10HALF, 0x04000400, "10 Mbps Half Duplex" }, { 0, 0x04000400, "unknown" } - }, *p; - u16 adv; + }, *p = NULL; + u16 adv, autoexp, gigadv, gigrec; val = mdio_read(ioaddr, phy_id, 0x1f); net_link(tp, KERN_INFO "%s: mii ext = %04x.\n", dev->name, val); val = mdio_read(ioaddr, phy_id, MII_LPA); adv = mdio_read(ioaddr, phy_id, MII_ADVERTISE); - net_link(tp, KERN_INFO "%s: mii lpa = %04x adv = %04x.\n", - dev->name, val, adv); - - val &= adv; + autoexp = mdio_read(ioaddr, phy_id, MII_EXPANSION); + net_link(tp, KERN_INFO "%s: mii lpa=%04x adv=%04x exp=%04x.\n", + dev->name, val, adv, autoexp); + + if (val & LPA_NPAGE && autoexp & EXPANSION_NWAY) { + /* check for gigabit speed */ + gigadv = mdio_read(ioaddr, phy_id, MII_CTRL1000); + gigrec = mdio_read(ioaddr, phy_id, MII_STAT1000); + val = (gigadv & (gigrec >> 2)); + if (val & ADVERTISE_1000FULL) + p = reg31; + else if (val & ADVERTISE_1000HALF) + p = reg31 + 1; + } + if (!p) { + val &= adv; - for (p = reg31; p->val; p++) { - if ((val & p->val) == p->val) - break; + for (p = reg31; p->val; p++) { + if ((val & p->val) == p->val) + break; + } } p->ctl |= SIS_R32(StationControl) & ~0x0f001c00; @@ -1204,8 +1218,6 @@ static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev) SIS_W32(TxControl, 0x1a00 | CmdReset | CmdTxEnb); - dev->trans_start = jiffies; - dirty_tx = tp->dirty_tx; if ((tp->cur_tx - NUM_TX_DESC) == dirty_tx) { netif_stop_queue(dev); @@ -1315,12 +1327,15 @@ static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp, ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ? LAN : HOME) : p->type; tp->features |= p->feature; - } else + net_probe(tp, KERN_INFO "%s: %s transceiver at address %d.\n", + pci_name(tp->pci_dev), p->name, phy_id); + } else { phy->type = UNKNOWN; - - net_probe(tp, KERN_INFO "%s: %s transceiver at address %d.\n", - pci_name(tp->pci_dev), - (phy->type == UNKNOWN) ? "Unknown PHY" : p->name, phy_id); + net_probe(tp, KERN_INFO + "%s: unknown PHY 0x%x:0x%x transceiver at address %d\n", + pci_name(tp->pci_dev), + phy->id[0], (phy->id[1] & 0xfff0), phy_id); + } } static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp) diff --git a/drivers/net/skge.c b/drivers/net/skge.c index c11cdd08ec57..60d502eef4fc 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2837,8 +2837,6 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - dev->trans_start = jiffies; - return NETDEV_TX_OK; } diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a2ff9cb1e7ac..6b5946fe8ae2 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1690,7 +1690,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod); - dev->trans_start = jiffies; return NETDEV_TX_OK; mapping_unwind: diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 3cff84078a9e..b60639bd181b 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -2155,7 +2155,7 @@ static int smsc911x_resume(struct platform_device *pdev) static struct platform_driver smsc911x_driver = { .probe = smsc911x_drv_probe, - .remove = smsc911x_drv_remove, + .remove = __devexit_p(smsc911x_drv_remove), .driver = { .name = SMSC_CHIPNAME, }, diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index c399b1955c1e..545f81b34ad7 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -369,7 +369,6 @@ struct netdev_private { struct sk_buff* tx_skbuff[TX_RING_SIZE]; dma_addr_t tx_ring_dma; dma_addr_t rx_ring_dma; - struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ /* Frequently used values: keep some adjacent for cache effect. */ spinlock_t lock; @@ -975,7 +974,7 @@ static void tx_timeout(struct net_device *dev) dev->if_port = 0; dev->trans_start = jiffies; - np->stats.tx_errors++; + dev->stats.tx_errors++; if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { netif_wake_queue(dev); } @@ -1123,7 +1122,7 @@ reset_tx (struct net_device *dev) else dev_kfree_skb (skb); np->tx_skbuff[i] = NULL; - np->stats.tx_dropped++; + dev->stats.tx_dropped++; } } np->cur_tx = np->dirty_tx = 0; @@ -1181,15 +1180,15 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) if (netif_msg_tx_err(np)) printk("%s: Transmit error status %4.4x.\n", dev->name, tx_status); - np->stats.tx_errors++; + dev->stats.tx_errors++; if (tx_status & 0x10) - np->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (tx_status & 0x08) - np->stats.collisions++; + dev->stats.collisions++; if (tx_status & 0x04) - np->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; if (tx_status & 0x02) - np->stats.tx_window_errors++; + dev->stats.tx_window_errors++; /* ** This reset has been verified on @@ -1313,11 +1312,15 @@ static void rx_poll(unsigned long data) if (netif_msg_rx_err(np)) printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", frame_status); - np->stats.rx_errors++; - if (frame_status & 0x00100000) np->stats.rx_length_errors++; - if (frame_status & 0x00010000) np->stats.rx_fifo_errors++; - if (frame_status & 0x00060000) np->stats.rx_frame_errors++; - if (frame_status & 0x00080000) np->stats.rx_crc_errors++; + dev->stats.rx_errors++; + if (frame_status & 0x00100000) + dev->stats.rx_length_errors++; + if (frame_status & 0x00010000) + dev->stats.rx_fifo_errors++; + if (frame_status & 0x00060000) + dev->stats.rx_frame_errors++; + if (frame_status & 0x00080000) + dev->stats.rx_crc_errors++; if (frame_status & 0x00100000) { printk(KERN_WARNING "%s: Oversized Ethernet frame," " status %8.8x.\n", @@ -1485,22 +1488,22 @@ static struct net_device_stats *get_stats(struct net_device *dev) the vulnerability window is very small and statistics are non-critical. */ /* The chip only need report frame silently dropped. */ - np->stats.rx_missed_errors += ioread8(ioaddr + RxMissed); - np->stats.tx_packets += ioread16(ioaddr + TxFramesOK); - np->stats.rx_packets += ioread16(ioaddr + RxFramesOK); - np->stats.collisions += ioread8(ioaddr + StatsLateColl); - np->stats.collisions += ioread8(ioaddr + StatsMultiColl); - np->stats.collisions += ioread8(ioaddr + StatsOneColl); - np->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError); + dev->stats.rx_missed_errors += ioread8(ioaddr + RxMissed); + dev->stats.tx_packets += ioread16(ioaddr + TxFramesOK); + dev->stats.rx_packets += ioread16(ioaddr + RxFramesOK); + dev->stats.collisions += ioread8(ioaddr + StatsLateColl); + dev->stats.collisions += ioread8(ioaddr + StatsMultiColl); + dev->stats.collisions += ioread8(ioaddr + StatsOneColl); + dev->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError); ioread8(ioaddr + StatsTxDefer); for (i = StatsTxDefer; i <= StatsMcastRx; i++) ioread8(ioaddr + i); - np->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow); - np->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16; - np->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow); - np->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16; + dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow); + dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16; + dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow); + dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16; - return &np->stats; + return &dev->stats; } static void set_rx_mode(struct net_device *dev) diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 7f4a9683ba1e..3c2679cd196b 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -948,8 +948,7 @@ static void print_rxfd(struct rxf_desc *rxfd); static void bdx_rxdb_destroy(struct rxdb *db) { - if (db) - vfree(db); + vfree(db); } static struct rxdb *bdx_rxdb_create(int nelem) @@ -1482,10 +1481,8 @@ static void bdx_tx_db_close(struct txdb *d) { BDX_ASSERT(d == NULL); - if (d->start) { - vfree(d->start); - d->start = NULL; - } + vfree(d->start); + d->start = NULL; } /************************************************************************* @@ -1718,8 +1715,9 @@ static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev) WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR); #endif - ndev->trans_start = jiffies; - +#ifdef BDX_LLTX + ndev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ +#endif priv->net_stats.tx_packets++; priv->net_stats.tx_bytes += skb->len; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index eb65e25989f3..46a3f86125be 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5021,7 +5021,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, /* New SKB is guaranteed to be linear. */ entry = *start; ret = skb_dma_map(&tp->pdev->dev, new_skb, DMA_TO_DEVICE); - new_addr = skb_shinfo(new_skb)->dma_maps[0]; + new_addr = skb_shinfo(new_skb)->dma_head; /* Make sure new skb does not cross any 4G boundaries. * Drop the packet if it does. @@ -5155,7 +5155,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) sp = skb_shinfo(skb); - mapping = sp->dma_maps[0]; + mapping = sp->dma_head; tp->tx_buffers[entry].skb = skb; @@ -5173,7 +5173,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; len = frag->size; - mapping = sp->dma_maps[i + 1]; + mapping = sp->dma_maps[i]; tp->tx_buffers[entry].skb = NULL; tg3_set_txd(tp, entry, mapping, len, @@ -5194,9 +5194,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) } out_unlock: - mmiowb(); - - dev->trans_start = jiffies; + mmiowb(); return NETDEV_TX_OK; } @@ -5333,7 +5331,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) sp = skb_shinfo(skb); - mapping = sp->dma_maps[0]; + mapping = sp->dma_head; tp->tx_buffers[entry].skb = skb; @@ -5358,7 +5356,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; len = frag->size; - mapping = sp->dma_maps[i + 1]; + mapping = sp->dma_maps[i]; tp->tx_buffers[entry].skb = NULL; @@ -5407,9 +5405,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) } out_unlock: - mmiowb(); - - dev->trans_start = jiffies; + mmiowb(); return NETDEV_TX_OK; } diff --git a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig index d913405bc393..1cc8cf4425d1 100644 --- a/drivers/net/tulip/Kconfig +++ b/drivers/net/tulip/Kconfig @@ -27,6 +27,18 @@ config DE2104X To compile this driver as a module, choose M here. The module will be called de2104x. +config DE2104X_DSL + int "Descriptor Skip Length in 32 bit longwords" + depends on DE2104X + range 0 31 + default 0 + help + Setting this value allows to align ring buffer descriptors into their + own cache lines. Value of 4 corresponds to the typical 32 byte line + (the descriptor is 16 bytes). This is necessary on systems that lack + cache coherence, an example is PowerMac 5500. Otherwise 0 is safe. + Default is 0, and range is 0 to 31. + config TULIP tristate "DECchip Tulip (dc2114x) PCI support" depends on PCI diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index d4c5ecc51f77..e7609a05032d 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -82,6 +82,13 @@ MODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copi NETIF_MSG_RX_ERR | \ NETIF_MSG_TX_ERR) +/* Descriptor skip length in 32 bit longwords. */ +#ifndef CONFIG_DE2104X_DSL +#define DSL 0 +#else +#define DSL CONFIG_DE2104X_DSL +#endif + #define DE_RX_RING_SIZE 64 #define DE_TX_RING_SIZE 64 #define DE_RING_BYTES \ @@ -153,6 +160,7 @@ enum { CmdReset = (1 << 0), CacheAlign16 = 0x00008000, BurstLen4 = 0x00000400, + DescSkipLen = (DSL << 2), /* Rx/TxPoll bits */ NormalTxPoll = (1 << 0), @@ -246,7 +254,7 @@ static const u32 de_intr_mask = * Set the programmable burst length to 4 longwords for all: * DMA errors result without these values. Cache align 16 long. */ -static const u32 de_bus_mode = CacheAlign16 | BurstLen4; +static const u32 de_bus_mode = CacheAlign16 | BurstLen4 | DescSkipLen; struct de_srom_media_block { u8 opts; @@ -266,6 +274,9 @@ struct de_desc { __le32 opts2; __le32 addr1; __le32 addr2; +#if DSL + __le32 skip[DSL]; +#endif }; struct media_info { diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 4cda69b6b28c..811d3517fce0 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -565,9 +565,13 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso))) return -EFAULT; + if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && + gso.csum_start + gso.csum_offset + 2 > gso.hdr_len) + gso.hdr_len = gso.csum_start + gso.csum_offset + 2; + if (gso.hdr_len > len) return -EINVAL; - offset += sizeof(pi); + offset += sizeof(gso); } if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { @@ -844,12 +848,12 @@ static void tun_sock_write_space(struct sock *sk) if (!sock_writeable(sk)) return; - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible_sync(sk->sk_sleep); - if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags)) return; + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible_sync(sk->sk_sleep); + tun = container_of(sk, struct tun_sock, sk)->tun; kill_fasync(&tun->fasync, SIGIO, POLL_OUT); } @@ -1318,21 +1322,22 @@ static int tun_chr_open(struct inode *inode, struct file * file) static int tun_chr_close(struct inode *inode, struct file *file) { struct tun_file *tfile = file->private_data; - struct tun_struct *tun = __tun_get(tfile); + struct tun_struct *tun; + rtnl_lock(); + tun = __tun_get(tfile); if (tun) { DBG(KERN_INFO "%s: tun_chr_close\n", tun->dev->name); - rtnl_lock(); __tun_detach(tun); /* If desireable, unregister the netdevice. */ if (!(tun->flags & TUN_PERSIST)) unregister_netdevice(tun->dev); - rtnl_unlock(); } + rtnl_unlock(); tun = tfile->tun; if (tun) diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 0cf22c4f123b..fd6140bd9aae 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2007 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006-2009 Freescale Semicondutor, Inc. All rights reserved. * * Author: Shlomi Gridish <gridish@freescale.com> * Li Yang <leoli@freescale.com> @@ -65,6 +65,8 @@ static DEFINE_SPINLOCK(ugeth_lock); +static void uec_configure_serdes(struct net_device *dev); + static struct { u32 msg_enable; } debug = { -1 }; @@ -1410,6 +1412,9 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { upsmr |= UCC_GETH_UPSMR_TBIM; } + if ((ugeth->phy_interface == PHY_INTERFACE_MODE_SGMII)) + upsmr |= UCC_GETH_UPSMR_SGMM; + out_be32(&uf_regs->upsmr, upsmr); /* Disable autonegotiation in tbi mode, because by default it @@ -1554,6 +1559,9 @@ static int init_phy(struct net_device *dev) return -ENODEV; } + if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII) + uec_configure_serdes(dev); + phydev->supported &= (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | @@ -1569,7 +1577,41 @@ static int init_phy(struct net_device *dev) return 0; } +/* Initialize TBI PHY interface for communicating with the + * SERDES lynx PHY on the chip. We communicate with this PHY + * through the MDIO bus on each controller, treating it as a + * "normal" PHY at the address found in the UTBIPA register. We assume + * that the UTBIPA register is valid. Either the MDIO bus code will set + * it to a value that doesn't conflict with other PHYs on the bus, or the + * value doesn't matter, as there are no other PHYs on the bus. + */ +static void uec_configure_serdes(struct net_device *dev) +{ + struct ucc_geth_private *ugeth = netdev_priv(dev); + + if (!ugeth->tbiphy) { + printk(KERN_WARNING "SGMII mode requires that the device " + "tree specify a tbi-handle\n"); + return; + } + + /* + * If the link is already up, we must already be ok, and don't need to + * configure and reset the TBI<->SerDes link. Maybe U-Boot configured + * everything for us? Resetting it takes the link down and requires + * several seconds for it to come back. + */ + if (phy_read(ugeth->tbiphy, ENET_TBI_MII_SR) & TBISR_LSTATUS) + return; + + /* Single clk mode, mii mode off(for serdes communication) */ + phy_write(ugeth->tbiphy, ENET_TBI_MII_ANA, TBIANA_SETTINGS); + phy_write(ugeth->tbiphy, ENET_TBI_MII_TBICON, TBICON_CLK_SELECT); + + phy_write(ugeth->tbiphy, ENET_TBI_MII_CR, TBICR_SETTINGS); + +} static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) { @@ -3523,6 +3565,8 @@ static phy_interface_t to_phy_interface(const char *phy_connection_type) return PHY_INTERFACE_MODE_RGMII_RXID; if (strcasecmp(phy_connection_type, "rtbi") == 0) return PHY_INTERFACE_MODE_RTBI; + if (strcasecmp(phy_connection_type, "sgmii") == 0) + return PHY_INTERFACE_MODE_SGMII; return PHY_INTERFACE_MODE_MII; } @@ -3567,6 +3611,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, + PHY_INTERFACE_MODE_SGMII, }; ugeth_vdbg("%s: IN", __func__); @@ -3682,6 +3727,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma case PHY_INTERFACE_MODE_RGMII_TXID: case PHY_INTERFACE_MODE_TBI: case PHY_INTERFACE_MODE_RTBI: + case PHY_INTERFACE_MODE_SGMII: max_speed = SPEED_1000; break; default: @@ -3756,6 +3802,37 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ugeth->ndev = dev; ugeth->node = np; + /* Find the TBI PHY. If it's not there, we don't support SGMII */ + ph = of_get_property(np, "tbi-handle", NULL); + if (ph) { + struct device_node *tbi = of_find_node_by_phandle(*ph); + struct of_device *ofdev; + struct mii_bus *bus; + const unsigned int *id; + + if (!tbi) + return 0; + + mdio = of_get_parent(tbi); + if (!mdio) + return 0; + + ofdev = of_find_device_by_node(mdio); + + of_node_put(mdio); + + id = of_get_property(tbi, "reg", NULL); + if (!id) + return 0; + of_node_put(tbi); + + bus = dev_get_drvdata(&ofdev->dev); + if (!bus) + return 0; + + ugeth->tbiphy = bus->phy_map[*id]; + } + return 0; } diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index dca628a922ba..deb962bb68ef 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1,5 +1,5 @@ /* - * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * Copyright (C) Freescale Semicondutor, Inc. 2006-2009. All rights reserved. * * Author: Shlomi Gridish <gridish@freescale.com> * @@ -193,6 +193,31 @@ struct ucc_geth { #define ENET_TBI_MII_JD 0x10 /* Jitter diagnostics */ #define ENET_TBI_MII_TBICON 0x11 /* TBI control */ +/* TBI MDIO register bit fields*/ +#define TBISR_LSTATUS 0x0004 +#define TBICON_CLK_SELECT 0x0020 +#define TBIANA_ASYMMETRIC_PAUSE 0x0100 +#define TBIANA_SYMMETRIC_PAUSE 0x0080 +#define TBIANA_HALF_DUPLEX 0x0040 +#define TBIANA_FULL_DUPLEX 0x0020 +#define TBICR_PHY_RESET 0x8000 +#define TBICR_ANEG_ENABLE 0x1000 +#define TBICR_RESTART_ANEG 0x0200 +#define TBICR_FULL_DUPLEX 0x0100 +#define TBICR_SPEED1_SET 0x0040 + +#define TBIANA_SETTINGS ( \ + TBIANA_ASYMMETRIC_PAUSE \ + | TBIANA_SYMMETRIC_PAUSE \ + | TBIANA_FULL_DUPLEX \ + ) +#define TBICR_SETTINGS ( \ + TBICR_PHY_RESET \ + | TBICR_ANEG_ENABLE \ + | TBICR_FULL_DUPLEX \ + | TBICR_SPEED1_SET \ + ) + /* UCC GETH MACCFG1 (MAC Configuration 1 Register) */ #define MACCFG1_FLOW_RX 0x00000020 /* Flow Control Rx */ @@ -1188,6 +1213,7 @@ struct ucc_geth_private { struct ugeth_mii_info *mii_info; struct phy_device *phydev; + struct phy_device *tbiphy; phy_interface_t phy_interface; int max_speed; uint32_t msg_enable; diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 837135f0390a..e3580f42c899 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -899,15 +899,14 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, continue; } /* Allocate an sk_buff */ - odev->skb_rx_buf = dev_alloc_skb(frame_len); + odev->skb_rx_buf = netdev_alloc_skb(odev->net, + frame_len); if (!odev->skb_rx_buf) { /* We got no receive buffer. */ D1("could not allocate memory"); odev->rx_parse_state = WAIT_SYNC; return; } - /* Here's where it came from */ - odev->skb_rx_buf->dev = odev->net; /* Copy what we got so far. make room for iphdr * after tail. */ @@ -2481,10 +2480,10 @@ static int add_net_device(struct hso_device *hso_dev) return 0; } -static int hso_radio_toggle(void *data, enum rfkill_state state) +static int hso_rfkill_set_block(void *data, bool blocked) { struct hso_device *hso_dev = data; - int enabled = (state == RFKILL_STATE_UNBLOCKED); + int enabled = !blocked; int rv; mutex_lock(&hso_dev->mutex); @@ -2498,6 +2497,10 @@ static int hso_radio_toggle(void *data, enum rfkill_state state) return rv; } +static const struct rfkill_ops hso_rfkill_ops = { + .set_block = hso_rfkill_set_block, +}; + /* Creates and sets up everything for rfkill */ static void hso_create_rfkill(struct hso_device *hso_dev, struct usb_interface *interface) @@ -2506,29 +2509,25 @@ static void hso_create_rfkill(struct hso_device *hso_dev, struct device *dev = &hso_net->net->dev; char *rfkn; - hso_net->rfkill = rfkill_allocate(&interface_to_usbdev(interface)->dev, - RFKILL_TYPE_WWAN); - if (!hso_net->rfkill) { - dev_err(dev, "%s - Out of memory\n", __func__); - return; - } rfkn = kzalloc(20, GFP_KERNEL); - if (!rfkn) { - rfkill_free(hso_net->rfkill); - hso_net->rfkill = NULL; + if (!rfkn) dev_err(dev, "%s - Out of memory\n", __func__); - return; - } + snprintf(rfkn, 20, "hso-%d", interface->altsetting->desc.bInterfaceNumber); - hso_net->rfkill->name = rfkn; - hso_net->rfkill->state = RFKILL_STATE_UNBLOCKED; - hso_net->rfkill->data = hso_dev; - hso_net->rfkill->toggle_radio = hso_radio_toggle; + + hso_net->rfkill = rfkill_alloc(rfkn, + &interface_to_usbdev(interface)->dev, + RFKILL_TYPE_WWAN, + &hso_rfkill_ops, hso_dev); + if (!hso_net->rfkill) { + dev_err(dev, "%s - Out of memory\n", __func__); + kfree(rfkn); + return; + } if (rfkill_register(hso_net->rfkill) < 0) { + rfkill_destroy(hso_net->rfkill); kfree(rfkn); - hso_net->rfkill->name = NULL; - rfkill_free(hso_net->rfkill); hso_net->rfkill = NULL; dev_err(dev, "%s - Failed to register rfkill\n", __func__); return; @@ -3165,8 +3164,10 @@ static void hso_free_interface(struct usb_interface *interface) hso_stop_net_device(network_table[i]); cancel_work_sync(&network_table[i]->async_put_intf); cancel_work_sync(&network_table[i]->async_get_intf); - if (rfk) + if (rfk) { rfkill_unregister(rfk); + rfkill_destroy(rfk); + } hso_free_net_device(network_table[i]); } } diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index f9fb454ffa8b..fcc6fa0905d1 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -221,7 +221,8 @@ static void ctrl_callback(struct urb *urb) case -ENOENT: break; default: - dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status); + if (printk_ratelimit()) + dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status); } dev = urb->context; clear_bit(RX_REG_SET, &dev->flags); @@ -442,10 +443,12 @@ static void read_bulk_callback(struct urb *urb) case -ENOENT: return; /* the urb is in unlink state */ case -ETIME: - dev_warn(&urb->dev->dev, "may be reset is needed?..\n"); + if (printk_ratelimit()) + dev_warn(&urb->dev->dev, "may be reset is needed?..\n"); goto goon; default: - dev_warn(&urb->dev->dev, "Rx status %d\n", status); + if (printk_ratelimit()) + dev_warn(&urb->dev->dev, "Rx status %d\n", status); goto goon; } diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 8e56fcf0a0e3..87197dd9c788 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -176,8 +176,6 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev) if (dev->features & NETIF_F_NO_CSUM) skb->ip_summed = rcv_priv->ip_summed; - dst_release(skb->dst); - skb->dst = NULL; skb->mark = 0; secpath_reset(skb); nf_reset(skb); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 45daba726b66..d3489a3c4c03 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -388,7 +388,6 @@ struct rhine_private { long pioaddr; struct net_device *dev; struct napi_struct napi; - struct net_device_stats stats; spinlock_t lock; /* Frequently used values: keep some adjacent for cache effect. */ @@ -1209,7 +1208,7 @@ static void rhine_tx_timeout(struct net_device *dev) enable_irq(rp->pdev->irq); dev->trans_start = jiffies; - rp->stats.tx_errors++; + dev->stats.tx_errors++; netif_wake_queue(dev); } @@ -1237,7 +1236,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) /* packet too long, drop it */ dev_kfree_skb(skb); rp->tx_skbuff[entry] = NULL; - rp->stats.tx_dropped++; + dev->stats.tx_dropped++; return 0; } @@ -1378,29 +1377,33 @@ static void rhine_tx(struct net_device *dev) printk(KERN_DEBUG "%s: Transmit error, " "Tx status %8.8x.\n", dev->name, txstatus); - rp->stats.tx_errors++; - if (txstatus & 0x0400) rp->stats.tx_carrier_errors++; - if (txstatus & 0x0200) rp->stats.tx_window_errors++; - if (txstatus & 0x0100) rp->stats.tx_aborted_errors++; - if (txstatus & 0x0080) rp->stats.tx_heartbeat_errors++; + dev->stats.tx_errors++; + if (txstatus & 0x0400) + dev->stats.tx_carrier_errors++; + if (txstatus & 0x0200) + dev->stats.tx_window_errors++; + if (txstatus & 0x0100) + dev->stats.tx_aborted_errors++; + if (txstatus & 0x0080) + dev->stats.tx_heartbeat_errors++; if (((rp->quirks & rqRhineI) && txstatus & 0x0002) || (txstatus & 0x0800) || (txstatus & 0x1000)) { - rp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; rp->tx_ring[entry].tx_status = cpu_to_le32(DescOwn); break; /* Keep the skb - we try again */ } /* Transmitter restarted in 'abnormal' handler. */ } else { if (rp->quirks & rqRhineI) - rp->stats.collisions += (txstatus >> 3) & 0x0F; + dev->stats.collisions += (txstatus >> 3) & 0x0F; else - rp->stats.collisions += txstatus & 0x0F; + dev->stats.collisions += txstatus & 0x0F; if (debug > 6) printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n", (txstatus >> 3) & 0xF, txstatus & 0xF); - rp->stats.tx_bytes += rp->tx_skbuff[entry]->len; - rp->stats.tx_packets++; + dev->stats.tx_bytes += rp->tx_skbuff[entry]->len; + dev->stats.tx_packets++; } /* Free the original skb. */ if (rp->tx_skbuff_dma[entry]) { @@ -1455,21 +1458,24 @@ static int rhine_rx(struct net_device *dev, int limit) printk(KERN_WARNING "%s: Oversized Ethernet " "frame %p vs %p.\n", dev->name, rp->rx_head_desc, &rp->rx_ring[entry]); - rp->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } else if (desc_status & RxErr) { /* There was a error. */ if (debug > 2) printk(KERN_DEBUG "rhine_rx() Rx " "error was %8.8x.\n", desc_status); - rp->stats.rx_errors++; - if (desc_status & 0x0030) rp->stats.rx_length_errors++; - if (desc_status & 0x0048) rp->stats.rx_fifo_errors++; - if (desc_status & 0x0004) rp->stats.rx_frame_errors++; + dev->stats.rx_errors++; + if (desc_status & 0x0030) + dev->stats.rx_length_errors++; + if (desc_status & 0x0048) + dev->stats.rx_fifo_errors++; + if (desc_status & 0x0004) + dev->stats.rx_frame_errors++; if (desc_status & 0x0002) { /* this can also be updated outside the interrupt handler */ spin_lock(&rp->lock); - rp->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; spin_unlock(&rp->lock); } } @@ -1513,8 +1519,8 @@ static int rhine_rx(struct net_device *dev, int limit) } skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - rp->stats.rx_bytes += pkt_len; - rp->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; } entry = (++rp->cur_rx) % RX_RING_SIZE; rp->rx_head_desc = &rp->rx_ring[entry]; @@ -1599,8 +1605,8 @@ static void rhine_error(struct net_device *dev, int intr_status) if (intr_status & IntrLinkChange) rhine_check_media(dev, 0); if (intr_status & IntrStatsMax) { - rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); - rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); + dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); + dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); clear_tally_counters(ioaddr); } if (intr_status & IntrTxAborted) { @@ -1654,12 +1660,12 @@ static struct net_device_stats *rhine_get_stats(struct net_device *dev) unsigned long flags; spin_lock_irqsave(&rp->lock, flags); - rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); - rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); + dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); + dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); clear_tally_counters(ioaddr); spin_unlock_irqrestore(&rp->lock, flags); - return &rp->stats; + return &dev->stats; } static void rhine_set_rx_mode(struct net_device *dev) diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 754a4b182c1d..e2a7725e567e 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1385,7 +1385,7 @@ static void velocity_free_td_ring(struct velocity_info *vptr) static int velocity_rx_srv(struct velocity_info *vptr, int status) { - struct net_device_stats *stats = &vptr->stats; + struct net_device_stats *stats = &vptr->dev->stats; int rd_curr = vptr->rx.curr; int works = 0; @@ -1519,7 +1519,7 @@ static inline void velocity_iph_realign(struct velocity_info *vptr, static int velocity_receive_frame(struct velocity_info *vptr, int idx) { void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int); - struct net_device_stats *stats = &vptr->stats; + struct net_device_stats *stats = &vptr->dev->stats; struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]); struct rx_desc *rd = &(vptr->rx.ring[idx]); int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff; @@ -1532,7 +1532,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) } if (rd->rdesc0.RSR & RSR_MAR) - vptr->stats.multicast++; + stats->multicast++; skb = rd_info->skb; @@ -1634,7 +1634,7 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status) int idx; int works = 0; struct velocity_td_info *tdinfo; - struct net_device_stats *stats = &vptr->stats; + struct net_device_stats *stats = &vptr->dev->stats; for (qnum = 0; qnum < vptr->tx.numq; qnum++) { for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0; @@ -2324,22 +2324,22 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev) /* If the hardware is down, don't touch MII */ if(!netif_running(dev)) - return &vptr->stats; + return &dev->stats; spin_lock_irq(&vptr->lock); velocity_update_hw_mibs(vptr); spin_unlock_irq(&vptr->lock); - vptr->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts]; - vptr->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts]; - vptr->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors]; + dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts]; + dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts]; + dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors]; // unsigned long rx_dropped; /* no space in linux buffers */ - vptr->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions]; + dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions]; /* detailed rx_errors: */ // unsigned long rx_length_errors; // unsigned long rx_over_errors; /* receiver ring buff overflow */ - vptr->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE]; + dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE]; // unsigned long rx_frame_errors; /* recv'd frame alignment error */ // unsigned long rx_fifo_errors; /* recv'r fifo overrun */ // unsigned long rx_missed_errors; /* receiver missed packet */ @@ -2347,7 +2347,7 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev) /* detailed tx_errors */ // unsigned long tx_fifo_errors; - return &vptr->stats; + return &dev->stats; } diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index ea43e1832afb..4cd3f6c97379 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -1503,7 +1503,6 @@ struct velocity_info { struct pci_dev *pdev; struct net_device *dev; - struct net_device_stats stats; struct vlan_group *vlgrp; u8 ip_addr[4]; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 6cc5bcd34fb0..09bd4410fa65 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -470,7 +470,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) } if (skb_is_gso(skb)) { - hdr->hdr_len = skb_transport_header(skb) - skb->data; + hdr->hdr_len = skb_headlen(skb); hdr->gso_size = skb_shinfo(skb)->gso_size; if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; @@ -680,6 +680,7 @@ static void virtnet_set_rx_mode(struct net_device *dev) u8 promisc, allmulti; struct virtio_net_ctrl_mac *mac_data; struct dev_addr_list *addr; + struct netdev_hw_addr *ha; void *buf; int i; @@ -718,9 +719,9 @@ static void virtnet_set_rx_mode(struct net_device *dev) /* Store the unicast list and count in the front of the buffer */ mac_data->entries = dev->uc_count; - addr = dev->uc_list; - for (i = 0; i < dev->uc_count; i++, addr = addr->next) - memcpy(&mac_data->macs[i][0], addr->da_addr, ETH_ALEN); + i = 0; + list_for_each_entry(ha, &dev->uc_list, list) + memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN); sg_set_buf(&sg[0], mac_data, sizeof(mac_data->entries) + (dev->uc_count * ETH_ALEN)); diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 6b41c884a337..26cde573af43 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -1884,17 +1884,13 @@ void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool) mempool->memblock_size, dma_object); } - if (mempool->items_arr) - vfree(mempool->items_arr); + vfree(mempool->items_arr); - if (mempool->memblocks_dma_arr) - vfree(mempool->memblocks_dma_arr); + vfree(mempool->memblocks_dma_arr); - if (mempool->memblocks_priv_arr) - vfree(mempool->memblocks_priv_arr); + vfree(mempool->memblocks_priv_arr); - if (mempool->memblocks_arr) - vfree(mempool->memblocks_arr); + vfree(mempool->memblocks_arr); vfree(mempool); } diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index b7f08f3e524b..6c838b3e063a 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -677,7 +677,7 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, return VXGE_HW_OK; } -/* select a vpath to trasmit the packet */ +/* select a vpath to transmit the packet */ static u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb, int *do_lock) { @@ -992,7 +992,9 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN); vxge_hw_fifo_txdl_post(fifo_hw, dtr); - dev->trans_start = jiffies; +#ifdef NETIF_F_LLTX + dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ +#endif spin_unlock_irqrestore(&fifo->tx_lock, flags); VXGE_COMPLETE_VPATH_TX(fifo); diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index 765a7f5d6aa4..08b1a284b690 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -731,8 +731,8 @@ static int hss_hdlc_poll(struct napi_struct *napi, int budget) dma_unmap_single(&dev->dev, desc->data, RX_SIZE, DMA_FROM_DEVICE); #else - dma_sync_single(&dev->dev, desc->data, - RX_SIZE, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(&dev->dev, desc->data, + RX_SIZE, DMA_FROM_DEVICE); memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n], ALIGN(desc->pkt_len, 4) / 4); #endif diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index b3cadb626fe0..bd193ae2178b 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c @@ -292,8 +292,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m, d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state); - if (unlikely(i2400m->ready == 0)) /* act if up */ - goto out; if (i2400m->state != i2400m_state) { i2400m->state = i2400m_state; wake_up_all(&i2400m->state_wq); @@ -341,7 +339,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m, i2400m->bus_reset(i2400m, I2400M_RT_WARM); break; }; -out: d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n", i2400m, ss, i2400m_state); } @@ -372,8 +369,6 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m, d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status); - if (unlikely(i2400m->ready == 0)) /* act if up */ - goto out; switch (status) { case I2400M_MEDIA_STATUS_LINK_UP: netif_carrier_on(net_dev); @@ -393,14 +388,59 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m, dev_err(dev, "HW BUG? unknown media status %u\n", status); }; -out: d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n", i2400m, ms, status); } /* - * Parse a 'state report' and extract carrier on/off information + * Process a TLV from a 'state report' + * + * @i2400m: device descriptor + * @tlv: pointer to the TLV header; it has been already validated for + * consistent size. + * @tag: for error messages + * + * Act on the TLVs from a 'state report'. + */ +static +void i2400m_report_state_parse_tlv(struct i2400m *i2400m, + const struct i2400m_tlv_hdr *tlv, + const char *tag) +{ + struct device *dev = i2400m_dev(i2400m); + const struct i2400m_tlv_media_status *ms; + const struct i2400m_tlv_system_state *ss; + const struct i2400m_tlv_rf_switches_status *rfss; + + if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, sizeof(*ss))) { + ss = container_of(tlv, typeof(*ss), hdr); + d_printf(2, dev, "%s: system state TLV " + "found (0x%04x), state 0x%08x\n", + tag, I2400M_TLV_SYSTEM_STATE, + le32_to_cpu(ss->state)); + i2400m_report_tlv_system_state(i2400m, ss); + } + if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, sizeof(*rfss))) { + rfss = container_of(tlv, typeof(*rfss), hdr); + d_printf(2, dev, "%s: RF status TLV " + "found (0x%04x), sw 0x%02x hw 0x%02x\n", + tag, I2400M_TLV_RF_STATUS, + le32_to_cpu(rfss->sw_rf_switch), + le32_to_cpu(rfss->hw_rf_switch)); + i2400m_report_tlv_rf_switches_status(i2400m, rfss); + } + if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, sizeof(*ms))) { + ms = container_of(tlv, typeof(*ms), hdr); + d_printf(2, dev, "%s: Media Status TLV: %u\n", + tag, le32_to_cpu(ms->media_status)); + i2400m_report_tlv_media_status(i2400m, ms); + } +} + + +/* + * Parse a 'state report' and extract information * * @i2400m: device descriptor * @l3l4_hdr: pointer to message; it has been already validated for @@ -409,13 +449,7 @@ out: * declaration is assumed to be congruent with @size (as in * sizeof(*l3l4_hdr) + l3l4_hdr->length == size) * - * Extract from the report state the system state TLV and infer from - * there if we have a carrier or not. Update our local state and tell - * netdev. - * - * When setting the carrier, it's fine to set OFF twice (for example), - * as netif_carrier_off() will not generate two OFF events (just on - * the transitions). + * Walk over the TLVs in a report state and act on them. */ static void i2400m_report_state_hook(struct i2400m *i2400m, @@ -424,9 +458,6 @@ void i2400m_report_state_hook(struct i2400m *i2400m, { struct device *dev = i2400m_dev(i2400m); const struct i2400m_tlv_hdr *tlv; - const struct i2400m_tlv_system_state *ss; - const struct i2400m_tlv_rf_switches_status *rfss; - const struct i2400m_tlv_media_status *ms; size_t tlv_size = le16_to_cpu(l3l4_hdr->length); d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n", @@ -434,34 +465,8 @@ void i2400m_report_state_hook(struct i2400m *i2400m, tlv = NULL; while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl, - tlv_size, tlv))) { - if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, - sizeof(*ss))) { - ss = container_of(tlv, typeof(*ss), hdr); - d_printf(2, dev, "%s: system state TLV " - "found (0x%04x), state 0x%08x\n", - tag, I2400M_TLV_SYSTEM_STATE, - le32_to_cpu(ss->state)); - i2400m_report_tlv_system_state(i2400m, ss); - } - if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, - sizeof(*rfss))) { - rfss = container_of(tlv, typeof(*rfss), hdr); - d_printf(2, dev, "%s: RF status TLV " - "found (0x%04x), sw 0x%02x hw 0x%02x\n", - tag, I2400M_TLV_RF_STATUS, - le32_to_cpu(rfss->sw_rf_switch), - le32_to_cpu(rfss->hw_rf_switch)); - i2400m_report_tlv_rf_switches_status(i2400m, rfss); - } - if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, - sizeof(*ms))) { - ms = container_of(tlv, typeof(*ms), hdr); - d_printf(2, dev, "%s: Media Status TLV: %u\n", - tag, le32_to_cpu(ms->media_status)); - i2400m_report_tlv_media_status(i2400m, ms); - } - } + tlv_size, tlv))) + i2400m_report_state_parse_tlv(i2400m, tlv, tag); d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n", i2400m, l3l4_hdr, size, tag); } @@ -721,6 +726,8 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, ack_timeout = HZ; }; + if (unlikely(i2400m->trace_msg_from_user)) + wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL); /* The RX path in rx.c will put any response for this message * in i2400m->ack_skb and wake us up. If we cancel the wait, * we need to change the value of i2400m->ack_skb to something @@ -755,6 +762,9 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m, ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len); /* Check the ack and deliver it if it is ok */ + if (unlikely(i2400m->trace_msg_from_user)) + wimax_msg(&i2400m->wimax_dev, "echo", + ack_l3l4_hdr, ack_len, GFP_KERNEL); result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len); if (result < 0) { dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n", diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 07a54bad237b..ef16c573bb22 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -62,6 +62,7 @@ * unregister_netdev() */ #include "i2400m.h" +#include <linux/etherdevice.h> #include <linux/wimax/i2400m.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -234,9 +235,6 @@ int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev, result = PTR_ERR(ack_skb); if (IS_ERR(ack_skb)) goto error_msg_to_dev; - if (unlikely(i2400m->trace_msg_from_user)) - wimax_msg(&i2400m->wimax_dev, "trace", - msg_buf, msg_len, GFP_KERNEL); result = wimax_msg_send(&i2400m->wimax_dev, ack_skb); error_msg_to_dev: d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu " @@ -650,6 +648,7 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) result = i2400m_read_mac_addr(i2400m); if (result < 0) goto error_read_mac_addr; + random_ether_addr(i2400m->src_mac_addr); result = register_netdev(net_dev); /* Okey dokey, bring it up */ if (result < 0) { diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 3ae2df38b59a..434ba310c2fe 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h @@ -323,6 +323,10 @@ struct i2400m_roq; * delivered. Then the driver can release them to the host. See * drivers/net/i2400m/rx.c for details. * + * @src_mac_addr: MAC address used to make ethernet packets be coming + * from. This is generated at i2400m_setup() time and used during + * the life cycle of the instance. See i2400m_fake_eth_header(). + * * @init_mutex: Mutex used for serializing the device bringup * sequence; this way if the device reboots in the middle, we * don't try to do a bringup again while we are tearing down the @@ -421,6 +425,7 @@ struct i2400m { unsigned rx_pl_num, rx_pl_max, rx_pl_min, rx_num, rx_size_acc, rx_size_min, rx_size_max; struct i2400m_roq *rx_roq; /* not under rx_lock! */ + u8 src_mac_addr[ETH_HLEN]; struct mutex msg_mutex; /* serialize command execution */ struct completion msg_completion; diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 6b1fe7a81f25..9653f478b382 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c @@ -404,10 +404,12 @@ static void i2400m_rx_fake_eth_header(struct net_device *net_dev, void *_eth_hdr, __be16 protocol) { + struct i2400m *i2400m = net_dev_to_i2400m(net_dev); struct ethhdr *eth_hdr = _eth_hdr; memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest)); - memset(eth_hdr->h_source, 0, sizeof(eth_hdr->h_dest)); + memcpy(eth_hdr->h_source, i2400m->src_mac_addr, + sizeof(eth_hdr->h_source)); eth_hdr->h_proto = protocol; } diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index f9fc38902322..7643850a6fb8 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c @@ -177,7 +177,8 @@ void i2400m_report_hook_work(struct work_struct *ws) struct i2400m_work *iw = container_of(ws, struct i2400m_work, ws); struct i2400m_report_hook_args *args = (void *) iw->pl; - i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size); + if (iw->i2400m->ready) + i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size); kfree_skb(args->skb_rx); i2400m_put(iw->i2400m); kfree(iw); @@ -309,6 +310,9 @@ void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx, skb_get(skb_rx); i2400m_queue_work(i2400m, i2400m_report_hook_work, GFP_KERNEL, &args, sizeof(args)); + if (unlikely(i2400m->trace_msg_from_user)) + wimax_msg(&i2400m->wimax_dev, "echo", + l3l4_hdr, size, GFP_KERNEL); result = wimax_msg(&i2400m->wimax_dev, NULL, l3l4_hdr, size, GFP_KERNEL); if (result < 0) diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c index 5ac5e76701cd..777c981676fc 100644 --- a/drivers/net/wimax/i2400m/sdio.c +++ b/drivers/net/wimax/i2400m/sdio.c @@ -409,19 +409,19 @@ int i2400ms_probe(struct sdio_func *func, i2400m->bus_fw_names = i2400ms_bus_fw_names; i2400m->bus_bm_mac_addr_impaired = 1; - result = i2400ms_enable_function(i2400ms->func); - if (result < 0) { - dev_err(dev, "Cannot enable SDIO function: %d\n", result); - goto error_func_enable; - } - sdio_claim_host(func); result = sdio_set_block_size(func, I2400MS_BLK_SIZE); + sdio_release_host(func); if (result < 0) { dev_err(dev, "Failed to set block size: %d\n", result); goto error_set_blk_size; } - sdio_release_host(func); + + result = i2400ms_enable_function(i2400ms->func); + if (result < 0) { + dev_err(dev, "Cannot enable SDIO function: %d\n", result); + goto error_func_enable; + } result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); if (result < 0) { @@ -440,12 +440,12 @@ int i2400ms_probe(struct sdio_func *func, error_debugfs_add: i2400m_release(i2400m); error_setup: - sdio_set_drvdata(func, NULL); sdio_claim_host(func); -error_set_blk_size: sdio_disable_func(func); sdio_release_host(func); error_func_enable: +error_set_blk_size: + sdio_set_drvdata(func, NULL); free_netdev(net_dev); error_alloc_netdev: return result; diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index ca4151a9e222..17851321b7fd 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -505,27 +505,52 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg) #ifdef CONFIG_PM struct usb_device *usb_dev = i2400mu->usb_dev; #endif + unsigned is_autosuspend = 0; struct i2400m *i2400m = &i2400mu->i2400m; +#ifdef CONFIG_PM + if (usb_dev->auto_pm > 0) + is_autosuspend = 1; +#endif + d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); if (i2400m->updown == 0) goto no_firmware; - d_printf(1, dev, "fw up, requesting standby\n"); + if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) { + /* ugh -- the device is connected and this suspend + * request is an autosuspend one (not a system standby + * / hibernate). + * + * The only way the device can go to standby is if the + * link with the base station is in IDLE mode; that + * were the case, we'd be in status + * I2400M_SS_CONNECTED_IDLE. But we are not. + * + * If we *tell* him to go power save now, it'll reset + * as a precautionary measure, so if this is an + * autosuspend thing, say no and it'll come back + * later, when the link is IDLE + */ + result = -EBADF; + d_printf(1, dev, "fw up, link up, not-idle, autosuspend: " + "not entering powersave\n"); + goto error_not_now; + } + d_printf(1, dev, "fw up: entering powersave\n"); atomic_dec(&i2400mu->do_autopm); result = i2400m_cmd_enter_powersave(i2400m); atomic_inc(&i2400mu->do_autopm); -#ifdef CONFIG_PM - if (result < 0 && usb_dev->auto_pm == 0) { + if (result < 0 && !is_autosuspend) { /* System suspend, can't fail */ dev_err(dev, "failed to suspend, will reset on resume\n"); result = 0; } -#endif if (result < 0) goto error_enter_powersave; i2400mu_notification_release(i2400mu); - d_printf(1, dev, "fw up, got standby\n"); + d_printf(1, dev, "powersave requested\n"); error_enter_powersave: +error_not_now: no_firmware: d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n", iface, pm_msg.event, result); diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index a67d29290ba0..fb7541c28e58 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -153,7 +153,7 @@ config LIBERTAS_SDIO config LIBERTAS_SPI tristate "Marvell Libertas 8686 SPI 802.11b/g cards" - depends on LIBERTAS && SPI && GENERIC_GPIO + depends on LIBERTAS && SPI ---help--- A driver for Marvell Libertas 8686 SPI devices. @@ -333,11 +333,11 @@ config USB_ZD1201 config USB_NET_RNDIS_WLAN tristate "Wireless RNDIS USB support" depends on USB && WLAN_80211 && EXPERIMENTAL + depends on CFG80211 select USB_USBNET select USB_NET_CDCETHER select USB_NET_RNDIS_HOST select WIRELESS_EXT - select CFG80211 ---help--- This is a driver for wireless RNDIS devices. These are USB based adapters found in devices such as: @@ -431,6 +431,7 @@ config RTL8187 ASUS P5B Deluxe Toshiba Satellite Pro series of laptops Asus Wireless Link + Linksys WUSB54GC-EU Thanks to Realtek for their support! diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index cea7f1466c54..4efbdbe6d6bf 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1873,18 +1873,18 @@ static void at76_dwork_hw_scan(struct work_struct *work) if (ret != CMD_STATUS_COMPLETE) { queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan, SCAN_POLL_INTERVAL); - goto exit; + mutex_unlock(&priv->mtx); + return; } - ieee80211_scan_completed(priv->hw, false); - if (is_valid_ether_addr(priv->bssid)) at76_join(priv); - ieee80211_wake_queues(priv->hw); - -exit: mutex_unlock(&priv->mtx); + + ieee80211_scan_completed(priv->hw, false); + + ieee80211_wake_queues(priv->hw); } static int at76_hw_scan(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 17bd3eaf3e03..bb97981fb248 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -91,6 +91,7 @@ struct ar9170_led { struct led_classdev l; char name[32]; unsigned int toggled; + bool last_state; bool registered; }; @@ -101,7 +102,6 @@ enum ar9170_device_state { AR9170_STOPPED, AR9170_IDLE, AR9170_STARTED, - AR9170_ASSOCIATED, }; struct ar9170_rxstream_mpdu_merge { @@ -109,6 +109,11 @@ struct ar9170_rxstream_mpdu_merge { bool has_plcp; }; +#define AR9170_QUEUE_TIMEOUT 64 +#define AR9170_TX_TIMEOUT 8 +#define AR9170_JANITOR_DELAY 128 +#define AR9170_TX_INVALID_RATE 0xffffffff + struct ar9170 { struct ieee80211_hw *hw; struct mutex mutex; @@ -117,10 +122,11 @@ struct ar9170 { int (*open)(struct ar9170 *); void (*stop)(struct ar9170 *); - int (*tx)(struct ar9170 *, struct sk_buff *, bool, unsigned int); + int (*tx)(struct ar9170 *, struct sk_buff *); int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 , void *, u32 , void *); void (*callback_cmd)(struct ar9170 *, u32 , void *); + int (*flush)(struct ar9170 *); /* interface mode settings */ struct ieee80211_vif *vif; @@ -140,7 +146,7 @@ struct ar9170 { struct work_struct filter_config_work; u64 cur_mc_hash, want_mc_hash; u32 cur_filter, want_filter; - unsigned int filter_changed; + unsigned long filter_changed; unsigned int filter_state; bool sniffer_enabled; @@ -177,10 +183,10 @@ struct ar9170 { struct ar9170_eeprom eeprom; struct ath_regulatory regulatory; - /* global tx status for unregistered Stations. */ - struct sk_buff_head global_tx_status; - struct sk_buff_head global_tx_status_waste; - struct delayed_work tx_status_janitor; + /* tx queues - as seen by hw - */ + struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; + struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; + struct delayed_work tx_janitor; /* rxstream mpdu merge */ struct ar9170_rxstream_mpdu_merge rx_mpdu; @@ -189,13 +195,21 @@ struct ar9170 { }; struct ar9170_sta_info { - struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; }; -#define IS_STARTED(a) (a->state >= AR9170_STARTED) -#define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE) +#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0) +#define AR9170_TX_FLAG_NO_ACK BIT(1) +#define AR9170_TX_FLAG_BLOCK_ACK BIT(2) + +struct ar9170_tx_info { + unsigned long timeout; + unsigned int flags; +}; + +#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) +#define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE) -#define AR9170_FILTER_CHANGED_PROMISC BIT(0) +#define AR9170_FILTER_CHANGED_MODE BIT(0) #define AR9170_FILTER_CHANGED_MULTICAST BIT(1) #define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2) @@ -204,8 +218,9 @@ void *ar9170_alloc(size_t priv_size); int ar9170_register(struct ar9170 *ar, struct device *pdev); void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); void ar9170_unregister(struct ar9170 *ar); -void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, - bool update_statistics, u16 tx_status); +void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb); +void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); +int ar9170_nag_limiter(struct ar9170 *ar); /* MAC */ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); @@ -215,6 +230,9 @@ int ar9170_update_multicast(struct ar9170 *ar); int ar9170_update_frame_filter(struct ar9170 *ar); int ar9170_set_operating_mode(struct ar9170 *ar); int ar9170_set_beacon_timers(struct ar9170 *ar); +int ar9170_set_dyn_sifs_ack(struct ar9170 *ar); +int ar9170_set_slot_time(struct ar9170 *ar); +int ar9170_set_basic_rates(struct ar9170 *ar); int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); int ar9170_update_beacon(struct ar9170 *ar); void ar9170_new_beacon(struct work_struct *work); diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 3293e0fb24fb..6cbfb2f83391 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -207,7 +207,8 @@ enum ar9170_cmd { #define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) #define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) -#define AR9170_MAC_REG_AMPDU_SET (AR9170_MAC_REG_BASE + 0xba0) +#define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xB9C) +#define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xBA0) #define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) #define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) @@ -376,7 +377,6 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t) #define AR9170_RX_ERROR_FATAL 0x80 struct ar9170_cmd_tx_status { - __le16 unkn; u8 dst[ETH_ALEN]; __le32 rate; __le16 status; @@ -394,6 +394,7 @@ struct ar9170_cmd_ba_failed_count { struct ar9170_cmd_response { u8 flag; u8 type; + __le16 padding; union { struct ar9170_cmd_tx_status tx_status; @@ -419,4 +420,7 @@ enum ar9170_txq { __AR9170_NUM_TXQ, }; +#define AR9170_TXQ_DEPTH 32 +#define AR9170_TX_MAX_PENDING 128 + #endif /* __AR9170_HW_H */ diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c index 341cead7f606..63fda6cd2101 100644 --- a/drivers/net/wireless/ath/ar9170/led.c +++ b/drivers/net/wireless/ath/ar9170/led.c @@ -74,7 +74,7 @@ static void ar9170_update_leds(struct work_struct *work) mutex_lock(&ar->mutex); for (i = 0; i < AR9170_NUM_LEDS; i++) - if (ar->leds[i].toggled) { + if (ar->leds[i].registered && ar->leds[i].toggled) { led_val |= 1 << i; tmp = 70 + 200 / (ar->leds[i].toggled); @@ -101,9 +101,15 @@ static void ar9170_led_brightness_set(struct led_classdev *led, struct ar9170_led *arl = container_of(led, struct ar9170_led, l); struct ar9170 *ar = arl->ar; - arl->toggled++; + if (unlikely(!arl->registered)) + return ; + + if (arl->last_state != !!brightness) { + arl->toggled++; + arl->last_state = !!brightness; + } - if (likely(IS_ACCEPTING_CMD(ar) && brightness)) + if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled)) queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10); } @@ -136,13 +142,14 @@ void ar9170_unregister_leds(struct ar9170 *ar) { int i; - cancel_delayed_work_sync(&ar->led_work); - for (i = 0; i < AR9170_NUM_LEDS; i++) if (ar->leds[i].registered) { led_classdev_unregister(&ar->leds[i].l); ar->leds[i].registered = false; + ar->leds[i].toggled = 0; } + + cancel_delayed_work_sync(&ar->led_work); } int ar9170_register_leds(struct ar9170 *ar) diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index 43aeb69685d3..d9f1f46de183 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -38,6 +38,55 @@ #include "ar9170.h" #include "cmd.h" +int ar9170_set_dyn_sifs_ack(struct ar9170 *ar) +{ + u32 val; + + if (conf_is_ht40(&ar->hw->conf)) + val = 0x010a; + else { + if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) + val = 0x105; + else + val = 0x104; + } + + return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val); +} + +int ar9170_set_slot_time(struct ar9170 *ar) +{ + u32 slottime = 20; + + if (!ar->vif) + return 0; + + if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) || + ar->vif->bss_conf.use_short_slot) + slottime = 9; + + return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10); +} + +int ar9170_set_basic_rates(struct ar9170 *ar) +{ + u8 cck, ofdm; + + if (!ar->vif) + return 0; + + ofdm = ar->vif->bss_conf.basic_rates >> 4; + + /* FIXME: is still necessary? */ + if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) + cck = 0; + else + cck = ar->vif->bss_conf.basic_rates & 0xf; + + return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE, + ofdm << 8 | cck); +} + int ar9170_set_qos(struct ar9170 *ar) { ar9170_regwrite_begin(ar); @@ -84,7 +133,7 @@ static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity) val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0); ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_AMPDU_SET, val); + ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val); ar9170_regwrite_finish(); return ar9170_regwrite_result(); @@ -398,10 +447,10 @@ int ar9170_update_beacon(struct ar9170 *ar) /* XXX: use skb->cb info */ if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << (3+16)) + 0x0400); + ((skb->len + 4) << (3 + 16)) + 0x0400); else ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << (3+16)) + 0x0400); + ((skb->len + 4) << 16) + 0x001b); ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 99df9ddae9cb..9d38cf60a0db 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -146,7 +146,6 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = { { \ .ht_supported = true, \ .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ - IEEE80211_HT_CAP_SM_PS | \ IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ IEEE80211_HT_CAP_SGI_40 | \ IEEE80211_HT_CAP_DSSSCCK40 | \ @@ -174,59 +173,122 @@ static struct ieee80211_supported_band ar9170_band_5GHz = { .ht_cap = AR9170_HT_CAP, }; -#ifdef AR9170_QUEUE_DEBUG -/* - * In case some wants works with AR9170's crazy tx_status queueing techniques. - * He might need this rather useful probing function. - * - * NOTE: caller must hold the queue's spinlock! - */ +static void ar9170_tx(struct ar9170 *ar); +#ifdef AR9170_QUEUE_DEBUG static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) { struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *)txc->frame_data; + struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); + struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; + struct ieee80211_hdr *hdr = (void *) txc->frame_data; - printk(KERN_DEBUG "%s: => FRAME [skb:%p, queue:%d, DA:[%pM] " - "mac_control:%04x, phy_control:%08x]\n", + printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x " + "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), - ieee80211_get_DA(hdr), le16_to_cpu(txc->mac_control), - le32_to_cpu(txc->phy_control)); + ieee80211_get_DA(hdr), arinfo->flags, + le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), + jiffies_to_msecs(arinfo->timeout - jiffies)); } -static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar, - struct sk_buff_head *queue) +static void __ar9170_dump_txqueue(struct ar9170 *ar, + struct sk_buff_head *queue) { struct sk_buff *skb; int i = 0; printk(KERN_DEBUG "---[ cut here ]---\n"); - printk(KERN_DEBUG "%s: %d entries in tx_status queue.\n", + printk(KERN_DEBUG "%s: %d entries in queue.\n", wiphy_name(ar->hw->wiphy), skb_queue_len(queue)); skb_queue_walk(queue, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *)txc->frame_data; - - printk(KERN_DEBUG "index:%d => \n", i); + printk(KERN_DEBUG "index:%d => \n", i++); ar9170_print_txheader(ar, skb); } + if (i != skb_queue_len(queue)) + printk(KERN_DEBUG "WARNING: queue frame counter " + "mismatch %d != %d\n", skb_queue_len(queue), i); printk(KERN_DEBUG "---[ end ]---\n"); } -#endif /* AR9170_QUEUE_DEBUG */ -void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, - bool valid_status, u16 tx_status) +static void ar9170_dump_txqueue(struct ar9170 *ar, + struct sk_buff_head *queue) +{ + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + __ar9170_dump_txqueue(ar, queue); + spin_unlock_irqrestore(&queue->lock, flags); +} + +static void __ar9170_dump_txstats(struct ar9170 *ar) +{ + int i; + + printk(KERN_DEBUG "%s: QoS queue stats\n", + wiphy_name(ar->hw->wiphy)); + + for (i = 0; i < __AR9170_NUM_TXQ; i++) + printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n", + wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit, + ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i])); +} + +static void ar9170_dump_txstats(struct ar9170 *ar) { - struct ieee80211_tx_info *txinfo; - unsigned int retries = 0, queue = skb_get_queue_mapping(skb); unsigned long flags; spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - if (ieee80211_queue_stopped(ar->hw, queue)) - ieee80211_wake_queue(ar->hw, queue); + __ar9170_dump_txstats(ar); spin_unlock_irqrestore(&ar->tx_stats_lock, flags); +} +#endif /* AR9170_QUEUE_DEBUG */ + +/* caller must guarantee exclusive access for _bin_ queue. */ +static void ar9170_recycle_expired(struct ar9170 *ar, + struct sk_buff_head *queue, + struct sk_buff_head *bin) +{ + struct sk_buff *skb, *old = NULL; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + while ((skb = skb_peek(queue))) { + struct ieee80211_tx_info *txinfo; + struct ar9170_tx_info *arinfo; + + txinfo = IEEE80211_SKB_CB(skb); + arinfo = (void *) txinfo->rate_driver_data; + + if (time_is_before_jiffies(arinfo->timeout)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: [%ld > %ld] frame expired => " + "recycle \n", wiphy_name(ar->hw->wiphy), + jiffies, arinfo->timeout); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + __skb_unlink(skb, queue); + __skb_queue_tail(bin, skb); + } else { + break; + } + + if (unlikely(old == skb)) { + /* bail out - queue is shot. */ + + WARN_ON(1); + break; + } + old = skb; + } + spin_unlock_irqrestore(&queue->lock, flags); +} + +static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, + u16 tx_status) +{ + struct ieee80211_tx_info *txinfo; + unsigned int retries = 0; txinfo = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(txinfo); @@ -248,45 +310,61 @@ void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, break; } - if (valid_status) - txinfo->status.rates[0].count = retries + 1; - + txinfo->status.rates[0].count = retries + 1; skb_pull(skb, sizeof(struct ar9170_tx_control)); ieee80211_tx_status_irqsafe(ar->hw, skb); } -static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar, - const u8 *mac, - const u32 queue, - struct sk_buff_head *q) +void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data; + unsigned int queue = skb_get_queue_mapping(skb); unsigned long flags; - struct sk_buff *skb; - spin_lock_irqsave(&q->lock, flags); - skb_queue_walk(q, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *) txc->frame_data; - u32 txc_queue = (le32_to_cpu(txc->phy_control) & - AR9170_TX_PHY_QOS_MASK) >> - AR9170_TX_PHY_QOS_SHIFT; + spin_lock_irqsave(&ar->tx_stats_lock, flags); + ar->tx_stats[queue].len--; - if ((queue != txc_queue) || - (compare_ether_addr(ieee80211_get_DA(hdr), mac))) - continue; + if (skb_queue_empty(&ar->tx_pending[queue])) { +#ifdef AR9170_QUEUE_STOP_DEBUG + printk(KERN_DEBUG "%s: wake queue %d\n", + wiphy_name(ar->hw->wiphy), queue); + __ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_STOP_DEBUG */ + ieee80211_wake_queue(ar->hw, queue); + } + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - __skb_unlink(skb, q); - spin_unlock_irqrestore(&q->lock, flags); - return skb; + if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) { + dev_kfree_skb_any(skb); + } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) { + arinfo->timeout = jiffies + + msecs_to_jiffies(AR9170_TX_TIMEOUT); + + skb_queue_tail(&ar->tx_status[queue], skb); + } else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) { + ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); + } else { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: unsupported frame flags!\n", + wiphy_name(ar->hw->wiphy)); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + dev_kfree_skb_any(skb); + } + + if (!ar->tx_stats[queue].len && + !skb_queue_empty(&ar->tx_pending[queue])) { + ar9170_tx(ar); } - spin_unlock_irqrestore(&q->lock, flags); - return NULL; } -static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, - const u32 queue) +static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, + const u8 *mac, + struct sk_buff_head *queue, + const u32 rate) { - struct ieee80211_sta *sta; + unsigned long flags; struct sk_buff *skb; /* @@ -297,85 +375,94 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, * the firmware provided (-> destination MAC, and phy_control) - * and hope that we picked the right one... */ - rcu_read_lock(); - sta = ieee80211_find_sta(ar->hw, mac); - - if (likely(sta)) { - struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv; - skb = skb_dequeue(&sta_priv->tx_status[queue]); - rcu_read_unlock(); - if (likely(skb)) - return skb; - } else - rcu_read_unlock(); - - /* scan the waste queue for candidates */ - skb = ar9170_find_skb_in_queue(ar, mac, queue, - &ar->global_tx_status_waste); - if (!skb) { - /* so it still _must_ be in the global list. */ - skb = ar9170_find_skb_in_queue(ar, mac, queue, - &ar->global_tx_status); - } + spin_lock_irqsave(&queue->lock, flags); + skb_queue_walk(queue, skb) { + struct ar9170_tx_control *txc = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *) txc->frame_data; + u32 r; + + if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: skip frame => DA %pM != %pM\n", + wiphy_name(ar->hw->wiphy), mac, + ieee80211_get_DA(hdr)); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + continue; + } + + r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >> + AR9170_TX_PHY_MCS_SHIFT; + + if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) { #ifdef AR9170_QUEUE_DEBUG - if (unlikely((!skb) && net_ratelimit())) { - printk(KERN_ERR "%s: ESS:[%pM] does not have any " - "outstanding frames in this queue (%d).\n", - wiphy_name(ar->hw->wiphy), mac, queue); + printk(KERN_DEBUG "%s: skip frame => rate %d != %d\n", + wiphy_name(ar->hw->wiphy), rate, r); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + continue; + } + + __skb_unlink(skb, queue); + spin_unlock_irqrestore(&queue->lock, flags); + return skb; } + +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_ERR "%s: ESS:[%pM] does not have any " + "outstanding frames in queue.\n", + wiphy_name(ar->hw->wiphy), mac); + __ar9170_dump_txqueue(ar, queue); #endif /* AR9170_QUEUE_DEBUG */ - return skb; + spin_unlock_irqrestore(&queue->lock, flags); + + return NULL; } /* - * This worker tries to keep the global tx_status queue empty. - * So we can guarantee that incoming tx_status reports for - * unregistered stations are always synced with the actual - * frame - which we think - belongs to. + * This worker tries to keeps an maintain tx_status queues. + * So we can guarantee that incoming tx_status reports are + * actually for a pending frame. */ -static void ar9170_tx_status_janitor(struct work_struct *work) +static void ar9170_tx_janitor(struct work_struct *work) { struct ar9170 *ar = container_of(work, struct ar9170, - tx_status_janitor.work); - struct sk_buff *skb; + tx_janitor.work); + struct sk_buff_head waste; + unsigned int i; + bool resched = false; if (unlikely(!IS_STARTED(ar))) return ; - mutex_lock(&ar->mutex); - /* recycle the garbage back to mac80211... one by one. */ - while ((skb = skb_dequeue(&ar->global_tx_status_waste))) { + skb_queue_head_init(&waste); + + for (i = 0; i < __AR9170_NUM_TXQ; i++) { #ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: dispose queued frame =>\n", - wiphy_name(ar->hw->wiphy)); - ar9170_print_txheader(ar, skb); + printk(KERN_DEBUG "%s: garbage collector scans queue:%d\n", + wiphy_name(ar->hw->wiphy), i); + ar9170_dump_txqueue(ar, &ar->tx_pending[i]); + ar9170_dump_txqueue(ar, &ar->tx_status[i]); #endif /* AR9170_QUEUE_DEBUG */ - ar9170_handle_tx_status(ar, skb, false, - AR9170_TX_STATUS_FAILED); - } - while ((skb = skb_dequeue(&ar->global_tx_status))) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: moving frame into waste queue =>\n", - wiphy_name(ar->hw->wiphy)); + ar9170_recycle_expired(ar, &ar->tx_status[i], &waste); + ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste); + skb_queue_purge(&waste); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - skb_queue_tail(&ar->global_tx_status_waste, skb); + if (!skb_queue_empty(&ar->tx_status[i]) || + !skb_queue_empty(&ar->tx_pending[i])) + resched = true; } - /* recall the janitor in 100ms - if there's garbage in the can. */ - if (skb_queue_len(&ar->global_tx_status_waste) > 0) - queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, - msecs_to_jiffies(100)); - - mutex_unlock(&ar->mutex); + if (resched) + queue_delayed_work(ar->hw->workqueue, + &ar->tx_janitor, + msecs_to_jiffies(AR9170_JANITOR_DELAY)); } -static void ar9170_handle_command_response(struct ar9170 *ar, - void *buf, u32 len) +void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) { struct ar9170_cmd_response *cmd = (void *) buf; @@ -399,15 +486,21 @@ static void ar9170_handle_command_response(struct ar9170 *ar, */ struct sk_buff *skb; - u32 queue = (le32_to_cpu(cmd->tx_status.rate) & - AR9170_TX_PHY_QOS_MASK) >> AR9170_TX_PHY_QOS_SHIFT; + u32 phy = le32_to_cpu(cmd->tx_status.rate); + u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >> + AR9170_TX_PHY_QOS_SHIFT; +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: recv tx_status for %pM, p:%08x, q:%d\n", + wiphy_name(ar->hw->wiphy), cmd->tx_status.dst, phy, q); +#endif /* AR9170_QUEUE_DEBUG */ - skb = ar9170_find_queued_skb(ar, cmd->tx_status.dst, queue); + skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst, + &ar->tx_status[q], + AR9170_TX_INVALID_RATE); if (unlikely(!skb)) return ; - ar9170_handle_tx_status(ar, skb, true, - le16_to_cpu(cmd->tx_status.status)); + ar9170_tx_status(ar, skb, le16_to_cpu(cmd->tx_status.status)); break; } @@ -447,6 +540,38 @@ static void ar9170_handle_command_response(struct ar9170 *ar, /* retransmission issue / SIFS/EIFS collision ?! */ break; + /* firmware debug */ + case 0xca: + printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, (char *)buf + 4); + break; + case 0xcb: + len -= 4; + + switch (len) { + case 1: + printk(KERN_DEBUG "ar9170 FW: u8: %#.2x\n", + *((char *)buf + 4)); + break; + case 2: + printk(KERN_DEBUG "ar9170 FW: u8: %#.4x\n", + le16_to_cpup((__le16 *)((char *)buf + 4))); + break; + case 4: + printk(KERN_DEBUG "ar9170 FW: u8: %#.8x\n", + le32_to_cpup((__le32 *)((char *)buf + 4))); + break; + case 8: + printk(KERN_DEBUG "ar9170 FW: u8: %#.16lx\n", + (unsigned long)le64_to_cpup( + (__le64 *)((char *)buf + 4))); + break; + } + break; + case 0xcc: + print_hex_dump_bytes("ar9170 FW:", DUMP_PREFIX_NONE, + (char *)buf + 4, len - 4); + break; + default: printk(KERN_INFO "received unhandled event %x\n", cmd->type); print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); @@ -460,7 +585,7 @@ static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar) ar->rx_mpdu.has_plcp = false; } -static int ar9170_nag_limiter(struct ar9170 *ar) +int ar9170_nag_limiter(struct ar9170 *ar) { bool print_message; @@ -957,10 +1082,12 @@ static int ar9170_op_start(struct ieee80211_hw *hw) mutex_lock(&ar->mutex); + ar->filter_changed = 0; + /* reinitialize queues statistics */ memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); - for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++) - ar->tx_stats[i].limit = 8; + for (i = 0; i < __AR9170_NUM_TXQ; i++) + ar->tx_stats[i].limit = AR9170_TXQ_DEPTH; /* reset QoS defaults */ AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/ @@ -1006,18 +1133,17 @@ out: static void ar9170_op_stop(struct ieee80211_hw *hw) { struct ar9170 *ar = hw->priv; + unsigned int i; if (IS_STARTED(ar)) ar->state = AR9170_IDLE; flush_workqueue(ar->hw->workqueue); - mutex_lock(&ar->mutex); - cancel_delayed_work_sync(&ar->tx_status_janitor); + cancel_delayed_work_sync(&ar->tx_janitor); cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->beacon_work); - skb_queue_purge(&ar->global_tx_status_waste); - skb_queue_purge(&ar->global_tx_status); + mutex_lock(&ar->mutex); if (IS_ACCEPTING_CMD(ar)) { ar9170_set_leds_state(ar, 0); @@ -1027,51 +1153,32 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) ar->stop(ar); } + for (i = 0; i < __AR9170_NUM_TXQ; i++) { + skb_queue_purge(&ar->tx_pending[i]); + skb_queue_purge(&ar->tx_status[i]); + } mutex_unlock(&ar->mutex); } -int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) { - struct ar9170 *ar = hw->priv; struct ieee80211_hdr *hdr; struct ar9170_tx_control *txc; struct ieee80211_tx_info *info; - struct ieee80211_rate *rate = NULL; struct ieee80211_tx_rate *txrate; + struct ar9170_tx_info *arinfo; unsigned int queue = skb_get_queue_mapping(skb); - unsigned long flags = 0; - struct ar9170_sta_info *sta_info = NULL; - u32 power, chains; u16 keytype = 0; u16 len, icv = 0; - int err; - bool tx_status; - if (unlikely(!IS_STARTED(ar))) - goto err_free; + BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); hdr = (void *)skb->data; info = IEEE80211_SKB_CB(skb); len = skb->len; - spin_lock_irqsave(&ar->tx_stats_lock, flags); - if (ar->tx_stats[queue].limit < ar->tx_stats[queue].len) { - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - return NETDEV_TX_OK; - } - - ar->tx_stats[queue].len++; - ar->tx_stats[queue].count++; - if (ar->tx_stats[queue].limit == ar->tx_stats[queue].len) - ieee80211_stop_queue(hw, queue); - - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - txc = (void *)skb_push(skb, sizeof(*txc)); - tx_status = (((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) != 0) || - ((info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) != 0)); - if (info->control.hw_key) { icv = info->control.hw_key->icv_len; @@ -1087,7 +1194,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) break; default: WARN_ON(1); - goto err_dequeue; + goto err_out; } } @@ -1104,16 +1211,65 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (info->flags & IEEE80211_TX_CTL_NO_ACK) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); - if (info->flags & IEEE80211_TX_CTL_AMPDU) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); - txrate = &info->control.rates[0]; - if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); + arinfo = (void *)info->rate_driver_data; + arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_QUEUE_TIMEOUT); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (is_valid_ether_addr(ieee80211_get_DA(hdr)))) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + if (unlikely(!info->control.sta)) + goto err_out; + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); + arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK; + goto out; + } + + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); + /* + * WARNING: + * Putting the QoS queue bits into an unexplored territory is + * certainly not elegant. + * + * In my defense: This idea provides a reasonable way to + * smuggle valuable information to the tx_status callback. + * Also, the idea behind this bit-abuse came straight from + * the original driver code. + */ + + txc->phy_control |= + cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); + arinfo->flags = AR9170_TX_FLAG_WAIT_FOR_ACK; + } else { + arinfo->flags = AR9170_TX_FLAG_NO_ACK; + } + +out: + return 0; + +err_out: + skb_pull(skb, sizeof(*txc)); + return -EINVAL; +} + +static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ar9170_tx_control *txc; + struct ieee80211_tx_info *info; + struct ieee80211_rate *rate = NULL; + struct ieee80211_tx_rate *txrate; + u32 power, chains; + + txc = (void *) skb->data; + info = IEEE80211_SKB_CB(skb); + txrate = &info->control.rates[0]; + if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); @@ -1133,9 +1289,12 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) u32 r = txrate->idx; u8 *txpower; + /* heavy clip control */ + txc->phy_control |= cpu_to_le32((r & 0x7) << 7); + r <<= AR9170_TX_PHY_MCS_SHIFT; - if (WARN_ON(r & ~AR9170_TX_PHY_MCS_MASK)) - goto err_dequeue; + BUG_ON(r & ~AR9170_TX_PHY_MCS_MASK); + txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); @@ -1197,53 +1356,154 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) chains = AR9170_TX_PHY_TXCHAIN_1; } txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); +} - if (tx_status) { - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); - /* - * WARNING: - * Putting the QoS queue bits into an unexplored territory is - * certainly not elegant. - * - * In my defense: This idea provides a reasonable way to - * smuggle valuable information to the tx_status callback. - * Also, the idea behind this bit-abuse came straight from - * the original driver code. - */ +static void ar9170_tx(struct ar9170 *ar) +{ + struct sk_buff *skb; + unsigned long flags; + struct ieee80211_tx_info *info; + struct ar9170_tx_info *arinfo; + unsigned int i, frames, frames_failed, remaining_space; + int err; + bool schedule_garbagecollector = false; - txc->phy_control |= - cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); + BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); - if (info->control.sta) { - sta_info = (void *) info->control.sta->drv_priv; - skb_queue_tail(&sta_info->tx_status[queue], skb); - } else { - skb_queue_tail(&ar->global_tx_status, skb); + if (unlikely(!IS_STARTED(ar))) + return ; + + remaining_space = AR9170_TX_MAX_PENDING; + + for (i = 0; i < __AR9170_NUM_TXQ; i++) { + spin_lock_irqsave(&ar->tx_stats_lock, flags); + if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: queue %d full\n", + wiphy_name(ar->hw->wiphy), i); - queue_delayed_work(ar->hw->workqueue, - &ar->tx_status_janitor, - msecs_to_jiffies(100)); + __ar9170_dump_txstats(ar); + printk(KERN_DEBUG "stuck frames: ===> \n"); + ar9170_dump_txqueue(ar, &ar->tx_pending[i]); + ar9170_dump_txqueue(ar, &ar->tx_status[i]); +#endif /* AR9170_QUEUE_DEBUG */ + ieee80211_stop_queue(ar->hw, i); + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + continue; + } + + frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, + skb_queue_len(&ar->tx_pending[i])); + + if (remaining_space < frames) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: tx quota reached queue:%d, " + "remaining slots:%d, needed:%d\n", + wiphy_name(ar->hw->wiphy), i, remaining_space, + frames); + + ar9170_dump_txstats(ar); +#endif /* AR9170_QUEUE_DEBUG */ + frames = remaining_space; + } + + ar->tx_stats[i].len += frames; + ar->tx_stats[i].count += frames; + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); + + if (!frames) + continue; + + frames_failed = 0; + while (frames) { + skb = skb_dequeue(&ar->tx_pending[i]); + if (unlikely(!skb)) { + frames_failed += frames; + frames = 0; + break; + } + + info = IEEE80211_SKB_CB(skb); + arinfo = (void *) info->rate_driver_data; + + /* TODO: cancel stuck frames */ + arinfo->timeout = jiffies + + msecs_to_jiffies(AR9170_TX_TIMEOUT); + +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: send frame q:%d =>\n", + wiphy_name(ar->hw->wiphy), i); + ar9170_print_txheader(ar, skb); +#endif /* AR9170_QUEUE_DEBUG */ + + err = ar->tx(ar, skb); + if (unlikely(err)) { + frames_failed++; + dev_kfree_skb_any(skb); + } else { + remaining_space--; + schedule_garbagecollector = true; + } + + frames--; + } + +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: ar9170_tx report for queue %d\n", + wiphy_name(ar->hw->wiphy), i); + + printk(KERN_DEBUG "%s: unprocessed pending frames left:\n", + wiphy_name(ar->hw->wiphy)); + ar9170_dump_txqueue(ar, &ar->tx_pending[i]); +#endif /* AR9170_QUEUE_DEBUG */ + + if (unlikely(frames_failed)) { +#ifdef AR9170_QUEUE_DEBUG + printk(KERN_DEBUG "%s: frames failed =>\n", + wiphy_name(ar->hw->wiphy), frames_failed); +#endif /* AR9170_QUEUE_DEBUG */ + + spin_lock_irqsave(&ar->tx_stats_lock, flags); + ar->tx_stats[i].len -= frames_failed; + ar->tx_stats[i].count -= frames_failed; + ieee80211_wake_queue(ar->hw, i); + spin_unlock_irqrestore(&ar->tx_stats_lock, flags); } } - err = ar->tx(ar, skb, tx_status, 0); - if (unlikely(tx_status && err)) { - if (info->control.sta) - skb_unlink(skb, &sta_info->tx_status[queue]); - else - skb_unlink(skb, &ar->global_tx_status); + if (schedule_garbagecollector) + queue_delayed_work(ar->hw->workqueue, + &ar->tx_janitor, + msecs_to_jiffies(AR9170_JANITOR_DELAY)); +} + +int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ar9170 *ar = hw->priv; + struct ieee80211_tx_info *info; + + if (unlikely(!IS_STARTED(ar))) + goto err_free; + + if (unlikely(ar9170_tx_prepare(ar, skb))) + goto err_free; + + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + /* drop frame, we do not allow TX A-MPDU aggregation yet. */ + goto err_free; + } else { + unsigned int queue = skb_get_queue_mapping(skb); + + ar9170_tx_prepare_phy(ar, skb); + skb_queue_tail(&ar->tx_pending[queue], skb); } + ar9170_tx(ar); return NETDEV_TX_OK; -err_dequeue: - spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - ar->tx_stats[queue].count--; - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - err_free: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -1306,11 +1566,6 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&ar->mutex); - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - /* TODO */ - err = 0; - } - if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /* TODO */ err = 0; @@ -1344,15 +1599,21 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + + /* adjust slot time for 5 GHz */ + err = ar9170_set_slot_time(ar); + if (err) + goto out; + + err = ar9170_set_dyn_sifs_ack(ar); + if (err) + goto out; + err = ar9170_set_channel(ar, hw->conf.channel, AR9170_RFI_NONE, nl80211_to_ar9170(hw->conf.channel_type)); if (err) goto out; - /* adjust slot time for 5 GHz */ - if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) - err = ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, - 9 << 10); } out: @@ -1370,20 +1631,26 @@ static void ar9170_set_filters(struct work_struct *work) return ; mutex_lock(&ar->mutex); - if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) { + if (test_and_clear_bit(AR9170_FILTER_CHANGED_MODE, + &ar->filter_changed)) { err = ar9170_set_operating_mode(ar); if (err) goto unlock; } - if (ar->filter_changed & AR9170_FILTER_CHANGED_MULTICAST) { + if (test_and_clear_bit(AR9170_FILTER_CHANGED_MULTICAST, + &ar->filter_changed)) { err = ar9170_update_multicast(ar); if (err) goto unlock; } - if (ar->filter_changed & AR9170_FILTER_CHANGED_FRAMEFILTER) + if (test_and_clear_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, + &ar->filter_changed)) { err = ar9170_update_frame_filter(ar); + if (err) + goto unlock; + } unlock: mutex_unlock(&ar->mutex); @@ -1413,7 +1680,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, int i; /* always get broadcast frames */ - mchash = 1ULL << (0xff>>2); + mchash = 1ULL << (0xff >> 2); for (i = 0; i < mc_count; i++) { if (WARN_ON(!mclist)) @@ -1423,7 +1690,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, } ar->want_mc_hash = mchash; } - ar->filter_changed |= AR9170_FILTER_CHANGED_MULTICAST; + set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed); } if (changed_flags & FIF_CONTROL) { @@ -1439,12 +1706,14 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, else ar->want_filter = ar->cur_filter & ~filter; - ar->filter_changed |= AR9170_FILTER_CHANGED_FRAMEFILTER; + set_bit(AR9170_FILTER_CHANGED_FRAMEFILTER, + &ar->filter_changed); } if (changed_flags & FIF_PROMISC_IN_BSS) { ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; - ar->filter_changed |= AR9170_FILTER_CHANGED_PROMISC; + set_bit(AR9170_FILTER_CHANGED_MODE, + &ar->filter_changed); } if (likely(IS_STARTED(ar))) @@ -1464,27 +1733,32 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID) { memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN); err = ar9170_set_operating_mode(ar); + if (err) + goto out; } if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) { err = ar9170_update_beacon(ar); - if (!err) - ar9170_set_beacon_timers(ar); - } + if (err) + goto out; - ar9170_regwrite_begin(ar); + err = ar9170_set_beacon_timers(ar); + if (err) + goto out; + } if (changed & BSS_CHANGED_ASSOC) { - ar->state = bss_conf->assoc ? AR9170_ASSOCIATED : ar->state; - #ifndef CONFIG_AR9170_LEDS /* enable assoc LED. */ err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); #endif /* CONFIG_AR9170_LEDS */ } - if (changed & BSS_CHANGED_BEACON_INT) + if (changed & BSS_CHANGED_BEACON_INT) { err = ar9170_set_beacon_timers(ar); + if (err) + goto out; + } if (changed & BSS_CHANGED_HT) { /* TODO */ @@ -1492,31 +1766,18 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ERP_SLOT) { - u32 slottime = 20; - - if (bss_conf->use_short_slot) - slottime = 9; - - ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, slottime << 10); + err = ar9170_set_slot_time(ar); + if (err) + goto out; } if (changed & BSS_CHANGED_BASIC_RATES) { - u32 cck, ofdm; - - if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) { - ofdm = bss_conf->basic_rates; - cck = 0; - } else { - /* four cck rates */ - cck = bss_conf->basic_rates & 0xf; - ofdm = bss_conf->basic_rates >> 4; - } - ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, - ofdm << 8 | cck); + err = ar9170_set_basic_rates(ar); + if (err) + goto out; } - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); +out: mutex_unlock(&ar->mutex); } @@ -1668,43 +1929,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { - struct ar9170 *ar = hw->priv; - struct ar9170_sta_info *info = (void *) sta->drv_priv; - struct sk_buff *skb; - unsigned int i; - - switch (cmd) { - case STA_NOTIFY_ADD: - for (i = 0; i < ar->hw->queues; i++) - skb_queue_head_init(&info->tx_status[i]); - break; - - case STA_NOTIFY_REMOVE: - - /* - * transfer all outstanding frames that need a tx_status - * reports to the global tx_status queue - */ - - for (i = 0; i < ar->hw->queues; i++) { - while ((skb = skb_dequeue(&info->tx_status[i]))) { -#ifdef AR9170_QUEUE_DEBUG - printk(KERN_DEBUG "%s: queueing frame in " - "global tx_status queue =>\n", - wiphy_name(ar->hw->wiphy)); - - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - skb_queue_tail(&ar->global_tx_status, skb); - } - } - queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, - msecs_to_jiffies(100)); - break; - - default: - break; - } } static int ar9170_get_stats(struct ieee80211_hw *hw, @@ -1743,7 +1967,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, int ret; mutex_lock(&ar->mutex); - if ((param) && !(queue > ar->hw->queues)) { + if ((param) && !(queue > __AR9170_NUM_TXQ)) { memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], param, sizeof(*param)); @@ -1819,12 +2043,14 @@ void *ar9170_alloc(size_t priv_size) mutex_init(&ar->mutex); spin_lock_init(&ar->cmdlock); spin_lock_init(&ar->tx_stats_lock); - skb_queue_head_init(&ar->global_tx_status); - skb_queue_head_init(&ar->global_tx_status_waste); + for (i = 0; i < __AR9170_NUM_TXQ; i++) { + skb_queue_head_init(&ar->tx_status[i]); + skb_queue_head_init(&ar->tx_pending[i]); + } ar9170_rx_reset_rx_mpdu(ar); INIT_WORK(&ar->filter_config_work, ar9170_set_filters); INIT_WORK(&ar->beacon_work, ar9170_new_beacon); - INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor); + INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); /* all hw supports 2.4 GHz, so set channel to 1 by default */ ar->channel = &ar9170_2ghz_chantable[0]; diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index 6ce20754b8e7..df86f70cd817 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -401,7 +401,7 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) int i, err; u32 val; bool is_2ghz = band == IEEE80211_BAND_2GHZ; - bool is_40mhz = false; /* XXX: for now */ + bool is_40mhz = conf_is_ht40(&ar->hw->conf); ar9170_regwrite_begin(ar); @@ -1200,7 +1200,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, return -ENOSYS; } - if (0 /* 2 streams capable */) + if (ar->eeprom.tx_mask != 1) tmp |= 0x100; err = ar9170_write_reg(ar, 0x1c5804, tmp); @@ -1214,7 +1214,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, freqpar = ar9170_get_hw_dyn_params(channel, bw); vals[0] = cpu_to_le32(channel->center_freq * 1000); - vals[1] = cpu_to_le32(bw == AR9170_BW_20 ? 0 : 1); + vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf)); vals[2] = cpu_to_le32(offs << 2 | 1); vals[3] = cpu_to_le32(freqpar->coeff_exp); vals[4] = cpu_to_le32(freqpar->coeff_man); diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index d7c13c0177ca..754b1f8d8da9 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -51,9 +51,14 @@ MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); +MODULE_FIRMWARE("ar9170.fw"); MODULE_FIRMWARE("ar9170-1.fw"); MODULE_FIRMWARE("ar9170-2.fw"); +enum ar9170_requirements { + AR9170_REQ_FW1_ONLY = 1, +}; + static struct usb_device_id ar9170_usb_ids[] = { /* Atheros 9170 */ { USB_DEVICE(0x0cf3, 0x9170) }, @@ -81,25 +86,74 @@ static struct usb_device_id ar9170_usb_ids[] = { { USB_DEVICE(0x2019, 0x5304) }, /* IO-Data WNGDNUS2 */ { USB_DEVICE(0x04bb, 0x093f) }, + /* AVM FRITZ!WLAN USB Stick N */ + { USB_DEVICE(0x057C, 0x8401) }, + /* AVM FRITZ!WLAN USB Stick N 2.4 */ + { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY }, /* terminate */ {} }; MODULE_DEVICE_TABLE(usb, ar9170_usb_ids); -static void ar9170_usb_tx_urb_complete_free(struct urb *urb) +static void ar9170_usb_submit_urb(struct ar9170_usb *aru) +{ + struct urb *urb; + unsigned long flags; + int err; + + if (unlikely(!IS_STARTED(&aru->common))) + return ; + + spin_lock_irqsave(&aru->tx_urb_lock, flags); + if (aru->tx_submitted_urbs >= AR9170_NUM_TX_URBS) { + spin_unlock_irqrestore(&aru->tx_urb_lock, flags); + return ; + } + aru->tx_submitted_urbs++; + + urb = usb_get_from_anchor(&aru->tx_pending); + if (!urb) { + aru->tx_submitted_urbs--; + spin_unlock_irqrestore(&aru->tx_urb_lock, flags); + + return ; + } + spin_unlock_irqrestore(&aru->tx_urb_lock, flags); + + aru->tx_pending_urbs--; + usb_anchor_urb(urb, &aru->tx_submitted); + + err = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(err)) { + if (ar9170_nag_limiter(&aru->common)) + dev_err(&aru->udev->dev, "submit_urb failed (%d).\n", + err); + + usb_unanchor_urb(urb); + aru->tx_submitted_urbs--; + ar9170_tx_callback(&aru->common, urb->context); + } + + usb_free_urb(urb); +} + +static void ar9170_usb_tx_urb_complete_frame(struct urb *urb) { struct sk_buff *skb = urb->context; struct ar9170_usb *aru = (struct ar9170_usb *) usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); - if (!aru) { + if (unlikely(!aru)) { dev_kfree_skb_irq(skb); return ; } - ar9170_handle_tx_status(&aru->common, skb, false, - AR9170_TX_STATUS_COMPLETE); + aru->tx_submitted_urbs--; + + ar9170_tx_callback(&aru->common, skb); + + ar9170_usb_submit_urb(aru); } static void ar9170_usb_tx_urb_complete(struct urb *urb) @@ -126,8 +180,8 @@ static void ar9170_usb_irq_completed(struct urb *urb) goto resubmit; } - print_hex_dump_bytes("ar9170 irq: ", DUMP_PREFIX_OFFSET, - urb->transfer_buffer, urb->actual_length); + ar9170_handle_command_response(&aru->common, urb->transfer_buffer, + urb->actual_length); resubmit: usb_anchor_urb(urb, &aru->rx_submitted); @@ -177,16 +231,15 @@ resubmit: usb_anchor_urb(urb, &aru->rx_submitted); err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { + if (unlikely(err)) { usb_unanchor_urb(urb); - dev_kfree_skb_irq(skb); + goto free; } return ; free: dev_kfree_skb_irq(skb); - return; } static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, @@ -282,21 +335,47 @@ err_out: return err; } -static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) +static int ar9170_usb_flush(struct ar9170 *ar) { - int ret; + struct ar9170_usb *aru = (void *) ar; + struct urb *urb; + int ret, err = 0; - aru->common.state = AR9170_UNKNOWN_STATE; + if (IS_STARTED(ar)) + aru->common.state = AR9170_IDLE; - usb_unlink_anchored_urbs(&aru->tx_submitted); + usb_wait_anchor_empty_timeout(&aru->tx_pending, + msecs_to_jiffies(800)); + while ((urb = usb_get_from_anchor(&aru->tx_pending))) { + ar9170_tx_callback(&aru->common, (void *) urb->context); + usb_free_urb(urb); + } - /* give the LED OFF command and the deauth frame a chance to air. */ + /* lets wait a while until the tx - queues are dried out */ ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, msecs_to_jiffies(100)); if (ret == 0) - dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); - usb_poison_anchored_urbs(&aru->tx_submitted); + err = -ETIMEDOUT; + + usb_kill_anchored_urbs(&aru->tx_submitted); + + if (IS_ACCEPTING_CMD(ar)) + aru->common.state = AR9170_STARTED; + return err; +} + +static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) +{ + int err; + + aru->common.state = AR9170_UNKNOWN_STATE; + + err = ar9170_usb_flush(&aru->common); + if (err) + dev_err(&aru->udev->dev, "stuck tx urbs!\n"); + + usb_poison_anchored_urbs(&aru->tx_submitted); usb_poison_anchored_urbs(&aru->rx_submitted); } @@ -337,7 +416,7 @@ static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, usb_anchor_urb(urb, &aru->tx_submitted); err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { + if (unlikely(err)) { usb_unanchor_urb(urb); usb_free_urb(urb); goto err_unbuf; @@ -380,12 +459,10 @@ err_free: return err; } -static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb, - bool txstatus_needed, unsigned int extra_len) +static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb) { struct ar9170_usb *aru = (struct ar9170_usb *) ar; struct urb *urb; - int err; if (unlikely(!IS_STARTED(ar))) { /* Seriously, what were you drink... err... thinking!? */ @@ -398,18 +475,17 @@ static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb, usb_fill_bulk_urb(urb, aru->udev, usb_sndbulkpipe(aru->udev, AR9170_EP_TX), - skb->data, skb->len + extra_len, (txstatus_needed ? - ar9170_usb_tx_urb_complete : - ar9170_usb_tx_urb_complete_free), skb); + skb->data, skb->len, + ar9170_usb_tx_urb_complete_frame, skb); urb->transfer_flags |= URB_ZERO_PACKET; - usb_anchor_urb(urb, &aru->tx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) - usb_unanchor_urb(urb); + usb_anchor_urb(urb, &aru->tx_pending); + aru->tx_pending_urbs++; usb_free_urb(urb); - return err; + + ar9170_usb_submit_urb(aru); + return 0; } static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) @@ -418,7 +494,7 @@ static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) unsigned long flags; u32 in, out; - if (!buffer) + if (unlikely(!buffer)) return ; in = le32_to_cpup((__le32 *)buffer); @@ -504,17 +580,29 @@ static int ar9170_usb_request_firmware(struct ar9170_usb *aru) { int err = 0; - err = request_firmware(&aru->init_values, "ar9170-1.fw", + err = request_firmware(&aru->firmware, "ar9170.fw", &aru->udev->dev); - if (err) { - dev_err(&aru->udev->dev, "file with init values not found.\n"); - return err; + if (!err) { + aru->init_values = NULL; + return 0; + } + + if (aru->req_one_stage_fw) { + dev_err(&aru->udev->dev, "ar9170.fw firmware file " + "not found and is required for this device\n"); + return -EINVAL; } + dev_err(&aru->udev->dev, "ar9170.fw firmware file " + "not found, trying old firmware...\n"); + + err = request_firmware(&aru->init_values, "ar9170-1.fw", + &aru->udev->dev); + err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev); if (err) { release_firmware(aru->init_values); - dev_err(&aru->udev->dev, "firmware file not found.\n"); + dev_err(&aru->udev->dev, "file with init values not found.\n"); return err; } @@ -548,6 +636,9 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) { int err; + if (!aru->init_values) + goto upload_fw_start; + /* First, upload initial values to device RAM */ err = ar9170_usb_upload(aru, aru->init_values->data, aru->init_values->size, 0x102800, false); @@ -557,6 +648,8 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) return err; } +upload_fw_start: + /* Then, upload the firmware itself and start it */ return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, 0x200000, true); @@ -592,10 +685,8 @@ static void ar9170_usb_stop(struct ar9170 *ar) if (IS_ACCEPTING_CMD(ar)) aru->common.state = AR9170_STOPPED; - /* lets wait a while until the tx - queues are dried out */ - ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, - msecs_to_jiffies(1000)); - if (ret == 0) + ret = ar9170_usb_flush(ar); + if (ret) dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); usb_poison_anchored_urbs(&aru->tx_submitted); @@ -656,6 +747,15 @@ err_out: return err; } +static bool ar9170_requires_one_stage(const struct usb_device_id *id) +{ + if (!id->driver_info) + return false; + if (id->driver_info == AR9170_REQ_FW1_ONLY) + return true; + return false; +} + static int ar9170_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -676,14 +776,22 @@ static int ar9170_usb_probe(struct usb_interface *intf, aru->intf = intf; ar = &aru->common; + aru->req_one_stage_fw = ar9170_requires_one_stage(id); + usb_set_intfdata(intf, aru); SET_IEEE80211_DEV(ar->hw, &udev->dev); init_usb_anchor(&aru->rx_submitted); + init_usb_anchor(&aru->tx_pending); init_usb_anchor(&aru->tx_submitted); init_completion(&aru->cmd_wait); + spin_lock_init(&aru->tx_urb_lock); + + aru->tx_pending_urbs = 0; + aru->tx_submitted_urbs = 0; aru->common.stop = ar9170_usb_stop; + aru->common.flush = ar9170_usb_flush; aru->common.open = ar9170_usb_open; aru->common.tx = ar9170_usb_tx; aru->common.exec_cmd = ar9170_usb_exec_cmd; @@ -691,7 +799,7 @@ static int ar9170_usb_probe(struct usb_interface *intf, #ifdef CONFIG_PM udev->reset_resume = 1; -#endif +#endif /* CONFIG_PM */ err = ar9170_usb_reset(aru); if (err) goto err_freehw; @@ -776,11 +884,6 @@ static int ar9170_resume(struct usb_interface *intf) usb_unpoison_anchored_urbs(&aru->rx_submitted); usb_unpoison_anchored_urbs(&aru->tx_submitted); - /* - * FIXME: firmware upload will fail on resume. - * but this is better than a hang! - */ - err = ar9170_usb_init_device(aru); if (err) goto err_unrx; diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h index ac42586495d8..d098f4d5d2f2 100644 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ b/drivers/net/wireless/ath/ar9170/usb.h @@ -51,6 +51,7 @@ #include "ar9170.h" #define AR9170_NUM_RX_URBS 16 +#define AR9170_NUM_TX_URBS 8 struct firmware; @@ -60,9 +61,15 @@ struct ar9170_usb { struct usb_interface *intf; struct usb_anchor rx_submitted; + struct usb_anchor tx_pending; struct usb_anchor tx_submitted; - spinlock_t cmdlock; + bool req_one_stage_fw; + + spinlock_t tx_urb_lock; + unsigned int tx_submitted_urbs; + unsigned int tx_pending_urbs; + struct completion cmd_wait; int readlen; u8 *readbuf; diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile index 84a74c5248e5..090dc6d268a3 100644 --- a/drivers/net/wireless/ath/ath5k/Makefile +++ b/drivers/net/wireless/ath/ath5k/Makefile @@ -11,5 +11,6 @@ ath5k-y += reset.o ath5k-y += attach.o ath5k-y += base.o ath5k-y += led.o +ath5k-y += rfkill.o ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 813718210338..6358233bac99 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1256,6 +1256,10 @@ extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio); extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level); +/* rfkill Functions */ +extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah); +extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah); + /* Misc functions */ int ath5k_hw_set_capabilities(struct ath5k_hw *ah); extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index fb5193764afa..55f7de09d134 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2070,6 +2070,13 @@ err_unmap: return ret; } +static void ath5k_beacon_disable(struct ath5k_softc *sc) +{ + sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA); + ath5k_hw_set_imr(sc->ah, sc->imask); + ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq); +} + /* * Transmit a beacon frame at SWBA. Dynamic updates to the * frame contents are done as needed and the slot time is @@ -2353,6 +2360,8 @@ ath5k_init(struct ath5k_softc *sc) if (ret) goto done; + ath5k_rfkill_hw_start(ah); + /* * Reset the key cache since some parts do not reset the * contents on initial power up or resume from suspend. @@ -2461,6 +2470,8 @@ ath5k_stop_hw(struct ath5k_softc *sc) tasklet_kill(&sc->restq); tasklet_kill(&sc->beacontq); + ath5k_rfkill_hw_stop(sc->ah); + return ret; } @@ -2519,6 +2530,9 @@ ath5k_intr(int irq, void *dev_id) */ ath5k_hw_update_mib_counters(ah, &sc->ll_stats); } + if (status & AR5K_INT_GPIO) + tasklet_schedule(&sc->rf_kill.toggleq); + } } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); @@ -2757,6 +2771,7 @@ ath5k_remove_interface(struct ieee80211_hw *hw, goto end; ath5k_hw_set_lladdr(sc->ah, mac); + ath5k_beacon_disable(sc); sc->vif = NULL; end: mutex_unlock(&sc->lock); @@ -2775,11 +2790,9 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&sc->lock); - sc->bintval = conf->beacon_int; - ret = ath5k_chan_set(sc, conf->channel); if (ret < 0) - return ret; + goto unlock; if ((changed & IEEE80211_CONF_CHANGE_POWER) && (sc->power_level != conf->power_level)) { @@ -2808,8 +2821,9 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) */ ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT); +unlock: mutex_unlock(&sc->lock); - return 0; + return ret; } #define SUPPORTED_FIF_FLAGS \ @@ -3061,7 +3075,14 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { int ret; struct ath5k_softc *sc = hw->priv; - struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + struct sk_buff *skb; + + if (WARN_ON(!vif)) { + ret = -EINVAL; + goto out; + } + + skb = ieee80211_beacon_get(hw, vif); if (!skb) { ret = -ENOMEM; diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 852b2c189fd8..f9b7f2f819b7 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -46,6 +46,7 @@ #include <linux/wireless.h> #include <linux/if_ether.h> #include <linux/leds.h> +#include <linux/rfkill.h> #include "ath5k.h" #include "debug.h" @@ -91,6 +92,15 @@ struct ath5k_led struct led_classdev led_dev; /* led classdev */ }; +/* Rfkill */ +struct ath5k_rfkill { + /* GPIO PIN for rfkill */ + u16 gpio; + /* polarity of rfkill GPIO PIN */ + bool polarity; + /* RFKILL toggle tasklet */ + struct tasklet_struct toggleq; +}; #if CHAN_DEBUG #define ATH_CHAN_MAX (26+26+26+200+200) @@ -167,6 +177,8 @@ struct ath5k_softc { struct tasklet_struct txtq; /* tx intr tasklet */ struct ath5k_led tx_led; /* tx led */ + struct ath5k_rfkill rf_kill; + spinlock_t block; /* protects beacon */ struct tasklet_struct beacontq; /* beacon intr tasklet */ struct ath5k_buf *bbuf; /* beacon buffer */ diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 66067733ddd3..bd0a97a38d34 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1304,23 +1304,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, if (ah->ah_version != AR5K_AR5210) ath5k_hw_set_imr(ah, ah->ah_imr); - /* - * Setup RFKill interrupt if rfkill flag is set on eeprom. - * TODO: Use gpio pin and polarity infos from eeprom - * TODO: Handle this in ath5k_intr because it'll result - * a nasty interrupt storm. - */ -#if 0 - if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { - ath5k_hw_set_gpio_input(ah, 0); - ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0); - if (ah->ah_gpio[0] == 0) - ath5k_hw_set_gpio_intr(ah, 0, 1); - else - ath5k_hw_set_gpio_intr(ah, 0, 0); - } -#endif - /* Enable 32KHz clock function for AR5212+ chips * Set clocks to 32KHz operation and use an * external 32KHz crystal when sleeping if one diff --git a/drivers/net/wireless/ath/ath5k/rfkill.c b/drivers/net/wireless/ath/ath5k/rfkill.c new file mode 100644 index 000000000000..41a877b73fce --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/rfkill.c @@ -0,0 +1,121 @@ +/* + * RFKILL support for ath5k + * + * Copyright (c) 2009 Tobias Doerffel <tobias.doerffel@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "base.h" + + +static inline void ath5k_rfkill_disable(struct ath5k_softc *sc) +{ + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "rfkill disable (gpio:%d polarity:%d)\n", + sc->rf_kill.gpio, sc->rf_kill.polarity); + ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio); + ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, !sc->rf_kill.polarity); +} + + +static inline void ath5k_rfkill_enable(struct ath5k_softc *sc) +{ + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "rfkill enable (gpio:%d polarity:%d)\n", + sc->rf_kill.gpio, sc->rf_kill.polarity); + ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio); + ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, sc->rf_kill.polarity); +} + +static inline void ath5k_rfkill_set_intr(struct ath5k_softc *sc, bool enable) +{ + struct ath5k_hw *ah = sc->ah; + u32 curval; + + ath5k_hw_set_gpio_input(ah, sc->rf_kill.gpio); + curval = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio); + ath5k_hw_set_gpio_intr(ah, sc->rf_kill.gpio, enable ? + !!curval : !curval); +} + +static bool +ath5k_is_rfkill_set(struct ath5k_softc *sc) +{ + /* configuring GPIO for input for some reason disables rfkill */ + /*ath5k_hw_set_gpio_input(sc->ah, sc->rf_kill.gpio);*/ + return ath5k_hw_get_gpio(sc->ah, sc->rf_kill.gpio) == + sc->rf_kill.polarity; +} + +static void +ath5k_tasklet_rfkill_toggle(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + bool blocked; + + blocked = ath5k_is_rfkill_set(sc); + wiphy_rfkill_set_hw_state(sc->hw->wiphy, blocked); +} + + +void +ath5k_rfkill_hw_start(struct ath5k_hw *ah) +{ + struct ath5k_softc *sc = ah->ah_sc; + + /* read rfkill GPIO configuration from EEPROM header */ + sc->rf_kill.gpio = ah->ah_capabilities.cap_eeprom.ee_rfkill_pin; + sc->rf_kill.polarity = ah->ah_capabilities.cap_eeprom.ee_rfkill_pol; + + tasklet_init(&sc->rf_kill.toggleq, ath5k_tasklet_rfkill_toggle, + (unsigned long)sc); + + ath5k_rfkill_disable(sc); + + /* enable interrupt for rfkill switch */ + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) + ath5k_rfkill_set_intr(sc, true); +} + + +void +ath5k_rfkill_hw_stop(struct ath5k_hw *ah) +{ + struct ath5k_softc *sc = ah->ah_sc; + + /* disable interrupt for rfkill switch */ + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) + ath5k_rfkill_set_intr(sc, false); + + tasklet_kill(&sc->rf_kill.toggleq); + + /* enable RFKILL when stopping HW so Wifi LED is turned off */ + ath5k_rfkill_enable(sc); +} + diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 796a3adffea0..515880aa2116 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -460,12 +460,9 @@ struct ath_led { bool registered; }; -/* Rfkill */ -#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */ - struct ath_rfkill { struct rfkill *rfkill; - struct delayed_work rfkill_poll; + struct rfkill_ops ops; char rfkill_name[32]; }; @@ -509,8 +506,6 @@ struct ath_rfkill { #define SC_OP_RXFLUSH BIT(7) #define SC_OP_LED_ASSOCIATED BIT(8) #define SC_OP_RFKILL_REGISTERED BIT(9) -#define SC_OP_RFKILL_SW_BLOCKED BIT(10) -#define SC_OP_RFKILL_HW_BLOCKED BIT(11) #define SC_OP_WAIT_FOR_BEACON BIT(12) #define SC_OP_LED_ON BIT(13) #define SC_OP_SCANNING BIT(14) diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index a21b21339fbc..3639a2e6987d 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -411,6 +411,7 @@ void ath_beacon_tasklet(unsigned long data) } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { DPRINTF(sc, ATH_DBG_BEACON, "beacon is officially stuck\n"); + sc->sc_flags |= SC_OP_TSF_RESET; ath_reset(sc, false); } @@ -673,6 +674,14 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + /* + * It looks like mac80211 may end up using beacon interval of zero in + * some cases (at least for mesh point). Avoid getting into an + * infinite loop by using a bit safer value instead.. + */ + if (intval == 0) + intval = 100; + /* Pull nexttbtt forward to reflect the current TSF */ nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 97df20cbf528..6d20725d6451 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -44,6 +44,44 @@ static int ath9k_debugfs_open(struct inode *inode, struct file *file) return 0; } +static ssize_t read_file_debug(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[32]; + unsigned int len; + + len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.debug_mask); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_debug(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned long mask; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EINVAL; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &mask)) + return -EINVAL; + + sc->debug.debug_mask = mask; + return count; +} + +static const struct file_operations fops_debug = { + .read = read_file_debug, + .write = write_file_debug, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + static ssize_t read_file_dma(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -224,111 +262,66 @@ static const struct file_operations fops_interrupt = { .owner = THIS_MODULE }; -static void ath_debug_stat_11n_rc(struct ath_softc *sc, struct sk_buff *skb) -{ - struct ath_tx_info_priv *tx_info_priv = NULL; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->status.rates; - int final_ts_idx, idx; - - tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - final_ts_idx = tx_info_priv->tx.ts_rateindex; - idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate; - - sc->debug.stats.n_rcstats[idx].success++; -} - -static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb) +void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) { struct ath_tx_info_priv *tx_info_priv = NULL; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rates = tx_info->status.rates; int final_ts_idx, idx; + struct ath_rc_stats *stats; tx_info_priv = ATH_TX_INFO_PRIV(tx_info); final_ts_idx = tx_info_priv->tx.ts_rateindex; idx = rates[final_ts_idx].idx; - - sc->debug.stats.legacy_rcstats[idx].success++; -} - -void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) -{ - if (conf_is_ht(&sc->hw->conf)) - ath_debug_stat_11n_rc(sc, skb); - else - ath_debug_stat_legacy_rc(sc, skb); + stats = &sc->debug.stats.rcstats[idx]; + stats->success++; } -/* FIXME: legacy rates, later on .. */ void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per) { - if (conf_is_ht(&sc->hw->conf)) { - int idx = sc->cur_rate_table->info[rix].dot11rate; + struct ath_rc_stats *stats = &sc->debug.stats.rcstats[rix]; - sc->debug.stats.n_rcstats[idx].xretries += xretries; - sc->debug.stats.n_rcstats[idx].retries += retries; - sc->debug.stats.n_rcstats[idx].per = per; - } + stats->xretries += xretries; + stats->retries += retries; + stats->per = per; } -static ssize_t ath_read_file_stat_11n_rc(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; - char buf[1024]; - unsigned int len = 0; + char *buf; + unsigned int len = 0, max; int i = 0; + ssize_t retval; - len += sprintf(buf, "%7s %13s %8s %8s %6s\n\n", "Rate", "Success", - "Retries", "XRetries", "PER"); - - for (i = 0; i <= 15; i++) { - len += snprintf(buf + len, sizeof(buf) - len, - "%5s%3d: %8u %8u %8u %8u\n", "MCS", i, - sc->debug.stats.n_rcstats[i].success, - sc->debug.stats.n_rcstats[i].retries, - sc->debug.stats.n_rcstats[i].xretries, - sc->debug.stats.n_rcstats[i].per); - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} + if (sc->cur_rate_table == NULL) + return 0; -static ssize_t ath_read_file_stat_legacy_rc(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[512]; - unsigned int len = 0; - int i = 0; + max = 80 + sc->cur_rate_table->rate_cnt * 64; + buf = kmalloc(max + 1, GFP_KERNEL); + if (buf == NULL) + return 0; + buf[max] = 0; - len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success"); + len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success", + "Retries", "XRetries", "PER"); for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { - len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n", - sc->cur_rate_table->info[i].ratekbps / 1000, - sc->debug.stats.legacy_rcstats[i].success); + u32 ratekbps = sc->cur_rate_table->info[i].ratekbps; + struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i]; + + len += snprintf(buf + len, max - len, + "%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000, + (ratekbps % 1000) / 100, stats->success, + stats->retries, stats->xretries, + stats->per); } - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - - if (sc->cur_rate_table == NULL) - return 0; - - if (conf_is_ht(&sc->hw->conf)) - return ath_read_file_stat_11n_rc(file, user_buf, count, ppos); - else - return ath_read_file_stat_legacy_rc(file, user_buf, count ,ppos); + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return retval; } static const struct file_operations fops_rcstat = { @@ -506,6 +499,11 @@ int ath9k_init_debug(struct ath_softc *sc) if (!sc->debug.debugfs_phy) goto err; + sc->debug.debugfs_debug = debugfs_create_file("debug", + S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); + if (!sc->debug.debugfs_debug) + goto err; + sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, sc->debug.debugfs_phy, sc, &fops_dma); if (!sc->debug.debugfs_dma) @@ -543,6 +541,7 @@ void ath9k_exit_debug(struct ath_softc *sc) debugfs_remove(sc->debug.debugfs_rcstat); debugfs_remove(sc->debug.debugfs_interrupt); debugfs_remove(sc->debug.debugfs_dma); + debugfs_remove(sc->debug.debugfs_debug); debugfs_remove(sc->debug.debugfs_phy); } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index db845cf960c9..edda15bf2c15 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -80,11 +80,7 @@ struct ath_interrupt_stats { u32 dtim; }; -struct ath_legacy_rc_stats { - u32 success; -}; - -struct ath_11n_rc_stats { +struct ath_rc_stats { u32 success; u32 retries; u32 xretries; @@ -93,13 +89,13 @@ struct ath_11n_rc_stats { struct ath_stats { struct ath_interrupt_stats istats; - struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */ - struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */ + struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; }; struct ath9k_debug { int debug_mask; struct dentry *debugfs_phy; + struct dentry *debugfs_debug; struct dentry *debugfs_dma; struct dentry *debugfs_interrupt; struct dentry *debugfs_rcstat; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 61da08a1648c..f7baa406918b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1192,120 +1192,69 @@ static bool ath_is_rfkill_set(struct ath_softc *sc) ah->rfkill_polarity; } -/* h/w rfkill poll function */ -static void ath_rfkill_poll(struct work_struct *work) +/* s/w rfkill handlers */ +static int ath_rfkill_set_block(void *data, bool blocked) { - struct ath_softc *sc = container_of(work, struct ath_softc, - rf_kill.rfkill_poll.work); - bool radio_on; - - if (sc->sc_flags & SC_OP_INVALID) - return; - - radio_on = !ath_is_rfkill_set(sc); - - /* - * enable/disable radio only when there is a - * state change in RF switch - */ - if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) { - enum rfkill_state state; - - if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) { - state = radio_on ? RFKILL_STATE_SOFT_BLOCKED - : RFKILL_STATE_HARD_BLOCKED; - } else if (radio_on) { - ath_radio_enable(sc); - state = RFKILL_STATE_UNBLOCKED; - } else { - ath_radio_disable(sc); - state = RFKILL_STATE_HARD_BLOCKED; - } - - if (state == RFKILL_STATE_HARD_BLOCKED) - sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED; - else - sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED; + struct ath_softc *sc = data; - rfkill_force_state(sc->rf_kill.rfkill, state); - } + if (blocked) + ath_radio_disable(sc); + else + ath_radio_enable(sc); - queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll, - msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL)); + return 0; } -/* s/w rfkill handler */ -static int ath_sw_toggle_radio(void *data, enum rfkill_state state) +static void ath_rfkill_poll_state(struct rfkill *rfkill, void *data) { struct ath_softc *sc = data; + bool blocked = !!ath_is_rfkill_set(sc); - switch (state) { - case RFKILL_STATE_SOFT_BLOCKED: - if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED | - SC_OP_RFKILL_SW_BLOCKED))) - ath_radio_disable(sc); - sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED; - return 0; - case RFKILL_STATE_UNBLOCKED: - if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) { - sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED; - if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) { - DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the" - "radio as it is disabled by h/w\n"); - return -EPERM; - } - ath_radio_enable(sc); - } - return 0; - default: - return -EINVAL; - } + if (rfkill_set_hw_state(rfkill, blocked)) + ath_radio_disable(sc); + else + ath_radio_enable(sc); } /* Init s/w rfkill */ static int ath_init_sw_rfkill(struct ath_softc *sc) { - sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy), - RFKILL_TYPE_WLAN); + sc->rf_kill.ops.set_block = ath_rfkill_set_block; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + sc->rf_kill.ops.poll = ath_rfkill_poll_state; + + snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), + "ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy)); + + sc->rf_kill.rfkill = rfkill_alloc(sc->rf_kill.rfkill_name, + wiphy_dev(sc->hw->wiphy), + RFKILL_TYPE_WLAN, + &sc->rf_kill.ops, sc); if (!sc->rf_kill.rfkill) { DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n"); return -ENOMEM; } - snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name), - "ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy)); - sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name; - sc->rf_kill.rfkill->data = sc; - sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio; - sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED; - return 0; } /* Deinitialize rfkill */ static void ath_deinit_rfkill(struct ath_softc *sc) { - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); - if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { rfkill_unregister(sc->rf_kill.rfkill); + rfkill_destroy(sc->rf_kill.rfkill); sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; - sc->rf_kill.rfkill = NULL; } } static int ath_start_rfkill_poll(struct ath_softc *sc) { - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - queue_delayed_work(sc->hw->workqueue, - &sc->rf_kill.rfkill_poll, 0); - if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { if (rfkill_register(sc->rf_kill.rfkill)) { DPRINTF(sc, ATH_DBG_FATAL, "Unable to register rfkill\n"); - rfkill_free(sc->rf_kill.rfkill); + rfkill_destroy(sc->rf_kill.rfkill); /* Deinitialize the device */ ath_cleanup(sc); @@ -1678,10 +1627,6 @@ int ath_attach(u16 devid, struct ath_softc *sc) goto error_attach; #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - /* Initialze h/w Rfkill */ - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); - /* Initialize s/w rfkill */ error = ath_init_sw_rfkill(sc); if (error) @@ -2214,10 +2159,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) } else sc->rx.rxlink = NULL; -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); -#endif + rfkill_pause_polling(sc->rf_kill.rfkill); + /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); ath9k_hw_configpcipowersave(sc->sc_ah, 1); diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 168411d322a2..ccdf20a2e9be 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -227,11 +227,6 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); -#endif - pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); @@ -256,16 +251,6 @@ static int ath_pci_resume(struct pci_dev *pdev) AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) - /* - * check the h/w rfkill state on resume - * and start the rfkill poll timer - */ - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - queue_delayed_work(sc->hw->workqueue, - &sc->rf_kill.rfkill_poll, 0); -#endif - return 0; } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a8def4fa449c..b61a071788a5 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -711,6 +711,7 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) return 0; if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { + txtid->state &= ~AGGR_ADDBA_PROGRESS; txtid->addba_exchangeattempts = 0; return 0; } diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 7a89f9fac7d4..eef370bd1211 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -366,11 +366,17 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) if (rd & COUNTRY_ERD_FLAG) { /* EEPROM value is a country code */ u16 cc = rd & ~COUNTRY_ERD_FLAG; + printk(KERN_DEBUG + "ath: EEPROM indicates we should expect " + "a country code\n"); for (i = 0; i < ARRAY_SIZE(allCountries); i++) if (allCountries[i].countryCode == cc) return true; } else { /* EEPROM value is a regpair value */ + if (rd != CTRY_DEFAULT) + printk(KERN_DEBUG "ath: EEPROM indicates we " + "should expect a direct regpair map\n"); for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) if (regDomainPairs[i].regDmnEnum == rd) return true; @@ -477,6 +483,11 @@ ath_regd_init(struct ath_regulatory *reg, struct country_code_to_enum_rd *country = NULL; u16 regdmn; + if (!reg) + return -EINVAL; + + printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd); + if (!ath_regd_is_eeprom_valid(reg)) { printk(KERN_ERR "ath: Invalid EEPROM contents\n"); return -EINVAL; @@ -486,20 +497,30 @@ ath_regd_init(struct ath_regulatory *reg, reg->country_code = ath_regd_get_default_country(regdmn); if (reg->country_code == CTRY_DEFAULT && - regdmn == CTRY_DEFAULT) + regdmn == CTRY_DEFAULT) { + printk(KERN_DEBUG "ath: EEPROM indicates default " + "country code should be used\n"); reg->country_code = CTRY_UNITED_STATES; + } if (reg->country_code == CTRY_DEFAULT) { country = NULL; } else { + printk(KERN_DEBUG "ath: doing EEPROM country->regdmn " + "map search\n"); country = ath_regd_find_country(reg->country_code); if (country == NULL) { printk(KERN_DEBUG - "ath: Country is NULL!!!!, cc= %d\n", + "ath: no valid country maps found for " + "country code: 0x%0x\n", reg->country_code); return -EINVAL; - } else + } else { regdmn = country->regDmnEnum; + printk(KERN_DEBUG "ath: country maps to " + "regdmn code: 0x%0x\n", + regdmn); + } } reg->regpair = ath_get_regpair(regdmn); @@ -523,7 +544,7 @@ ath_regd_init(struct ath_regulatory *reg, printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", reg->alpha2[0], reg->alpha2[1]); - printk(KERN_DEBUG "ath: Regpair detected: 0x%0x\n", + printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", reg->regpair->regDmnEnum); ath_regd_init_wiphy(reg, wiphy, reg_notifier); diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 21572e40b79d..67f564e37225 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -98,13 +98,6 @@ config B43_LEDS depends on B43 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43) default y -# This config option automatically enables b43 RFKILL support, -# if it's possible. -config B43_RFKILL - bool - depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43) - default y - # This config option automatically enables b43 HW-RNG support, # if the HW-RNG core is enabled. config B43_HWRNG diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 281ef8310350..da379f4b0c3a 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -13,7 +13,7 @@ b43-y += lo.o b43-y += wa.o b43-y += dma.o b43-$(CONFIG_B43_PIO) += pio.o -b43-$(CONFIG_B43_RFKILL) += rfkill.o +b43-y += rfkill.o b43-$(CONFIG_B43_LEDS) += leds.o b43-$(CONFIG_B43_PCMCIA) += pcmcia.o b43-$(CONFIG_B43_DEBUG) += debugfs.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 4e8ad841c3c5..f580c2812d91 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -163,6 +163,7 @@ enum { #define B43_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */ #define B43_SHM_SH_PCTLWDPOS 0x0008 #define B43_SHM_SH_RXPADOFF 0x0034 /* RX Padding data offset (PIO only) */ +#define B43_SHM_SH_FWCAPA 0x0042 /* Firmware capabilities (Opensource firmware only) */ #define B43_SHM_SH_PHYVER 0x0050 /* PHY version */ #define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */ #define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */ @@ -297,6 +298,10 @@ enum { #define B43_HF_MLADVW 0x001000000000ULL /* N PHY ML ADV workaround (rev >= 13 only) */ #define B43_HF_PR45960W 0x080000000000ULL /* PR 45960 workaround (rev >= 13 only) */ +/* Firmware capabilities field in SHM (Opensource firmware only) */ +#define B43_FWCAPA_HWCRYPTO 0x0001 +#define B43_FWCAPA_QOS 0x0002 + /* MacFilter offsets. */ #define B43_MACFILTER_SELF 0x0000 #define B43_MACFILTER_BSSID 0x0003 @@ -596,6 +601,13 @@ struct b43_wl { /* Pointer to the ieee80211 hardware data structure */ struct ieee80211_hw *hw; + /* The number of queues that were registered with the mac80211 subsystem + * initially. This is a backup copy of hw->queues in case hw->queues has + * to be dynamically lowered at runtime (Firmware does not support QoS). + * hw->queues has to be restored to the original value before unregistering + * from the mac80211 subsystem. */ + u16 mac80211_initially_registered_queues; + struct mutex mutex; spinlock_t irq_lock; /* R/W lock for data transmission. @@ -631,9 +643,6 @@ struct b43_wl { char rng_name[30 + 1]; #endif /* CONFIG_B43_HWRNG */ - /* The RF-kill button */ - struct b43_rfkill rfkill; - /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; @@ -752,6 +761,8 @@ struct b43_wldev { bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */ + bool qos_enabled; /* TRUE, if QoS is used. */ + bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */ /* PHY/Radio device. */ struct b43_phy phy; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index eae680b53052..7964cc32b258 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1285,7 +1285,7 @@ static struct b43_dmaring *select_ring_by_priority(struct b43_wldev *dev, { struct b43_dmaring *ring; - if (b43_modparam_qos) { + if (dev->qos_enabled) { /* 0 = highest priority */ switch (queue_prio) { default: diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 76f4c7bad8b8..c8b317094c31 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -28,6 +28,7 @@ #include "b43.h" #include "leds.h" +#include "rfkill.h" static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index, @@ -87,7 +88,7 @@ static void b43_led_brightness_set(struct led_classdev *led_dev, } static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, - const char *name, char *default_trigger, + const char *name, const char *default_trigger, u8 led_index, bool activelow) { int err; @@ -164,10 +165,10 @@ static void b43_map_led(struct b43_wldev *dev, snprintf(name, sizeof(name), "b43-%s::radio", wiphy_name(hw->wiphy)); b43_register_led(dev, &dev->led_radio, name, - b43_rfkill_led_name(dev), + ieee80211_get_radio_led_name(hw), led_index, activelow); - /* Sync the RF-kill LED state with the switch state. */ - if (dev->radio_hw_enable) + /* Sync the RF-kill LED state with radio and switch states. */ + if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev)) b43_led_turn_on(dev, led_index, activelow); break; case B43_LED_WEIRD: diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index cb4a8712946a..6456afebdba1 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -80,8 +80,8 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -int b43_modparam_qos = 1; -module_param_named(qos, b43_modparam_qos, int, 0444); +static int modparam_qos = 1; +module_param_named(qos, modparam_qos, int, 0444); MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); static int modparam_btcoex = 1; @@ -538,6 +538,13 @@ void b43_hf_write(struct b43_wldev *dev, u64 value) b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi); } +/* Read the firmware capabilities bitmask (Opensource firmware only) */ +static u16 b43_fwcapa_read(struct b43_wldev *dev) +{ + B43_WARN_ON(!dev->fw.opensource); + return b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_FWCAPA); +} + void b43_tsf_read(struct b43_wldev *dev, u64 *tsf) { u32 low, high; @@ -2307,12 +2314,34 @@ static int b43_upload_microcode(struct b43_wldev *dev) dev->fw.patch = fwpatch; dev->fw.opensource = (fwdate == 0xFFFF); + /* Default to use-all-queues. */ + dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues; + dev->qos_enabled = !!modparam_qos; + /* Default to firmware/hardware crypto acceleration. */ + dev->hwcrypto_enabled = 1; + if (dev->fw.opensource) { + u16 fwcapa; + /* Patchlevel info is encoded in the "time" field. */ dev->fw.patch = fwtime; - b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n", - dev->fw.rev, dev->fw.patch, - dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : ""); + b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n", + dev->fw.rev, dev->fw.patch); + + fwcapa = b43_fwcapa_read(dev); + if (!(fwcapa & B43_FWCAPA_HWCRYPTO) || dev->fw.pcm_request_failed) { + b43info(dev->wl, "Hardware crypto acceleration not supported by firmware\n"); + /* Disable hardware crypto and fall back to software crypto. */ + dev->hwcrypto_enabled = 0; + } + if (!(fwcapa & B43_FWCAPA_QOS)) { + b43info(dev->wl, "QoS not supported by firmware\n"); + /* Disable QoS. Tweak hw->queues to 1. It will be restored before + * ieee80211_unregister to make sure the networking core can + * properly free possible resources. */ + dev->wl->hw->queues = 1; + dev->qos_enabled = 0; + } } else { b43info(dev->wl, "Loading firmware version %u.%u " "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", @@ -3470,7 +3499,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) if (!!conf->radio_enabled != phy->radio_on) { if (conf->radio_enabled) { - b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED); + b43_software_rfkill(dev, false); b43info(dev->wl, "Radio turned on by software\n"); if (!dev->radio_hw_enable) { b43info(dev->wl, "The hardware RF-kill button " @@ -3478,7 +3507,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) "Press the button to turn it on.\n"); } } else { - b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + b43_software_rfkill(dev, true); b43info(dev->wl, "Radio turned off by software\n"); } } @@ -3627,7 +3656,7 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) goto out_unlock; - if (dev->fw.pcm_request_failed) { + if (dev->fw.pcm_request_failed || !dev->hwcrypto_enabled) { /* We don't have firmware for the crypto engine. * Must use software-crypto. */ err = -EOPNOTSUPP; @@ -4298,7 +4327,6 @@ static int b43_op_start(struct ieee80211_hw *hw) struct b43_wldev *dev = wl->current_dev; int did_init = 0; int err = 0; - bool do_rfkill_exit = 0; /* Kill all old instance specific information to make sure * the card won't use it in the short timeframe between start @@ -4312,18 +4340,12 @@ static int b43_op_start(struct ieee80211_hw *hw) wl->beacon1_uploaded = 0; wl->beacon_templates_virgin = 1; - /* First register RFkill. - * LEDs that are registered later depend on it. */ - b43_rfkill_init(dev); - mutex_lock(&wl->mutex); if (b43_status(dev) < B43_STAT_INITIALIZED) { err = b43_wireless_core_init(dev); - if (err) { - do_rfkill_exit = 1; + if (err) goto out_mutex_unlock; - } did_init = 1; } @@ -4332,17 +4354,16 @@ static int b43_op_start(struct ieee80211_hw *hw) if (err) { if (did_init) b43_wireless_core_exit(dev); - do_rfkill_exit = 1; goto out_mutex_unlock; } } + /* XXX: only do if device doesn't support rfkill irq */ + wiphy_rfkill_start_polling(hw->wiphy); + out_mutex_unlock: mutex_unlock(&wl->mutex); - if (do_rfkill_exit) - b43_rfkill_exit(dev); - return err; } @@ -4351,7 +4372,6 @@ static void b43_op_stop(struct ieee80211_hw *hw) struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; - b43_rfkill_exit(dev); cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); @@ -4433,6 +4453,7 @@ static const struct ieee80211_ops b43_hw_ops = { .sta_notify = b43_op_sta_notify, .sw_scan_start = b43_op_sw_scan_start_notifier, .sw_scan_complete = b43_op_sw_scan_complete_notifier, + .rfkill_poll = b43_rfkill_poll, }; /* Hard-reset the chip. Do not call this directly. @@ -4735,6 +4756,7 @@ static int b43_wireless_init(struct ssb_device *dev) b43err(NULL, "Could not allocate ieee80211 device\n"); goto out; } + wl = hw_to_b43_wl(hw); /* fill hw info */ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | @@ -4748,7 +4770,8 @@ static int b43_wireless_init(struct ssb_device *dev) BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_ADHOC); - hw->queues = b43_modparam_qos ? 4 : 1; + hw->queues = modparam_qos ? 4 : 1; + wl->mac80211_initially_registered_queues = hw->queues; hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) @@ -4756,9 +4779,7 @@ static int b43_wireless_init(struct ssb_device *dev) else SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); - /* Get and initialize struct b43_wl */ - wl = hw_to_b43_wl(hw); - memset(wl, 0, sizeof(*wl)); + /* Initialize struct b43_wl */ wl->hw = hw; spin_lock_init(&wl->irq_lock); rwlock_init(&wl->tx_lock); @@ -4824,8 +4845,13 @@ static void b43_remove(struct ssb_device *dev) cancel_work_sync(&wldev->restart_work); B43_WARN_ON(!wl); - if (wl->current_dev == wldev) + if (wl->current_dev == wldev) { + /* Restore the queues count before unregistering, because firmware detect + * might have modified it. Restoring is important, so the networking + * stack can properly free resources. */ + wl->hw->queues = wl->mac80211_initially_registered_queues; ieee80211_unregister_hw(wl->hw); + } b43_one_core_detach(dev); @@ -4920,7 +4946,7 @@ static struct ssb_driver b43_ssb_driver = { static void b43_print_driverinfo(void) { const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "", - *feat_leds = "", *feat_rfkill = ""; + *feat_leds = ""; #ifdef CONFIG_B43_PCI_AUTOSELECT feat_pci = "P"; @@ -4934,14 +4960,11 @@ static void b43_print_driverinfo(void) #ifdef CONFIG_B43_LEDS feat_leds = "L"; #endif -#ifdef CONFIG_B43_RFKILL - feat_rfkill = "R"; -#endif printk(KERN_INFO "Broadcom 43xx driver loaded " - "[ Features: %s%s%s%s%s, Firmware-ID: " + "[ Features: %s%s%s%s, Firmware-ID: " B43_SUPPORTED_FIRMWARE_ID " ]\n", feat_pci, feat_pcmcia, feat_nphy, - feat_leds, feat_rfkill); + feat_leds); } static int __init b43_init(void) diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 40abcf5d1b43..950fb1b0546d 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -39,7 +39,6 @@ #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) -extern int b43_modparam_qos; extern int b43_modparam_verbose; /* Logmessage verbosity levels. Update the b43_modparam_verbose helptext, if diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index c836c077d51d..816e028a2620 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -480,11 +480,11 @@ static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev) } static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) + bool blocked) { struct b43_phy *phy = &dev->phy; - if (state == RFKILL_STATE_UNBLOCKED) { + if (!blocked) { if (phy->radio_on) return; b43_radio_write16(dev, 0x0004, 0x00C0); diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index e176b6e0d9cf..6d241622210e 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -84,7 +84,7 @@ int b43_phy_init(struct b43_wldev *dev) phy->channel = ops->get_default_chan(dev); - ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED); + ops->software_rfkill(dev, false); err = ops->init(dev); if (err) { b43err(dev->wl, "PHY init failed\n"); @@ -104,7 +104,7 @@ err_phy_exit: if (ops->exit) ops->exit(dev); err_block_rf: - ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + ops->software_rfkill(dev, true); return err; } @@ -113,7 +113,7 @@ void b43_phy_exit(struct b43_wldev *dev) { const struct b43_phy_operations *ops = dev->phy.ops; - ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + ops->software_rfkill(dev, true); if (ops->exit) ops->exit(dev); } @@ -295,18 +295,13 @@ err_restore_cookie: return err; } -void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) +void b43_software_rfkill(struct b43_wldev *dev, bool blocked) { struct b43_phy *phy = &dev->phy; - if (state == RFKILL_STATE_HARD_BLOCKED) { - /* We cannot hardware-block the device */ - state = RFKILL_STATE_SOFT_BLOCKED; - } - b43_mac_suspend(dev); - phy->ops->software_rfkill(dev, state); - phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); + phy->ops->software_rfkill(dev, blocked); + phy->radio_on = !blocked; b43_mac_enable(dev); } diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index b2d99101947b..44cc918e4fc6 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -1,7 +1,7 @@ #ifndef LINUX_B43_PHY_COMMON_H_ #define LINUX_B43_PHY_COMMON_H_ -#include <linux/rfkill.h> +#include <linux/types.h> struct b43_wldev; @@ -159,7 +159,7 @@ struct b43_phy_operations { /* Radio */ bool (*supports_hwpctl)(struct b43_wldev *dev); - void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state); + void (*software_rfkill)(struct b43_wldev *dev, bool blocked); void (*switch_analog)(struct b43_wldev *dev, bool on); int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel); unsigned int (*get_default_chan)(struct b43_wldev *dev); @@ -364,7 +364,7 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); /** * b43_software_rfkill - Turn the radio ON or OFF in software. */ -void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); +void b43_software_rfkill(struct b43_wldev *dev, bool blocked); /** * b43_phy_txpower_check - Check TX power output. diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index e7b98f013b0f..5300232449f6 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2592,7 +2592,7 @@ static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev) } static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) + bool blocked) { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; @@ -2600,7 +2600,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, might_sleep(); - if (state == RFKILL_STATE_UNBLOCKED) { + if (!blocked) { /* Turn radio ON */ if (phy->radio_on) return; diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 58e319d6b1ed..ea0d3a3a6a64 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -488,7 +488,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) } static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) + bool blocked) { //TODO } diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8bcfda5f3f07..be7b5604947b 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -579,7 +579,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) } static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, - enum rfkill_state state) + bool blocked) {//TODO } diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 8cd9776752e6..69138e8c1db6 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -313,7 +313,7 @@ static struct b43_pio_txqueue *select_queue_by_priority(struct b43_wldev *dev, { struct b43_pio_txqueue *q; - if (b43_modparam_qos) { + if (dev->qos_enabled) { /* 0 = highest priority */ switch (queue_prio) { default: diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 9e1d00bc24d3..31e55999893f 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -22,15 +22,11 @@ */ -#include "rfkill.h" #include "b43.h" -#include "phy_common.h" - -#include <linux/kmod.h> /* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) +bool b43_is_hw_radio_enabled(struct b43_wldev *dev) { if (dev->phy.rev >= 3) { if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI) @@ -45,165 +41,39 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) } /* The poll callback for the hardware button. */ -static void b43_rfkill_poll(struct input_polled_dev *poll_dev) +void b43_rfkill_poll(struct ieee80211_hw *hw) { - struct b43_wldev *dev = poll_dev->private; - struct b43_wl *wl = dev->wl; + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + struct ssb_bus *bus = dev->dev->bus; bool enabled; - bool report_change = 0; + bool brought_up = false; mutex_lock(&wl->mutex); if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) { - mutex_unlock(&wl->mutex); - return; + if (ssb_bus_powerup(bus, 0)) { + mutex_unlock(&wl->mutex); + return; + } + ssb_device_enable(dev->dev, 0); + brought_up = true; } + enabled = b43_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; - report_change = 1; b43info(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); + wiphy_rfkill_set_hw_state(hw->wiphy, !enabled); + if (enabled != dev->phy.radio_on) + b43_software_rfkill(dev, !enabled); } - mutex_unlock(&wl->mutex); - /* send the radio switch event to the system - note both a key press - * and a release are required */ - if (unlikely(report_change)) { - input_report_key(poll_dev->input, KEY_WLAN, 1); - input_report_key(poll_dev->input, KEY_WLAN, 0); + if (brought_up) { + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(bus); } -} - -/* Called when the RFKILL toggled in software. */ -static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) -{ - struct b43_wldev *dev = data; - struct b43_wl *wl = dev->wl; - int err = -EBUSY; - if (!wl->rfkill.registered) - return 0; - - mutex_lock(&wl->mutex); - if (b43_status(dev) < B43_STAT_INITIALIZED) - goto out_unlock; - err = 0; - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (!dev->radio_hw_enable) { - /* No luck. We can't toggle the hardware RF-kill - * button from software. */ - err = -EBUSY; - goto out_unlock; - } - if (!dev->phy.radio_on) - b43_software_rfkill(dev, state); - break; - case RFKILL_STATE_SOFT_BLOCKED: - if (dev->phy.radio_on) - b43_software_rfkill(dev, state); - break; - default: - b43warn(wl, "Received unexpected rfkill state %d.\n", state); - break; - } -out_unlock: mutex_unlock(&wl->mutex); - - return err; -} - -char *b43_rfkill_led_name(struct b43_wldev *dev) -{ - struct b43_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return NULL; - return rfkill_get_led_name(rfk->rfkill); -} - -void b43_rfkill_init(struct b43_wldev *dev) -{ - struct b43_wl *wl = dev->wl; - struct b43_rfkill *rfk = &(wl->rfkill); - int err; - - rfk->registered = 0; - - rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); - if (!rfk->rfkill) - goto out_error; - snprintf(rfk->name, sizeof(rfk->name), - "b43-%s", wiphy_name(wl->hw->wiphy)); - rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; - rfk->rfkill->data = dev; - rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; - - rfk->poll_dev = input_allocate_polled_device(); - if (!rfk->poll_dev) { - rfkill_free(rfk->rfkill); - goto err_freed_rfk; - } - - rfk->poll_dev->private = dev; - rfk->poll_dev->poll = b43_rfkill_poll; - rfk->poll_dev->poll_interval = 1000; /* msecs */ - - rfk->poll_dev->input->name = rfk->name; - rfk->poll_dev->input->id.bustype = BUS_HOST; - rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; - rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); - - err = rfkill_register(rfk->rfkill); - if (err) - goto err_free_polldev; - -#ifdef CONFIG_RFKILL_INPUT_MODULE - /* B43 RF-kill isn't useful without the rfkill-input subsystem. - * Try to load the module. */ - err = request_module("rfkill-input"); - if (err) - b43warn(wl, "Failed to load the rfkill-input module. " - "The built-in radio LED will not work.\n"); -#endif /* CONFIG_RFKILL_INPUT */ - -#if !defined(CONFIG_RFKILL_INPUT) && !defined(CONFIG_RFKILL_INPUT_MODULE) - b43warn(wl, "The rfkill-input subsystem is not available. " - "The built-in radio LED will not work.\n"); -#endif - - err = input_register_polled_device(rfk->poll_dev); - if (err) - goto err_unreg_rfk; - - rfk->registered = 1; - - return; -err_unreg_rfk: - rfkill_unregister(rfk->rfkill); -err_free_polldev: - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; -err_freed_rfk: - rfk->rfkill = NULL; -out_error: - rfk->registered = 0; - b43warn(wl, "RF-kill button init failed\n"); -} - -void b43_rfkill_exit(struct b43_wldev *dev) -{ - struct b43_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return; - rfk->registered = 0; - - input_unregister_polled_device(rfk->poll_dev); - rfkill_unregister(rfk->rfkill); - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; - rfk->rfkill = NULL; } diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h index adacf936d815..f046c3ca0519 100644 --- a/drivers/net/wireless/b43/rfkill.h +++ b/drivers/net/wireless/b43/rfkill.h @@ -1,52 +1,11 @@ #ifndef B43_RFKILL_H_ #define B43_RFKILL_H_ +struct ieee80211_hw; struct b43_wldev; +void b43_rfkill_poll(struct ieee80211_hw *hw); -#ifdef CONFIG_B43_RFKILL - -#include <linux/rfkill.h> -#include <linux/input-polldev.h> - - -struct b43_rfkill { - /* The RFKILL subsystem data structure */ - struct rfkill *rfkill; - /* The poll device for the RFKILL input button */ - struct input_polled_dev *poll_dev; - /* Did initialization succeed? Used for freeing. */ - bool registered; - /* The unique name of this rfkill switch */ - char name[sizeof("b43-phy4294967295")]; -}; - -/* The init function returns void, because we are not interested - * in failing the b43 init process when rfkill init failed. */ -void b43_rfkill_init(struct b43_wldev *dev); -void b43_rfkill_exit(struct b43_wldev *dev); - -char * b43_rfkill_led_name(struct b43_wldev *dev); - - -#else /* CONFIG_B43_RFKILL */ -/* No RFKILL support. */ - -struct b43_rfkill { - /* empty */ -}; - -static inline void b43_rfkill_init(struct b43_wldev *dev) -{ -} -static inline void b43_rfkill_exit(struct b43_wldev *dev) -{ -} -static inline char * b43_rfkill_led_name(struct b43_wldev *dev) -{ - return NULL; -} - -#endif /* CONFIG_B43_RFKILL */ +bool b43_is_hw_radio_enabled(struct b43_wldev *dev); #endif /* B43_RFKILL_H_ */ diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index a63d88841df8..55f36a7254d9 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -118,7 +118,6 @@ u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate) void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, const u16 octets, const u8 bitrate) { - __le32 *data = &(plcp->data); __u8 *raw = plcp->raw; if (b43_is_ofdm_rate(bitrate)) { @@ -127,7 +126,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, d = b43_plcp_get_ratecode_ofdm(bitrate); B43_WARN_ON(octets & 0xF000); d |= (octets << 5); - *data = cpu_to_le32(d); + plcp->data = cpu_to_le32(d); } else { u32 plen; @@ -141,7 +140,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, raw[1] = 0x04; } else raw[1] = 0x04; - *data |= cpu_to_le32(plen << 16); + plcp->data |= cpu_to_le32(plen << 16); raw[0] = b43_plcp_get_ratecode_cck(bitrate); } } diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index d4f628a74bbd..94a463478053 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -42,14 +42,6 @@ config B43LEGACY_LEDS depends on B43LEGACY && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43LEGACY) default y -# RFKILL support -# This config option automatically enables b43legacy RFKILL support, -# if it's possible. -config B43LEGACY_RFKILL - bool - depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY) - default y - # This config option automatically enables b43 HW-RNG support, # if the HW-RNG core is enabled. config B43LEGACY_HWRNG diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile index 80cdb73bd140..227a77e84362 100644 --- a/drivers/net/wireless/b43legacy/Makefile +++ b/drivers/net/wireless/b43legacy/Makefile @@ -6,7 +6,7 @@ b43legacy-y += radio.o b43legacy-y += sysfs.o b43legacy-y += xmit.o # b43 RFKILL button support -b43legacy-$(CONFIG_B43LEGACY_RFKILL) += rfkill.o +b43legacy-y += rfkill.o # b43legacy LED support b43legacy-$(CONFIG_B43LEGACY_LEDS) += leds.o # b43legacy debugging diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 19a4b0bc0d87..77fda148ac46 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -602,9 +602,6 @@ struct b43legacy_wl { char rng_name[30 + 1]; #endif - /* The RF-kill button */ - struct b43legacy_rfkill rfkill; - /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index 3ea55b18c700..37e9be893560 100644 --- a/drivers/net/wireless/b43legacy/leds.c +++ b/drivers/net/wireless/b43legacy/leds.c @@ -28,6 +28,7 @@ #include "b43legacy.h" #include "leds.h" +#include "rfkill.h" static void b43legacy_led_turn_on(struct b43legacy_wldev *dev, u8 led_index, @@ -86,7 +87,8 @@ static void b43legacy_led_brightness_set(struct led_classdev *led_dev, static int b43legacy_register_led(struct b43legacy_wldev *dev, struct b43legacy_led *led, - const char *name, char *default_trigger, + const char *name, + const char *default_trigger, u8 led_index, bool activelow) { int err; @@ -163,10 +165,10 @@ static void b43legacy_map_led(struct b43legacy_wldev *dev, snprintf(name, sizeof(name), "b43legacy-%s::radio", wiphy_name(hw->wiphy)); b43legacy_register_led(dev, &dev->led_radio, name, - b43legacy_rfkill_led_name(dev), + ieee80211_get_radio_led_name(hw), led_index, activelow); - /* Sync the RF-kill LED state with the switch state. */ - if (dev->radio_hw_enable) + /* Sync the RF-kill LED state with radio and switch states. */ + if (dev->phy.radio_on && b43legacy_is_hw_radio_enabled(dev)) b43legacy_led_turn_on(dev, led_index, activelow); break; case B43legacy_LED_WEIRD: diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index f6f3fbf0a2f4..e5136fb65ddd 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3431,11 +3431,6 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) struct b43legacy_wldev *dev = wl->current_dev; int did_init = 0; int err = 0; - bool do_rfkill_exit = 0; - - /* First register RFkill. - * LEDs that are registered later depend on it. */ - b43legacy_rfkill_init(dev); /* Kill all old instance specific information to make sure * the card won't use it in the short timeframe between start @@ -3451,10 +3446,8 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { err = b43legacy_wireless_core_init(dev); - if (err) { - do_rfkill_exit = 1; + if (err) goto out_mutex_unlock; - } did_init = 1; } @@ -3463,17 +3456,15 @@ static int b43legacy_op_start(struct ieee80211_hw *hw) if (err) { if (did_init) b43legacy_wireless_core_exit(dev); - do_rfkill_exit = 1; goto out_mutex_unlock; } } + wiphy_rfkill_start_polling(hw->wiphy); + out_mutex_unlock: mutex_unlock(&wl->mutex); - if (do_rfkill_exit) - b43legacy_rfkill_exit(dev); - return err; } @@ -3482,7 +3473,6 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw) struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; - b43legacy_rfkill_exit(dev); cancel_work_sync(&(wl->beacon_update_trigger)); mutex_lock(&wl->mutex); @@ -3518,6 +3508,7 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .start = b43legacy_op_start, .stop = b43legacy_op_stop, .set_tim = b43legacy_op_beacon_set_tim, + .rfkill_poll = b43legacy_rfkill_poll, }; /* Hard-reset the chip. Do not call this directly. diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index 4b0c7d27a51f..8783022db11e 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -22,15 +22,12 @@ */ -#include "rfkill.h" #include "radio.h" #include "b43legacy.h" -#include <linux/kmod.h> - /* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) +bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) { if (dev->phy.rev >= 3) { if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) @@ -45,164 +42,43 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) } /* The poll callback for the hardware button. */ -static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) +void b43legacy_rfkill_poll(struct ieee80211_hw *hw) { - struct b43legacy_wldev *dev = poll_dev->private; - struct b43legacy_wl *wl = dev->wl; + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + struct ssb_bus *bus = dev->dev->bus; bool enabled; - bool report_change = 0; + bool brought_up = false; mutex_lock(&wl->mutex); if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { - mutex_unlock(&wl->mutex); - return; + if (ssb_bus_powerup(bus, 0)) { + mutex_unlock(&wl->mutex); + return; + } + ssb_device_enable(dev->dev, 0); + brought_up = true; } + enabled = b43legacy_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; - report_change = 1; b43legacyinfo(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); - } - mutex_unlock(&wl->mutex); - - /* send the radio switch event to the system - note both a key press - * and a release are required */ - if (unlikely(report_change)) { - input_report_key(poll_dev->input, KEY_WLAN, 1); - input_report_key(poll_dev->input, KEY_WLAN, 0); - } -} - -/* Called when the RFKILL toggled in software. - * This is called without locking. */ -static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) -{ - struct b43legacy_wldev *dev = data; - struct b43legacy_wl *wl = dev->wl; - int err = -EBUSY; - - if (!wl->rfkill.registered) - return 0; - - mutex_lock(&wl->mutex); - if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) - goto out_unlock; - err = 0; - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (!dev->radio_hw_enable) { - /* No luck. We can't toggle the hardware RF-kill - * button from software. */ - err = -EBUSY; - goto out_unlock; + wiphy_rfkill_set_hw_state(hw->wiphy, !enabled); + if (enabled != dev->phy.radio_on) { + if (enabled) + b43legacy_radio_turn_on(dev); + else + b43legacy_radio_turn_off(dev, 0); } - if (!dev->phy.radio_on) - b43legacy_radio_turn_on(dev); - break; - case RFKILL_STATE_SOFT_BLOCKED: - if (dev->phy.radio_on) - b43legacy_radio_turn_off(dev, 0); - break; - default: - b43legacywarn(wl, "Received unexpected rfkill state %d.\n", - state); - break; } -out_unlock: - mutex_unlock(&wl->mutex); - - return err; -} - -char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) -{ - struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return NULL; - return rfkill_get_led_name(rfk->rfkill); -} - -void b43legacy_rfkill_init(struct b43legacy_wldev *dev) -{ - struct b43legacy_wl *wl = dev->wl; - struct b43legacy_rfkill *rfk = &(wl->rfkill); - int err; - - rfk->registered = 0; - - rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); - if (!rfk->rfkill) - goto out_error; - snprintf(rfk->name, sizeof(rfk->name), - "b43legacy-%s", wiphy_name(wl->hw->wiphy)); - rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; - rfk->rfkill->data = dev; - rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; - - rfk->poll_dev = input_allocate_polled_device(); - if (!rfk->poll_dev) { - rfkill_free(rfk->rfkill); - goto err_freed_rfk; + if (brought_up) { + ssb_device_disable(dev->dev, 0); + ssb_bus_may_powerdown(bus); } - rfk->poll_dev->private = dev; - rfk->poll_dev->poll = b43legacy_rfkill_poll; - rfk->poll_dev->poll_interval = 1000; /* msecs */ - - rfk->poll_dev->input->name = rfk->name; - rfk->poll_dev->input->id.bustype = BUS_HOST; - rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; - rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); - set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); - - err = rfkill_register(rfk->rfkill); - if (err) - goto err_free_polldev; - -#ifdef CONFIG_RFKILL_INPUT_MODULE - /* B43legacy RF-kill isn't useful without the rfkill-input subsystem. - * Try to load the module. */ - err = request_module("rfkill-input"); - if (err) - b43legacywarn(wl, "Failed to load the rfkill-input module." - "The built-in radio LED will not work.\n"); -#endif /* CONFIG_RFKILL_INPUT */ - - err = input_register_polled_device(rfk->poll_dev); - if (err) - goto err_unreg_rfk; - - rfk->registered = 1; - - return; -err_unreg_rfk: - rfkill_unregister(rfk->rfkill); -err_free_polldev: - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; -err_freed_rfk: - rfk->rfkill = NULL; -out_error: - rfk->registered = 0; - b43legacywarn(wl, "RF-kill button init failed\n"); -} - -void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) -{ - struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); - - if (!rfk->registered) - return; - rfk->registered = 0; - - input_unregister_polled_device(rfk->poll_dev); - rfkill_unregister(rfk->rfkill); - input_free_polled_device(rfk->poll_dev); - rfk->poll_dev = NULL; - rfk->rfkill = NULL; + mutex_unlock(&wl->mutex); } - diff --git a/drivers/net/wireless/b43legacy/rfkill.h b/drivers/net/wireless/b43legacy/rfkill.h index 11150a8032f0..75585571c544 100644 --- a/drivers/net/wireless/b43legacy/rfkill.h +++ b/drivers/net/wireless/b43legacy/rfkill.h @@ -1,59 +1,11 @@ #ifndef B43legacy_RFKILL_H_ #define B43legacy_RFKILL_H_ +struct ieee80211_hw; struct b43legacy_wldev; -#ifdef CONFIG_B43LEGACY_RFKILL +void b43legacy_rfkill_poll(struct ieee80211_hw *hw); -#include <linux/rfkill.h> -#include <linux/workqueue.h> -#include <linux/input-polldev.h> - - - -struct b43legacy_rfkill { - /* The RFKILL subsystem data structure */ - struct rfkill *rfkill; - /* The poll device for the RFKILL input button */ - struct input_polled_dev *poll_dev; - /* Did initialization succeed? Used for freeing. */ - bool registered; - /* The unique name of this rfkill switch */ - char name[sizeof("b43legacy-phy4294967295")]; -}; - -/* The init function returns void, because we are not interested - * in failing the b43 init process when rfkill init failed. */ -void b43legacy_rfkill_init(struct b43legacy_wldev *dev); -void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); - -char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); - - -#else /* CONFIG_B43LEGACY_RFKILL */ -/* No RFKILL support. */ - -struct b43legacy_rfkill { - /* empty */ -}; - -static inline void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev) -{ -} -static inline void b43legacy_rfkill_free(struct b43legacy_wldev *dev) -{ -} -static inline void b43legacy_rfkill_init(struct b43legacy_wldev *dev) -{ -} -static inline void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) -{ -} -static inline char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) -{ - return NULL; -} - -#endif /* CONFIG_B43LEGACY_RFKILL */ +bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev); #endif /* B43legacy_RFKILL_H_ */ diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 8304f6406a17..029ccb6bdbaa 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -5,16 +5,11 @@ config IWLWIFI select FW_LOADER select MAC80211_LEDS if IWLWIFI_LEDS select LEDS_CLASS if IWLWIFI_LEDS - select RFKILL if IWLWIFI_RFKILL config IWLWIFI_LEDS bool "Enable LED support in iwlagn and iwl3945 drivers" depends on IWLWIFI -config IWLWIFI_RFKILL - bool "Enable RF kill support in iwlagn and iwl3945 drivers" - depends on IWLWIFI - config IWLWIFI_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwlagn driver" depends on IWLWIFI diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index d79d97ad61a5..1d4e0a226fd4 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -4,7 +4,6 @@ iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o iwlcore-objs += iwl-scan.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o -iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o obj-$(CONFIG_IWLAGN) += iwlagn.o diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index bd7e520d98c2..225e5f889346 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -167,10 +167,6 @@ static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id) IWL_DEBUG_LED(priv, "Disassociated\n"); priv->allow_blinking = 0; - if (iwl_is_rfkill(priv)) - iwl3945_led_off(priv, led_id); - else - iwl3945_led_on(priv, led_id); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 814afaf6d10b..5eb538d18a80 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -38,6 +38,7 @@ #include "iwl-commands.h" #include "iwl-3945.h" +#include "iwl-sta.h" #define RS_NAME "iwl-3945-rs" @@ -714,13 +715,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !rs_sta->ibss_sta_added) { - u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1); + u8 sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n", hdr->addr1); - sta_id = iwl3945_add_station(priv, - hdr->addr1, 0, CMD_ASYNC, NULL); + sta_id = iwl_add_station(priv, hdr->addr1, false, + CMD_ASYNC, NULL); } if (sta_id != IWL_INVALID_STATION) rs_sta->ibss_sta_added = 1; @@ -975,7 +976,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) rcu_read_lock(); - sta = ieee80211_find_sta(hw, priv->stations_39[sta_id].sta.sta.addr); + sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr); if (!sta) { rcu_read_unlock(); return; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index fd65e1c3e055..46288e724889 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -769,35 +769,6 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) return ; } -u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *addr) -{ - int i, start = IWL_AP_ID; - int ret = IWL_INVALID_STATION; - unsigned long flags; - - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || - (priv->iw_mode == NL80211_IFTYPE_AP)) - start = IWL_STA_ID; - - if (is_broadcast_ether_addr(addr)) - return priv->hw_params.bcast_sta_id; - - spin_lock_irqsave(&priv->sta_lock, flags); - for (i = start; i < priv->hw_params.max_stations; i++) - if ((priv->stations_39[i].used) && - (!compare_ether_addr - (priv->stations_39[i].sta.sta.addr, addr))) { - ret = i; - goto out; - } - - IWL_DEBUG_INFO(priv, "can not find STA %pM (total %d)\n", - addr, priv->num_stations); - out: - spin_unlock_irqrestore(&priv->sta_lock, flags); - return ret; -} - /** * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: * @@ -875,13 +846,13 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd, u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) { unsigned long flags_spin; - struct iwl3945_station_entry *station; + struct iwl_station_entry *station; if (sta_id == IWL_INVALID_STATION) return IWL_INVALID_STATION; spin_lock_irqsave(&priv->sta_lock, flags_spin); - station = &priv->stations_39[sta_id]; + station = &priv->stations[sta_id]; station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK; station->sta.rate_n_flags = cpu_to_le16(tx_rate); @@ -889,8 +860,7 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&station->sta, flags); + iwl_send_add_sta(priv, &station->sta, flags); IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n", sta_id, tx_rate); return sta_id; @@ -2029,7 +1999,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ @@ -2040,7 +2010,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) } /* Add the broadcast address so we can send broadcast frames */ - if (priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL) == + if (iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL) == IWL_INVALID_STATION) { IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); return -EIO; @@ -2050,9 +2020,8 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) * add the IWL_AP_ID to the station rate table */ if (iwl_is_associated(priv) && (priv->iw_mode == NL80211_IFTYPE_STATION)) - if (priv->cfg->ops->smgmt->add_station(priv, - priv->active_rxon.bssid_addr, 1, 0, NULL) - == IWL_INVALID_STATION) { + if (iwl_add_station(priv, priv->active_rxon.bssid_addr, + true, CMD_SYNC, NULL) == IWL_INVALID_STATION) { IWL_ERR(priv, "Error adding AP address for transmit\n"); return -EIO; } @@ -2466,13 +2435,25 @@ static u16 iwl3945_get_hcmd_size(u8 cmd_id, u16 len) } } + static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { - u16 size = (u16)sizeof(struct iwl3945_addsta_cmd); - memcpy(data, cmd, size); - return size; + struct iwl3945_addsta_cmd *addsta = (struct iwl3945_addsta_cmd *)data; + addsta->mode = cmd->mode; + memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify)); + memcpy(&addsta->key, &cmd->key, sizeof(struct iwl4965_keyinfo)); + addsta->station_flags = cmd->station_flags; + addsta->station_flags_msk = cmd->station_flags_msk; + addsta->tid_disable_tx = cpu_to_le16(0); + addsta->rate_n_flags = cmd->rate_n_flags; + addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid; + addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid; + addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn; + + return (u16)sizeof(struct iwl3945_addsta_cmd); } + /** * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table */ @@ -2842,15 +2823,6 @@ static struct iwl_lib_ops iwl3945_lib = { .config_ap = iwl3945_config_ap, }; -static struct iwl_station_mgmt_ops iwl3945_station_mgmt = { - .add_station = iwl3945_add_station, -#if 0 - .remove_station = iwl3945_remove_station, -#endif - .find_station = iwl3945_hw_find_station, - .clear_station_table = iwl3945_clear_stations_table, -}; - static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { .get_hcmd_size = iwl3945_get_hcmd_size, .build_addsta_hcmd = iwl3945_build_addsta_hcmd, @@ -2860,7 +2832,6 @@ static struct iwl_ops iwl3945_ops = { .lib = &iwl3945_lib, .hcmd = &iwl3945_hcmd, .utils = &iwl3945_hcmd_utils, - .smgmt = &iwl3945_station_mgmt, }; static struct iwl_cfg iwl3945_bg_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index da87528f355f..fbb3a573463e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -36,10 +36,6 @@ #include <linux/kernel.h> #include <net/ieee80211_radiotap.h> -/*used for rfkill*/ -#include <linux/rfkill.h> -#include <linux/input.h> - /* Hardware specific file defines the PCI IDs table for that hardware module */ extern struct pci_device_id iwl3945_hw_card_ids[]; @@ -155,7 +151,6 @@ struct iwl3945_frame { #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 #define STATUS_RF_KILL_HW 3 -#define STATUS_RF_KILL_SW 4 #define STATUS_INIT 5 #define STATUS_ALIVE 6 #define STATUS_READY 7 @@ -202,12 +197,6 @@ struct iwl3945_ibss_seq { * for use by iwl-*.c * *****************************************************************************/ -struct iwl3945_addsta_cmd; -extern int iwl3945_send_add_station(struct iwl_priv *priv, - struct iwl3945_addsta_cmd *sta, u8 flags); -extern u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *bssid, - int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); -extern void iwl3945_clear_stations_table(struct iwl_priv *priv); extern int iwl3945_power_init_handle(struct iwl_priv *priv); extern int iwl3945_eeprom_init(struct iwl_priv *priv); extern int iwl3945_calc_db_from_ratio(int sig_ratio); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a0b29411a4b3..8f3d4bc6a03f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2221,13 +2221,6 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) cancel_work_sync(&priv->txpower_work); } -static struct iwl_station_mgmt_ops iwl4965_station_mgmt = { - .add_station = iwl_add_station_flags, - .remove_station = iwl_remove_station, - .find_station = iwl_find_station, - .clear_station_table = iwl_clear_stations_table, -}; - static struct iwl_hcmd_ops iwl4965_hcmd = { .rxon_assoc = iwl4965_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, @@ -2297,7 +2290,6 @@ static struct iwl_ops iwl4965_ops = { .lib = &iwl4965_lib, .hcmd = &iwl4965_hcmd, .utils = &iwl4965_hcmd_utils, - .smgmt = &iwl4965_station_mgmt, }; struct iwl_cfg iwl4965_agn_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ab29aab6b2d5..b3c648ce8c7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -651,7 +651,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv) goto restart; } - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARN(priv, @@ -1049,7 +1049,10 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { u16 size = (u16)sizeof(struct iwl_addsta_cmd); - memcpy(data, cmd, size); + struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data; + memcpy(addsta, cmd, size); + /* resrved in 5000 */ + addsta->rate_n_flags = cpu_to_le16(0); return size; } @@ -1423,13 +1426,6 @@ int iwl5000_calc_rssi(struct iwl_priv *priv, return max_rssi - agc - IWL49_RSSI_OFFSET; } -struct iwl_station_mgmt_ops iwl5000_station_mgmt = { - .add_station = iwl_add_station_flags, - .remove_station = iwl_remove_station, - .find_station = iwl_find_station, - .clear_station_table = iwl_clear_stations_table, -}; - struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, @@ -1549,14 +1545,12 @@ struct iwl_ops iwl5000_ops = { .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, - .smgmt = &iwl5000_station_mgmt, }; static struct iwl_ops iwl5150_ops = { .lib = &iwl5150_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, - .smgmt = &iwl5000_station_mgmt, }; struct iwl_mod_params iwl50_mod_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 7236382aeaa6..bd438d8acf55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -72,7 +72,6 @@ static struct iwl_ops iwl6000_ops = { .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl6000_hcmd_utils, - .smgmt = &iwl5000_station_mgmt, }; struct iwl_cfg iwl6000_2ag_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 23a58b00f180..ff20e5048a55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2502,15 +2502,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) { - u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, - hdr->addr1); + u8 sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", hdr->addr1); - sta_id = priv->cfg->ops->smgmt->add_station(priv, - hdr->addr1, 0, - CMD_ASYNC, NULL); + sta_id = iwl_add_station(priv, hdr->addr1, + false, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2598,7 +2596,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->ibss_sta_added = 0; if (priv->iw_mode == NL80211_IFTYPE_AP) { - u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, + u8 sta_id = iwl_find_station(priv, sta->addr); /* for IBSS the call are from tasklet */ @@ -2606,9 +2604,8 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); - sta_id = priv->cfg->ops->smgmt->add_station(priv, - sta->addr, 0, - CMD_ASYNC, NULL); + sta_id = iwl_add_station(priv, sta->addr, false, + CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { lq_sta->lq.sta_id = sta_id; @@ -2790,9 +2787,10 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv, repeat_rate--; } - lq_cmd->agg_params.agg_frame_cnt_limit = 64; - lq_cmd->agg_params.agg_dis_start_th = 3; - lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); + lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_MAX; + lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + lq_cmd->agg_params.agg_time_limit = + cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); } static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0a5507cbeb3f..a5637c4aa85d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -188,7 +188,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); } - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); priv->start_calib = 0; @@ -737,19 +737,13 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, clear_bit(STATUS_RF_KILL_HW, &priv->status); - if (flags & SW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_SW, &priv->status); - else - clear_bit(STATUS_RF_KILL_SW, &priv->status); - if (!(flags & RXON_CARD_DISABLED)) iwl_scan_cancel(priv); if ((test_bit(STATUS_RF_KILL_HW, &status) != - test_bit(STATUS_RF_KILL_HW, &priv->status)) || - (test_bit(STATUS_RF_KILL_SW, &status) != - test_bit(STATUS_RF_KILL_SW, &priv->status))) - queue_work(priv->workqueue, &priv->rf_kill); + test_bit(STATUS_RF_KILL_HW, &priv->status))) + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); else wake_up_interruptible(&priv->wait_command_queue); } @@ -1045,7 +1039,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); else clear_bit(STATUS_RF_KILL_HW, &priv->status); - queue_work(priv->workqueue, &priv->rf_kill); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); } handled |= CSR_INT_BIT_RF_KILL; @@ -1218,7 +1212,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); else clear_bit(STATUS_RF_KILL_HW, &priv->status); - queue_work(priv->workqueue, &priv->rf_kill); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); } handled |= CSR_INT_BIT_RF_KILL; @@ -1617,7 +1611,7 @@ static void iwl_alive_start(struct iwl_priv *priv) goto restart; } - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARN(priv, @@ -1703,7 +1697,7 @@ static void __iwl_down(struct iwl_priv *priv) iwl_leds_unregister(priv); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -1726,12 +1720,10 @@ static void __iwl_down(struct iwl_priv *priv) ieee80211_stop_queues(priv->hw); /* If we have not previously called iwl_init() then - * clear all bits but the RF Kill bits and return */ + * clear all bits but the RF Kill bit and return */ if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_EXIT_PENDING, &priv->status) << @@ -1740,11 +1732,9 @@ static void __iwl_down(struct iwl_priv *priv) } /* ...otherwise clear out all the status bits but the RF Kill - * bits and continue taking the NIC down. */ + * bit and continue taking the NIC down. */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_FW_ERROR, &priv->status) << @@ -1866,9 +1856,10 @@ static int __iwl_up(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); if (iwl_is_rfkill(priv)) { + wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); + iwl_enable_interrupts(priv); - IWL_WARN(priv, "Radio disabled by %s RF Kill switch\n", - test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); + IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); return 0; } @@ -1887,8 +1878,6 @@ static int __iwl_up(struct iwl_priv *priv) /* clear (again), then enable host interrupts */ iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - /* enable dram interrupt */ - iwl_reset_ict(priv); iwl_enable_interrupts(priv); /* really make sure rfkill handshake bits are cleared */ @@ -1903,7 +1892,7 @@ static int __iwl_up(struct iwl_priv *priv) for (i = 0; i < MAX_HW_RESTARTS; i++) { - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, @@ -1962,6 +1951,9 @@ static void iwl_bg_alive_start(struct work_struct *data) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + /* enable dram interrupt */ + iwl_reset_ict(priv); + mutex_lock(&priv->mutex); iwl_alive_start(priv); mutex_unlock(&priv->mutex); @@ -2000,7 +1992,6 @@ static void iwl_bg_up(struct work_struct *data) mutex_lock(&priv->mutex); __iwl_up(priv); mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); } static void iwl_bg_restart(struct work_struct *data) @@ -2178,8 +2169,6 @@ static int iwl_mac_start(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); - if (ret) return ret; @@ -2348,7 +2337,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } addr = sta ? sta->addr : iwl_bcast_addr; - sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", addr); @@ -2774,7 +2763,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->up, iwl_bg_up); INIT_WORK(&priv->restart, iwl_bg_restart); INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); - INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); @@ -3045,12 +3033,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) else set_bit(STATUS_RF_KILL_HW, &priv->status); - err = iwl_rfkill_init(priv); - if (err) - IWL_ERR(priv, "Unable to initialize RFKILL system. " - "Ignoring error: %d\n", err); - else - iwl_rfkill_set_hw_state(priv); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); iwl_power_initialize(priv); return 0; @@ -3114,14 +3098,13 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_synchronize_irq(priv); - iwl_rfkill_unregister(priv); iwl_dealloc_ucode_pci(priv); if (priv->rxq.bd) iwl_rx_queue_free(priv, &priv->rxq); iwl_hw_txq_ctx_free(priv); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); iwl_eeprom_free(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index e581dc323f0a..c87033bf3ad2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1067,7 +1067,7 @@ struct iwl_addsta_cmd { * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ __le16 tid_disable_tx; - __le16 reserved1; + __le16 rate_n_flags; /* 3945 only */ /* TID for which to add block-ack support. * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ @@ -1913,6 +1913,18 @@ struct iwl_link_qual_general_params { u8 start_rate_index[LINK_QUAL_AC_NUM]; } __attribute__ ((packed)); +#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */ +#define LINK_QUAL_AGG_TIME_LIMIT_MAX (65535) +#define LINK_QUAL_AGG_TIME_LIMIT_MIN (0) + +#define LINK_QUAL_AGG_DISABLE_START_DEF (3) +#define LINK_QUAL_AGG_DISABLE_START_MAX (255) +#define LINK_QUAL_AGG_DISABLE_START_MIN (0) + +#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31) +#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (64) +#define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) + /** * struct iwl_link_qual_agg_params * diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e93ddb74457e..f9d16ca5b3d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -36,7 +36,6 @@ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-rfkill.h" #include "iwl-power.h" #include "iwl-sta.h" #include "iwl-helpers.h" @@ -1389,7 +1388,7 @@ int iwl_init_drv(struct iwl_priv *priv) mutex_init(&priv->mutex); /* Clear the driver's (not device's) station table */ - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; @@ -1704,8 +1703,9 @@ static irqreturn_t iwl_isr(int irq, void *data) { struct iwl_priv *priv = data; u32 inta, inta_mask; +#ifdef CONFIG_IWLWIFI_DEBUG u32 inta_fh; - +#endif if (!priv) return IRQ_NONE; @@ -2210,126 +2210,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) } EXPORT_SYMBOL(iwl_send_card_state); -void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv) -{ - unsigned long flags; - - if (test_bit(STATUS_RF_KILL_SW, &priv->status)) - return; - - IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO OFF\n"); - - iwl_scan_cancel(priv); - /* FIXME: This is a workaround for AP */ - if (priv->iw_mode != NL80211_IFTYPE_AP) { - spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_SW_BIT_RFKILL); - spin_unlock_irqrestore(&priv->lock, flags); - /* call the host command only if no hw rf-kill set */ - if (!test_bit(STATUS_RF_KILL_HW, &priv->status) && - iwl_is_ready(priv)) - iwl_send_card_state(priv, - CARD_STATE_CMD_DISABLE, 0); - set_bit(STATUS_RF_KILL_SW, &priv->status); - /* make sure mac80211 stop sending Tx frame */ - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); - } -} -EXPORT_SYMBOL(iwl_radio_kill_sw_disable_radio); - -int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv) -{ - unsigned long flags; - - if (!test_bit(STATUS_RF_KILL_SW, &priv->status)) - return 0; - - IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO ON\n"); - - spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - - /* If the driver is up it will receive CARD_STATE_NOTIFICATION - * notification where it will clear SW rfkill status. - * Setting it here would break the handler. Only if the - * interface is down we can set here since we don't - * receive any further notification. - */ - if (!priv->is_open) - clear_bit(STATUS_RF_KILL_SW, &priv->status); - spin_unlock_irqrestore(&priv->lock, flags); - - /* wake up ucode */ - msleep(10); - - iwl_read32(priv, CSR_UCODE_DRV_GP1); - spin_lock_irqsave(&priv->reg_lock, flags); - if (!iwl_grab_nic_access(priv)) - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, flags); - - if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { - IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - " - "disabled by HW switch\n"); - return 0; - } - - /* when driver is up while rfkill is on, it wont receive - * any CARD_STATE_NOTIFICATION notifications so we have to - * restart it in here - */ - if (priv->is_open && !test_bit(STATUS_ALIVE, &priv->status)) { - clear_bit(STATUS_RF_KILL_SW, &priv->status); - if (!iwl_is_rfkill(priv)) - queue_work(priv->workqueue, &priv->up); - } - - /* If the driver is already loaded, it will receive - * CARD_STATE_NOTIFICATION notifications and the handler will - * call restart to reload the driver. - */ - return 1; -} -EXPORT_SYMBOL(iwl_radio_kill_sw_enable_radio); - -void iwl_bg_rf_kill(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); - - wake_up_interruptible(&priv->wait_command_queue); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - - if (!iwl_is_rfkill(priv)) { - IWL_DEBUG_RF_KILL(priv, - "HW and/or SW RF Kill no longer active, restarting " - "device\n"); - if (!test_bit(STATUS_EXIT_PENDING, &priv->status) && - priv->is_open) - queue_work(priv->workqueue, &priv->restart); - } else { - /* make sure mac80211 stop sending Tx frame */ - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); - - if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) - IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - " - "disabled by SW switch\n"); - else - IWL_WARN(priv, "Radio Frequency Kill Switch is On:\n" - "Kill switch must be turned off for " - "wireless networking to work.\n"); - } - mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); -} -EXPORT_SYMBOL(iwl_bg_rf_kill); - void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -2679,19 +2559,12 @@ int iwl_set_mode(struct iwl_priv *priv, int mode) memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* dont commit rxon if rf-kill is on*/ if (!iwl_is_ready_rf(priv)) return -EAGAIN; - cancel_delayed_work(&priv->scan_check); - if (iwl_scan_cancel_timeout(priv, 100)) { - IWL_WARN(priv, "Aborted scan still in progress after 100ms\n"); - IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); - return -EAGAIN; - } - iwlcore_commit_rxon(priv); return 0; @@ -2855,23 +2728,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv); - if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { - if (conf->radio_enabled && - iwl_radio_kill_sw_enable_radio(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - " - "waiting for uCode\n"); - goto out; - } - - if (!conf->radio_enabled) - iwl_radio_kill_sw_disable_radio(priv); - } - - if (!conf->radio_enabled) { - IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); - goto out; - } - if (!iwl_is_ready(priv)) { IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); goto out; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 87df1b767941..dabf663e36e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -83,15 +83,6 @@ struct iwl_cmd; #define IWL_SKU_A 0x2 #define IWL_SKU_N 0x8 -struct iwl_station_mgmt_ops { - u8 (*add_station)(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); - int (*remove_station)(struct iwl_priv *priv, const u8 *addr, - int is_ap); - u8 (*find_station)(struct iwl_priv *priv, const u8 *addr); - void (*clear_station_table)(struct iwl_priv *priv); -}; - struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); int (*commit_rxon)(struct iwl_priv *priv); @@ -183,7 +174,6 @@ struct iwl_ops { const struct iwl_lib_ops *lib; const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; - const struct iwl_station_mgmt_ops *smgmt; }; struct iwl_mod_params { @@ -192,7 +182,7 @@ struct iwl_mod_params { int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int num_of_ampdu_queues;/* def: HW dependent */ - int disable_11n; /* def: 0 = disable 11n capabilities */ + int disable_11n; /* def: 0 = 11n capabilities enabled */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int antenna; /* def: 0 = both antennas (use diversity) */ int restart_fw; /* def: 1 = restart firmware */ @@ -358,14 +348,6 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); ****************************************************/ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); -/***************************************************** - * RF -Kill - here and not in iwl-rfkill.h to be available when - * RF-kill subsystem is not compiled. - ****************************************************/ -void iwl_bg_rf_kill(struct work_struct *work); -void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv); -int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv); - /******************************************************************************* * Rate ******************************************************************************/ @@ -508,7 +490,6 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 #define STATUS_RF_KILL_HW 3 -#define STATUS_RF_KILL_SW 4 #define STATUS_INIT 5 #define STATUS_ALIVE 6 #define STATUS_READY 7 @@ -543,11 +524,6 @@ static inline int iwl_is_init(struct iwl_priv *priv) return test_bit(STATUS_INIT, &priv->status); } -static inline int iwl_is_rfkill_sw(struct iwl_priv *priv) -{ - return test_bit(STATUS_RF_KILL_SW, &priv->status); -} - static inline int iwl_is_rfkill_hw(struct iwl_priv *priv) { return test_bit(STATUS_RF_KILL_HW, &priv->status); @@ -555,7 +531,7 @@ static inline int iwl_is_rfkill_hw(struct iwl_priv *priv) static inline int iwl_is_rfkill(struct iwl_priv *priv) { - return iwl_is_rfkill_hw(priv) || iwl_is_rfkill_sw(priv); + return iwl_is_rfkill_hw(priv); } static inline int iwl_is_ready_rf(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index af70229144b3..11e08c068917 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -449,8 +449,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, test_bit(STATUS_INT_ENABLED, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", test_bit(STATUS_RF_KILL_HW, &priv->status)); - pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_SW:\t %d\n", - test_bit(STATUS_RF_KILL_SW, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n", test_bit(STATUS_INIT, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2dafc26fb6a8..e2d620f0b6e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -41,7 +41,6 @@ #include "iwl-prph.h" #include "iwl-fh.h" #include "iwl-debug.h" -#include "iwl-rfkill.h" #include "iwl-4965-hw.h" #include "iwl-3945-hw.h" #include "iwl-3945-led.h" @@ -70,7 +69,6 @@ extern struct iwl_ops iwl5000_ops; extern struct iwl_lib_ops iwl5000_lib; extern struct iwl_hcmd_ops iwl5000_hcmd; extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils; -extern struct iwl_station_mgmt_ops iwl5000_station_mgmt; /* shared functions from iwl-5000.c */ extern u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len); @@ -290,11 +288,11 @@ struct iwl_frame { #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) enum { - /* CMD_SIZE_NORMAL = 0, */ + CMD_SYNC = 0, + CMD_SIZE_NORMAL = 0, + CMD_NO_SKB = 0, CMD_SIZE_HUGE = (1 << 0), - /* CMD_SYNC = 0, */ CMD_ASYNC = (1 << 1), - /* CMD_NO_SKB = 0, */ CMD_WANT_SKB = (1 << 2), }; @@ -937,9 +935,6 @@ struct iwl_priv { * 4965's initialize alive response contains some calibration data. */ struct iwl_init_alive_resp card_alive_init; struct iwl_alive_resp card_alive; -#if defined(CONFIG_IWLWIFI_RFKILL) - struct rfkill *rfkill; -#endif #ifdef CONFIG_IWLWIFI_LEDS unsigned long last_blink_time; @@ -1073,7 +1068,6 @@ struct iwl_priv { struct work_struct calibrated_work; struct work_struct scan_completed; struct work_struct rx_replenish; - struct work_struct rf_kill; struct work_struct abort_scan; struct work_struct update_link_led; struct work_struct auth_work; @@ -1119,8 +1113,6 @@ struct iwl_priv { struct iwl3945_notif_statistics statistics_39; - struct iwl3945_station_entry stations_39[IWL_STATION_COUNT]; - u32 sta_supp_rates; }; /*iwl_priv */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index cefa501e5971..7d7554a2f341 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -240,13 +240,11 @@ static int iwl_init_otp_access(struct iwl_priv *priv) if (ret < 0) IWL_ERR(priv, "Time out access OTP\n"); else { - if (!ret) { - iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); - udelay(5); - iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); - } + iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + udelay(5); + iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); } return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 19680f72087f..5e64252f80f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -176,10 +176,6 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id) static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) { priv->allow_blinking = 0; - if (iwl_is_rfkill(priv)) - iwl4965_led_off_reg(priv, led_id); - else - iwl4965_led_on_reg(priv, led_id); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c deleted file mode 100644 index 65605ad44e4b..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ /dev/null @@ -1,144 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> - -#include <net/mac80211.h> - -#include "iwl-eeprom.h" -#include "iwl-dev.h" -#include "iwl-core.h" - -/* software rf-kill from user */ -static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) -{ - struct iwl_priv *priv = data; - int err = 0; - - if (!priv->rfkill) - return 0; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return 0; - - IWL_DEBUG_RF_KILL(priv, "we received soft RFKILL set to state %d\n", state); - mutex_lock(&priv->mutex); - - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (iwl_is_rfkill_hw(priv)) { - err = -EBUSY; - goto out_unlock; - } - iwl_radio_kill_sw_enable_radio(priv); - break; - case RFKILL_STATE_SOFT_BLOCKED: - iwl_radio_kill_sw_disable_radio(priv); - break; - default: - IWL_WARN(priv, "we received unexpected RFKILL state %d\n", - state); - break; - } -out_unlock: - mutex_unlock(&priv->mutex); - - return err; -} - -int iwl_rfkill_init(struct iwl_priv *priv) -{ - struct device *device = wiphy_dev(priv->hw->wiphy); - int ret = 0; - - BUG_ON(device == NULL); - - IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n"); - priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); - if (!priv->rfkill) { - IWL_ERR(priv, "Unable to allocate RFKILL device.\n"); - ret = -ENOMEM; - goto error; - } - - priv->rfkill->name = priv->cfg->name; - priv->rfkill->data = priv; - priv->rfkill->state = RFKILL_STATE_UNBLOCKED; - priv->rfkill->toggle_radio = iwl_rfkill_soft_rf_kill; - - priv->rfkill->dev.class->suspend = NULL; - priv->rfkill->dev.class->resume = NULL; - - ret = rfkill_register(priv->rfkill); - if (ret) { - IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret); - goto free_rfkill; - } - - IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); - return ret; - -free_rfkill: - if (priv->rfkill != NULL) - rfkill_free(priv->rfkill); - priv->rfkill = NULL; - -error: - IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); - return ret; -} -EXPORT_SYMBOL(iwl_rfkill_init); - -void iwl_rfkill_unregister(struct iwl_priv *priv) -{ - - if (priv->rfkill) - rfkill_unregister(priv->rfkill); - - priv->rfkill = NULL; -} -EXPORT_SYMBOL(iwl_rfkill_unregister); - -/* set RFKILL to the right state. */ -void iwl_rfkill_set_hw_state(struct iwl_priv *priv) -{ - if (!priv->rfkill) - return; - - if (iwl_is_rfkill_hw(priv)) { - rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED); - return; - } - - if (!iwl_is_rfkill_sw(priv)) - rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED); - else - rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED); -} -EXPORT_SYMBOL(iwl_rfkill_set_hw_state); diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h deleted file mode 100644 index 633dafb4bf1b..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h +++ /dev/null @@ -1,48 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ -#ifndef __iwl_rf_kill_h__ -#define __iwl_rf_kill_h__ - -struct iwl_priv; - -#include <linux/rfkill.h> - -#ifdef CONFIG_IWLWIFI_RFKILL - -void iwl_rfkill_set_hw_state(struct iwl_priv *priv); -void iwl_rfkill_unregister(struct iwl_priv *priv); -int iwl_rfkill_init(struct iwl_priv *priv); -#else -static inline void iwl_rfkill_set_hw_state(struct iwl_priv *priv) {} -static inline void iwl_rfkill_unregister(struct iwl_priv *priv) {} -static inline int iwl_rfkill_init(struct iwl_priv *priv) { return 0; } -#endif - - - -#endif /* __iwl_rf_kill_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 0eb939c40ac1..2addf735b193 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -75,7 +75,7 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) return IWL_AP_ID; } else { u8 *da = ieee80211_get_DA(hdr); - return priv->cfg->ops->smgmt->find_station(priv, da); + return iwl_find_station(priv, da); } } EXPORT_SYMBOL(iwl_get_ra_sta_id); @@ -86,8 +86,7 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) spin_lock_irqsave(&priv->sta_lock, flags); - if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && - !(priv->stations_39[sta_id].used & IWL_STA_DRIVER_ACTIVE)) + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n", sta_id); @@ -228,15 +227,16 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, } /** - * iwl_add_station_flags - Add station to tables in driver and device + * iwl_add_station - Add station to tables in driver and device */ -u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, - u8 flags, struct ieee80211_sta_ht_cap *ht_info) +u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, + struct ieee80211_sta_ht_cap *ht_info) { - int i; - int sta_id = IWL_INVALID_STATION; struct iwl_station_entry *station; unsigned long flags_spin; + int i; + int sta_id = IWL_INVALID_STATION; + u16 rate; spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) @@ -288,6 +288,12 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, priv->iw_mode != NL80211_IFTYPE_ADHOC) iwl_set_ht_add_station(priv, sta_id, ht_info); + /* 3945 only */ + rate = (priv->band == IEEE80211_BAND_5GHZ) ? + IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP; + /* Turn on both antennas for the station... */ + station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); + spin_unlock_irqrestore(&priv->sta_lock, flags_spin); /* Add station to device's station table */ @@ -295,12 +301,12 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, return sta_id; } -EXPORT_SYMBOL(iwl_add_station_flags); +EXPORT_SYMBOL(iwl_add_station); static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) { unsigned long flags; - u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + u8 sta_id = iwl_find_station(priv, addr); BUG_ON(sta_id == IWL_INVALID_STATION); @@ -408,7 +414,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, /** * iwl_remove_station - Remove driver's knowledge of station. */ -int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) { int sta_id = IWL_INVALID_STATION; int i, ret = -EINVAL; @@ -767,7 +773,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv, unsigned long flags; int i; - sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", addr); @@ -946,7 +952,7 @@ EXPORT_SYMBOL(iwl_send_lq_cmd); * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, * which requires station table entry to exist). */ -static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) +static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap) { int i, r; struct iwl_link_quality_cmd link_cmd = { @@ -979,8 +985,9 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) link_cmd.general_params.single_stream_ant_msk = first_antenna(priv->hw_params.valid_tx_ant); link_cmd.general_params.dual_stream_ant_msk = 3; - link_cmd.agg_params.agg_dis_start_th = 3; - link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); + link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + link_cmd.agg_params.agg_time_limit = + cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); /* Update the rate scaling for control frame Tx to AP */ link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; @@ -995,7 +1002,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) * there is only one AP station with id= IWL_AP_ID * NOTE: mutex must be held before calling this function */ -int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) { struct ieee80211_sta *sta; struct ieee80211_sta_ht_cap ht_config; @@ -1020,8 +1027,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) rcu_read_unlock(); } - sta_id = priv->cfg->ops->smgmt->add_station(priv, addr, is_ap, - 0, cur_ht_config); + sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config); /* Set up default rate scaling table in device's station table */ iwl_sta_init_lq(priv, addr, is_ap); @@ -1054,7 +1060,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* If we are an AP, then find the station, or use BCAST */ case NL80211_IFTYPE_AP: - sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1); + sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; return priv->hw_params.bcast_sta_id; @@ -1062,13 +1068,13 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* If this frame is going out to an IBSS network, find the station, * or create a new station table entry */ case NL80211_IFTYPE_ADHOC: - sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1); + sta_id = iwl_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; /* Create new station table entry */ - sta_id = priv->cfg->ops->smgmt->add_station(priv, hdr->addr1, - 0, CMD_ASYNC, NULL); + sta_id = iwl_add_station(priv, hdr->addr1, false, + CMD_ASYNC, NULL); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -1111,7 +1117,7 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, unsigned long flags; int sta_id; - sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) return -ENXIO; @@ -1133,7 +1139,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) unsigned long flags; int sta_id; - sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); return -ENXIO; @@ -1168,7 +1174,7 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) { /* FIXME: need locking over ps_status ??? */ - u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + u8 sta_id = iwl_find_station(priv, addr); if (sta_id != IWL_INVALID_STATION) { u8 sta_awake = priv->stations[sta_id]. diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 59a586b6b56c..6deebade6361 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -51,16 +51,15 @@ void iwl_update_tkip_key(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf, const u8 *addr, u32 iv32, u16 *phase1key); -int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); -int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); +int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); +int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); void iwl_clear_stations_table(struct iwl_priv *priv); int iwl_get_free_ucode_key_index(struct iwl_priv *priv); int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags); -u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, +u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info); void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); int iwl_sta_rx_agg_start(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5c10b87d0336..83d31606dd00 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -95,144 +95,6 @@ struct iwl_mod_params iwl3945_mod_params = { /* the rest are 0 by default */ }; -/*************** STATION TABLE MANAGEMENT **** - * mac80211 should be examined to determine if sta_info is duplicating - * the functionality provided here - */ - -/**************************************************************/ -#if 0 /* temporary disable till we add real remove station */ -/** - * iwl3945_remove_station - Remove driver's knowledge of station. - * - * NOTE: This does not remove station from device's station table. - */ -static u8 iwl3945_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) -{ - int index = IWL_INVALID_STATION; - int i; - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - if (is_ap) - index = IWL_AP_ID; - else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; - else - for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) - if (priv->stations_39[i].used && - !compare_ether_addr(priv->stations_39[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (unlikely(index == IWL_INVALID_STATION)) - goto out; - - if (priv->stations_39[index].used) { - priv->stations_39[index].used = 0; - priv->num_stations--; - } - - BUG_ON(priv->num_stations < 0); - -out: - spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; -} -#endif - -/** - * iwl3945_clear_stations_table - Clear the driver's station table - * - * NOTE: This does not clear or otherwise alter the device's station table. - */ -void iwl3945_clear_stations_table(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->num_stations = 0; - memset(priv->stations_39, 0, sizeof(priv->stations_39)); - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} - -/** - * iwl3945_add_station - Add station to station tables in driver and device - */ -u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info) -{ - int i; - int index = IWL_INVALID_STATION; - struct iwl3945_station_entry *station; - unsigned long flags_spin; - u8 rate; - - spin_lock_irqsave(&priv->sta_lock, flags_spin); - if (is_ap) - index = IWL_AP_ID; - else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; - else - for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { - if (!compare_ether_addr(priv->stations_39[i].sta.sta.addr, - addr)) { - index = i; - break; - } - - if (!priv->stations_39[i].used && - index == IWL_INVALID_STATION) - index = i; - } - - /* These two conditions has the same outcome but keep them separate - since they have different meaning */ - if (unlikely(index == IWL_INVALID_STATION)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - if (priv->stations_39[index].used && - !compare_ether_addr(priv->stations_39[index].sta.sta.addr, addr)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; - } - - IWL_DEBUG_ASSOC(priv, "Add STA ID %d: %pM\n", index, addr); - station = &priv->stations_39[index]; - station->used = 1; - priv->num_stations++; - - /* Set up the REPLY_ADD_STA command to send to device */ - memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd)); - memcpy(station->sta.sta.addr, addr, ETH_ALEN); - station->sta.mode = 0; - station->sta.sta.sta_id = index; - station->sta.station_flags = 0; - - if (priv->band == IEEE80211_BAND_5GHZ) - rate = IWL_RATE_6M_PLCP; - else - rate = IWL_RATE_1M_PLCP; - - /* Turn on both antennas for the station... */ - station->sta.rate_n_flags = - iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK); - - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - - /* Add station to device's station table */ - iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&station->sta, flags); - return index; - -} - /** * iwl3945_get_antenna_flags - Get antenna flags for RXON command * @priv: eeprom and antenna fields are used to determine antenna flags @@ -289,32 +151,31 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv, key_flags &= ~STA_KEY_FLG_INVALID; spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations_39[sta_id].keyinfo.alg = keyconf->alg; - priv->stations_39[sta_id].keyinfo.keylen = keyconf->keylen; - memcpy(priv->stations_39[sta_id].keyinfo.key, keyconf->key, + priv->stations[sta_id].keyinfo.alg = keyconf->alg; + priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, keyconf->keylen); - memcpy(priv->stations_39[sta_id].sta.key.key, keyconf->key, + memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, keyconf->keylen); - if ((priv->stations_39[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) + if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) == STA_KEY_FLG_NO_ENC) - priv->stations_39[sta_id].sta.key.key_offset = + priv->stations[sta_id].sta.key.key_offset = iwl_get_free_ucode_key_index(priv); /* else, we are overriding an existing key => no need to allocated room * in uCode. */ - WARN(priv->stations_39[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, + WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, "no space for a new key"); - priv->stations_39[sta_id].sta.key.key_flags = key_flags; - priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n"); - ret = iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, CMD_ASYNC); + ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -340,17 +201,16 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); - memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); - memset(&priv->stations_39[sta_id].sta.key, 0, + memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); + memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); - priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; - priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n"); - iwl_send_add_sta(priv, - (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, 0); + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0); return 0; } @@ -578,7 +438,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, int sta_id) { struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; - struct iwl_hw_key *keyinfo = &priv->stations_39[sta_id].keyinfo; + struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: @@ -753,7 +613,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - seq_number = priv->stations_39[sta_id].tid[tid].seq_number & + seq_number = priv->stations[sta_id].tid[tid].seq_number & IEEE80211_SCTL_SEQ; hdr->seq_ctrl = cpu_to_le16(seq_number) | (hdr->seq_ctrl & @@ -813,7 +673,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; if (qc) - priv->stations_39[sta_id].tid[tid].seq_number = seq_number; + priv->stations[sta_id].tid[tid].seq_number = seq_number; } else { wait_write_ptr = 1; txq->need_update = 0; @@ -1149,18 +1009,12 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, clear_bit(STATUS_RF_KILL_HW, &priv->status); - if (flags & SW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_SW, &priv->status); - else - clear_bit(STATUS_RF_KILL_SW, &priv->status); - iwl_scan_cancel(priv); if ((test_bit(STATUS_RF_KILL_HW, &status) != - test_bit(STATUS_RF_KILL_HW, &priv->status)) || - (test_bit(STATUS_RF_KILL_SW, &status) != - test_bit(STATUS_RF_KILL_SW, &priv->status))) - queue_work(priv->workqueue, &priv->rf_kill); + test_bit(STATUS_RF_KILL_HW, &priv->status))) + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); else wake_up_interruptible(&priv->wait_command_queue); } @@ -1316,7 +1170,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ - if ((write != (rxq->write & ~0x7)) + if ((rxq->write_actual != (rxq->write & ~0x7)) || (abs(rxq->write - rxq->read) > 7)) { spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; @@ -1337,7 +1191,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) * Also restock the Rx queue via iwl3945_rx_queue_restock. * This is called as a scheduled work item (except for during initialization) */ -static void iwl3945_rx_allocate(struct iwl_priv *priv) +static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) { struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; @@ -1360,7 +1214,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv) /* Alloc a new receive buffer */ rxb->skb = alloc_skb(priv->hw_params.rx_buf_size, - GFP_KERNEL); + priority); if (!rxb->skb) { if (net_ratelimit()) IWL_CRIT(priv, ": Can not allocate SKB buffers\n"); @@ -1419,6 +1273,7 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; rxq->free_count = 0; + rxq->write_actual = 0; spin_unlock_irqrestore(&rxq->lock, flags); } @@ -1427,13 +1282,21 @@ void iwl3945_rx_replenish(void *data) struct iwl_priv *priv = data; unsigned long flags; - iwl3945_rx_allocate(priv); + iwl3945_rx_allocate(priv, GFP_KERNEL); spin_lock_irqsave(&priv->lock, flags); iwl3945_rx_queue_restock(priv); spin_unlock_irqrestore(&priv->lock, flags); } +static void iwl3945_rx_replenish_now(struct iwl_priv *priv) +{ + iwl3945_rx_allocate(priv, GFP_ATOMIC); + + iwl3945_rx_queue_restock(priv); +} + + /* Assumes that the skb field of the buffers in 'pool' is kept accurate. * If an SKB has been detached, the POOL needs to have its SKB set to NULL * This free routine walks the list of POOL entries and if SKB is set to @@ -1556,13 +1419,19 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) unsigned long flags; u8 fill_rx = 0; u32 count = 8; + int total_empty = 0; /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; i = rxq->read; - if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) + /* calculate total frames need to be restock after handling RX */ + total_empty = r - priv->rxq.write_actual; + if (total_empty < 0) + total_empty += RX_QUEUE_SIZE; + + if (total_empty > (RX_QUEUE_SIZE / 2)) fill_rx = 1; /* Rx interrupt, but nothing sent from uCode */ if (i == r) @@ -1639,7 +1508,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - iwl3945_rx_queue_restock(priv); + iwl3945_rx_replenish_now(priv); count = 0; } } @@ -1647,7 +1516,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) /* Backtrack one entry */ priv->rxq.read = i; - iwl3945_rx_queue_restock(priv); + if (fill_rx) + iwl3945_rx_replenish_now(priv); + else + iwl3945_rx_queue_restock(priv); } /* call this function to flush any scheduled tasklet */ @@ -2589,7 +2461,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) goto restart; } - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); rfkill = iwl_read_prph(priv, APMG_RFKILL_REG); IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill); @@ -2681,7 +2553,7 @@ static void __iwl3945_down(struct iwl_priv *priv) set_bit(STATUS_EXIT_PENDING, &priv->status); iwl3945_led_unregister(priv); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -2708,8 +2580,6 @@ static void __iwl3945_down(struct iwl_priv *priv) if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_EXIT_PENDING, &priv->status) << @@ -2718,11 +2588,9 @@ static void __iwl3945_down(struct iwl_priv *priv) } /* ...otherwise clear out all the status bits but the RF Kill - * bits and continue taking the NIC down. */ + * bit and continue taking the NIC down. */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_RF_KILL_SW, &priv->status) << - STATUS_RF_KILL_SW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | test_bit(STATUS_FW_ERROR, &priv->status) << @@ -2779,12 +2647,6 @@ static int __iwl3945_up(struct iwl_priv *priv) return -EIO; } - if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { - IWL_WARN(priv, "Radio disabled by SW RF kill (module " - "parameter)\n"); - return -ENODEV; - } - if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { IWL_ERR(priv, "ucode not available for device bring up\n"); return -EIO; @@ -2833,7 +2695,7 @@ static int __iwl3945_up(struct iwl_priv *priv) for (i = 0; i < MAX_HW_RESTARTS; i++) { - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, @@ -2901,15 +2763,14 @@ static void iwl3945_rfkill_poll(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, rfkill_poll.work); - unsigned long status = priv->status; if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) clear_bit(STATUS_RF_KILL_HW, &priv->status); else set_bit(STATUS_RF_KILL_HW, &priv->status); - if (test_bit(STATUS_RF_KILL_HW, &status) != test_bit(STATUS_RF_KILL_HW, &priv->status)) - queue_work(priv->workqueue, &priv->rf_kill); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, + test_bit(STATUS_RF_KILL_HW, &priv->status)); queue_delayed_work(priv->workqueue, &priv->rfkill_poll, round_jiffies_relative(2 * HZ)); @@ -3141,7 +3002,6 @@ static void iwl3945_bg_up(struct work_struct *data) mutex_lock(&priv->mutex); __iwl3945_up(priv); mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); } static void iwl3945_bg_restart(struct work_struct *data) @@ -3247,7 +3107,7 @@ void iwl3945_post_associate(struct iwl_priv *priv) case NL80211_IFTYPE_ADHOC: priv->assoc_id = 1; - priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 0, 0, NULL); + iwl_add_station(priv, priv->bssid, 0, CMD_SYNC, NULL); iwl3945_sync_sta(priv, IWL_STA_ID, (priv->band == IEEE80211_BAND_5GHZ) ? IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, @@ -3304,8 +3164,6 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); - iwl_rfkill_set_hw_state(priv); - if (ret) goto out_release_irq; @@ -3438,7 +3296,7 @@ void iwl3945_config_ap(struct iwl_priv *priv) /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwlcore_commit_rxon(priv); - priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL); + iwl_add_station(priv, iwl_bcast_addr, 0, CMD_SYNC, NULL); } iwl3945_send_beacon_cmd(priv); @@ -3469,7 +3327,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, static_key = !iwl_is_associated(priv); if (!static_key) { - sta_id = priv->cfg->ops->smgmt->find_station(priv, addr); + sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", addr); @@ -3958,7 +3816,6 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->up, iwl3945_bg_up); INIT_WORK(&priv->restart, iwl3945_bg_restart); INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish); - INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); @@ -4044,7 +3901,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv) mutex_init(&priv->mutex); /* Clear the driver's (not device's) station table */ - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; @@ -4325,13 +4182,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (err) IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); - err = iwl_rfkill_init(priv); - if (err) - IWL_ERR(priv, "Unable to initialize RFKILL system. " - "Ignoring error: %d\n", err); - else - iwl_rfkill_set_hw_state(priv); - /* Start monitoring the killswitch */ queue_delayed_work(priv->workqueue, &priv->rfkill_poll, 2 * HZ); @@ -4397,7 +4247,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); - iwl_rfkill_unregister(priv); cancel_delayed_work_sync(&priv->rfkill_poll); iwl3945_dealloc_ucode_pci(priv); @@ -4407,7 +4256,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_hw_txq_ctx_free(priv); iwl3945_unset_hw_params(priv); - priv->cfg->ops->smgmt->clear_station_table(priv); + iwl_clear_stations_table(priv); /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig index 41bd4b2b5411..1eccb6df46dd 100644 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -1,10 +1,9 @@ config IWM tristate "Intel Wireless Multicomm 3200 WiFi driver" depends on MMC && WLAN_80211 && EXPERIMENTAL + depends on CFG80211 select WIRELESS_EXT - select CFG80211 select FW_LOADER - select RFKILL config IWM_DEBUG bool "Enable full debugging output in iwmc3200wifi" diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile index 7cb415e5c11b..927f022545c1 100644 --- a/drivers/net/wireless/iwmc3200wifi/Makefile +++ b/drivers/net/wireless/iwmc3200wifi/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_IWM) := iwmc3200wifi.o iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o -iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o rfkill.o +iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 3256ad2c96ce..96f714e6e12b 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -268,7 +268,7 @@ static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) iwm->conf.frag_threshold = wiphy->frag_threshold; - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, CFG_FRAG_THRESHOLD, iwm->conf.frag_threshold); if (ret < 0) diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index db4ba0864730..ec1a15a5a0e4 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -72,7 +72,7 @@ static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw, } if (fw->size < IWM_HDR_LEN) { - IWM_ERR(iwm, "FW is too small (%d)\n", fw->size); + IWM_ERR(iwm, "FW is too small (%zu)\n", fw->size); return -EINVAL; } diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 3b29681792bb..635c16ee6186 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -343,8 +343,4 @@ int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd); void iwm_rx_free(struct iwm_priv *iwm); -/* RF Kill API */ -int iwm_rfkill_init(struct iwm_priv *iwm); -void iwm_rfkill_exit(struct iwm_priv *iwm); - #endif diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index eec7201e91a8..68e2c3b6c7a1 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -136,17 +136,8 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev, wdev->netdev = ndev; - ret = iwm_rfkill_init(iwm); - if (ret) { - dev_err(dev, "Failed to init rfkill\n"); - goto out_rfkill; - } - return iwm; - out_rfkill: - unregister_netdev(ndev); - out_ndev: free_netdev(ndev); @@ -162,7 +153,6 @@ void iwm_if_free(struct iwm_priv *iwm) if (!iwm_to_ndev(iwm)) return; - iwm_rfkill_exit(iwm); unregister_netdev(iwm_to_ndev(iwm)); free_netdev(iwm_to_ndev(iwm)); iwm_wdev_free(iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/rfkill.c b/drivers/net/wireless/iwmc3200wifi/rfkill.c deleted file mode 100644 index 4ca8b495f82d..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/rfkill.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#include <linux/rfkill.h> - -#include "iwm.h" - -static int iwm_rfkill_soft_toggle(void *data, enum rfkill_state state) -{ - struct iwm_priv *iwm = data; - - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio)) - return -EBUSY; - - if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) && - (iwm_to_ndev(iwm)->flags & IFF_UP)) - iwm_up(iwm); - - break; - case RFKILL_STATE_SOFT_BLOCKED: - if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) - iwm_down(iwm); - - break; - default: - break; - } - - return 0; -} - -int iwm_rfkill_init(struct iwm_priv *iwm) -{ - int ret; - - iwm->rfkill = rfkill_allocate(iwm_to_dev(iwm), RFKILL_TYPE_WLAN); - if (!iwm->rfkill) { - IWM_ERR(iwm, "Unable to allocate rfkill device\n"); - return -ENOMEM; - } - - iwm->rfkill->name = KBUILD_MODNAME; - iwm->rfkill->data = iwm; - iwm->rfkill->state = RFKILL_STATE_UNBLOCKED; - iwm->rfkill->toggle_radio = iwm_rfkill_soft_toggle; - - ret = rfkill_register(iwm->rfkill); - if (ret) { - IWM_ERR(iwm, "Failed to register rfkill device\n"); - goto fail; - } - - return 0; - fail: - rfkill_free(iwm->rfkill); - return ret; -} - -void iwm_rfkill_exit(struct iwm_priv *iwm) -{ - if (iwm->rfkill) - rfkill_unregister(iwm->rfkill); - - rfkill_free(iwm->rfkill); - iwm->rfkill = NULL; -} diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index edc0a0091058..b54da677b371 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -395,7 +395,7 @@ static struct iwm_if_ops if_sdio_ops = { .debugfs_init = if_sdio_debugfs_init, .debugfs_exit = if_sdio_debugfs_exit, .umac_name = "iwmc3200wifi-umac-sdio.bin", - .calib_lmac_name = "iwmc3200wifi-lmac-calib-sdio.bin", + .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin", .lmac_name = "iwmc3200wifi-lmac-sdio.bin", }; diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 4bc46a60ae2f..9a5408e7d94a 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -207,7 +207,7 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband); lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo, COUNTRY_CODE_LEN + 1 + - sizeof(struct ieeetypes_subbandset) * nr_subband); + sizeof(struct ieee_subbandset) * nr_subband); return 0; } @@ -302,11 +302,9 @@ done: * @param parsed_region_chan pointer to parsed_region_chan_11d * @return 0 */ -static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* - countryinfo, +static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo, u8 band, - struct parsed_region_chan_11d * - parsed_region_chan) + struct parsed_region_chan_11d *parsed_region_chan) { u8 nr_subband, nrchan; u8 lastchan, firstchan; @@ -331,7 +329,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30); if ((*(countryinfo->countrycode)) == 0 - || (countryinfo->len <= COUNTRY_CODE_LEN)) { + || (countryinfo->header.len <= COUNTRY_CODE_LEN)) { /* No region Info or Wrong region info: treat as No 11D info */ goto done; } @@ -349,8 +347,8 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* memcpy(parsed_region_chan->countrycode, countryinfo->countrycode, COUNTRY_CODE_LEN); - nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) / - sizeof(struct ieeetypes_subbandset); + nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) / + sizeof(struct ieee_subbandset); for (j = 0, lastchan = 0; j < nr_subband; j++) { @@ -502,7 +500,7 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, { struct cmd_ds_802_11d_domain_info *pdomaininfo = &cmd->params.domaininfo; - struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain; + struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain; u8 nr_subband = priv->domainreg.nr_subband; lbs_deb_enter(LBS_DEB_11D); @@ -524,16 +522,16 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, sizeof(domain->countrycode)); domain->header.len = - cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) + + cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) + sizeof(domain->countrycode)); if (nr_subband) { memcpy(domain->subband, priv->domainreg.subband, - nr_subband * sizeof(struct ieeetypes_subbandset)); + nr_subband * sizeof(struct ieee_subbandset)); cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + le16_to_cpu(domain->header.len) + - sizeof(struct mrvlietypesheader) + + sizeof(struct mrvl_ie_header) + S_DS_GEN); } else { cmd->size = @@ -556,7 +554,7 @@ done: int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp) { struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp; - struct mrvlietypes_domainparamset *domain = &domaininfo->domain; + struct mrvl_ie_domain_param_set *domain = &domaininfo->domain; u16 action = le16_to_cpu(domaininfo->action); s16 ret = 0; u8 nr_subband = 0; @@ -567,7 +565,7 @@ int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp) (int)le16_to_cpu(resp->size)); nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) / - sizeof(struct ieeetypes_subbandset); + sizeof(struct ieee_subbandset); lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband); diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h index 4f4f47f0f878..fb75d3e321a0 100644 --- a/drivers/net/wireless/libertas/11d.h +++ b/drivers/net/wireless/libertas/11d.h @@ -20,35 +20,36 @@ struct cmd_ds_command; /** Data structure for Country IE*/ -struct ieeetypes_subbandset { +struct ieee_subbandset { u8 firstchan; u8 nrchan; u8 maxtxpwr; } __attribute__ ((packed)); -struct ieeetypes_countryinfoset { - u8 element_id; - u8 len; +struct ieee_ie_country_info_set { + struct ieee_ie_header header; + u8 countrycode[COUNTRY_CODE_LEN]; - struct ieeetypes_subbandset subband[1]; + struct ieee_subbandset subband[1]; }; -struct ieeetypes_countryinfofullset { - u8 element_id; - u8 len; +struct ieee_ie_country_info_full_set { + struct ieee_ie_header header; + u8 countrycode[COUNTRY_CODE_LEN]; - struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; + struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; } __attribute__ ((packed)); -struct mrvlietypes_domainparamset { - struct mrvlietypesheader header; +struct mrvl_ie_domain_param_set { + struct mrvl_ie_header header; + u8 countrycode[COUNTRY_CODE_LEN]; - struct ieeetypes_subbandset subband[1]; + struct ieee_subbandset subband[1]; } __attribute__ ((packed)); struct cmd_ds_802_11d_domain_info { __le16 action; - struct mrvlietypes_domainparamset domain; + struct mrvl_ie_domain_param_set domain; } __attribute__ ((packed)); /** domain regulatory information */ @@ -57,7 +58,7 @@ struct lbs_802_11d_domain_reg { u8 countrycode[COUNTRY_CODE_LEN]; /** No. of subband*/ u8 nr_subband; - struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; + struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; }; struct chan_power_11d { diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index a0e440cd8967..b9b374119033 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -12,15 +12,14 @@ #include "scan.h" #include "cmd.h" -static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp); - static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -/* The firmware needs certain bits masked out of the beacon-derviced capability - * field when associating/joining to BSSs. +/* The firmware needs the following bits masked out of the beacon-derived + * capability field when associating/joining to a BSS: + * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused) */ #define CAPINFO_MASK (~(0xda00)) @@ -102,6 +101,295 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len) } +static u8 iw_auth_to_ieee_auth(u8 auth) +{ + if (auth == IW_AUTH_ALG_OPEN_SYSTEM) + return 0x00; + else if (auth == IW_AUTH_ALG_SHARED_KEY) + return 0x01; + else if (auth == IW_AUTH_ALG_LEAP) + return 0x80; + + lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth); + return 0; +} + +/** + * @brief This function prepares the authenticate command. AUTHENTICATE only + * sets the authentication suite for future associations, as the firmware + * handles authentication internally during the ASSOCIATE command. + * + * @param priv A pointer to struct lbs_private structure + * @param bssid The peer BSSID with which to authenticate + * @param auth The authentication mode to use (from wireless.h) + * + * @return 0 or -1 + */ +static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth) +{ + struct cmd_ds_802_11_authenticate cmd; + int ret = -1; + DECLARE_MAC_BUF(mac); + + lbs_deb_enter(LBS_DEB_JOIN); + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + memcpy(cmd.bssid, bssid, ETH_ALEN); + + cmd.authtype = iw_auth_to_ieee_auth(auth); + + lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", + print_mac(mac, bssid), cmd.authtype); + + ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); + + lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + return ret; +} + + +static int lbs_assoc_post(struct lbs_private *priv, + struct cmd_ds_802_11_associate_response *resp) +{ + int ret = 0; + union iwreq_data wrqu; + struct bss_descriptor *bss; + u16 status_code; + + lbs_deb_enter(LBS_DEB_ASSOC); + + if (!priv->in_progress_assoc_req) { + lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); + ret = -1; + goto done; + } + bss = &priv->in_progress_assoc_req->bss; + + /* + * Older FW versions map the IEEE 802.11 Status Code in the association + * response to the following values returned in resp->statuscode: + * + * IEEE Status Code Marvell Status Code + * 0 -> 0x0000 ASSOC_RESULT_SUCCESS + * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED + * others -> 0x0003 ASSOC_RESULT_REFUSED + * + * Other response codes: + * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) + * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for + * association response from the AP) + */ + + status_code = le16_to_cpu(resp->statuscode); + if (priv->fwrelease < 0x09000000) { + switch (status_code) { + case 0x00: + break; + case 0x01: + lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); + break; + case 0x02: + lbs_deb_assoc("ASSOC_RESP: internal timer " + "expired while waiting for the AP\n"); + break; + case 0x03: + lbs_deb_assoc("ASSOC_RESP: association " + "refused by AP\n"); + break; + case 0x04: + lbs_deb_assoc("ASSOC_RESP: authentication " + "refused by AP\n"); + break; + default: + lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " + " unknown\n", status_code); + break; + } + } else { + /* v9+ returns the AP's association response */ + lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code); + } + + if (status_code) { + lbs_mac_event_disconnected(priv); + ret = -1; + goto done; + } + + lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", + (void *) (resp + sizeof (resp->hdr)), + le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr)); + + /* Send a Media Connected event, according to the Spec */ + priv->connect_status = LBS_CONNECTED; + + /* Update current SSID and BSSID */ + memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); + priv->curbssparams.ssid_len = bss->ssid_len; + memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); + + priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; + priv->NF[TYPE_RXPD][TYPE_AVG] = 0; + + memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); + memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); + priv->nextSNRNF = 0; + priv->numSNRNF = 0; + + netif_carrier_on(priv->dev); + if (!priv->tx_pending_len) + netif_wake_queue(priv->dev); + + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + +done: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; +} + +/** + * @brief This function prepares an association-class command. + * + * @param priv A pointer to struct lbs_private structure + * @param assoc_req The association request describing the BSS to associate + * or reassociate with + * @param command The actual command, either CMD_802_11_ASSOCIATE or + * CMD_802_11_REASSOCIATE + * + * @return 0 or -1 + */ +static int lbs_associate(struct lbs_private *priv, + struct assoc_request *assoc_req, + u16 command) +{ + struct cmd_ds_802_11_associate cmd; + int ret = 0; + struct bss_descriptor *bss = &assoc_req->bss; + u8 *pos = &(cmd.iebuf[0]); + u16 tmpcap, tmplen, tmpauth; + struct mrvl_ie_ssid_param_set *ssid; + struct mrvl_ie_ds_param_set *ds; + struct mrvl_ie_cf_param_set *cf; + struct mrvl_ie_rates_param_set *rates; + struct mrvl_ie_rsn_param_set *rsn; + struct mrvl_ie_auth_type *auth; + + lbs_deb_enter(LBS_DEB_ASSOC); + + BUG_ON((command != CMD_802_11_ASSOCIATE) && + (command != CMD_802_11_REASSOCIATE)); + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.command = cpu_to_le16(command); + + /* Fill in static fields */ + memcpy(cmd.bssid, bss->bssid, ETH_ALEN); + cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); + + /* Capability info */ + tmpcap = (bss->capability & CAPINFO_MASK); + if (bss->mode == IW_MODE_INFRA) + tmpcap |= WLAN_CAPABILITY_ESS; + cmd.capability = cpu_to_le16(tmpcap); + lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); + + /* SSID */ + ssid = (struct mrvl_ie_ssid_param_set *) pos; + ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); + tmplen = bss->ssid_len; + ssid->header.len = cpu_to_le16(tmplen); + memcpy(ssid->ssid, bss->ssid, tmplen); + pos += sizeof(ssid->header) + tmplen; + + ds = (struct mrvl_ie_ds_param_set *) pos; + ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); + ds->header.len = cpu_to_le16(1); + ds->channel = bss->phy.ds.channel; + pos += sizeof(ds->header) + 1; + + cf = (struct mrvl_ie_cf_param_set *) pos; + cf->header.type = cpu_to_le16(TLV_TYPE_CF); + tmplen = sizeof(*cf) - sizeof (cf->header); + cf->header.len = cpu_to_le16(tmplen); + /* IE payload should be zeroed, firmware fills it in for us */ + pos += sizeof(*cf); + + rates = (struct mrvl_ie_rates_param_set *) pos; + rates->header.type = cpu_to_le16(TLV_TYPE_RATES); + memcpy(&rates->rates, &bss->rates, MAX_RATES); + tmplen = MAX_RATES; + if (get_common_rates(priv, rates->rates, &tmplen)) { + ret = -1; + goto done; + } + pos += sizeof(rates->header) + tmplen; + rates->header.len = cpu_to_le16(tmplen); + lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); + + /* Copy the infra. association rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(rates->rates, tmplen); + + /* Firmware v9+ indicate authentication suites as a TLV */ + if (priv->fwrelease >= 0x09000000) { + DECLARE_MAC_BUF(mac); + + auth = (struct mrvl_ie_auth_type *) pos; + auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); + auth->header.len = cpu_to_le16(2); + tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode); + auth->auth = cpu_to_le16(tmpauth); + pos += sizeof(auth->header) + 2; + + lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", + print_mac(mac, bss->bssid), priv->secinfo.auth_mode); + } + + /* WPA/WPA2 IEs */ + if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { + rsn = (struct mrvl_ie_rsn_param_set *) pos; + /* WPA_IE or WPA2_IE */ + rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); + tmplen = (u16) assoc_req->wpa_ie[1]; + rsn->header.len = cpu_to_le16(tmplen); + memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); + lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn, + sizeof(rsn->header) + tmplen); + pos += sizeof(rsn->header) + tmplen; + } + + cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) + + (u16)(pos - (u8 *) &cmd.iebuf)); + + /* update curbssparams */ + priv->curbssparams.channel = bss->phy.ds.channel; + + if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { + ret = -1; + goto done; + } + + ret = lbs_cmd_with_response(priv, command, &cmd); + if (ret == 0) { + ret = lbs_assoc_post(priv, + (struct cmd_ds_802_11_associate_response *) &cmd); + } + +done: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; +} + /** * @brief Associate to a specific BSS discovered in a scan * @@ -110,7 +398,7 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len) * * @return 0-success, otherwise fail */ -static int lbs_associate(struct lbs_private *priv, +static int lbs_try_associate(struct lbs_private *priv, struct assoc_request *assoc_req) { int ret; @@ -118,11 +406,15 @@ static int lbs_associate(struct lbs_private *priv, lbs_deb_enter(LBS_DEB_ASSOC); - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, - 0, CMD_OPTION_WAITFORRSP, - 0, assoc_req->bss.bssid); - if (ret) - goto out; + /* FW v9 and higher indicate authentication suites as a TLV in the + * association command, not as a separate authentication command. + */ + if (priv->fwrelease < 0x09000000) { + ret = lbs_set_authentication(priv, assoc_req->bss.bssid, + priv->secinfo.auth_mode); + if (ret) + goto out; + } /* Use short preamble only when both the BSS and firmware support it */ if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && @@ -133,14 +425,78 @@ static int lbs_associate(struct lbs_private *priv, if (ret) goto out; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, - 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); + ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } +static int lbs_adhoc_post(struct lbs_private *priv, + struct cmd_ds_802_11_ad_hoc_result *resp) +{ + int ret = 0; + u16 command = le16_to_cpu(resp->hdr.command); + u16 result = le16_to_cpu(resp->hdr.result); + union iwreq_data wrqu; + struct bss_descriptor *bss; + DECLARE_SSID_BUF(ssid); + + lbs_deb_enter(LBS_DEB_JOIN); + + if (!priv->in_progress_assoc_req) { + lbs_deb_join("ADHOC_RESP: no in-progress association " + "request\n"); + ret = -1; + goto done; + } + bss = &priv->in_progress_assoc_req->bss; + + /* + * Join result code 0 --> SUCCESS + */ + if (result) { + lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result); + if (priv->connect_status == LBS_CONNECTED) + lbs_mac_event_disconnected(priv); + ret = -1; + goto done; + } + + /* Send a Media Connected event, according to the Spec */ + priv->connect_status = LBS_CONNECTED; + + if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { + /* Update the created network descriptor with the new BSSID */ + memcpy(bss->bssid, resp->bssid, ETH_ALEN); + } + + /* Set the BSSID from the joined/started descriptor */ + memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); + + /* Set the new SSID to current SSID */ + memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); + priv->curbssparams.ssid_len = bss->ssid_len; + + netif_carrier_on(priv->dev); + if (!priv->tx_pending_len) + netif_wake_queue(priv->dev); + + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + + lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", + print_ssid(ssid, bss->ssid, bss->ssid_len), + priv->curbssparams.bssid, + priv->curbssparams.channel); + +done: + lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + return ret; +} + /** * @brief Join an adhoc network found in a previous scan * @@ -219,11 +575,10 @@ static int lbs_adhoc_join(struct lbs_private *priv, memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN); memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len); - memcpy(&cmd.bss.phyparamset, &bss->phyparamset, - sizeof(union ieeetypes_phyparamset)); + memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set)); - memcpy(&cmd.bss.ssparamset, &bss->ssparamset, - sizeof(union IEEEtypes_ssparamset)); + memcpy(&cmd.bss.ibss, &bss->ss.ibss, + sizeof(struct ieee_ie_ibss_param_set)); cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", @@ -260,7 +615,7 @@ static int lbs_adhoc_join(struct lbs_private *priv, */ lbs_set_basic_rate_flags(cmd.bss.rates, ratesize); - cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); + cmd.bss.ibss.atimwindow = bss->atimwindow; if (assoc_req->secinfo.wep_enabled) { u16 tmp = le16_to_cpu(cmd.bss.capability); @@ -287,8 +642,10 @@ static int lbs_adhoc_join(struct lbs_private *priv, } ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); - if (ret == 0) - ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); + if (ret == 0) { + ret = lbs_adhoc_post(priv, + (struct cmd_ds_802_11_ad_hoc_result *)&cmd); + } out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -343,22 +700,24 @@ static int lbs_adhoc_start(struct lbs_private *priv, WARN_ON(!assoc_req->channel); /* set Physical parameter set */ - cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS; - cmd.phyparamset.dsparamset.len = 1; - cmd.phyparamset.dsparamset.currentchan = assoc_req->channel; + cmd.ds.header.id = WLAN_EID_DS_PARAMS; + cmd.ds.header.len = 1; + cmd.ds.channel = assoc_req->channel; /* set IBSS parameter set */ - cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS; - cmd.ssparamset.ibssparamset.len = 2; - cmd.ssparamset.ibssparamset.atimwindow = 0; + cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS; + cmd.ibss.header.len = 2; + cmd.ibss.atimwindow = cpu_to_le16(0); /* set capability info */ tmpcap = WLAN_CAPABILITY_IBSS; - if (assoc_req->secinfo.wep_enabled) { - lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n"); + if (assoc_req->secinfo.wep_enabled || + assoc_req->secinfo.WPAenabled || + assoc_req->secinfo.WPA2enabled) { + lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n"); tmpcap |= WLAN_CAPABILITY_PRIVACY; } else - lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n"); + lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n"); cmd.capability = cpu_to_le16(tmpcap); @@ -395,7 +754,8 @@ static int lbs_adhoc_start(struct lbs_private *priv, ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); if (ret == 0) - ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); + ret = lbs_adhoc_post(priv, + (struct cmd_ds_802_11_ad_hoc_result *)&cmd); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -720,7 +1080,7 @@ static int assoc_helper_essid(struct lbs_private *priv, assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); if (bss != NULL) { memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); - ret = lbs_associate(priv, assoc_req); + ret = lbs_try_associate(priv, assoc_req); } else { lbs_deb_assoc("SSID not found; cannot associate\n"); } @@ -772,8 +1132,9 @@ static int assoc_helper_bssid(struct lbs_private *priv, memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); if (assoc_req->mode == IW_MODE_INFRA) { - ret = lbs_associate(priv, assoc_req); - lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret); + ret = lbs_try_associate(priv, assoc_req); + lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n", + ret); } else if (assoc_req->mode == IW_MODE_ADHOC) { lbs_adhoc_join(priv, assoc_req); } @@ -1467,57 +1828,6 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv) /** - * @brief This function prepares command of authenticate. - * - * @param priv A pointer to struct lbs_private structure - * @param cmd A pointer to cmd_ds_command structure - * @param pdata_buf Void cast of pointer to a BSSID to authenticate with - * - * @return 0 or -1 - */ -int lbs_cmd_80211_authenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf) -{ - struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; - int ret = -1; - u8 *bssid = pdata_buf; - - lbs_deb_enter(LBS_DEB_JOIN); - - cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) - + S_DS_GEN); - - /* translate auth mode to 802.11 defined wire value */ - switch (priv->secinfo.auth_mode) { - case IW_AUTH_ALG_OPEN_SYSTEM: - pauthenticate->authtype = 0x00; - break; - case IW_AUTH_ALG_SHARED_KEY: - pauthenticate->authtype = 0x01; - break; - case IW_AUTH_ALG_LEAP: - pauthenticate->authtype = 0x80; - break; - default: - lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n", - priv->secinfo.auth_mode); - goto out; - } - - memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); - - lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", - bssid, pauthenticate->authtype); - ret = 0; - -out: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - -/** * @brief Deauthenticate from a specific BSS * * @param priv A pointer to struct lbs_private structure @@ -1550,285 +1860,3 @@ int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], return ret; } -int lbs_cmd_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_associate *passo = &cmd->params.associate; - int ret = 0; - struct assoc_request *assoc_req = pdata_buf; - struct bss_descriptor *bss = &assoc_req->bss; - u8 *pos; - u16 tmpcap, tmplen; - struct mrvlietypes_ssidparamset *ssid; - struct mrvlietypes_phyparamset *phy; - struct mrvlietypes_ssparamset *ss; - struct mrvlietypes_ratesparamset *rates; - struct mrvlietypes_rsnparamset *rsn; - - lbs_deb_enter(LBS_DEB_ASSOC); - - pos = (u8 *) passo; - - if (!priv) { - ret = -1; - goto done; - } - - cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE); - - memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr)); - pos += sizeof(passo->peerstaaddr); - - /* set the listen interval */ - passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); - - pos += sizeof(passo->capability); - pos += sizeof(passo->listeninterval); - pos += sizeof(passo->bcnperiod); - pos += sizeof(passo->dtimperiod); - - ssid = (struct mrvlietypes_ssidparamset *) pos; - ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); - tmplen = bss->ssid_len; - ssid->header.len = cpu_to_le16(tmplen); - memcpy(ssid->ssid, bss->ssid, tmplen); - pos += sizeof(ssid->header) + tmplen; - - phy = (struct mrvlietypes_phyparamset *) pos; - phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); - tmplen = sizeof(phy->fh_ds.dsparamset); - phy->header.len = cpu_to_le16(tmplen); - memcpy(&phy->fh_ds.dsparamset, - &bss->phyparamset.dsparamset.currentchan, - tmplen); - pos += sizeof(phy->header) + tmplen; - - ss = (struct mrvlietypes_ssparamset *) pos; - ss->header.type = cpu_to_le16(TLV_TYPE_CF); - tmplen = sizeof(ss->cf_ibss.cfparamset); - ss->header.len = cpu_to_le16(tmplen); - pos += sizeof(ss->header) + tmplen; - - rates = (struct mrvlietypes_ratesparamset *) pos; - rates->header.type = cpu_to_le16(TLV_TYPE_RATES); - memcpy(&rates->rates, &bss->rates, MAX_RATES); - tmplen = MAX_RATES; - if (get_common_rates(priv, rates->rates, &tmplen)) { - ret = -1; - goto done; - } - pos += sizeof(rates->header) + tmplen; - rates->header.len = cpu_to_le16(tmplen); - lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); - - /* Copy the infra. association rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(rates->rates, tmplen); - - if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { - rsn = (struct mrvlietypes_rsnparamset *) pos; - /* WPA_IE or WPA2_IE */ - rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); - tmplen = (u16) assoc_req->wpa_ie[1]; - rsn->header.len = cpu_to_le16(tmplen); - memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); - lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn, - sizeof(rsn->header) + tmplen); - pos += sizeof(rsn->header) + tmplen; - } - - /* update curbssparams */ - priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; - - if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); - - /* set the capability info */ - tmpcap = (bss->capability & CAPINFO_MASK); - if (bss->mode == IW_MODE_INFRA) - tmpcap |= WLAN_CAPABILITY_ESS; - passo->capability = cpu_to_le16(tmpcap); - lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); - -done: - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); - return ret; -} - -int lbs_ret_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - int ret = 0; - union iwreq_data wrqu; - struct ieeetypes_assocrsp *passocrsp; - struct bss_descriptor *bss; - u16 status_code; - - lbs_deb_enter(LBS_DEB_ASSOC); - - if (!priv->in_progress_assoc_req) { - lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); - ret = -1; - goto done; - } - bss = &priv->in_progress_assoc_req->bss; - - passocrsp = (struct ieeetypes_assocrsp *) &resp->params; - - /* - * Older FW versions map the IEEE 802.11 Status Code in the association - * response to the following values returned in passocrsp->statuscode: - * - * IEEE Status Code Marvell Status Code - * 0 -> 0x0000 ASSOC_RESULT_SUCCESS - * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED - * others -> 0x0003 ASSOC_RESULT_REFUSED - * - * Other response codes: - * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) - * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for - * association response from the AP) - */ - - status_code = le16_to_cpu(passocrsp->statuscode); - switch (status_code) { - case 0x00: - break; - case 0x01: - lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); - break; - case 0x02: - lbs_deb_assoc("ASSOC_RESP: internal timer " - "expired while waiting for the AP\n"); - break; - case 0x03: - lbs_deb_assoc("ASSOC_RESP: association " - "refused by AP\n"); - break; - case 0x04: - lbs_deb_assoc("ASSOC_RESP: authentication " - "refused by AP\n"); - break; - default: - lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " - " unknown\n", status_code); - break; - } - - if (status_code) { - lbs_mac_event_disconnected(priv); - ret = -1; - goto done; - } - - lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params, - le16_to_cpu(resp->size) - S_DS_GEN); - - /* Send a Media Connected event, according to the Spec */ - priv->connect_status = LBS_CONNECTED; - - /* Update current SSID and BSSID */ - memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); - priv->curbssparams.ssid_len = bss->ssid_len; - memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); - - priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; - priv->NF[TYPE_RXPD][TYPE_AVG] = 0; - - memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); - memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); - priv->nextSNRNF = 0; - priv->numSNRNF = 0; - - netif_carrier_on(priv->dev); - if (!priv->tx_pending_len) - netif_wake_queue(priv->dev); - - memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - -done: - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); - return ret; -} - -static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) -{ - int ret = 0; - u16 command = le16_to_cpu(resp->command); - u16 result = le16_to_cpu(resp->result); - struct cmd_ds_802_11_ad_hoc_result *adhoc_resp; - union iwreq_data wrqu; - struct bss_descriptor *bss; - DECLARE_SSID_BUF(ssid); - - lbs_deb_enter(LBS_DEB_JOIN); - - adhoc_resp = (struct cmd_ds_802_11_ad_hoc_result *) resp; - - if (!priv->in_progress_assoc_req) { - lbs_deb_join("ADHOC_RESP: no in-progress association " - "request\n"); - ret = -1; - goto done; - } - bss = &priv->in_progress_assoc_req->bss; - - /* - * Join result code 0 --> SUCCESS - */ - if (result) { - lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result); - if (priv->connect_status == LBS_CONNECTED) - lbs_mac_event_disconnected(priv); - ret = -1; - goto done; - } - - /* Send a Media Connected event, according to the Spec */ - priv->connect_status = LBS_CONNECTED; - - if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { - /* Update the created network descriptor with the new BSSID */ - memcpy(bss->bssid, adhoc_resp->bssid, ETH_ALEN); - } - - /* Set the BSSID from the joined/started descriptor */ - memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); - - /* Set the new SSID to current SSID */ - memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); - priv->curbssparams.ssid_len = bss->ssid_len; - - netif_carrier_on(priv->dev); - if (!priv->tx_pending_len) - netif_wake_queue(priv->dev); - - memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - - lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", - print_ssid(ssid, bss->ssid, bss->ssid_len), - priv->curbssparams.bssid, - priv->curbssparams.channel); - -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index 8b7336dd02a3..6e765e9f91a3 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -8,22 +8,9 @@ void lbs_association_worker(struct work_struct *work); struct assoc_request *lbs_get_association_request(struct lbs_private *priv); -struct cmd_ds_command; -int lbs_cmd_80211_authenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); - int lbs_adhoc_stop(struct lbs_private *priv); int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], u16 reason); -int lbs_cmd_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); - -int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *resp); -int lbs_ret_80211_associate(struct lbs_private *priv, - struct cmd_ds_command *resp); #endif /* _LBS_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index c455b9abbfc0..01db705a38ec 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1220,8 +1220,7 @@ static void lbs_submit_command(struct lbs_private *priv, command = le16_to_cpu(cmd->command); /* These commands take longer */ - if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE || - command == CMD_802_11_AUTHENTICATE) + if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE) timeo = 5 * HZ; lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n", @@ -1415,15 +1414,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action); break; - case CMD_802_11_ASSOCIATE: - case CMD_802_11_REASSOCIATE: - ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); - break; - - case CMD_802_11_AUTHENTICATE: - ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf); - break; - case CMD_MAC_REG_ACCESS: case CMD_BBP_REG_ACCESS: case CMD_RF_REG_ACCESS: @@ -1470,8 +1460,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, break; case CMD_802_11_LED_GPIO_CTRL: { - struct mrvlietypes_ledgpio *gpio = - (struct mrvlietypes_ledgpio*) + struct mrvl_ie_ledgpio *gpio = + (struct mrvl_ie_ledgpio*) cmdptr->params.ledgpio.data; memmove(&cmdptr->params.ledgpio, diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index bcf2a9756fb6..c42d3faa2660 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -5,7 +5,7 @@ #include <linux/delay.h> #include <linux/if_arp.h> #include <linux/netdevice.h> - +#include <asm/unaligned.h> #include <net/iw_handler.h> #include "host.h" @@ -154,11 +154,11 @@ static int lbs_ret_802_11_rssi(struct lbs_private *priv, lbs_deb_enter(LBS_DEB_CMD); /* store the non average value */ - priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); - priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor); + priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR); + priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor); - priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR); - priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor); + priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR); + priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgnoisefloor); priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], @@ -210,12 +210,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_reg_access(priv, respcmd, resp); break; - case CMD_RET_802_11_ASSOCIATE: - case CMD_RET(CMD_802_11_ASSOCIATE): - case CMD_RET(CMD_802_11_REASSOCIATE): - ret = lbs_ret_80211_associate(priv, resp); - break; - case CMD_RET(CMD_802_11_SET_AFC): case CMD_RET(CMD_802_11_GET_AFC): spin_lock_irqsave(&priv->driver_lock, flags); @@ -225,7 +219,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, break; - case CMD_RET(CMD_802_11_AUTHENTICATE): case CMD_RET(CMD_802_11_BEACON_STOP): break; diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 50e28a0cdfee..811ffc3ef414 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -183,12 +183,12 @@ out_unlock: */ static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size) { - struct mrvlietypesheader *tlv_h; + struct mrvl_ie_header *tlv_h; uint16_t length; ssize_t pos = 0; while (pos < size) { - tlv_h = (struct mrvlietypesheader *) tlv; + tlv_h = (struct mrvl_ie_header *) tlv; if (!tlv_h->len) return NULL; if (tlv_h->type == cpu_to_le16(tlv_type)) @@ -206,7 +206,7 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask, size_t count, loff_t *ppos) { struct cmd_ds_802_11_subscribe_event *subscribed; - struct mrvlietypes_thresholds *got; + struct mrvl_ie_thresholds *got; struct lbs_private *priv = file->private_data; ssize_t ret = 0; size_t pos = 0; @@ -259,7 +259,7 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask, loff_t *ppos) { struct cmd_ds_802_11_subscribe_event *events; - struct mrvlietypes_thresholds *tlv; + struct mrvl_ie_thresholds *tlv; struct lbs_private *priv = file->private_data; ssize_t buf_size; int value, freq, new_mask; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index a4455ec7c354..f9ec69e04734 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -321,8 +321,6 @@ struct lbs_private { u32 monitormode; u8 fw_ready; - u8 fn_init_required; - u8 fn_shutdown_required; }; extern struct cmd_confirm_sleep confirm_sleep; @@ -340,7 +338,7 @@ struct bss_descriptor { u32 rssi; u32 channel; u16 beaconperiod; - u32 atimwindow; + __le16 atimwindow; /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ u8 mode; @@ -350,10 +348,10 @@ struct bss_descriptor { unsigned long last_scanned; - union ieeetypes_phyparamset phyparamset; - union IEEEtypes_ssparamset ssparamset; + union ieee_phy_param_set phy; + union ieee_ss_param_set ss; - struct ieeetypes_countryinfofullset countryinfo; + struct ieee_ie_country_info_full_set countryinfo; u8 wpa_ie[MAX_WPA_IE_LEN]; size_t wpa_ie_len; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 391c54ab2b09..0a2e29140add 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -250,7 +250,9 @@ struct cmd_ds_gspi_bus_config { } __attribute__ ((packed)); struct cmd_ds_802_11_authenticate { - u8 macaddr[ETH_ALEN]; + struct cmd_header hdr; + + u8 bssid[ETH_ALEN]; u8 authtype; u8 reserved[10]; } __attribute__ ((packed)); @@ -263,22 +265,23 @@ struct cmd_ds_802_11_deauthenticate { } __attribute__ ((packed)); struct cmd_ds_802_11_associate { - u8 peerstaaddr[6]; + struct cmd_header hdr; + + u8 bssid[6]; __le16 capability; __le16 listeninterval; __le16 bcnperiod; u8 dtimperiod; - -#if 0 - mrvlietypes_ssidparamset_t ssidParamSet; - mrvlietypes_phyparamset_t phyparamset; - mrvlietypes_ssparamset_t ssparamset; - mrvlietypes_ratesparamset_t ratesParamSet; -#endif + u8 iebuf[512]; /* Enough for required and most optional IEs */ } __attribute__ ((packed)); -struct cmd_ds_802_11_associate_rsp { - struct ieeetypes_assocrsp assocRsp; +struct cmd_ds_802_11_associate_response { + struct cmd_header hdr; + + __le16 capability; + __le16 statuscode; + __le16 aid; + u8 iebuf[512]; } __attribute__ ((packed)); struct cmd_ds_802_11_set_wep { @@ -535,9 +538,11 @@ struct cmd_ds_802_11_ad_hoc_start { u8 bsstype; __le16 beaconperiod; u8 dtimperiod; /* Reserved on v9 and later */ - union IEEEtypes_ssparamset ssparamset; - union ieeetypes_phyparamset phyparamset; - __le16 probedelay; + struct ieee_ie_ibss_param_set ibss; + u8 reserved1[4]; + struct ieee_ie_ds_param_set ds; + u8 reserved2[4]; + __le16 probedelay; /* Reserved on v9 and later */ __le16 capability; u8 rates[MAX_RATES]; u8 tlv_memory_size_pad[100]; @@ -558,8 +563,10 @@ struct adhoc_bssdesc { u8 dtimperiod; __le64 timestamp; __le64 localtime; - union ieeetypes_phyparamset phyparamset; - union IEEEtypes_ssparamset ssparamset; + struct ieee_ie_ds_param_set ds; + u8 reserved1[4]; + struct ieee_ie_ibss_param_set ibss; + u8 reserved2[4]; __le16 capability; u8 rates[MAX_RATES]; @@ -765,8 +772,6 @@ struct cmd_ds_command { /* command Body */ union { struct cmd_ds_802_11_ps_mode psmode; - struct cmd_ds_802_11_associate associate; - struct cmd_ds_802_11_authenticate auth; struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; struct cmd_ds_802_11_rf_antenna rant; diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index a7e3fc119b70..8cdb88c6ca28 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -39,8 +39,24 @@ #include "decl.h" #include "defs.h" #include "dev.h" +#include "cmd.h" #include "if_sdio.h" +/* The if_sdio_remove() callback function is called when + * user removes this module from kernel space or ejects + * the card from the slot. The driver handles these 2 cases + * differently for SD8688 combo chip. + * If the user is removing the module, the FUNC_SHUTDOWN + * command for SD8688 is sent to the firmware. + * If the card is removed, there is no need to send this command. + * + * The variable 'user_rmmod' is used to distinguish these two + * scenarios. This flag is initialized as FALSE in case the card + * is removed, and will be set to TRUE for module removal when + * module_exit function is called. + */ +static u8 user_rmmod; + static char *lbs_helper_name = NULL; module_param_named(helper_name, lbs_helper_name, charp, 0644); @@ -61,7 +77,6 @@ struct if_sdio_model { int model; const char *helper; const char *firmware; - struct if_sdio_card *card; }; static struct if_sdio_model if_sdio_models[] = { @@ -70,21 +85,18 @@ static struct if_sdio_model if_sdio_models[] = { .model = IF_SDIO_MODEL_8385, .helper = "sd8385_helper.bin", .firmware = "sd8385.bin", - .card = NULL, }, { /* 8686 */ .model = IF_SDIO_MODEL_8686, .helper = "sd8686_helper.bin", .firmware = "sd8686.bin", - .card = NULL, }, { /* 8688 */ .model = IF_SDIO_MODEL_8688, .helper = "sd8688_helper.bin", .firmware = "sd8688.bin", - .card = NULL, }, }; @@ -927,8 +939,6 @@ static int if_sdio_probe(struct sdio_func *func, goto free; } - if_sdio_models[i].card = card; - card->helper = if_sdio_models[i].helper; card->firmware = if_sdio_models[i].firmware; @@ -1014,8 +1024,16 @@ static int if_sdio_probe(struct sdio_func *func, /* * FUNC_INIT is required for SD8688 WLAN/BT multiple functions */ - priv->fn_init_required = - (card->model == IF_SDIO_MODEL_8688) ? 1 : 0; + if (card->model == IF_SDIO_MODEL_8688) { + struct cmd_header cmd; + + memset(&cmd, 0, sizeof(cmd)); + + lbs_deb_sdio("send function INIT command\n"); + if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), + lbs_cmd_copyback, (unsigned long) &cmd)) + lbs_pr_alert("CMD_FUNC_INIT cmd failed\n"); + } ret = lbs_start_card(priv); if (ret) @@ -1057,30 +1075,39 @@ static void if_sdio_remove(struct sdio_func *func) { struct if_sdio_card *card; struct if_sdio_packet *packet; - int ret; lbs_deb_enter(LBS_DEB_SDIO); card = sdio_get_drvdata(func); - lbs_stop_card(card->priv); + if (user_rmmod && (card->model == IF_SDIO_MODEL_8688)) { + /* + * FUNC_SHUTDOWN is required for SD8688 WLAN/BT + * multiple functions + */ + struct cmd_header cmd; + + memset(&cmd, 0, sizeof(cmd)); + + lbs_deb_sdio("send function SHUTDOWN command\n"); + if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN, + &cmd, sizeof(cmd), lbs_cmd_copyback, + (unsigned long) &cmd)) + lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n"); + } card->priv->surpriseremoved = 1; lbs_deb_sdio("call remove card\n"); + lbs_stop_card(card->priv); lbs_remove_card(card->priv); flush_workqueue(card->workqueue); destroy_workqueue(card->workqueue); sdio_claim_host(func); - - /* Disable interrupts */ - sdio_writeb(func, 0x00, IF_SDIO_H_INT_MASK, &ret); - sdio_release_irq(func); sdio_disable_func(func); - sdio_release_host(func); while (card->packets) { @@ -1116,6 +1143,9 @@ static int __init if_sdio_init_module(void) ret = sdio_register_driver(&if_sdio_driver); + /* Clear the flag in case user removes the card. */ + user_rmmod = 0; + lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; @@ -1123,22 +1153,10 @@ static int __init if_sdio_init_module(void) static void __exit if_sdio_exit_module(void) { - int i; - struct if_sdio_card *card; - lbs_deb_enter(LBS_DEB_SDIO); - for (i = 0; i < ARRAY_SIZE(if_sdio_models); i++) { - card = if_sdio_models[i].card; - - /* - * FUNC_SHUTDOWN is required for SD8688 WLAN/BT - * multiple functions - */ - if (card && card->priv) - card->priv->fn_shutdown_required = - (card->model == IF_SDIO_MODEL_8688) ? 1 : 0; - } + /* Set the flag as user is removing this module. */ + user_rmmod = 1; sdio_unregister_driver(&if_sdio_driver); diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 5fa55fe1f860..f8c2898d82b0 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -19,7 +19,6 @@ #include <linux/moduleparam.h> #include <linux/firmware.h> -#include <linux/gpio.h> #include <linux/jiffies.h> #include <linux/kthread.h> #include <linux/list.h> @@ -51,13 +50,6 @@ struct if_spi_card { u16 card_id; u8 card_rev; - /* Pin number for our GPIO chip-select. */ - /* TODO: Once the generic SPI layer has some additional features, we - * should take this out and use the normal chip select here. - * We need support for chip select delays, and not dropping chipselect - * after each word. */ - int gpio_cs; - /* The last time that we initiated an SPU operation */ unsigned long prev_xfer_time; @@ -119,9 +111,6 @@ static struct chip_ident chip_id_to_device_name[] = { * First we have to put a SPU register name on the bus. Then we can * either read from or write to that register. * - * For 16-bit transactions, byte order on the bus is big-endian. - * We don't have to worry about that here, though. - * The translation takes place in the SPI routines. */ static void spu_transaction_init(struct if_spi_card *card) @@ -133,12 +122,10 @@ static void spu_transaction_init(struct if_spi_card *card) * If not, we have to busy-wait to be on the safe side. */ ndelay(400); } - gpio_set_value(card->gpio_cs, 0); /* assert CS */ } static void spu_transaction_finish(struct if_spi_card *card) { - gpio_set_value(card->gpio_cs, 1); /* drop CS */ card->prev_xfer_time = jiffies; } @@ -147,7 +134,14 @@ static void spu_transaction_finish(struct if_spi_card *card) static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) { int err = 0; - u16 reg_out = reg | IF_SPI_WRITE_OPERATION_MASK; + u16 reg_out = cpu_to_le16(reg | IF_SPI_WRITE_OPERATION_MASK); + struct spi_message m; + struct spi_transfer reg_trans; + struct spi_transfer data_trans; + + spi_message_init(&m); + memset(®_trans, 0, sizeof(reg_trans)); + memset(&data_trans, 0, sizeof(data_trans)); /* You must give an even number of bytes to the SPU, even if it * doesn't care about the last one. */ @@ -156,29 +150,26 @@ static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) spu_transaction_init(card); /* write SPU register index */ - err = spi_write(card->spi, (u8 *)®_out, sizeof(u16)); - if (err) - goto out; + reg_trans.tx_buf = ®_out; + reg_trans.len = sizeof(reg_out); - err = spi_write(card->spi, buf, len); + data_trans.tx_buf = buf; + data_trans.len = len; -out: + spi_message_add_tail(®_trans, &m); + spi_message_add_tail(&data_trans, &m); + + err = spi_sync(card->spi, &m); spu_transaction_finish(card); return err; } static inline int spu_write_u16(struct if_spi_card *card, u16 reg, u16 val) { - return spu_write(card, reg, (u8 *)&val, sizeof(u16)); -} + u16 buff; -static inline int spu_write_u32(struct if_spi_card *card, u16 reg, u32 val) -{ - /* The lower 16 bits are written first. */ - u16 out[2]; - out[0] = val & 0xffff; - out[1] = (val & 0xffff0000) >> 16; - return spu_write(card, reg, (u8 *)&out, sizeof(u32)); + buff = cpu_to_le16(val); + return spu_write(card, reg, (u8 *)&buff, sizeof(u16)); } static inline int spu_reg_is_port_reg(u16 reg) @@ -195,10 +186,13 @@ static inline int spu_reg_is_port_reg(u16 reg) static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) { - unsigned int i, delay; + unsigned int delay; int err = 0; - u16 zero = 0; - u16 reg_out = reg | IF_SPI_READ_OPERATION_MASK; + u16 reg_out = cpu_to_le16(reg | IF_SPI_READ_OPERATION_MASK); + struct spi_message m; + struct spi_transfer reg_trans; + struct spi_transfer dummy_trans; + struct spi_transfer data_trans; /* You must take an even number of bytes from the SPU, even if you * don't care about the last one. */ @@ -206,29 +200,34 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) spu_transaction_init(card); + spi_message_init(&m); + memset(®_trans, 0, sizeof(reg_trans)); + memset(&dummy_trans, 0, sizeof(dummy_trans)); + memset(&data_trans, 0, sizeof(data_trans)); + /* write SPU register index */ - err = spi_write(card->spi, (u8 *)®_out, sizeof(u16)); - if (err) - goto out; + reg_trans.tx_buf = ®_out; + reg_trans.len = sizeof(reg_out); + spi_message_add_tail(®_trans, &m); delay = spu_reg_is_port_reg(reg) ? card->spu_port_delay : card->spu_reg_delay; if (card->use_dummy_writes) { /* Clock in dummy cycles while the SPU fills the FIFO */ - for (i = 0; i < delay / 16; ++i) { - err = spi_write(card->spi, (u8 *)&zero, sizeof(u16)); - if (err) - return err; - } + dummy_trans.len = delay / 8; + spi_message_add_tail(&dummy_trans, &m); } else { /* Busy-wait while the SPU fills the FIFO */ - ndelay(100 + (delay * 10)); + reg_trans.delay_usecs = + DIV_ROUND_UP((100 + (delay * 10)), 1000); } /* read in data */ - err = spi_read(card->spi, buf, len); + data_trans.rx_buf = buf; + data_trans.len = len; + spi_message_add_tail(&data_trans, &m); -out: + err = spi_sync(card->spi, &m); spu_transaction_finish(card); return err; } @@ -236,18 +235,25 @@ out: /* Read 16 bits from an SPI register */ static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val) { - return spu_read(card, reg, (u8 *)val, sizeof(u16)); + u16 buf; + int ret; + + ret = spu_read(card, reg, (u8 *)&buf, sizeof(buf)); + if (ret == 0) + *val = le16_to_cpup(&buf); + return ret; } /* Read 32 bits from an SPI register. * The low 16 bits are read first. */ static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val) { - u16 buf[2]; + u32 buf; int err; - err = spu_read(card, reg, (u8 *)buf, sizeof(u32)); + + err = spu_read(card, reg, (u8 *)&buf, sizeof(buf)); if (!err) - *val = buf[0] | (buf[1] << 16); + *val = le32_to_cpup(&buf); return err; } @@ -1051,7 +1057,6 @@ static int __devinit if_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, card); card->pdata = pdata; card->spi = spi; - card->gpio_cs = pdata->gpio_cs; card->prev_xfer_time = jiffies; sema_init(&card->spi_ready, 0); @@ -1060,26 +1065,18 @@ static int __devinit if_spi_probe(struct spi_device *spi) INIT_LIST_HEAD(&card->data_packet_list); spin_lock_init(&card->buffer_lock); - /* set up GPIO CS line. TODO: use regular CS line */ - err = gpio_request(card->gpio_cs, "if_spi_gpio_chip_select"); - if (err) - goto free_card; - err = gpio_direction_output(card->gpio_cs, 1); - if (err) - goto free_gpio; - /* Initialize the SPI Interface Unit */ err = spu_init(card, pdata->use_dummy_writes); if (err) - goto free_gpio; + goto free_card; err = spu_get_chip_revision(card, &card->card_id, &card->card_rev); if (err) - goto free_gpio; + goto free_card; /* Firmware load */ err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch); if (err) - goto free_gpio; + goto free_card; if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC) lbs_deb_spi("Firmware is already loaded for " "Marvell WLAN 802.11 adapter\n"); @@ -1087,7 +1084,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) err = if_spi_calculate_fw_names(card->card_id, card->helper_fw_name, card->main_fw_name); if (err) - goto free_gpio; + goto free_card; lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter " "(chip_id = 0x%04x, chip_rev = 0x%02x) " @@ -1098,23 +1095,23 @@ static int __devinit if_spi_probe(struct spi_device *spi) spi->max_speed_hz); err = if_spi_prog_helper_firmware(card); if (err) - goto free_gpio; + goto free_card; err = if_spi_prog_main_firmware(card); if (err) - goto free_gpio; + goto free_card; lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n"); } err = spu_set_interrupt_mode(card, 0, 1); if (err) - goto free_gpio; + goto free_card; /* Register our card with libertas. * This will call alloc_etherdev */ priv = lbs_add_card(card, &spi->dev); if (!priv) { err = -ENOMEM; - goto free_gpio; + goto free_card; } card->priv = priv; priv->card = card; @@ -1159,8 +1156,6 @@ terminate_thread: if_spi_terminate_spi_thread(card); remove_card: lbs_remove_card(priv); /* will call free_netdev */ -free_gpio: - gpio_free(card->gpio_cs); free_card: free_if_spi_card(card); out: @@ -1181,7 +1176,6 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) free_irq(spi->irq, card); if_spi_terminate_spi_thread(card); lbs_remove_card(priv); /* will call free_netdev */ - gpio_free(card->gpio_cs); if (card->pdata->teardown) card->pdata->teardown(spi); free_if_spi_card(card); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index a58a12352672..89575e448015 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1002,17 +1002,9 @@ static int lbs_setup_firmware(struct lbs_private *priv) { int ret = -1; s16 curlevel = 0, minlevel = 0, maxlevel = 0; - struct cmd_header cmd; lbs_deb_enter(LBS_DEB_FW); - if (priv->fn_init_required) { - memset(&cmd, 0, sizeof(cmd)); - if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), - lbs_cmd_copyback, (unsigned long) &cmd)) - lbs_pr_alert("CMD_FUNC_INIT command failed\n"); - } - /* Read MAC address from firmware */ memset(priv->current_addr, 0xff, ETH_ALEN); ret = lbs_update_hw_spec(priv); @@ -1200,9 +1192,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->mesh_open = 0; priv->infra_open = 0; - priv->fn_init_required = 0; - priv->fn_shutdown_required = 0; - /* Setup the OS Interface to our functions */ dev->netdev_ops = &lbs_netdev_ops; dev->watchdog_timeo = 5 * HZ; @@ -1384,20 +1373,11 @@ void lbs_stop_card(struct lbs_private *priv) struct net_device *dev; struct cmd_ctrl_node *cmdnode; unsigned long flags; - struct cmd_header cmd; lbs_deb_enter(LBS_DEB_MAIN); if (!priv) goto out; - - if (priv->fn_shutdown_required) { - memset(&cmd, 0, sizeof(cmd)); - if (__lbs_cmd(priv, CMD_FUNC_SHUTDOWN, &cmd, sizeof(cmd), - lbs_cmd_copyback, (unsigned long) &cmd)) - lbs_pr_alert("CMD_FUNC_SHUTDOWN command failed\n"); - } - dev = priv->dev; netif_stop_queue(dev); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 8124db36aaff..601b54249677 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -27,12 +27,12 @@ + 40) /* 40 for WPAIE */ //! Memory needed to store a max sized channel List TLV for a firmware scan -#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvlietypesheader) \ +#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvl_ie_header) \ + (MRVDRV_MAX_CHANNELS_PER_SCAN \ * sizeof(struct chanscanparamset))) //! Memory needed to store a max number/size SSID TLV for a firmware scan -#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset)) +#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvl_ie_ssid_param_set)) //! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max #define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \ @@ -211,7 +211,7 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, */ static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv) { - struct mrvlietypes_ssidparamset *ssid_tlv = (void *)tlv; + struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv; ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len); @@ -249,7 +249,7 @@ static int lbs_scan_add_chanlist_tlv(uint8_t *tlv, int chan_count) { size_t size = sizeof(struct chanscanparamset) *chan_count; - struct mrvlietypes_chanlistparamset *chan_tlv = (void *)tlv; + struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv; chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); memcpy(chan_tlv->chanscanparam, chan_list, size); @@ -270,7 +270,7 @@ static int lbs_scan_add_chanlist_tlv(uint8_t *tlv, static int lbs_scan_add_rates_tlv(uint8_t *tlv) { int i; - struct mrvlietypes_ratesparamset *rate_tlv = (void *)tlv; + struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv; rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); tlv += sizeof(rate_tlv->header); @@ -513,12 +513,12 @@ void lbs_scan_worker(struct work_struct *work) static int lbs_process_bss(struct bss_descriptor *bss, uint8_t **pbeaconinfo, int *bytesleft) { - struct ieeetypes_fhparamset *pFH; - struct ieeetypes_dsparamset *pDS; - struct ieeetypes_cfparamset *pCF; - struct ieeetypes_ibssparamset *pibss; + struct ieee_ie_fh_param_set *fh; + struct ieee_ie_ds_param_set *ds; + struct ieee_ie_cf_param_set *cf; + struct ieee_ie_ibss_param_set *ibss; DECLARE_SSID_BUF(ssid); - struct ieeetypes_countryinfoset *pcountryinfo; + struct ieee_ie_country_info_set *pcountryinfo; uint8_t *pos, *end, *p; uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; uint16_t beaconsize = 0; @@ -616,50 +616,49 @@ static int lbs_process_bss(struct bss_descriptor *bss, break; case WLAN_EID_FH_PARAMS: - pFH = (struct ieeetypes_fhparamset *) pos; - memmove(&bss->phyparamset.fhparamset, pFH, - sizeof(struct ieeetypes_fhparamset)); + fh = (struct ieee_ie_fh_param_set *) pos; + memcpy(&bss->phy.fh, fh, sizeof(*fh)); lbs_deb_scan("got FH IE\n"); break; case WLAN_EID_DS_PARAMS: - pDS = (struct ieeetypes_dsparamset *) pos; - bss->channel = pDS->currentchan; - memcpy(&bss->phyparamset.dsparamset, pDS, - sizeof(struct ieeetypes_dsparamset)); + ds = (struct ieee_ie_ds_param_set *) pos; + bss->channel = ds->channel; + memcpy(&bss->phy.ds, ds, sizeof(*ds)); lbs_deb_scan("got DS IE, channel %d\n", bss->channel); break; case WLAN_EID_CF_PARAMS: - pCF = (struct ieeetypes_cfparamset *) pos; - memcpy(&bss->ssparamset.cfparamset, pCF, - sizeof(struct ieeetypes_cfparamset)); + cf = (struct ieee_ie_cf_param_set *) pos; + memcpy(&bss->ss.cf, cf, sizeof(*cf)); lbs_deb_scan("got CF IE\n"); break; case WLAN_EID_IBSS_PARAMS: - pibss = (struct ieeetypes_ibssparamset *) pos; - bss->atimwindow = le16_to_cpu(pibss->atimwindow); - memmove(&bss->ssparamset.ibssparamset, pibss, - sizeof(struct ieeetypes_ibssparamset)); + ibss = (struct ieee_ie_ibss_param_set *) pos; + bss->atimwindow = ibss->atimwindow; + memcpy(&bss->ss.ibss, ibss, sizeof(*ibss)); lbs_deb_scan("got IBSS IE\n"); break; case WLAN_EID_COUNTRY: - pcountryinfo = (struct ieeetypes_countryinfoset *) pos; + pcountryinfo = (struct ieee_ie_country_info_set *) pos; lbs_deb_scan("got COUNTRY IE\n"); - if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) - || pcountryinfo->len > 254) { - lbs_deb_scan("process_bss: 11D- Err CountryInfo len %d, min %zd, max 254\n", - pcountryinfo->len, sizeof(pcountryinfo->countrycode)); + if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode) + || pcountryinfo->header.len > 254) { + lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n", + __func__, + pcountryinfo->header.len, + sizeof(pcountryinfo->countrycode)); ret = -1; goto done; } - memcpy(&bss->countryinfo, pcountryinfo, pcountryinfo->len + 2); + memcpy(&bss->countryinfo, pcountryinfo, + pcountryinfo->header.len + 2); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", (uint8_t *) pcountryinfo, - (int) (pcountryinfo->len + 2)); + (int) (pcountryinfo->header.len + 2)); break; case WLAN_EID_EXT_SUPP_RATES: @@ -1130,7 +1129,7 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, goto done; } - bytesleft = le16_to_cpu(scanresp->bssdescriptsize); + bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize); lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); scanrespsize = le16_to_cpu(resp->size); diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index de03b9c9c204..99905df65b25 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -8,9 +8,14 @@ #include <asm/byteorder.h> #include <linux/wireless.h> -struct ieeetypes_cfparamset { - u8 elementid; +struct ieee_ie_header { + u8 id; u8 len; +} __attribute__ ((packed)); + +struct ieee_ie_cf_param_set { + struct ieee_ie_header header; + u8 cfpcnt; u8 cfpperiod; __le16 cfpmaxduration; @@ -18,42 +23,35 @@ struct ieeetypes_cfparamset { } __attribute__ ((packed)); -struct ieeetypes_ibssparamset { - u8 elementid; - u8 len; +struct ieee_ie_ibss_param_set { + struct ieee_ie_header header; + __le16 atimwindow; } __attribute__ ((packed)); -union IEEEtypes_ssparamset { - struct ieeetypes_cfparamset cfparamset; - struct ieeetypes_ibssparamset ibssparamset; +union ieee_ss_param_set { + struct ieee_ie_cf_param_set cf; + struct ieee_ie_ibss_param_set ibss; } __attribute__ ((packed)); -struct ieeetypes_fhparamset { - u8 elementid; - u8 len; +struct ieee_ie_fh_param_set { + struct ieee_ie_header header; + __le16 dwelltime; u8 hopset; u8 hoppattern; u8 hopindex; } __attribute__ ((packed)); -struct ieeetypes_dsparamset { - u8 elementid; - u8 len; - u8 currentchan; -} __attribute__ ((packed)); +struct ieee_ie_ds_param_set { + struct ieee_ie_header header; -union ieeetypes_phyparamset { - struct ieeetypes_fhparamset fhparamset; - struct ieeetypes_dsparamset dsparamset; + u8 channel; } __attribute__ ((packed)); -struct ieeetypes_assocrsp { - __le16 capability; - __le16 statuscode; - __le16 aid; - u8 iebuffer[1]; +union ieee_phy_param_set { + struct ieee_ie_fh_param_set fh; + struct ieee_ie_ds_param_set ds; } __attribute__ ((packed)); /** TLV type ID definition */ @@ -94,32 +92,33 @@ struct ieeetypes_assocrsp { #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) #define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) #define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23) +#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) #define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37) #define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291) /** TLV related data structures*/ -struct mrvlietypesheader { +struct mrvl_ie_header { __le16 type; __le16 len; } __attribute__ ((packed)); -struct mrvlietypes_data { - struct mrvlietypesheader header; +struct mrvl_ie_data { + struct mrvl_ie_header header; u8 Data[1]; } __attribute__ ((packed)); -struct mrvlietypes_ratesparamset { - struct mrvlietypesheader header; +struct mrvl_ie_rates_param_set { + struct mrvl_ie_header header; u8 rates[1]; } __attribute__ ((packed)); -struct mrvlietypes_ssidparamset { - struct mrvlietypesheader header; +struct mrvl_ie_ssid_param_set { + struct mrvl_ie_header header; u8 ssid[1]; } __attribute__ ((packed)); -struct mrvlietypes_wildcardssidparamset { - struct mrvlietypesheader header; +struct mrvl_ie_wildcard_ssid_param_set { + struct mrvl_ie_header header; u8 MaxSsidlength; u8 ssid[1]; } __attribute__ ((packed)); @@ -144,91 +143,72 @@ struct chanscanparamset { __le16 maxscantime; } __attribute__ ((packed)); -struct mrvlietypes_chanlistparamset { - struct mrvlietypesheader header; +struct mrvl_ie_chanlist_param_set { + struct mrvl_ie_header header; struct chanscanparamset chanscanparam[1]; } __attribute__ ((packed)); -struct cfparamset { +struct mrvl_ie_cf_param_set { + struct mrvl_ie_header header; u8 cfpcnt; u8 cfpperiod; __le16 cfpmaxduration; __le16 cfpdurationremaining; } __attribute__ ((packed)); -struct ibssparamset { - __le16 atimwindow; -} __attribute__ ((packed)); - -struct mrvlietypes_ssparamset { - struct mrvlietypesheader header; - union { - struct cfparamset cfparamset[1]; - struct ibssparamset ibssparamset[1]; - } cf_ibss; +struct mrvl_ie_ds_param_set { + struct mrvl_ie_header header; + u8 channel; } __attribute__ ((packed)); -struct fhparamset { - __le16 dwelltime; - u8 hopset; - u8 hoppattern; - u8 hopindex; -} __attribute__ ((packed)); - -struct dsparamset { - u8 currentchan; -} __attribute__ ((packed)); - -struct mrvlietypes_phyparamset { - struct mrvlietypesheader header; - union { - struct fhparamset fhparamset[1]; - struct dsparamset dsparamset[1]; - } fh_ds; -} __attribute__ ((packed)); - -struct mrvlietypes_rsnparamset { - struct mrvlietypesheader header; +struct mrvl_ie_rsn_param_set { + struct mrvl_ie_header header; u8 rsnie[1]; } __attribute__ ((packed)); -struct mrvlietypes_tsftimestamp { - struct mrvlietypesheader header; +struct mrvl_ie_tsf_timestamp { + struct mrvl_ie_header header; __le64 tsftable[1]; } __attribute__ ((packed)); +/* v9 and later firmware only */ +struct mrvl_ie_auth_type { + struct mrvl_ie_header header; + __le16 auth; +} __attribute__ ((packed)); + /** Local Power capability */ -struct mrvlietypes_powercapability { - struct mrvlietypesheader header; +struct mrvl_ie_power_capability { + struct mrvl_ie_header header; s8 minpower; s8 maxpower; } __attribute__ ((packed)); /* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */ -struct mrvlietypes_thresholds { - struct mrvlietypesheader header; +struct mrvl_ie_thresholds { + struct mrvl_ie_header header; u8 value; u8 freq; } __attribute__ ((packed)); -struct mrvlietypes_beaconsmissed { - struct mrvlietypesheader header; +struct mrvl_ie_beacons_missed { + struct mrvl_ie_header header; u8 beaconmissed; u8 reserved; } __attribute__ ((packed)); -struct mrvlietypes_numprobes { - struct mrvlietypesheader header; +struct mrvl_ie_num_probes { + struct mrvl_ie_header header; __le16 numprobes; } __attribute__ ((packed)); -struct mrvlietypes_bcastprobe { - struct mrvlietypesheader header; +struct mrvl_ie_bcast_probe { + struct mrvl_ie_header header; __le16 bcastprobe; } __attribute__ ((packed)); -struct mrvlietypes_numssidprobe { - struct mrvlietypesheader header; +struct mrvl_ie_num_ssid_probe { + struct mrvl_ie_header header; __le16 numssidprobe; } __attribute__ ((packed)); @@ -237,8 +217,8 @@ struct led_pin { u8 pin; } __attribute__ ((packed)); -struct mrvlietypes_ledgpio { - struct mrvlietypesheader header; +struct mrvl_ie_ledgpio { + struct mrvl_ie_header header; struct led_pin ledpin[1]; } __attribute__ ((packed)); @@ -250,8 +230,8 @@ struct led_bhv { } __attribute__ ((packed)); -struct mrvlietypes_ledbhv { - struct mrvlietypesheader header; +struct mrvl_ie_ledbhv { + struct mrvl_ie_header header; struct led_bhv ledbhv[1]; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 574b8bb121e1..e789c6e9938c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -280,7 +280,6 @@ struct mac80211_hwsim_data { struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; struct ieee80211_channel *channel; - int radio_enabled; unsigned long beacon_int; /* in jiffies unit */ unsigned int rx_filter; int started; @@ -418,8 +417,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (data == data2) continue; - if (!data2->started || !data2->radio_enabled || - !hwsim_ps_rx_ok(data2, skb) || + if (!data2->started || !hwsim_ps_rx_ok(data2, skb) || data->channel->center_freq != data2->channel->center_freq || !(data->group & data2->group)) continue; @@ -441,7 +439,6 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct mac80211_hwsim_data *data = hw->priv; bool ack; struct ieee80211_tx_info *txi; @@ -453,13 +450,6 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } - if (!data->radio_enabled) { - printk(KERN_DEBUG "%s: dropped TX frame since radio " - "disabled\n", wiphy_name(hw->wiphy)); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - ack = mac80211_hwsim_tx_frame(hw, skb); txi = IEEE80211_SKB_CB(skb); @@ -546,7 +536,7 @@ static void mac80211_hwsim_beacon(unsigned long arg) struct ieee80211_hw *hw = (struct ieee80211_hw *) arg; struct mac80211_hwsim_data *data = hw->priv; - if (!data->started || !data->radio_enabled) + if (!data->started) return; ieee80211_iterate_active_interfaces_atomic( @@ -562,15 +552,14 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) struct mac80211_hwsim_data *data = hw->priv; struct ieee80211_conf *conf = &hw->conf; - printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d idle=%d ps=%d)\n", + printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n", wiphy_name(hw->wiphy), __func__, - conf->channel->center_freq, conf->radio_enabled, + conf->channel->center_freq, !!(conf->flags & IEEE80211_CONF_IDLE), !!(conf->flags & IEEE80211_CONF_PS)); data->channel = conf->channel; - data->radio_enabled = conf->radio_enabled; - if (!data->started || !data->radio_enabled || !data->beacon_int) + if (!data->started || !data->beacon_int) del_timer(&data->beacon_timer); else mod_timer(&data->beacon_timer, jiffies + data->beacon_int); @@ -787,8 +776,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) pspoll->aid = cpu_to_le16(0xc000 | vp->aid); memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); memcpy(pspoll->ta, mac, ETH_ALEN); - if (data->radio_enabled && - !mac80211_hwsim_tx_frame(data->hw, skb)) + if (!mac80211_hwsim_tx_frame(data->hw, skb)) printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); dev_kfree_skb(skb); } @@ -819,8 +807,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, memcpy(hdr->addr1, vp->bssid, ETH_ALEN); memcpy(hdr->addr2, mac, ETH_ALEN); memcpy(hdr->addr3, vp->bssid, ETH_ALEN); - if (data->radio_enabled && - !mac80211_hwsim_tx_frame(data->hw, skb)) + if (!mac80211_hwsim_tx_frame(data->hw, skb)) printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); dev_kfree_skb(skb); } diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 48d81d98e12d..b618bd14583f 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -823,30 +823,30 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_tx_info *range; unsigned long flags; - if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) + if (unlikely(!skb || !dev || skb_queue_empty(&priv->tx_queue))) return; - /* - * don't try to free an already unlinked skb + /* There used to be a check here to see if the SKB was on the + * TX queue or not. This can never happen because all SKBs we + * see here successfully went through p54_assign_address() + * which means the SKB is on the ->tx_queue. */ - if (unlikely((!skb->next) || (!skb->prev))) - return; spin_lock_irqsave(&priv->tx_queue.lock, flags); info = IEEE80211_SKB_CB(skb); range = (void *)info->rate_driver_data; - if (skb->prev != (struct sk_buff *)&priv->tx_queue) { + if (!skb_queue_is_first(&priv->tx_queue, skb)) { struct ieee80211_tx_info *ni; struct p54_tx_info *mr; - ni = IEEE80211_SKB_CB(skb->prev); + ni = IEEE80211_SKB_CB(skb_queue_prev(&priv->tx_queue, skb)); mr = (struct p54_tx_info *)ni->rate_driver_data; } - if (skb->next != (struct sk_buff *)&priv->tx_queue) { + if (!skb_queue_is_last(&priv->tx_queue, skb)) { struct ieee80211_tx_info *ni; struct p54_tx_info *mr; - ni = IEEE80211_SKB_CB(skb->next); + ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, skb)); mr = (struct p54_tx_info *)ni->rate_driver_data; } __skb_unlink(skb, &priv->tx_queue); @@ -864,15 +864,13 @@ static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev, unsigned long flags; spin_lock_irqsave(&priv->tx_queue.lock, flags); - entry = priv->tx_queue.next; - while (entry != (struct sk_buff *)&priv->tx_queue) { + skb_queue_walk(&priv->tx_queue, entry) { struct p54_hdr *hdr = (struct p54_hdr *) entry->data; if (hdr->req_id == req_id) { spin_unlock_irqrestore(&priv->tx_queue.lock, flags); return entry; } - entry = entry->next; } spin_unlock_irqrestore(&priv->tx_queue.lock, flags); return NULL; @@ -890,24 +888,22 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) int count, idx; spin_lock_irqsave(&priv->tx_queue.lock, flags); - entry = (struct sk_buff *) priv->tx_queue.next; - while (entry != (struct sk_buff *)&priv->tx_queue) { + skb_queue_walk(&priv->tx_queue, entry) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); struct p54_hdr *entry_hdr; struct p54_tx_data *entry_data; unsigned int pad = 0, frame_len; range = (void *)info->rate_driver_data; - if (range->start_addr != addr) { - entry = entry->next; + if (range->start_addr != addr) continue; - } - if (entry->next != (struct sk_buff *)&priv->tx_queue) { + if (!skb_queue_is_last(&priv->tx_queue, entry)) { struct ieee80211_tx_info *ni; struct p54_tx_info *mr; - ni = IEEE80211_SKB_CB(entry->next); + ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, + entry)); mr = (struct p54_tx_info *)ni->rate_driver_data; } @@ -1168,23 +1164,21 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, } } - entry = priv->tx_queue.next; - while (left--) { + skb_queue_walk(&priv->tx_queue, entry) { u32 hole_size; info = IEEE80211_SKB_CB(entry); range = (void *)info->rate_driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { - target_skb = entry->prev; + target_skb = skb_queue_prev(&priv->tx_queue, entry); hole_size -= len; target_addr = last_addr; } largest_hole = max(largest_hole, hole_size); last_addr = range->end_addr; - entry = entry->next; } if (!target_skb && priv->rx_end - last_addr >= len) { - target_skb = priv->tx_queue.prev; + target_skb = skb_peek_tail(&priv->tx_queue); largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { info = IEEE80211_SKB_CB(target_skb); @@ -2090,7 +2084,6 @@ out: static void p54_stop(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct sk_buff *skb; mutex_lock(&priv->conf_mutex); priv->mode = NL80211_IFTYPE_UNSPECIFIED; @@ -2105,8 +2098,7 @@ static void p54_stop(struct ieee80211_hw *dev) p54_tx_cancel(dev, priv->cached_beacon); priv->stop(dev); - while ((skb = skb_dequeue(&priv->tx_queue))) - kfree_skb(skb); + skb_queue_purge(&priv->tx_queue); priv->cached_beacon = NULL; priv->tsf_high32 = priv->tsf_low32 = 0; mutex_unlock(&priv->conf_mutex); diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index f40c0f468b27..0e877a104a89 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -84,8 +84,8 @@ MODULE_DEVICE_TABLE(usb, p54u_table); static const struct { u32 intf; enum p54u_hw_type type; - char fw[FIRMWARE_NAME_MAX]; - char fw_legacy[FIRMWARE_NAME_MAX]; + const char *fw; + const char *fw_legacy; char hw[20]; } p54u_fwlist[__NUM_P54U_HWTYPES] = { { diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c254fdf446fd..7441d5585110 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -157,55 +157,55 @@ MODULE_PARM_DESC(workaround_interval, #define NDIS_802_11_LENGTH_RATES_EX 16 enum ndis_80211_net_type { - ndis_80211_type_freq_hop, - ndis_80211_type_direct_seq, - ndis_80211_type_ofdm_a, - ndis_80211_type_ofdm_g + NDIS_80211_TYPE_FREQ_HOP, + NDIS_80211_TYPE_DIRECT_SEQ, + NDIS_80211_TYPE_OFDM_A, + NDIS_80211_TYPE_OFDM_G }; enum ndis_80211_net_infra { - ndis_80211_infra_adhoc, - ndis_80211_infra_infra, - ndis_80211_infra_auto_unknown + NDIS_80211_INFRA_ADHOC, + NDIS_80211_INFRA_INFRA, + NDIS_80211_INFRA_AUTO_UNKNOWN }; enum ndis_80211_auth_mode { - ndis_80211_auth_open, - ndis_80211_auth_shared, - ndis_80211_auth_auto_switch, - ndis_80211_auth_wpa, - ndis_80211_auth_wpa_psk, - ndis_80211_auth_wpa_none, - ndis_80211_auth_wpa2, - ndis_80211_auth_wpa2_psk + NDIS_80211_AUTH_OPEN, + NDIS_80211_AUTH_SHARED, + NDIS_80211_AUTH_AUTO_SWITCH, + NDIS_80211_AUTH_WPA, + NDIS_80211_AUTH_WPA_PSK, + NDIS_80211_AUTH_WPA_NONE, + NDIS_80211_AUTH_WPA2, + NDIS_80211_AUTH_WPA2_PSK }; enum ndis_80211_encr_status { - ndis_80211_encr_wep_enabled, - ndis_80211_encr_disabled, - ndis_80211_encr_wep_key_absent, - ndis_80211_encr_not_supported, - ndis_80211_encr_tkip_enabled, - ndis_80211_encr_tkip_key_absent, - ndis_80211_encr_ccmp_enabled, - ndis_80211_encr_ccmp_key_absent + NDIS_80211_ENCR_WEP_ENABLED, + NDIS_80211_ENCR_DISABLED, + NDIS_80211_ENCR_WEP_KEY_ABSENT, + NDIS_80211_ENCR_NOT_SUPPORTED, + NDIS_80211_ENCR_TKIP_ENABLED, + NDIS_80211_ENCR_TKIP_KEY_ABSENT, + NDIS_80211_ENCR_CCMP_ENABLED, + NDIS_80211_ENCR_CCMP_KEY_ABSENT }; enum ndis_80211_priv_filter { - ndis_80211_priv_accept_all, - ndis_80211_priv_8021x_wep + NDIS_80211_PRIV_ACCEPT_ALL, + NDIS_80211_PRIV_8021X_WEP }; enum ndis_80211_addkey_bits { - ndis_80211_addkey_8021x_auth = cpu_to_le32(1 << 28), - ndis_80211_addkey_set_init_recv_seq = cpu_to_le32(1 << 29), - ndis_80211_addkey_pairwise_key = cpu_to_le32(1 << 30), - ndis_80211_addkey_transmit_key = cpu_to_le32(1 << 31), + NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28), + NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29), + NDIS_80211_ADDKEY_PAIRWISE_KEY = cpu_to_le32(1 << 30), + NDIS_80211_ADDKEY_TRANSMIT_KEY = cpu_to_le32(1 << 31) }; enum ndis_80211_addwep_bits { - ndis_80211_addwep_perclient_key = cpu_to_le32(1 << 30), - ndis_80211_addwep_transmit_key = cpu_to_le32(1 << 31), + NDIS_80211_ADDWEP_PERCLIENT_KEY = cpu_to_le32(1 << 30), + NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31) }; struct ndis_80211_ssid { @@ -361,7 +361,7 @@ static const struct ieee80211_rate rndis_rates[] = { }; /* RNDIS device private data */ -struct rndis_wext_private { +struct rndis_wlan_private { struct usbnet *usbdev; struct wireless_dev wdev; @@ -441,13 +441,13 @@ static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -static struct rndis_wext_private *get_rndis_wext_priv(struct usbnet *dev) +static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev) { - return (struct rndis_wext_private *)dev->driver_priv; + return (struct rndis_wlan_private *)dev->driver_priv; } -static u32 get_bcm4320_power(struct rndis_wext_private *priv) +static u32 get_bcm4320_power(struct rndis_wlan_private *priv) { return BCM4320_DEFAULT_TXPOWER * bcm4320_power_output[priv->param_power_output] / 100; @@ -480,7 +480,7 @@ static int rndis_error_status(__le32 rndis_status) static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) { - struct rndis_wext_private *priv = get_rndis_wext_priv(dev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); union { void *buf; struct rndis_msg_hdr *header; @@ -526,7 +526,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) { - struct rndis_wext_private *priv = get_rndis_wext_priv(dev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); union { void *buf; struct rndis_msg_hdr *header; @@ -747,7 +747,7 @@ static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid)); @@ -794,7 +794,7 @@ static int is_associated(struct usbnet *usbdev) static int disassociate(struct usbnet *usbdev, int reset_ssid) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_ssid ssid; int i, ret = 0; @@ -826,7 +826,7 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid) static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int auth_mode, ret; @@ -835,23 +835,23 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) { if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) - auth_mode = ndis_80211_auth_wpa2; + auth_mode = NDIS_80211_AUTH_WPA2; else - auth_mode = ndis_80211_auth_wpa2_psk; + auth_mode = NDIS_80211_AUTH_WPA2_PSK; } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) { if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X) - auth_mode = ndis_80211_auth_wpa; + auth_mode = NDIS_80211_AUTH_WPA; else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK) - auth_mode = ndis_80211_auth_wpa_psk; + auth_mode = NDIS_80211_AUTH_WPA_PSK; else - auth_mode = ndis_80211_auth_wpa_none; + auth_mode = NDIS_80211_AUTH_WPA_NONE; } else if (authalg & IW_AUTH_ALG_SHARED_KEY) { if (authalg & IW_AUTH_ALG_OPEN_SYSTEM) - auth_mode = ndis_80211_auth_auto_switch; + auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; else - auth_mode = ndis_80211_auth_shared; + auth_mode = NDIS_80211_AUTH_SHARED; } else - auth_mode = ndis_80211_auth_open; + auth_mode = NDIS_80211_AUTH_OPEN; tmp = cpu_to_le32(auth_mode); ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp, @@ -869,16 +869,16 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg) static int set_priv_filter(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version); if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 || priv->wpa_version & IW_AUTH_WPA_VERSION_WPA) - tmp = cpu_to_le32(ndis_80211_priv_8021x_wep); + tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP); else - tmp = cpu_to_le32(ndis_80211_priv_accept_all); + tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL); return rndis_set_oid(usbdev, OID_802_11_PRIVACY_FILTER, &tmp, sizeof(tmp)); @@ -887,7 +887,7 @@ static int set_priv_filter(struct usbnet *usbdev) static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int encr_mode, ret; @@ -896,18 +896,18 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) groupwise); if (pairwise & IW_AUTH_CIPHER_CCMP) - encr_mode = ndis_80211_encr_ccmp_enabled; + encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; else if (pairwise & IW_AUTH_CIPHER_TKIP) - encr_mode = ndis_80211_encr_tkip_enabled; + encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; else if (pairwise & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) - encr_mode = ndis_80211_encr_wep_enabled; + encr_mode = NDIS_80211_ENCR_WEP_ENABLED; else if (groupwise & IW_AUTH_CIPHER_CCMP) - encr_mode = ndis_80211_encr_ccmp_enabled; + encr_mode = NDIS_80211_ENCR_CCMP_ENABLED; else if (groupwise & IW_AUTH_CIPHER_TKIP) - encr_mode = ndis_80211_encr_tkip_enabled; + encr_mode = NDIS_80211_ENCR_TKIP_ENABLED; else - encr_mode = ndis_80211_encr_disabled; + encr_mode = NDIS_80211_ENCR_DISABLED; tmp = cpu_to_le32(encr_mode); ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp, @@ -925,7 +925,7 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) static int set_assoc_params(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); set_auth_mode(usbdev, priv->wpa_version, priv->wpa_authalg); set_priv_filter(usbdev); @@ -937,7 +937,7 @@ static int set_assoc_params(struct usbnet *usbdev) static int set_infra_mode(struct usbnet *usbdev, int mode) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tmp; int ret, i; @@ -970,12 +970,12 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) static void set_default_iw_params(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); priv->wpa_keymgmt = 0; priv->wpa_version = 0; - set_infra_mode(usbdev, ndis_80211_infra_infra); + set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA); set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED, IW_AUTH_ALG_OPEN_SYSTEM); set_priv_filter(usbdev); @@ -996,7 +996,7 @@ static int deauthenticate(struct usbnet *usbdev) /* index must be 0 - N, as per NDIS */ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_wep_key ndis_key; int ret; @@ -1011,7 +1011,7 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) memcpy(&ndis_key.material, key, key_len); if (index == priv->encr_tx_key_index) { - ndis_key.index |= ndis_80211_addwep_transmit_key; + ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY; ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, IW_AUTH_CIPHER_NONE); if (ret) @@ -1039,7 +1039,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, int index, const struct sockaddr *addr, const u8 *rx_seq, int alg, int flags) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_key ndis_key; int ret; @@ -1047,15 +1047,15 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, return -EINVAL; if (key_len > sizeof(ndis_key.material) || key_len < 0) return -EINVAL; - if ((flags & ndis_80211_addkey_set_init_recv_seq) && !rx_seq) + if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq) return -EINVAL; - if ((flags & ndis_80211_addkey_pairwise_key) && !addr) + if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !addr) return -EINVAL; devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index, - !!(flags & ndis_80211_addkey_transmit_key), - !!(flags & ndis_80211_addkey_pairwise_key), - !!(flags & ndis_80211_addkey_set_init_recv_seq)); + !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY), + !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY), + !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ)); memset(&ndis_key, 0, sizeof(ndis_key)); @@ -1073,15 +1073,15 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, } else memcpy(ndis_key.material, key, key_len); - if (flags & ndis_80211_addkey_set_init_recv_seq) + if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) memcpy(ndis_key.rsc, rx_seq, 6); - if (flags & ndis_80211_addkey_pairwise_key) { + if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) { /* pairwise key */ memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN); } else { /* group key */ - if (priv->infra_mode == ndis_80211_infra_adhoc) + if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) memset(ndis_key.bssid, 0xff, ETH_ALEN); else get_bssid(usbdev, ndis_key.bssid); @@ -1096,7 +1096,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, priv->encr_key_len[index] = key_len; priv->encr_key_wpa[index] = 1; - if (flags & ndis_80211_addkey_transmit_key) + if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY) priv->encr_tx_key_index = index; return 0; @@ -1106,7 +1106,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, /* remove_key is for both wep and wpa */ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ndis_80211_remove_key remove_key; __le32 keyindex; int ret; @@ -1128,7 +1128,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) /* pairwise key */ if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0) remove_key.index |= - ndis_80211_addkey_pairwise_key; + NDIS_80211_ADDKEY_PAIRWISE_KEY; memcpy(remove_key.bssid, bssid, sizeof(remove_key.bssid)); } else @@ -1161,7 +1161,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) static void set_multicast_list(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct dev_mc_list *mclist; __le32 filter; int ret, i, size; @@ -1238,10 +1238,10 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex, switch (type) { case NL80211_IFTYPE_ADHOC: - mode = ndis_80211_infra_adhoc; + mode = NDIS_80211_INFRA_ADHOC; break; case NL80211_IFTYPE_STATION: - mode = ndis_80211_infra_infra; + mode = NDIS_80211_INFRA_INFRA; break; default: return -EINVAL; @@ -1256,7 +1256,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; __le32 tmp; @@ -1286,7 +1286,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, struct ndis_80211_bssid_ex *bssid) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct ieee80211_channel *channel; s32 signal; u64 timestamp; @@ -1371,8 +1371,8 @@ out: static void rndis_get_scan_results(struct work_struct *work) { - struct rndis_wext_private *priv = - container_of(work, struct rndis_wext_private, scan_work.work); + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, scan_work.work); struct usbnet *usbdev = priv->usbdev; int ret; @@ -1497,7 +1497,7 @@ static int rndis_iw_set_auth(struct net_device *dev, { struct iw_param *p = &wrqu->param; struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret = -ENOTSUPP; switch (p->flags & IW_AUTH_INDEX) { @@ -1578,7 +1578,7 @@ static int rndis_iw_get_auth(struct net_device *dev, { struct iw_param *p = &wrqu->param; struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); switch (p->flags & IW_AUTH_INDEX) { case IW_AUTH_WPA_VERSION: @@ -1609,7 +1609,7 @@ static int rndis_iw_set_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret, index, key_len; u8 *key; @@ -1672,7 +1672,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, { struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int keyidx, flags; keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; @@ -1698,11 +1698,11 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, flags = 0; if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) - flags |= ndis_80211_addkey_set_init_recv_seq; + flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ; if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)) - flags |= ndis_80211_addkey_pairwise_key; + flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY; if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - flags |= ndis_80211_addkey_transmit_key; + flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY; return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr, ext->rx_seq, ext->alg, flags); @@ -1713,7 +1713,7 @@ static int rndis_iw_set_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret = 0; #ifdef DEBUG @@ -1747,7 +1747,7 @@ static int rndis_iw_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); devdbg(usbdev, "SIOCGIWGENIE"); @@ -1886,7 +1886,7 @@ static int rndis_iw_get_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tx_power; if (priv->radio_on) { @@ -1912,7 +1912,7 @@ static int rndis_iw_set_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); __le32 tx_power = 0; if (!wrqu->txpower.disabled) { @@ -1969,7 +1969,7 @@ static int rndis_iw_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct iw_mlme *mlme = (struct iw_mlme *)extra; unsigned char bssid[ETH_ALEN]; @@ -1994,7 +1994,7 @@ static int rndis_iw_set_mlme(struct net_device *dev, static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); unsigned long flags; spin_lock_irqsave(&priv->stats_lock, flags); @@ -2037,28 +2037,28 @@ static const iw_handler rndis_iw_handler[] = IW_IOCTL(SIOCSIWMLME) = rndis_iw_set_mlme, }; -static const iw_handler rndis_wext_private_handler[] = { +static const iw_handler rndis_wlan_private_handler[] = { }; -static const struct iw_priv_args rndis_wext_private_args[] = { +static const struct iw_priv_args rndis_wlan_private_args[] = { }; static const struct iw_handler_def rndis_iw_handlers = { .num_standard = ARRAY_SIZE(rndis_iw_handler), - .num_private = ARRAY_SIZE(rndis_wext_private_handler), - .num_private_args = ARRAY_SIZE(rndis_wext_private_args), + .num_private = ARRAY_SIZE(rndis_wlan_private_handler), + .num_private_args = ARRAY_SIZE(rndis_wlan_private_args), .standard = (iw_handler *)rndis_iw_handler, - .private = (iw_handler *)rndis_wext_private_handler, - .private_args = (struct iw_priv_args *)rndis_wext_private_args, + .private = (iw_handler *)rndis_wlan_private_handler, + .private_args = (struct iw_priv_args *)rndis_wlan_private_args, .get_wireless_stats = rndis_get_wireless_stats, }; -static void rndis_wext_worker(struct work_struct *work) +static void rndis_wlan_worker(struct work_struct *work) { - struct rndis_wext_private *priv = - container_of(work, struct rndis_wext_private, work); + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, work); struct usbnet *usbdev = priv->usbdev; union iwreq_data evt; unsigned char bssid[ETH_ALEN]; @@ -2119,10 +2119,10 @@ get_bssid: set_multicast_list(usbdev); } -static void rndis_wext_set_multicast_list(struct net_device *dev) +static void rndis_wlan_set_multicast_list(struct net_device *dev) { struct usbnet *usbdev = netdev_priv(dev); - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) return; @@ -2131,9 +2131,9 @@ static void rndis_wext_set_multicast_list(struct net_device *dev) queue_work(priv->workqueue, &priv->work); } -static void rndis_wext_link_change(struct usbnet *usbdev, int state) +static void rndis_wlan_link_change(struct usbnet *usbdev, int state) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* queue work to avoid recursive calls into rndis_command */ set_bit(state ? WORK_LINK_UP : WORK_LINK_DOWN, &priv->work_pending); @@ -2141,14 +2141,14 @@ static void rndis_wext_link_change(struct usbnet *usbdev, int state) } -static int rndis_wext_get_caps(struct usbnet *usbdev) +static int rndis_wlan_get_caps(struct usbnet *usbdev) { struct { __le32 num_items; __le32 items[8]; } networks_supported; int len, retval, i, n; - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* determine supported modes */ len = sizeof(networks_supported); @@ -2160,14 +2160,14 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) n = 8; for (i = 0; i < n; i++) { switch (le32_to_cpu(networks_supported.items[i])) { - case ndis_80211_type_freq_hop: - case ndis_80211_type_direct_seq: + case NDIS_80211_TYPE_FREQ_HOP: + case NDIS_80211_TYPE_DIRECT_SEQ: priv->caps |= CAP_MODE_80211B; break; - case ndis_80211_type_ofdm_a: + case NDIS_80211_TYPE_OFDM_A: priv->caps |= CAP_MODE_80211A; break; - case ndis_80211_type_ofdm_g: + case NDIS_80211_TYPE_OFDM_G: priv->caps |= CAP_MODE_80211G; break; } @@ -2181,8 +2181,8 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) #define STATS_UPDATE_JIFFIES (HZ) static void rndis_update_wireless_stats(struct work_struct *work) { - struct rndis_wext_private *priv = - container_of(work, struct rndis_wext_private, stats_work.work); + struct rndis_wlan_private *priv = + container_of(work, struct rndis_wlan_private, stats_work.work); struct usbnet *usbdev = priv->usbdev; struct iw_statistics iwstats; __le32 rssi, tmp; @@ -2297,7 +2297,7 @@ static int bcm4320a_early_init(struct usbnet *usbdev) static int bcm4320b_early_init(struct usbnet *usbdev) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); char buf[8]; /* Early initialization settings, setting these won't have effect @@ -2363,21 +2363,21 @@ static int bcm4320b_early_init(struct usbnet *usbdev) } /* same as rndis_netdev_ops but with local multicast handler */ -static const struct net_device_ops rndis_wext_netdev_ops = { +static const struct net_device_ops rndis_wlan_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop, .ndo_start_xmit = usbnet_start_xmit, .ndo_tx_timeout = usbnet_tx_timeout, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = rndis_wext_set_multicast_list, + .ndo_set_multicast_list = rndis_wlan_set_multicast_list, }; -static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) +static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) { struct wiphy *wiphy; - struct rndis_wext_private *priv; + struct rndis_wlan_private *priv; int retval, len; __le32 tmp; @@ -2385,7 +2385,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) * NOTE: We only support a single virtual interface, so wiphy * and wireless_dev are somewhat synonymous for this device. */ - wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wext_private)); + wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wlan_private)); if (!wiphy) return -ENOMEM; @@ -2395,7 +2395,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) priv->wdev.iftype = NL80211_IFTYPE_STATION; /* These have to be initialized before calling generic_rndis_bind(). - * Otherwise we'll be in big trouble in rndis_wext_early_init(). + * Otherwise we'll be in big trouble in rndis_wlan_early_init(). */ usbdev->driver_priv = priv; usbdev->net->wireless_handlers = &rndis_iw_handlers; @@ -2406,7 +2406,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); - INIT_WORK(&priv->work, rndis_wext_worker); + INIT_WORK(&priv->work, rndis_wlan_worker); INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats); INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); @@ -2420,9 +2420,9 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) * picks up rssi to closest station instead of to access point). * * rndis_host wants to avoid all OID as much as possible - * so do promisc/multicast handling in rndis_wext. + * so do promisc/multicast handling in rndis_wlan. */ - usbdev->net->netdev_ops = &rndis_wext_netdev_ops; + usbdev->net->netdev_ops = &rndis_wlan_netdev_ops; tmp = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST; retval = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &tmp, @@ -2455,7 +2455,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf) wiphy->max_scan_ssids = 1; /* TODO: fill-out band information based on priv->caps */ - rndis_wext_get_caps(usbdev); + rndis_wlan_get_caps(usbdev); memcpy(priv->channels, rndis_channels, sizeof(rndis_channels)); memcpy(priv->rates, rndis_rates, sizeof(rndis_rates)); @@ -2497,9 +2497,9 @@ fail: } -static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf) +static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf) { - struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); /* turn radio off */ disassociate(usbdev, 0); @@ -2520,7 +2520,7 @@ static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf) } -static int rndis_wext_reset(struct usbnet *usbdev) +static int rndis_wlan_reset(struct usbnet *usbdev) { return deauthenticate(usbdev); } @@ -2529,40 +2529,40 @@ static int rndis_wext_reset(struct usbnet *usbdev) static const struct driver_info bcm4320b_info = { .description = "Wireless RNDIS device, BCM4320b based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_wext_bind, - .unbind = rndis_wext_unbind, + .bind = rndis_wlan_bind, + .unbind = rndis_wlan_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, - .reset = rndis_wext_reset, + .reset = rndis_wlan_reset, .early_init = bcm4320b_early_init, - .link_change = rndis_wext_link_change, + .link_change = rndis_wlan_link_change, }; static const struct driver_info bcm4320a_info = { .description = "Wireless RNDIS device, BCM4320a based", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_wext_bind, - .unbind = rndis_wext_unbind, + .bind = rndis_wlan_bind, + .unbind = rndis_wlan_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, - .reset = rndis_wext_reset, + .reset = rndis_wlan_reset, .early_init = bcm4320a_early_init, - .link_change = rndis_wext_link_change, + .link_change = rndis_wlan_link_change, }; -static const struct driver_info rndis_wext_info = { +static const struct driver_info rndis_wlan_info = { .description = "Wireless RNDIS device", .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .bind = rndis_wext_bind, - .unbind = rndis_wext_unbind, + .bind = rndis_wlan_bind, + .unbind = rndis_wlan_unbind, .status = rndis_status, .rx_fixup = rndis_rx_fixup, .tx_fixup = rndis_tx_fixup, - .reset = rndis_wext_reset, + .reset = rndis_wlan_reset, .early_init = bcm4320a_early_init, - .link_change = rndis_wext_link_change, + .link_change = rndis_wlan_link_change, }; /*-------------------------------------------------------------------------*/ @@ -2672,11 +2672,11 @@ static const struct usb_device_id products [] = { { /* RNDIS is MSFT's un-official variant of CDC ACM */ USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), - .driver_info = (unsigned long) &rndis_wext_info, + .driver_info = (unsigned long) &rndis_wlan_info, }, { /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), - .driver_info = (unsigned long) &rndis_wext_info, + .driver_info = (unsigned long) &rndis_wlan_info, }, { }, // END }; diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 0197531bd88c..435f945fe64d 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -520,7 +520,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2x00pci_register_read(rt2x00dev, CSR20, ®); rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, - (libconf->conf->beacon_int - 20) * 16); + (rt2x00dev->beacon_int - 20) * 16); rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index f95cb646f85a..08b30d01e67d 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -569,7 +569,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2x00pci_register_read(rt2x00dev, CSR20, ®); rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, - (libconf->conf->beacon_int - 20) * 16); + (rt2x00dev->beacon_int - 20) * 16); rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 69f966f1ce54..66daf68ff0ee 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -647,7 +647,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON, - libconf->conf->beacon_int - 20); + rt2x00dev->beacon_int - 20); rt2x00_set_field16(®, MAC_CSR18_BEACONS_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 142ad34fdc49..37561667925b 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2927,12 +2927,17 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Edimax */ { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Encore */ + { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) }, /* EnGenius */ { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -2951,6 +2956,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* I-O DATA */ + { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, /* LevelOne */ { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -2970,6 +2977,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Pegatron */ { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Philips */ { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Planex */ @@ -2981,6 +2989,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Quanta */ { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Ralink */ + { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -3005,6 +3014,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, /* SMC */ { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -3029,6 +3039,8 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Zinwell */ { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zyxel */ { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 2b64a6198698..a498dde024e1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -802,6 +802,11 @@ struct rt2x00_dev { u8 calibration[2]; /* + * Beacon interval. + */ + u16 beacon_int; + + /* * Low level statistics which will have * to be kept up to date while device is running. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index c5bbf0b6e207..3e019a12df2e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -108,6 +108,9 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.basic_rates = bss_conf->basic_rates; erp.beacon_int = bss_conf->beacon_int; + /* Update global beacon interval time, this is needed for PS support */ + rt2x00dev->beacon_int = bss_conf->beacon_int; + rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index a8bf5c432858..49b29ff90c47 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -956,7 +956,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2x00pci_register_read(rt2x00dev, MAC_CSR11, ®); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, - libconf->conf->beacon_int - 10); + rt2x00dev->beacon_int - 10); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 211a3d6bc054..c18848836f2d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -852,7 +852,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2x00usb_register_read(rt2x00dev, MAC_CSR11, ®); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, - libconf->conf->beacon_int - 10); + rt2x00dev->beacon_int - 10); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, libconf->conf->listen_interval - 1); rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5); diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 6499ccc34c94..294250e294dd 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -74,6 +74,8 @@ static struct usb_device_id rtl8187_table[] __devinitdata = { {USB_DEVICE(0x18E8, 0x6232), .driver_info = DEVICE_RTL8187}, /* AirLive */ {USB_DEVICE(0x1b75, 0x8187), .driver_info = DEVICE_RTL8187}, + /* Linksys */ + {USB_DEVICE(0x1737, 0x0073), .driver_info = DEVICE_RTL8187B}, {} }; @@ -321,12 +323,7 @@ static void rtl8187_rx_cb(struct urb *urb) unsigned long f; spin_lock_irqsave(&priv->rx_queue.lock, f); - if (skb->next) - __skb_unlink(skb, &priv->rx_queue); - else { - spin_unlock_irqrestore(&priv->rx_queue.lock, f); - return; - } + __skb_unlink(skb, &priv->rx_queue); spin_unlock_irqrestore(&priv->rx_queue.lock, f); skb_put(skb, urb->actual_length); diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 3ab3eb957189..25d27b64f528 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -2869,10 +2869,6 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) if (lp->tx_n_in_use == (NTXBLOCKS - 1)) return 1; } -#ifdef DEBUG_TX_ERROR - if (skb->next) - printk(KERN_INFO "skb has next\n"); -#endif /* Do we need some padding? */ /* Note : on wireless the propagation time is in the order of 1us, diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index e55b33961aeb..1a90d69f18a9 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3107,11 +3107,6 @@ wavelan_packet_xmit(struct sk_buff * skb, * so the Tx buffer is now free */ } -#ifdef DEBUG_TX_ERROR - if (skb->next) - printk(KERN_INFO "skb has next\n"); -#endif - /* Check if we need some padding */ /* Note : on wireless the propagation time is in the order of 1us, * and we don't have the Ethernet specific requirement of beeing diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 7477ffdcddb4..3c7a5053f1da 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -717,7 +717,7 @@ static void yellowfin_tx_timeout(struct net_device *dev) if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE) netif_wake_queue (dev); /* Typical path */ - dev->trans_start = jiffies; + dev->trans_start = jiffies; /* prevent tx timeout */ dev->stats.tx_errors++; } @@ -876,7 +876,6 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_start_queue (dev); /* Typical path */ else yp->tx_full = 1; - dev->trans_start = jiffies; if (yellowfin_debug > 4) { printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n", diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 284ebaca6e45..c682ac536415 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -21,7 +21,7 @@ config ACER_WMI depends on NEW_LEDS depends on BACKLIGHT_CLASS_DEVICE depends on SERIO_I8042 - depends on RFKILL + depends on RFKILL || RFKILL = n select ACPI_WMI ---help--- This is a driver for newer Acer (and Wistron) laptops. It adds @@ -60,7 +60,7 @@ config DELL_LAPTOP depends on DCDBAS depends on EXPERIMENTAL depends on BACKLIGHT_CLASS_DEVICE - depends on RFKILL + depends on RFKILL || RFKILL = n depends on POWER_SUPPLY default n ---help--- @@ -117,7 +117,7 @@ config HP_WMI tristate "HP WMI extras" depends on ACPI_WMI depends on INPUT - depends on RFKILL + depends on RFKILL || RFKILL = n help Say Y here if you want to support WMI-based hotkeys on HP laptops and to read data from WMI such as docking or ambient light sensor state. @@ -196,14 +196,13 @@ config THINKPAD_ACPI tristate "ThinkPad ACPI Laptop Extras" depends on ACPI depends on INPUT + depends on RFKILL || RFKILL = n select BACKLIGHT_LCD_SUPPORT select BACKLIGHT_CLASS_DEVICE select HWMON select NVRAM select NEW_LEDS select LEDS_CLASS - select NET - select RFKILL ---help--- This is a driver for the IBM and Lenovo ThinkPad laptops. It adds support for Fn-Fx key combinations, Bluetooth control, video @@ -338,9 +337,9 @@ config EEEPC_LAPTOP depends on ACPI depends on INPUT depends on EXPERIMENTAL + depends on RFKILL || RFKILL = n select BACKLIGHT_CLASS_DEVICE select HWMON - select RFKILL ---help--- This driver supports the Fn-Fx keys on Eee PC laptops. It also adds the ability to switch camera/wlan on/off. @@ -405,9 +404,8 @@ config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on ACPI depends on INPUT + depends on RFKILL || RFKILL = n select INPUT_POLLDEV - select NET - select RFKILL select BACKLIGHT_CLASS_DEVICE ---help--- This driver adds support for access to certain system settings diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 62d02b3c998e..09a503e5da6a 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -958,58 +958,47 @@ static void acer_rfkill_update(struct work_struct *ignored) status = get_u32(&state, ACER_CAP_WIRELESS); if (ACPI_SUCCESS(status)) - rfkill_force_state(wireless_rfkill, state ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED); + rfkill_set_sw_state(wireless_rfkill, !!state); if (has_cap(ACER_CAP_BLUETOOTH)) { status = get_u32(&state, ACER_CAP_BLUETOOTH); if (ACPI_SUCCESS(status)) - rfkill_force_state(bluetooth_rfkill, state ? - RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED); + rfkill_set_sw_state(bluetooth_rfkill, !!state); } schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); } -static int acer_rfkill_set(void *data, enum rfkill_state state) +static int acer_rfkill_set(void *data, bool blocked) { acpi_status status; - u32 *cap = data; - status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap); + u32 cap = (unsigned long)data; + status = set_u32(!!blocked, cap); if (ACPI_FAILURE(status)) return -ENODEV; return 0; } -static struct rfkill * acer_rfkill_register(struct device *dev, -enum rfkill_type type, char *name, u32 cap) +static const struct rfkill_ops acer_rfkill_ops = { + .set_block = acer_rfkill_set, +}; + +static struct rfkill *acer_rfkill_register(struct device *dev, + enum rfkill_type type, + char *name, u32 cap) { int err; - u32 state; - u32 *data; struct rfkill *rfkill_dev; - rfkill_dev = rfkill_allocate(dev, type); + rfkill_dev = rfkill_alloc(name, dev, type, + &acer_rfkill_ops, + (void *)(unsigned long)cap); if (!rfkill_dev) return ERR_PTR(-ENOMEM); - rfkill_dev->name = name; - get_u32(&state, cap); - rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED; - data = kzalloc(sizeof(u32), GFP_KERNEL); - if (!data) { - rfkill_free(rfkill_dev); - return ERR_PTR(-ENOMEM); - } - *data = cap; - rfkill_dev->data = data; - rfkill_dev->toggle_radio = acer_rfkill_set; err = rfkill_register(rfkill_dev); if (err) { - kfree(rfkill_dev->data); - rfkill_free(rfkill_dev); + rfkill_destroy(rfkill_dev); return ERR_PTR(err); } return rfkill_dev; @@ -1027,8 +1016,8 @@ static int acer_rfkill_init(struct device *dev) RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", ACER_CAP_BLUETOOTH); if (IS_ERR(bluetooth_rfkill)) { - kfree(wireless_rfkill->data); rfkill_unregister(wireless_rfkill); + rfkill_destroy(wireless_rfkill); return PTR_ERR(bluetooth_rfkill); } } @@ -1041,11 +1030,13 @@ static int acer_rfkill_init(struct device *dev) static void acer_rfkill_exit(void) { cancel_delayed_work_sync(&acer_rfkill_work); - kfree(wireless_rfkill->data); + rfkill_unregister(wireless_rfkill); + rfkill_destroy(wireless_rfkill); + if (has_cap(ACER_CAP_BLUETOOTH)) { - kfree(bluetooth_rfkill->data); rfkill_unregister(bluetooth_rfkill); + rfkill_destroy(bluetooth_rfkill); } return; } diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index af9f43021172..2faf0e14f05a 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -174,10 +174,11 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, result[3]: NVRAM format version number */ -static int dell_rfkill_set(int radio, enum rfkill_state state) +static int dell_rfkill_set(void *data, bool blocked) { struct calling_interface_buffer buffer; - int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1; + int disable = blocked ? 0 : 1; + unsigned long radio = (unsigned long)data; memset(&buffer, 0, sizeof(struct calling_interface_buffer)); buffer.input[0] = (1 | (radio<<8) | (disable << 16)); @@ -186,56 +187,24 @@ static int dell_rfkill_set(int radio, enum rfkill_state state) return 0; } -static int dell_wifi_set(void *data, enum rfkill_state state) -{ - return dell_rfkill_set(1, state); -} - -static int dell_bluetooth_set(void *data, enum rfkill_state state) -{ - return dell_rfkill_set(2, state); -} - -static int dell_wwan_set(void *data, enum rfkill_state state) -{ - return dell_rfkill_set(3, state); -} - -static int dell_rfkill_get(int bit, enum rfkill_state *state) +static void dell_rfkill_query(struct rfkill *rfkill, void *data) { struct calling_interface_buffer buffer; int status; - int new_state = RFKILL_STATE_HARD_BLOCKED; + int bit = (unsigned long)data + 16; memset(&buffer, 0, sizeof(struct calling_interface_buffer)); dell_send_request(&buffer, 17, 11); status = buffer.output[1]; - if (status & (1<<16)) - new_state = RFKILL_STATE_SOFT_BLOCKED; - - if (status & (1<<bit)) - *state = new_state; - else - *state = RFKILL_STATE_UNBLOCKED; - - return 0; -} - -static int dell_wifi_get(void *data, enum rfkill_state *state) -{ - return dell_rfkill_get(17, state); -} - -static int dell_bluetooth_get(void *data, enum rfkill_state *state) -{ - return dell_rfkill_get(18, state); + if (status & BIT(bit)) + rfkill_set_hw_state(rfkill, !!(status & BIT(16))); } -static int dell_wwan_get(void *data, enum rfkill_state *state) -{ - return dell_rfkill_get(19, state); -} +static const struct rfkill_ops dell_rfkill_ops = { + .set_block = dell_rfkill_set, + .query = dell_rfkill_query, +}; static int dell_setup_rfkill(void) { @@ -248,36 +217,37 @@ static int dell_setup_rfkill(void) status = buffer.output[1]; if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { - wifi_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WLAN); - if (!wifi_rfkill) + wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN, + &dell_rfkill_ops, (void *) 1); + if (!wifi_rfkill) { + ret = -ENOMEM; goto err_wifi; - wifi_rfkill->name = "dell-wifi"; - wifi_rfkill->toggle_radio = dell_wifi_set; - wifi_rfkill->get_state = dell_wifi_get; + } ret = rfkill_register(wifi_rfkill); if (ret) goto err_wifi; } if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { - bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH); - if (!bluetooth_rfkill) + bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL, + RFKILL_TYPE_BLUETOOTH, + &dell_rfkill_ops, (void *) 2); + if (!bluetooth_rfkill) { + ret = -ENOMEM; goto err_bluetooth; - bluetooth_rfkill->name = "dell-bluetooth"; - bluetooth_rfkill->toggle_radio = dell_bluetooth_set; - bluetooth_rfkill->get_state = dell_bluetooth_get; + } ret = rfkill_register(bluetooth_rfkill); if (ret) goto err_bluetooth; } if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { - wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN); - if (!wwan_rfkill) + wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN, + &dell_rfkill_ops, (void *) 3); + if (!wwan_rfkill) { + ret = -ENOMEM; goto err_wwan; - wwan_rfkill->name = "dell-wwan"; - wwan_rfkill->toggle_radio = dell_wwan_set; - wwan_rfkill->get_state = dell_wwan_get; + } ret = rfkill_register(wwan_rfkill); if (ret) goto err_wwan; @@ -285,22 +255,15 @@ static int dell_setup_rfkill(void) return 0; err_wwan: - if (wwan_rfkill) - rfkill_free(wwan_rfkill); - if (bluetooth_rfkill) { + rfkill_destroy(wwan_rfkill); + if (bluetooth_rfkill) rfkill_unregister(bluetooth_rfkill); - bluetooth_rfkill = NULL; - } err_bluetooth: - if (bluetooth_rfkill) - rfkill_free(bluetooth_rfkill); - if (wifi_rfkill) { + rfkill_destroy(bluetooth_rfkill); + if (wifi_rfkill) rfkill_unregister(wifi_rfkill); - wifi_rfkill = NULL; - } err_wifi: - if (wifi_rfkill) - rfkill_free(wifi_rfkill); + rfkill_destroy(wifi_rfkill); return ret; } diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 353a898c3693..03bf522bd7ab 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -299,39 +299,22 @@ static int update_bl_status(struct backlight_device *bd) * Rfkill helpers */ -static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state) -{ - if (state == RFKILL_STATE_SOFT_BLOCKED) - return set_acpi(CM_ASL_WLAN, 0); - else - return set_acpi(CM_ASL_WLAN, 1); -} - -static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state) +static bool eeepc_wlan_rfkill_blocked(void) { if (get_acpi(CM_ASL_WLAN) == 1) - *state = RFKILL_STATE_UNBLOCKED; - else - *state = RFKILL_STATE_SOFT_BLOCKED; - return 0; + return false; + return true; } -static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state) +static int eeepc_rfkill_set(void *data, bool blocked) { - if (state == RFKILL_STATE_SOFT_BLOCKED) - return set_acpi(CM_ASL_BLUETOOTH, 0); - else - return set_acpi(CM_ASL_BLUETOOTH, 1); + unsigned long asl = (unsigned long)data; + return set_acpi(asl, !blocked); } -static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state) -{ - if (get_acpi(CM_ASL_BLUETOOTH) == 1) - *state = RFKILL_STATE_UNBLOCKED; - else - *state = RFKILL_STATE_SOFT_BLOCKED; - return 0; -} +static const struct rfkill_ops eeepc_rfkill_ops = { + .set_block = eeepc_rfkill_set, +}; /* * Sys helpers @@ -531,9 +514,9 @@ static int notify_brn(void) static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) { - enum rfkill_state state; struct pci_dev *dev; struct pci_bus *bus = pci_find_bus(0, 1); + bool blocked; if (event != ACPI_NOTIFY_BUS_CHECK) return; @@ -543,9 +526,8 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) return; } - eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state); - - if (state == RFKILL_STATE_UNBLOCKED) { + blocked = eeepc_wlan_rfkill_blocked(); + if (!blocked) { dev = pci_get_slot(bus, 0); if (dev) { /* Device already present */ @@ -566,7 +548,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) } } - rfkill_force_state(ehotk->eeepc_wlan_rfkill, state); + rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked); } static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) @@ -684,26 +666,17 @@ static int eeepc_hotk_add(struct acpi_device *device) eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); if (get_acpi(CM_ASL_WLAN) != -1) { - ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev, - RFKILL_TYPE_WLAN); + ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan", + &device->dev, + RFKILL_TYPE_WLAN, + &eeepc_rfkill_ops, + (void *)CM_ASL_WLAN); if (!ehotk->eeepc_wlan_rfkill) goto wlan_fail; - ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan"; - ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set; - ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state; - if (get_acpi(CM_ASL_WLAN) == 1) { - ehotk->eeepc_wlan_rfkill->state = - RFKILL_STATE_UNBLOCKED; - rfkill_set_default(RFKILL_TYPE_WLAN, - RFKILL_STATE_UNBLOCKED); - } else { - ehotk->eeepc_wlan_rfkill->state = - RFKILL_STATE_SOFT_BLOCKED; - rfkill_set_default(RFKILL_TYPE_WLAN, - RFKILL_STATE_SOFT_BLOCKED); - } + rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, + get_acpi(CM_ASL_WLAN) != 1); result = rfkill_register(ehotk->eeepc_wlan_rfkill); if (result) goto wlan_fail; @@ -711,28 +684,17 @@ static int eeepc_hotk_add(struct acpi_device *device) if (get_acpi(CM_ASL_BLUETOOTH) != -1) { ehotk->eeepc_bluetooth_rfkill = - rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH); + rfkill_alloc("eeepc-bluetooth", + &device->dev, + RFKILL_TYPE_BLUETOOTH, + &eeepc_rfkill_ops, + (void *)CM_ASL_BLUETOOTH); if (!ehotk->eeepc_bluetooth_rfkill) goto bluetooth_fail; - ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth"; - ehotk->eeepc_bluetooth_rfkill->toggle_radio = - eeepc_bluetooth_rfkill_set; - ehotk->eeepc_bluetooth_rfkill->get_state = - eeepc_bluetooth_rfkill_state; - if (get_acpi(CM_ASL_BLUETOOTH) == 1) { - ehotk->eeepc_bluetooth_rfkill->state = - RFKILL_STATE_UNBLOCKED; - rfkill_set_default(RFKILL_TYPE_BLUETOOTH, - RFKILL_STATE_UNBLOCKED); - } else { - ehotk->eeepc_bluetooth_rfkill->state = - RFKILL_STATE_SOFT_BLOCKED; - rfkill_set_default(RFKILL_TYPE_BLUETOOTH, - RFKILL_STATE_SOFT_BLOCKED); - } - + rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill, + get_acpi(CM_ASL_BLUETOOTH) != 1); result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); if (result) goto bluetooth_fail; @@ -741,13 +703,10 @@ static int eeepc_hotk_add(struct acpi_device *device) return 0; bluetooth_fail: - if (ehotk->eeepc_bluetooth_rfkill) - rfkill_free(ehotk->eeepc_bluetooth_rfkill); + rfkill_destroy(ehotk->eeepc_bluetooth_rfkill); rfkill_unregister(ehotk->eeepc_wlan_rfkill); - ehotk->eeepc_wlan_rfkill = NULL; wlan_fail: - if (ehotk->eeepc_wlan_rfkill) - rfkill_free(ehotk->eeepc_wlan_rfkill); + rfkill_destroy(ehotk->eeepc_wlan_rfkill); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); ehotk_fail: diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index fe171fad12cf..16fffe44e333 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -154,58 +154,46 @@ static int hp_wmi_dock_state(void) return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0); } -static int hp_wmi_wifi_set(void *data, enum rfkill_state state) +static int hp_wmi_set_block(void *data, bool blocked) { - if (state) - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101); - else - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100); -} + unsigned long b = (unsigned long) data; + int query = BIT(b + 8) | ((!!blocked) << b); -static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state) -{ - if (state) - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202); - else - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200); + return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); } -static int hp_wmi_wwan_set(void *data, enum rfkill_state state) -{ - if (state) - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404); - else - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400); -} +static const struct rfkill_ops hp_wmi_rfkill_ops = { + .set_block = hp_wmi_set_block, +}; -static int hp_wmi_wifi_state(void) +static bool hp_wmi_wifi_state(void) { int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); if (wireless & 0x100) - return RFKILL_STATE_UNBLOCKED; + return false; else - return RFKILL_STATE_SOFT_BLOCKED; + return true; } -static int hp_wmi_bluetooth_state(void) +static bool hp_wmi_bluetooth_state(void) { int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); if (wireless & 0x10000) - return RFKILL_STATE_UNBLOCKED; + return false; else - return RFKILL_STATE_SOFT_BLOCKED; + return true; } -static int hp_wmi_wwan_state(void) +static bool hp_wmi_wwan_state(void) { int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); if (wireless & 0x1000000) - return RFKILL_STATE_UNBLOCKED; + return false; else - return RFKILL_STATE_SOFT_BLOCKED; + return true; } static ssize_t show_display(struct device *dev, struct device_attribute *attr, @@ -347,14 +335,14 @@ static void hp_wmi_notify(u32 value, void *context) } } else if (eventcode == 0x5) { if (wifi_rfkill) - rfkill_force_state(wifi_rfkill, - hp_wmi_wifi_state()); + rfkill_set_sw_state(wifi_rfkill, + hp_wmi_wifi_state()); if (bluetooth_rfkill) - rfkill_force_state(bluetooth_rfkill, - hp_wmi_bluetooth_state()); + rfkill_set_sw_state(bluetooth_rfkill, + hp_wmi_bluetooth_state()); if (wwan_rfkill) - rfkill_force_state(wwan_rfkill, - hp_wmi_wwan_state()); + rfkill_set_sw_state(wwan_rfkill, + hp_wmi_wwan_state()); } else printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", eventcode); @@ -430,31 +418,30 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) goto add_sysfs_error; if (wireless & 0x1) { - wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); - wifi_rfkill->name = "hp-wifi"; - wifi_rfkill->state = hp_wmi_wifi_state(); - wifi_rfkill->toggle_radio = hp_wmi_wifi_set; + wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, + RFKILL_TYPE_WLAN, + &hp_wmi_rfkill_ops, + (void *) 0); err = rfkill_register(wifi_rfkill); if (err) - goto add_sysfs_error; + goto register_wifi_error; } if (wireless & 0x2) { - bluetooth_rfkill = rfkill_allocate(&device->dev, - RFKILL_TYPE_BLUETOOTH); - bluetooth_rfkill->name = "hp-bluetooth"; - bluetooth_rfkill->state = hp_wmi_bluetooth_state(); - bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set; + bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, + RFKILL_TYPE_BLUETOOTH, + &hp_wmi_rfkill_ops, + (void *) 1); err = rfkill_register(bluetooth_rfkill); if (err) goto register_bluetooth_error; } if (wireless & 0x4) { - wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); - wwan_rfkill->name = "hp-wwan"; - wwan_rfkill->state = hp_wmi_wwan_state(); - wwan_rfkill->toggle_radio = hp_wmi_wwan_set; + wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, + RFKILL_TYPE_WWAN, + &hp_wmi_rfkill_ops, + (void *) 2); err = rfkill_register(wwan_rfkill); if (err) goto register_wwan_err; @@ -462,11 +449,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) return 0; register_wwan_err: + rfkill_destroy(wwan_rfkill); if (bluetooth_rfkill) rfkill_unregister(bluetooth_rfkill); register_bluetooth_error: + rfkill_destroy(bluetooth_rfkill); if (wifi_rfkill) rfkill_unregister(wifi_rfkill); +register_wifi_error: + rfkill_destroy(wifi_rfkill); add_sysfs_error: cleanup_sysfs(device); return err; @@ -476,12 +467,18 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) { cleanup_sysfs(device); - if (wifi_rfkill) + if (wifi_rfkill) { rfkill_unregister(wifi_rfkill); - if (bluetooth_rfkill) + rfkill_destroy(wifi_rfkill); + } + if (bluetooth_rfkill) { rfkill_unregister(bluetooth_rfkill); - if (wwan_rfkill) + rfkill_destroy(wifi_rfkill); + } + if (wwan_rfkill) { rfkill_unregister(wwan_rfkill); + rfkill_destroy(wwan_rfkill); + } return 0; } diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index f1963b05175b..e48d9a4506ff 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -128,11 +128,11 @@ enum sony_nc_rfkill { SONY_BLUETOOTH, SONY_WWAN, SONY_WIMAX, - SONY_RFKILL_MAX, + N_SONY_RFKILL, }; -static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX]; -static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900}; +static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; +static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; static void sony_nc_rfkill_update(void); /*********** Input Devices ***********/ @@ -1051,147 +1051,96 @@ static void sony_nc_rfkill_cleanup(void) { int i; - for (i = 0; i < SONY_RFKILL_MAX; i++) { - if (sony_rfkill_devices[i]) + for (i = 0; i < N_SONY_RFKILL; i++) { + if (sony_rfkill_devices[i]) { rfkill_unregister(sony_rfkill_devices[i]); + rfkill_destroy(sony_rfkill_devices[i]); + } } } -static int sony_nc_rfkill_get(void *data, enum rfkill_state *state) -{ - int result; - int argument = sony_rfkill_address[(long) data]; - - sony_call_snc_handle(0x124, 0x200, &result); - if (result & 0x1) { - sony_call_snc_handle(0x124, argument, &result); - if (result & 0xf) - *state = RFKILL_STATE_UNBLOCKED; - else - *state = RFKILL_STATE_SOFT_BLOCKED; - } else { - *state = RFKILL_STATE_HARD_BLOCKED; - } - - return 0; -} - -static int sony_nc_rfkill_set(void *data, enum rfkill_state state) +static int sony_nc_rfkill_set(void *data, bool blocked) { int result; int argument = sony_rfkill_address[(long) data] + 0x100; - if (state == RFKILL_STATE_UNBLOCKED) + if (!blocked) argument |= 0xff0000; return sony_call_snc_handle(0x124, argument, &result); } -static int sony_nc_setup_wifi_rfkill(struct acpi_device *device) -{ - int err = 0; - struct rfkill *sony_wifi_rfkill; - - sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); - if (!sony_wifi_rfkill) - return -1; - sony_wifi_rfkill->name = "sony-wifi"; - sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set; - sony_wifi_rfkill->get_state = sony_nc_rfkill_get; - sony_wifi_rfkill->data = (void *)SONY_WIFI; - err = rfkill_register(sony_wifi_rfkill); - if (err) - rfkill_free(sony_wifi_rfkill); - else { - sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill; - sony_nc_rfkill_set(sony_wifi_rfkill->data, - RFKILL_STATE_UNBLOCKED); - } - return err; -} +static const struct rfkill_ops sony_rfkill_ops = { + .set_block = sony_nc_rfkill_set, +}; -static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device) +static int sony_nc_setup_rfkill(struct acpi_device *device, + enum sony_nc_rfkill nc_type) { int err = 0; - struct rfkill *sony_bluetooth_rfkill; - - sony_bluetooth_rfkill = rfkill_allocate(&device->dev, - RFKILL_TYPE_BLUETOOTH); - if (!sony_bluetooth_rfkill) - return -1; - sony_bluetooth_rfkill->name = "sony-bluetooth"; - sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set; - sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get; - sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH; - err = rfkill_register(sony_bluetooth_rfkill); - if (err) - rfkill_free(sony_bluetooth_rfkill); - else { - sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill; - sony_nc_rfkill_set(sony_bluetooth_rfkill->data, - RFKILL_STATE_UNBLOCKED); + struct rfkill *rfk; + enum rfkill_type type; + const char *name; + + switch (nc_type) { + case SONY_WIFI: + type = RFKILL_TYPE_WLAN; + name = "sony-wifi"; + break; + case SONY_BLUETOOTH: + type = RFKILL_TYPE_BLUETOOTH; + name = "sony-bluetooth"; + break; + case SONY_WWAN: + type = RFKILL_TYPE_WWAN; + name = "sony-wwan"; + break; + case SONY_WIMAX: + type = RFKILL_TYPE_WIMAX; + name = "sony-wimax"; + break; + default: + return -EINVAL; } - return err; -} -static int sony_nc_setup_wwan_rfkill(struct acpi_device *device) -{ - int err = 0; - struct rfkill *sony_wwan_rfkill; + rfk = rfkill_alloc(name, &device->dev, type, + &sony_rfkill_ops, (void *)nc_type); + if (!rfk) + return -ENOMEM; - sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); - if (!sony_wwan_rfkill) - return -1; - sony_wwan_rfkill->name = "sony-wwan"; - sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set; - sony_wwan_rfkill->get_state = sony_nc_rfkill_get; - sony_wwan_rfkill->data = (void *)SONY_WWAN; - err = rfkill_register(sony_wwan_rfkill); - if (err) - rfkill_free(sony_wwan_rfkill); - else { - sony_rfkill_devices[SONY_WWAN] = sony_wwan_rfkill; - sony_nc_rfkill_set(sony_wwan_rfkill->data, - RFKILL_STATE_UNBLOCKED); + err = rfkill_register(rfk); + if (err) { + rfkill_destroy(rfk); + return err; } + sony_rfkill_devices[nc_type] = rfk; return err; } -static int sony_nc_setup_wimax_rfkill(struct acpi_device *device) +static void sony_nc_rfkill_update() { - int err = 0; - struct rfkill *sony_wimax_rfkill; + enum sony_nc_rfkill i; + int result; + bool hwblock; - sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX); - if (!sony_wimax_rfkill) - return -1; - sony_wimax_rfkill->name = "sony-wimax"; - sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set; - sony_wimax_rfkill->get_state = sony_nc_rfkill_get; - sony_wimax_rfkill->data = (void *)SONY_WIMAX; - err = rfkill_register(sony_wimax_rfkill); - if (err) - rfkill_free(sony_wimax_rfkill); - else { - sony_rfkill_devices[SONY_WIMAX] = sony_wimax_rfkill; - sony_nc_rfkill_set(sony_wimax_rfkill->data, - RFKILL_STATE_UNBLOCKED); - } - return err; -} + sony_call_snc_handle(0x124, 0x200, &result); + hwblock = !(result & 0x1); -static void sony_nc_rfkill_update() -{ - int i; - enum rfkill_state state; + for (i = 0; i < N_SONY_RFKILL; i++) { + int argument = sony_rfkill_address[i]; - for (i = 0; i < SONY_RFKILL_MAX; i++) { - if (sony_rfkill_devices[i]) { - sony_rfkill_devices[i]-> - get_state(sony_rfkill_devices[i]->data, - &state); - rfkill_force_state(sony_rfkill_devices[i], state); + if (!sony_rfkill_devices[i]) + continue; + + if (hwblock) { + if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) + sony_nc_rfkill_set((void *)i, true); + continue; } + + sony_call_snc_handle(0x124, argument, &result); + rfkill_set_states(sony_rfkill_devices[i], + !(result & 0xf), false); } } @@ -1210,13 +1159,13 @@ static int sony_nc_rfkill_setup(struct acpi_device *device) } if (result & 0x1) - sony_nc_setup_wifi_rfkill(device); + sony_nc_setup_rfkill(device, SONY_WIFI); if (result & 0x2) - sony_nc_setup_bluetooth_rfkill(device); + sony_nc_setup_rfkill(device, SONY_BLUETOOTH); if (result & 0x1c) - sony_nc_setup_wwan_rfkill(device); + sony_nc_setup_rfkill(device, SONY_WWAN); if (result & 0x20) - sony_nc_setup_wimax_rfkill(device); + sony_nc_setup_rfkill(device, SONY_WIMAX); return 0; } diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 912be65b6261..86e958539f46 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -166,13 +166,6 @@ enum { #define TPACPI_MAX_ACPI_ARGS 3 -/* rfkill switches */ -enum { - TPACPI_RFK_BLUETOOTH_SW_ID = 0, - TPACPI_RFK_WWAN_SW_ID, - TPACPI_RFK_UWB_SW_ID, -}; - /* printk headers */ #define TPACPI_LOG TPACPI_FILE ": " #define TPACPI_EMERG KERN_EMERG TPACPI_LOG @@ -1005,67 +998,234 @@ static int __init tpacpi_check_std_acpi_brightness_support(void) return 0; } -static int __init tpacpi_new_rfkill(const unsigned int id, - struct rfkill **rfk, +static void printk_deprecated_attribute(const char * const what, + const char * const details) +{ + tpacpi_log_usertask("deprecated sysfs attribute"); + printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and " + "will be removed. %s\n", + what, details); +} + +/************************************************************************* + * rfkill and radio control support helpers + */ + +/* + * ThinkPad-ACPI firmware handling model: + * + * WLSW (master wireless switch) is event-driven, and is common to all + * firmware-controlled radios. It cannot be controlled, just monitored, + * as expected. It overrides all radio state in firmware + * + * The kernel, a masked-off hotkey, and WLSW can change the radio state + * (TODO: verify how WLSW interacts with the returned radio state). + * + * The only time there are shadow radio state changes, is when + * masked-off hotkeys are used. + */ + +/* + * Internal driver API for radio state: + * + * int: < 0 = error, otherwise enum tpacpi_rfkill_state + * bool: true means radio blocked (off) + */ +enum tpacpi_rfkill_state { + TPACPI_RFK_RADIO_OFF = 0, + TPACPI_RFK_RADIO_ON +}; + +/* rfkill switches */ +enum tpacpi_rfk_id { + TPACPI_RFK_BLUETOOTH_SW_ID = 0, + TPACPI_RFK_WWAN_SW_ID, + TPACPI_RFK_UWB_SW_ID, + TPACPI_RFK_SW_MAX +}; + +static const char *tpacpi_rfkill_names[] = { + [TPACPI_RFK_BLUETOOTH_SW_ID] = "bluetooth", + [TPACPI_RFK_WWAN_SW_ID] = "wwan", + [TPACPI_RFK_UWB_SW_ID] = "uwb", + [TPACPI_RFK_SW_MAX] = NULL +}; + +/* ThinkPad-ACPI rfkill subdriver */ +struct tpacpi_rfk { + struct rfkill *rfkill; + enum tpacpi_rfk_id id; + const struct tpacpi_rfk_ops *ops; +}; + +struct tpacpi_rfk_ops { + /* firmware interface */ + int (*get_status)(void); + int (*set_status)(const enum tpacpi_rfkill_state); +}; + +static struct tpacpi_rfk *tpacpi_rfkill_switches[TPACPI_RFK_SW_MAX]; + +/* Query FW and update rfkill sw state for a given rfkill switch */ +static int tpacpi_rfk_update_swstate(const struct tpacpi_rfk *tp_rfk) +{ + int status; + + if (!tp_rfk) + return -ENODEV; + + status = (tp_rfk->ops->get_status)(); + if (status < 0) + return status; + + rfkill_set_sw_state(tp_rfk->rfkill, + (status == TPACPI_RFK_RADIO_OFF)); + + return status; +} + +/* Query FW and update rfkill sw state for all rfkill switches */ +static void tpacpi_rfk_update_swstate_all(void) +{ + unsigned int i; + + for (i = 0; i < TPACPI_RFK_SW_MAX; i++) + tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[i]); +} + +/* + * Sync the HW-blocking state of all rfkill switches, + * do notice it causes the rfkill core to schedule uevents + */ +static void tpacpi_rfk_update_hwblock_state(bool blocked) +{ + unsigned int i; + struct tpacpi_rfk *tp_rfk; + + for (i = 0; i < TPACPI_RFK_SW_MAX; i++) { + tp_rfk = tpacpi_rfkill_switches[i]; + if (tp_rfk) { + if (rfkill_set_hw_state(tp_rfk->rfkill, + blocked)) { + /* ignore -- we track sw block */ + } + } + } +} + +/* Call to get the WLSW state from the firmware */ +static int hotkey_get_wlsw(void); + +/* Call to query WLSW state and update all rfkill switches */ +static bool tpacpi_rfk_check_hwblock_state(void) +{ + int res = hotkey_get_wlsw(); + int hw_blocked; + + /* When unknown or unsupported, we have to assume it is unblocked */ + if (res < 0) + return false; + + hw_blocked = (res == TPACPI_RFK_RADIO_OFF); + tpacpi_rfk_update_hwblock_state(hw_blocked); + + return hw_blocked; +} + +static int tpacpi_rfk_hook_set_block(void *data, bool blocked) +{ + struct tpacpi_rfk *tp_rfk = data; + int res; + + dbg_printk(TPACPI_DBG_RFKILL, + "request to change radio state to %s\n", + blocked ? "blocked" : "unblocked"); + + /* try to set radio state */ + res = (tp_rfk->ops->set_status)(blocked ? + TPACPI_RFK_RADIO_OFF : TPACPI_RFK_RADIO_ON); + + /* and update the rfkill core with whatever the FW really did */ + tpacpi_rfk_update_swstate(tp_rfk); + + return (res < 0) ? res : 0; +} + +static const struct rfkill_ops tpacpi_rfk_rfkill_ops = { + .set_block = tpacpi_rfk_hook_set_block, +}; + +static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, + const struct tpacpi_rfk_ops *tp_rfkops, const enum rfkill_type rfktype, const char *name, - const bool set_default, - int (*toggle_radio)(void *, enum rfkill_state), - int (*get_state)(void *, enum rfkill_state *)) + const bool set_default) { + struct tpacpi_rfk *atp_rfk; int res; - enum rfkill_state initial_state = RFKILL_STATE_SOFT_BLOCKED; - - res = get_state(NULL, &initial_state); - if (res < 0) { - printk(TPACPI_ERR - "failed to read initial state for %s, error %d; " - "will turn radio off\n", name, res); - } else if (set_default) { - /* try to set the initial state as the default for the rfkill - * type, since we ask the firmware to preserve it across S5 in - * NVRAM */ - if (rfkill_set_default(rfktype, - (initial_state == RFKILL_STATE_UNBLOCKED) ? - RFKILL_STATE_UNBLOCKED : - RFKILL_STATE_SOFT_BLOCKED) == -EPERM) - vdbg_printk(TPACPI_DBG_RFKILL, - "Default state for %s cannot be changed\n", - name); - } - - *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); - if (!*rfk) { + bool initial_sw_state = false; + int initial_sw_status; + + BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); + + atp_rfk = kzalloc(sizeof(struct tpacpi_rfk), GFP_KERNEL); + if (atp_rfk) + atp_rfk->rfkill = rfkill_alloc(name, + &tpacpi_pdev->dev, + rfktype, + &tpacpi_rfk_rfkill_ops, + atp_rfk); + if (!atp_rfk || !atp_rfk->rfkill) { printk(TPACPI_ERR "failed to allocate memory for rfkill class\n"); + kfree(atp_rfk); return -ENOMEM; } - (*rfk)->name = name; - (*rfk)->get_state = get_state; - (*rfk)->toggle_radio = toggle_radio; - (*rfk)->state = initial_state; + atp_rfk->id = id; + atp_rfk->ops = tp_rfkops; + + initial_sw_status = (tp_rfkops->get_status)(); + if (initial_sw_status < 0) { + printk(TPACPI_ERR + "failed to read initial state for %s, error %d\n", + name, initial_sw_status); + } else { + initial_sw_state = (initial_sw_status == TPACPI_RFK_RADIO_OFF); + if (set_default) { + /* try to keep the initial state, since we ask the + * firmware to preserve it across S5 in NVRAM */ + rfkill_set_sw_state(atp_rfk->rfkill, initial_sw_state); + } + } + rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state()); - res = rfkill_register(*rfk); + res = rfkill_register(atp_rfk->rfkill); if (res < 0) { printk(TPACPI_ERR "failed to register %s rfkill switch: %d\n", name, res); - rfkill_free(*rfk); - *rfk = NULL; + rfkill_destroy(atp_rfk->rfkill); + kfree(atp_rfk); return res; } + tpacpi_rfkill_switches[id] = atp_rfk; return 0; } -static void printk_deprecated_attribute(const char * const what, - const char * const details) +static void tpacpi_destroy_rfkill(const enum tpacpi_rfk_id id) { - tpacpi_log_usertask("deprecated sysfs attribute"); - printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and " - "will be removed. %s\n", - what, details); + struct tpacpi_rfk *tp_rfk; + + BUG_ON(id >= TPACPI_RFK_SW_MAX); + + tp_rfk = tpacpi_rfkill_switches[id]; + if (tp_rfk) { + rfkill_unregister(tp_rfk->rfkill); + tpacpi_rfkill_switches[id] = NULL; + kfree(tp_rfk); + } } static void printk_deprecated_rfkill_attribute(const char * const what) @@ -1074,6 +1234,112 @@ static void printk_deprecated_rfkill_attribute(const char * const what) "Please switch to generic rfkill before year 2010"); } +/* sysfs <radio> enable ------------------------------------------------ */ +static ssize_t tpacpi_rfk_sysfs_enable_show(const enum tpacpi_rfk_id id, + struct device_attribute *attr, + char *buf) +{ + int status; + + printk_deprecated_rfkill_attribute(attr->attr.name); + + /* This is in the ABI... */ + if (tpacpi_rfk_check_hwblock_state()) { + status = TPACPI_RFK_RADIO_OFF; + } else { + status = tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); + if (status < 0) + return status; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", + (status == TPACPI_RFK_RADIO_ON) ? 1 : 0); +} + +static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long t; + int res; + + printk_deprecated_rfkill_attribute(attr->attr.name); + + if (parse_strtoul(buf, 1, &t)) + return -EINVAL; + + tpacpi_disclose_usertask(attr->attr.name, "set to %ld\n", t); + + /* This is in the ABI... */ + if (tpacpi_rfk_check_hwblock_state() && !!t) + return -EPERM; + + res = tpacpi_rfkill_switches[id]->ops->set_status((!!t) ? + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF); + tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); + + return (res < 0) ? res : count; +} + +/* procfs -------------------------------------------------------------- */ +static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p) +{ + int len = 0; + + if (id >= TPACPI_RFK_SW_MAX) + len += sprintf(p + len, "status:\t\tnot supported\n"); + else { + int status; + + /* This is in the ABI... */ + if (tpacpi_rfk_check_hwblock_state()) { + status = TPACPI_RFK_RADIO_OFF; + } else { + status = tpacpi_rfk_update_swstate( + tpacpi_rfkill_switches[id]); + if (status < 0) + return status; + } + + len += sprintf(p + len, "status:\t\t%s\n", + (status == TPACPI_RFK_RADIO_ON) ? + "enabled" : "disabled"); + len += sprintf(p + len, "commands:\tenable, disable\n"); + } + + return len; +} + +static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf) +{ + char *cmd; + int status = -1; + int res = 0; + + if (id >= TPACPI_RFK_SW_MAX) + return -ENODEV; + + while ((cmd = next_cmd(&buf))) { + if (strlencmp(cmd, "enable") == 0) + status = TPACPI_RFK_RADIO_ON; + else if (strlencmp(cmd, "disable") == 0) + status = TPACPI_RFK_RADIO_OFF; + else + return -EINVAL; + } + + if (status != -1) { + tpacpi_disclose_usertask("procfs", "attempt to %s %s\n", + (status == TPACPI_RFK_RADIO_ON) ? + "enable" : "disable", + tpacpi_rfkill_names[id]); + res = (tpacpi_rfkill_switches[id]->ops->set_status)(status); + tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); + } + + return res; +} + /************************************************************************* * thinkpad-acpi driver attributes */ @@ -1127,8 +1393,6 @@ static DRIVER_ATTR(version, S_IRUGO, #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES -static void tpacpi_send_radiosw_update(void); - /* wlsw_emulstate ------------------------------------------------------ */ static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv, char *buf) @@ -1144,11 +1408,10 @@ static ssize_t tpacpi_driver_wlsw_emulstate_store(struct device_driver *drv, if (parse_strtoul(buf, 1, &t)) return -EINVAL; - if (tpacpi_wlsw_emulstate != t) { - tpacpi_wlsw_emulstate = !!t; - tpacpi_send_radiosw_update(); - } else + if (tpacpi_wlsw_emulstate != !!t) { tpacpi_wlsw_emulstate = !!t; + tpacpi_rfk_update_hwblock_state(!t); /* negative logic */ + } return count; } @@ -1463,17 +1726,23 @@ static struct attribute_set *hotkey_dev_attributes; /* HKEY.MHKG() return bits */ #define TP_HOTKEY_TABLET_MASK (1 << 3) -static int hotkey_get_wlsw(int *status) +static int hotkey_get_wlsw(void) { + int status; + + if (!tp_features.hotkey_wlsw) + return -ENODEV; + #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES - if (dbg_wlswemul) { - *status = !!tpacpi_wlsw_emulstate; - return 0; - } + if (dbg_wlswemul) + return (tpacpi_wlsw_emulstate) ? + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; #endif - if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) + + if (!acpi_evalf(hkey_handle, &status, "WLSW", "d")) return -EIO; - return 0; + + return (status) ? TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; } static int hotkey_get_tablet_mode(int *status) @@ -2107,12 +2376,16 @@ static ssize_t hotkey_radio_sw_show(struct device *dev, struct device_attribute *attr, char *buf) { - int res, s; - res = hotkey_get_wlsw(&s); + int res; + res = hotkey_get_wlsw(); if (res < 0) return res; - return snprintf(buf, PAGE_SIZE, "%d\n", !!s); + /* Opportunistic update */ + tpacpi_rfk_update_hwblock_state((res == TPACPI_RFK_RADIO_OFF)); + + return snprintf(buf, PAGE_SIZE, "%d\n", + (res == TPACPI_RFK_RADIO_OFF) ? 0 : 1); } static struct device_attribute dev_attr_hotkey_radio_sw = @@ -2223,30 +2496,52 @@ static struct attribute *hotkey_mask_attributes[] __initdata = { &dev_attr_hotkey_wakeup_hotunplug_complete.attr, }; -static void bluetooth_update_rfk(void); -static void wan_update_rfk(void); -static void uwb_update_rfk(void); +/* + * Sync both the hw and sw blocking state of all switches + */ static void tpacpi_send_radiosw_update(void) { int wlsw; - /* Sync these BEFORE sending any rfkill events */ - if (tp_features.bluetooth) - bluetooth_update_rfk(); - if (tp_features.wan) - wan_update_rfk(); - if (tp_features.uwb) - uwb_update_rfk(); + /* + * We must sync all rfkill controllers *before* issuing any + * rfkill input events, or we will race the rfkill core input + * handler. + * + * tpacpi_inputdev_send_mutex works as a syncronization point + * for the above. + * + * We optimize to avoid numerous calls to hotkey_get_wlsw. + */ + + wlsw = hotkey_get_wlsw(); + + /* Sync hw blocking state first if it is hw-blocked */ + if (wlsw == TPACPI_RFK_RADIO_OFF) + tpacpi_rfk_update_hwblock_state(true); - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { + /* Sync sw blocking state */ + tpacpi_rfk_update_swstate_all(); + + /* Sync hw blocking state last if it is hw-unblocked */ + if (wlsw == TPACPI_RFK_RADIO_ON) + tpacpi_rfk_update_hwblock_state(false); + + /* Issue rfkill input event for WLSW switch */ + if (!(wlsw < 0)) { mutex_lock(&tpacpi_inputdev_send_mutex); input_report_switch(tpacpi_inputdev, - SW_RFKILL_ALL, !!wlsw); + SW_RFKILL_ALL, (wlsw > 0)); input_sync(tpacpi_inputdev); mutex_unlock(&tpacpi_inputdev_send_mutex); } + + /* + * this can be unconditional, as we will poll state again + * if userspace uses the notify to read data + */ hotkey_radio_sw_notify_change(); } @@ -3056,8 +3351,6 @@ enum { #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" -static struct rfkill *tpacpi_bluetooth_rfkill; - static void bluetooth_suspend(pm_message_t state) { /* Try to make sure radio will resume powered off */ @@ -3067,83 +3360,47 @@ static void bluetooth_suspend(pm_message_t state) "bluetooth power down on resume request failed\n"); } -static int bluetooth_get_radiosw(void) +static int bluetooth_get_status(void) { int status; - if (!tp_features.bluetooth) - return -ENODEV; - - /* WLSW overrides bluetooth in firmware/hardware, reflect that */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) - return RFKILL_STATE_HARD_BLOCKED; - #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_bluetoothemul) return (tpacpi_bluetooth_emulstate) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; #endif if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) return -EIO; return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; -} - -static void bluetooth_update_rfk(void) -{ - int status; - - if (!tpacpi_bluetooth_rfkill) - return; - - status = bluetooth_get_radiosw(); - if (status < 0) - return; - rfkill_force_state(tpacpi_bluetooth_rfkill, status); - - vdbg_printk(TPACPI_DBG_RFKILL, - "forced rfkill state to %d\n", - status); + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; } -static int bluetooth_set_radiosw(int radio_on, int update_rfk) +static int bluetooth_set_status(enum tpacpi_rfkill_state state) { int status; - if (!tp_features.bluetooth) - return -ENODEV; - - /* WLSW overrides bluetooth in firmware/hardware, but there is no - * reason to risk weird behaviour. */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status - && radio_on) - return -EPERM; - vdbg_printk(TPACPI_DBG_RFKILL, - "will %s bluetooth\n", radio_on ? "enable" : "disable"); + "will attempt to %s bluetooth\n", + (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_bluetoothemul) { - tpacpi_bluetooth_emulstate = !!radio_on; - if (update_rfk) - bluetooth_update_rfk(); + tpacpi_bluetooth_emulstate = (state == TPACPI_RFK_RADIO_ON); return 0; } #endif /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ - if (radio_on) + if (state == TPACPI_RFK_RADIO_ON) status = TP_ACPI_BLUETOOTH_RADIOSSW; else status = 0; + if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) return -EIO; - if (update_rfk) - bluetooth_update_rfk(); - return 0; } @@ -3152,35 +3409,16 @@ static ssize_t bluetooth_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { - int status; - - printk_deprecated_rfkill_attribute("bluetooth_enable"); - - status = bluetooth_get_radiosw(); - if (status < 0) - return status; - - return snprintf(buf, PAGE_SIZE, "%d\n", - (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); + return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_BLUETOOTH_SW_ID, + attr, buf); } static ssize_t bluetooth_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - unsigned long t; - int res; - - printk_deprecated_rfkill_attribute("bluetooth_enable"); - - if (parse_strtoul(buf, 1, &t)) - return -EINVAL; - - tpacpi_disclose_usertask("bluetooth_enable", "set to %ld\n", t); - - res = bluetooth_set_radiosw(t, 1); - - return (res) ? res : count; + return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_BLUETOOTH_SW_ID, + attr, buf, count); } static struct device_attribute dev_attr_bluetooth_enable = @@ -3198,23 +3436,10 @@ static const struct attribute_group bluetooth_attr_group = { .attrs = bluetooth_attributes, }; -static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state) -{ - int bts = bluetooth_get_radiosw(); - - if (bts < 0) - return bts; - - *state = bts; - return 0; -} - -static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state) -{ - dbg_printk(TPACPI_DBG_RFKILL, - "request to change radio state to %d\n", state); - return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); -} +static const struct tpacpi_rfk_ops bluetooth_tprfk_ops = { + .get_status = bluetooth_get_status, + .set_status = bluetooth_set_status, +}; static void bluetooth_shutdown(void) { @@ -3230,13 +3455,12 @@ static void bluetooth_shutdown(void) static void bluetooth_exit(void) { - bluetooth_shutdown(); - - if (tpacpi_bluetooth_rfkill) - rfkill_unregister(tpacpi_bluetooth_rfkill); - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &bluetooth_attr_group); + + tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); + + bluetooth_shutdown(); } static int __init bluetooth_init(struct ibm_init_struct *iibm) @@ -3277,20 +3501,18 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) if (!tp_features.bluetooth) return 1; - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &bluetooth_attr_group); - if (res) - return res; - res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, - &tpacpi_bluetooth_rfkill, + &bluetooth_tprfk_ops, RFKILL_TYPE_BLUETOOTH, TPACPI_RFK_BLUETOOTH_SW_NAME, - true, - tpacpi_bluetooth_rfk_set, - tpacpi_bluetooth_rfk_get); + true); + if (res) + return res; + + res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &bluetooth_attr_group); if (res) { - bluetooth_exit(); + tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); return res; } @@ -3300,46 +3522,12 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) /* procfs -------------------------------------------------------------- */ static int bluetooth_read(char *p) { - int len = 0; - int status = bluetooth_get_radiosw(); - - if (!tp_features.bluetooth) - len += sprintf(p + len, "status:\t\tnot supported\n"); - else { - len += sprintf(p + len, "status:\t\t%s\n", - (status == RFKILL_STATE_UNBLOCKED) ? - "enabled" : "disabled"); - len += sprintf(p + len, "commands:\tenable, disable\n"); - } - - return len; + return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, p); } static int bluetooth_write(char *buf) { - char *cmd; - int state = -1; - - if (!tp_features.bluetooth) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (strlencmp(cmd, "enable") == 0) { - state = 1; - } else if (strlencmp(cmd, "disable") == 0) { - state = 0; - } else - return -EINVAL; - } - - if (state != -1) { - tpacpi_disclose_usertask("procfs bluetooth", - "attempt to %s\n", - state ? "enable" : "disable"); - bluetooth_set_radiosw(state, 1); - } - - return 0; + return tpacpi_rfk_procfs_write(TPACPI_RFK_BLUETOOTH_SW_ID, buf); } static struct ibm_struct bluetooth_driver_data = { @@ -3365,8 +3553,6 @@ enum { #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" -static struct rfkill *tpacpi_wan_rfkill; - static void wan_suspend(pm_message_t state) { /* Try to make sure radio will resume powered off */ @@ -3376,83 +3562,47 @@ static void wan_suspend(pm_message_t state) "WWAN power down on resume request failed\n"); } -static int wan_get_radiosw(void) +static int wan_get_status(void) { int status; - if (!tp_features.wan) - return -ENODEV; - - /* WLSW overrides WWAN in firmware/hardware, reflect that */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) - return RFKILL_STATE_HARD_BLOCKED; - #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_wwanemul) return (tpacpi_wwan_emulstate) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; #endif if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) return -EIO; return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; -} - -static void wan_update_rfk(void) -{ - int status; - - if (!tpacpi_wan_rfkill) - return; - - status = wan_get_radiosw(); - if (status < 0) - return; - rfkill_force_state(tpacpi_wan_rfkill, status); - - vdbg_printk(TPACPI_DBG_RFKILL, - "forced rfkill state to %d\n", - status); + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; } -static int wan_set_radiosw(int radio_on, int update_rfk) +static int wan_set_status(enum tpacpi_rfkill_state state) { int status; - if (!tp_features.wan) - return -ENODEV; - - /* WLSW overrides bluetooth in firmware/hardware, but there is no - * reason to risk weird behaviour. */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status - && radio_on) - return -EPERM; - vdbg_printk(TPACPI_DBG_RFKILL, - "will %s WWAN\n", radio_on ? "enable" : "disable"); + "will attempt to %s wwan\n", + (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_wwanemul) { - tpacpi_wwan_emulstate = !!radio_on; - if (update_rfk) - wan_update_rfk(); + tpacpi_wwan_emulstate = (state == TPACPI_RFK_RADIO_ON); return 0; } #endif /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */ - if (radio_on) + if (state == TPACPI_RFK_RADIO_ON) status = TP_ACPI_WANCARD_RADIOSSW; else status = 0; + if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) return -EIO; - if (update_rfk) - wan_update_rfk(); - return 0; } @@ -3461,35 +3611,16 @@ static ssize_t wan_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { - int status; - - printk_deprecated_rfkill_attribute("wwan_enable"); - - status = wan_get_radiosw(); - if (status < 0) - return status; - - return snprintf(buf, PAGE_SIZE, "%d\n", - (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0); + return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_WWAN_SW_ID, + attr, buf); } static ssize_t wan_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - unsigned long t; - int res; - - printk_deprecated_rfkill_attribute("wwan_enable"); - - if (parse_strtoul(buf, 1, &t)) - return -EINVAL; - - tpacpi_disclose_usertask("wwan_enable", "set to %ld\n", t); - - res = wan_set_radiosw(t, 1); - - return (res) ? res : count; + return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_WWAN_SW_ID, + attr, buf, count); } static struct device_attribute dev_attr_wan_enable = @@ -3507,23 +3638,10 @@ static const struct attribute_group wan_attr_group = { .attrs = wan_attributes, }; -static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state) -{ - int wans = wan_get_radiosw(); - - if (wans < 0) - return wans; - - *state = wans; - return 0; -} - -static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state) -{ - dbg_printk(TPACPI_DBG_RFKILL, - "request to change radio state to %d\n", state); - return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); -} +static const struct tpacpi_rfk_ops wan_tprfk_ops = { + .get_status = wan_get_status, + .set_status = wan_set_status, +}; static void wan_shutdown(void) { @@ -3539,13 +3657,12 @@ static void wan_shutdown(void) static void wan_exit(void) { - wan_shutdown(); - - if (tpacpi_wan_rfkill) - rfkill_unregister(tpacpi_wan_rfkill); - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &wan_attr_group); + + tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); + + wan_shutdown(); } static int __init wan_init(struct ibm_init_struct *iibm) @@ -3584,20 +3701,19 @@ static int __init wan_init(struct ibm_init_struct *iibm) if (!tp_features.wan) return 1; - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &wan_attr_group); - if (res) - return res; - res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, - &tpacpi_wan_rfkill, + &wan_tprfk_ops, RFKILL_TYPE_WWAN, TPACPI_RFK_WWAN_SW_NAME, - true, - tpacpi_wan_rfk_set, - tpacpi_wan_rfk_get); + true); + if (res) + return res; + + res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &wan_attr_group); + if (res) { - wan_exit(); + tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); return res; } @@ -3607,48 +3723,12 @@ static int __init wan_init(struct ibm_init_struct *iibm) /* procfs -------------------------------------------------------------- */ static int wan_read(char *p) { - int len = 0; - int status = wan_get_radiosw(); - - tpacpi_disclose_usertask("procfs wan", "read"); - - if (!tp_features.wan) - len += sprintf(p + len, "status:\t\tnot supported\n"); - else { - len += sprintf(p + len, "status:\t\t%s\n", - (status == RFKILL_STATE_UNBLOCKED) ? - "enabled" : "disabled"); - len += sprintf(p + len, "commands:\tenable, disable\n"); - } - - return len; + return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, p); } static int wan_write(char *buf) { - char *cmd; - int state = -1; - - if (!tp_features.wan) - return -ENODEV; - - while ((cmd = next_cmd(&buf))) { - if (strlencmp(cmd, "enable") == 0) { - state = 1; - } else if (strlencmp(cmd, "disable") == 0) { - state = 0; - } else - return -EINVAL; - } - - if (state != -1) { - tpacpi_disclose_usertask("procfs wan", - "attempt to %s\n", - state ? "enable" : "disable"); - wan_set_radiosw(state, 1); - } - - return 0; + return tpacpi_rfk_procfs_write(TPACPI_RFK_WWAN_SW_ID, buf); } static struct ibm_struct wan_driver_data = { @@ -3672,108 +3752,59 @@ enum { #define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw" -static struct rfkill *tpacpi_uwb_rfkill; - -static int uwb_get_radiosw(void) +static int uwb_get_status(void) { int status; - if (!tp_features.uwb) - return -ENODEV; - - /* WLSW overrides UWB in firmware/hardware, reflect that */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) - return RFKILL_STATE_HARD_BLOCKED; - #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_uwbemul) return (tpacpi_uwb_emulstate) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; #endif if (!acpi_evalf(hkey_handle, &status, "GUWB", "d")) return -EIO; return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ? - RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; + TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF; } -static void uwb_update_rfk(void) +static int uwb_set_status(enum tpacpi_rfkill_state state) { int status; - if (!tpacpi_uwb_rfkill) - return; - - status = uwb_get_radiosw(); - if (status < 0) - return; - rfkill_force_state(tpacpi_uwb_rfkill, status); - vdbg_printk(TPACPI_DBG_RFKILL, - "forced rfkill state to %d\n", - status); -} - -static int uwb_set_radiosw(int radio_on, int update_rfk) -{ - int status; - - if (!tp_features.uwb) - return -ENODEV; - - /* WLSW overrides UWB in firmware/hardware, but there is no - * reason to risk weird behaviour. */ - if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status - && radio_on) - return -EPERM; - - vdbg_printk(TPACPI_DBG_RFKILL, - "will %s UWB\n", radio_on ? "enable" : "disable"); + "will attempt to %s UWB\n", + (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_uwbemul) { - tpacpi_uwb_emulstate = !!radio_on; - if (update_rfk) - uwb_update_rfk(); + tpacpi_uwb_emulstate = (state == TPACPI_RFK_RADIO_ON); return 0; } #endif - status = (radio_on) ? TP_ACPI_UWB_RADIOSSW : 0; + if (state == TPACPI_RFK_RADIO_ON) + status = TP_ACPI_UWB_RADIOSSW; + else + status = 0; + if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status)) return -EIO; - if (update_rfk) - uwb_update_rfk(); - return 0; } /* --------------------------------------------------------------------- */ -static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state) -{ - int uwbs = uwb_get_radiosw(); - - if (uwbs < 0) - return uwbs; - - *state = uwbs; - return 0; -} - -static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state) -{ - dbg_printk(TPACPI_DBG_RFKILL, - "request to change radio state to %d\n", state); - return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); -} +static const struct tpacpi_rfk_ops uwb_tprfk_ops = { + .get_status = uwb_get_status, + .set_status = uwb_set_status, +}; static void uwb_exit(void) { - if (tpacpi_uwb_rfkill) - rfkill_unregister(tpacpi_uwb_rfkill); + tpacpi_destroy_rfkill(TPACPI_RFK_UWB_SW_ID); } static int __init uwb_init(struct ibm_init_struct *iibm) @@ -3813,13 +3844,10 @@ static int __init uwb_init(struct ibm_init_struct *iibm) return 1; res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, - &tpacpi_uwb_rfkill, + &uwb_tprfk_ops, RFKILL_TYPE_UWB, TPACPI_RFK_UWB_SW_NAME, - false, - tpacpi_uwb_rfk_set, - tpacpi_uwb_rfk_get); - + false); return res; } diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 4345089f5171..81d31ea507d1 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -45,7 +45,6 @@ #include <linux/backlight.h> #include <linux/platform_device.h> #include <linux/rfkill.h> -#include <linux/input-polldev.h> #include <asm/uaccess.h> @@ -250,21 +249,15 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result) struct toshiba_acpi_dev { struct platform_device *p_dev; - struct rfkill *rfk_dev; - struct input_polled_dev *poll_dev; + struct rfkill *bt_rfk; const char *bt_name; - const char *rfk_name; - - bool last_rfk_state; struct mutex mutex; }; static struct toshiba_acpi_dev toshiba_acpi = { .bt_name = "Toshiba Bluetooth", - .rfk_name = "Toshiba RFKill Switch", - .last_rfk_state = false, }; /* Bluetooth rfkill handlers */ @@ -283,21 +276,6 @@ static u32 hci_get_bt_present(bool *present) return hci_result; } -static u32 hci_get_bt_on(bool *on) -{ - u32 hci_result; - u32 value, value2; - - value = 0; - value2 = 0x0001; - hci_read2(HCI_WIRELESS, &value, &value2, &hci_result); - if (hci_result == HCI_SUCCESS) - *on = (value & HCI_WIRELESS_BT_POWER) && - (value & HCI_WIRELESS_BT_ATTACH); - - return hci_result; -} - static u32 hci_get_radio_state(bool *radio_state) { u32 hci_result; @@ -311,70 +289,67 @@ static u32 hci_get_radio_state(bool *radio_state) return hci_result; } -static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state) +static int bt_rfkill_set_block(void *data, bool blocked) { + struct toshiba_acpi_dev *dev = data; u32 result1, result2; u32 value; + int err; bool radio_state; - struct toshiba_acpi_dev *dev = data; - value = (state == RFKILL_STATE_UNBLOCKED); + value = (blocked == false); - if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) - return -EFAULT; + mutex_lock(&dev->mutex); + if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) { + err = -EBUSY; + goto out; + } - switch (state) { - case RFKILL_STATE_UNBLOCKED: - if (!radio_state) - return -EPERM; - break; - case RFKILL_STATE_SOFT_BLOCKED: - break; - default: - return -EINVAL; + if (!radio_state) { + err = 0; + goto out; } - mutex_lock(&dev->mutex); hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1); hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2); - mutex_unlock(&dev->mutex); if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS) - return -EFAULT; - - return 0; + err = -EBUSY; + else + err = 0; + out: + mutex_unlock(&dev->mutex); + return err; } -static void bt_poll_rfkill(struct input_polled_dev *poll_dev) +static void bt_rfkill_poll(struct rfkill *rfkill, void *data) { - bool state_changed; bool new_rfk_state; bool value; u32 hci_result; - struct toshiba_acpi_dev *dev = poll_dev->private; + struct toshiba_acpi_dev *dev = data; + + mutex_lock(&dev->mutex); hci_result = hci_get_radio_state(&value); - if (hci_result != HCI_SUCCESS) - return; /* Can't do anything useful */ + if (hci_result != HCI_SUCCESS) { + /* Can't do anything useful */ + mutex_unlock(&dev->mutex); + } new_rfk_state = value; - mutex_lock(&dev->mutex); - state_changed = new_rfk_state != dev->last_rfk_state; - dev->last_rfk_state = new_rfk_state; mutex_unlock(&dev->mutex); - if (unlikely(state_changed)) { - rfkill_force_state(dev->rfk_dev, - new_rfk_state ? - RFKILL_STATE_SOFT_BLOCKED : - RFKILL_STATE_HARD_BLOCKED); - input_report_switch(poll_dev->input, SW_RFKILL_ALL, - new_rfk_state); - input_sync(poll_dev->input); - } + if (rfkill_set_hw_state(rfkill, !new_rfk_state)) + bt_rfkill_set_block(data, true); } +static const struct rfkill_ops toshiba_rfk_ops = { + .set_block = bt_rfkill_set_block, + .poll = bt_rfkill_poll, +}; + static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; static struct backlight_device *toshiba_backlight_device; static int force_fan; @@ -702,14 +677,11 @@ static struct backlight_ops toshiba_backlight_data = { static void toshiba_acpi_exit(void) { - if (toshiba_acpi.poll_dev) { - input_unregister_polled_device(toshiba_acpi.poll_dev); - input_free_polled_device(toshiba_acpi.poll_dev); + if (toshiba_acpi.bt_rfk) { + rfkill_unregister(toshiba_acpi.bt_rfk); + rfkill_destroy(toshiba_acpi.bt_rfk); } - if (toshiba_acpi.rfk_dev) - rfkill_unregister(toshiba_acpi.rfk_dev); - if (toshiba_backlight_device) backlight_device_unregister(toshiba_backlight_device); @@ -728,8 +700,6 @@ static int __init toshiba_acpi_init(void) acpi_status status = AE_OK; u32 hci_result; bool bt_present; - bool bt_on; - bool radio_on; int ret = 0; if (acpi_disabled) @@ -793,60 +763,21 @@ static int __init toshiba_acpi_init(void) /* Register rfkill switch for Bluetooth */ if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) { - toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev, - RFKILL_TYPE_BLUETOOTH); - if (!toshiba_acpi.rfk_dev) { + toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name, + &toshiba_acpi.p_dev->dev, + RFKILL_TYPE_BLUETOOTH, + &toshiba_rfk_ops, + &toshiba_acpi); + if (!toshiba_acpi.bt_rfk) { printk(MY_ERR "unable to allocate rfkill device\n"); toshiba_acpi_exit(); return -ENOMEM; } - toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name; - toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio; - toshiba_acpi.rfk_dev->data = &toshiba_acpi; - - if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) { - toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED; - } else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS && - radio_on) { - toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED; - } else { - toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED; - } - - ret = rfkill_register(toshiba_acpi.rfk_dev); + ret = rfkill_register(toshiba_acpi.bt_rfk); if (ret) { printk(MY_ERR "unable to register rfkill device\n"); - toshiba_acpi_exit(); - return -ENOMEM; - } - - /* Register input device for kill switch */ - toshiba_acpi.poll_dev = input_allocate_polled_device(); - if (!toshiba_acpi.poll_dev) { - printk(MY_ERR - "unable to allocate kill-switch input device\n"); - toshiba_acpi_exit(); - return -ENOMEM; - } - toshiba_acpi.poll_dev->private = &toshiba_acpi; - toshiba_acpi.poll_dev->poll = bt_poll_rfkill; - toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */ - - toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name; - toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST; - /* Toshiba USB ID */ - toshiba_acpi.poll_dev->input->id.vendor = 0x0930; - set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit); - set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit); - input_report_switch(toshiba_acpi.poll_dev->input, - SW_RFKILL_ALL, TRUE); - input_sync(toshiba_acpi.poll_dev->input); - - ret = input_register_polled_device(toshiba_acpi.poll_dev); - if (ret) { - printk(MY_ERR - "unable to register kill-switch input device\n"); + rfkill_destroy(toshiba_acpi.bt_rfk); toshiba_acpi_exit(); return ret; } diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 2994aa1ed466..74c49d9a8dba 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2937,8 +2937,8 @@ int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) if (card->info.type == QETH_CARD_TYPE_OSN) return cast_type; - if (skb->dst && skb->dst->neighbour) { - cast_type = skb->dst->neighbour->type; + if (skb_dst(skb) && skb_dst(skb)->neighbour) { + cast_type = skb_dst(skb)->neighbour->type; if ((cast_type == RTN_BROADCAST) || (cast_type == RTN_MULTICAST) || (cast_type == RTN_ANYCAST)) diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 9ca6bab7c9ba..ecd3d06c0d5c 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -19,6 +19,7 @@ #include <linux/etherdevice.h> #include <linux/mii.h> #include <linux/ip.h> +#include <linux/list.h> #include "qeth_core.h" @@ -640,6 +641,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; struct dev_addr_list *dm; + struct netdev_hw_addr *ha; if (card->info.type == QETH_CARD_TYPE_OSN) return ; @@ -653,8 +655,8 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) for (dm = dev->mc_list; dm; dm = dm->next) qeth_l2_add_mc(card, dm->da_addr, 0); - for (dm = dev->uc_list; dm; dm = dm->next) - qeth_l2_add_mc(card, dm->da_addr, 1); + list_for_each_entry(ha, &dev->uc_list, list) + qeth_l2_add_mc(card, ha->addr, 1); spin_unlock_bh(&card->mclock); if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index b36b5cdf9000..6f2386e9d6e2 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2549,9 +2549,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, /* IPv4 */ hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type); memset(hdr->hdr.l3.dest_addr, 0, 12); - if ((skb->dst) && (skb->dst->neighbour)) { + if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = - *((u32 *) skb->dst->neighbour->primary_key); + *((u32 *) skb_dst(skb)->neighbour->primary_key); } else { /* fill in destination address used in ip header */ *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = @@ -2562,9 +2562,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type); if (card->info.type == QETH_CARD_TYPE_IQD) hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU; - if ((skb->dst) && (skb->dst->neighbour)) { + if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { memcpy(hdr->hdr.l3.dest_addr, - skb->dst->neighbour->primary_key, 16); + skb_dst(skb)->neighbour->primary_key, 16); } else { /* fill in destination address used in ip header */ memcpy(hdr->hdr.l3.dest_addr, @@ -3012,6 +3012,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; + card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; SET_NETDEV_DEV(card->dev, &card->gdev->dev); return register_netdev(card->dev); diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index ce33f107b0a0..f791348871fc 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -182,8 +182,8 @@ static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) fc = fcoe_from_ctlr(fip); rtnl_lock(); if (!is_zero_ether_addr(old)) - dev_unicast_delete(fc->real_dev, old, ETH_ALEN); - dev_unicast_add(fc->real_dev, new, ETH_ALEN); + dev_unicast_delete(fc->real_dev, old); + dev_unicast_add(fc->real_dev, new); rtnl_unlock(); } @@ -233,13 +233,11 @@ void fcoe_netdev_cleanup(struct fcoe_softc *fc) /* Delete secondary MAC addresses */ rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); + dev_unicast_delete(fc->real_dev, flogi_maddr); if (!is_zero_ether_addr(fc->ctlr.data_src_addr)) - dev_unicast_delete(fc->real_dev, - fc->ctlr.data_src_addr, ETH_ALEN); + dev_unicast_delete(fc->real_dev, fc->ctlr.data_src_addr); if (fc->ctlr.spma) - dev_unicast_delete(fc->real_dev, - fc->ctlr.ctl_src_addr, ETH_ALEN); + dev_unicast_delete(fc->real_dev, fc->ctlr.ctl_src_addr); dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); } @@ -347,9 +345,9 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) */ rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN); + dev_unicast_add(fc->real_dev, flogi_maddr); if (fc->ctlr.spma) - dev_unicast_add(fc->real_dev, fc->ctlr.ctl_src_addr, ETH_ALEN); + dev_unicast_add(fc->real_dev, fc->ctlr.ctl_src_addr); dev_mc_add(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); rtnl_unlock(); diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index c1abeb89b413..96fb118355b0 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -188,8 +188,7 @@ static struct usb_descriptor_header *hs_pn_function[] = { static int pn_net_open(struct net_device *dev) { - if (netif_carrier_ok(dev)) - netif_wake_queue(dev); + netif_wake_queue(dev); return 0; } @@ -219,8 +218,7 @@ static void pn_tx_complete(struct usb_ep *ep, struct usb_request *req) } dev_kfree_skb_any(skb); - if (netif_carrier_ok(dev)) - netif_wake_queue(dev); + netif_wake_queue(dev); } static int pn_net_xmit(struct sk_buff *skb, struct net_device *dev) @@ -255,7 +253,7 @@ out_unlock: spin_unlock_irqrestore(&port->lock, flags); out: if (unlikely(skb)) { - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); dev->stats.tx_dropped++; } return 0; @@ -383,7 +381,6 @@ static void __pn_reset(struct usb_function *f) struct phonet_port *port = netdev_priv(dev); netif_carrier_off(dev); - netif_stop_queue(dev); port->usb = NULL; usb_ep_disable(fp->out_ep); @@ -427,8 +424,6 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) fp->in_ep->driver_data = fp; netif_carrier_on(dev); - if (netif_running(dev)) - netif_wake_queue(dev); for (i = 0; i < phonet_rxq_size; i++) pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC); } @@ -574,9 +569,10 @@ static struct net_device *dev; int __init phonet_bind_config(struct usb_configuration *c) { struct f_phonet *fp; - int err; + int err, size; - fp = kzalloc(sizeof(*fp), GFP_KERNEL); + size = sizeof(*fp) + (phonet_rxq_size * sizeof(struct usb_request *)); + fp = kzalloc(size, GFP_KERNEL); if (!fp) return -ENOMEM; @@ -601,16 +597,13 @@ int __init gphonet_setup(struct usb_gadget *gadget) /* Create net device */ BUG_ON(dev); - dev = alloc_netdev(sizeof(*port) - + (phonet_rxq_size * sizeof(struct usb_request *)), - "upnlink%d", pn_net_setup); + dev = alloc_netdev(sizeof(*port), "upnlink%d", pn_net_setup); if (!dev) return -ENOMEM; port = netdev_priv(dev); spin_lock_init(&port->lock); netif_carrier_off(dev); - netif_stop_queue(dev); SET_NETDEV_DEV(dev, &gadget->dev); err = register_netdev(dev); |